/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

(vila) Skip test for bug 488519 on OS X (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
from cStringIO import StringIO
20
20
import os
21
21
import sys
 
22
import threading
 
23
 
 
24
 
 
25
from testtools import matchers
22
26
 
23
27
#import bzrlib specific imports here
24
28
from bzrlib import (
35
39
    trace,
36
40
    transport,
37
41
    )
 
42
from bzrlib.tests import (
 
43
    features,
 
44
    scenarios,
 
45
    )
38
46
from bzrlib.util.configobj import configobj
39
47
 
40
48
 
 
49
def lockable_config_scenarios():
 
50
    return [
 
51
        ('global',
 
52
         {'config_class': config.GlobalConfig,
 
53
          'config_args': [],
 
54
          'config_section': 'DEFAULT'}),
 
55
        ('locations',
 
56
         {'config_class': config.LocationConfig,
 
57
          'config_args': ['.'],
 
58
          'config_section': '.'}),]
 
59
 
 
60
 
 
61
load_tests = scenarios.load_tests_apply_scenarios
 
62
 
 
63
 
41
64
sample_long_alias="log -r-15..-1 --line"
42
65
sample_config_text = u"""
43
66
[DEFAULT]
105
128
"""
106
129
 
107
130
 
 
131
def create_configs(test):
 
132
    """Create configuration files for a given test.
 
133
 
 
134
    This requires creating a tree (and populate the ``test.tree`` attribute)
 
135
    and its associated branch and will populate the following attributes:
 
136
 
 
137
    - branch_config: A BranchConfig for the associated branch.
 
138
 
 
139
    - locations_config : A LocationConfig for the associated branch
 
140
 
 
141
    - bazaar_config: A GlobalConfig.
 
142
 
 
143
    The tree and branch are created in a 'tree' subdirectory so the tests can
 
144
    still use the test directory to stay outside of the branch.
 
145
    """
 
146
    tree = test.make_branch_and_tree('tree')
 
147
    test.tree = tree
 
148
    test.branch_config = config.BranchConfig(tree.branch)
 
149
    test.locations_config = config.LocationConfig(tree.basedir)
 
150
    test.bazaar_config = config.GlobalConfig()
 
151
 
 
152
 
 
153
def create_configs_with_file_option(test):
 
154
    """Create configuration files with a ``file`` option set in each.
 
155
 
 
156
    This builds on ``create_configs`` and add one ``file`` option in each
 
157
    configuration with a value which allows identifying the configuration file.
 
158
    """
 
159
    create_configs(test)
 
160
    test.bazaar_config.set_user_option('file', 'bazaar')
 
161
    test.locations_config.set_user_option('file', 'locations')
 
162
    test.branch_config.set_user_option('file', 'branch')
 
163
 
 
164
 
 
165
class TestOptionsMixin:
 
166
 
 
167
    def assertOptions(self, expected, conf):
 
168
        # We don't care about the parser (as it will make tests hard to write
 
169
        # and error-prone anyway)
 
170
        self.assertThat([opt[:4] for opt in conf._get_options()],
 
171
                        matchers.Equals(expected))
 
172
 
 
173
 
108
174
class InstrumentedConfigObj(object):
109
175
    """A config obj look-enough-alike to record calls made to it."""
110
176
 
129
195
        self._calls.append(('keys',))
130
196
        return []
131
197
 
 
198
    def reload(self):
 
199
        self._calls.append(('reload',))
 
200
 
132
201
    def write(self, arg):
133
202
        self._calls.append(('write',))
134
203
 
350
419
        self.assertEqual(config.config_filename(),
351
420
                         self.bzr_home + '/bazaar.conf')
352
421
 
353
 
    def test_branches_config_filename(self):
354
 
        self.assertEqual(config.branches_config_filename(),
355
 
                         self.bzr_home + '/branches.conf')
356
 
 
357
422
    def test_locations_config_filename(self):
358
423
        self.assertEqual(config.locations_config_filename(),
359
424
                         self.bzr_home + '/locations.conf')
367
432
            '/home/bogus/.cache')
368
433
 
369
434
 
370
 
class TestIniConfig(tests.TestCase):
 
435
class TestXDGConfigDir(tests.TestCaseInTempDir):
 
436
    # must be in temp dir because config tests for the existence of the bazaar
 
437
    # subdirectory of $XDG_CONFIG_HOME
 
438
 
 
439
    def setUp(self):
 
440
        if sys.platform in ('darwin', 'win32'):
 
441
            raise tests.TestNotApplicable(
 
442
                'XDG config dir not used on this platform')
 
443
        super(TestXDGConfigDir, self).setUp()
 
444
        os.environ['HOME'] = self.test_home_dir
 
445
        # BZR_HOME overrides everything we want to test so unset it.
 
446
        del os.environ['BZR_HOME']
 
447
 
 
448
    def test_xdg_config_dir_exists(self):
 
449
        """When ~/.config/bazaar exists, use it as the config dir."""
 
450
        newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
 
451
        os.makedirs(newdir)
 
452
        self.assertEqual(config.config_dir(), newdir)
 
453
 
 
454
    def test_xdg_config_home(self):
 
