371
459
'/home/bogus/.cache')
462
class TestXDGConfigDir(tests.TestCaseInTempDir):
463
# must be in temp dir because config tests for the existence of the bazaar
464
# subdirectory of $XDG_CONFIG_HOME
467
if sys.platform in ('darwin', 'win32'):
468
raise tests.TestNotApplicable(
469
'XDG config dir not used on this platform')
470
super(TestXDGConfigDir, self).setUp()
471
self.overrideEnv('HOME', self.test_home_dir)
472
# BZR_HOME overrides everything we want to test so unset it.
473
self.overrideEnv('BZR_HOME', None)
475
def test_xdg_config_dir_exists(self):
476
"""When ~/.config/bazaar exists, use it as the config dir."""
477
newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
479
self.assertEqual(config.config_dir(), newdir)
481
def test_xdg_config_home(self):
482
"""When XDG_CONFIG_HOME is set, use it."""
483
xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
484
self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
485
newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
487
self.assertEqual(config.config_dir(), newdir)
374
490
class TestIniConfig(tests.TestCaseInTempDir):
376
492
def make_config_parser(self, s):
377
conf = config.IniBasedConfig(None)
378
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
493
conf = config.IniBasedConfig.from_string(s)
494
return conf, conf._get_parser()
382
497
class TestIniConfigBuilding(TestIniConfig):
384
499
def test_contructs(self):
385
my_config = config.IniBasedConfig("nothing")
500
my_config = config.IniBasedConfig()
387
502
def test_from_fp(self):
388
config_file = StringIO(sample_config_text.encode('utf-8'))
389
my_config = config.IniBasedConfig(None)
391
isinstance(my_config._get_parser(file=config_file),
392
configobj.ConfigObj))
503
my_config = config.IniBasedConfig.from_string(sample_config_text)
504
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
394
506
def test_cached(self):
395
config_file = StringIO(sample_config_text.encode('utf-8'))
396
my_config = config.IniBasedConfig(None)
397
parser = my_config._get_parser(file=config_file)
507
my_config = config.IniBasedConfig.from_string(sample_config_text)
508
parser = my_config._get_parser()
398
509
self.failUnless(my_config._get_parser() is parser)
400
511
def _dummy_chown(self, path, uid, gid):
401
512
self.path, self.uid, self.gid = path, uid, gid
403
514
def test_ini_config_ownership(self):
404
"""Ensure that chown is happening during _write_config_file.
515
"""Ensure that chown is happening during _write_config_file"""
406
516
self.requireFeature(features.chown_feature)
407
517
self.overrideAttr(os, 'chown', self._dummy_chown)
408
518
self.path = self.uid = self.gid = None
411
conf = config.IniBasedConfig(get_filename)
519
conf = config.IniBasedConfig(file_name='./foo.conf')
412
520
conf._write_config_file()
413
self.assertEquals(self.path, 'foo.conf')
521
self.assertEquals(self.path, './foo.conf')
414
522
self.assertTrue(isinstance(self.uid, int))
415
523
self.assertTrue(isinstance(self.gid, int))
525
def test_get_filename_parameter_is_deprecated_(self):
526
conf = self.callDeprecated([
527
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
528
' Use file_name instead.'],
529
config.IniBasedConfig, lambda: 'ini.conf')
530
self.assertEqual('ini.conf', conf.file_name)
532
def test_get_parser_file_parameter_is_deprecated_(self):
533
config_file = StringIO(sample_config_text.encode('utf-8'))
534
conf = config.IniBasedConfig.from_string(sample_config_text)
535
conf = self.callDeprecated([
536
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
537
' Use IniBasedConfig(_content=xxx) instead.'],
538
conf._get_parser, file=config_file)
540
class TestIniConfigSaving(tests.TestCaseInTempDir):
542
def test_cant_save_without_a_file_name(self):
543
conf = config.IniBasedConfig()
544
self.assertRaises(AssertionError, conf._write_config_file)
546
def test_saved_with_content(self):
547
content = 'foo = bar\n'
548
conf = config.IniBasedConfig.from_string(
549
content, file_name='./test.conf', save=True)
550
self.assertFileEqual(content, 'test.conf')
553
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
555
def test_cannot_reload_without_name(self):
556
conf = config.IniBasedConfig.from_string(sample_config_text)
557
self.assertRaises(AssertionError, conf.reload)
559
def test_reload_see_new_value(self):
560
c1 = config.IniBasedConfig.from_string('editor=vim\n',
561
file_name='./test/conf')
562
c1._write_config_file()
563
c2 = config.IniBasedConfig.from_string('editor=emacs\n',
564
file_name='./test/conf')
565
c2._write_config_file()
566
self.assertEqual('vim', c1.get_user_option('editor'))
567
self.assertEqual('emacs', c2.get_user_option('editor'))
568
# Make sure we get the Right value
570
self.assertEqual('emacs', c1.get_user_option('editor'))
573
class TestLockableConfig(tests.TestCaseInTempDir):
575
scenarios = lockable_config_scenarios()
580
config_section = None
583
super(TestLockableConfig, self).setUp()
584
self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
585
self.config = self.create_config(self._content)
587
def get_existing_config(self):
588
return self.config_class(*self.config_args)
590
def create_config(self, content):
591
kwargs = dict(save=True)
592
c = self.config_class.from_string(content, *self.config_args, **kwargs)
595
def test_simple_read_access(self):
596
self.assertEquals('1', self.config.get_user_option('one'))
598
def test_simple_write_access(self):
599
self.config.set_user_option('one', 'one')
600
self.assertEquals('one', self.config.get_user_option('one'))
602
def test_listen_to_the_last_speaker(self):
604
c2 = self.get_existing_config()
605
c1.set_user_option('one', 'ONE')
606
c2.set_user_option('two', 'TWO')
607
self.assertEquals('ONE', c1.get_user_option('one'))
608
self.assertEquals('TWO', c2.get_user_option('two'))
609
# The second update respect the first one
610
self.assertEquals('ONE', c2.get_user_option('one'))
612
def test_last_speaker_wins(self):
613
# If the same config is not shared, the same variable modified twice
614
# can only see a single result.
616
c2 = self.get_existing_config()
617
c1.set_user_option('one', 'c1')
618
c2.set_user_option('one', 'c2')
619
self.assertEquals('c2', c2._get_user_option('one'))
620
# The first modification is still available until another refresh
622
self.assertEquals('c1', c1._get_user_option('one'))
623
c1.set_user_option('two', 'done')
624
self.assertEquals('c2', c1._get_user_option('one'))
626
def test_writes_are_serialized(self):
628
c2 = self.get_existing_config()
630
# We spawn a thread that will pause *during* the write
631
before_writing = threading.Event()
632
after_writing = threading.Event()
633
writing_done = threading.Event()
634
c1_orig = c1._write_config_file
635
def c1_write_config_file():
638
# The lock is held we wait for the main thread to decide when to
641
c1._write_config_file = c1_write_config_file
643
c1.set_user_option('one', 'c1')
645
t1 = threading.Thread(target=c1_set_option)
646
# Collect the thread after the test
647
self.addCleanup(t1.join)
648
# Be ready to unblock the thread if the test goes wrong
649
self.addCleanup(after_writing.set)
651
before_writing.wait()
652
self.assertTrue(c1._lock.is_held)
653
self.assertRaises(errors.LockContention,
654
c2.set_user_option, 'one', 'c2')
655
self.assertEquals('c1', c1.get_user_option('one'))
656
# Let the lock be released
659
c2.set_user_option('one', 'c2')
660
self.assertEquals('c2', c2.get_user_option('one'))
662
def test_read_while_writing(self):
664
# We spawn a thread that will pause *during* the write
665
ready_to_write = threading.Event()
666
do_writing = threading.Event()
667
writing_done = threading.Event()
668
c1_orig = c1._write_config_file
669
def c1_write_config_file():
671
# The lock is held we wait for the main thread to decide when to
676
c1._write_config_file = c1_write_config_file
678
c1.set_user_option('one', 'c1')
679
t1 = threading.Thread(target=c1_set_option)
680
# Collect the thread after the test
681
self.addCleanup(t1.join)
682
# Be ready to unblock the thread if the test goes wrong
683
self.addCleanup(do_writing.set)
685
# Ensure the thread is ready to write
686
ready_to_write.wait()
687
self.assertTrue(c1._lock.is_held)
688
self.assertEquals('c1', c1.get_user_option('one'))
689
# If we read during the write, we get the old value
690
c2 = self.get_existing_config()
691
self.assertEquals('1', c2.get_user_option('one'))
692
# Let the writing occur and ensure it occurred
695
# Now we get the updated value
696
c3 = self.get_existing_config()
697
self.assertEquals('c1', c3.get_user_option('one'))
417
700
class TestGetUserOptionAs(TestIniConfig):
419
702
def test_get_user_option_as_bool(self):
577
858
self.assertEqual(1, len(warnings))
578
859
self.assertEqual(warning, warnings[0])
579
trace.warning = warning
581
branch = self.make_branch('.')
582
conf = branch.get_config()
583
set_option(config.STORE_GLOBAL)
585
set_option(config.STORE_BRANCH)
587
set_option(config.STORE_GLOBAL)
588
assertWarning('Value "4" is masked by "3" from branch.conf')
589
set_option(config.STORE_GLOBAL, warn_masked=False)
591
set_option(config.STORE_LOCATION)
593
set_option(config.STORE_BRANCH)
594
assertWarning('Value "3" is masked by "0" from locations.conf')
595
set_option(config.STORE_BRANCH, warn_masked=False)
598
trace.warning = _warning
601
class TestGlobalConfigItems(tests.TestCase):
860
branch = self.make_branch('.')
861
conf = branch.get_config()
862
set_option(config.STORE_GLOBAL)
864
set_option(config.STORE_BRANCH)
866
set_option(config.STORE_GLOBAL)
867
assertWarning('Value "4" is masked by "3" from branch.conf')
868
set_option(config.STORE_GLOBAL, warn_masked=False)
870
set_option(config.STORE_LOCATION)
872
set_option(config.STORE_BRANCH)
873
assertWarning('Value "3" is masked by "0" from locations.conf')
874
set_option(config.STORE_BRANCH, warn_masked=False)
878
class TestGlobalConfigItems(tests.TestCaseInTempDir):
603
880
def test_user_id(self):
604
config_file = StringIO(sample_config_text.encode('utf-8'))
605
my_config = config.GlobalConfig()
606
my_config._parser = my_config._get_parser(file=config_file)
881
my_config = config.GlobalConfig.from_string(sample_config_text)
607
882
self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
608
883
my_config._get_user_id())
610
885
def test_absent_user_id(self):
611
config_file = StringIO("")
612
886
my_config = config.GlobalConfig()
613
my_config._parser = my_config._get_parser(file=config_file)
614
887
self.assertEqual(None, my_config._get_user_id())
616
889
def test_configured_editor(self):
617
config_file = StringIO(sample_config_text.encode('utf-8'))
618
my_config = config.GlobalConfig()
619
my_config._parser = my_config._get_parser(file=config_file)
890
my_config = config.GlobalConfig.from_string(sample_config_text)
620
891
self.assertEqual("vim", my_config.get_editor())
622
893
def test_signatures_always(self):
623
config_file = StringIO(sample_always_signatures)
624
my_config = config.GlobalConfig()
625
my_config._parser = my_config._get_parser(file=config_file)
894
my_config = config.GlobalConfig.from_string(sample_always_signatures)
626
895
self.assertEqual(config.CHECK_NEVER,
627
896
my_config.signature_checking())
628
897
self.assertEqual(config.SIGN_ALWAYS,
1009
1273
self.assertEqual('bzrlib.tests.test_config.post_commit',
1010
1274
self.my_config.post_commit())
1012
def get_branch_config(self, location, global_config=None):
1276
def get_branch_config(self, location, global_config=None,
1277
location_config=None):
1278
my_branch = FakeBranch(location)
1013
1279
if global_config is None:
1014
global_file = StringIO(sample_config_text.encode('utf-8'))
1016
global_file = StringIO(global_config.encode('utf-8'))
1017
branches_file = StringIO(sample_branches_text.encode('utf-8'))
1018
self.my_config = config.BranchConfig(FakeBranch(location))
1019
# Force location config to use specified file
1020
self.my_location_config = self.my_config._get_location_config()
1021
self.my_location_config._get_parser(branches_file)
1022
# Force global config to use specified file
1023
self.my_config._get_global_config()._get_parser(global_file)
1280
global_config = sample_config_text
1281
if location_config is None:
1282
location_config = sample_branches_text
1284
my_global_config = config.GlobalConfig.from_string(global_config,
1286
my_location_config = config.LocationConfig.from_string(
1287
location_config, my_branch.base, save=True)
1288
my_config = config.BranchConfig(my_branch)
1289
self.my_config = my_config
1290
self.my_location_config = my_config._get_location_config()
1025
1292
def test_set_user_setting_sets_and_saves(self):
1026
1293
self.get_branch_config('/a/c')
1027
1294
record = InstrumentedConfigObj("foo")
1028
1295
self.my_location_config._parser = record
1030
real_mkdir = os.mkdir
1031
self.created = False
1032
def checked_mkdir(path, mode=0777):
1033
self.log('making directory: %s', path)
1034
real_mkdir(path, mode)
1037
os.mkdir = checked_mkdir
1039
self.callDeprecated(['The recurse option is deprecated as of '
1040
'0.14. The section "/a/c" has been '
1041
'converted to use policies.'],
1042
self.my_config.set_user_option,
1043
'foo', 'bar', store=config.STORE_LOCATION)
1045
os.mkdir = real_mkdir
1047
self.failUnless(self.created, 'Failed to create ~/.bazaar')
1048
self.assertEqual([('__contains__', '/a/c'),
1297
self.callDeprecated(['The recurse option is deprecated as of '
1298
'0.14. The section "/a/c" has been '
1299
'converted to use policies.'],
1300
self.my_config.set_user_option,
1301
'foo', 'bar', store=config.STORE_LOCATION)
1302
self.assertEqual([('reload',),
1303
('__contains__', '/a/c'),
1049
1304
('__contains__', '/a/c/'),
1050
1305
('__setitem__', '/a/c', {}),
1051
1306
('__getitem__', '/a/c'),
1332
1586
self.assertIs(None, bzrdir_config.get_default_stack_on())
1589
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1592
super(TestConfigGetOptions, self).setUp()
1593
create_configs(self)
1595
# One variable in none of the above
1596
def test_no_variable(self):
1597
# Using branch should query branch, locations and bazaar
1598
self.assertOptions([], self.branch_config)
1600
def test_option_in_bazaar(self):
1601
self.bazaar_config.set_user_option('file', 'bazaar')
1602
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1605
def test_option_in_locations(self):
1606
self.locations_config.set_user_option('file', 'locations')
1608
[('file', 'locations', self.tree.basedir, 'locations')],
1609
self.locations_config)
1611
def test_option_in_branch(self):
1612
self.branch_config.set_user_option('file', 'branch')
1613
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
1616
def test_option_in_bazaar_and_branch(self):
1617
self.bazaar_config.set_user_option('file', 'bazaar')
1618
self.branch_config.set_user_option('file', 'branch')
1619
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
1620
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1623
def test_option_in_branch_and_locations(self):
1624
# Hmm, locations override branch :-/
1625
self.locations_config.set_user_option('file', 'locations')
1626
self.branch_config.set_user_option('file', 'branch')
1628
[('file', 'locations', self.tree.basedir, 'locations'),
1629
('file', 'branch', 'DEFAULT', 'branch'),],
1632
def test_option_in_bazaar_locations_and_branch(self):
1633
self.bazaar_config.set_user_option('file', 'bazaar')
1634
self.locations_config.set_user_option('file', 'locations')
1635
self.branch_config.set_user_option('file', 'branch')
1637
[('file', 'locations', self.tree.basedir, 'locations'),
1638
('file', 'branch', 'DEFAULT', 'branch'),
1639
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1643
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1646
super(TestConfigRemoveOption, self).setUp()
1647
create_configs_with_file_option(self)
1649
def test_remove_in_locations(self):
1650
self.locations_config.remove_user_option('file', self.tree.basedir)
1652
[('file', 'branch', 'DEFAULT', 'branch'),
1653
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1656
def test_remove_in_branch(self):
1657
self.branch_config.remove_user_option('file')
1659
[('file', 'locations', self.tree.basedir, 'locations'),
1660
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1663
def test_remove_in_bazaar(self):
1664
self.bazaar_config.remove_user_option('file')
1666
[('file', 'locations', self.tree.basedir, 'locations'),
1667
('file', 'branch', 'DEFAULT', 'branch'),],
1671
class TestConfigGetSections(tests.TestCaseWithTransport):
1674
super(TestConfigGetSections, self).setUp()
1675
create_configs(self)
1677
def assertSectionNames(self, expected, conf, name=None):
1678
"""Check which sections are returned for a given config.
1680
If fallback configurations exist their sections can be included.
1682
:param expected: A list of section names.
1684
:param conf: The configuration that will be queried.
1686
:param name: An optional section name that will be passed to
1689
sections = list(conf._get_sections(name))
1690
self.assertLength(len(expected), sections)
1691
self.assertEqual(expected, [name for name, _, _ in sections])
1693
def test_bazaar_default_section(self):
1694
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1696
def test_locations_default_section(self):
1697
# No sections are defined in an empty file
1698
self.assertSectionNames([], self.locations_config)
1700
def test_locations_named_section(self):
1701
self.locations_config.set_user_option('file', 'locations')
1702
self.assertSectionNames([self.tree.basedir], self.locations_config)
1704
def test_locations_matching_sections(self):
1705
loc_config = self.locations_config
1706
loc_config.set_user_option('file', 'locations')
1707
# We need to cheat a bit here to create an option in sections above and
1708
# below the 'location' one.
1709
parser = loc_config._get_parser()
1710
# locations.cong deals with '/' ignoring native os.sep
1711
location_names = self.tree.basedir.split('/')
1712
parent = '/'.join(location_names[:-1])
1713
child = '/'.join(location_names + ['child'])
1715
parser[parent]['file'] = 'parent'
1717
parser[child]['file'] = 'child'
1718
self.assertSectionNames([self.tree.basedir, parent], loc_config)
1720
def test_branch_data_default_section(self):
1721
self.assertSectionNames([None],
1722
self.branch_config._get_branch_data_config())
1724
def test_branch_default_sections(self):
1725
# No sections are defined in an empty locations file
1726
self.assertSectionNames([None, 'DEFAULT'],
1728
# Unless we define an option
1729
self.branch_config._get_location_config().set_user_option(
1730
'file', 'locations')
1731
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
1734
def test_bazaar_named_section(self):
1735
# We need to cheat as the API doesn't give direct access to sections
1736
# other than DEFAULT.
1737
self.bazaar_config.set_alias('bazaar', 'bzr')
1738
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1335
1741
class TestAuthenticationConfigFile(tests.TestCase):
1336
1742
"""Test the authentication.conf file matching"""