367
462
'/home/bogus/.cache')
370
class TestIniConfig(tests.TestCase):
465
class TestXDGConfigDir(tests.TestCaseInTempDir):
466
# must be in temp dir because config tests for the existence of the bazaar
467
# subdirectory of $XDG_CONFIG_HOME
470
if sys.platform in ('darwin', 'win32'):
471
raise tests.TestNotApplicable(
472
'XDG config dir not used on this platform')
473
super(TestXDGConfigDir, self).setUp()
474
self.overrideEnv('HOME', self.test_home_dir)
475
# BZR_HOME overrides everything we want to test so unset it.
476
self.overrideEnv('BZR_HOME', None)
478
def test_xdg_config_dir_exists(self):
479
"""When ~/.config/bazaar exists, use it as the config dir."""
480
newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
482
self.assertEqual(config.config_dir(), newdir)
484
def test_xdg_config_home(self):
485
"""When XDG_CONFIG_HOME is set, use it."""
486
xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
487
self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
488
newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
490
self.assertEqual(config.config_dir(), newdir)
493
class TestIniConfig(tests.TestCaseInTempDir):
372
495
def make_config_parser(self, s):
373
conf = config.IniBasedConfig(None)
374
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
496
conf = config.IniBasedConfig.from_string(s)
497
return conf, conf._get_parser()
378
500
class TestIniConfigBuilding(TestIniConfig):
380
502
def test_contructs(self):
381
my_config = config.IniBasedConfig("nothing")
503
my_config = config.IniBasedConfig()
383
505
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))
506
my_config = config.IniBasedConfig.from_string(sample_config_text)
507
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
390
509
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)
510
my_config = config.IniBasedConfig.from_string(sample_config_text)
511
parser = my_config._get_parser()
394
512
self.failUnless(my_config._get_parser() is parser)
514
def _dummy_chown(self, path, uid, gid):
515
self.path, self.uid, self.gid = path, uid, gid
517
def test_ini_config_ownership(self):
518
"""Ensure that chown is happening during _write_config_file"""
519
self.requireFeature(features.chown_feature)
520
self.overrideAttr(os, 'chown', self._dummy_chown)
521
self.path = self.uid = self.gid = None
522
conf = config.IniBasedConfig(file_name='./foo.conf')
523
conf._write_config_file()
524
self.assertEquals(self.path, './foo.conf')
525
self.assertTrue(isinstance(self.uid, int))
526
self.assertTrue(isinstance(self.gid, int))
528
def test_get_filename_parameter_is_deprecated_(self):
529
conf = self.callDeprecated([
530
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
531
' Use file_name instead.'],
532
config.IniBasedConfig, lambda: 'ini.conf')
533
self.assertEqual('ini.conf', conf.file_name)
535
def test_get_parser_file_parameter_is_deprecated_(self):
536
config_file = StringIO(sample_config_text.encode('utf-8'))
537
conf = config.IniBasedConfig.from_string(sample_config_text)
538
conf = self.callDeprecated([
539
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
540
' Use IniBasedConfig(_content=xxx) instead.'],
541
conf._get_parser, file=config_file)
544
class TestIniConfigSaving(tests.TestCaseInTempDir):
546
def test_cant_save_without_a_file_name(self):
547
conf = config.IniBasedConfig()
548
self.assertRaises(AssertionError, conf._write_config_file)
550
def test_saved_with_content(self):
551
content = 'foo = bar\n'
552
conf = config.IniBasedConfig.from_string(
553
content, file_name='./test.conf', save=True)
554
self.assertFileEqual(content, 'test.conf')
557
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
558
"""What is the default value of expand for config options.
560
This is an opt-in beta feature used to evaluate whether or not option
561
references can appear in dangerous place raising exceptions, disapearing
562
(and as such corrupting data) or if it's safe to activate the option by
565
Note that these tests relies on config._expand_default_value being already
566
overwritten in the parent class setUp.
570
super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
574
self.warnings.append(args[0] % args[1:])
575
self.overrideAttr(trace, 'warning', warning)
577
def get_config(self, expand):
578
c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
582
def assertExpandIs(self, expected):
583
actual = config._get_expand_default_value()
584
#self.config.get_user_option_as_bool('bzr.config.expand')
585
self.assertEquals(expected, actual)
587
def test_default_is_None(self):
588
self.assertEquals(None, config._expand_default_value)
590
def test_default_is_False_even_if_None(self):
591
self.config = self.get_config(None)
592
self.assertExpandIs(False)
594
def test_default_is_False_even_if_invalid(self):
595
self.config = self.get_config('<your choice>')
596
self.assertExpandIs(False)
598
# Huh ? My choice is False ? Thanks, always happy to hear that :D
599
# Wait, you've been warned !
600
self.assertLength(1, self.warnings)
602
'Value "<your choice>" is not a boolean for "bzr.config.expand"',
605
def test_default_is_True(self):
606
self.config = self.get_config(True)
607
self.assertExpandIs(True)
609
def test_default_is_False(self):
610
self.config = self.get_config(False)
611
self.assertExpandIs(False)
614
class TestIniConfigOptionExpansion(tests.TestCase):
615
"""Test option expansion from the IniConfig level.
617
What we really want here is to test the Config level, but the class being
618
abstract as far as storing values is concerned, this can't be done
621
# FIXME: This should be rewritten when all configs share a storage
622
# implementation -- vila 2011-02-18
624
def get_config(self, string=None):
627
c = config.IniBasedConfig.from_string(string)
630
def assertExpansion(self, expected, conf, string, env=None):
631
self.assertEquals(expected, conf.expand_options(string, env))
633
def test_no_expansion(self):
634
c = self.get_config('')
635
self.assertExpansion('foo', c, 'foo')
637
def test_env_adding_options(self):
638
c = self.get_config('')
639
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
641
def test_env_overriding_options(self):
642
c = self.get_config('foo=baz')
643
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
645
def test_simple_ref(self):
646
c = self.get_config('foo=xxx')
647
self.assertExpansion('xxx', c, '{foo}')
649
def test_unknown_ref(self):
650
c = self.get_config('')
651
self.assertRaises(errors.ExpandingUnknownOption,
652
c.expand_options, '{foo}')
654
def test_indirect_ref(self):
655
c = self.get_config('''
659
self.assertExpansion('xxx', c, '{bar}')
661
def test_embedded_ref(self):
662
c = self.get_config('''
666
self.assertExpansion('xxx', c, '{{bar}}')
668
def test_simple_loop(self):
669
c = self.get_config('foo={foo}')
670
self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
672
def test_indirect_loop(self):
673
c = self.get_config('''
677
e = self.assertRaises(errors.OptionExpansionLoop,
678
c.expand_options, '{foo}')
679
self.assertEquals('foo->bar->baz', e.refs)
680
self.assertEquals('{foo}', e.string)
683
conf = self.get_config('''
687
list={foo},{bar},{baz}
689
self.assertEquals(['start', 'middle', 'end'],
690
conf.get_user_option('list', expand=True))
692
def test_cascading_list(self):
693
conf = self.get_config('''
699
self.assertEquals(['start', 'middle', 'end'],
700
conf.get_user_option('list', expand=True))
702
def test_pathological_hidden_list(self):
703
conf = self.get_config('''
709
hidden={start}{middle}{end}
711
# Nope, it's either a string or a list, and the list wins as soon as a
712
# ',' appears, so the string concatenation never occur.
713
self.assertEquals(['{foo', '}', '{', 'bar}'],
714
conf.get_user_option('hidden', expand=True))
716
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
718
def get_config(self, location, string=None):
721
# Since we don't save the config we won't strictly require to inherit
722
# from TestCaseInTempDir, but an error occurs so quickly...
723
c = config.LocationConfig.from_string(string, location)
726
def test_dont_cross_unrelated_section(self):
727
c = self.get_config('/another/branch/path','''
732
[/another/branch/path]
735
self.assertRaises(errors.ExpandingUnknownOption,
736
c.get_user_option, 'bar', expand=True)
738
def test_cross_related_sections(self):
739
c = self.get_config('/project/branch/path','''
743
[/project/branch/path]
746
self.assertEquals('quux', c.get_user_option('bar', expand=True))
749
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
751
def test_cannot_reload_without_name(self):
752
conf = config.IniBasedConfig.from_string(sample_config_text)
753
self.assertRaises(AssertionError, conf.reload)
755
def test_reload_see_new_value(self):
756
c1 = config.IniBasedConfig.from_string('editor=vim\n',
757
file_name='./test/conf')
758
c1._write_config_file()
759
c2 = config.IniBasedConfig.from_string('editor=emacs\n',
760
file_name='./test/conf')
761
c2._write_config_file()
762
self.assertEqual('vim', c1.get_user_option('editor'))
763
self.assertEqual('emacs', c2.get_user_option('editor'))
764
# Make sure we get the Right value
766
self.assertEqual('emacs', c1.get_user_option('editor'))
769
class TestLockableConfig(tests.TestCaseInTempDir):
771
scenarios = lockable_config_scenarios()
776
config_section = None
779
super(TestLockableConfig, self).setUp()
780
self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
781
self.config = self.create_config(self._content)
783
def get_existing_config(self):
784
return self.config_class(*self.config_args)
786
def create_config(self, content):
787
kwargs = dict(save=True)
788
c = self.config_class.from_string(content, *self.config_args, **kwargs)
791
def test_simple_read_access(self):
792
self.assertEquals('1', self.config.get_user_option('one'))
794
def test_simple_write_access(self):
795
self.config.set_user_option('one', 'one')
796
self.assertEquals('one', self.config.get_user_option('one'))
798
def test_listen_to_the_last_speaker(self):
800
c2 = self.get_existing_config()
801
c1.set_user_option('one', 'ONE')
802
c2.set_user_option('two', 'TWO')
803
self.assertEquals('ONE', c1.get_user_option('one'))
804
self.assertEquals('TWO', c2.get_user_option('two'))
805
# The second update respect the first one
806
self.assertEquals('ONE', c2.get_user_option('one'))
808
def test_last_speaker_wins(self):
809
# If the same config is not shared, the same variable modified twice
810
# can only see a single result.
812
c2 = self.get_existing_config()
813
c1.set_user_option('one', 'c1')
814
c2.set_user_option('one', 'c2')
815
self.assertEquals('c2', c2._get_user_option('one'))
816
# The first modification is still available until another refresh
818
self.assertEquals('c1', c1._get_user_option('one'))
819
c1.set_user_option('two', 'done')
820
self.assertEquals('c2', c1._get_user_option('one'))
822
def test_writes_are_serialized(self):
824
c2 = self.get_existing_config()
826
# We spawn a thread that will pause *during* the write
827
before_writing = threading.Event()
828
after_writing = threading.Event()
829
writing_done = threading.Event()
830
c1_orig = c1._write_config_file
831
def c1_write_config_file():
834
# The lock is held we wait for the main thread to decide when to
837
c1._write_config_file = c1_write_config_file
839
c1.set_user_option('one', 'c1')
841
t1 = threading.Thread(target=c1_set_option)
842
# Collect the thread after the test
843
self.addCleanup(t1.join)
844
# Be ready to unblock the thread if the test goes wrong
845
self.addCleanup(after_writing.set)
847
before_writing.wait()
848
self.assertTrue(c1._lock.is_held)
849
self.assertRaises(errors.LockContention,
850
c2.set_user_option, 'one', 'c2')
851
self.assertEquals('c1', c1.get_user_option('one'))
852
# Let the lock be released
855
c2.set_user_option('one', 'c2')
856
self.assertEquals('c2', c2.get_user_option('one'))
858
def test_read_while_writing(self):
860
# We spawn a thread that will pause *during* the write
861
ready_to_write = threading.Event()
862
do_writing = threading.Event()
863
writing_done = threading.Event()
864
c1_orig = c1._write_config_file
865
def c1_write_config_file():
867
# The lock is held we wait for the main thread to decide when to
872
c1._write_config_file = c1_write_config_file
874
c1.set_user_option('one', 'c1')
875
t1 = threading.Thread(target=c1_set_option)
876
# Collect the thread after the test
877
self.addCleanup(t1.join)
878
# Be ready to unblock the thread if the test goes wrong
879
self.addCleanup(do_writing.set)
881
# Ensure the thread is ready to write
882
ready_to_write.wait()
883
self.assertTrue(c1._lock.is_held)
884
self.assertEquals('c1', c1.get_user_option('one'))
885
# If we read during the write, we get the old value
886
c2 = self.get_existing_config()
887
self.assertEquals('1', c2.get_user_option('one'))
888
# Let the writing occur and ensure it occurred
891
# Now we get the updated value
892
c3 = self.get_existing_config()
893
self.assertEquals('c1', c3.get_user_option('one'))
397
896
class TestGetUserOptionAs(TestIniConfig):
1312
1817
self.assertIs(None, bzrdir_config.get_default_stack_on())
1820
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1823
super(TestConfigGetOptions, self).setUp()
1824
create_configs(self)
1826
# One variable in none of the above
1827
def test_no_variable(self):
1828
# Using branch should query branch, locations and bazaar
1829
self.assertOptions([], self.branch_config)
1831
def test_option_in_bazaar(self):
1832
self.bazaar_config.set_user_option('file', 'bazaar')
1833
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1836
def test_option_in_locations(self):
1837
self.locations_config.set_user_option('file', 'locations')
1839
[('file', 'locations', self.tree.basedir, 'locations')],
1840
self.locations_config)
1842
def test_option_in_branch(self):
1843
self.branch_config.set_user_option('file', 'branch')
1844
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
1847
def test_option_in_bazaar_and_branch(self):
1848
self.bazaar_config.set_user_option('file', 'bazaar')
1849
self.branch_config.set_user_option('file', 'branch')
1850
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
1851
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1854
def test_option_in_branch_and_locations(self):
1855
# Hmm, locations override branch :-/
1856
self.locations_config.set_user_option('file', 'locations')
1857
self.branch_config.set_user_option('file', 'branch')
1859
[('file', 'locations', self.tree.basedir, 'locations'),
1860
('file', 'branch', 'DEFAULT', 'branch'),],
1863
def test_option_in_bazaar_locations_and_branch(self):
1864
self.bazaar_config.set_user_option('file', 'bazaar')
1865
self.locations_config.set_user_option('file', 'locations')
1866
self.branch_config.set_user_option('file', 'branch')
1868
[('file', 'locations', self.tree.basedir, 'locations'),
1869
('file', 'branch', 'DEFAULT', 'branch'),
1870
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1874
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1877
super(TestConfigRemoveOption, self).setUp()
1878
create_configs_with_file_option(self)
1880
def test_remove_in_locations(self):
1881
self.locations_config.remove_user_option('file', self.tree.basedir)
1883
[('file', 'branch', 'DEFAULT', 'branch'),
1884
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1887
def test_remove_in_branch(self):
1888
self.branch_config.remove_user_option('file')
1890
[('file', 'locations', self.tree.basedir, 'locations'),
1891
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1894
def test_remove_in_bazaar(self):
1895
self.bazaar_config.remove_user_option('file')
1897
[('file', 'locations', self.tree.basedir, 'locations'),
1898
('file', 'branch', 'DEFAULT', 'branch'),],
1902
class TestConfigGetSections(tests.TestCaseWithTransport):
1905
super(TestConfigGetSections, self).setUp()
1906
create_configs(self)
1908
def assertSectionNames(self, expected, conf, name=None):
1909
"""Check which sections are returned for a given config.
1911
If fallback configurations exist their sections can be included.
1913
:param expected: A list of section names.
1915
:param conf: The configuration that will be queried.
1917
:param name: An optional section name that will be passed to
1920
sections = list(conf._get_sections(name))
1921
self.assertLength(len(expected), sections)
1922
self.assertEqual(expected, [name for name, _, _ in sections])
1924
def test_bazaar_default_section(self):
1925
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1927
def test_locations_default_section(self):
1928
# No sections are defined in an empty file
1929
self.assertSectionNames([], self.locations_config)
1931
def test_locations_named_section(self):
1932
self.locations_config.set_user_option('file', 'locations')
1933
self.assertSectionNames([self.tree.basedir], self.locations_config)
1935
def test_locations_matching_sections(self):
1936
loc_config = self.locations_config
1937
loc_config.set_user_option('file', 'locations')
1938
# We need to cheat a bit here to create an option in sections above and
1939
# below the 'location' one.
1940
parser = loc_config._get_parser()
1941
# locations.cong deals with '/' ignoring native os.sep
1942
location_names = self.tree.basedir.split('/')
1943
parent = '/'.join(location_names[:-1])
1944
child = '/'.join(location_names + ['child'])
1946
parser[parent]['file'] = 'parent'
1948
parser[child]['file'] = 'child'
1949
self.assertSectionNames([self.tree.basedir, parent], loc_config)
1951
def test_branch_data_default_section(self):
1952
self.assertSectionNames([None],
1953
self.branch_config._get_branch_data_config())
1955
def test_branch_default_sections(self):
1956
# No sections are defined in an empty locations file
1957
self.assertSectionNames([None, 'DEFAULT'],
1959
# Unless we define an option
1960
self.branch_config._get_location_config().set_user_option(
1961
'file', 'locations')
1962
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
1965
def test_bazaar_named_section(self):
1966
# We need to cheat as the API doesn't give direct access to sections
1967
# other than DEFAULT.
1968
self.bazaar_config.set_alias('bazaar', 'bzr')
1969
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1315
1972
class TestAuthenticationConfigFile(tests.TestCase):
1316
1973
"""Test the authentication.conf file matching"""