455
        """When XDG_CONFIG_HOME is set, use it."""
 
456
        xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
 
457
        os.environ['XDG_CONFIG_HOME'] = xdgconfigdir
 
458
        newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
 
459
        os.makedirs(newdir)
 
460
        self.assertEqual(config.config_dir(), newdir)
 
461
 
 
462
 
 
463
class TestIniConfig(tests.TestCaseInTempDir):
371
464
 
372
465
    def make_config_parser(self, s):
373
 
        conf = config.IniBasedConfig(None)
374
 
        parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
375
 
        return conf, parser
 
466
        conf = config.IniBasedConfig.from_string(s)
 
467
        return conf, conf._get_parser()
376
468
 
377
469
 
378
470
class TestIniConfigBuilding(TestIniConfig):
379
471
 
380
472
    def test_contructs(self):
381
 
        my_config = config.IniBasedConfig("nothing")
 
473
        my_config = config.IniBasedConfig()
382
474
 
383
475
    def test_from_fp(self):
384
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
385
 
        my_config = config.IniBasedConfig(None)
386
 
        self.failUnless(
387
 
            isinstance(my_config._get_parser(file=config_file),
388
 
                        configobj.ConfigObj))
 
476
        my_config = config.IniBasedConfig.from_string(sample_config_text)
 
477
        self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
389
478
 
390
479
    def test_cached(self):
391
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
392
 
        my_config = config.IniBasedConfig(None)
393
 
        parser = my_config._get_parser(file=config_file)
 
480
        my_config = config.IniBasedConfig.from_string(sample_config_text)
 
481
        parser = my_config._get_parser()
394
482
        self.failUnless(my_config._get_parser() is parser)
395
483
 
 
484
    def _dummy_chown(self, path, uid, gid):
 
485
        self.path, self.uid, self.gid = path, uid, gid
 
486
 
 
487
    def test_ini_config_ownership(self):
 
488
        """Ensure that chown is happening during _write_config_file"""
 
489
        self.requireFeature(features.chown_feature)
 
490
        self.overrideAttr(os, 'chown', self._dummy_chown)
 
491
        self.path = self.uid = self.gid = None
 
492
        conf = config.IniBasedConfig(file_name='./foo.conf')
 
493
        conf._write_config_file()
 
494
        self.assertEquals(self.path, './foo.conf')
 
495
        self.assertTrue(isinstance(self.uid, int))
 
496
        self.assertTrue(isinstance(self.gid, int))
 
497
 
 
498
    def test_get_filename_parameter_is_deprecated_(self):
 
499
        conf = self.callDeprecated([
 
500
            'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
 
501
            ' Use file_name instead.'],
 
502
            config.IniBasedConfig, lambda: 'ini.conf')
 
503
        self.assertEqual('ini.conf', conf.file_name)
 
504
 
 
505
    def test_get_parser_file_parameter_is_deprecated_(self):
 
506
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
507
        conf = config.IniBasedConfig.from_string(sample_config_text)
 
508
        conf = self.callDeprecated([
 
509
            'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
 
510
            ' Use IniBasedConfig(_content=xxx) instead.'],
 
511
            conf._get_parser, file=config_file)
 
512
 
 
513
class TestIniConfigSaving(tests.TestCaseInTempDir):
 
514
 
 
515
    def test_cant_save_without_a_file_name(self):
 
516
        conf = config.IniBasedConfig()
 
517
        self.assertRaises(AssertionError, conf._write_config_file)
 
518
 
 
519
    def test_saved_with_content(self):
 
520
        content = 'foo = bar\n'
 
521
        conf = config.IniBasedConfig.from_string(
 
522
            content, file_name='./test.conf', save=True)
 
523
        self.assertFileEqual(content, 'test.conf')
 
524
 
 
525
 
 
526
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
 
527
 
 
528
    def test_cannot_reload_without_name(self):
 
529
        conf = config.IniBasedConfig.from_string(sample_config_text)
 
530
        self.assertRaises(AssertionError, conf.reload)
 
531
 
 
532
    def test_reload_see_new_value(self):
 
533
        c1 = config.IniBasedConfig.from_string('editor=vim\n',
 
534
                                               file_name='./test/conf')
 
535
        c1._write_config_file()
 
536
        c2 = config.IniBasedConfig.from_string('editor=emacs\n',
 
537
                                               file_name='./test/conf')
 
538
        c2._write_config_file()
 
539
        self.assertEqual('vim', c1.get_user_option('editor'))
 
540
        self.assertEqual('emacs', c2.get_user_option('editor'))
 
541
        # Make sure we get the Right value
 
542
        c1.reload()
 
543
        self.assertEqual('emacs', c1.get_user_option('editor'))
 
544
 
 
545
 
 
546
class TestLockableConfig(tests.TestCaseInTempDir):
 
547
 
 
548
    scenarios = lockable_config_scenarios()
 
549
 
 
550
    # Set by load_tests
 
551
    config_class = None
 
552
    config_args = None
 
553
    config_section = None
 
554
 
 
555
    def setUp(self):
 
556
        super(TestLockableConfig, self).setUp()
 
557
        self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
 
