/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-07-20 08:56:45 UTC
  • mfrom: (4526.9.23 apply-inventory-delta)
  • Revision ID: pqm@pqm.ubuntu.com-20090720085645-54mtgybxua0yx6hw
(robertc) Add checks for inventory deltas which try to ensure that
        deltas that are not an exact fit are not applied. (Robert
        Collins, bug 397705, bug 367633)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2008 Canonical Ltd
 
2
#   Authors: Robert Collins <robert.collins@canonical.com>
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
17
 
 
18
"""Tests for finding and reading the bzr config file[s]."""
 
19
# import system imports here
 
20
from cStringIO import StringIO
 
21
import os
 
22
import sys
 
23
 
 
24
#import bzrlib specific imports here
 
25
from bzrlib import (
 
26
    branch,
 
27
    bzrdir,
 
28
    config,
 
29
    errors,
 
30
    osutils,
 
31
    mail_client,
 
32
    ui,
 
33
    urlutils,
 
34
    tests,
 
35
    trace,
 
36
    transport,
 
37
    )
 
38
from bzrlib.util.configobj import configobj
 
39
 
 
40
 
 
41
sample_long_alias="log -r-15..-1 --line"
 
42
sample_config_text = u"""
 
43
[DEFAULT]
 
44
email=Erik B\u00e5gfors <erik@bagfors.nu>
 
45
editor=vim
 
46
gpg_signing_command=gnome-gpg
 
47
log_format=short
 
48
user_global_option=something
 
49
[ALIASES]
 
50
h=help
 
51
ll=""" + sample_long_alias + "\n"
 
52
 
 
53
 
 
54
sample_always_signatures = """
 
55
[DEFAULT]
 
56
check_signatures=ignore
 
57
create_signatures=always
 
58
"""
 
59
 
 
60
sample_ignore_signatures = """
 
61
[DEFAULT]
 
62
check_signatures=require
 
63
create_signatures=never
 
64
"""
 
65
 
 
66
sample_maybe_signatures = """
 
67
[DEFAULT]
 
68
check_signatures=ignore
 
69
create_signatures=when-required
 
70
"""
 
71
 
 
72
sample_branches_text = """
 
73
[http://www.example.com]
 
74
# Top level policy
 
75
email=Robert Collins <robertc@example.org>
 
76
normal_option = normal
 
77
appendpath_option = append
 
78
appendpath_option:policy = appendpath
 
79
norecurse_option = norecurse
 
80
norecurse_option:policy = norecurse
 
81
[http://www.example.com/ignoreparent]
 
82
# different project: ignore parent dir config
 
83
ignore_parents=true
 
84
[http://www.example.com/norecurse]
 
85
# configuration items that only apply to this dir
 
86
recurse=false
 
87
normal_option = norecurse
 
88
[http://www.example.com/dir]
 
89
appendpath_option = normal
 
90
[/b/]
 
91
check_signatures=require
 
92
# test trailing / matching with no children
 
93
[/a/]
 
94
check_signatures=check-available
 
95
gpg_signing_command=false
 
96
user_local_option=local
 
97
# test trailing / matching
 
98
[/a/*]
 
99
#subdirs will match but not the parent
 
100
[/a/c]
 
101
check_signatures=ignore
 
102
post_commit=bzrlib.tests.test_config.post_commit
 
103
#testing explicit beats globs
 
104
"""
 
105
 
 
106
 
 
107
class InstrumentedConfigObj(object):
 
108
    """A config obj look-enough-alike to record calls made to it."""
 
109
 
 
110
    def __contains__(self, thing):
 
111
        self._calls.append(('__contains__', thing))
 
112
        return False
 
113
 
 
114
    def __getitem__(self, key):
 
115
        self._calls.append(('__getitem__', key))
 
116
        return self
 
117
 
 
118
    def __init__(self, input, encoding=None):
 
119
        self._calls = [('__init__', input, encoding)]
 
120
 
 
121
    def __setitem__(self, key, value):
 
122
        self._calls.append(('__setitem__', key, value))
 
123
 
 
124
    def __delitem__(self, key):
 
125
        self._calls.append(('__delitem__', key))
 
126
 
 
127
    def keys(self):
 
128
        self._calls.append(('keys',))
 
129
        return []
 
130
 
 
131
    def write(self, arg):
 
132
        self._calls.append(('write',))
 
133
 
 
134
    def as_bool(self, value):
 
135
        self._calls.append(('as_bool', value))
 
136
        return False
 
137
 
 
138
    def get_value(self, section, name):
 
139
        self._calls.append(('get_value', section, name))
 
140
        return None
 
141
 
 
142
 
 
143
class FakeBranch(object):
 
144
 
 
145
    def __init__(self, base=None, user_id=None):
 
146
        if base is None:
 
147
            self.base = "http://example.com/branches/demo"
 
148
        else:
 
149
            self.base = base
 
150
        self._transport = self.control_files = \
 
151
            FakeControlFilesAndTransport(user_id=user_id)
 
152
 
 
153
    def _get_config(self):
 
154
        return config.TransportConfig(self._transport, 'branch.conf')
 
155
 
 
156
    def lock_write(self):
 
157
        pass
 
158
 
 
159
    def unlock(self):
 
160
        pass
 
161
 
 
162
 
 
163
class FakeControlFilesAndTransport(object):
 
164
 
 
165
    def __init__(self, user_id=None):
 
166
        self.files = {}
 
167
        if user_id:
 
168
            self.files['email'] = user_id
 
169
        self._transport = self
 
170
 
 
171
    def get_utf8(self, filename):
 
172
        # from LockableFiles
 
173
        raise AssertionError("get_utf8 should no longer be used")
 
174
 
 
175
    def get(self, filename):
 
176
        # from Transport
 
177
        try:
 
178
            return StringIO(self.files[filename])
 
179
        except KeyError:
 
180
            raise errors.NoSuchFile(filename)
 
181
 
 
182
    def get_bytes(self, filename):
 
183
        # from Transport
 
184
        try:
 
185
            return self.files[filename]
 
186
        except KeyError:
 
187
            raise errors.NoSuchFile(filename)
 
188
 
 
189
    def put(self, filename, fileobj):
 
190
        self.files[filename] = fileobj.read()
 
191
 
 
192
    def put_file(self, filename, fileobj):
 
193
        return self.put(filename, fileobj)
 
194
 
 
195
 
 
196
class InstrumentedConfig(config.Config):
 
197
    """An instrumented config that supplies stubs for template methods."""
 
198
 
 
199
    def __init__(self):
 
200
        super(InstrumentedConfig, self).__init__()
 
201
        self._calls = []
 
202
        self._signatures = config.CHECK_NEVER
 
203
 
 
204
    def _get_user_id(self):
 
205
        self._calls.append('_get_user_id')
 
206
        return "Robert Collins <robert.collins@example.org>"
 
207
 
 
208
    def _get_signature_checking(self):
 
209
        self._calls.append('_get_signature_checking')
 
210
        return self._signatures
 
211
 
 
212
 
 
213
bool_config = """[DEFAULT]
 
214
active = true
 
215
inactive = false
 
216
[UPPERCASE]
 
217
active = True
 
218
nonactive = False
 
219
"""
 
220
 
 
221
 
 
222
class TestConfigObj(tests.TestCase):
 
223
 
 
224
    def test_get_bool(self):
 
225
        co = config.ConfigObj(StringIO(bool_config))
 
226
        self.assertIs(co.get_bool('DEFAULT', 'active'), True)
 
227
        self.assertIs(co.get_bool('DEFAULT', 'inactive'), False)
 
228
        self.assertIs(co.get_bool('UPPERCASE', 'active'), True)
 
229
        self.assertIs(co.get_bool('UPPERCASE', 'nonactive'), False)
 
230
 
 
231
    def test_hash_sign_in_value(self):
 
232
        """
 
233
        Before 4.5.0, ConfigObj did not quote # signs in values, so they'd be
 
234
        treated as comments when read in again. (#86838)
 
235
        """
 
236
        co = config.ConfigObj()
 
237
        co['test'] = 'foo#bar'
 
238
        lines = co.write()
 
239
        self.assertEqual(lines, ['test = "foo#bar"'])
 
240
        co2 = config.ConfigObj(lines)
 
241
        self.assertEqual(co2['test'], 'foo#bar')
 
242
 
 
243
 
 
244
erroneous_config = """[section] # line 1
 
245
good=good # line 2
 
246
[section] # line 3
 
247
whocares=notme # line 4
 
248
"""
 
249
 
 
250
 
 
251
class TestConfigObjErrors(tests.TestCase):
 
252
 
 
253
    def test_duplicate_section_name_error_line(self):
 
254
        try:
 
255
            co = configobj.ConfigObj(StringIO(erroneous_config),
 
256
                                     raise_errors=True)
 
257
        except config.configobj.DuplicateError, e:
 
258
            self.assertEqual(3, e.line_number)
 
259
        else:
 
260
            self.fail('Error in config file not detected')
 
261
 
 
262
 
 
263
class TestConfig(tests.TestCase):
 
264
 
 
265
    def test_constructs(self):
 
266
        config.Config()
 
267
 
 
268
    def test_no_default_editor(self):
 
269
        self.assertRaises(NotImplementedError, config.Config().get_editor)
 
270
 
 
271
    def test_user_email(self):
 
272
        my_config = InstrumentedConfig()
 
273
        self.assertEqual('robert.collins@example.org', my_config.user_email())
 
274
        self.assertEqual(['_get_user_id'], my_config._calls)
 
275
 
 
276
    def test_username(self):
 
277
        my_config = InstrumentedConfig()
 
278
        self.assertEqual('Robert Collins <robert.collins@example.org>',
 
279
                         my_config.username())
 
280
        self.assertEqual(['_get_user_id'], my_config._calls)
 
281
 
 
282
    def test_signatures_default(self):
 
283
        my_config = config.Config()
 
284
        self.assertFalse(my_config.signature_needed())
 
