367
463
'/home/bogus/.cache')
370
class TestIniConfig(tests.TestCase):
466
class TestXDGConfigDir(tests.TestCaseInTempDir):
467
# must be in temp dir because config tests for the existence of the bazaar
468
# subdirectory of $XDG_CONFIG_HOME
471
if sys.platform in ('darwin', 'win32'):
472
raise tests.TestNotApplicable(
473
'XDG config dir not used on this platform')
474
super(TestXDGConfigDir, self).setUp()
475
self.overrideEnv('HOME', self.test_home_dir)
476
# BZR_HOME overrides everything we want to test so unset it.
477
self.overrideEnv('BZR_HOME', None)
479
def test_xdg_config_dir_exists(self):
480
"""When ~/.config/bazaar exists, use it as the config dir."""
481
newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
483
self.assertEqual(config.config_dir(), newdir)
485
def test_xdg_config_home(self):
486
"""When XDG_CONFIG_HOME is set, use it."""
487
xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
488
self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
489
newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
491
self.assertEqual(config.config_dir(), newdir)
494
class TestIniConfig(tests.TestCaseInTempDir):
372
496
def make_config_parser(self, s):
373
conf = config.IniBasedConfig(None)
374
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
497
conf = config.IniBasedConfig.from_string(s)
498
return conf, conf._get_parser()
378
501
class TestIniConfigBuilding(TestIniConfig):
380
503
def test_contructs(self):
381
my_config = config.IniBasedConfig("nothing")
504
my_config = config.IniBasedConfig()
383
506
def test_from_fp(self):
384
config_file = StringIO(sample_config_text.encode('utf-8'))
385
my_config = config.IniBasedConfig(None)
387
isinstance(my_config._get_parser(file=config_file),
388
configobj.ConfigObj))
507
my_config = config.IniBasedConfig.from_string(sample_config_text)
508
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
390
510
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)
511
my_config = config.IniBasedConfig.from_string(sample_config_text)
512
parser = my_config._get_parser()
394
513
self.failUnless(my_config._get_parser() is parser)
515
def _dummy_chown(self, path, uid, gid):
516
self.path, self.uid, self.gid = path, uid, gid
518
def test_ini_config_ownership(self):
519
"""Ensure that chown is happening during _write_config_file"""
520
self.requireFeature(features.chown_feature)
521
self.overrideAttr(os, 'chown', self._dummy_chown)
522
self.path = self.uid = self.gid = None
523
conf = config.IniBasedConfig(file_name='./foo.conf')
524
conf._write_config_file()
525
self.assertEquals(self.path, './foo.conf')
526
self.assertTrue(isinstance(self.uid, int))
527
self.assertTrue(isinstance(self.gid, int))
529
def test_get_filename_parameter_is_deprecated_(self):
530
conf = self.callDeprecated([
531
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
532
' Use file_name instead.'],
533
config.IniBasedConfig, lambda: 'ini.conf')
534
self.assertEqual('ini.conf', conf.file_name)
536
def test_get_parser_file_parameter_is_deprecated_(self):
537
config_file = StringIO(sample_config_text.encode('utf-8'))
538
conf = config.IniBasedConfig.from_string(sample_config_text)
539
conf = self.callDeprecated([
540
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
541
' Use IniBasedConfig(_content=xxx) instead.'],
542
conf._get_parser, file=config_file)
545
class TestIniConfigSaving(tests.TestCaseInTempDir):
547
def test_cant_save_without_a_file_name(self):
548
conf = config.IniBasedConfig()
549
self.assertRaises(AssertionError, conf._write_config_file)
551
def test_saved_with_content(self):
552
content = 'foo = bar\n'
553
conf = config.IniBasedConfig.from_string(
554
content, file_name='./test.conf', save=True)
555
self.assertFileEqual(content, 'test.conf')
558
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
559
"""What is the default value of expand for config options.
561
This is an opt-in beta feature used to evaluate whether or not option
562
references can appear in dangerous place raising exceptions, disapearing
563
(and as such corrupting data) or if it's safe to activate the option by
566
Note that these tests relies on config._expand_default_value being already
567
overwritten in the parent class setUp.
571
super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
575
self.warnings.append(args[0] % args[1:])
576
self.overrideAttr(trace, 'warning', warning)
578
def get_config(self, expand):
579
c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
583
def assertExpandIs(self, expected):
584
actual = config._get_expand_default_value()
585
#self.config.get_user_option_as_bool('bzr.config.expand')
586
self.assertEquals(expected, actual)
588
def test_default_is_None(self):
589
self.assertEquals(None, config._expand_default_value)
591
def test_default_is_False_even_if_None(self):
592
self.config = self.get_config(None)
593
self.assertExpandIs(False)
595
def test_default_is_False_even_if_invalid(self):
596
self.config = self.get_config('<your choice>')
597
self.assertExpandIs(False)
599
# Huh ? My choice is False ? Thanks, always happy to hear that :D
600
# Wait, you've been warned !
601
self.assertLength(1, self.warnings)
603
'Value "<your choice>" is not a boolean for "bzr.config.expand"',
606
def test_default_is_True(self):
607
self.config = self.get_config(True)
608
self.assertExpandIs(True)
610
def test_default_is_False(self):
611
self.config = self.get_config(False)
612
self.assertExpandIs(False)
615
class TestIniConfigOptionExpansion(tests.TestCase):
616
"""Test option expansion from the IniConfig level.
618
What we really want here is to test the Config level, but the class being
619
abstract as far as storing values is concerned, this can't be done
622
# FIXME: This should be rewritten when all configs share a storage
623
# implementation -- vila 2011-02-18
625
def get_config(self, string=None):
628
c = config.IniBasedConfig.from_string(string)
631
def assertExpansion(self, expected, conf, string, env=None):
632
self.assertEquals(expected, conf.expand_options(string, env))
634
def test_no_expansion(self):
635
c = self.get_config('')
636
self.assertExpansion('foo', c, 'foo')
638
def test_env_adding_options(self):
639
c = self.get_config('')
640
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
642
def test_env_overriding_options(self):
643
c = self.get_config('foo=baz')
644
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
646
def test_simple_ref(self):
647
c = self.get_config('foo=xxx')
648
self.assertExpansion('xxx', c, '{foo}')
650
def test_unknown_ref(self):
651
c = self.get_config('')
652
self.assertRaises(errors.ExpandingUnknownOption,
653
c.expand_options, '{foo}')
655
def test_indirect_ref(self):
656
c = self.get_config('''
660
self.assertExpansion('xxx', c, '{bar}')
662
def test_embedded_ref(self):
663
c = self.get_config('''
667
self.assertExpansion('xxx', c, '{{bar}}')
669
def test_simple_loop(self):
670
c = self.get_config('foo={foo}')
671
self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
673
def test_indirect_loop(self):
674
c = self.get_config('''
678
e = self.assertRaises(errors.OptionExpansionLoop,
679
c.expand_options, '{foo}')
680
self.assertEquals('foo->bar->baz', e.refs)
681
self.assertEquals('{foo}', e.string)
684
conf = self.get_config('''
688
list={foo},{bar},{baz}
690
self.assertEquals(['start', 'middle', 'end'],
691
conf.get_user_option('list', expand=True))
693
def test_cascading_list(self):
694
conf = self.get_config('''
700
self.assertEquals(['start', 'middle', 'end'],
701
conf.get_user_option('list', expand=True))
703
def test_pathological_hidden_list(self):
704
conf = self.get_config('''
710
hidden={start}{middle}{end}
712
# Nope, it's either a string or a list, and the list wins as soon as a
713
# ',' appears, so the string concatenation never occur.
714
self.assertEquals(['{foo', '}', '{', 'bar}'],
715
conf.get_user_option('hidden', expand=True))
717
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
719
def get_config(self, location, string=None):
722
# Since we don't save the config we won't strictly require to inherit
723
# from TestCaseInTempDir, but an error occurs so quickly...
724
c = config.LocationConfig.from_string(string, location)
727
def test_dont_cross_unrelated_section(self):
728
c = self.get_config('/another/branch/path','''
733
[/another/branch/path]
736
self.assertRaises(errors.ExpandingUnknownOption,
737
c.get_user_option, 'bar', expand=True)
739
def test_cross_related_sections(self):
740
c = self.get_config('/project/branch/path','''
744
[/project/branch/path]
747
self.assertEquals('quux', c.get_user_option('bar', expand=True))
750
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
752
def test_cannot_reload_without_name(self):
753
conf = config.IniBasedConfig.from_string(sample_config_text)
754
self.assertRaises(AssertionError, conf.reload)
756
def test_reload_see_new_value(self):
757
c1 = config.IniBasedConfig.from_string('editor=vim\n',
758
file_name='./test/conf')
759
c1._write_config_file()
760
c2 = config.IniBasedConfig.from_string('editor=emacs\n',
761
file_name='./test/conf')
762
c2._write_config_file()
763
self.assertEqual('vim', c1.get_user_option('editor'))
764
self.assertEqual('emacs', c2.get_user_option('editor'))
765
# Make sure we get the Right value
767
self.assertEqual('emacs', c1.get_user_option('editor'))
770
class TestLockableConfig(tests.TestCaseInTempDir):
772
scenarios = lockable_config_scenarios()
777
config_section = None
780
super(TestLockableConfig, self).setUp()
781
self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
782
self.config = self.create_config(self._content)
784
def get_existing_config(self):
785
return self.config_class(*self.config_args)
787
def create_config(self, content):
788
kwargs = dict(save=True)
789
c = self.config_class.from_string(content, *self.config_args, **kwargs)
792
def test_simple_read_access(self):
793
self.assertEquals('1', self.config.get_user_option('one'))
795
def test_simple_write_access(self):
796
self.config.set_user_option('one', 'one')
797
self.assertEquals('one', self.config.get_user_option('one'))
799
def test_listen_to_the_last_speaker(self):
801
c2 = self.get_existing_config()
802
c1.set_user_option('one', 'ONE')
803
c2.set_user_option('two', 'TWO')
804
self.assertEquals('ONE', c1.get_user_option('one'))
805
self.assertEquals('TWO', c2.get_user_option('two'))
806
# The second update respect the first one
807
self.assertEquals('ONE', c2.get_user_option('one'))
809
def test_last_speaker_wins(self):
810
# If the same config is not shared, the same variable modified twice
811
# can only see a single result.
813
c2 = self.get_existing_config()
814
c1.set_user_option('one', 'c1')
815
c2.set_user_option('one', 'c2')
816
self.assertEquals('c2', c2._get_user_option('one'))
817
# The first modification is still available until another refresh
819
self.assertEquals('c1', c1._get_user_option('one'))
820
c1.set_user_option('two', 'done')
821
self.assertEquals('c2', c1._get_user_option('one'))
823
def test_writes_are_serialized(self):
825
c2 = self.get_existing_config()
827
# We spawn a thread that will pause *during* the write
828
before_writing = threading.Event()
829
after_writing = threading.Event()
830
writing_done = threading.Event()
831
c1_orig = c1._write_config_file
832
def c1_write_config_file():
835
# The lock is held we wait for the main thread to decide when to
838
c1._write_config_file = c1_write_config_file
840
c1.set_user_option('one', 'c1')
842
t1 = threading.Thread(target=c1_set_option)
843
# Collect the thread after the test
844
self.addCleanup(t1.join)
845
# Be ready to unblock the thread if the test goes wrong
846
self.addCleanup(after_writing.set)
848
before_writing.wait()
849
self.assertTrue(c1._lock.is_held)
850
self.assertRaises(errors.LockContention,
851
c2.set_user_option, 'one', 'c2')
852
self.assertEquals('c1', c1.get_user_option('one'))
853
# Let the lock be released
856
c2.set_user_option('one', 'c2')
857
self.assertEquals('c2', c2.get_user_option('one'))
859
def test_read_while_writing(self):
861
# We spawn a thread that will pause *during* the write
862
ready_to_write = threading.Event()
863
do_writing = threading.Event()
864
writing_done = threading.Event()
865
c1_orig = c1._write_config_file
866
def c1_write_config_file():
868
# The lock is held we wait for the main thread to decide when to
873
c1._write_config_file = c1_write_config_file
875
c1.set_user_option('one', 'c1')
876
t1 = threading.Thread(target=c1_set_option)
877
# Collect the thread after the test
878
self.addCleanup(t1.join)
879
# Be ready to unblock the thread if the test goes wrong
880
self.addCleanup(do_writing.set)
882
# Ensure the thread is ready to write
883
ready_to_write.wait()
884
self.assertTrue(c1._lock.is_held)
885
self.assertEquals('c1', c1.get_user_option('one'))
886
# If we read during the write, we get the old value
887
c2 = self.get_existing_config()
888
self.assertEquals('1', c2.get_user_option('one'))
889
# Let the writing occur and ensure it occurred
892
# Now we get the updated value
893
c3 = self.get_existing_config()
894
self.assertEquals('c1', c3.get_user_option('one'))
397
897
class TestGetUserOptionAs(TestIniConfig):
1312
1818
self.assertIs(None, bzrdir_config.get_default_stack_on())
1821
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1824
super(TestConfigGetOptions, self).setUp()
1825
create_configs(self)
1827
# One variable in none of the above
1828
def test_no_variable(self):
1829
# Using branch should query branch, locations and bazaar
1830
self.assertOptions([], self.branch_config)
1832
def test_option_in_bazaar(self):
1833
self.bazaar_config.set_user_option('file', 'bazaar')
1834
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1837
def test_option_in_locations(self):
1838
self.locations_config.set_user_option('file', 'locations')
1840
[('file', 'locations', self.tree.basedir, 'locations')],
1841
self.locations_config)
1843
def test_option_in_branch(self):
1844
self.branch_config.set_user_option('file', 'branch')
1845
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
1848
def test_option_in_bazaar_and_branch(self):
1849
self.bazaar_config.set_user_option('file', 'bazaar')
1850
self.branch_config.set_user_option('file', 'branch')
1851
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
1852
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1855
def test_option_in_branch_and_locations(self):
1856
# Hmm, locations override branch :-/
1857
self.locations_config.set_user_option('file', 'locations')
1858
self.branch_config.set_user_option('file', 'branch')
1860
[('file', 'locations', self.tree.basedir, 'locations'),
1861
('file', 'branch', 'DEFAULT', 'branch'),],
1864
def test_option_in_bazaar_locations_and_branch(self):
1865
self.bazaar_config.set_user_option('file', 'bazaar')
1866
self.locations_config.set_user_option('file', 'locations')
1867
self.branch_config.set_user_option('file', 'branch')
1869
[('file', 'locations', self.tree.basedir, 'locations'),
1870
('file', 'branch', 'DEFAULT', 'branch'),
1871
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1875
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1878
super(TestConfigRemoveOption, self).setUp()
1879
create_configs_with_file_option(self)
1881
def test_remove_in_locations(self):
1882
self.locations_config.remove_user_option('file', self.tree.basedir)
1884
[('file', 'branch', 'DEFAULT', 'branch'),
1885
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1888
def test_remove_in_branch(self):
1889
self.branch_config.remove_user_option('file')
1891
[('file', 'locations', self.tree.basedir, 'locations'),
1892
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1895
def test_remove_in_bazaar(self):
1896
self.bazaar_config.remove_user_option('file')
1898
[('file', 'locations', self.tree.basedir, 'locations'),
1899
('file', 'branch', 'DEFAULT', 'branch'),],
1903
class TestConfigGetSections(tests.TestCaseWithTransport):
1906
super(TestConfigGetSections, self).setUp()
1907
create_configs(self)
1909
def assertSectionNames(self, expected, conf, name=None):
1910
"""Check which sections are returned for a given config.
1912
If fallback configurations exist their sections can be included.
1914
:param expected: A list of section names.
1916
:param conf: The configuration that will be queried.
1918
:param name: An optional section name that will be passed to
1921
sections = list(conf._get_sections(name))
1922
self.assertLength(len(expected), sections)
1923
self.assertEqual(expected, [name for name, _, _ in sections])
1925
def test_bazaar_default_section(self):
1926
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1928
def test_locations_default_section(self):
1929
# No sections are defined in an empty file
1930
self.assertSectionNames([], self.locations_config)
1932
def test_locations_named_section(self):
1933
self.locations_config.set_user_option('file', 'locations')
1934
self.assertSectionNames([self.tree.basedir], self.locations_config)
1936
def test_locations_matching_sections(self):
1937
loc_config = self.locations_config
1938
loc_config.set_user_option('file', 'locations')
1939
# We need to cheat a bit here to create an option in sections above and
1940
# below the 'location' one.
1941
parser = loc_config._get_parser()
1942
# locations.cong deals with '/' ignoring native os.sep
1943
location_names = self.tree.basedir.split('/')
1944
parent = '/'.join(location_names[:-1])
1945
child = '/'.join(location_names + ['child'])
1947
parser[parent]['file'] = 'parent'
1949
parser[child]['file'] = 'child'
1950
self.assertSectionNames([self.tree.basedir, parent], loc_config)
1952
def test_branch_data_default_section(self):
1953
self.assertSectionNames([None],
1954
self.branch_config._get_branch_data_config())
1956
def test_branch_default_sections(self):
1957
# No sections are defined in an empty locations file
1958
self.assertSectionNames([None, 'DEFAULT'],
1960
# Unless we define an option
1961
self.branch_config._get_location_config().set_user_option(
1962
'file', 'locations')
1963
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
1966
def test_bazaar_named_section(self):
1967
# We need to cheat as the API doesn't give direct access to sections
1968
# other than DEFAULT.
1969
self.bazaar_config.set_alias('bazaar', 'bzr')
1970
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1315
1973
class TestAuthenticationConfigFile(tests.TestCase):
1316
1974
"""Test the authentication.conf file matching"""