558
        self.config = self.create_config(self._content)
 
559
 
 
560
    def get_existing_config(self):
 
561
        return self.config_class(*self.config_args)
 
562
 
 
563
    def create_config(self, content):
 
564
        kwargs = dict(save=True)
 
565
        c = self.config_class.from_string(content, *self.config_args, **kwargs)
 
566
        return c
 
567
 
 
568
    def test_simple_read_access(self):
 
569
        self.assertEquals('1', self.config.get_user_option('one'))
 
570
 
 
571
    def test_simple_write_access(self):
 
572
        self.config.set_user_option('one', 'one')
 
573
        self.assertEquals('one', self.config.get_user_option('one'))
 
574
 
 
575
    def test_listen_to_the_last_speaker(self):
 
576
        c1 = self.config
 
577
        c2 = self.get_existing_config()
 
578
        c1.set_user_option('one', 'ONE')
 
579
        c2.set_user_option('two', 'TWO')
 
580
        self.assertEquals('ONE', c1.get_user_option('one'))
 
581
        self.assertEquals('TWO', c2.get_user_option('two'))
 
582
        # The second update respect the first one
 
583
        self.assertEquals('ONE', c2.get_user_option('one'))
 
584
 
 
585
    def test_last_speaker_wins(self):
 
586
        # If the same config is not shared, the same variable modified twice
 
587
        # can only see a single result.
 
588
        c1 = self.config
 
589
        c2 = self.get_existing_config()
 
590
        c1.set_user_option('one', 'c1')
 
591
        c2.set_user_option('one', 'c2')
 
592
        self.assertEquals('c2', c2._get_user_option('one'))
 
593
        # The first modification is still available until another refresh
 
594
        # occur
 
595
        self.assertEquals('c1', c1._get_user_option('one'))
 
596
        c1.set_user_option('two', 'done')
 
597
        self.assertEquals('c2', c1._get_user_option('one'))
 
598
 
 
599
    def test_writes_are_serialized(self):
 
600
        c1 = self.config
 
601
        c2 = self.get_existing_config()
 
602
 
 
603
        # We spawn a thread that will pause *during* the write
 
604
        before_writing = threading.Event()
 
605
        after_writing = threading.Event()
 
606
        writing_done = threading.Event()
 
607
        c1_orig = c1._write_config_file
 
608
        def c1_write_config_file():
 
609
            before_writing.set()
 
610
            c1_orig()
 
611
            # The lock is held we wait for the main thread to decide when to
 
612
            # continue
 
613
            after_writing.wait()
 
614
        c1._write_config_file = c1_write_config_file
 
615
        def c1_set_option():
 
616
            c1.set_user_option('one', 'c1')
 
617
            writing_done.set()
 
618
        t1 = threading.Thread(target=c1_set_option)
 
619
        # Collect the thread after the test
 
620
        self.addCleanup(t1.join)
 
621
        # Be ready to unblock the thread if the test goes wrong
 
622
        self.addCleanup(after_writing.set)
 
623
        t1.start()
 
624
        before_writing.wait()
 
625
        self.assertTrue(c1._lock.is_held)
 
626
        self.assertRaises(errors.LockContention,
 
627
                          c2.set_user_option, 'one', 'c2')
 
628
        self.assertEquals('c1', c1.get_user_option('one'))
 
629
        # Let the lock be released
 
630
        after_writing.set()
 
631
        writing_done.wait()
 
632
        c2.set_user_option('one', 'c2')
 
633
        self.assertEquals('c2', c2.get_user_option('one'))
 
634
 
 
635
    def test_read_while_writing(self):
 
636
       c1 = self.config
 
637
       # We spawn a thread that will pause *during* the write
 
638
       ready_to_write = threading.Event()
 
639
       do_writing = threading.Event()
 
640
       writing_done = threading.Event()
 
641
       c1_orig = c1._write_config_file
 
642
       def c1_write_config_file():
 
643
           ready_to_write.set()
 
644
           # The lock is held we wait for the main thread to decide when to
 
645
           # continue
 
646
           do_writing.wait()
 
647
           c1_orig()
 
648
           writing_done.set()
 
649
       c1._write_config_file = c1_write_config_file
 
650
       def c1_set_option():
 
651
           c1.set_user_option('one', 'c1')
 
652
       t1 = threading.Thread(target=c1_set_option)
 
653
       # Collect the thread after the test
 
654
       self.addCleanup(t1.join)
 
655
       # Be ready to unblock the thread if the test goes wrong
 
656
       self.addCleanup(do_writing.set)
 
657
       t1.start()
 
658
       # Ensure the thread is ready to write
 
659
       ready_to_write.wait()
 
660
       self.assertTrue(c1._lock.is_held)
 
661
       self.assertEquals('c1', c1.get_user_option('one'))
 
662
       # If we read during the write, we get the old value
 
663
       c2 = self.get_existing_config()
 
664
       self.assertEquals('1', c2.get_user_option('one'))
 
665
       # Let the writing occur and ensure it occurred
 
666
       do_writing.set()
 
667
       writing_done.wait()
 
668
       # Now we get the updated value
 
669
       c3 = self.get_existing_config()
 