285
        self.assertEqual(config.CHECK_IF_POSSIBLE,
 
286
                         my_config.signature_checking())
 
287
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
 
288
                         my_config.signing_policy())
 
289
 
 
290
    def test_signatures_template_method(self):
 
291
        my_config = InstrumentedConfig()
 
292
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
293
        self.assertEqual(['_get_signature_checking'], my_config._calls)
 
294
 
 
295
    def test_signatures_template_method_none(self):
 
296
        my_config = InstrumentedConfig()
 
297
        my_config._signatures = None
 
298
        self.assertEqual(config.CHECK_IF_POSSIBLE,
 
299
                         my_config.signature_checking())
 
300
        self.assertEqual(['_get_signature_checking'], my_config._calls)
 
301
 
 
302
    def test_gpg_signing_command_default(self):
 
303
        my_config = config.Config()
 
304
        self.assertEqual('gpg', my_config.gpg_signing_command())
 
305
 
 
306
    def test_get_user_option_default(self):
 
307
        my_config = config.Config()
 
308
        self.assertEqual(None, my_config.get_user_option('no_option'))
 
309
 
 
310
    def test_post_commit_default(self):
 
311
        my_config = config.Config()
 
312
        self.assertEqual(None, my_config.post_commit())
 
313
 
 
314
    def test_log_format_default(self):
 
315
        my_config = config.Config()
 
316
        self.assertEqual('long', my_config.log_format())
 
317
 
 
318
 
 
319
class TestConfigPath(tests.TestCase):
 
320
 
 
321
    def setUp(self):
 
322
        super(TestConfigPath, self).setUp()
 
323
        os.environ['HOME'] = '/home/bogus'
 
324
        if sys.platform == 'win32':
 
325
            os.environ['BZR_HOME'] = \
 
326
                r'C:\Documents and Settings\bogus\Application Data'
 
327
            self.bzr_home = \
 
328
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
 
329
        else:
 
330
            self.bzr_home = '/home/bogus/.bazaar'
 
331
 
 
332
    def test_config_dir(self):
 
333
        self.assertEqual(config.config_dir(), self.bzr_home)
 
334
 
 
335
    def test_config_filename(self):
 
336
        self.assertEqual(config.config_filename(),
 
337
                         self.bzr_home + '/bazaar.conf')
 
338
 
 
339
    def test_branches_config_filename(self):
 
340
        self.assertEqual(config.branches_config_filename(),
 
341
                         self.bzr_home + '/branches.conf')
 
342
 
 
343
    def test_locations_config_filename(self):
 
344
        self.assertEqual(config.locations_config_filename(),
 
345
                         self.bzr_home + '/locations.conf')
 
346
 
 
347
    def test_authentication_config_filename(self):
 
348
        self.assertEqual(config.authentication_config_filename(),
 
349
                         self.bzr_home + '/authentication.conf')
 
350
 
 
351
 
 
352
class TestIniConfig(tests.TestCase):
 
353
 
 
354
    def test_contructs(self):
 
355
        my_config = config.IniBasedConfig("nothing")
 
356
 
 
357
    def test_from_fp(self):
 
358
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
359
        my_config = config.IniBasedConfig(None)
 
360
        self.failUnless(
 
361
            isinstance(my_config._get_parser(file=config_file),
 
362
                        configobj.ConfigObj))
 
363
 
 
364
    def test_cached(self):
 
365
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
366
        my_config = config.IniBasedConfig(None)
 
367
        parser = my_config._get_parser(file=config_file)
 
368
        self.failUnless(my_config._get_parser() is parser)
 
369
 
 
370
    def test_get_user_option_as_bool(self):
 
371
        config_file = StringIO("""
 
372
a_true_bool = true
 
373
a_false_bool = 0
 
374
an_invalid_bool = maybe
 
375
a_list = hmm, who knows ? # This interpreted as a list !
 
376
""".encode('utf-8'))
 
377
        my_config = config.IniBasedConfig(None)
 
378
        parser = my_config._get_parser(file=config_file)
 
379
        get_option = my_config.get_user_option_as_bool
 
380
        self.assertEqual(True, get_option('a_true_bool'))
 
381
        self.assertEqual(False, get_option('a_false_bool'))
 
382
        self.assertIs(None, get_option('an_invalid_bool'))
 
383
        self.assertIs(None, get_option('not_defined_in_this_config'))
 
384
 
 
385
class TestGetConfig(tests.TestCase):
 
386
 
 
387
    def test_constructs(self):
 
388
        my_config = config.GlobalConfig()
 
389
 
 
390
    def test_calls_read_filenames(self):
 
391
        # replace the class that is constructed, to check its parameters
 
392
        oldparserclass = config.ConfigObj
 
393
        config.ConfigObj = InstrumentedConfigObj
 
394
        my_config = config.GlobalConfig()
 
395
        try:
 
396
            parser = my_config._get_parser()
 
397
        finally:
 
398
            config.ConfigObj = oldparserclass
 
399
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
 
400
        self.assertEqual(parser._calls, [('__init__', config.config_filename(),
 
401
                                          'utf-8')])
 
402
 
 
403
 
 
404
class TestBranchConfig(tests.TestCaseWithTransport):
 
405
 
 
406
    def test_constructs(self):
 
407
        branch = FakeBranch()
 
408
        my_config = config.BranchConfig(branch)
 
409
        self.assertRaises(TypeError, config.BranchConfig)
 
410
 
 
411
    def test_get_location_config(self):
 
412
        branch = FakeBranch()
 
413
        my_config = config.BranchConfig(branch)
 
414
        location_config = my_config._get_location_config()
 
415
        self.assertEqual(branch.base, location_config.location)
 
416
        self.failUnless(location_config is my_config._get_location_config())
 
417
 
 
418
    def test_get_config(self):
 
419
        """The Branch.get_config method works properly"""
 
420
        b = bzrdir.BzrDir.create_standalone_workingtree('.').branch
 
421
        my_config = b.get_config()
 
422
        self.assertIs(my_config.get_user_option('wacky'), None)
 
423
        my_config.set_user_option('wacky', 'unlikely')
 
424
        self.assertEqual(my_config.get_user_option('wacky'), 'unlikely')
 
425
 
 
426
        # Ensure we get the same thing if we start again
 
427
        b2 = branch.Branch.open('.')
 
428
        my_config2 = b2.get_config()
 
429
        self.assertEqual(my_config2.get_user_option('wacky'), 'unlikely')
 
430
 
 
431
    def test_has_explicit_nickname(self):
 
432
        b = self.make_branch('.')
 
433
        self.assertFalse(b.get_config().has_explicit_nickname())
 
434
        b.nick = 'foo'
 
435
        self.assertTrue(b.get_config().has_explicit_nickname())
 
436
 
 
437
    def test_config_url(self):
 
438
        """The Branch.get_config will use section that uses a local url"""
 
439
        branch = self.make_branch('branch')
 
440
        self.assertEqual('branch', branch.nick)
 
441
 
 
442
        locations = config.locations_config_filename()
 
443
        config.ensure_config_dir_exists()
 
444
        local_url = urlutils.local_path_to_url('branch')
 
445
        open(locations, 'wb').write('[%s]\nnickname = foobar'
 
446
                                    % (local_url,))
 
447
        self.assertEqual('foobar', branch.nick)
 
448
 
 
449
    def test_config_local_path(self):
 
450
        """The Branch.get_config will use a local system path"""
 
451
        branch = self.make_branch('branch')
 
452
        self.assertEqual('branch', branch.nick)
 
453
 
 
454
        locations = config.locations_config_filename()
 
455
        config.ensure_config_dir_exists()
 
456
        open(locations, 'wb').write('[%s/branch]\nnickname = barry'
 
457
                                    % (osutils.getcwd().encode('utf8'),))
 
458
        self.assertEqual('barry', branch.nick)
 
459
 
 
460
    def test_config_creates_local(self):
 
461
        """Creating a new entry in config uses a local path."""
 
462
        branch = self.make_branch('branch', format='knit')
 
463
        branch.set_push_location('http://foobar')
 
464
        locations = config.locations_config_filename()
 
465
        local_path = osutils.getcwd().encode('utf8')
 
466
        # Surprisingly ConfigObj doesn't create a trailing newline
 
467
        self.check_file_contents(locations,
 
468
                                 '[%s/branch]\n'
 
469
                                 'push_location = http://foobar\n'
 
470
                                 'push_location:policy = norecurse\n'
 
471
                                 % (local_path,))
 
472
 
 
473
    def test_autonick_urlencoded(self):
 
474
        b = self.make_branch('!repo')
 
475
        self.assertEqual('!repo', b.get_config().get_nickname())
 
476
 
 
477
    def test_warn_if_masked(self):
 
478
        _warning = trace.warning
 
479
        warnings = []
 
480
        def warning(*args):
 
481
            warnings.append(args[0] % args[1:])
 
482
 
 
483
        def set_option(store, warn_masked=True):
 
484
            warnings[:] = []
 
485
            conf.set_user_option('example_option', repr(store), store=store,
 
486
                                 warn_masked=warn_masked)
 
487
        def assertWarning(warning):
 
488
            if warning is None:
 
489
                self.assertEqual(0, len(warnings))
 
490
            else:
 
491
                self.assertEqual(1, len(warnings))
 
492
                self.assertEqual(warning, warnings[0])
 
493
        trace.warning = warning
 
494
        try:
 
495
            branch = self.make_branch('.')
 
496
            conf = branch.get_config()
 
497
            set_option(config.STORE_GLOBAL)
 
498
            assertWarning(None)
 
499
            set_option(config.STORE_BRANCH)
 
500
            assertWarning(None)
 
501
            set_option(config.STORE_GLOBAL)
 
502
            assertWarning('Value "4" is masked by "3" from branch.conf')
 
503
            set_option(config.STORE_GLOBAL, warn_masked=False)
 
504
            assertWarning(None)
 
505
            set_option(config.STORE_LOCATION)
 
