367
432
'/home/bogus/.cache')
370
class TestIniConfig(tests.TestCase):
435
class TestIniConfig(tests.TestCaseInTempDir):
372
437
def make_config_parser(self, s):
373
conf = config.IniBasedConfig(None)
374
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
438
conf = config.IniBasedConfig.from_string(s)
439
return conf, conf._get_parser()
378
442
class TestIniConfigBuilding(TestIniConfig):
380
444
def test_contructs(self):
381
my_config = config.IniBasedConfig("nothing")
445
my_config = config.IniBasedConfig()
383
447
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))
448
my_config = config.IniBasedConfig.from_string(sample_config_text)
449
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
390
451
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)
452
my_config = config.IniBasedConfig.from_string(sample_config_text)
453
parser = my_config._get_parser()
394
454
self.failUnless(my_config._get_parser() is parser)
456
def _dummy_chown(self, path, uid, gid):
457
self.path, self.uid, self.gid = path, uid, gid
459
def test_ini_config_ownership(self):
460
"""Ensure that chown is happening during _write_config_file"""
461
self.requireFeature(features.chown_feature)
462
self.overrideAttr(os, 'chown', self._dummy_chown)
463
self.path = self.uid = self.gid = None
464
conf = config.IniBasedConfig(file_name='./foo.conf')
465
conf._write_config_file()
466
self.assertEquals(self.path, './foo.conf')
467
self.assertTrue(isinstance(self.uid, int))
468
self.assertTrue(isinstance(self.gid, int))
470
def test_get_filename_parameter_is_deprecated_(self):
471
conf = self.callDeprecated([
472
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
473
' Use file_name instead.'],
474
config.IniBasedConfig, lambda: 'ini.conf')
475
self.assertEqual('ini.conf', conf.file_name)
477
def test_get_parser_file_parameter_is_deprecated_(self):
478
config_file = StringIO(sample_config_text.encode('utf-8'))
479
conf = config.IniBasedConfig.from_string(sample_config_text)
480
conf = self.callDeprecated([
481
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
482
' Use IniBasedConfig(_content=xxx) instead.'],
483
conf._get_parser, file=config_file)
485
class TestIniConfigSaving(tests.TestCaseInTempDir):
487
def test_cant_save_without_a_file_name(self):
488
conf = config.IniBasedConfig()
489
self.assertRaises(AssertionError, conf._write_config_file)
491
def test_saved_with_content(self):
492
content = 'foo = bar\n'
493
conf = config.IniBasedConfig.from_string(
494
content, file_name='./test.conf', save=True)
495
self.assertFileEqual(content, 'test.conf')
498
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
500
def test_cannot_reload_without_name(self):
501
conf = config.IniBasedConfig.from_string(sample_config_text)
502
self.assertRaises(AssertionError, conf.reload)
504
def test_reload_see_new_value(self):
505
c1 = config.IniBasedConfig.from_string('editor=vim\n',
506
file_name='./test/conf')
507
c1._write_config_file()
508
c2 = config.IniBasedConfig.from_string('editor=emacs\n',
509
file_name='./test/conf')
510
c2._write_config_file()
511
self.assertEqual('vim', c1.get_user_option('editor'))
512
self.assertEqual('emacs', c2.get_user_option('editor'))
513
# Make sure we get the Right value
515
self.assertEqual('emacs', c1.get_user_option('editor'))
518
class TestLockableConfig(tests.TestCaseInTempDir):
520
scenarios = lockable_config_scenarios()
525
config_section = None
528
super(TestLockableConfig, self).setUp()
529
self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
530
self.config = self.create_config(self._content)
532
def get_existing_config(self):
533
return self.config_class(*self.config_args)
535
def create_config(self, content):
536
kwargs = dict(save=True)
537
c = self.config_class.from_string(content, *self.config_args, **kwargs)
540
def test_simple_read_access(self):
541
self.assertEquals('1', self.config.get_user_option('one'))
543
def test_simple_write_access(self):
544
self.config.set_user_option('one', 'one')
545
self.assertEquals('one', self.config.get_user_option('one'))
547
def test_listen_to_the_last_speaker(self):
549
c2 = self.get_existing_config()
550
c1.set_user_option('one', 'ONE')
551
c2.set_user_option('two', 'TWO')
552
self.assertEquals('ONE', c1.get_user_option('one'))
553
self.assertEquals('TWO', c2.get_user_option('two'))
554
# The second update respect the first one
555
self.assertEquals('ONE', c2.get_user_option('one'))
557
def test_last_speaker_wins(self):
558
# If the same config is not shared, the same variable modified twice
559
# can only see a single result.
561
c2 = self.get_existing_config()
562
c1.set_user_option('one', 'c1')
563
c2.set_user_option('one', 'c2')
564
self.assertEquals('c2', c2._get_user_option('one'))
565
# The first modification is still available until another refresh
567
self.assertEquals('c1', c1._get_user_option('one'))
568
c1.set_user_option('two', 'done')
569
self.assertEquals('c2', c1._get_user_option('one'))
571
def test_writes_are_serialized(self):
573
c2 = self.get_existing_config()
575
# We spawn a thread that will pause *during* the write
576
before_writing = threading.Event()
577
after_writing = threading.Event()
578
writing_done = threading.Event()
579
c1_orig = c1._write_config_file
580
def c1_write_config_file():
583
# The lock is held we wait for the main thread to decide when to
586
c1._write_config_file = c1_write_config_file
588
c1.set_user_option('one', 'c1')
590
t1 = threading.Thread(target=c1_set_option)
591
# Collect the thread after the test
592
self.addCleanup(t1.join)
593
# Be ready to unblock the thread if the test goes wrong
594
self.addCleanup(after_writing.set)
596
before_writing.wait()
597
self.assertTrue(c1._lock.is_held)
598
self.assertRaises(errors.LockContention,
599
c2.set_user_option, 'one', 'c2')
600
self.assertEquals('c1', c1.get_user_option('one'))
601
# Let the lock be released
604
c2.set_user_option('one', 'c2')
605
self.assertEquals('c2', c2.get_user_option('one'))
607
def test_read_while_writing(self):
609
# We spawn a thread that will pause *during* the write
610
ready_to_write = threading.Event()
611
do_writing = threading.Event()
612
writing_done = threading.Event()
613
c1_orig = c1._write_config_file
614
def c1_write_config_file():
616
# The lock is held we wait for the main thread to decide when to
621
c1._write_config_file = c1_write_config_file
623
c1.set_user_option('one', 'c1')
624
t1 = threading.Thread(target=c1_set_option)
625
# Collect the thread after the test
626
self.addCleanup(t1.join)
627
# Be ready to unblock the thread if the test goes wrong
628
self.addCleanup(do_writing.set)
630
# Ensure the thread is ready to write
631
ready_to_write.wait()
632
self.assertTrue(c1._lock.is_held)
633
self.assertEquals('c1', c1.get_user_option('one'))
634
# If we read during the write, we get the old value
635
c2 = self.get_existing_config()
636
self.assertEquals('1', c2.get_user_option('one'))
637
# Let the writing occur and ensure it occurred
640
# Now we get the updated value
641
c3 = self.get_existing_config()
642
self.assertEquals('c1', c3.get_user_option('one'))
397
645
class TestGetUserOptionAs(TestIniConfig):
550
803
self.assertEqual(1, len(warnings))
551
804
self.assertEqual(warning, warnings[0])
552
trace.warning = warning
554
branch = self.make_branch('.')
555
conf = branch.get_config()
556
set_option(config.STORE_GLOBAL)
558
set_option(config.STORE_BRANCH)
560
set_option(config.STORE_GLOBAL)
561
assertWarning('Value "4" is masked by "3" from branch.conf')
562
set_option(config.STORE_GLOBAL, warn_masked=False)
564
set_option(config.STORE_LOCATION)
566
set_option(config.STORE_BRANCH)
567
assertWarning('Value "3" is masked by "0" from locations.conf')
568
set_option(config.STORE_BRANCH, warn_masked=False)
571
trace.warning = _warning
574
class TestGlobalConfigItems(tests.TestCase):
805
branch = self.make_branch('.')
806
conf = branch.get_config()
807
set_option(config.STORE_GLOBAL)
809
set_option(config.STORE_BRANCH)
811
set_option(config.STORE_GLOBAL)
812
assertWarning('Value "4" is masked by "3" from branch.conf')
813
set_option(config.STORE_GLOBAL, warn_masked=False)
815
set_option(config.STORE_LOCATION)
817
set_option(config.STORE_BRANCH)
818
assertWarning('Value "3" is masked by "0" from locations.conf')
819
set_option(config.STORE_BRANCH, warn_masked=False)
823
class TestGlobalConfigItems(tests.TestCaseInTempDir):
576
825
def test_user_id(self):
577
config_file = StringIO(sample_config_text.encode('utf-8'))
578
my_config = config.GlobalConfig()
579
my_config._parser = my_config._get_parser(file=config_file)
826
my_config = config.GlobalConfig.from_string(sample_config_text)
580
827
self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
581
828
my_config._get_user_id())
583
830
def test_absent_user_id(self):
584
config_file = StringIO("")
585
831
my_config = config.GlobalConfig()
586
my_config._parser = my_config._get_parser(file=config_file)
587
832
self.assertEqual(None, my_config._get_user_id())
589
834
def test_configured_editor(self):
590
config_file = StringIO(sample_config_text.encode('utf-8'))
591
my_config = config.GlobalConfig()
592
my_config._parser = my_config._get_parser(file=config_file)
835
my_config = config.GlobalConfig.from_string(sample_config_text)
593
836
self.assertEqual("vim", my_config.get_editor())
595
838
def test_signatures_always(self):
596
config_file = StringIO(sample_always_signatures)
597
my_config = config.GlobalConfig()
598
my_config._parser = my_config._get_parser(file=config_file)
839
my_config = config.GlobalConfig.from_string(sample_always_signatures)
599
840
self.assertEqual(config.CHECK_NEVER,
600
841
my_config.signature_checking())
601
842
self.assertEqual(config.SIGN_ALWAYS,
982
1218
self.assertEqual('bzrlib.tests.test_config.post_commit',
983
1219
self.my_config.post_commit())
985
def get_branch_config(self, location, global_config=None):
1221
def get_branch_config(self, location, global_config=None,
1222
location_config=None):
1223
my_branch = FakeBranch(location)
986
1224
if global_config is None:
987
global_file = StringIO(sample_config_text.encode('utf-8'))
989
global_file = StringIO(global_config.encode('utf-8'))
990
branches_file = StringIO(sample_branches_text.encode('utf-8'))
991
self.my_config = config.BranchConfig(FakeBranch(location))
992
# Force location config to use specified file
993
self.my_location_config = self.my_config._get_location_config()
994
self.my_location_config._get_parser(branches_file)
995
# Force global config to use specified file
996
self.my_config._get_global_config()._get_parser(global_file)
1225
global_config = sample_config_text
1226
if location_config is None:
1227
location_config = sample_branches_text
1229
my_global_config = config.GlobalConfig.from_string(global_config,
1231
my_location_config = config.LocationConfig.from_string(
1232
location_config, my_branch.base, save=True)
1233
my_config = config.BranchConfig(my_branch)
1234
self.my_config = my_config
1235
self.my_location_config = my_config._get_location_config()
998
1237
def test_set_user_setting_sets_and_saves(self):
999
1238
self.get_branch_config('/a/c')
1000
1239
record = InstrumentedConfigObj("foo")
1001
1240
self.my_location_config._parser = record
1003
real_mkdir = os.mkdir
1004
self.created = False
1005
def checked_mkdir(path, mode=0777):
1006
self.log('making directory: %s', path)
1007
real_mkdir(path, mode)
1010
os.mkdir = checked_mkdir
1012
self.callDeprecated(['The recurse option is deprecated as of '
1013
'0.14. The section "/a/c" has been '
1014
'converted to use policies.'],
1015
self.my_config.set_user_option,
1016
'foo', 'bar', store=config.STORE_LOCATION)
1018
os.mkdir = real_mkdir
1020
self.failUnless(self.created, 'Failed to create ~/.bazaar')
1021
self.assertEqual([('__contains__', '/a/c'),
1242
self.callDeprecated(['The recurse option is deprecated as of '
1243
'0.14. The section "/a/c" has been '
1244
'converted to use policies.'],
1245
self.my_config.set_user_option,
1246
'foo', 'bar', store=config.STORE_LOCATION)
1247
self.assertEqual([('reload',),
1248
('__contains__', '/a/c'),
1022
1249
('__contains__', '/a/c/'),
1023
1250
('__setitem__', '/a/c', {}),
1024
1251
('__getitem__', '/a/c'),
1130
1356
def test_gpg_signing_command(self):
1131
1357
my_config = self.get_branch_config(
1358
global_config=sample_config_text,
1132
1359
# branch data cannot set gpg_signing_command
1133
1360
branch_data_config="gpg_signing_command=pgp")
1134
config_file = StringIO(sample_config_text.encode('utf-8'))
1135
my_config._get_global_config()._get_parser(config_file)
1136
1361
self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1138
1363
def test_get_user_option_global(self):
1139
branch = FakeBranch()
1140
my_config = config.BranchConfig(branch)
1141
config_file = StringIO(sample_config_text.encode('utf-8'))
1142
(my_config._get_global_config()._get_parser(config_file))
1364
my_config = self.get_branch_config(global_config=sample_config_text)
1143
1365
self.assertEqual('something',
1144
1366
my_config.get_user_option('user_global_option'))
1146
1368
def test_post_commit_default(self):
1147
branch = FakeBranch()
1148
my_config = self.get_branch_config(sample_config_text, '/a/c',
1149
sample_branches_text)
1369
my_config = self.get_branch_config(global_config=sample_config_text,
1371
location_config=sample_branches_text)
1150
1372
self.assertEqual(my_config.branch.base, '/a/c')
1151
1373
self.assertEqual('bzrlib.tests.test_config.post_commit',
1152
1374
my_config.post_commit())
1153
1375
my_config.set_user_option('post_commit', 'rmtree_root')
1154
# post-commit is ignored when bresent in branch data
1376
# post-commit is ignored when present in branch data
1155
1377
self.assertEqual('bzrlib.tests.test_config.post_commit',
1156
1378
my_config.post_commit())
1157
1379
my_config.set_user_option('post_commit', 'rmtree_root',
1159
1381
self.assertEqual('rmtree_root', my_config.post_commit())
1161
1383
def test_config_precedence(self):
1384
# FIXME: eager test, luckily no persitent config file makes it fail
1162
1386
my_config = self.get_branch_config(global_config=precedence_global)
1163
1387
self.assertEqual(my_config.get_user_option('option'), 'global')
1164
1388
my_config = self.get_branch_config(global_config=precedence_global,
1165
branch_data_config=precedence_branch)
1389
branch_data_config=precedence_branch)
1166
1390
self.assertEqual(my_config.get_user_option('option'), 'branch')
1167
my_config = self.get_branch_config(global_config=precedence_global,
1168
branch_data_config=precedence_branch,
1169
location_config=precedence_location)
1391
my_config = self.get_branch_config(
1392
global_config=precedence_global,
1393
branch_data_config=precedence_branch,
1394
location_config=precedence_location)
1170
1395
self.assertEqual(my_config.get_user_option('option'), 'recurse')
1171
my_config = self.get_branch_config(global_config=precedence_global,
1172
branch_data_config=precedence_branch,
1173
location_config=precedence_location,
1174
location='http://example.com/specific')
1396
my_config = self.get_branch_config(
1397
global_config=precedence_global,
1398
branch_data_config=precedence_branch,
1399
location_config=precedence_location,
1400
location='http://example.com/specific')
1175
1401
self.assertEqual(my_config.get_user_option('option'), 'exact')
1177
1403
def test_get_mail_client(self):
1305
1531
self.assertIs(None, bzrdir_config.get_default_stack_on())
1534
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1537
super(TestConfigGetOptions, self).setUp()
1538
create_configs(self)
1540
# One variable in none of the above
1541
def test_no_variable(self):
1542
# Using branch should query branch, locations and bazaar
1543
self.assertOptions([], self.branch_config)
1545
def test_option_in_bazaar(self):
1546
self.bazaar_config.set_user_option('file', 'bazaar')
1547
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1550
def test_option_in_locations(self):
1551
self.locations_config.set_user_option('file', 'locations')
1553
[('file', 'locations', self.tree.basedir, 'locations')],
1554
self.locations_config)
1556
def test_option_in_branch(self):
1557
self.branch_config.set_user_option('file', 'branch')
1558
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
1561
def test_option_in_bazaar_and_branch(self):
1562
self.bazaar_config.set_user_option('file', 'bazaar')
1563
self.branch_config.set_user_option('file', 'branch')
1564
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
1565
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1568
def test_option_in_branch_and_locations(self):
1569
# Hmm, locations override branch :-/
1570
self.locations_config.set_user_option('file', 'locations')
1571
self.branch_config.set_user_option('file', 'branch')
1573
[('file', 'locations', self.tree.basedir, 'locations'),
1574
('file', 'branch', 'DEFAULT', 'branch'),],
1577
def test_option_in_bazaar_locations_and_branch(self):
1578
self.bazaar_config.set_user_option('file', 'bazaar')
1579
self.locations_config.set_user_option('file', 'locations')
1580
self.branch_config.set_user_option('file', 'branch')
1582
[('file', 'locations', self.tree.basedir, 'locations'),
1583
('file', 'branch', 'DEFAULT', 'branch'),
1584
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1588
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1591
super(TestConfigRemoveOption, self).setUp()
1592
create_configs_with_file_option(self)
1594
def test_remove_in_locations(self):
1595
self.locations_config.remove_user_option('file', self.tree.basedir)
1597
[('file', 'branch', 'DEFAULT', 'branch'),
1598
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1601
def test_remove_in_branch(self):
1602
self.branch_config.remove_user_option('file')
1604
[('file', 'locations', self.tree.basedir, 'locations'),
1605
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1608
def test_remove_in_bazaar(self):
1609
self.bazaar_config.remove_user_option('file')
1611
[('file', 'locations', self.tree.basedir, 'locations'),
1612
('file', 'branch', 'DEFAULT', 'branch'),],
1616
class TestConfigGetSections(tests.TestCaseWithTransport):
1619
super(TestConfigGetSections, self).setUp()
1620
create_configs(self)
1622
def assertSectionNames(self, expected, conf, name=None):
1623
"""Check which sections are returned for a given config.
1625
If fallback configurations exist their sections can be included.
1627
:param expected: A list of section names.
1629
:param conf: The configuration that will be queried.
1631
:param name: An optional section name that will be passed to
1634
sections = list(conf._get_sections(name))
1635
self.assertLength(len(expected), sections)
1636
self.assertEqual(expected, [name for name, _, _ in sections])
1638
def test_bazaar_default_section(self):
1639
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1641
def test_locations_default_section(self):
1642
# No sections are defined in an empty file
1643
self.assertSectionNames([], self.locations_config)
1645
def test_locations_named_section(self):
1646
self.locations_config.set_user_option('file', 'locations')
1647
self.assertSectionNames([self.tree.basedir], self.locations_config)
1649
def test_locations_matching_sections(self):
1650
loc_config = self.locations_config
1651
loc_config.set_user_option('file', 'locations')
1652
# We need to cheat a bit here to create an option in sections above and
1653
# below the 'location' one.
1654
parser = loc_config._get_parser()
1655
# locations.cong deals with '/' ignoring native os.sep
1656
location_names = self.tree.basedir.split('/')
1657
parent = '/'.join(location_names[:-1])
1658
child = '/'.join(location_names + ['child'])
1660
parser[parent]['file'] = 'parent'
1662
parser[child]['file'] = 'child'
1663
self.assertSectionNames([self.tree.basedir, parent], loc_config)
1665
def test_branch_data_default_section(self):
1666
self.assertSectionNames([None],
1667
self.branch_config._get_branch_data_config())
1669
def test_branch_default_sections(self):
1670
# No sections are defined in an empty locations file
1671
self.assertSectionNames([None, 'DEFAULT'],
1673
# Unless we define an option
1674
self.branch_config._get_location_config().set_user_option(
1675
'file', 'locations')
1676
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
1679
def test_bazaar_named_section(self):
1680
# We need to cheat as the API doesn't give direct access to sections
1681
# other than DEFAULT.
1682
self.bazaar_config.set_alias('bazaar', 'bzr')
1683
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1308
1686
class TestAuthenticationConfigFile(tests.TestCase):
1309
1687
"""Test the authentication.conf file matching"""