670
       self.assertEquals('c1', c3.get_user_option('one'))
 
671
 
396
672
 
397
673
class TestGetUserOptionAs(TestIniConfig):
398
674
 
505
781
        branch = self.make_branch('branch')
506
782
        self.assertEqual('branch', branch.nick)
507
783
 
508
 
        locations = config.locations_config_filename()
509
 
        config.ensure_config_dir_exists()
510
784
        local_url = urlutils.local_path_to_url('branch')
511
 
        open(locations, 'wb').write('[%s]\nnickname = foobar'
512
 
                                    % (local_url,))
 
785
        conf = config.LocationConfig.from_string(
 
786
            '[%s]\nnickname = foobar' % (local_url,),
 
787
            local_url, save=True)
513
788
        self.assertEqual('foobar', branch.nick)
514
789
 
515
790
    def test_config_local_path(self):
517
792
        branch = self.make_branch('branch')
518
793
        self.assertEqual('branch', branch.nick)
519
794
 
520
 
        locations = config.locations_config_filename()
521
 
        config.ensure_config_dir_exists()
522
 
        open(locations, 'wb').write('[%s/branch]\nnickname = barry'
523
 
                                    % (osutils.getcwd().encode('utf8'),))
 
795
        local_path = osutils.getcwd().encode('utf8')
 
796
        conf = config.LocationConfig.from_string(
 
797
            '[%s/branch]\nnickname = barry' % (local_path,),
 
798
            'branch',  save=True)
524
799
        self.assertEqual('barry', branch.nick)
525
800
 
526
801
    def test_config_creates_local(self):
527
802
        """Creating a new entry in config uses a local path."""
528
803
        branch = self.make_branch('branch', format='knit')
529
804
        branch.set_push_location('http://foobar')
530
 
        locations = config.locations_config_filename()
531
805
        local_path = osutils.getcwd().encode('utf8')
532
806
        # Surprisingly ConfigObj doesn't create a trailing newline