506
            assertWarning(None)
 
507
            set_option(config.STORE_BRANCH)
 
508
            assertWarning('Value "3" is masked by "0" from locations.conf')
 
509
            set_option(config.STORE_BRANCH, warn_masked=False)
 
510
            assertWarning(None)
 
511
        finally:
 
512
            trace.warning = _warning
 
513
 
 
514
 
 
515
class TestGlobalConfigItems(tests.TestCase):
 
516
 
 
517
    def test_user_id(self):
 
518
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
519
        my_config = config.GlobalConfig()
 
520
        my_config._parser = my_config._get_parser(file=config_file)
 
521
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
 
522
                         my_config._get_user_id())
 
523
 
 
524
    def test_absent_user_id(self):
 
525
        config_file = StringIO("")
 
526
        my_config = config.GlobalConfig()
 
527
        my_config._parser = my_config._get_parser(file=config_file)
 
528
        self.assertEqual(None, my_config._get_user_id())
 
529
 
 
530
    def test_configured_editor(self):
 
531
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
532
        my_config = config.GlobalConfig()
 
533
        my_config._parser = my_config._get_parser(file=config_file)
 
534
        self.assertEqual("vim", my_config.get_editor())
 
535
 
 
536
    def test_signatures_always(self):
 
537
        config_file = StringIO(sample_always_signatures)
 
538
        my_config = config.GlobalConfig()
 
539
        my_config._parser = my_config._get_parser(file=config_file)
 
540
        self.assertEqual(config.CHECK_NEVER,
 
541
                         my_config.signature_checking())
 
542
        self.assertEqual(config.SIGN_ALWAYS,
 
543
                         my_config.signing_policy())
 
544
        self.assertEqual(True, my_config.signature_needed())
 
545
 
 
546
    def test_signatures_if_possible(self):
 
547
        config_file = StringIO(sample_maybe_signatures)
 
548
        my_config = config.GlobalConfig()
 
549
        my_config._parser = my_config._get_parser(file=config_file)
 
550
        self.assertEqual(config.CHECK_NEVER,
 
551
                         my_config.signature_checking())
 
552
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
 
553
                         my_config.signing_policy())
 
554
        self.assertEqual(False, my_config.signature_needed())
 
555
 
 
556
    def test_signatures_ignore(self):
 
557
        config_file = StringIO(sample_ignore_signatures)
 
558
        my_config = config.GlobalConfig()
 
559
        my_config._parser = my_config._get_parser(file=config_file)
 
560
        self.assertEqual(config.CHECK_ALWAYS,
 
561
                         my_config.signature_checking())
 
562
        self.assertEqual(config.SIGN_NEVER,
 
563
                         my_config.signing_policy())
 
564
        self.assertEqual(False, my_config.signature_needed())
 
565
 
 
566
    def _get_sample_config(self):
 
567
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
568
        my_config = config.GlobalConfig()
 
569
        my_config._parser = my_config._get_parser(file=config_file)
 
570
        return my_config
 
571
 
 
572
    def test_gpg_signing_command(self):
 
573
        my_config = self._get_sample_config()
 
574
        self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
 
575
        self.assertEqual(False, my_config.signature_needed())
 
576
 
 
577
    def _get_empty_config(self):
 
578
        config_file = StringIO("")
 
579
        my_config = config.GlobalConfig()
 
580
        my_config._parser = my_config._get_parser(file=config_file)
 
581
        return my_config
 
582
 
 
583
    def test_gpg_signing_command_unset(self):
 
584
        my_config = self._get_empty_config()
 
585
        self.assertEqual("gpg", my_config.gpg_signing_command())
 
586
 
 
587
    def test_get_user_option_default(self):
 
588
        my_config = self._get_empty_config()
 
589
        self.assertEqual(None, my_config.get_user_option('no_option'))
 
590
 
 
591
    def test_get_user_option_global(self):
 
592
        my_config = self._get_sample_config()
 
593
        self.assertEqual("something",
 
594
                         my_config.get_user_option('user_global_option'))
 
595
 
 
596
    def test_post_commit_default(self):
 
597
        my_config = self._get_sample_config()
 
598
        self.assertEqual(None, my_config.post_commit())
 
599
 
 
600
    def test_configured_logformat(self):
 
601
        my_config = self._get_sample_config()
 
602
        self.assertEqual("short", my_config.log_format())
 
603
 
 
604
    def test_get_alias(self):
 
605
        my_config = self._get_sample_config()
 
606
        self.assertEqual('help', my_config.get_alias('h'))
 
607
 
 
608
    def test_get_aliases(self):
 
609
        my_config = self._get_sample_config()
 
610
        aliases = my_config.get_aliases()
 
611
        self.assertEqual(2, len(aliases))
 
612
        sorted_keys = sorted(aliases)
 
613
        self.assertEqual('help', aliases[sorted_keys[0]])
 
614
        self.assertEqual(sample_long_alias, aliases[sorted_keys[1]])
 
615
 
 
616
    def test_get_no_alias(self):
 
617
        my_config = self._get_sample_config()
 
618
        self.assertEqual(None, my_config.get_alias('foo'))
 
619
 
 
620
    def test_get_long_alias(self):
 
621
        my_config = self._get_sample_config()
 
622
        self.assertEqual(sample_long_alias, my_config.get_alias('ll'))
 
623
 
 
624
 
 
625
class TestGlobalConfigSavingOptions(tests.TestCaseInTempDir):
 
626
 
 
627
    def test_empty(self):
 
628
        my_config = config.GlobalConfig()
 
629
        self.assertEqual(0, len(my_config.get_aliases()))
 
630
 
 
631
    def test_set_alias(self):
 
632
        my_config = config.GlobalConfig()
 
633
        alias_value = 'commit --strict'
 
634
        my_config.set_alias('commit', alias_value)
 
635
        new_config = config.GlobalConfig()
 
636
        self.assertEqual(alias_value, new_config.get_alias('commit'))
 
637
 
 
638
    def test_remove_alias(self):
 
639
        my_config = config.GlobalConfig()
 
640
        my_config.set_alias('commit', 'commit --strict')
 
641
        # Now remove the alias again.
 
642
        my_config.unset_alias('commit')
 
643
        new_config = config.GlobalConfig()
 
644
        self.assertIs(None, new_config.get_alias('commit'))
 
645
 
 
646
 
 
647
class TestLocationConfig(tests.TestCaseInTempDir):
 
648
 
 
649
    def test_constructs(self):
 
650
        my_config = config.LocationConfig('http://example.com')
 
651
        self.assertRaises(TypeError, config.LocationConfig)
 
652
 
 
653
    def test_branch_calls_read_filenames(self):
 
654
        # This is testing the correct file names are provided.
 
655
        # TODO: consolidate with the test for GlobalConfigs filename checks.
 
656
        #
 
657
        # replace the class that is constructed, to check its parameters
 
658
        oldparserclass = config.ConfigObj
 
659
        config.ConfigObj = InstrumentedConfigObj
 
660
        try:
 
661
            my_config = config.LocationConfig('http://www.example.com')
 
662
            parser = my_config._get_parser()
 
663
        finally:
 
664
            config.ConfigObj = oldparserclass
 
665
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
 
666
        self.assertEqual(parser._calls,
 
667
                         [('__init__', config.locations_config_filename(),
 
668
                           'utf-8')])
 
669
        config.ensure_config_dir_exists()
 
670
        #os.mkdir(config.config_dir())
 
671
        f = file(config.branches_config_filename(), 'wb')
 
672
        f.write('')
 
673
        f.close()
 
674
        oldparserclass = config.ConfigObj
 
675
        config.ConfigObj = InstrumentedConfigObj
 
676
        try:
 
677
            my_config = config.LocationConfig('http://www.example.com')
 
678
            parser = my_config._get_parser()
 
679
        finally:
 
680
            config.ConfigObj = oldparserclass
 
681
 
 
682
    def test_get_global_config(self):
 
683
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
 
684
        global_config = my_config._get_global_config()
 
685
        self.failUnless(isinstance(global_config, config.GlobalConfig))
 
686
        self.failUnless(global_config is my_config._get_global_config())
 
687
 
 
688
    def test__get_matching_sections_no_match(self):
 
689
        self.get_branch_config('/')
 
690
        self.assertEqual([], self.my_location_config._get_matching_sections())
 
691
 
 
692
    def test__get_matching_sections_exact(self):
 
693
        self.get_branch_config('http://www.example.com')
 
694
        self.assertEqual([('http://www.example.com', '')],
 
695
                         self.my_location_config._get_matching_sections())
 
696
 
 
697
    def test__get_matching_sections_suffix_does_not(self):
 
698
        self.get_branch_config('http://www.example.com-com')
 
699
        self.assertEqual([], self.my_location_config._get_matching_sections())
 
700
 
 
701
    def test__get_matching_sections_subdir_recursive(self):
 
702
        self.get_branch_config('http://www.example.com/com')
 
703
        self.assertEqual([('http://www.example.com', 'com')],
 
704
                         self.my_location_config._get_matching_sections())
 
705
 
 
706
    def test__get_matching_sections_ignoreparent(self):
 
707
        self.get_branch_config('http://www.example.com/ignoreparent')
 
708
        self.assertEqual([('http://www.example.com/ignoreparent', '')],
 
709
                         self.my_location_config._get_matching_sections())
 
710
 
 
711
    def test__get_matching_sections_ignoreparent_subdir(self):
 
712
        self.get_branch_config(
 
713
            'http://www.example.com/ignoreparent/childbranch')
 
714
        self.assertEqual([('http://www.example.com/ignoreparent',
 
715
                           'childbranch')],
 
716
                         self.my_location_config._get_matching_sections())
 
717
 
 
718
    def test__get_matching_sections_subdir_trailing_slash(self):
 
719
        self.get_branch_config('/b')
 
720
        self.assertEqual([('/b/', '')],
 
721
                         self.my_location_config._get_matching_sections())
 
