463
367
'/home/bogus/.cache')
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):
370
class TestIniConfig(tests.TestCase):
496
372
def make_config_parser(self, s):
497
conf = config.IniBasedConfig.from_string(s)
498
return conf, conf._get_parser()
373
conf = config.IniBasedConfig(None)
374
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
501
378
class TestIniConfigBuilding(TestIniConfig):
503
380
def test_contructs(self):
504
my_config = config.IniBasedConfig()
381
my_config = config.IniBasedConfig("nothing")
506
383
def test_from_fp(self):
507
my_config = config.IniBasedConfig.from_string(sample_config_text)
508
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
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))
510
390
def test_cached(self):
511
my_config = config.IniBasedConfig.from_string(sample_config_text)
512
parser = my_config._get_parser()
513
self.assertTrue(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
391
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'))
392
my_config = config.IniBasedConfig(None)
393
parser = my_config._get_parser(file=config_file)
394
self.failUnless(my_config._get_parser() is parser)
897
397
class TestGetUserOptionAs(TestIniConfig):
1253
740
parser = my_config._get_parser()
1255
742
config.ConfigObj = oldparserclass
1256
self.assertIsInstance(parser, InstrumentedConfigObj)
743
self.failUnless(isinstance(parser, InstrumentedConfigObj))
1257
744
self.assertEqual(parser._calls,
1258
745
[('__init__', config.locations_config_filename(),
747
config.ensure_config_dir_exists()
748
#os.mkdir(config.config_dir())
749
f = file(config.branches_config_filename(), 'wb')
752
oldparserclass = config.ConfigObj
753
config.ConfigObj = InstrumentedConfigObj
755
my_config = config.LocationConfig('http://www.example.com')
756
parser = my_config._get_parser()
758
config.ConfigObj = oldparserclass
1261
760
def test_get_global_config(self):
1262
761
my_config = config.BranchConfig(FakeBranch('http://example.com'))
1263
762
global_config = my_config._get_global_config()
1264
self.assertIsInstance(global_config, config.GlobalConfig)
1265
self.assertIs(global_config, my_config._get_global_config())
1267
def assertLocationMatching(self, expected):
1268
self.assertEqual(expected,
1269
list(self.my_location_config._get_matching_sections()))
763
self.failUnless(isinstance(global_config, config.GlobalConfig))
764
self.failUnless(global_config is my_config._get_global_config())
1271
766
def test__get_matching_sections_no_match(self):
1272
767
self.get_branch_config('/')
1273
self.assertLocationMatching([])
768
self.assertEqual([], self.my_location_config._get_matching_sections())
1275
770
def test__get_matching_sections_exact(self):
1276
771
self.get_branch_config('http://www.example.com')
1277
self.assertLocationMatching([('http://www.example.com', '')])
772
self.assertEqual([('http://www.example.com', '')],
773
self.my_location_config._get_matching_sections())
1279
775
def test__get_matching_sections_suffix_does_not(self):
1280
776
self.get_branch_config('http://www.example.com-com')
1281
self.assertLocationMatching([])
777
self.assertEqual([], self.my_location_config._get_matching_sections())
1283
779
def test__get_matching_sections_subdir_recursive(self):
1284
780
self.get_branch_config('http://www.example.com/com')
1285
self.assertLocationMatching([('http://www.example.com', 'com')])
781
self.assertEqual([('http://www.example.com', 'com')],
782
self.my_location_config._get_matching_sections())
1287
784
def test__get_matching_sections_ignoreparent(self):
1288
785
self.get_branch_config('http://www.example.com/ignoreparent')
1289
self.assertLocationMatching([('http://www.example.com/ignoreparent',
786
self.assertEqual([('http://www.example.com/ignoreparent', '')],
787
self.my_location_config._get_matching_sections())
1292
789
def test__get_matching_sections_ignoreparent_subdir(self):
1293
790
self.get_branch_config(
1294
791
'http://www.example.com/ignoreparent/childbranch')
1295
self.assertLocationMatching([('http://www.example.com/ignoreparent',
792
self.assertEqual([('http://www.example.com/ignoreparent',
794
self.my_location_config._get_matching_sections())
1298
796
def test__get_matching_sections_subdir_trailing_slash(self):
1299
797
self.get_branch_config('/b')
1300
self.assertLocationMatching([('/b/', '')])
798
self.assertEqual([('/b/', '')],
799
self.my_location_config._get_matching_sections())
1302
801
def test__get_matching_sections_subdir_child(self):
1303
802
self.get_branch_config('/a/foo')
1304
self.assertLocationMatching([('/a/*', ''), ('/a/', 'foo')])
803
self.assertEqual([('/a/*', ''), ('/a/', 'foo')],
804
self.my_location_config._get_matching_sections())
1306
806
def test__get_matching_sections_subdir_child_child(self):
1307
807
self.get_branch_config('/a/foo/bar')
1308
self.assertLocationMatching([('/a/*', 'bar'), ('/a/', 'foo/bar')])
808
self.assertEqual([('/a/*', 'bar'), ('/a/', 'foo/bar')],
809
self.my_location_config._get_matching_sections())
1310
811
def test__get_matching_sections_trailing_slash_with_children(self):
1311
812
self.get_branch_config('/a/')
1312
self.assertLocationMatching([('/a/', '')])
813
self.assertEqual([('/a/', '')],
814
self.my_location_config._get_matching_sections())
1314
816
def test__get_matching_sections_explicit_over_glob(self):
1315
817
# XXX: 2006-09-08 jamesh
1814
1312
self.assertIs(None, bzrdir_config.get_default_stack_on())
1817
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1820
super(TestConfigGetOptions, self).setUp()
1821
create_configs(self)
1823
# One variable in none of the above
1824
def test_no_variable(self):
1825
# Using branch should query branch, locations and bazaar
1826
self.assertOptions([], self.branch_config)
1828
def test_option_in_bazaar(self):
1829
self.bazaar_config.set_user_option('file', 'bazaar')
1830
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1833
def test_option_in_locations(self):
1834
self.locations_config.set_user_option('file', 'locations')
1836
[('file', 'locations', self.tree.basedir, 'locations')],
1837
self.locations_config)
1839
def test_option_in_branch(self):
1840
self.branch_config.set_user_option('file', 'branch')
1841
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
1844
def test_option_in_bazaar_and_branch(self):
1845
self.bazaar_config.set_user_option('file', 'bazaar')
1846
self.branch_config.set_user_option('file', 'branch')
1847
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
1848
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1851
def test_option_in_branch_and_locations(self):
1852
# Hmm, locations override branch :-/
1853
self.locations_config.set_user_option('file', 'locations')
1854
self.branch_config.set_user_option('file', 'branch')
1856
[('file', 'locations', self.tree.basedir, 'locations'),
1857
('file', 'branch', 'DEFAULT', 'branch'),],
1860
def test_option_in_bazaar_locations_and_branch(self):
1861
self.bazaar_config.set_user_option('file', 'bazaar')
1862
self.locations_config.set_user_option('file', 'locations')
1863
self.branch_config.set_user_option('file', 'branch')
1865
[('file', 'locations', self.tree.basedir, 'locations'),
1866
('file', 'branch', 'DEFAULT', 'branch'),
1867
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1871
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1874
super(TestConfigRemoveOption, self).setUp()
1875
create_configs_with_file_option(self)
1877
def test_remove_in_locations(self):
1878
self.locations_config.remove_user_option('file', self.tree.basedir)
1880
[('file', 'branch', 'DEFAULT', 'branch'),
1881
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1884
def test_remove_in_branch(self):
1885
self.branch_config.remove_user_option('file')
1887
[('file', 'locations', self.tree.basedir, 'locations'),
1888
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1891
def test_remove_in_bazaar(self):
1892
self.bazaar_config.remove_user_option('file')
1894
[('file', 'locations', self.tree.basedir, 'locations'),
1895
('file', 'branch', 'DEFAULT', 'branch'),],
1899
class TestConfigGetSections(tests.TestCaseWithTransport):
1902
super(TestConfigGetSections, self).setUp()
1903
create_configs(self)
1905
def assertSectionNames(self, expected, conf, name=None):
1906
"""Check which sections are returned for a given config.
1908
If fallback configurations exist their sections can be included.
1910
:param expected: A list of section names.
1912
:param conf: The configuration that will be queried.
1914
:param name: An optional section name that will be passed to
1917
sections = list(conf._get_sections(name))
1918
self.assertLength(len(expected), sections)
1919
self.assertEqual(expected, [name for name, _, _ in sections])
1921
def test_bazaar_default_section(self):
1922
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1924
def test_locations_default_section(self):
1925
# No sections are defined in an empty file
1926
self.assertSectionNames([], self.locations_config)
1928
def test_locations_named_section(self):
1929
self.locations_config.set_user_option('file', 'locations')
1930
self.assertSectionNames([self.tree.basedir], self.locations_config)
1932
def test_locations_matching_sections(self):
1933
loc_config = self.locations_config
1934
loc_config.set_user_option('file', 'locations')
1935
# We need to cheat a bit here to create an option in sections above and
1936
# below the 'location' one.
1937
parser = loc_config._get_parser()
1938
# locations.cong deals with '/' ignoring native os.sep
1939
location_names = self.tree.basedir.split('/')
1940
parent = '/'.join(location_names[:-1])
1941
child = '/'.join(location_names + ['child'])
1943
parser[parent]['file'] = 'parent'
1945
parser[child]['file'] = 'child'
1946
self.assertSectionNames([self.tree.basedir, parent], loc_config)
1948
def test_branch_data_default_section(self):
1949
self.assertSectionNames([None],
1950
self.branch_config._get_branch_data_config())
1952
def test_branch_default_sections(self):
1953
# No sections are defined in an empty locations file
1954
self.assertSectionNames([None, 'DEFAULT'],
1956
# Unless we define an option
1957
self.branch_config._get_location_config().set_user_option(
1958
'file', 'locations')
1959
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
1962
def test_bazaar_named_section(self):
1963
# We need to cheat as the API doesn't give direct access to sections
1964
# other than DEFAULT.
1965
self.bazaar_config.set_alias('bazaar', 'bzr')
1966
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1969
1315
class TestAuthenticationConfigFile(tests.TestCase):
1970
1316
"""Test the authentication.conf file matching"""