368
432
'/home/bogus/.cache')
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
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
self.overrideEnv('HOME', self.test_home_dir)
445
# BZR_HOME overrides everything we want to test so unset it.
446
self.overrideEnv('BZR_HOME', None)
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')
452
self.assertEqual(config.config_dir(), newdir)
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
self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
458
newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
460
self.assertEqual(config.config_dir(), newdir)
371
463
class TestIniConfig(tests.TestCaseInTempDir):
373
465
def make_config_parser(self, s):
374
conf = config.IniBasedConfig(None)
375
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
466
conf = config.IniBasedConfig.from_string(s)
467
return conf, conf._get_parser()
379
470
class TestIniConfigBuilding(TestIniConfig):
381
472
def test_contructs(self):
382
my_config = config.IniBasedConfig("nothing")
473
my_config = config.IniBasedConfig()
384
475
def test_from_fp(self):
385
config_file = StringIO(sample_config_text.encode('utf-8'))
386
my_config = config.IniBasedConfig(None)
388
isinstance(my_config._get_parser(file=config_file),
389
configobj.ConfigObj))
476
my_config = config.IniBasedConfig.from_string(sample_config_text)
477
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
391
479
def test_cached(self):
392
config_file = StringIO(sample_config_text.encode('utf-8'))
393
my_config = config.IniBasedConfig(None)
394
parser = my_config._get_parser(file=config_file)
480
my_config = config.IniBasedConfig.from_string(sample_config_text)
481
parser = my_config._get_parser()
395
482
self.failUnless(my_config._get_parser() is parser)
397
484
def _dummy_chown(self, path, uid, gid):
398
485
self.path, self.uid, self.gid = path, uid, gid
400
487
def test_ini_config_ownership(self):
401
"""Ensure that chown is happening during _write_config_file.
488
"""Ensure that chown is happening during _write_config_file"""
403
489
self.requireFeature(features.chown_feature)
404
490
self.overrideAttr(os, 'chown', self._dummy_chown)
405
491
self.path = self.uid = self.gid = None
408
conf = config.IniBasedConfig(get_filename)
492
conf = config.IniBasedConfig(file_name='./foo.conf')
409
493
conf._write_config_file()
410
self.assertEquals(self.path, 'foo.conf')
494
self.assertEquals(self.path, './foo.conf')
411
495
self.assertTrue(isinstance(self.uid, int))
412
496
self.assertTrue(isinstance(self.gid, int))
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)
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)
513
class TestIniConfigSaving(tests.TestCaseInTempDir):
515
def test_cant_save_without_a_file_name(self):
516
conf = config.IniBasedConfig()
517
self.assertRaises(AssertionError, conf._write_config_file)
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')
526
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
528
def test_cannot_reload_without_name(self):
529
conf = config.IniBasedConfig.from_string(sample_config_text)
530
self.assertRaises(AssertionError, conf.reload)
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
543
self.assertEqual('emacs', c1.get_user_option('editor'))
546
class TestLockableConfig(tests.TestCaseInTempDir):
548
scenarios = lockable_config_scenarios()
553
config_section = None
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)
560
def get_existing_config(self):
561
return self.config_class(*self.config_args)
563
def create_config(self, content):
564
kwargs = dict(save=True)
565
c = self.config_class.from_string(content, *self.config_args, **kwargs)
568
def test_simple_read_access(self):
569
self.assertEquals('1', self.config.get_user_option('one'))
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'))
575
def test_listen_to_the_last_speaker(self):
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'))
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.
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
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'))
599
def test_writes_are_serialized(self):
601
c2 = self.get_existing_config()
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():
611
# The lock is held we wait for the main thread to decide when to
614
c1._write_config_file = c1_write_config_file
616
c1.set_user_option('one', 'c1')
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)
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
632
c2.set_user_option('one', 'c2')
633
self.assertEquals('c2', c2.get_user_option('one'))
635
def test_read_while_writing(self):
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():
644
# The lock is held we wait for the main thread to decide when to
649
c1._write_config_file = c1_write_config_file
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)
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
668
# Now we get the updated value
669
c3 = self.get_existing_config()
670
self.assertEquals('c1', c3.get_user_option('one'))
414
673
class TestGetUserOptionAs(TestIniConfig):
416
675
def test_get_user_option_as_bool(self):
574
831
self.assertEqual(1, len(warnings))
575
832
self.assertEqual(warning, warnings[0])
576
trace.warning = warning
578
branch = self.make_branch('.')
579
conf = branch.get_config()
580
set_option(config.STORE_GLOBAL)
582
set_option(config.STORE_BRANCH)
584
set_option(config.STORE_GLOBAL)
585
assertWarning('Value "4" is masked by "3" from branch.conf')
586
set_option(config.STORE_GLOBAL, warn_masked=False)
588
set_option(config.STORE_LOCATION)
590
set_option(config.STORE_BRANCH)
591
assertWarning('Value "3" is masked by "0" from locations.conf')
592
set_option(config.STORE_BRANCH, warn_masked=False)
595
trace.warning = _warning
598
class TestGlobalConfigItems(tests.TestCase):
833
branch = self.make_branch('.')
834
conf = branch.get_config()
835
set_option(config.STORE_GLOBAL)
837
set_option(config.STORE_BRANCH)
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)
843
set_option(config.STORE_LOCATION)
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)
851
class TestGlobalConfigItems(tests.TestCaseInTempDir):
600
853
def test_user_id(self):
601
config_file = StringIO(sample_config_text.encode('utf-8'))
602
my_config = config.GlobalConfig()
603
my_config._parser = my_config._get_parser(file=config_file)
854
my_config = config.GlobalConfig.from_string(sample_config_text)
604
855
self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
605
856
my_config._get_user_id())
607
858
def test_absent_user_id(self):
608
config_file = StringIO("")
609
859
my_config = config.GlobalConfig()
610
my_config._parser = my_config._get_parser(file=config_file)
611
860
self.assertEqual(None, my_config._get_user_id())
613
862
def test_configured_editor(self):
614
config_file = StringIO(sample_config_text.encode('utf-8'))
615
my_config = config.GlobalConfig()
616
my_config._parser = my_config._get_parser(file=config_file)
863
my_config = config.GlobalConfig.from_string(sample_config_text)
617
864
self.assertEqual("vim", my_config.get_editor())
619
866
def test_signatures_always(self):
620
config_file = StringIO(sample_always_signatures)
621
my_config = config.GlobalConfig()
622
my_config._parser = my_config._get_parser(file=config_file)
867
my_config = config.GlobalConfig.from_string(sample_always_signatures)
623
868
self.assertEqual(config.CHECK_NEVER,
624
869
my_config.signature_checking())
625
870
self.assertEqual(config.SIGN_ALWAYS,
1006
1246
self.assertEqual('bzrlib.tests.test_config.post_commit',
1007
1247
self.my_config.post_commit())
1009
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)
1010
1252
if global_config is None:
1011
global_file = StringIO(sample_config_text.encode('utf-8'))
1013
global_file = StringIO(global_config.encode('utf-8'))
1014
branches_file = StringIO(sample_branches_text.encode('utf-8'))
1015
self.my_config = config.BranchConfig(FakeBranch(location))
1016
# Force location config to use specified file
1017
self.my_location_config = self.my_config._get_location_config()
1018
self.my_location_config._get_parser(branches_file)
1019
# Force global config to use specified file
1020
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
1257
my_global_config = config.GlobalConfig.from_string(global_config,
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()
1022
1265
def test_set_user_setting_sets_and_saves(self):
1023
1266
self.get_branch_config('/a/c')
1024
1267
record = InstrumentedConfigObj("foo")
1025
1268
self.my_location_config._parser = record
1027
real_mkdir = os.mkdir
1028
self.created = False
1029
def checked_mkdir(path, mode=0777):
1030
self.log('making directory: %s', path)
1031
real_mkdir(path, mode)
1034
os.mkdir = checked_mkdir
1036
self.callDeprecated(['The recurse option is deprecated as of '
1037
'0.14. The section "/a/c" has been '
1038
'converted to use policies.'],
1039
self.my_config.set_user_option,
1040
'foo', 'bar', store=config.STORE_LOCATION)
1042
os.mkdir = real_mkdir
1044
self.failUnless(self.created, 'Failed to create ~/.bazaar')
1045
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'),
1046
1277
('__contains__', '/a/c/'),
1047
1278
('__setitem__', '/a/c', {}),
1048
1279
('__getitem__', '/a/c'),
1329
1559
self.assertIs(None, bzrdir_config.get_default_stack_on())
1562
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1565
super(TestConfigGetOptions, self).setUp()
1566
create_configs(self)
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)
1573
def test_option_in_bazaar(self):
1574
self.bazaar_config.set_user_option('file', 'bazaar')
1575
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1578
def test_option_in_locations(self):
1579
self.locations_config.set_user_option('file', 'locations')
1581
[('file', 'locations', self.tree.basedir, 'locations')],
1582
self.locations_config)
1584
def test_option_in_branch(self):
1585
self.branch_config.set_user_option('file', 'branch')
1586
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
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'),],
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')
1601
[('file', 'locations', self.tree.basedir, 'locations'),
1602
('file', 'branch', 'DEFAULT', 'branch'),],
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')
1610
[('file', 'locations', self.tree.basedir, 'locations'),
1611
('file', 'branch', 'DEFAULT', 'branch'),
1612
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1616
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1619
super(TestConfigRemoveOption, self).setUp()
1620
create_configs_with_file_option(self)
1622
def test_remove_in_locations(self):
1623
self.locations_config.remove_user_option('file', self.tree.basedir)
1625
[('file', 'branch', 'DEFAULT', 'branch'),
1626
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1629
def test_remove_in_branch(self):
1630
self.branch_config.remove_user_option('file')
1632
[('file', 'locations', self.tree.basedir, 'locations'),
1633
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1636
def test_remove_in_bazaar(self):
1637
self.bazaar_config.remove_user_option('file')
1639
[('file', 'locations', self.tree.basedir, 'locations'),
1640
('file', 'branch', 'DEFAULT', 'branch'),],
1644
class TestConfigGetSections(tests.TestCaseWithTransport):
1647
super(TestConfigGetSections, self).setUp()
1648
create_configs(self)
1650
def assertSectionNames(self, expected, conf, name=None):
1651
"""Check which sections are returned for a given config.
1653
If fallback configurations exist their sections can be included.
1655
:param expected: A list of section names.
1657
:param conf: The configuration that will be queried.
1659
:param name: An optional section name that will be passed to
1662
sections = list(conf._get_sections(name))
1663
self.assertLength(len(expected), sections)
1664
self.assertEqual(expected, [name for name, _, _ in sections])
1666
def test_bazaar_default_section(self):
1667
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1669
def test_locations_default_section(self):
1670
# No sections are defined in an empty file
1671
self.assertSectionNames([], self.locations_config)
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)
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'])
1688
parser[parent]['file'] = 'parent'
1690
parser[child]['file'] = 'child'
1691
self.assertSectionNames([self.tree.basedir, parent], loc_config)
1693
def test_branch_data_default_section(self):
1694
self.assertSectionNames([None],
1695
self.branch_config._get_branch_data_config())
1697
def test_branch_default_sections(self):
1698
# No sections are defined in an empty locations file
1699
self.assertSectionNames([None, 'DEFAULT'],
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'],
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')
1332
1714
class TestAuthenticationConfigFile(tests.TestCase):
1333
1715
"""Test the authentication.conf file matching"""