722
 
 
723
    def test__get_matching_sections_subdir_child(self):
 
724
        self.get_branch_config('/a/foo')
 
725
        self.assertEqual([('/a/*', ''), ('/a/', 'foo')],
 
726
                         self.my_location_config._get_matching_sections())
 
727
 
 
728
    def test__get_matching_sections_subdir_child_child(self):
 
729
        self.get_branch_config('/a/foo/bar')
 
730
        self.assertEqual([('/a/*', 'bar'), ('/a/', 'foo/bar')],
 
731
                         self.my_location_config._get_matching_sections())
 
732
 
 
733
    def test__get_matching_sections_trailing_slash_with_children(self):
 
734
        self.get_branch_config('/a/')
 
735
        self.assertEqual([('/a/', '')],
 
736
                         self.my_location_config._get_matching_sections())
 
737
 
 
738
    def test__get_matching_sections_explicit_over_glob(self):
 
739
        # XXX: 2006-09-08 jamesh
 
740
        # This test only passes because ord('c') > ord('*').  If there
 
741
        # was a config section for '/a/?', it would get precedence
 
742
        # over '/a/c'.
 
743
        self.get_branch_config('/a/c')
 
744
        self.assertEqual([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')],
 
745
                         self.my_location_config._get_matching_sections())
 
746
 
 
747
    def test__get_option_policy_normal(self):
 
748
        self.get_branch_config('http://www.example.com')
 
749
        self.assertEqual(
 
750
            self.my_location_config._get_config_policy(
 
751
            'http://www.example.com', 'normal_option'),
 
752
            config.POLICY_NONE)
 
753
 
 
754
    def test__get_option_policy_norecurse(self):
 
755
        self.get_branch_config('http://www.example.com')
 
756
        self.assertEqual(
 
757
            self.my_location_config._get_option_policy(
 
758
            'http://www.example.com', 'norecurse_option'),
 
759
            config.POLICY_NORECURSE)
 
760
        # Test old recurse=False setting:
 
761
        self.assertEqual(
 
762
            self.my_location_config._get_option_policy(
 
763
            'http://www.example.com/norecurse', 'normal_option'),
 
764
            config.POLICY_NORECURSE)
 
765
 
 
766
    def test__get_option_policy_normal(self):
 
767
        self.get_branch_config('http://www.example.com')
 
768
        self.assertEqual(
 
769
            self.my_location_config._get_option_policy(
 
770
            'http://www.example.com', 'appendpath_option'),
 
771
            config.POLICY_APPENDPATH)
 
772
 
 
773
    def test_location_without_username(self):
 
774
        self.get_branch_config('http://www.example.com/ignoreparent')
 
775
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
 
776
                         self.my_config.username())
 
777
 
 
778
    def test_location_not_listed(self):
 
779
        """Test that the global username is used when no location matches"""
 
780
        self.get_branch_config('/home/robertc/sources')
 
781
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
 
782
                         self.my_config.username())
 
783
 
 
784
    def test_overriding_location(self):
 
785
        self.get_branch_config('http://www.example.com/foo')
 
786
        self.assertEqual('Robert Collins <robertc@example.org>',
 
787
                         self.my_config.username())
 
788
 
 
789
    def test_signatures_not_set(self):
 
790
        self.get_branch_config('http://www.example.com',
 
791
                                 global_config=sample_ignore_signatures)
 
792
        self.assertEqual(config.CHECK_ALWAYS,
 
793
                         self.my_config.signature_checking())
 
794
        self.assertEqual(config.SIGN_NEVER,
 
795
                         self.my_config.signing_policy())
 
796
 
 
797
    def test_signatures_never(self):
 
798
        self.get_branch_config('/a/c')
 
799
        self.assertEqual(config.CHECK_NEVER,
 
800
                         self.my_config.signature_checking())
 
801
 
 
802
    def test_signatures_when_available(self):
 
803
        self.get_branch_config('/a/', global_config=sample_ignore_signatures)
 
804
        self.assertEqual(config.CHECK_IF_POSSIBLE,
 
805
                         self.my_config.signature_checking())
 
806
 
 
807
    def test_signatures_always(self):
 
808
        self.get_branch_config('/b')
 
809
        self.assertEqual(config.CHECK_ALWAYS,
 
810
                         self.my_config.signature_checking())
 
811
 
 
812
    def test_gpg_signing_command(self):
 
813
        self.get_branch_config('/b')
 
814
        self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
 
815
 
 
816
    def test_gpg_signing_command_missing(self):
 
817
        self.get_branch_config('/a')
 
818
        self.assertEqual("false", self.my_config.gpg_signing_command())
 
819
 
 
820
    def test_get_user_option_global(self):
 
821
        self.get_branch_config('/a')
 
822
        self.assertEqual('something',
 
823
                         self.my_config.get_user_option('user_global_option'))
 
824
 
 
825
    def test_get_user_option_local(self):
 
826
        self.get_branch_config('/a')
 
827
        self.assertEqual('local',
 
828
                         self.my_config.get_user_option('user_local_option'))
 
829
 
 
830
    def test_get_user_option_appendpath(self):
 
831
        # returned as is for the base path:
 
832
        self.get_branch_config('http://www.example.com')
 
833
        self.assertEqual('append',
 
834
                         self.my_config.get_user_option('appendpath_option'))
 
835
        # Extra path components get appended:
 
836
        self.get_branch_config('http://www.example.com/a/b/c')
 
837
        self.assertEqual('append/a/b/c',
 
838
                         self.my_config.get_user_option('appendpath_option'))
 
839
        # Overriden for http://www.example.com/dir, where it is a
 
840
        # normal option:
 
841
        self.get_branch_config('http://www.example.com/dir/a/b/c')
 
842
        self.assertEqual('normal',
 
843
                         self.my_config.get_user_option('appendpath_option'))
 
844
 
 
845
    def test_get_user_option_norecurse(self):
 
846
        self.get_branch_config('http://www.example.com')
 
847
        self.assertEqual('norecurse',
 
848
                         self.my_config.get_user_option('norecurse_option'))
 
849
        self.get_branch_config('http://www.example.com/dir')
 
850
        self.assertEqual(None,
 
851
                         self.my_config.get_user_option('norecurse_option'))
 
852
        # http://www.example.com/norecurse is a recurse=False section
 
853
        # that redefines normal_option.  Subdirectories do not pick up
 
854
        # this redefinition.
 
855
        self.get_branch_config('http://www.example.com/norecurse')
 
856
        self.assertEqual('norecurse',
 
857
                         self.my_config.get_user_option('normal_option'))
 
858
        self.get_branch_config('http://www.example.com/norecurse/subdir')
 
859
        self.assertEqual('normal',
 
860
                         self.my_config.get_user_option('normal_option'))
 
861
 
 
862
    def test_set_user_option_norecurse(self):
 
863
        self.get_branch_config('http://www.example.com')
 
864
        self.my_config.set_user_option('foo', 'bar',
 
865
                                       store=config.STORE_LOCATION_NORECURSE)
 
866
        self.assertEqual(
 
867
            self.my_location_config._get_option_policy(
 
868
            'http://www.example.com', 'foo'),
 
869
            config.POLICY_NORECURSE)
 
870
 
 
871
    def test_set_user_option_appendpath(self):
 
872
        self.get_branch_config('http://www.example.com')
 
873
        self.my_config.set_user_option('foo', 'bar',
 
874
                                       store=config.STORE_LOCATION_APPENDPATH)
 
875
        self.assertEqual(
 
876
            self.my_location_config._get_option_policy(
 
877
            'http://www.example.com', 'foo'),
 
878
            config.POLICY_APPENDPATH)
 
879
 
 
880
    def test_set_user_option_change_policy(self):
 
881
        self.get_branch_config('http://www.example.com')
 
882
        self.my_config.set_user_option('norecurse_option', 'normal',
 
883
                                       store=config.STORE_LOCATION)
 
884
        self.assertEqual(
 
885
            self.my_location_config._get_option_policy(
 
886
            'http://www.example.com', 'norecurse_option'),
 
887
            config.POLICY_NONE)
 
888
 
 
889
    def test_set_user_option_recurse_false_section(self):
 
890
        # The following section has recurse=False set.  The test is to
 
891
        # make sure that a normal option can be added to the section,
 
892
        # converting recurse=False to the norecurse policy.
 
893
        self.get_branch_config('http://www.example.com/norecurse')
 
894
        self.callDeprecated(['The recurse option is deprecated as of 0.14.  '
 
895
                             'The section "http://www.example.com/norecurse" '
 
896
                             'has been converted to use policies.'],
 
897
                            self.my_config.set_user_option,
 
898
                            'foo', 'bar', store=config.STORE_LOCATION)
 
899
        self.assertEqual(
 
900
            self.my_location_config._get_option_policy(
 
901
            'http://www.example.com/norecurse', 'foo'),
 
902
            config.POLICY_NONE)
 
903
        # The previously existing option is still norecurse:
 
904
        self.assertEqual(
 
905
            self.my_location_config._get_option_policy(
 
906
            'http://www.example.com/norecurse', 'normal_option'),
 
907
            config.POLICY_NORECURSE)
 
908
 
 
909
    def test_post_commit_default(self):
 
910
        self.get_branch_config('/a/c')
 
911
        self.assertEqual('bzrlib.tests.test_config.post_commit',
 
912
                         self.my_config.post_commit())
 
913
 
 
914
    def get_branch_config(self, location, global_config=None):
 
915
        if global_config is None:
 
916
            global_file = StringIO(sample_config_text.encode('utf-8'))
 
917
        else:
 
918
            global_file = StringIO(global_config.encode('utf-8'))
 
919
        branches_file = StringIO(sample_branches_text.encode('utf-8'))
 
920
        self.my_config = config.BranchConfig(FakeBranch(location))
 
921
        # Force location config to use specified file
 
922
        self.my_location_config = self.my_config._get_location_config()
 
923
        self.my_location_config._get_parser(branches_file)
 