533
 
        self.check_file_contents(locations,
 
807
        self.check_file_contents(config.locations_config_filename(),
534
808
                                 '[%s/branch]\n'
535
809
                                 'push_location = http://foobar\n'
536
810
                                 'push_location:policy = norecurse\n'
541
815
        self.assertEqual('!repo', b.get_config().get_nickname())
542
816
 
543
817
    def test_warn_if_masked(self):
544
 
        _warning = trace.warning
545
818
        warnings = []
546
819
        def warning(*args):
547
820
            warnings.append(args[0] % args[1:])
 
821
        self.overrideAttr(trace, 'warning', warning)
548
822
 
549
823
        def set_option(store, warn_masked=True):
550
824
            warnings[:] = []
556
830
            else:
557
831
                self.assertEqual(1, len(warnings))
558
832
                self.assertEqual(warning, warnings[0])
559
 
        trace.warning = warning
560
 
        try:
561
 
            branch = self.make_branch('.')
562
 
            conf = branch.get_config()
563
 
            set_option(config.STORE_GLOBAL)
564
 
            assertWarning(None)
565
 
            set_option(config.STORE_BRANCH)
566
 
            assertWarning(None)
567
 
            set_option(config.STORE_GLOBAL)
568
 
            assertWarning('Value "4" is masked by "3" from branch.conf')
569
 
            set_option(config.STORE_GLOBAL, warn_masked=False)
570
 
            assertWarning(None)
571
 
            set_option(config.STORE_LOCATION)
572
 
            assertWarning(None)
573
 
            set_option(config.STORE_BRANCH)
574
 
            assertWarning('Value "3" is masked by "0" from locations.conf')
575
 
            set_option(config.STORE_BRANCH, warn_masked=False)
576
 
            assertWarning(None)
577
 
        finally:
578
 
            trace.warning = _warning
579
 
 
580
 
 
581
 
class TestGlobalConfigItems(tests.TestCase):
 
833
        branch = self.make_branch('.')
 
834
        conf = branch.get_config()
 
835
        set_option(config.STORE_GLOBAL)
 
836
        assertWarning(None)
 
837
        set_option(config.STORE_BRANCH)
 
838
        assertWarning(None)
 
839
        set_option(config.STORE_GLOBAL)
 
840
        assertWarning('Value "4" is masked by "3" from branch.conf')
 
841
        set_option(config.STORE_GLOBAL, warn_masked=False)
 
842
        assertWarning(None)
 
843
        set_option(config.STORE_LOCATION)
 
844
        assertWarning(None)
 
845
        set_option(config.STORE_BRANCH)
 
846
        assertWarning('Value "3" is masked by "0" from locations.conf')
 
847
        set_option(config.STORE_BRANCH, warn_masked=False)
 
848
        assertWarning(None)
 
849
 
 
850
 
 
851
class TestGlobalConfigItems(tests.TestCaseInTempDir):
582
852
 
583
853
    def test_user_id(self):
584
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
585
 
        my_config = config.GlobalConfig()
586
 
        my_config._parser = my_config._get_parser(file=config_file)
 
854
        my_config = config.GlobalConfig.from_string(sample_config_text)
587
855
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
588
856
                         my_config._get_user_id())
589
857
 
590
858
    def test_absent_user_id(self):
591
 
        config_file = StringIO("")
592
859
        my_config = config.GlobalConfig()
593
 
        my_config._parser = my_config._get_parser(file=config_file)
594
860
        self.assertEqual(None, my_config._get_user_id())
595
861
 
596
862
    def test_configured_editor(self):
597
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
598
 
        my_config = config.GlobalConfig()
599
 
        my_config._parser = my_config._get_parser(file=config_file)
 
863
        my_config = config.GlobalConfig.from_string(sample_config_text)
600
864
        self.assertEqual("vim", my_config.get_editor())
601
865
 
602
866
    def test_signatures_always(self):
603
 
        config_file = StringIO(sample_always_signatures)
604
 
        my_config = config.GlobalConfig()
605
 
        my_config._parser = my_config._get_parser(file=config_file)
 
867
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
606
868
        self.assertEqual(config.CHECK_NEVER,
607
869
                         my_config.signature_checking())
608
870
        self.assertEqual(config.SIGN_ALWAYS,
610
872
        self.assertEqual(True, my_config.signature_needed())
611
873
 
612
874
    def test_signatures_if_possible(self):
613
 
        config_file = StringIO(sample_maybe_signatures)
614
 
        my_config = config.GlobalConfig()
615
 
        my_config._parser = my_config._get_parser(file=config_file)
 
875
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
616
876
        self.assertEqual(config.CHECK_NEVER,
617
877
                         my_config.signature_checking())
618
878
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
620
880
        self.assertEqual(False, my_config.signature_needed())
621
881
 
622
882
    def test_signatures_ignore(self):
623
 
        config_file = StringIO(sample_ignore_signatures)
624
 
        my_config = config.GlobalConfig()
625
 
        my_config._parser = my_config._get_parser(file=config_file)
 
883
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
626
884
        self.assertEqual(config.CHECK_ALWAYS,
627
885
                         my_config.signature_checking())
628
886
        self.assertEqual(config.SIGN_NEVER,
630
888
        self.assertEqual(False, my_config.signature_needed())
631
889
 
632
890
    def _get_sample_config(self):
633
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
634
 
        my_config = config.GlobalConfig()
635
 
        my_config._parser = my_config._get_parser(file=config_file)
 
891
        my_config = config.GlobalConfig.from_string(sample_config_text)
636
892
        return my_config
637
893
 
638
894
    def test_gpg_signing_command(self):
641
897
        self.assertEqual(False, my_config.signature_needed())
642
898
 
643
899
    def _get_empty_config(self):
644
 
        config_file = StringIO("")
645
900
        my_config = config.GlobalConfig()
646
 
        my_config._parser = my_config._get_parser(file=config_file)
647
901
        return my_config
648
902
 
649
903
    def test_gpg_signing_command_unset(self):
722
976
        self.assertIs(None, new_config.get_alias('commit'))
723
977
 
724
978
 
725
 
class TestLocationConfig(tests.TestCaseInTempDir):
 
979
class TestLocationConfig(tests.TestCaseInTempDir, TestOptionsMixin):
726
980
 
727
981
    def test_constructs(self):
728
982
        my_config = config.LocationConfig('http://example.com')
744
998
        self.assertEqual(parser._calls,
745
999
                         [('__init__', config.locations_config_filename(),
746
1000
                           'utf-8')])
747
 
        config.ensure_config_dir_exists()
748
 
        #os.mkdir(config.config_dir())
749
 
        f = file(config.branches_config_filename(), 'wb')
750
 
        f.write('')
751
 
        f.close()
752
 
        oldparserclass = config.ConfigObj
753
 
        config.ConfigObj = InstrumentedConfigObj
754
 
        try:
755
 
            my_config = config.LocationConfig('http://www.example.com')
756
 
            parser = my_config._get_parser()
757
 
        finally:
758
 
            config.ConfigObj = oldparserclass
759
1001
 
760
1002
    def test_get_global_config(self):
761
1003
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
848
1090
            'http://www.example.com', 'appendpath_option'),
849
1091
            config.POLICY_APPENDPATH)
850
1092
 
 
1093
    def test__get_options_with_policy(self):
 
1094
        self.get_branch_config('/dir/subdir',
 
1095
                               location_config="""\
 
1096
[/dir]
 
1097
other_url = /other-dir
 
1098
other_url:policy = appendpath
 
1099
[/dir/subdir]
 
1100
other_url = /other-subdir
 
1101
""")
 
1102
        self.assertOptions(
 
1103
            [(u'other_url', u'/other-subdir', u'/dir/subdir', 'locations'),
 
1104
             (u'other_url', u'/other-dir', u'/dir', 'locations'),
 
1105
             (u'other_url:policy', u'appendpath', u'/dir', 'locations')],
 
1106
            self.my_location_config)
 
1107
 
851
1108
    def test_location_without_username(self):
852
1109
        self.get_branch_config('http://www.example.com/ignoreparent')
853
1110
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
989
1246
        self.assertEqual('bzrlib.tests.test_config.post_commit',
990
1247
                         self.my_config.post_commit())
991
1248
 
992
 
    def get_branch_config(self, location, global_config=None):
 
1249
    def get_branch_config(self, location, global_config=None,
 
1250
                          location_config=None):
 
1251
        my_branch = FakeBranch(location)
993
1252
        if global_config is None:
994
 
            global_file = StringIO(sample_config_text.encode('utf-8'))
995
 
        else:
996
 
            global_file = StringIO(global_config.encode('utf-8'))
997
 
        branches_file = StringIO(sample_branches_text.encode('utf-8'))
998
 
        self.my_config = config.BranchConfig(FakeBranch(location))
999
 
        # Force location config to use specified file
1000
 
        self.my_location_config = self.my_config._get_location_config()
1001
 
        self.my_location_config._get_parser(branches_file)
1002
 
        # Force global config to use specified file
1003
 
        self.my_config._get_global_config()._get_parser(global_file)
 
1253
            global_config = sample_config_text
 
1254
        if location_config is None:
 
1255
            location_config = sample_branches_text
 
1256
 
 
1257
        my_global_config = config.GlobalConfig.from_string(global_config,
 
1258
                                                           save=True)
 
1259
        my_location_config = config.LocationConfig.from_string(
 
1260
            location_config, my_branch.base, save=True)
 
1261
        my_config = config.BranchConfig(my_branch)
 
1262
        self.my_config = my_config
 
1263
        self.my_location_config = my_config._get_location_config()
1004
1264
 
1005
1265
    def test_set_user_setting_sets_and_saves(self):
1006
1266
        self.get_branch_config('/a/c')
1007
1267
        record = InstrumentedConfigObj("foo")
1008
1268
        self.my_location_config._parser = record
1009
1269
 
1010
 
        real_mkdir = os.mkdir
1011
 
        self.created = False
1012
 
        def checked_mkdir(path, mode=0777):
1013
 
            self.log('making directory: %s', path)
1014
 
            real_mkdir(path, mode)
1015
 
            self.created = True
1016
 
 
1017
 
        os.mkdir = checked_mkdir
1018
 
        try:
1019
 
            self.callDeprecated(['The recurse option is deprecated as of '
1020
 
                                 '0.14.  The section "/a/c" has been '
1021
 
                                 'converted to use policies.'],
1022
 
                                self.my_config.set_user_option,
1023
 
                                'foo', 'bar', store=config.STORE_LOCATION)
1024
 
        finally:
1025
 
            os.mkdir = real_mkdir
1026
 
 
1027
 
        self.failUnless(self.created, 'Failed to create ~/.bazaar')
1028
 
        self.assertEqual([('__contains__', '/a/c'),
 
1270
        self.callDeprecated(['The recurse option is deprecated as of '
 
1271
                             '0.14.  The section "/a/c" has been '
 
1272
                             'converted to use policies.'],
 
1273
                            self.my_config.set_user_option,
 
1274
                            'foo', 'bar', store=config.STORE_LOCATION)
 
1275
        self.assertEqual([('reload',),
 
1276
                          ('__contains__', '/a/c'),
1029
1277
                          ('__contains__', '/a/c/'),
1030
1278
                          ('__setitem__', '/a/c', {}),
1031
1279
                          ('__getitem__', '/a/c'),
1074
1322
option = exact
1075
1323
"""
1076
1324
 
1077
 
 
1078
1325
class TestBranchConfigItems(tests.TestCaseInTempDir):
1079
1326
 
1080
1327
    def get_branch_config(self, global_config=None, location=None,
1081
1328
                          location_config=None, branch_data_config=None):
1082
 
        my_config = config.BranchConfig(FakeBranch(location))
 
1329
        my_branch = FakeBranch(location)
1083
1330
        if global_config is not None:
1084
 
            global_file = StringIO(global_config.encode('utf-8'))
1085
 
            my_config._get_global_config()._get_parser(global_file)
1086
 
        self.my_location_config = my_config._get_location_config()
 
1331
            my_global_config = config.GlobalConfig.from_string(global_config,
 
1332
                                                               save=True)
1087
1333
        if location_config is not None:
1088
 
            location_file = StringIO(location_config.encode('utf-8'))
1089
 
            self.my_location_config._get_parser(location_file)
 
1334
            my_location_config = config.LocationConfig.from_string(
 
1335
                location_config, my_branch.base, save=True)
 
1336
        my_config = config.BranchConfig(my_branch)
1090
1337
        if branch_data_config is not None:
1091
1338
            my_config.branch.control_files.files['branch.conf'] = \
1092
1339
                branch_data_config
1106
1353
                         my_config.username())
1107
1354
 
1108
1355
    def test_not_set_in_branch(self):
1109
 
        my_config = self.get_branch_config(sample_config_text)
 
1356
        my_config = self.get_branch_config(global_config=sample_config_text)
1110
1357
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
1111
1358
                         my_config._get_user_id())
1112
1359
        my_config.branch.control_files.files['email'] = "John"
1136
1383
 
1137
1384
    def test_gpg_signing_command(self):
1138
1385
        my_config = self.get_branch_config(
 
1386
            global_config=sample_config_text,
1139
1387
            # branch data cannot set gpg_signing_command
1140
1388
            branch_data_config="gpg_signing_command=pgp")
1141
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
1142
 
        my_config._get_global_config()._get_parser(config_file)
1143
1389
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1144
1390
 
1145
1391
    def test_get_user_option_global(self):
1146
 
        branch = FakeBranch()
1147
 
        my_config = config.BranchConfig(branch)
1148
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
1149
 
        (my_config._get_global_config()._get_parser(config_file))
 
1392
        my_config = self.get_branch_config(global_config=sample_config_text)
1150
1393
        self.assertEqual('something',
1151
1394
                         my_config.get_user_option('user_global_option'))
1152
1395
 
1153
1396
    def test_post_commit_default(self):
1154
 
        branch = FakeBranch()
1155
 
        my_config = self.get_branch_config(sample_config_text, '/a/c',
1156
 
                                           sample_branches_text)
 
1397
        my_config = self.get_branch_config(global_config=sample_config_text,
 
1398
                                      location='/a/c',
 
1399
                                      location_config=sample_branches_text)
1157
1400
        self.assertEqual(my_config.branch.base, '/a/c')
1158
1401
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1159
1402
                         my_config.post_commit())
1160
1403
        my_config.set_user_option('post_commit', 'rmtree_root')
1161
 
        # post-commit is ignored when bresent in branch data
 
1404
        # post-commit is ignored when present in branch data
1162
1405
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1163
1406
                         my_config.post_commit())
1164
1407
        my_config.set_user_option('post_commit', 'rmtree_root',
1166
1409
        self.assertEqual('rmtree_root', my_config.post_commit())
1167
1410
 
1168
1411
    def test_config_precedence(self):
 
1412
        # FIXME: eager test, luckily no persitent config file makes it fail
 
1413
        # -- vila 20100716
1169
1414
        my_config = self.get_branch_config(global_config=precedence_global)
1170
1415
        self.assertEqual(my_config.get_user_option('option'), 'global')
1171
1416
        my_config = self.get_branch_config(global_config=precedence_global,
1172
 
                                      branch_data_config=precedence_branch)
 
1417
                                           branch_data_config=precedence_branch)
1173
1418
        self.assertEqual(my_config.get_user_option('option'), 'branch')
1174
 
        my_config = self.get_branch_config(global_config=precedence_global,
1175
 
                                      branch_data_config=precedence_branch,
1176
 
                                      location_config=precedence_location)
 
1419
        my_config = self.get_branch_config(
 
1420
            global_config=precedence_global,
 
1421
            branch_data_config=precedence_branch,
 
1422
            location_config=precedence_location)
1177
1423
        self.assertEqual(my_config.get_user_option('option'), 'recurse')
1178
 
        my_config = self.get_branch_config(global_config=precedence_global,
1179
 
                                      branch_data_config=precedence_branch,
1180
 
                                      location_config=precedence_location,
1181
 
                                      location='http://example.com/specific')
 
1424
        my_config = self.get_branch_config(
 
1425
            global_config=precedence_global,
 
1426
            branch_data_config=precedence_branch,
 
1427
            location_config=precedence_location,
 
1428
            location='http://example.com/specific')
1182
1429
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1183
1430
 
1184
1431
    def test_get_mail_client(self):
1312
1559
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1313
1560
 
1314
1561
 
 
1562
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
 
1563
 
 
1564
    def setUp(self):
 
1565
        super(TestConfigGetOptions, self).setUp()
 
1566
        create_configs(self)
 
1567
 
 
1568
    # One variable in none of the above
 
1569
    def test_no_variable(self):
 
1570
        # Using branch should query branch, locations and bazaar
 
1571
        self.assertOptions([], self.branch_config)
 
1572
 
 
1573
    def test_option_in_bazaar(self):
 
1574
        self.bazaar_config.set_user_option('file', 'bazaar')
 
1575
        self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
 
1576
                           self.bazaar_config)
 
1577
 
 
1578
    def test_option_in_locations(self):
 
1579
        self.locations_config.set_user_option('file', 'locations')
 
1580
        self.assertOptions(
 
1581
            [('file', 'locations', self.tree.basedir, 'locations')],
 
1582
            self.locations_config)
 
1583
 
 
1584
    def test_option_in_branch(self):
 
1585
        self.branch_config.set_user_option('file', 'branch')
 
1586
        self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
 
1587
                           self.branch_config)
 
1588
 
 
1589
    def test_option_in_bazaar_and_branch(self):
 
1590
        self.bazaar_config.set_user_option('file', 'bazaar')
 
1591
        self.branch_config.set_user_option('file', 'branch')
 
1592
        self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
 
1593
                            ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
 
1594
                           self.branch_config)
 
1595
 
 
1596
    def test_option_in_branch_and_locations(self):
 
1597
        # Hmm, locations override branch :-/
 
1598
        self.locations_config.set_user_option('file', 'locations')
 
1599
        self.branch_config.set_user_option('file', 'branch')
 
1600
        self.assertOptions(
 
1601
            [('file', 'locations', self.tree.basedir, 'locations'),
 
1602
             ('file', 'branch', 'DEFAULT', 'branch'),],
 
1603
            self.branch_config)
 
1604
 
 
1605
    def test_option_in_bazaar_locations_and_branch(self):
 
1606
        self.bazaar_config.set_user_option('file', 'bazaar')
 
1607
        self.locations_config.set_user_option('file', 'locations')
 
1608
        self.branch_config.set_user_option('file', 'branch')
 
1609
        self.assertOptions(
 
1610
            [('file', 'locations', self.tree.basedir, 'locations'),
 
1611
             ('file', 'branch', 'DEFAULT', 'branch'),
 
1612
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
 
1613
            self.branch_config)
 
1614
 
 
1615
 
 
1616
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
 
1617
 
 
1618
    def setUp(self):
 
1619
        super(TestConfigRemoveOption, self).setUp()
 
1620
        create_configs_with_file_option(self)
 
1621
 
 
1622
    def test_remove_in_locations(self):
 
1623
        self.locations_config.remove_user_option('file', self.tree.basedir)
 
1624
        self.assertOptions(
 
1625
            [('file', 'branch', 'DEFAULT', 'branch'),
 
1626
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
 
1627
            self.branch_config)
 
1628
 
 
1629
    def test_remove_in_branch(self):
 
1630
        self.branch_config.remove_user_option('file')
 
1631
        self.assertOptions(
 
1632
            [('file', 'locations', self.tree.basedir, 'locations'),
 
1633
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
 
1634
            self.branch_config)
 
1635
 
 
1636
    def test_remove_in_bazaar(self):
 
1637
        self.bazaar_config.remove_user_option('file')
 
1638
        self.assertOptions(
 
1639
            [('file', 'locations', self.tree.basedir, 'locations'),
 
1640
             ('file', 'branch', 'DEFAULT', 'branch'),],
 
1641
            self.branch_config)
 
1642
 
 
1643
 
 
1644
class TestConfigGetSections(tests.TestCaseWithTransport):
 
1645
 
 
1646
    def setUp(self):
 
1647
        super(TestConfigGetSections, self).setUp()
 
1648
        create_configs(self)
 
1649
 
 
1650
    def assertSectionNames(self, expected, conf, name=None):
 
1651
        """Check which sections are returned for a given config.
 
1652
 
 
1653
        If fallback configurations exist their sections can be included.
 
1654
 
 
1655
        :param expected: A list of section names.
 
1656
 
 
1657
        :param conf: The configuration that will be queried.
 
1658
 
 
1659
        :param name: An optional section name that will be passed to
 
1660
            get_sections().
 
1661
        """
 
1662
        sections = list(conf._get_sections(name))
 
1663
        self.assertLength(len(expected), sections)
 
1664
        self.assertEqual(expected, [name for name, _, _ in sections])
 
1665
 
 
1666
    def test_bazaar_default_section(self):
 
1667
        self.assertSectionNames(['DEFAULT'], self.bazaar_config)
 
1668
 
 
1669
    def test_locations_default_section(self):
 
1670
        # No sections are defined in an empty file
 
1671
        self.assertSectionNames([], self.locations_config)
 
1672
 
 
1673
    def test_locations_named_section(self):
 
1674
        self.locations_config.set_user_option('file', 'locations')
 
1675
        self.assertSectionNames([self.tree.basedir], self.locations_config)
 
1676
 
 
1677
    def test_locations_matching_sections(self):
 
1678
        loc_config = self.locations_config
 
1679
        loc_config.set_user_option('file', 'locations')
 
1680
        # We need to cheat a bit here to create an option in sections above and
 
1681
        # below the 'location' one.
 
1682
        parser = loc_config._get_parser()
 
1683
        # locations.cong deals with '/' ignoring native os.sep
 
1684
        location_names = self.tree.basedir.split('/')
 
1685
        parent = '/'.join(location_names[:-1])
 
1686
        child = '/'.join(location_names + ['child'])
 
1687
        parser[parent] = {}
 
1688
        parser[parent]['file'] = 'parent'
 
1689
        parser[child] = {}
 
1690
        parser[child]['file'] = 'child'
 
1691
        self.assertSectionNames([self.tree.basedir, parent], loc_config)
 
1692
 
 
1693
    def test_branch_data_default_section(self):
 
1694
        self.assertSectionNames([None],
 
1695
                                self.branch_config._get_branch_data_config())
 
1696
 
 
1697
    def test_branch_default_sections(self):
 
1698
        # No sections are defined in an empty locations file
 
1699
        self.assertSectionNames([None, 'DEFAULT'],
 
1700
                                self.branch_config)
 
1701
        # Unless we define an option
 
1702
        self.branch_config._get_location_config().set_user_option(
 
1703
            'file', 'locations')
 
1704
        self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
 
1705
                                self.branch_config)
 
1706
 
 
1707
    def test_bazaar_named_section(self):
 
1708
        # We need to cheat as the API doesn't give direct access to sections
 
1709
        # other than DEFAULT.
 
1710
        self.bazaar_config.set_alias('bazaar', 'bzr')
 
1711
        self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
 
1712
 
 
1713
 
1315
1714
class TestAuthenticationConfigFile(tests.TestCase):
1316
1715
    """Test the authentication.conf file matching"""
1317
1716