234
419
my_config = config.Config()
235
420
self.assertEqual('long', my_config.log_format())
238
class TestConfigPath(TestCase):
422
def test_get_change_editor(self):
423
my_config = InstrumentedConfig()
424
change_editor = my_config.get_change_editor('old_tree', 'new_tree')
425
self.assertEqual(['_get_change_editor'], my_config._calls)
426
self.assertIs(diff.DiffFromTool, change_editor.__class__)
427
self.assertEqual(['vimdiff', '-fo', '@new_path', '@old_path'],
428
change_editor.command_template)
431
class TestConfigPath(tests.TestCase):
241
434
super(TestConfigPath, self).setUp()
242
self.old_home = os.environ.get('HOME', None)
243
self.old_appdata = os.environ.get('APPDATA', None)
244
os.environ['HOME'] = '/home/bogus'
245
os.environ['APPDATA'] = \
246
r'C:\Documents and Settings\bogus\Application Data'
435
self.overrideEnv('HOME', '/home/bogus')
436
self.overrideEnv('XDG_CACHE_DIR', '')
437
if sys.platform == 'win32':
439
'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
441
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
443
self.bzr_home = '/home/bogus/.bazaar'
249
if self.old_home is None:
250
del os.environ['HOME']
252
os.environ['HOME'] = self.old_home
253
if self.old_appdata is None:
254
del os.environ['APPDATA']
256
os.environ['APPDATA'] = self.old_appdata
257
super(TestConfigPath, self).tearDown()
259
445
def test_config_dir(self):
260
if sys.platform == 'win32':
261
self.assertEqual(config.config_dir(),
262
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0')
264
self.assertEqual(config.config_dir(), '/home/bogus/.bazaar')
446
self.assertEqual(config.config_dir(), self.bzr_home)
266
448
def test_config_filename(self):
267
if sys.platform == 'win32':
268
self.assertEqual(config.config_filename(),
269
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/bazaar.conf')
271
self.assertEqual(config.config_filename(),
272
'/home/bogus/.bazaar/bazaar.conf')
274
def test_branches_config_filename(self):
275
if sys.platform == 'win32':
276
self.assertEqual(config.branches_config_filename(),
277
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/branches.conf')
279
self.assertEqual(config.branches_config_filename(),
280
'/home/bogus/.bazaar/branches.conf')
449
self.assertEqual(config.config_filename(),
450
self.bzr_home + '/bazaar.conf')
282
452
def test_locations_config_filename(self):
283
if sys.platform == 'win32':
284
self.assertEqual(config.locations_config_filename(),
285
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/locations.conf')
287
self.assertEqual(config.locations_config_filename(),
288
'/home/bogus/.bazaar/locations.conf')
290
class TestIniConfig(TestCase):
453
self.assertEqual(config.locations_config_filename(),
454
self.bzr_home + '/locations.conf')
456
def test_authentication_config_filename(self):
457
self.assertEqual(config.authentication_config_filename(),
458
self.bzr_home + '/authentication.conf')
460
def test_xdg_cache_dir(self):
461
self.assertEqual(config.xdg_cache_dir(),
462
'/home/bogus/.cache')
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):
495
def make_config_parser(self, s):
496
conf = config.IniBasedConfig.from_string(s)
497
return conf, conf._get_parser()
500
class TestIniConfigBuilding(TestIniConfig):
292
502
def test_contructs(self):
293
my_config = config.IniBasedConfig("nothing")
503
my_config = config.IniBasedConfig()
295
505
def test_from_fp(self):
296
config_file = StringIO(sample_config_text.encode('utf-8'))
297
my_config = config.IniBasedConfig(None)
299
isinstance(my_config._get_parser(file=config_file),
506
my_config = config.IniBasedConfig.from_string(sample_config_text)
507
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
302
509
def test_cached(self):
303
config_file = StringIO(sample_config_text.encode('utf-8'))
304
my_config = config.IniBasedConfig(None)
305
parser = my_config._get_parser(file=config_file)
510
my_config = config.IniBasedConfig.from_string(sample_config_text)
511
parser = my_config._get_parser()
306
512
self.failUnless(my_config._get_parser() is parser)
309
class TestGetConfig(TestCase):
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'))
896
class TestGetUserOptionAs(TestIniConfig):
898
def test_get_user_option_as_bool(self):
899
conf, parser = self.make_config_parser("""
902
an_invalid_bool = maybe
903
a_list = hmm, who knows ? # This is interpreted as a list !
905
get_bool = conf.get_user_option_as_bool
906
self.assertEqual(True, get_bool('a_true_bool'))
907
self.assertEqual(False, get_bool('a_false_bool'))
910
warnings.append(args[0] % args[1:])
911
self.overrideAttr(trace, 'warning', warning)
912
msg = 'Value "%s" is not a boolean for "%s"'
913
self.assertIs(None, get_bool('an_invalid_bool'))
914
self.assertEquals(msg % ('maybe', 'an_invalid_bool'), warnings[0])
916
self.assertIs(None, get_bool('not_defined_in_this_config'))
917
self.assertEquals([], warnings)
919
def test_get_user_option_as_list(self):
920
conf, parser = self.make_config_parser("""
925
get_list = conf.get_user_option_as_list
926
self.assertEqual(['a', 'b', 'c'], get_list('a_list'))
927
self.assertEqual(['1'], get_list('length_1'))
928
self.assertEqual('x', conf.get_user_option('one_item'))
929
# automatically cast to list
930
self.assertEqual(['x'], get_list('one_item'))
933
class TestSupressWarning(TestIniConfig):
935
def make_warnings_config(self, s):
936
conf, parser = self.make_config_parser(s)
937
return conf.suppress_warning
939
def test_suppress_warning_unknown(self):
940
suppress_warning = self.make_warnings_config('')
941
self.assertEqual(False, suppress_warning('unknown_warning'))
943
def test_suppress_warning_known(self):
944
suppress_warning = self.make_warnings_config('suppress_warnings=a,b')
945
self.assertEqual(False, suppress_warning('c'))
946
self.assertEqual(True, suppress_warning('a'))
947
self.assertEqual(True, suppress_warning('b'))
950
class TestGetConfig(tests.TestCase):
311
952
def test_constructs(self):
312
953
my_config = config.GlobalConfig()
314
955
def test_calls_read_filenames(self):
315
# replace the class that is constructured, to check its parameters
956
# replace the class that is constructed, to check its parameters
316
957
oldparserclass = config.ConfigObj
317
958
config.ConfigObj = InstrumentedConfigObj
318
959
my_config = config.GlobalConfig()
775
1642
def test_gpg_signing_command(self):
776
1643
my_config = self.get_branch_config(
1644
global_config=sample_config_text,
777
1645
# branch data cannot set gpg_signing_command
778
1646
branch_data_config="gpg_signing_command=pgp")
779
config_file = StringIO(sample_config_text.encode('utf-8'))
780
my_config._get_global_config()._get_parser(config_file)
781
1647
self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
783
1649
def test_get_user_option_global(self):
784
branch = FakeBranch()
785
my_config = config.BranchConfig(branch)
786
config_file = StringIO(sample_config_text.encode('utf-8'))
787
(my_config._get_global_config()._get_parser(config_file))
1650
my_config = self.get_branch_config(global_config=sample_config_text)
788
1651
self.assertEqual('something',
789
1652
my_config.get_user_option('user_global_option'))
791
1654
def test_post_commit_default(self):
792
branch = FakeBranch()
793
my_config = self.get_branch_config(sample_config_text, '/a/c',
794
sample_branches_text)
1655
my_config = self.get_branch_config(global_config=sample_config_text,
1657
location_config=sample_branches_text)
795
1658
self.assertEqual(my_config.branch.base, '/a/c')
796
1659
self.assertEqual('bzrlib.tests.test_config.post_commit',
797
1660
my_config.post_commit())
798
1661
my_config.set_user_option('post_commit', 'rmtree_root')
799
# post-commit is ignored when bresent in branch data
1662
# post-commit is ignored when present in branch data
800
1663
self.assertEqual('bzrlib.tests.test_config.post_commit',
801
1664
my_config.post_commit())
802
my_config.set_user_option('post_commit', 'rmtree_root', local=True)
1665
my_config.set_user_option('post_commit', 'rmtree_root',
1666
store=config.STORE_LOCATION)
803
1667
self.assertEqual('rmtree_root', my_config.post_commit())
805
1669
def test_config_precedence(self):
1670
# FIXME: eager test, luckily no persitent config file makes it fail
806
1672
my_config = self.get_branch_config(global_config=precedence_global)
807
1673
self.assertEqual(my_config.get_user_option('option'), 'global')
808
my_config = self.get_branch_config(global_config=precedence_global,
809
branch_data_config=precedence_branch)
1674
my_config = self.get_branch_config(global_config=precedence_global,
1675
branch_data_config=precedence_branch)
810
1676
self.assertEqual(my_config.get_user_option('option'), 'branch')
811
my_config = self.get_branch_config(global_config=precedence_global,
812
branch_data_config=precedence_branch,
813
location_config=precedence_location)
1677
my_config = self.get_branch_config(
1678
global_config=precedence_global,
1679
branch_data_config=precedence_branch,
1680
location_config=precedence_location)
814
1681
self.assertEqual(my_config.get_user_option('option'), 'recurse')
815
my_config = self.get_branch_config(global_config=precedence_global,
816
branch_data_config=precedence_branch,
817
location_config=precedence_location,
818
location='http://example.com/specific')
1682
my_config = self.get_branch_config(
1683
global_config=precedence_global,
1684
branch_data_config=precedence_branch,
1685
location_config=precedence_location,
1686
location='http://example.com/specific')
819
1687
self.assertEqual(my_config.get_user_option('option'), 'exact')
822
class TestMailAddressExtraction(TestCase):
1689
def test_get_mail_client(self):
1690
config = self.get_branch_config()
1691
client = config.get_mail_client()
1692
self.assertIsInstance(client, mail_client.DefaultMail)
1695
config.set_user_option('mail_client', 'evolution')
1696
client = config.get_mail_client()
1697
self.assertIsInstance(client, mail_client.Evolution)
1699
config.set_user_option('mail_client', 'kmail')
1700
client = config.get_mail_client()
1701
self.assertIsInstance(client, mail_client.KMail)
1703
config.set_user_option('mail_client', 'mutt')
1704
client = config.get_mail_client()
1705
self.assertIsInstance(client, mail_client.Mutt)
1707
config.set_user_option('mail_client', 'thunderbird')
1708
client = config.get_mail_client()
1709
self.assertIsInstance(client, mail_client.Thunderbird)
1712
config.set_user_option('mail_client', 'default')
1713
client = config.get_mail_client()
1714
self.assertIsInstance(client, mail_client.DefaultMail)
1716
config.set_user_option('mail_client', 'editor')
1717
client = config.get_mail_client()
1718
self.assertIsInstance(client, mail_client.Editor)
1720
config.set_user_option('mail_client', 'mapi')
1721
client = config.get_mail_client()
1722
self.assertIsInstance(client, mail_client.MAPIClient)
1724
config.set_user_option('mail_client', 'xdg-email')
1725
client = config.get_mail_client()
1726
self.assertIsInstance(client, mail_client.XDGEmail)
1728
config.set_user_option('mail_client', 'firebird')
1729
self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
1732
class TestMailAddressExtraction(tests.TestCase):
824
1734
def test_extract_email_address(self):
825
1735
self.assertEqual('jane@test.com',
826
1736
config.extract_email_address('Jane <jane@test.com>'))
827
self.assertRaises(errors.BzrError,
1737
self.assertRaises(errors.NoEmailInUsername,
828
1738
config.extract_email_address, 'Jane Tester')
1740
def test_parse_username(self):
1741
self.assertEqual(('', 'jdoe@example.com'),
1742
config.parse_username('jdoe@example.com'))
1743
self.assertEqual(('', 'jdoe@example.com'),
1744
config.parse_username('<jdoe@example.com>'))
1745
self.assertEqual(('John Doe', 'jdoe@example.com'),
1746
config.parse_username('John Doe <jdoe@example.com>'))
1747
self.assertEqual(('John Doe', ''),
1748
config.parse_username('John Doe'))
1749
self.assertEqual(('John Doe', 'jdoe@example.com'),
1750
config.parse_username('John Doe jdoe@example.com'))
1752
class TestTreeConfig(tests.TestCaseWithTransport):
1754
def test_get_value(self):
1755
"""Test that retreiving a value from a section is possible"""
1756
branch = self.make_branch('.')
1757
tree_config = config.TreeConfig(branch)
1758
tree_config.set_option('value', 'key', 'SECTION')
1759
tree_config.set_option('value2', 'key2')
1760
tree_config.set_option('value3-top', 'key3')
1761
tree_config.set_option('value3-section', 'key3', 'SECTION')
1762
value = tree_config.get_option('key', 'SECTION')
1763
self.assertEqual(value, 'value')
1764
value = tree_config.get_option('key2')
1765
self.assertEqual(value, 'value2')
1766
self.assertEqual(tree_config.get_option('non-existant'), None)
1767
value = tree_config.get_option('non-existant', 'SECTION')
1768
self.assertEqual(value, None)
1769
value = tree_config.get_option('non-existant', default='default')
1770
self.assertEqual(value, 'default')
1771
self.assertEqual(tree_config.get_option('key2', 'NOSECTION'), None)
1772
value = tree_config.get_option('key2', 'NOSECTION', default='default')
1773
self.assertEqual(value, 'default')
1774
value = tree_config.get_option('key3')
1775
self.assertEqual(value, 'value3-top')
1776
value = tree_config.get_option('key3', 'SECTION')
1777
self.assertEqual(value, 'value3-section')
1780
class TestTransportConfig(tests.TestCaseWithTransport):
1782
def test_get_value(self):
1783
"""Test that retreiving a value from a section is possible"""
1784
bzrdir_config = config.TransportConfig(transport.get_transport('.'),
1786
bzrdir_config.set_option('value', 'key', 'SECTION')
1787
bzrdir_config.set_option('value2', 'key2')
1788
bzrdir_config.set_option('value3-top', 'key3')
1789
bzrdir_config.set_option('value3-section', 'key3', 'SECTION')
1790
value = bzrdir_config.get_option('key', 'SECTION')
1791
self.assertEqual(value, 'value')
1792
value = bzrdir_config.get_option('key2')
1793
self.assertEqual(value, 'value2')
1794
self.assertEqual(bzrdir_config.get_option('non-existant'), None)
1795
value = bzrdir_config.get_option('non-existant', 'SECTION')
1796
self.assertEqual(value, None)
1797
value = bzrdir_config.get_option('non-existant', default='default')
1798
self.assertEqual(value, 'default')
1799
self.assertEqual(bzrdir_config.get_option('key2', 'NOSECTION'), None)
1800
value = bzrdir_config.get_option('key2', 'NOSECTION',
1802
self.assertEqual(value, 'default')
1803
value = bzrdir_config.get_option('key3')
1804
self.assertEqual(value, 'value3-top')
1805
value = bzrdir_config.get_option('key3', 'SECTION')
1806
self.assertEqual(value, 'value3-section')
1808
def test_set_unset_default_stack_on(self):
1809
my_dir = self.make_bzrdir('.')
1810
bzrdir_config = config.BzrDirConfig(my_dir)
1811
self.assertIs(None, bzrdir_config.get_default_stack_on())
1812
bzrdir_config.set_default_stack_on('Foo')
1813
self.assertEqual('Foo', bzrdir_config._config.get_option(
1814
'default_stack_on'))
1815
self.assertEqual('Foo', bzrdir_config.get_default_stack_on())
1816
bzrdir_config.set_default_stack_on(None)
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')
1972
class TestAuthenticationConfigFile(tests.TestCase):
1973
"""Test the authentication.conf file matching"""
1975
def _got_user_passwd(self, expected_user, expected_password,
1976
config, *args, **kwargs):
1977
credentials = config.get_credentials(*args, **kwargs)
1978
if credentials is None:
1982
user = credentials['user']
1983
password = credentials['password']
1984
self.assertEquals(expected_user, user)
1985
self.assertEquals(expected_password, password)
1987
def test_empty_config(self):
1988
conf = config.AuthenticationConfig(_file=StringIO())
1989
self.assertEquals({}, conf._get_config())
1990
self._got_user_passwd(None, None, conf, 'http', 'foo.net')
1992
def test_missing_auth_section_header(self):
1993
conf = config.AuthenticationConfig(_file=StringIO('foo = bar'))
1994
self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
1996
def test_auth_section_header_not_closed(self):
1997
conf = config.AuthenticationConfig(_file=StringIO('[DEF'))
1998
self.assertRaises(errors.ParseConfigError, conf._get_config)
2000
def test_auth_value_not_boolean(self):
2001
conf = config.AuthenticationConfig(_file=StringIO(
2005
verify_certificates=askme # Error: Not a boolean
2007
self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
2009
def test_auth_value_not_int(self):
2010
conf = config.AuthenticationConfig(_file=StringIO(
2014
port=port # Error: Not an int
2016
self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
2018
def test_unknown_password_encoding(self):
2019
conf = config.AuthenticationConfig(_file=StringIO(
2023
password_encoding=unknown
2025
self.assertRaises(ValueError, conf.get_password,
2026
'ftp', 'foo.net', 'joe')
2028
def test_credentials_for_scheme_host(self):
2029
conf = config.AuthenticationConfig(_file=StringIO(
2030
"""# Identity on foo.net
2035
password=secret-pass
2038
self._got_user_passwd('joe', 'secret-pass', conf, 'ftp', 'foo.net')
2040
self._got_user_passwd(None, None, conf, 'http', 'foo.net')
2042
self._got_user_passwd(None, None, conf, 'ftp', 'bar.net')
2044
def test_credentials_for_host_port(self):
2045
conf = config.AuthenticationConfig(_file=StringIO(
2046
"""# Identity on foo.net
2052
password=secret-pass
2055
self._got_user_passwd('joe', 'secret-pass',
2056
conf, 'ftp', 'foo.net', port=10021)
2058
self._got_user_passwd(None, None, conf, 'ftp', 'foo.net')
2060
def test_for_matching_host(self):
2061
conf = config.AuthenticationConfig(_file=StringIO(
2062
"""# Identity on foo.net
2068
[sourceforge domain]
2075
self._got_user_passwd('georges', 'bendover',
2076
conf, 'bzr', 'foo.bzr.sf.net')
2078
self._got_user_passwd(None, None,
2079
conf, 'bzr', 'bbzr.sf.net')
2081
def test_for_matching_host_None(self):
2082
conf = config.AuthenticationConfig(_file=StringIO(
2083
"""# Identity on foo.net
2093
self._got_user_passwd('joe', 'joepass',
2094
conf, 'bzr', 'quux.net')
2095
# no host but different scheme
2096
self._got_user_passwd('georges', 'bendover',
2097
conf, 'ftp', 'quux.net')
2099
def test_credentials_for_path(self):
2100
conf = config.AuthenticationConfig(_file=StringIO(
2116
self._got_user_passwd(None, None,
2117
conf, 'http', host='bar.org', path='/dir3')
2119
self._got_user_passwd('georges', 'bendover',
2120
conf, 'http', host='bar.org', path='/dir2')
2122
self._got_user_passwd('jim', 'jimpass',
2123
conf, 'http', host='bar.org',path='/dir1/subdir')
2125
def test_credentials_for_user(self):
2126
conf = config.AuthenticationConfig(_file=StringIO(
2135
self._got_user_passwd('jim', 'jimpass',
2136
conf, 'http', 'bar.org')
2138
self._got_user_passwd('jim', 'jimpass',
2139
conf, 'http', 'bar.org', user='jim')
2140
# Don't get a different user if one is specified
2141
self._got_user_passwd(None, None,
2142
conf, 'http', 'bar.org', user='georges')
2144
def test_credentials_for_user_without_password(self):
2145
conf = config.AuthenticationConfig(_file=StringIO(
2152
# Get user but no password
2153
self._got_user_passwd('jim', None,
2154
conf, 'http', 'bar.org')
2156
def test_verify_certificates(self):
2157
conf = config.AuthenticationConfig(_file=StringIO(
2164
verify_certificates=False
2171
credentials = conf.get_credentials('https', 'bar.org')
2172
self.assertEquals(False, credentials.get('verify_certificates'))
2173
credentials = conf.get_credentials('https', 'foo.net')
2174
self.assertEquals(True, credentials.get('verify_certificates'))
2177
class TestAuthenticationStorage(tests.TestCaseInTempDir):
2179
def test_set_credentials(self):
2180
conf = config.AuthenticationConfig()
2181
conf.set_credentials('name', 'host', 'user', 'scheme', 'password',
2182
99, path='/foo', verify_certificates=False, realm='realm')
2183
credentials = conf.get_credentials(host='host', scheme='scheme',
2184
port=99, path='/foo',
2186
CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password',
2187
'verify_certificates': False, 'scheme': 'scheme',
2188
'host': 'host', 'port': 99, 'path': '/foo',
2190
self.assertEqual(CREDENTIALS, credentials)
2191
credentials_from_disk = config.AuthenticationConfig().get_credentials(
2192
host='host', scheme='scheme', port=99, path='/foo', realm='realm')
2193
self.assertEqual(CREDENTIALS, credentials_from_disk)
2195
def test_reset_credentials_different_name(self):
2196
conf = config.AuthenticationConfig()
2197
conf.set_credentials('name', 'host', 'user', 'scheme', 'password'),
2198
conf.set_credentials('name2', 'host', 'user2', 'scheme', 'password'),
2199
self.assertIs(None, conf._get_config().get('name'))
2200
credentials = conf.get_credentials(host='host', scheme='scheme')
2201
CREDENTIALS = {'name': 'name2', 'user': 'user2', 'password':
2202
'password', 'verify_certificates': True,
2203
'scheme': 'scheme', 'host': 'host', 'port': None,
2204
'path': None, 'realm': None}
2205
self.assertEqual(CREDENTIALS, credentials)
2208
class TestAuthenticationConfig(tests.TestCase):
2209
"""Test AuthenticationConfig behaviour"""
2211
def _check_default_password_prompt(self, expected_prompt_format, scheme,
2212
host=None, port=None, realm=None,
2216
user, password = 'jim', 'precious'
2217
expected_prompt = expected_prompt_format % {
2218
'scheme': scheme, 'host': host, 'port': port,
2219
'user': user, 'realm': realm}
2221
stdout = tests.StringIOWrapper()
2222
stderr = tests.StringIOWrapper()
2223
ui.ui_factory = tests.TestUIFactory(stdin=password + '\n',
2224
stdout=stdout, stderr=stderr)
2225
# We use an empty conf so that the user is always prompted
2226
conf = config.AuthenticationConfig()
2227
self.assertEquals(password,
2228
conf.get_password(scheme, host, user, port=port,
2229
realm=realm, path=path))
2230
self.assertEquals(expected_prompt, stderr.getvalue())
2231
self.assertEquals('', stdout.getvalue())
2233
def _check_default_username_prompt(self, expected_prompt_format, scheme,
2234
host=None, port=None, realm=None,
2239
expected_prompt = expected_prompt_format % {
2240
'scheme': scheme, 'host': host, 'port': port,
2242
stdout = tests.StringIOWrapper()
2243
stderr = tests.StringIOWrapper()
2244
ui.ui_factory = tests.TestUIFactory(stdin=username+ '\n',
2245
stdout=stdout, stderr=stderr)
2246
# We use an empty conf so that the user is always prompted
2247
conf = config.AuthenticationConfig()
2248
self.assertEquals(username, conf.get_user(scheme, host, port=port,
2249
realm=realm, path=path, ask=True))
2250
self.assertEquals(expected_prompt, stderr.getvalue())
2251
self.assertEquals('', stdout.getvalue())
2253
def test_username_defaults_prompts(self):
2254
# HTTP prompts can't be tested here, see test_http.py
2255
self._check_default_username_prompt('FTP %(host)s username: ', 'ftp')
2256
self._check_default_username_prompt(
2257
'FTP %(host)s:%(port)d username: ', 'ftp', port=10020)
2258
self._check_default_username_prompt(
2259
'SSH %(host)s:%(port)d username: ', 'ssh', port=12345)
2261
def test_username_default_no_prompt(self):
2262
conf = config.AuthenticationConfig()
2263
self.assertEquals(None,
2264
conf.get_user('ftp', 'example.com'))
2265
self.assertEquals("explicitdefault",
2266
conf.get_user('ftp', 'example.com', default="explicitdefault"))
2268
def test_password_default_prompts(self):
2269
# HTTP prompts can't be tested here, see test_http.py
2270
self._check_default_password_prompt(
2271
'FTP %(user)s@%(host)s password: ', 'ftp')
2272
self._check_default_password_prompt(
2273
'FTP %(user)s@%(host)s:%(port)d password: ', 'ftp', port=10020)
2274
self._check_default_password_prompt(
2275
'SSH %(user)s@%(host)s:%(port)d password: ', 'ssh', port=12345)
2276
# SMTP port handling is a bit special (it's handled if embedded in the
2278
# FIXME: should we: forbid that, extend it to other schemes, leave
2279
# things as they are that's fine thank you ?
2280
self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
2282
self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
2283
'smtp', host='bar.org:10025')
2284
self._check_default_password_prompt(
2285
'SMTP %(user)s@%(host)s:%(port)d password: ',
2288
def test_ssh_password_emits_warning(self):
2289
conf = config.AuthenticationConfig(_file=StringIO(
2297
entered_password = 'typed-by-hand'
2298
stdout = tests.StringIOWrapper()
2299
stderr = tests.StringIOWrapper()
2300
ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
2301
stdout=stdout, stderr=stderr)
2303
# Since the password defined in the authentication config is ignored,
2304
# the user is prompted
2305
self.assertEquals(entered_password,
2306
conf.get_password('ssh', 'bar.org', user='jim'))
2307
self.assertContainsRe(
2309
'password ignored in section \[ssh with password\]')
2311
def test_ssh_without_password_doesnt_emit_warning(self):
2312
conf = config.AuthenticationConfig(_file=StringIO(
2319
entered_password = 'typed-by-hand'
2320
stdout = tests.StringIOWrapper()
2321
stderr = tests.StringIOWrapper()
2322
ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
2326
# Since the password defined in the authentication config is ignored,
2327
# the user is prompted
2328
self.assertEquals(entered_password,
2329
conf.get_password('ssh', 'bar.org', user='jim'))
2330
# No warning shoud be emitted since there is no password. We are only
2332
self.assertNotContainsRe(
2334
'password ignored in section \[ssh with password\]')
2336
def test_uses_fallback_stores(self):
2337
self.overrideAttr(config, 'credential_store_registry',
2338
config.CredentialStoreRegistry())
2339
store = StubCredentialStore()
2340
store.add_credentials("http", "example.com", "joe", "secret")
2341
config.credential_store_registry.register("stub", store, fallback=True)
2342
conf = config.AuthenticationConfig(_file=StringIO())
2343
creds = conf.get_credentials("http", "example.com")
2344
self.assertEquals("joe", creds["user"])
2345
self.assertEquals("secret", creds["password"])
2348
class StubCredentialStore(config.CredentialStore):
2354
def add_credentials(self, scheme, host, user, password=None):
2355
self._username[(scheme, host)] = user
2356
self._password[(scheme, host)] = password
2358
def get_credentials(self, scheme, host, port=None, user=None,
2359
path=None, realm=None):
2360
key = (scheme, host)
2361
if not key in self._username:
2363
return { "scheme": scheme, "host": host, "port": port,
2364
"user": self._username[key], "password": self._password[key]}
2367
class CountingCredentialStore(config.CredentialStore):
2372
def get_credentials(self, scheme, host, port=None, user=None,
2373
path=None, realm=None):
2378
class TestCredentialStoreRegistry(tests.TestCase):
2380
def _get_cs_registry(self):
2381
return config.credential_store_registry
2383
def test_default_credential_store(self):
2384
r = self._get_cs_registry()
2385
default = r.get_credential_store(None)
2386
self.assertIsInstance(default, config.PlainTextCredentialStore)
2388
def test_unknown_credential_store(self):
2389
r = self._get_cs_registry()
2390
# It's hard to imagine someone creating a credential store named
2391
# 'unknown' so we use that as an never registered key.
2392
self.assertRaises(KeyError, r.get_credential_store, 'unknown')
2394
def test_fallback_none_registered(self):
2395
r = config.CredentialStoreRegistry()
2396
self.assertEquals(None,
2397
r.get_fallback_credentials("http", "example.com"))
2399
def test_register(self):
2400
r = config.CredentialStoreRegistry()
2401
r.register("stub", StubCredentialStore(), fallback=False)
2402
r.register("another", StubCredentialStore(), fallback=True)
2403
self.assertEquals(["another", "stub"], r.keys())
2405
def test_register_lazy(self):
2406
r = config.CredentialStoreRegistry()
2407
r.register_lazy("stub", "bzrlib.tests.test_config",
2408
"StubCredentialStore", fallback=False)
2409
self.assertEquals(["stub"], r.keys())
2410
self.assertIsInstance(r.get_credential_store("stub"),
2411
StubCredentialStore)
2413
def test_is_fallback(self):
2414
r = config.CredentialStoreRegistry()
2415
r.register("stub1", None, fallback=False)
2416
r.register("stub2", None, fallback=True)
2417
self.assertEquals(False, r.is_fallback("stub1"))
2418
self.assertEquals(True, r.is_fallback("stub2"))
2420
def test_no_fallback(self):
2421
r = config.CredentialStoreRegistry()
2422
store = CountingCredentialStore()
2423
r.register("count", store, fallback=False)
2424
self.assertEquals(None,
2425
r.get_fallback_credentials("http", "example.com"))
2426
self.assertEquals(0, store._calls)
2428
def test_fallback_credentials(self):
2429
r = config.CredentialStoreRegistry()
2430
store = StubCredentialStore()
2431
store.add_credentials("http", "example.com",
2432
"somebody", "geheim")
2433
r.register("stub", store, fallback=True)
2434
creds = r.get_fallback_credentials("http", "example.com")
2435
self.assertEquals("somebody", creds["user"])
2436
self.assertEquals("geheim", creds["password"])
2438
def test_fallback_first_wins(self):
2439
r = config.CredentialStoreRegistry()
2440
stub1 = StubCredentialStore()
2441
stub1.add_credentials("http", "example.com",
2442
"somebody", "stub1")
2443
r.register("stub1", stub1, fallback=True)
2444
stub2 = StubCredentialStore()
2445
stub2.add_credentials("http", "example.com",
2446
"somebody", "stub2")
2447
r.register("stub2", stub1, fallback=True)
2448
creds = r.get_fallback_credentials("http", "example.com")
2449
self.assertEquals("somebody", creds["user"])
2450
self.assertEquals("stub1", creds["password"])
2453
class TestPlainTextCredentialStore(tests.TestCase):
2455
def test_decode_password(self):
2456
r = config.credential_store_registry
2457
plain_text = r.get_credential_store()
2458
decoded = plain_text.decode_password(dict(password='secret'))
2459
self.assertEquals('secret', decoded)
2462
# FIXME: Once we have a way to declare authentication to all test servers, we
2463
# can implement generic tests.
2464
# test_user_password_in_url
2465
# test_user_in_url_password_from_config
2466
# test_user_in_url_password_prompted
2467
# test_user_in_config
2468
# test_user_getpass.getuser
2469
# test_user_prompted ?
2470
class TestAuthenticationRing(tests.TestCaseWithTransport):