924
        # Force global config to use specified file
 
925
        self.my_config._get_global_config()._get_parser(global_file)
 
926
 
 
927
    def test_set_user_setting_sets_and_saves(self):
 
928
        self.get_branch_config('/a/c')
 
929
        record = InstrumentedConfigObj("foo")
 
930
        self.my_location_config._parser = record
 
931
 
 
932
        real_mkdir = os.mkdir
 
933
        self.created = False
 
934
        def checked_mkdir(path, mode=0777):
 
935
            self.log('making directory: %s', path)
 
936
            real_mkdir(path, mode)
 
937
            self.created = True
 
938
 
 
939
        os.mkdir = checked_mkdir
 
940
        try:
 
941
            self.callDeprecated(['The recurse option is deprecated as of '
 
942
                                 '0.14.  The section "/a/c" has been '
 
943
                                 'converted to use policies.'],
 
944
                                self.my_config.set_user_option,
 
945
                                'foo', 'bar', store=config.STORE_LOCATION)
 
946
        finally:
 
947
            os.mkdir = real_mkdir
 
948
 
 
949
        self.failUnless(self.created, 'Failed to create ~/.bazaar')
 
950
        self.assertEqual([('__contains__', '/a/c'),
 
951
                          ('__contains__', '/a/c/'),
 
952
                          ('__setitem__', '/a/c', {}),
 
953
                          ('__getitem__', '/a/c'),
 
954
                          ('__setitem__', 'foo', 'bar'),
 
955
                          ('__getitem__', '/a/c'),
 
956
                          ('as_bool', 'recurse'),
 
957
                          ('__getitem__', '/a/c'),
 
958
                          ('__delitem__', 'recurse'),
 
959
                          ('__getitem__', '/a/c'),
 
960
                          ('keys',),
 
961
                          ('__getitem__', '/a/c'),
 
962
                          ('__contains__', 'foo:policy'),
 
963
                          ('write',)],
 
964
                         record._calls[1:])
 
965
 
 
966
    def test_set_user_setting_sets_and_saves2(self):
 
967
        self.get_branch_config('/a/c')
 
968
        self.assertIs(self.my_config.get_user_option('foo'), None)
 
969
        self.my_config.set_user_option('foo', 'bar')
 
970
        self.assertEqual(
 
971
            self.my_config.branch.control_files.files['branch.conf'].strip(),
 
972
            'foo = bar')
 
973
        self.assertEqual(self.my_config.get_user_option('foo'), 'bar')
 
974
        self.my_config.set_user_option('foo', 'baz',
 
975
                                       store=config.STORE_LOCATION)
 
976
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
 
977
        self.my_config.set_user_option('foo', 'qux')
 
978
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
 
979
 
 
980
    def test_get_bzr_remote_path(self):
 
981
        my_config = config.LocationConfig('/a/c')
 
982
        self.assertEqual('bzr', my_config.get_bzr_remote_path())
 
983
        my_config.set_user_option('bzr_remote_path', '/path-bzr')
 
984
        self.assertEqual('/path-bzr', my_config.get_bzr_remote_path())
 
985
        os.environ['BZR_REMOTE_PATH'] = '/environ-bzr'
 
986
        self.assertEqual('/environ-bzr', my_config.get_bzr_remote_path())
 
987
 
 
988
 
 
989
precedence_global = 'option = global'
 
990
precedence_branch = 'option = branch'
 
991
precedence_location = """
 
992
[http://]
 
993
recurse = true
 
994
option = recurse
 
995
[http://example.com/specific]
 
996
option = exact
 
997
"""
 
998
 
 
999
 
 
1000
class TestBranchConfigItems(tests.TestCaseInTempDir):
 
1001
 
 
1002
    def get_branch_config(self, global_config=None, location=None,
 
1003
                          location_config=None, branch_data_config=None):
 
1004
        my_config = config.BranchConfig(FakeBranch(location))
 
1005
        if global_config is not None:
 
1006
            global_file = StringIO(global_config.encode('utf-8'))
 
1007
            my_config._get_global_config()._get_parser(global_file)
 
1008
        self.my_location_config = my_config._get_location_config()
 
1009
        if location_config is not None:
 
1010
            location_file = StringIO(location_config.encode('utf-8'))
 
1011
            self.my_location_config._get_parser(location_file)
 
1012
        if branch_data_config is not None:
 
1013
            my_config.branch.control_files.files['branch.conf'] = \
 
1014
                branch_data_config
 
1015
        return my_config
 
1016
 
 
1017
    def test_user_id(self):
 
1018
        branch = FakeBranch(user_id='Robert Collins <robertc@example.net>')
 
1019
        my_config = config.BranchConfig(branch)
 
1020
        self.assertEqual("Robert Collins <robertc@example.net>",
 
1021
                         my_config.username())
 
1022
        my_config.branch.control_files.files['email'] = "John"
 
1023
        my_config.set_user_option('email',
 
1024
                                  "Robert Collins <robertc@example.org>")
 
1025
        self.assertEqual("John", my_config.username())
 
1026
        del my_config.branch.control_files.files['email']
 
1027
        self.assertEqual("Robert Collins <robertc@example.org>",
 
1028
                         my_config.username())
 
1029
 
 
1030
    def test_not_set_in_branch(self):
 
1031
        my_config = self.get_branch_config(sample_config_text)
 
1032
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
 
1033
                         my_config._get_user_id())
 
1034
        my_config.branch.control_files.files['email'] = "John"
 
1035
        self.assertEqual("John", my_config._get_user_id())
 
1036
 
 
1037
    def test_BZR_EMAIL_OVERRIDES(self):
 
1038
        os.environ['BZR_EMAIL'] = "Robert Collins <robertc@example.org>"
 
1039
        branch = FakeBranch()
 
1040
        my_config = config.BranchConfig(branch)
 
1041
        self.assertEqual("Robert Collins <robertc@example.org>",
 
1042
                         my_config.username())
 
1043
 
 
1044
    def test_signatures_forced(self):
 
1045
        my_config = self.get_branch_config(
 
1046
            global_config=sample_always_signatures)
 
1047
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
1048
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
 
1049
        self.assertTrue(my_config.signature_needed())
 
1050
 
 
1051
    def test_signatures_forced_branch(self):
 
1052
        my_config = self.get_branch_config(
 
1053
            global_config=sample_ignore_signatures,
 
1054
            branch_data_config=sample_always_signatures)
 
1055
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
1056
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
 
1057
        self.assertTrue(my_config.signature_needed())
 
1058
 
 
1059
    def test_gpg_signing_command(self):
 
1060
        my_config = self.get_branch_config(
 
1061
            # branch data cannot set gpg_signing_command
 
1062
            branch_data_config="gpg_signing_command=pgp")
 
1063
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
1064
        my_config._get_global_config()._get_parser(config_file)
 
1065
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
 
1066
 
 
1067
    def test_get_user_option_global(self):
 
1068
        branch = FakeBranch()
 
1069
        my_config = config.BranchConfig(branch)
 
1070
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
1071
        (my_config._get_global_config()._get_parser(config_file))
 
1072
        self.assertEqual('something',
 
1073
                         my_config.get_user_option('user_global_option'))
 
1074
 
 
1075
    def test_post_commit_default(self):
 
1076
        branch = FakeBranch()
 
1077
        my_config = self.get_branch_config(sample_config_text, '/a/c',
 
1078
                                           sample_branches_text)
 
1079
        self.assertEqual(my_config.branch.base, '/a/c')
 
1080
        self.assertEqual('bzrlib.tests.test_config.post_commit',
 
1081
                         my_config.post_commit())
 
1082
        my_config.set_user_option('post_commit', 'rmtree_root')
 
1083
        # post-commit is ignored when bresent in branch data
 
1084
        self.assertEqual('bzrlib.tests.test_config.post_commit',
 
1085
                         my_config.post_commit())
 
1086
        my_config.set_user_option('post_commit', 'rmtree_root',
 
1087
                                  store=config.STORE_LOCATION)
 
1088
        self.assertEqual('rmtree_root', my_config.post_commit())
 
1089
 
 
1090
    def test_config_precedence(self):
 
1091
        my_config = self.get_branch_config(global_config=precedence_global)
 
1092
        self.assertEqual(my_config.get_user_option('option'), 'global')
 
1093
        my_config = self.get_branch_config(global_config=precedence_global,
 
1094
                                      branch_data_config=precedence_branch)
 
1095
        self.assertEqual(my_config.get_user_option('option'), 'branch')
 
1096
        my_config = self.get_branch_config(global_config=precedence_global,
 
1097
                                      branch_data_config=precedence_branch,
 
1098
                                      location_config=precedence_location)
 
1099
        self.assertEqual(my_config.get_user_option('option'), 'recurse')
 
1100
        my_config = self.get_branch_config(global_config=precedence_global,
 
1101
                                      branch_data_config=precedence_branch,
 
1102
                                      location_config=precedence_location,
 
1103
                                      location='http://example.com/specific')
 
1104
        self.assertEqual(my_config.get_user_option('option'), 'exact')
 
1105
 
 
1106
    def test_get_mail_client(self):
 
1107
        config = self.get_branch_config()
 
1108
        client = config.get_mail_client()
 
1109
        self.assertIsInstance(client, mail_client.DefaultMail)
 
1110
 
 
1111
        # Specific clients
 
1112
        config.set_user_option('mail_client', 'evolution')
 
1113
        client = config.get_mail_client()
 
1114
        self.assertIsInstance(client, mail_client.Evolution)
 
1115
 
 
1116
        config.set_user_option('mail_client', 'kmail')
 
1117
        client = config.get_mail_client()
 
1118
        self.assertIsInstance(client, mail_client.KMail)
 
1119
 
 
1120
        config.set_user_option('mail_client', 'mutt')
 
1121
        client = config.get_mail_client()
 
1122
        self.assertIsInstance(client, mail_client.Mutt)
 
