~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Jelmer Vernooij
  • Date: 2009-04-06 02:54:14 UTC
  • mfrom: (4253 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4255.
  • Revision ID: jelmer@samba.org-20090406025414-65tpjwcmjp5wa5oj
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2008 Canonical Ltd
 
2
#   Authors: Robert Collins <robert.collins@canonical.com>
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
19
20
from cStringIO import StringIO
20
21
import os
21
22
import sys
22
 
import threading
23
23
 
24
24
#import bzrlib specific imports here
25
25
from bzrlib import (
26
26
    branch,
27
27
    bzrdir,
28
28
    config,
29
 
    diff,
30
29
    errors,
31
30
    osutils,
32
31
    mail_client,
36
35
    trace,
37
36
    transport,
38
37
    )
39
 
from bzrlib.tests import features
40
38
from bzrlib.util.configobj import configobj
41
39
 
42
40
 
43
 
def lockable_config_scenarios():
44
 
    return [
45
 
        ('global',
46
 
         {'config_class': config.GlobalConfig,
47
 
          'config_args': [],
48
 
          'config_section': 'DEFAULT'}),
49
 
        ('locations',
50
 
         {'config_class': config.LocationConfig,
51
 
          'config_args': ['.'],
52
 
          'config_section': '.'}),]
53
 
 
54
 
 
55
 
def load_tests(standard_tests, module, loader):
56
 
    suite = loader.suiteClass()
57
 
 
58
 
    lc_tests, remaining_tests = tests.split_suite_by_condition(
59
 
        standard_tests, tests.condition_isinstance((
60
 
                TestLockableConfig,
61
 
                )))
62
 
    tests.multiply_tests(lc_tests, lockable_config_scenarios(), suite)
63
 
    suite.addTest(remaining_tests)
64
 
    return suite
65
 
 
66
 
 
67
41
sample_long_alias="log -r-15..-1 --line"
68
42
sample_config_text = u"""
69
43
[DEFAULT]
70
44
email=Erik B\u00e5gfors <erik@bagfors.nu>
71
45
editor=vim
72
 
change_editor=vimdiff -of @new_path @old_path
73
46
gpg_signing_command=gnome-gpg
74
47
log_format=short
75
48
user_global_option=something
155
128
        self._calls.append(('keys',))
156
129
        return []
157
130
 
158
 
    def reload(self):
159
 
        self._calls.append(('reload',))
160
 
 
161
131
    def write(self, arg):
162
132
        self._calls.append(('write',))
163
133
 
239
209
        self._calls.append('_get_signature_checking')
240
210
        return self._signatures
241
211
 
242
 
    def _get_change_editor(self):
243
 
        self._calls.append('_get_change_editor')
244
 
        return 'vimdiff -fo @new_path @old_path'
245
 
 
246
212
 
247
213
bool_config = """[DEFAULT]
248
214
active = true
349
315
        my_config = config.Config()
350
316
        self.assertEqual('long', my_config.log_format())
351
317
 
352
 
    def test_get_change_editor(self):
353
 
        my_config = InstrumentedConfig()
354
 
        change_editor = my_config.get_change_editor('old_tree', 'new_tree')
355
 
        self.assertEqual(['_get_change_editor'], my_config._calls)
356
 
        self.assertIs(diff.DiffFromTool, change_editor.__class__)
357
 
        self.assertEqual(['vimdiff', '-fo', '@new_path', '@old_path'],
358
 
                         change_editor.command_template)
359
 
 
360
318
 
361
319
class TestConfigPath(tests.TestCase):
362
320
 
363
321
    def setUp(self):
364
322
        super(TestConfigPath, self).setUp()
365
323
        os.environ['HOME'] = '/home/bogus'
366
 
        os.environ['XDG_CACHE_DIR'] = ''
367
324
        if sys.platform == 'win32':
368
325
            os.environ['BZR_HOME'] = \
369
326
                r'C:\Documents and Settings\bogus\Application Data'
379
336
        self.assertEqual(config.config_filename(),
380
337
                         self.bzr_home + '/bazaar.conf')
381
338
 
 
339
    def test_branches_config_filename(self):
 
340
        self.assertEqual(config.branches_config_filename(),
 
341
                         self.bzr_home + '/branches.conf')
 
342
 
382
343
    def test_locations_config_filename(self):
383
344
        self.assertEqual(config.locations_config_filename(),
384
345
                         self.bzr_home + '/locations.conf')
387
348
        self.assertEqual(config.authentication_config_filename(),
388
349
                         self.bzr_home + '/authentication.conf')
389
350
 
390
 
    def test_xdg_cache_dir(self):
391
 
        self.assertEqual(config.xdg_cache_dir(),
392
 
            '/home/bogus/.cache')
393
 
 
394
 
 
395
 
class TestIniConfig(tests.TestCaseInTempDir):
396
 
 
397
 
    def make_config_parser(self, s):
398
 
        conf = config.IniBasedConfig.from_string(s)
399
 
        return conf, conf._get_parser()
400
 
 
401
 
 
402
 
class TestIniConfigBuilding(TestIniConfig):
 
351
 
 
352
class TestIniConfig(tests.TestCase):
403
353
 
404
354
    def test_contructs(self):
405
 
        my_config = config.IniBasedConfig()
 
355
        my_config = config.IniBasedConfig("nothing")
406
356
 
407
357
    def test_from_fp(self):
408
 
        my_config = config.IniBasedConfig.from_string(sample_config_text)
409
 
        self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
 
358
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
359
        my_config = config.IniBasedConfig(None)
 
360
        self.failUnless(
 
361
            isinstance(my_config._get_parser(file=config_file),
 
362
                        configobj.ConfigObj))
410
363
 
411
364
    def test_cached(self):
412
 
        my_config = config.IniBasedConfig.from_string(sample_config_text)
413
 
        parser = my_config._get_parser()
 
365
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
366
        my_config = config.IniBasedConfig(None)
 
367
        parser = my_config._get_parser(file=config_file)
414
368
        self.failUnless(my_config._get_parser() is parser)
415
369
 
416
 
    def _dummy_chown(self, path, uid, gid):
417
 
        self.path, self.uid, self.gid = path, uid, gid
418
 
 
419
 
    def test_ini_config_ownership(self):
420
 
        """Ensure that chown is happening during _write_config_file"""
421
 
        self.requireFeature(features.chown_feature)
422
 
        self.overrideAttr(os, 'chown', self._dummy_chown)
423
 
        self.path = self.uid = self.gid = None
424
 
        conf = config.IniBasedConfig(file_name='./foo.conf')
425
 
        conf._write_config_file()
426
 
        self.assertEquals(self.path, './foo.conf')
427
 
        self.assertTrue(isinstance(self.uid, int))
428
 
        self.assertTrue(isinstance(self.gid, int))
429
 
 
430
 
    def test_get_filename_parameter_is_deprecated_(self):
431
 
        conf = self.callDeprecated([
432
 
            'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
433
 
            ' Use file_name instead.'],
434
 
            config.IniBasedConfig, lambda: 'ini.conf')
435
 
        self.assertEqual('ini.conf', conf.file_name)
436
 
 
437
 
    def test_get_parser_file_parameter_is_deprecated_(self):
438
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
439
 
        conf = config.IniBasedConfig.from_string(sample_config_text)
440
 
        conf = self.callDeprecated([
441
 
            'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
442
 
            ' Use IniBasedConfig(_content=xxx) instead.'],
443
 
            conf._get_parser, file=config_file)
444
 
 
445
 
class TestIniConfigSaving(tests.TestCaseInTempDir):
446
 
 
447
 
    def test_cant_save_without_a_file_name(self):
448
 
        conf = config.IniBasedConfig()
449
 
        self.assertRaises(AssertionError, conf._write_config_file)
450
 
 
451
 
    def test_saved_with_content(self):
452
 
        content = 'foo = bar\n'
453
 
        conf = config.IniBasedConfig.from_string(
454
 
            content, file_name='./test.conf', save=True)
455
 
        self.assertFileEqual(content, 'test.conf')
456
 
 
457
 
 
458
 
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
459
 
 
460
 
    def test_cannot_reload_without_name(self):
461
 
        conf = config.IniBasedConfig.from_string(sample_config_text)
462
 
        self.assertRaises(AssertionError, conf.reload)
463
 
 
464
 
    def test_reload_see_new_value(self):
465
 
        c1 = config.IniBasedConfig.from_string('editor=vim\n',
466
 
                                               file_name='./test/conf')
467
 
        c1._write_config_file()
468
 
        c2 = config.IniBasedConfig.from_string('editor=emacs\n',
469
 
                                               file_name='./test/conf')
470
 
        c2._write_config_file()
471
 
        self.assertEqual('vim', c1.get_user_option('editor'))
472
 
        self.assertEqual('emacs', c2.get_user_option('editor'))
473
 
        # Make sure we get the Right value
474
 
        c1.reload()
475
 
        self.assertEqual('emacs', c1.get_user_option('editor'))
476
 
 
477
 
 
478
 
class TestLockableConfig(tests.TestCaseInTempDir):
479
 
 
480
 
    # Set by load_tests
481
 
    config_class = None
482
 
    config_args = None
483
 
    config_section = None
484
 
 
485
 
    def setUp(self):
486
 
        super(TestLockableConfig, self).setUp()
487
 
        self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
488
 
        self.config = self.create_config(self._content)
489
 
 
490
 
    def get_existing_config(self):
491
 
        return self.config_class(*self.config_args)
492
 
 
493
 
    def create_config(self, content):
494
 
        kwargs = dict(save=True)
495
 
        c = self.config_class.from_string(content, *self.config_args, **kwargs)
496
 
        return c
497
 
 
498
 
    def test_simple_read_access(self):
499
 
        self.assertEquals('1', self.config.get_user_option('one'))
500
 
 
501
 
    def test_simple_write_access(self):
502
 
        self.config.set_user_option('one', 'one')
503
 
        self.assertEquals('one', self.config.get_user_option('one'))
504
 
 
505
 
    def test_listen_to_the_last_speaker(self):
506
 
        c1 = self.config
507
 
        c2 = self.get_existing_config()
508
 
        c1.set_user_option('one', 'ONE')
509
 
        c2.set_user_option('two', 'TWO')
510
 
        self.assertEquals('ONE', c1.get_user_option('one'))
511
 
        self.assertEquals('TWO', c2.get_user_option('two'))
512
 
        # The second update respect the first one
513
 
        self.assertEquals('ONE', c2.get_user_option('one'))
514
 
 
515
 
    def test_last_speaker_wins(self):
516
 
        # If the same config is not shared, the same variable modified twice
517
 
        # can only see a single result.
518
 
        c1 = self.config
519
 
        c2 = self.get_existing_config()
520
 
        c1.set_user_option('one', 'c1')
521
 
        c2.set_user_option('one', 'c2')
522
 
        self.assertEquals('c2', c2._get_user_option('one'))
523
 
        # The first modification is still available until another refresh
524
 
        # occur
525
 
        self.assertEquals('c1', c1._get_user_option('one'))
526
 
        c1.set_user_option('two', 'done')
527
 
        self.assertEquals('c2', c1._get_user_option('one'))
528
 
 
529
 
    def test_writes_are_serialized(self):
530
 
        c1 = self.config
531
 
        c2 = self.get_existing_config()
532
 
 
533
 
        # We spawn a thread that will pause *during* the write
534
 
        before_writing = threading.Event()
535
 
        after_writing = threading.Event()
536
 
        writing_done = threading.Event()
537
 
        c1_orig = c1._write_config_file
538
 
        def c1_write_config_file():
539
 
            before_writing.set()
540
 
            c1_orig()
541
 
            # The lock is held we wait for the main thread to decide when to
542
 
            # continue
543
 
            after_writing.wait()
544
 
        c1._write_config_file = c1_write_config_file
545
 
        def c1_set_option():
546
 
            c1.set_user_option('one', 'c1')
547
 
            writing_done.set()
548
 
        t1 = threading.Thread(target=c1_set_option)
549
 
        # Collect the thread after the test
550
 
        self.addCleanup(t1.join)
551
 
        # Be ready to unblock the thread if the test goes wrong
552
 
        self.addCleanup(after_writing.set)
553
 
        t1.start()
554
 
        before_writing.wait()
555
 
        self.assertTrue(c1._lock.is_held)
556
 
        self.assertRaises(errors.LockContention,
557
 
                          c2.set_user_option, 'one', 'c2')
558
 
        self.assertEquals('c1', c1.get_user_option('one'))
559
 
        # Let the lock be released
560
 
        after_writing.set()
561
 
        writing_done.wait()
562
 
        c2.set_user_option('one', 'c2')
563
 
        self.assertEquals('c2', c2.get_user_option('one'))
564
 
 
565
 
    def test_read_while_writing(self):
566
 
       c1 = self.config
567
 
       # We spawn a thread that will pause *during* the write
568
 
       ready_to_write = threading.Event()
569
 
       do_writing = threading.Event()
570
 
       writing_done = threading.Event()
571
 
       c1_orig = c1._write_config_file
572
 
       def c1_write_config_file():
573
 
           ready_to_write.set()
574
 
           # The lock is held we wait for the main thread to decide when to
575
 
           # continue
576
 
           do_writing.wait()
577
 
           c1_orig()
578
 
           writing_done.set()
579
 
       c1._write_config_file = c1_write_config_file
580
 
       def c1_set_option():
581
 
           c1.set_user_option('one', 'c1')
582
 
       t1 = threading.Thread(target=c1_set_option)
583
 
       # Collect the thread after the test
584
 
       self.addCleanup(t1.join)
585
 
       # Be ready to unblock the thread if the test goes wrong
586
 
       self.addCleanup(do_writing.set)
587
 
       t1.start()
588
 
       # Ensure the thread is ready to write
589
 
       ready_to_write.wait()
590
 
       self.assertTrue(c1._lock.is_held)
591
 
       self.assertEquals('c1', c1.get_user_option('one'))
592
 
       # If we read during the write, we get the old value
593
 
       c2 = self.get_existing_config()
594
 
       self.assertEquals('1', c2.get_user_option('one'))
595
 
       # Let the writing occur and ensure it occurred
596
 
       do_writing.set()
597
 
       writing_done.wait()
598
 
       # Now we get the updated value
599
 
       c3 = self.get_existing_config()
600
 
       self.assertEquals('c1', c3.get_user_option('one'))
601
 
 
602
 
 
603
 
class TestGetUserOptionAs(TestIniConfig):
604
 
 
605
 
    def test_get_user_option_as_bool(self):
606
 
        conf, parser = self.make_config_parser("""
607
 
a_true_bool = true
608
 
a_false_bool = 0
609
 
an_invalid_bool = maybe
610
 
a_list = hmm, who knows ? # This is interpreted as a list !
611
 
""")
612
 
        get_bool = conf.get_user_option_as_bool
613
 
        self.assertEqual(True, get_bool('a_true_bool'))
614
 
        self.assertEqual(False, get_bool('a_false_bool'))
615
 
        warnings = []
616
 
        def warning(*args):
617
 
            warnings.append(args[0] % args[1:])
618
 
        self.overrideAttr(trace, 'warning', warning)
619
 
        msg = 'Value "%s" is not a boolean for "%s"'
620
 
        self.assertIs(None, get_bool('an_invalid_bool'))
621
 
        self.assertEquals(msg % ('maybe', 'an_invalid_bool'), warnings[0])
622
 
        warnings = []
623
 
        self.assertIs(None, get_bool('not_defined_in_this_config'))
624
 
        self.assertEquals([], warnings)
625
 
 
626
 
    def test_get_user_option_as_list(self):
627
 
        conf, parser = self.make_config_parser("""
628
 
a_list = a,b,c
629
 
length_1 = 1,
630
 
one_item = x
631
 
""")
632
 
        get_list = conf.get_user_option_as_list
633
 
        self.assertEqual(['a', 'b', 'c'], get_list('a_list'))
634
 
        self.assertEqual(['1'], get_list('length_1'))
635
 
        self.assertEqual('x', conf.get_user_option('one_item'))
636
 
        # automatically cast to list
637
 
        self.assertEqual(['x'], get_list('one_item'))
638
 
 
639
 
 
640
 
class TestSupressWarning(TestIniConfig):
641
 
 
642
 
    def make_warnings_config(self, s):
643
 
        conf, parser = self.make_config_parser(s)
644
 
        return conf.suppress_warning
645
 
 
646
 
    def test_suppress_warning_unknown(self):
647
 
        suppress_warning = self.make_warnings_config('')
648
 
        self.assertEqual(False, suppress_warning('unknown_warning'))
649
 
 
650
 
    def test_suppress_warning_known(self):
651
 
        suppress_warning = self.make_warnings_config('suppress_warnings=a,b')
652
 
        self.assertEqual(False, suppress_warning('c'))
653
 
        self.assertEqual(True, suppress_warning('a'))
654
 
        self.assertEqual(True, suppress_warning('b'))
655
 
 
656
370
 
657
371
class TestGetConfig(tests.TestCase):
658
372
 
711
425
        branch = self.make_branch('branch')
712
426
        self.assertEqual('branch', branch.nick)
713
427
 
 
428
        locations = config.locations_config_filename()
 
429
        config.ensure_config_dir_exists()
714
430
        local_url = urlutils.local_path_to_url('branch')
715
 
        conf = config.LocationConfig.from_string(
716
 
            '[%s]\nnickname = foobar' % (local_url,),
717
 
            local_url, save=True)
 
431
        open(locations, 'wb').write('[%s]\nnickname = foobar'
 
432
                                    % (local_url,))
718
433
        self.assertEqual('foobar', branch.nick)
719
434
 
720
435
    def test_config_local_path(self):
722
437
        branch = self.make_branch('branch')
723
438
        self.assertEqual('branch', branch.nick)
724
439
 
725
 
        local_path = osutils.getcwd().encode('utf8')
726
 
        conf = config.LocationConfig.from_string(
727
 
            '[%s/branch]\nnickname = barry' % (local_path,),
728
 
            'branch',  save=True)
 
440
        locations = config.locations_config_filename()
 
441
        config.ensure_config_dir_exists()
 
442
        open(locations, 'wb').write('[%s/branch]\nnickname = barry'
 
443
                                    % (osutils.getcwd().encode('utf8'),))
729
444
        self.assertEqual('barry', branch.nick)
730
445
 
731
446
    def test_config_creates_local(self):
732
447
        """Creating a new entry in config uses a local path."""
733
448
        branch = self.make_branch('branch', format='knit')
734
449
        branch.set_push_location('http://foobar')
 
450
        locations = config.locations_config_filename()
735
451
        local_path = osutils.getcwd().encode('utf8')
736
452
        # Surprisingly ConfigObj doesn't create a trailing newline
737
 
        self.check_file_contents(config.locations_config_filename(),
 
453
        self.check_file_contents(locations,
738
454
                                 '[%s/branch]\n'
739
455
                                 'push_location = http://foobar\n'
740
456
                                 'push_location:policy = norecurse\n'
745
461
        self.assertEqual('!repo', b.get_config().get_nickname())
746
462
 
747
463
    def test_warn_if_masked(self):
 
464
        _warning = trace.warning
748
465
        warnings = []
749
466
        def warning(*args):
750
467
            warnings.append(args[0] % args[1:])
751
 
        self.overrideAttr(trace, 'warning', warning)
752
468
 
753
469
        def set_option(store, warn_masked=True):
754
470
            warnings[:] = []
760
476
            else:
761
477
                self.assertEqual(1, len(warnings))
762
478
                self.assertEqual(warning, warnings[0])
763
 
        branch = self.make_branch('.')
764
 
        conf = branch.get_config()
765
 
        set_option(config.STORE_GLOBAL)
766
 
        assertWarning(None)
767
 
        set_option(config.STORE_BRANCH)
768
 
        assertWarning(None)
769
 
        set_option(config.STORE_GLOBAL)
770
 
        assertWarning('Value "4" is masked by "3" from branch.conf')
771
 
        set_option(config.STORE_GLOBAL, warn_masked=False)
772
 
        assertWarning(None)
773
 
        set_option(config.STORE_LOCATION)
774
 
        assertWarning(None)
775
 
        set_option(config.STORE_BRANCH)
776
 
        assertWarning('Value "3" is masked by "0" from locations.conf')
777
 
        set_option(config.STORE_BRANCH, warn_masked=False)
778
 
        assertWarning(None)
779
 
 
780
 
 
781
 
class TestGlobalConfigItems(tests.TestCaseInTempDir):
 
479
        trace.warning = warning
 
480
        try:
 
481
            branch = self.make_branch('.')
 
482
            conf = branch.get_config()
 
483
            set_option(config.STORE_GLOBAL)
 
484
            assertWarning(None)
 
485
            set_option(config.STORE_BRANCH)
 
486
            assertWarning(None)
 
487
            set_option(config.STORE_GLOBAL)
 
488
            assertWarning('Value "4" is masked by "3" from branch.conf')
 
489
            set_option(config.STORE_GLOBAL, warn_masked=False)
 
490
            assertWarning(None)
 
491
            set_option(config.STORE_LOCATION)
 
492
            assertWarning(None)
 
493
            set_option(config.STORE_BRANCH)
 
494
            assertWarning('Value "3" is masked by "0" from locations.conf')
 
495
            set_option(config.STORE_BRANCH, warn_masked=False)
 
496
            assertWarning(None)
 
497
        finally:
 
498
            trace.warning = _warning
 
499
 
 
500
 
 
501
class TestGlobalConfigItems(tests.TestCase):
782
502
 
783
503
    def test_user_id(self):
784
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
504
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
505
        my_config = config.GlobalConfig()
 
506
        my_config._parser = my_config._get_parser(file=config_file)
785
507
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
786
508
                         my_config._get_user_id())
787
509
 
788
510
    def test_absent_user_id(self):
 
511
        config_file = StringIO("")
789
512
        my_config = config.GlobalConfig()
 
513
        my_config._parser = my_config._get_parser(file=config_file)
790
514
        self.assertEqual(None, my_config._get_user_id())
791
515
 
792
516
    def test_configured_editor(self):
793
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
517
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
518
        my_config = config.GlobalConfig()
 
519
        my_config._parser = my_config._get_parser(file=config_file)
794
520
        self.assertEqual("vim", my_config.get_editor())
795
521
 
796
522
    def test_signatures_always(self):
797
 
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
 
523
        config_file = StringIO(sample_always_signatures)
 
524
        my_config = config.GlobalConfig()
 
525
        my_config._parser = my_config._get_parser(file=config_file)
798
526
        self.assertEqual(config.CHECK_NEVER,
799
527
                         my_config.signature_checking())
800
528
        self.assertEqual(config.SIGN_ALWAYS,
802
530
        self.assertEqual(True, my_config.signature_needed())
803
531
 
804
532
    def test_signatures_if_possible(self):
805
 
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
 
533
        config_file = StringIO(sample_maybe_signatures)
 
534
        my_config = config.GlobalConfig()
 
535
        my_config._parser = my_config._get_parser(file=config_file)
806
536
        self.assertEqual(config.CHECK_NEVER,
807
537
                         my_config.signature_checking())
808
538
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
810
540
        self.assertEqual(False, my_config.signature_needed())
811
541
 
812
542
    def test_signatures_ignore(self):
813
 
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
 
543
        config_file = StringIO(sample_ignore_signatures)
 
544
        my_config = config.GlobalConfig()
 
545
        my_config._parser = my_config._get_parser(file=config_file)
814
546
        self.assertEqual(config.CHECK_ALWAYS,
815
547
                         my_config.signature_checking())
816
548
        self.assertEqual(config.SIGN_NEVER,
818
550
        self.assertEqual(False, my_config.signature_needed())
819
551
 
820
552
    def _get_sample_config(self):
821
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
553
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
554
        my_config = config.GlobalConfig()
 
555
        my_config._parser = my_config._get_parser(file=config_file)
822
556
        return my_config
823
557
 
824
558
    def test_gpg_signing_command(self):
827
561
        self.assertEqual(False, my_config.signature_needed())
828
562
 
829
563
    def _get_empty_config(self):
 
564
        config_file = StringIO("")
830
565
        my_config = config.GlobalConfig()
 
566
        my_config._parser = my_config._get_parser(file=config_file)
831
567
        return my_config
832
568
 
833
569
    def test_gpg_signing_command_unset(self):
871
607
        my_config = self._get_sample_config()
872
608
        self.assertEqual(sample_long_alias, my_config.get_alias('ll'))
873
609
 
874
 
    def test_get_change_editor(self):
875
 
        my_config = self._get_sample_config()
876
 
        change_editor = my_config.get_change_editor('old', 'new')
877
 
        self.assertIs(diff.DiffFromTool, change_editor.__class__)
878
 
        self.assertEqual('vimdiff -of @new_path @old_path',
879
 
                         ' '.join(change_editor.command_template))
880
 
 
881
 
    def test_get_no_change_editor(self):
882
 
        my_config = self._get_empty_config()
883
 
        change_editor = my_config.get_change_editor('old', 'new')
884
 
        self.assertIs(None, change_editor)
885
 
 
886
610
 
887
611
class TestGlobalConfigSavingOptions(tests.TestCaseInTempDir):
888
612
 
928
652
        self.assertEqual(parser._calls,
929
653
                         [('__init__', config.locations_config_filename(),
930
654
                           'utf-8')])
 
655
        config.ensure_config_dir_exists()
 
656
        #os.mkdir(config.config_dir())
 
657
        f = file(config.branches_config_filename(), 'wb')
 
658
        f.write('')
 
659
        f.close()
 
660
        oldparserclass = config.ConfigObj
 
661
        config.ConfigObj = InstrumentedConfigObj
 
662
        try:
 
663
            my_config = config.LocationConfig('http://www.example.com')
 
664
            parser = my_config._get_parser()
 
665
        finally:
 
666
            config.ConfigObj = oldparserclass
931
667
 
932
668
    def test_get_global_config(self):
933
669
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
1162
898
                         self.my_config.post_commit())
1163
899
 
1164
900
    def get_branch_config(self, location, global_config=None):
1165
 
        my_branch = FakeBranch(location)
1166
901
        if global_config is None:
1167
 
            global_config = sample_config_text
1168
 
 
1169
 
        my_global_config = config.GlobalConfig.from_string(global_config,
1170
 
                                                           save=True)
1171
 
        my_location_config = config.LocationConfig.from_string(
1172
 
            sample_branches_text, my_branch.base, save=True)
1173
 
        my_config = config.BranchConfig(my_branch)
1174
 
        self.my_config = my_config
1175
 
        self.my_location_config = my_config._get_location_config()
 
902
            global_file = StringIO(sample_config_text.encode('utf-8'))
 
903
        else:
 
904
            global_file = StringIO(global_config.encode('utf-8'))
 
905
        branches_file = StringIO(sample_branches_text.encode('utf-8'))
 
906
        self.my_config = config.BranchConfig(FakeBranch(location))
 
907
        # Force location config to use specified file
 
908
        self.my_location_config = self.my_config._get_location_config()
 
909
        self.my_location_config._get_parser(branches_file)
 
910
        # Force global config to use specified file
 
911
        self.my_config._get_global_config()._get_parser(global_file)
1176
912
 
1177
913
    def test_set_user_setting_sets_and_saves(self):
1178
914
        self.get_branch_config('/a/c')
1179
915
        record = InstrumentedConfigObj("foo")
1180
916
        self.my_location_config._parser = record
1181
917
 
1182
 
        self.callDeprecated(['The recurse option is deprecated as of '
1183
 
                             '0.14.  The section "/a/c" has been '
1184
 
                             'converted to use policies.'],
1185
 
                            self.my_config.set_user_option,
1186
 
                            'foo', 'bar', store=config.STORE_LOCATION)
1187
 
        self.assertEqual([('reload',),
1188
 
                          ('__contains__', '/a/c'),
 
918
        real_mkdir = os.mkdir
 
919
        self.created = False
 
920
        def checked_mkdir(path, mode=0777):
 
921
            self.log('making directory: %s', path)
 
922
            real_mkdir(path, mode)
 
923
            self.created = True
 
924
 
 
925
        os.mkdir = checked_mkdir
 
926
        try:
 
927
            self.callDeprecated(['The recurse option is deprecated as of '
 
928
                                 '0.14.  The section "/a/c" has been '
 
929
                                 'converted to use policies.'],
 
930
                                self.my_config.set_user_option,
 
931
                                'foo', 'bar', store=config.STORE_LOCATION)
 
932
        finally:
 
933
            os.mkdir = real_mkdir
 
934
 
 
935
        self.failUnless(self.created, 'Failed to create ~/.bazaar')
 
936
        self.assertEqual([('__contains__', '/a/c'),
1189
937
                          ('__contains__', '/a/c/'),
1190
938
                          ('__setitem__', '/a/c', {}),
1191
939
                          ('__getitem__', '/a/c'),
1234
982
option = exact
1235
983
"""
1236
984
 
 
985
 
1237
986
class TestBranchConfigItems(tests.TestCaseInTempDir):
1238
987
 
1239
988
    def get_branch_config(self, global_config=None, location=None,
1240
989
                          location_config=None, branch_data_config=None):
1241
 
        my_branch = FakeBranch(location)
 
990
        my_config = config.BranchConfig(FakeBranch(location))
1242
991
        if global_config is not None:
1243
 
            my_global_config = config.GlobalConfig.from_string(global_config,
1244
 
                                                               save=True)
 
992
            global_file = StringIO(global_config.encode('utf-8'))
 
993
            my_config._get_global_config()._get_parser(global_file)
 
994
        self.my_location_config = my_config._get_location_config()
1245
995
        if location_config is not None:
1246
 
            my_location_config = config.LocationConfig.from_string(
1247
 
                location_config, my_branch.base, save=True)
1248
 
        my_config = config.BranchConfig(my_branch)
 
996
            location_file = StringIO(location_config.encode('utf-8'))
 
997
            self.my_location_config._get_parser(location_file)
1249
998
        if branch_data_config is not None:
1250
999
            my_config.branch.control_files.files['branch.conf'] = \
1251
1000
                branch_data_config
1265
1014
                         my_config.username())
1266
1015
 
1267
1016
    def test_not_set_in_branch(self):
1268
 
        my_config = self.get_branch_config(global_config=sample_config_text)
 
1017
        my_config = self.get_branch_config(sample_config_text)
1269
1018
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
1270
1019
                         my_config._get_user_id())
1271
1020
        my_config.branch.control_files.files['email'] = "John"
1295
1044
 
1296
1045
    def test_gpg_signing_command(self):
1297
1046
        my_config = self.get_branch_config(
1298
 
            global_config=sample_config_text,
1299
1047
            # branch data cannot set gpg_signing_command
1300
1048
            branch_data_config="gpg_signing_command=pgp")
 
1049
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
1050
        my_config._get_global_config()._get_parser(config_file)
1301
1051
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1302
1052
 
1303
1053
    def test_get_user_option_global(self):
1304
 
        my_config = self.get_branch_config(global_config=sample_config_text)
 
1054
        branch = FakeBranch()
 
1055
        my_config = config.BranchConfig(branch)
 
1056
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
1057
        (my_config._get_global_config()._get_parser(config_file))
1305
1058
        self.assertEqual('something',
1306
1059
                         my_config.get_user_option('user_global_option'))
1307
1060
 
1308
1061
    def test_post_commit_default(self):
1309
 
        my_config = self.get_branch_config(global_config=sample_config_text,
1310
 
                                      location='/a/c',
1311
 
                                      location_config=sample_branches_text)
 
1062
        branch = FakeBranch()
 
1063
        my_config = self.get_branch_config(sample_config_text, '/a/c',
 
1064
                                           sample_branches_text)
1312
1065
        self.assertEqual(my_config.branch.base, '/a/c')
1313
1066
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1314
1067
                         my_config.post_commit())
1315
1068
        my_config.set_user_option('post_commit', 'rmtree_root')
1316
 
        # post-commit is ignored when present in branch data
 
1069
        # post-commit is ignored when bresent in branch data
1317
1070
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1318
1071
                         my_config.post_commit())
1319
1072
        my_config.set_user_option('post_commit', 'rmtree_root',
1321
1074
        self.assertEqual('rmtree_root', my_config.post_commit())
1322
1075
 
1323
1076
    def test_config_precedence(self):
1324
 
        # FIXME: eager test, luckily no persitent config file makes it fail
1325
 
        # -- vila 20100716
1326
1077
        my_config = self.get_branch_config(global_config=precedence_global)
1327
1078
        self.assertEqual(my_config.get_user_option('option'), 'global')
1328
1079
        my_config = self.get_branch_config(global_config=precedence_global,
1329
 
                                           branch_data_config=precedence_branch)
 
1080
                                      branch_data_config=precedence_branch)
1330
1081
        self.assertEqual(my_config.get_user_option('option'), 'branch')
1331
 
        my_config = self.get_branch_config(
1332
 
            global_config=precedence_global,
1333
 
            branch_data_config=precedence_branch,
1334
 
            location_config=precedence_location)
 
1082
        my_config = self.get_branch_config(global_config=precedence_global,
 
1083
                                      branch_data_config=precedence_branch,
 
1084
                                      location_config=precedence_location)
1335
1085
        self.assertEqual(my_config.get_user_option('option'), 'recurse')
1336
 
        my_config = self.get_branch_config(
1337
 
            global_config=precedence_global,
1338
 
            branch_data_config=precedence_branch,
1339
 
            location_config=precedence_location,
1340
 
            location='http://example.com/specific')
 
1086
        my_config = self.get_branch_config(global_config=precedence_global,
 
1087
                                      branch_data_config=precedence_branch,
 
1088
                                      location_config=precedence_location,
 
1089
                                      location='http://example.com/specific')
1341
1090
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1342
1091
 
1343
1092
    def test_get_mail_client(self):
1461
1210
 
1462
1211
    def test_set_unset_default_stack_on(self):
1463
1212
        my_dir = self.make_bzrdir('.')
1464
 
        bzrdir_config = config.BzrDirConfig(my_dir)
 
1213
        bzrdir_config = config.BzrDirConfig(my_dir.transport)
1465
1214
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1466
1215
        bzrdir_config.set_default_stack_on('Foo')
1467
1216
        self.assertEqual('Foo', bzrdir_config._config.get_option(
1710
1459
class TestAuthenticationConfig(tests.TestCase):
1711
1460
    """Test AuthenticationConfig behaviour"""
1712
1461
 
1713
 
    def _check_default_password_prompt(self, expected_prompt_format, scheme,
1714
 
                                       host=None, port=None, realm=None,
1715
 
                                       path=None):
 
1462
    def _check_default_prompt(self, expected_prompt_format, scheme,
 
1463
                              host=None, port=None, realm=None, path=None):
1716
1464
        if host is None:
1717
1465
            host = 'bar.org'
1718
1466
        user, password = 'jim', 'precious'
1721
1469
            'user': user, 'realm': realm}
1722
1470
 
1723
1471
        stdout = tests.StringIOWrapper()
1724
 
        stderr = tests.StringIOWrapper()
1725
1472
        ui.ui_factory = tests.TestUIFactory(stdin=password + '\n',
1726
 
                                            stdout=stdout, stderr=stderr)
 
1473
                                            stdout=stdout)
1727
1474
        # We use an empty conf so that the user is always prompted
1728
1475
        conf = config.AuthenticationConfig()
1729
1476
        self.assertEquals(password,
1730
1477
                          conf.get_password(scheme, host, user, port=port,
1731
1478
                                            realm=realm, path=path))
1732
 
        self.assertEquals(expected_prompt, stderr.getvalue())
1733
 
        self.assertEquals('', stdout.getvalue())
1734
 
 
1735
 
    def _check_default_username_prompt(self, expected_prompt_format, scheme,
1736
 
                                       host=None, port=None, realm=None,
1737
 
                                       path=None):
1738
 
        if host is None:
1739
 
            host = 'bar.org'
1740
 
        username = 'jim'
1741
 
        expected_prompt = expected_prompt_format % {
1742
 
            'scheme': scheme, 'host': host, 'port': port,
1743
 
            'realm': realm}
1744
 
        stdout = tests.StringIOWrapper()
1745
 
        stderr = tests.StringIOWrapper()
1746
 
        ui.ui_factory = tests.TestUIFactory(stdin=username+ '\n',
1747
 
                                            stdout=stdout, stderr=stderr)
1748
 
        # We use an empty conf so that the user is always prompted
1749
 
        conf = config.AuthenticationConfig()
1750
 
        self.assertEquals(username, conf.get_user(scheme, host, port=port,
1751
 
                          realm=realm, path=path, ask=True))
1752
 
        self.assertEquals(expected_prompt, stderr.getvalue())
1753
 
        self.assertEquals('', stdout.getvalue())
1754
 
 
1755
 
    def test_username_defaults_prompts(self):
1756
 
        # HTTP prompts can't be tested here, see test_http.py
1757
 
        self._check_default_username_prompt('FTP %(host)s username: ', 'ftp')
1758
 
        self._check_default_username_prompt(
1759
 
            'FTP %(host)s:%(port)d username: ', 'ftp', port=10020)
1760
 
        self._check_default_username_prompt(
1761
 
            'SSH %(host)s:%(port)d username: ', 'ssh', port=12345)
1762
 
 
1763
 
    def test_username_default_no_prompt(self):
1764
 
        conf = config.AuthenticationConfig()
1765
 
        self.assertEquals(None,
1766
 
            conf.get_user('ftp', 'example.com'))
1767
 
        self.assertEquals("explicitdefault",
1768
 
            conf.get_user('ftp', 'example.com', default="explicitdefault"))
1769
 
 
1770
 
    def test_password_default_prompts(self):
1771
 
        # HTTP prompts can't be tested here, see test_http.py
1772
 
        self._check_default_password_prompt(
1773
 
            'FTP %(user)s@%(host)s password: ', 'ftp')
1774
 
        self._check_default_password_prompt(
1775
 
            'FTP %(user)s@%(host)s:%(port)d password: ', 'ftp', port=10020)
1776
 
        self._check_default_password_prompt(
1777
 
            'SSH %(user)s@%(host)s:%(port)d password: ', 'ssh', port=12345)
 
1479
        self.assertEquals(stdout.getvalue(), expected_prompt)
 
1480
 
 
1481
    def test_default_prompts(self):
 
1482
        # HTTP prompts can't be tested here, see test_http.py
 
1483
        self._check_default_prompt('FTP %(user)s@%(host)s password: ', 'ftp')
 
1484
        self._check_default_prompt('FTP %(user)s@%(host)s:%(port)d password: ',
 
1485
                                   'ftp', port=10020)
 
1486
 
 
1487
        self._check_default_prompt('SSH %(user)s@%(host)s:%(port)d password: ',
 
1488
                                   'ssh', port=12345)
1778
1489
        # SMTP port handling is a bit special (it's handled if embedded in the
1779
1490
        # host too)
1780
1491
        # FIXME: should we: forbid that, extend it to other schemes, leave
1781
1492
        # things as they are that's fine thank you ?
1782
 
        self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
1783
 
                                            'smtp')
1784
 
        self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
1785
 
                                            'smtp', host='bar.org:10025')
1786
 
        self._check_default_password_prompt(
 
1493
        self._check_default_prompt('SMTP %(user)s@%(host)s password: ',
 
1494
                                   'smtp')
 
1495
        self._check_default_prompt('SMTP %(user)s@%(host)s password: ',
 
1496
                                   'smtp', host='bar.org:10025')
 
1497
        self._check_default_prompt(
1787
1498
            'SMTP %(user)s@%(host)s:%(port)d password: ',
1788
1499
            'smtp', port=10025)
1789
1500
 
1798
1509
"""))
1799
1510
        entered_password = 'typed-by-hand'
1800
1511
        stdout = tests.StringIOWrapper()
1801
 
        stderr = tests.StringIOWrapper()
1802
1512
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
1803
 
                                            stdout=stdout, stderr=stderr)
 
1513
                                            stdout=stdout)
1804
1514
 
1805
1515
        # Since the password defined in the authentication config is ignored,
1806
1516
        # the user is prompted
1807
1517
        self.assertEquals(entered_password,
1808
1518
                          conf.get_password('ssh', 'bar.org', user='jim'))
1809
1519
        self.assertContainsRe(
1810
 
            self.get_log(),
 
1520
            self._get_log(keep_log_file=True),
1811
1521
            'password ignored in section \[ssh with password\]')
1812
1522
 
1813
1523
    def test_ssh_without_password_doesnt_emit_warning(self):
1820
1530
"""))
1821
1531
        entered_password = 'typed-by-hand'
1822
1532
        stdout = tests.StringIOWrapper()
1823
 
        stderr = tests.StringIOWrapper()
1824
1533
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
1825
 
                                            stdout=stdout,
1826
 
                                            stderr=stderr)
 
1534
                                            stdout=stdout)
1827
1535
 
1828
1536
        # Since the password defined in the authentication config is ignored,
1829
1537
        # the user is prompted
1832
1540
        # No warning shoud be emitted since there is no password. We are only
1833
1541
        # providing "user".
1834
1542
        self.assertNotContainsRe(
1835
 
            self.get_log(),
 
1543
            self._get_log(keep_log_file=True),
1836
1544
            'password ignored in section \[ssh with password\]')
1837
1545
 
1838
 
    def test_uses_fallback_stores(self):
1839
 
        self.overrideAttr(config, 'credential_store_registry',
1840
 
                          config.CredentialStoreRegistry())
1841
 
        store = StubCredentialStore()
1842
 
        store.add_credentials("http", "example.com", "joe", "secret")
1843
 
        config.credential_store_registry.register("stub", store, fallback=True)
1844
 
        conf = config.AuthenticationConfig(_file=StringIO())
1845
 
        creds = conf.get_credentials("http", "example.com")
1846
 
        self.assertEquals("joe", creds["user"])
1847
 
        self.assertEquals("secret", creds["password"])
1848
 
 
1849
 
 
1850
 
class StubCredentialStore(config.CredentialStore):
1851
 
 
1852
 
    def __init__(self):
1853
 
        self._username = {}
1854
 
        self._password = {}
1855
 
 
1856
 
    def add_credentials(self, scheme, host, user, password=None):
1857
 
        self._username[(scheme, host)] = user
1858
 
        self._password[(scheme, host)] = password
1859
 
 
1860
 
    def get_credentials(self, scheme, host, port=None, user=None,
1861
 
        path=None, realm=None):
1862
 
        key = (scheme, host)
1863
 
        if not key in self._username:
1864
 
            return None
1865
 
        return { "scheme": scheme, "host": host, "port": port,
1866
 
                "user": self._username[key], "password": self._password[key]}
1867
 
 
1868
 
 
1869
 
class CountingCredentialStore(config.CredentialStore):
1870
 
 
1871
 
    def __init__(self):
1872
 
        self._calls = 0
1873
 
 
1874
 
    def get_credentials(self, scheme, host, port=None, user=None,
1875
 
        path=None, realm=None):
1876
 
        self._calls += 1
1877
 
        return None
1878
 
 
1879
1546
 
1880
1547
class TestCredentialStoreRegistry(tests.TestCase):
1881
1548
 
1893
1560
        # 'unknown' so we use that as an never registered key.
1894
1561
        self.assertRaises(KeyError, r.get_credential_store, 'unknown')
1895
1562
 
1896
 
    def test_fallback_none_registered(self):
1897
 
        r = config.CredentialStoreRegistry()
1898
 
        self.assertEquals(None,
1899
 
                          r.get_fallback_credentials("http", "example.com"))
1900
 
 
1901
 
    def test_register(self):
1902
 
        r = config.CredentialStoreRegistry()
1903
 
        r.register("stub", StubCredentialStore(), fallback=False)
1904
 
        r.register("another", StubCredentialStore(), fallback=True)
1905
 
        self.assertEquals(["another", "stub"], r.keys())
1906
 
 
1907
 
    def test_register_lazy(self):
1908
 
        r = config.CredentialStoreRegistry()
1909
 
        r.register_lazy("stub", "bzrlib.tests.test_config",
1910
 
                        "StubCredentialStore", fallback=False)
1911
 
        self.assertEquals(["stub"], r.keys())
1912
 
        self.assertIsInstance(r.get_credential_store("stub"),
1913
 
                              StubCredentialStore)
1914
 
 
1915
 
    def test_is_fallback(self):
1916
 
        r = config.CredentialStoreRegistry()
1917
 
        r.register("stub1", None, fallback=False)
1918
 
        r.register("stub2", None, fallback=True)
1919
 
        self.assertEquals(False, r.is_fallback("stub1"))
1920
 
        self.assertEquals(True, r.is_fallback("stub2"))
1921
 
 
1922
 
    def test_no_fallback(self):
1923
 
        r = config.CredentialStoreRegistry()
1924
 
        store = CountingCredentialStore()
1925
 
        r.register("count", store, fallback=False)
1926
 
        self.assertEquals(None,
1927
 
                          r.get_fallback_credentials("http", "example.com"))
1928
 
        self.assertEquals(0, store._calls)
1929
 
 
1930
 
    def test_fallback_credentials(self):
1931
 
        r = config.CredentialStoreRegistry()
1932
 
        store = StubCredentialStore()
1933
 
        store.add_credentials("http", "example.com",
1934
 
                              "somebody", "geheim")
1935
 
        r.register("stub", store, fallback=True)
1936
 
        creds = r.get_fallback_credentials("http", "example.com")
1937
 
        self.assertEquals("somebody", creds["user"])
1938
 
        self.assertEquals("geheim", creds["password"])
1939
 
 
1940
 
    def test_fallback_first_wins(self):
1941
 
        r = config.CredentialStoreRegistry()
1942
 
        stub1 = StubCredentialStore()
1943
 
        stub1.add_credentials("http", "example.com",
1944
 
                              "somebody", "stub1")
1945
 
        r.register("stub1", stub1, fallback=True)
1946
 
        stub2 = StubCredentialStore()
1947
 
        stub2.add_credentials("http", "example.com",
1948
 
                              "somebody", "stub2")
1949
 
        r.register("stub2", stub1, fallback=True)
1950
 
        creds = r.get_fallback_credentials("http", "example.com")
1951
 
        self.assertEquals("somebody", creds["user"])
1952
 
        self.assertEquals("stub1", creds["password"])
1953
 
 
1954
1563
 
1955
1564
class TestPlainTextCredentialStore(tests.TestCase):
1956
1565