1123
 
 
1124
        config.set_user_option('mail_client', 'thunderbird')
 
1125
        client = config.get_mail_client()
 
1126
        self.assertIsInstance(client, mail_client.Thunderbird)
 
1127
 
 
1128
        # Generic options
 
1129
        config.set_user_option('mail_client', 'default')
 
1130
        client = config.get_mail_client()
 
1131
        self.assertIsInstance(client, mail_client.DefaultMail)
 
1132
 
 
1133
        config.set_user_option('mail_client', 'editor')
 
1134
        client = config.get_mail_client()
 
1135
        self.assertIsInstance(client, mail_client.Editor)
 
1136
 
 
1137
        config.set_user_option('mail_client', 'mapi')
 
1138
        client = config.get_mail_client()
 
1139
        self.assertIsInstance(client, mail_client.MAPIClient)
 
1140
 
 
1141
        config.set_user_option('mail_client', 'xdg-email')
 
1142
        client = config.get_mail_client()
 
1143
        self.assertIsInstance(client, mail_client.XDGEmail)
 
1144
 
 
1145
        config.set_user_option('mail_client', 'firebird')
 
1146
        self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
 
1147
 
 
1148
 
 
1149
class TestMailAddressExtraction(tests.TestCase):
 
1150
 
 
1151
    def test_extract_email_address(self):
 
1152
        self.assertEqual('jane@test.com',
 
1153
                         config.extract_email_address('Jane <jane@test.com>'))
 
1154
        self.assertRaises(errors.NoEmailInUsername,
 
1155
                          config.extract_email_address, 'Jane Tester')
 
1156
 
 
1157
    def test_parse_username(self):
 
1158
        self.assertEqual(('', 'jdoe@example.com'),
 
1159
                         config.parse_username('jdoe@example.com'))
 
1160
        self.assertEqual(('', 'jdoe@example.com'),
 
1161
                         config.parse_username('<jdoe@example.com>'))
 
1162
        self.assertEqual(('John Doe', 'jdoe@example.com'),
 
1163
                         config.parse_username('John Doe <jdoe@example.com>'))
 
1164
        self.assertEqual(('John Doe', ''),
 
1165
                         config.parse_username('John Doe'))
 
1166
        self.assertEqual(('John Doe', 'jdoe@example.com'),
 
1167
                         config.parse_username('John Doe jdoe@example.com'))
 
1168
 
 
1169
class TestTreeConfig(tests.TestCaseWithTransport):
 
1170
 
 
1171
    def test_get_value(self):
 
1172
        """Test that retreiving a value from a section is possible"""
 
1173
        branch = self.make_branch('.')
 
1174
        tree_config = config.TreeConfig(branch)
 
1175
        tree_config.set_option('value', 'key', 'SECTION')
 
1176
        tree_config.set_option('value2', 'key2')
 
1177
        tree_config.set_option('value3-top', 'key3')
 
1178
        tree_config.set_option('value3-section', 'key3', 'SECTION')
 
1179
        value = tree_config.get_option('key', 'SECTION')
 
1180
        self.assertEqual(value, 'value')
 
1181
        value = tree_config.get_option('key2')
 
1182
        self.assertEqual(value, 'value2')
 
1183
        self.assertEqual(tree_config.get_option('non-existant'), None)
 
1184
        value = tree_config.get_option('non-existant', 'SECTION')
 
1185
        self.assertEqual(value, None)
 
1186
        value = tree_config.get_option('non-existant', default='default')
 
1187
        self.assertEqual(value, 'default')
 
1188
        self.assertEqual(tree_config.get_option('key2', 'NOSECTION'), None)
 
1189
        value = tree_config.get_option('key2', 'NOSECTION', default='default')
 
1190
        self.assertEqual(value, 'default')
 
1191
        value = tree_config.get_option('key3')
 
1192
        self.assertEqual(value, 'value3-top')
 
1193
        value = tree_config.get_option('key3', 'SECTION')
 
1194
        self.assertEqual(value, 'value3-section')
 
1195
 
 
1196
 
 
1197
class TestTransportConfig(tests.TestCaseWithTransport):
 
1198
 
 
1199
    def test_get_value(self):
 
1200
        """Test that retreiving a value from a section is possible"""
 
1201
        bzrdir_config = config.TransportConfig(transport.get_transport('.'),
 
1202
                                               'control.conf')
 
1203
        bzrdir_config.set_option('value', 'key', 'SECTION')
 
1204
        bzrdir_config.set_option('value2', 'key2')
 
1205
        bzrdir_config.set_option('value3-top', 'key3')
 
1206
        bzrdir_config.set_option('value3-section', 'key3', 'SECTION')
 
1207
        value = bzrdir_config.get_option('key', 'SECTION')
 
1208
        self.assertEqual(value, 'value')
 
1209
        value = bzrdir_config.get_option('key2')
 
1210
        self.assertEqual(value, 'value2')
 
1211
        self.assertEqual(bzrdir_config.get_option('non-existant'), None)
 
1212
        value = bzrdir_config.get_option('non-existant', 'SECTION')
 
1213
        self.assertEqual(value, None)
 
1214
        value = bzrdir_config.get_option('non-existant', default='default')
 
1215
        self.assertEqual(value, 'default')
 
1216
        self.assertEqual(bzrdir_config.get_option('key2', 'NOSECTION'), None)
 
1217
        value = bzrdir_config.get_option('key2', 'NOSECTION',
 
1218
                                         default='default')
 
1219
        self.assertEqual(value, 'default')
 
1220
        value = bzrdir_config.get_option('key3')
 
1221
        self.assertEqual(value, 'value3-top')
 
1222
        value = bzrdir_config.get_option('key3', 'SECTION')
 
1223
        self.assertEqual(value, 'value3-section')
 
1224
 
 
1225
    def test_set_unset_default_stack_on(self):
 
1226
        my_dir = self.make_bzrdir('.')
 
1227
        bzrdir_config = config.BzrDirConfig(my_dir)
 
1228
        self.assertIs(None, bzrdir_config.get_default_stack_on())
 
1229
        bzrdir_config.set_default_stack_on('Foo')
 
1230
        self.assertEqual('Foo', bzrdir_config._config.get_option(
 
1231
                         'default_stack_on'))
 
1232
        self.assertEqual('Foo', bzrdir_config.get_default_stack_on())
 
1233
        bzrdir_config.set_default_stack_on(None)
 
1234
        self.assertIs(None, bzrdir_config.get_default_stack_on())
 
1235
 
 
1236
 
 
1237
class TestAuthenticationConfigFile(tests.TestCase):
 
1238
    """Test the authentication.conf file matching"""
 
1239
 
 
1240
    def _got_user_passwd(self, expected_user, expected_password,
 
1241
                         config, *args, **kwargs):
 
1242
        credentials = config.get_credentials(*args, **kwargs)
 
1243
        if credentials is None:
 
1244
            user = None
 
1245
            password = None
 
1246
        else:
 
1247
            user = credentials['user']
 
1248
            password = credentials['password']
 
1249
        self.assertEquals(expected_user, user)
 
1250
        self.assertEquals(expected_password, password)
 
1251
 
 
1252
    def test_empty_config(self):
 
1253
        conf = config.AuthenticationConfig(_file=StringIO())
 
1254
        self.assertEquals({}, conf._get_config())
 
1255
        self._got_user_passwd(None, None, conf, 'http', 'foo.net')
 
1256
 
 
1257
    def test_missing_auth_section_header(self):
 
1258
        conf = config.AuthenticationConfig(_file=StringIO('foo = bar'))
 
1259
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
 
1260
 
 
1261
    def test_auth_section_header_not_closed(self):
 
1262
        conf = config.AuthenticationConfig(_file=StringIO('[DEF'))
 
1263
        self.assertRaises(errors.ParseConfigError, conf._get_config)
 
1264
 
 
1265
    def test_auth_value_not_boolean(self):
 
1266
        conf = config.AuthenticationConfig(_file=StringIO(
 
1267
                """[broken]
 
1268
scheme=ftp
 
1269
user=joe
 
1270
verify_certificates=askme # Error: Not a boolean
 
1271
"""))
 
1272
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
 
1273
 
 
1274
    def test_auth_value_not_int(self):
 
1275
        conf = config.AuthenticationConfig(_file=StringIO(
 
1276
                """[broken]
 
1277
scheme=ftp
 
1278
user=joe
 
1279
port=port # Error: Not an int
 
1280
"""))
 
1281
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
 
1282
 
 
1283
    def test_unknown_password_encoding(self):
 
1284
        conf = config.AuthenticationConfig(_file=StringIO(
 
1285
                """[broken]
 
1286
scheme=ftp
 
1287
user=joe
 
1288
password_encoding=unknown
 
1289
"""))
 
1290
        self.assertRaises(ValueError, conf.get_password,
 
1291
                          'ftp', 'foo.net', 'joe')
 
1292
 
 
1293
    def test_credentials_for_scheme_host(self):
 
1294
        conf = config.AuthenticationConfig(_file=StringIO(
 
1295
                """# Identity on foo.net
 
1296
[ftp definition]
 
1297
scheme=ftp
 
1298
host=foo.net
 
1299
user=joe
 
1300
password=secret-pass
 
1301
"""))
 
1302
        # Basic matching
 
1303
        self._got_user_passwd('joe', 'secret-pass', conf, 'ftp', 'foo.net')
 
1304
        # different scheme
 
1305
        self._got_user_passwd(None, None, conf, 'http', 'foo.net')
 
1306
        # different host
 
1307
        self._got_user_passwd(None, None, conf, 'ftp', 'bar.net')
 
1308
 
 
1309
    def test_credentials_for_host_port(self):
 
1310
        conf = config.AuthenticationConfig(_file=StringIO(
 
1311
                """# Identity on foo.net
 
1312
[ftp definition]
 
1313
scheme=ftp
 
1314
port=10021
 
1315
host=foo.net
 
1316
user=joe
 
1317
password=secret-pass
 
1318
"""))
 
1319
        # No port
 
1320
        self._got_user_passwd('joe', 'secret-pass',
 
1321
                              conf, 'ftp', 'foo.net', port=10021)
 
1322
        # different port
 
1323
        self._got_user_passwd(None, None, conf, 'ftp', 'foo.net')
 
1324
 
 
1325
    def test_for_matching_host(self):
 
1326
        conf = config.AuthenticationConfig(_file=StringIO(
 
1327
                """# Identity on foo.net
 
1328
[sourceforge]
 
1329
scheme=bzr
 
1330
host=bzr.sf.net
 
1331
user=joe
 
1332
password=joepass
 
1333
[sourceforge domain]
 
1334
scheme=bzr
 
1335
host=.bzr.sf.net
 
1336
user=georges
 
1337
password=bendover
 
1338
"""))
 
1339
        # matching domain
 
1340
        self._got_user_passwd('georges', 'bendover',
 
1341
                              conf, 'bzr', 'foo.bzr.sf.net')
 
1342
        # phishing attempt
 
1343
        self._got_user_passwd(None, None,
 
1344
                              conf, 'bzr', 'bbzr.sf.net')
 
1345
 
 
1346
    def test_for_matching_host_None(self):
 
1347
        conf = config.AuthenticationConfig(_file=StringIO(
 
1348
                """# Identity on foo.net
 
1349
[catchup bzr]
 
1350
scheme=bzr
 
1351
user=joe
 
1352
password=joepass
 
1353
[DEFAULT]
 
1354
user=georges
 
1355
password=bendover
 
1356
"""))
 
1357
        # match no host
 
1358
        self._got_user_passwd('joe', 'joepass',
 
1359
                              conf, 'bzr', 'quux.net')
 
1360
        # no host but different scheme
 
1361
        self._got_user_passwd('georges', 'bendover',
 
1362
                              conf, 'ftp', 'quux.net')
 
1363
 
 
1364
    def test_credentials_for_path(self):
 
1365
        conf = config.AuthenticationConfig(_file=StringIO(
 
1366
                """
 
1367
[http dir1]
 
1368
scheme=http
 
1369
host=bar.org
 
1370
path=/dir1
 
1371
user=jim
 
1372
password=jimpass
 
1373
[http dir2]
 
1374
scheme=http
 
1375
host=bar.org
 
1376
path=/dir2
 
1377
user=georges
 
1378
password=bendover
 
1379
"""))
 
1380
        # no path no dice
 
1381
        self._got_user_passwd(None, None,
 
1382
                              conf, 'http', host='bar.org', path='/dir3')
 
1383
        # matching path
 
1384
        self._got_user_passwd('georges', 'bendover',
 
1385
                              conf, 'http', host='bar.org', path='/dir2')
 
1386
        # matching subdir
 
1387
        self._got_user_passwd('jim', 'jimpass',
 
1388
                              conf, 'http', host='bar.org',path='/dir1/subdir')
 
1389
 
 
1390
    def test_credentials_for_user(self):
 
1391
        conf = config.AuthenticationConfig(_file=StringIO(
 
1392
                """
 
1393
[with user]
 
1394
scheme=http
 
1395
host=bar.org
 
1396
user=jim
 
1397
password=jimpass
 
1398
"""))
 
1399
        # Get user
 
1400
        self._got_user_passwd('jim', 'jimpass',
 
1401
                              conf, 'http', 'bar.org')
 
1402
        # Get same user
 
1403
        self._got_user_passwd('jim', 'jimpass',
 
1404
                              conf, 'http', 'bar.org', user='jim')
 
1405
        # Don't get a different user if one is specified
 
1406
        self._got_user_passwd(None, None,
 
1407
                              conf, 'http', 'bar.org', user='georges')
 
1408
 
 
1409
    def test_credentials_for_user_without_password(self):
 
1410
        conf = config.AuthenticationConfig(_file=StringIO(
 
1411
                """
 
1412
[without password]
 
1413
scheme=http
 
1414
host=bar.org
 
1415
user=jim
 
1416
"""))
 
1417
        # Get user but no password
 
1418
        self._got_user_passwd('jim', None,
 
1419
                              conf, 'http', 'bar.org')
 
1420
 
 
1421
    def test_verify_certificates(self):
 
1422
        conf = config.AuthenticationConfig(_file=StringIO(
 
1423
                """
 
1424
[self-signed]
 
1425
scheme=https
 
1426
host=bar.org
 
1427
user=jim
 
1428
password=jimpass
 
1429
verify_certificates=False
 
1430
[normal]
 
1431
scheme=https
 
1432
host=foo.net
 
1433
user=georges
 
1434
password=bendover
 
1435
"""))
 
1436
        credentials = conf.get_credentials('https', 'bar.org')
 
1437
        self.assertEquals(False, credentials.get('verify_certificates'))
 
1438
        credentials = conf.get_credentials('https', 'foo.net')
 
1439
        self.assertEquals(True, credentials.get('verify_certificates'))
 
1440
 
 
1441
 
 
1442
class TestAuthenticationStorage(tests.TestCaseInTempDir):
 
1443
 
 
1444
    def test_set_credentials(self):
 
1445
        conf = config.AuthenticationConfig()
 
1446
        conf.set_credentials('name', 'host', 'user', 'scheme', 'password',
 
1447
        99, path='/foo', verify_certificates=False, realm='realm')
 
1448
        credentials = conf.get_credentials(host='host', scheme='scheme',
 
1449
                                           port=99, path='/foo',
 
1450
                                           realm='realm')
 
1451
        CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password',
 
1452
                       'verify_certificates': False, 'scheme': 'scheme', 
 
1453
                       'host': 'host', 'port': 99, 'path': '/foo', 
 
1454
                       'realm': 'realm'}
 
1455
        self.assertEqual(CREDENTIALS, credentials)
 
1456
        credentials_from_disk = config.AuthenticationConfig().get_credentials(
 
1457
            host='host', scheme='scheme', port=99, path='/foo', realm='realm')
 
1458
        self.assertEqual(CREDENTIALS, credentials_from_disk)
 
1459
 
 
1460
    def test_reset_credentials_different_name(self):
 
1461
        conf = config.AuthenticationConfig()
 
1462
        conf.set_credentials('name', 'host', 'user', 'scheme', 'password'),
 
1463
        conf.set_credentials('name2', 'host', 'user2', 'scheme', 'password'),
 
1464
        self.assertIs(None, conf._get_config().get('name'))
 
1465
        credentials = conf.get_credentials(host='host', scheme='scheme')
 
1466
        CREDENTIALS = {'name': 'name2', 'user': 'user2', 'password':
 
1467
                       'password', 'verify_certificates': True, 
 
1468
                       'scheme': 'scheme', 'host': 'host', 'port': None, 
 
1469
                       'path': None, 'realm': None}
 
1470
        self.assertEqual(CREDENTIALS, credentials)
 
1471
 
 
1472
 
 
1473
class TestAuthenticationConfig(tests.TestCase):
 
1474
    """Test AuthenticationConfig behaviour"""
 
1475
 
 
1476
    def _check_default_password_prompt(self, expected_prompt_format, scheme,
 
1477
                                       host=None, port=None, realm=None,
 
1478
                                       path=None):
 
1479
        if host is None:
 
1480
            host = 'bar.org'
 
1481
        user, password = 'jim', 'precious'
 
1482
        expected_prompt = expected_prompt_format % {
 
1483
            'scheme': scheme, 'host': host, 'port': port,
 
1484
            'user': user, 'realm': realm}
 
1485
 
 
1486
        stdout = tests.StringIOWrapper()
 
1487
        stderr = tests.StringIOWrapper()
 
1488
        ui.ui_factory = tests.TestUIFactory(stdin=password + '\n',
 
1489
                                            stdout=stdout, stderr=stderr)
 
1490
        # We use an empty conf so that the user is always prompted
 
1491
        conf = config.AuthenticationConfig()
 
1492
        self.assertEquals(password,
 
1493
                          conf.get_password(scheme, host, user, port=port,
 
1494
                                            realm=realm, path=path))
 
1495
        self.assertEquals(expected_prompt, stderr.getvalue())
 
1496
        self.assertEquals('', stdout.getvalue())
 
1497
 
 
1498
    def _check_default_username_prompt(self, expected_prompt_format, scheme,
 
1499
                                       host=None, port=None, realm=None,
 
1500
                                       path=None):
 
1501
        if host is None:
 
1502
            host = 'bar.org'
 
1503
        username = 'jim'
 
1504
        expected_prompt = expected_prompt_format % {
 
1505
            'scheme': scheme, 'host': host, 'port': port,
 
1506
            'realm': realm}
 
1507
        stdout = tests.StringIOWrapper()
 
1508
        stderr = tests.StringIOWrapper()
 
1509
        ui.ui_factory = tests.TestUIFactory(stdin=username+ '\n',
 
1510
                                            stdout=stdout, stderr=stderr)
 
1511
        # We use an empty conf so that the user is always prompted
 
1512
        conf = config.AuthenticationConfig()
 
1513
        self.assertEquals(username, conf.get_user(scheme, host, port=port,
 
1514
                          realm=realm, path=path, ask=True))
 
1515
        self.assertEquals(expected_prompt, stderr.getvalue())
 
1516
        self.assertEquals('', stdout.getvalue())
 
1517
 
 
1518
    def test_username_defaults_prompts(self):
 
1519
        # HTTP prompts can't be tested here, see test_http.py
 
1520
        self._check_default_username_prompt('FTP %(host)s username: ', 'ftp')
 
1521
        self._check_default_username_prompt(
 
1522
            'FTP %(host)s:%(port)d username: ', 'ftp', port=10020)
 
1523
        self._check_default_username_prompt(
 
1524
            'SSH %(host)s:%(port)d username: ', 'ssh', port=12345)
 
1525
 
 
1526
    def test_username_default_no_prompt(self):
 
1527
        conf = config.AuthenticationConfig()
 
1528
        self.assertEquals(None,
 
1529
            conf.get_user('ftp', 'example.com'))
 
1530
        self.assertEquals("explicitdefault",
 
1531
            conf.get_user('ftp', 'example.com', default="explicitdefault"))
 
1532
 
 
1533
    def test_password_default_prompts(self):
 
1534
        # HTTP prompts can't be tested here, see test_http.py
 
1535
        self._check_default_password_prompt(
 
1536
            'FTP %(user)s@%(host)s password: ', 'ftp')
 
1537
        self._check_default_password_prompt(
 
1538
            'FTP %(user)s@%(host)s:%(port)d password: ', 'ftp', port=10020)
 
1539
        self._check_default_password_prompt(
 
1540
            'SSH %(user)s@%(host)s:%(port)d password: ', 'ssh', port=12345)
 
1541
        # SMTP port handling is a bit special (it's handled if embedded in the
 
1542
        # host too)
 
1543
        # FIXME: should we: forbid that, extend it to other schemes, leave
 
1544
        # things as they are that's fine thank you ?
 
1545
        self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
 
1546
                                            'smtp')
 
1547
        self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
 
1548
                                            'smtp', host='bar.org:10025')
 
1549
        self._check_default_password_prompt(
 
1550
            'SMTP %(user)s@%(host)s:%(port)d password: ',
 
1551
            'smtp', port=10025)
 
1552
 
 
1553
    def test_ssh_password_emits_warning(self):
 
1554
        conf = config.AuthenticationConfig(_file=StringIO(
 
1555
                """
 
1556
[ssh with password]
 
1557
scheme=ssh
 
1558
host=bar.org
 
1559
user=jim
 
1560
password=jimpass
 
1561
"""))
 
1562
        entered_password = 'typed-by-hand'
 
1563
        stdout = tests.StringIOWrapper()
 
1564
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
 
1565
                                            stdout=stdout)
 
1566
 
 
1567
        # Since the password defined in the authentication config is ignored,
 
1568
        # the user is prompted
 
1569
        self.assertEquals(entered_password,
 
1570
                          conf.get_password('ssh', 'bar.org', user='jim'))
 
1571
        self.assertContainsRe(
 
1572
            self._get_log(keep_log_file=True),
 
1573
            'password ignored in section \[ssh with password\]')
 
1574
 
 
1575
    def test_ssh_without_password_doesnt_emit_warning(self):
 
1576
        conf = config.AuthenticationConfig(_file=StringIO(
 
1577
                """
 
1578
[ssh with password]
 
1579
scheme=ssh
 
1580
host=bar.org
 
1581
user=jim
 
1582
"""))
 
1583
        entered_password = 'typed-by-hand'
 
1584
        stdout = tests.StringIOWrapper()
 
1585
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
 
1586
                                            stdout=stdout)
 
1587
 
 
1588
        # Since the password defined in the authentication config is ignored,
 
1589
        # the user is prompted
 
1590
        self.assertEquals(entered_password,
 
1591
                          conf.get_password('ssh', 'bar.org', user='jim'))
 
1592
        # No warning shoud be emitted since there is no password. We are only
 
1593
        # providing "user".
 
1594
        self.assertNotContainsRe(
 
1595
            self._get_log(keep_log_file=True),
 
1596
            'password ignored in section \[ssh with password\]')
 
1597
 
 
1598
    def test_uses_fallback_stores(self):
 
1599
        self._old_cs_registry = config.credential_store_registry
 
1600
        def restore():
 
1601
            config.credential_store_registry = self._old_cs_registry
 
1602
        self.addCleanup(restore)
 
1603
        config.credential_store_registry = config.CredentialStoreRegistry()
 
1604
        store = StubCredentialStore()
 
1605
        store.add_credentials("http", "example.com", "joe", "secret")
 
1606
        config.credential_store_registry.register("stub", store, fallback=True)
 
1607
        conf = config.AuthenticationConfig(_file=StringIO())
 
1608
        creds = conf.get_credentials("http", "example.com")
 
1609
        self.assertEquals("joe", creds["user"])
 
1610
        self.assertEquals("secret", creds["password"])
 
1611
 
 
1612
 
 
1613
class StubCredentialStore(config.CredentialStore):
 
1614
 
 
1615
    def __init__(self):
 
1616
        self._username = {}
 
1617
        self._password = {}
 
1618
 
 
1619
    def add_credentials(self, scheme, host, user, password=None):
 
1620
        self._username[(scheme, host)] = user
 
1621
        self._password[(scheme, host)] = password
 
1622
 
 
1623
    def get_credentials(self, scheme, host, port=None, user=None,
 
1624
        path=None, realm=None):
 
1625
        key = (scheme, host)
 
1626
        if not key in self._username:
 
1627
            return None
 
1628
        return { "scheme": scheme, "host": host, "port": port,
 
1629
                "user": self._username[key], "password": self._password[key]}
 
1630
 
 
1631
 
 
1632
class CountingCredentialStore(config.CredentialStore):
 
1633
 
 
1634
    def __init__(self):
 
1635
        self._calls = 0
 
1636
 
 
1637
    def get_credentials(self, scheme, host, port=None, user=None,
 
1638
        path=None, realm=None):
 
1639
        self._calls += 1
 
1640
        return None
 
1641
 
 
1642
 
 
1643
class TestCredentialStoreRegistry(tests.TestCase):
 
1644
 
 
1645
    def _get_cs_registry(self):
 
1646
        return config.credential_store_registry
 
1647
 
 
1648
    def test_default_credential_store(self):
 
1649
        r = self._get_cs_registry()
 
1650
        default = r.get_credential_store(None)
 
1651
        self.assertIsInstance(default, config.PlainTextCredentialStore)
 
1652
 
 
1653
    def test_unknown_credential_store(self):
 
1654
        r = self._get_cs_registry()
 
1655
        # It's hard to imagine someone creating a credential store named
 
1656
        # 'unknown' so we use that as an never registered key.
 
1657
        self.assertRaises(KeyError, r.get_credential_store, 'unknown')
 
1658
 
 
1659
    def test_fallback_none_registered(self):
 
1660
        r = config.CredentialStoreRegistry()
 
1661
        self.assertEquals(None,
 
1662
                          r.get_fallback_credentials("http", "example.com"))
 
1663
 
 
1664
    def test_register(self):
 
1665
        r = config.CredentialStoreRegistry()
 
1666
        r.register("stub", StubCredentialStore(), fallback=False)
 
1667
        r.register("another", StubCredentialStore(), fallback=True)
 
1668
        self.assertEquals(["another", "stub"], r.keys())
 
1669
 
 
1670
    def test_register_lazy(self):
 
1671
        r = config.CredentialStoreRegistry()
 
1672
        r.register_lazy("stub", "bzrlib.tests.test_config",
 
1673
                        "StubCredentialStore", fallback=False)
 
1674
        self.assertEquals(["stub"], r.keys())
 
1675
        self.assertIsInstance(r.get_credential_store("stub"),
 
1676
                              StubCredentialStore)
 
1677
 
 
1678
    def test_is_fallback(self):
 
1679
        r = config.CredentialStoreRegistry()
 
1680
        r.register("stub1", None, fallback=False)
 
1681
        r.register("stub2", None, fallback=True)
 
1682
        self.assertEquals(False, r.is_fallback("stub1"))
 
1683
        self.assertEquals(True, r.is_fallback("stub2"))
 
1684
 
 
1685
    def test_no_fallback(self):
 
1686
        r = config.CredentialStoreRegistry()
 
1687
        store = CountingCredentialStore()
 
1688
        r.register("count", store, fallback=False)
 
1689
        self.assertEquals(None,
 
1690
                          r.get_fallback_credentials("http", "example.com"))
 
1691
        self.assertEquals(0, store._calls)
 
1692
 
 
1693
    def test_fallback_credentials(self):
 
1694
        r = config.CredentialStoreRegistry()
 
1695
        store = StubCredentialStore()
 
1696
        store.add_credentials("http", "example.com",
 
1697
                              "somebody", "geheim")
 
1698
        r.register("stub", store, fallback=True)
 
1699
        creds = r.get_fallback_credentials("http", "example.com")
 
1700
        self.assertEquals("somebody", creds["user"])
 
1701
        self.assertEquals("geheim", creds["password"])
 
1702
 
 
1703
    def test_fallback_first_wins(self):
 
1704
        r = config.CredentialStoreRegistry()
 
1705
        stub1 = StubCredentialStore()
 
1706
        stub1.add_credentials("http", "example.com",
 
1707
                              "somebody", "stub1")
 
1708
        r.register("stub1", stub1, fallback=True)
 
1709
        stub2 = StubCredentialStore()
 
1710
        stub2.add_credentials("http", "example.com",
 
1711
                              "somebody", "stub2")
 
1712
        r.register("stub2", stub1, fallback=True)
 
1713
        creds = r.get_fallback_credentials("http", "example.com")
 
1714
        self.assertEquals("somebody", creds["user"])
 
1715
        self.assertEquals("stub1", creds["password"])
 
1716
 
 
1717
 
 
1718
class TestPlainTextCredentialStore(tests.TestCase):
 
1719
 
 
1720
    def test_decode_password(self):
 
1721
        r = config.credential_store_registry
 
1722
        plain_text = r.get_credential_store()
 
1723
        decoded = plain_text.decode_password(dict(password='secret'))
 
1724
        self.assertEquals('secret', decoded)
 
1725
 
 
1726
 
 
1727
# FIXME: Once we have a way to declare authentication to all test servers, we
 
1728
# can implement generic tests.
 
1729
# test_user_password_in_url
 
1730
# test_user_in_url_password_from_config
 
1731
# test_user_in_url_password_prompted
 
1732
# test_user_in_config
 
1733
# test_user_getpass.getuser
 
1734
# test_user_prompted ?
 
1735
class TestAuthenticationRing(tests.TestCaseWithTransport):
 
1736
    pass