~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_bzrdir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-02-18 13:27:08 UTC
  • mfrom: (4011.4.3 ssh-hints)
  • Revision ID: pqm@pqm.ubuntu.com-20090218132708-okubrahz9exvae9r
(Jelmer) Point out bzr+ssh:// to the user when they use ssh://.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Tests for the BzrDir facility and any format specific tests.
 
18
 
 
19
For interface contract tests, see tests/bzr_dir_implementations.
 
20
"""
 
21
 
 
22
import os
 
23
import os.path
 
24
from StringIO import StringIO
 
25
import subprocess
 
26
import sys
 
27
 
 
28
from bzrlib import (
 
29
    bzrdir,
 
30
    errors,
 
31
    help_topics,
 
32
    repository,
 
33
    osutils,
 
34
    symbol_versioning,
 
35
    urlutils,
 
36
    win32utils,
 
37
    workingtree,
 
38
    )
 
39
import bzrlib.branch
 
40
from bzrlib.errors import (NotBranchError,
 
41
                           UnknownFormatError,
 
42
                           UnsupportedFormatError,
 
43
                           )
 
44
from bzrlib.tests import (
 
45
    TestCase,
 
46
    TestCaseWithMemoryTransport,
 
47
    TestCaseWithTransport,
 
48
    TestSkipped,
 
49
    test_sftp_transport
 
50
    )
 
51
from bzrlib.tests import(
 
52
    http_server,
 
53
    http_utils,
 
54
    )
 
55
from bzrlib.tests.test_http import TestWithTransport_pycurl
 
56
from bzrlib.transport import get_transport
 
57
from bzrlib.transport.http._urllib import HttpTransport_urllib
 
58
from bzrlib.transport.memory import MemoryServer
 
59
from bzrlib.transport.nosmart import NoSmartTransportDecorator
 
60
from bzrlib.transport.readonly import ReadonlyTransportDecorator
 
61
from bzrlib.repofmt import knitrepo, weaverepo
 
62
 
 
63
 
 
64
class TestDefaultFormat(TestCase):
 
65
 
 
66
    def test_get_set_default_format(self):
 
67
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
68
        # default is BzrDirFormat6
 
69
        self.failUnless(isinstance(old_format, bzrdir.BzrDirMetaFormat1))
 
70
        bzrdir.BzrDirFormat._set_default_format(SampleBzrDirFormat())
 
71
        # creating a bzr dir should now create an instrumented dir.
 
72
        try:
 
73
            result = bzrdir.BzrDir.create('memory:///')
 
74
            self.failUnless(isinstance(result, SampleBzrDir))
 
75
        finally:
 
76
            bzrdir.BzrDirFormat._set_default_format(old_format)
 
77
        self.assertEqual(old_format, bzrdir.BzrDirFormat.get_default_format())
 
78
 
 
79
 
 
80
class TestFormatRegistry(TestCase):
 
81
 
 
82
    def make_format_registry(self):
 
83
        my_format_registry = bzrdir.BzrDirFormatRegistry()
 
84
        my_format_registry.register('weave', bzrdir.BzrDirFormat6,
 
85
            'Pre-0.8 format.  Slower and does not support checkouts or shared'
 
86
            ' repositories', deprecated=True)
 
87
        my_format_registry.register_lazy('lazy', 'bzrlib.bzrdir', 
 
88
            'BzrDirFormat6', 'Format registered lazily', deprecated=True)
 
89
        my_format_registry.register_metadir('knit',
 
90
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
91
            'Format using knits',
 
92
            )
 
93
        my_format_registry.set_default('knit')
 
94
        my_format_registry.register_metadir(
 
95
            'branch6',
 
96
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
97
            'Experimental successor to knit.  Use at your own risk.',
 
98
            branch_format='bzrlib.branch.BzrBranchFormat6',
 
99
            experimental=True)
 
100
        my_format_registry.register_metadir(
 
101
            'hidden format',
 
102
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
103
            'Experimental successor to knit.  Use at your own risk.',
 
104
            branch_format='bzrlib.branch.BzrBranchFormat6', hidden=True)
 
105
        my_format_registry.register('hiddenweave', bzrdir.BzrDirFormat6,
 
106
            'Pre-0.8 format.  Slower and does not support checkouts or shared'
 
107
            ' repositories', hidden=True)
 
108
        my_format_registry.register_lazy('hiddenlazy', 'bzrlib.bzrdir',
 
109
            'BzrDirFormat6', 'Format registered lazily', deprecated=True,
 
110
            hidden=True)
 
111
        return my_format_registry
 
112
 
 
113
    def test_format_registry(self):
 
114
        my_format_registry = self.make_format_registry()
 
115
        my_bzrdir = my_format_registry.make_bzrdir('lazy')
 
116
        self.assertIsInstance(my_bzrdir, bzrdir.BzrDirFormat6)
 
117
        my_bzrdir = my_format_registry.make_bzrdir('weave')
 
118
        self.assertIsInstance(my_bzrdir, bzrdir.BzrDirFormat6)
 
119
        my_bzrdir = my_format_registry.make_bzrdir('default')
 
120
        self.assertIsInstance(my_bzrdir.repository_format, 
 
121
            knitrepo.RepositoryFormatKnit1)
 
122
        my_bzrdir = my_format_registry.make_bzrdir('knit')
 
123
        self.assertIsInstance(my_bzrdir.repository_format, 
 
124
            knitrepo.RepositoryFormatKnit1)
 
125
        my_bzrdir = my_format_registry.make_bzrdir('branch6')
 
126
        self.assertIsInstance(my_bzrdir.get_branch_format(),
 
127
                              bzrlib.branch.BzrBranchFormat6)
 
128
 
 
129
    def test_get_help(self):
 
130
        my_format_registry = self.make_format_registry()
 
131
        self.assertEqual('Format registered lazily',
 
132
                         my_format_registry.get_help('lazy'))
 
133
        self.assertEqual('Format using knits', 
 
134
                         my_format_registry.get_help('knit'))
 
135
        self.assertEqual('Format using knits', 
 
136
                         my_format_registry.get_help('default'))
 
137
        self.assertEqual('Pre-0.8 format.  Slower and does not support'
 
138
                         ' checkouts or shared repositories', 
 
139
                         my_format_registry.get_help('weave'))
 
140
        
 
141
    def test_help_topic(self):
 
142
        topics = help_topics.HelpTopicRegistry()
 
143
        registry = self.make_format_registry()
 
144
        topics.register('current-formats', registry.help_topic, 
 
145
                        'Current formats')
 
146
        topics.register('other-formats', registry.help_topic, 
 
147
                        'Other formats')
 
148
        new = topics.get_detail('current-formats')
 
149
        rest = topics.get_detail('other-formats')
 
150
        experimental, deprecated = rest.split('Deprecated formats')
 
151
        self.assertContainsRe(new, 'bzr help formats')
 
152
        self.assertContainsRe(new, 
 
153
                ':knit:\n    \(native\) \(default\) Format using knits\n')
 
154
        self.assertContainsRe(experimental, 
 
155
                ':branch6:\n    \(native\) Experimental successor to knit')
 
156
        self.assertContainsRe(deprecated, 
 
157
                ':lazy:\n    \(native\) Format registered lazily\n')
 
158
        self.assertNotContainsRe(new, 'hidden')
 
159
 
 
160
    def test_set_default_repository(self):
 
161
        default_factory = bzrdir.format_registry.get('default')
 
162
        old_default = [k for k, v in bzrdir.format_registry.iteritems()
 
163
                       if v == default_factory and k != 'default'][0]
 
164
        bzrdir.format_registry.set_default_repository('dirstate-with-subtree')
 
165
        try:
 
166
            self.assertIs(bzrdir.format_registry.get('dirstate-with-subtree'),
 
167
                          bzrdir.format_registry.get('default'))
 
168
            self.assertIs(
 
169
                repository.RepositoryFormat.get_default_format().__class__,
 
170
                knitrepo.RepositoryFormatKnit3)
 
171
        finally:
 
172
            bzrdir.format_registry.set_default_repository(old_default)
 
173
 
 
174
    def test_aliases(self):
 
175
        a_registry = bzrdir.BzrDirFormatRegistry()
 
176
        a_registry.register('weave', bzrdir.BzrDirFormat6,
 
177
            'Pre-0.8 format.  Slower and does not support checkouts or shared'
 
178
            ' repositories', deprecated=True)
 
179
        a_registry.register('weavealias', bzrdir.BzrDirFormat6,
 
180
            'Pre-0.8 format.  Slower and does not support checkouts or shared'
 
181
            ' repositories', deprecated=True, alias=True)
 
182
        self.assertEqual(frozenset(['weavealias']), a_registry.aliases())
 
183
 
 
184
 
 
185
class SampleBranch(bzrlib.branch.Branch):
 
186
    """A dummy branch for guess what, dummy use."""
 
187
 
 
188
    def __init__(self, dir):
 
189
        self.bzrdir = dir
 
190
 
 
191
 
 
192
class SampleRepository(bzrlib.repository.Repository):
 
193
    """A dummy repo."""
 
194
 
 
195
    def __init__(self, dir):
 
196
        self.bzrdir = dir
 
197
 
 
198
 
 
199
class SampleBzrDir(bzrdir.BzrDir):
 
200
    """A sample BzrDir implementation to allow testing static methods."""
 
201
 
 
202
    def create_repository(self, shared=False):
 
203
        """See BzrDir.create_repository."""
 
204
        return "A repository"
 
205
 
 
206
    def open_repository(self):
 
207
        """See BzrDir.open_repository."""
 
208
        return SampleRepository(self)
 
209
 
 
210
    def create_branch(self):
 
211
        """See BzrDir.create_branch."""
 
212
        return SampleBranch(self)
 
213
 
 
214
    def create_workingtree(self):
 
215
        """See BzrDir.create_workingtree."""
 
216
        return "A tree"
 
217
 
 
218
 
 
219
class SampleBzrDirFormat(bzrdir.BzrDirFormat):
 
220
    """A sample format
 
221
 
 
222
    this format is initializable, unsupported to aid in testing the 
 
223
    open and open_downlevel routines.
 
224
    """
 
225
 
 
226
    def get_format_string(self):
 
227
        """See BzrDirFormat.get_format_string()."""
 
228
        return "Sample .bzr dir format."
 
229
 
 
230
    def initialize_on_transport(self, t):
 
231
        """Create a bzr dir."""
 
232
        t.mkdir('.bzr')
 
233
        t.put_bytes('.bzr/branch-format', self.get_format_string())
 
234
        return SampleBzrDir(t, self)
 
235
 
 
236
    def is_supported(self):
 
237
        return False
 
238
 
 
239
    def open(self, transport, _found=None):
 
240
        return "opened branch."
 
241
 
 
242
 
 
243
class TestBzrDirFormat(TestCaseWithTransport):
 
244
    """Tests for the BzrDirFormat facility."""
 
245
 
 
246
    def test_find_format(self):
 
247
        # is the right format object found for a branch?
 
248
        # create a branch with a few known format objects.
 
249
        # this is not quite the same as 
 
250
        t = get_transport(self.get_url())
 
251
        self.build_tree(["foo/", "bar/"], transport=t)
 
252
        def check_format(format, url):
 
253
            format.initialize(url)
 
254
            t = get_transport(url)
 
255
            found_format = bzrdir.BzrDirFormat.find_format(t)
 
256
            self.failUnless(isinstance(found_format, format.__class__))
 
257
        check_format(bzrdir.BzrDirFormat5(), "foo")
 
258
        check_format(bzrdir.BzrDirFormat6(), "bar")
 
259
        
 
260
    def test_find_format_nothing_there(self):
 
261
        self.assertRaises(NotBranchError,
 
262
                          bzrdir.BzrDirFormat.find_format,
 
263
                          get_transport('.'))
 
264
 
 
265
    def test_find_format_unknown_format(self):
 
266
        t = get_transport(self.get_url())
 
267
        t.mkdir('.bzr')
 
268
        t.put_bytes('.bzr/branch-format', '')
 
269
        self.assertRaises(UnknownFormatError,
 
270
                          bzrdir.BzrDirFormat.find_format,
 
271
                          get_transport('.'))
 
272
 
 
273
    def test_register_unregister_format(self):
 
274
        format = SampleBzrDirFormat()
 
275
        url = self.get_url()
 
276
        # make a bzrdir
 
277
        format.initialize(url)
 
278
        # register a format for it.
 
279
        bzrdir.BzrDirFormat.register_format(format)
 
280
        # which bzrdir.Open will refuse (not supported)
 
281
        self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open, url)
 
282
        # which bzrdir.open_containing will refuse (not supported)
 
283
        self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open_containing, url)
 
284
        # but open_downlevel will work
 
285
        t = get_transport(url)
 
286
        self.assertEqual(format.open(t), bzrdir.BzrDir.open_unsupported(url))
 
287
        # unregister the format
 
288
        bzrdir.BzrDirFormat.unregister_format(format)
 
289
        # now open_downlevel should fail too.
 
290
        self.assertRaises(UnknownFormatError, bzrdir.BzrDir.open_unsupported, url)
 
291
 
 
292
    def test_create_branch_and_repo_uses_default(self):
 
293
        format = SampleBzrDirFormat()
 
294
        branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url(),
 
295
                                                      format=format)
 
296
        self.assertTrue(isinstance(branch, SampleBranch))
 
297
 
 
298
    def test_create_branch_and_repo_under_shared(self):
 
299
        # creating a branch and repo in a shared repo uses the
 
300
        # shared repository
 
301
        format = bzrdir.format_registry.make_bzrdir('knit')
 
302
        self.make_repository('.', shared=True, format=format)
 
303
        branch = bzrdir.BzrDir.create_branch_and_repo(
 
304
            self.get_url('child'), format=format)
 
305
        self.assertRaises(errors.NoRepositoryPresent,
 
306
                          branch.bzrdir.open_repository)
 
307
 
 
308
    def test_create_branch_and_repo_under_shared_force_new(self):
 
309
        # creating a branch and repo in a shared repo can be forced to 
 
310
        # make a new repo
 
311
        format = bzrdir.format_registry.make_bzrdir('knit')
 
312
        self.make_repository('.', shared=True, format=format)
 
313
        branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'),
 
314
                                                      force_new_repo=True,
 
315
                                                      format=format)
 
316
        branch.bzrdir.open_repository()
 
317
 
 
318
    def test_create_standalone_working_tree(self):
 
319
        format = SampleBzrDirFormat()
 
320
        # note this is deliberately readonly, as this failure should 
 
321
        # occur before any writes.
 
322
        self.assertRaises(errors.NotLocalUrl,
 
323
                          bzrdir.BzrDir.create_standalone_workingtree,
 
324
                          self.get_readonly_url(), format=format)
 
325
        tree = bzrdir.BzrDir.create_standalone_workingtree('.', 
 
326
                                                           format=format)
 
327
        self.assertEqual('A tree', tree)
 
328
 
 
329
    def test_create_standalone_working_tree_under_shared_repo(self):
 
330
        # create standalone working tree always makes a repo.
 
331
        format = bzrdir.format_registry.make_bzrdir('knit')
 
332
        self.make_repository('.', shared=True, format=format)
 
333
        # note this is deliberately readonly, as this failure should 
 
334
        # occur before any writes.
 
335
        self.assertRaises(errors.NotLocalUrl,
 
336
                          bzrdir.BzrDir.create_standalone_workingtree,
 
337
                          self.get_readonly_url('child'), format=format)
 
338
        tree = bzrdir.BzrDir.create_standalone_workingtree('child', 
 
339
            format=format)
 
340
        tree.bzrdir.open_repository()
 
341
 
 
342
    def test_create_branch_convenience(self):
 
343
        # outside a repo the default convenience output is a repo+branch_tree
 
344
        format = bzrdir.format_registry.make_bzrdir('knit')
 
345
        branch = bzrdir.BzrDir.create_branch_convenience('.', format=format)
 
346
        branch.bzrdir.open_workingtree()
 
347
        branch.bzrdir.open_repository()
 
348
 
 
349
    def test_create_branch_convenience_possible_transports(self):
 
350
        """Check that the optional 'possible_transports' is recognized"""
 
351
        format = bzrdir.format_registry.make_bzrdir('knit')
 
352
        t = self.get_transport()
 
353
        branch = bzrdir.BzrDir.create_branch_convenience(
 
354
            '.', format=format, possible_transports=[t])
 
355
        branch.bzrdir.open_workingtree()
 
356
        branch.bzrdir.open_repository()
 
357
 
 
358
    def test_create_branch_convenience_root(self):
 
359
        """Creating a branch at the root of a fs should work."""
 
360
        self.vfs_transport_factory = MemoryServer
 
361
        # outside a repo the default convenience output is a repo+branch_tree
 
362
        format = bzrdir.format_registry.make_bzrdir('knit')
 
363
        branch = bzrdir.BzrDir.create_branch_convenience(self.get_url(), 
 
364
                                                         format=format)
 
365
        self.assertRaises(errors.NoWorkingTree,
 
366
                          branch.bzrdir.open_workingtree)
 
367
        branch.bzrdir.open_repository()
 
368
 
 
369
    def test_create_branch_convenience_under_shared_repo(self):
 
370
        # inside a repo the default convenience output is a branch+ follow the
 
371
        # repo tree policy
 
372
        format = bzrdir.format_registry.make_bzrdir('knit')
 
373
        self.make_repository('.', shared=True, format=format)
 
374
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
375
            format=format)
 
376
        branch.bzrdir.open_workingtree()
 
377
        self.assertRaises(errors.NoRepositoryPresent,
 
378
                          branch.bzrdir.open_repository)
 
379
            
 
380
    def test_create_branch_convenience_under_shared_repo_force_no_tree(self):
 
381
        # inside a repo the default convenience output is a branch+ follow the
 
382
        # repo tree policy but we can override that
 
383
        format = bzrdir.format_registry.make_bzrdir('knit')
 
384
        self.make_repository('.', shared=True, format=format)
 
385
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
386
            force_new_tree=False, format=format)
 
387
        self.assertRaises(errors.NoWorkingTree,
 
388
                          branch.bzrdir.open_workingtree)
 
389
        self.assertRaises(errors.NoRepositoryPresent,
 
390
                          branch.bzrdir.open_repository)
 
391
            
 
392
    def test_create_branch_convenience_under_shared_repo_no_tree_policy(self):
 
393
        # inside a repo the default convenience output is a branch+ follow the
 
394
        # repo tree policy
 
395
        format = bzrdir.format_registry.make_bzrdir('knit')
 
396
        repo = self.make_repository('.', shared=True, format=format)
 
397
        repo.set_make_working_trees(False)
 
398
        branch = bzrdir.BzrDir.create_branch_convenience('child', 
 
399
                                                         format=format)
 
400
        self.assertRaises(errors.NoWorkingTree,
 
401
                          branch.bzrdir.open_workingtree)
 
402
        self.assertRaises(errors.NoRepositoryPresent,
 
403
                          branch.bzrdir.open_repository)
 
404
 
 
405
    def test_create_branch_convenience_under_shared_repo_no_tree_policy_force_tree(self):
 
406
        # inside a repo the default convenience output is a branch+ follow the
 
407
        # repo tree policy but we can override that
 
408
        format = bzrdir.format_registry.make_bzrdir('knit')
 
409
        repo = self.make_repository('.', shared=True, format=format)
 
410
        repo.set_make_working_trees(False)
 
411
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
412
            force_new_tree=True, format=format)
 
413
        branch.bzrdir.open_workingtree()
 
414
        self.assertRaises(errors.NoRepositoryPresent,
 
415
                          branch.bzrdir.open_repository)
 
416
 
 
417
    def test_create_branch_convenience_under_shared_repo_force_new_repo(self):
 
418
        # inside a repo the default convenience output is overridable to give
 
419
        # repo+branch+tree
 
420
        format = bzrdir.format_registry.make_bzrdir('knit')
 
421
        self.make_repository('.', shared=True, format=format)
 
422
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
423
            force_new_repo=True, format=format)
 
424
        branch.bzrdir.open_repository()
 
425
        branch.bzrdir.open_workingtree()
 
426
 
 
427
 
 
428
class TestRepositoryAcquisitionPolicy(TestCaseWithTransport):
 
429
 
 
430
    def test_acquire_repository_standalone(self):
 
431
        """The default acquisition policy should create a standalone branch."""
 
432
        my_bzrdir = self.make_bzrdir('.')
 
433
        repo_policy = my_bzrdir.determine_repository_policy()
 
434
        repo = repo_policy.acquire_repository()
 
435
        self.assertEqual(repo.bzrdir.root_transport.base,
 
436
                         my_bzrdir.root_transport.base)
 
437
        self.assertFalse(repo.is_shared())
 
438
 
 
439
 
 
440
    def test_determine_stacking_policy(self):
 
441
        parent_bzrdir = self.make_bzrdir('.')
 
442
        child_bzrdir = self.make_bzrdir('child')
 
443
        parent_bzrdir.get_config().set_default_stack_on('http://example.org')
 
444
        repo_policy = child_bzrdir.determine_repository_policy()
 
445
        self.assertEqual('http://example.org', repo_policy._stack_on)
 
446
 
 
447
    def test_determine_stacking_policy_relative(self):
 
448
        parent_bzrdir = self.make_bzrdir('.')
 
449
        child_bzrdir = self.make_bzrdir('child')
 
450
        parent_bzrdir.get_config().set_default_stack_on('child2')
 
451
        repo_policy = child_bzrdir.determine_repository_policy()
 
452
        self.assertEqual('child2', repo_policy._stack_on)
 
453
        self.assertEqual(parent_bzrdir.root_transport.base,
 
454
                         repo_policy._stack_on_pwd)
 
455
 
 
456
    def prepare_default_stacking(self, child_format='1.6'):
 
457
        parent_bzrdir = self.make_bzrdir('.')
 
458
        child_branch = self.make_branch('child', format=child_format)
 
459
        parent_bzrdir.get_config().set_default_stack_on(child_branch.base)
 
460
        new_child_transport = parent_bzrdir.transport.clone('child2')
 
461
        return child_branch, new_child_transport
 
462
 
 
463
    def test_clone_on_transport_obeys_stacking_policy(self):
 
464
        child_branch, new_child_transport = self.prepare_default_stacking()
 
465
        new_child = child_branch.bzrdir.clone_on_transport(new_child_transport)
 
466
        self.assertEqual(child_branch.base,
 
467
                         new_child.open_branch().get_stacked_on_url())
 
468
 
 
469
    def test_sprout_obeys_stacking_policy(self):
 
470
        child_branch, new_child_transport = self.prepare_default_stacking()
 
471
        new_child = child_branch.bzrdir.sprout(new_child_transport.base)
 
472
        self.assertEqual(child_branch.base,
 
473
                         new_child.open_branch().get_stacked_on_url())
 
474
 
 
475
    def test_clone_ignores_policy_for_unsupported_formats(self):
 
476
        child_branch, new_child_transport = self.prepare_default_stacking(
 
477
            child_format='pack-0.92')
 
478
        new_child = child_branch.bzrdir.clone_on_transport(new_child_transport)
 
479
        self.assertRaises(errors.UnstackableBranchFormat,
 
480
                          new_child.open_branch().get_stacked_on_url)
 
481
 
 
482
    def test_sprout_ignores_policy_for_unsupported_formats(self):
 
483
        child_branch, new_child_transport = self.prepare_default_stacking(
 
484
            child_format='pack-0.92')
 
485
        new_child = child_branch.bzrdir.sprout(new_child_transport.base)
 
486
        self.assertRaises(errors.UnstackableBranchFormat,
 
487
                          new_child.open_branch().get_stacked_on_url)
 
488
 
 
489
    def test_sprout_upgrades_format_if_stacked_specified(self):
 
490
        child_branch, new_child_transport = self.prepare_default_stacking(
 
491
            child_format='pack-0.92')
 
492
        new_child = child_branch.bzrdir.sprout(new_child_transport.base,
 
493
                                               stacked=True)
 
494
        self.assertEqual(child_branch.bzrdir.root_transport.base,
 
495
                         new_child.open_branch().get_stacked_on_url())
 
496
        repo = new_child.open_repository()
 
497
        self.assertTrue(repo._format.supports_external_lookups)
 
498
        self.assertFalse(repo.supports_rich_root())
 
499
 
 
500
    def test_clone_on_transport_upgrades_format_if_stacked_on_specified(self):
 
501
        child_branch, new_child_transport = self.prepare_default_stacking(
 
502
            child_format='pack-0.92')
 
503
        new_child = child_branch.bzrdir.clone_on_transport(new_child_transport,
 
504
            stacked_on=child_branch.bzrdir.root_transport.base)
 
505
        self.assertEqual(child_branch.bzrdir.root_transport.base,
 
506
                         new_child.open_branch().get_stacked_on_url())
 
507
        repo = new_child.open_repository()
 
508
        self.assertTrue(repo._format.supports_external_lookups)
 
509
        self.assertFalse(repo.supports_rich_root())
 
510
 
 
511
    def test_sprout_upgrades_to_rich_root_format_if_needed(self):
 
512
        child_branch, new_child_transport = self.prepare_default_stacking(
 
513
            child_format='rich-root-pack')
 
514
        new_child = child_branch.bzrdir.sprout(new_child_transport.base,
 
515
                                               stacked=True)
 
516
        repo = new_child.open_repository()
 
517
        self.assertTrue(repo._format.supports_external_lookups)
 
518
        self.assertTrue(repo.supports_rich_root())
 
519
 
 
520
    def test_add_fallback_repo_handles_absolute_urls(self):
 
521
        stack_on = self.make_branch('stack_on', format='1.6')
 
522
        repo = self.make_repository('repo', format='1.6')
 
523
        policy = bzrdir.UseExistingRepository(repo, stack_on.base)
 
524
        policy._add_fallback(repo)
 
525
 
 
526
    def test_add_fallback_repo_handles_relative_urls(self):
 
527
        stack_on = self.make_branch('stack_on', format='1.6')
 
528
        repo = self.make_repository('repo', format='1.6')
 
529
        policy = bzrdir.UseExistingRepository(repo, '.', stack_on.base)
 
530
        policy._add_fallback(repo)
 
531
 
 
532
    def test_configure_relative_branch_stacking_url(self):
 
533
        stack_on = self.make_branch('stack_on', format='1.6')
 
534
        stacked = self.make_branch('stack_on/stacked', format='1.6')
 
535
        policy = bzrdir.UseExistingRepository(stacked.repository,
 
536
            '.', stack_on.base)
 
537
        policy.configure_branch(stacked)
 
538
        self.assertEqual('..', stacked.get_stacked_on_url())
 
539
 
 
540
    def test_relative_branch_stacking_to_absolute(self):
 
541
        stack_on = self.make_branch('stack_on', format='1.6')
 
542
        stacked = self.make_branch('stack_on/stacked', format='1.6')
 
543
        policy = bzrdir.UseExistingRepository(stacked.repository,
 
544
            '.', self.get_readonly_url('stack_on'))
 
545
        policy.configure_branch(stacked)
 
546
        self.assertEqual(self.get_readonly_url('stack_on'),
 
547
                         stacked.get_stacked_on_url())
 
548
 
 
549
 
 
550
class ChrootedTests(TestCaseWithTransport):
 
551
    """A support class that provides readonly urls outside the local namespace.
 
552
 
 
553
    This is done by checking if self.transport_server is a MemoryServer. if it
 
554
    is then we are chrooted already, if it is not then an HttpServer is used
 
555
    for readonly urls.
 
556
    """
 
557
 
 
558
    def setUp(self):
 
559
        super(ChrootedTests, self).setUp()
 
560
        if not self.vfs_transport_factory == MemoryServer:
 
561
            self.transport_readonly_server = http_server.HttpServer
 
562
 
 
563
    def local_branch_path(self, branch):
 
564
         return os.path.realpath(urlutils.local_path_from_url(branch.base))
 
565
 
 
566
    def test_open_containing(self):
 
567
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
 
568
                          self.get_readonly_url(''))
 
569
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
 
570
                          self.get_readonly_url('g/p/q'))
 
571
        control = bzrdir.BzrDir.create(self.get_url())
 
572
        branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url(''))
 
573
        self.assertEqual('', relpath)
 
574
        branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url('g/p/q'))
 
575
        self.assertEqual('g/p/q', relpath)
 
576
 
 
577
    def test_open_containing_tree_branch_or_repository_empty(self):
 
578
        self.assertRaises(errors.NotBranchError,
 
579
            bzrdir.BzrDir.open_containing_tree_branch_or_repository,
 
580
            self.get_readonly_url(''))
 
581
 
 
582
    def test_open_containing_tree_branch_or_repository_all(self):
 
583
        self.make_branch_and_tree('topdir')
 
584
        tree, branch, repo, relpath = \
 
585
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
586
                'topdir/foo')
 
587
        self.assertEqual(os.path.realpath('topdir'),
 
588
                         os.path.realpath(tree.basedir))
 
589
        self.assertEqual(os.path.realpath('topdir'),
 
590
                         self.local_branch_path(branch))
 
591
        self.assertEqual(
 
592
            osutils.realpath(os.path.join('topdir', '.bzr', 'repository')),
 
593
            repo.bzrdir.transport.local_abspath('repository'))
 
594
        self.assertEqual(relpath, 'foo')
 
595
 
 
596
    def test_open_containing_tree_branch_or_repository_no_tree(self):
 
597
        self.make_branch('branch')
 
598
        tree, branch, repo, relpath = \
 
599
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
600
                'branch/foo')
 
601
        self.assertEqual(tree, None)
 
602
        self.assertEqual(os.path.realpath('branch'),
 
603
                         self.local_branch_path(branch))
 
604
        self.assertEqual(
 
605
            osutils.realpath(os.path.join('branch', '.bzr', 'repository')),
 
606
            repo.bzrdir.transport.local_abspath('repository'))
 
607
        self.assertEqual(relpath, 'foo')
 
608
 
 
609
    def test_open_containing_tree_branch_or_repository_repo(self):
 
610
        self.make_repository('repo')
 
611
        tree, branch, repo, relpath = \
 
612
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
613
                'repo')
 
614
        self.assertEqual(tree, None)
 
615
        self.assertEqual(branch, None)
 
616
        self.assertEqual(
 
617
            osutils.realpath(os.path.join('repo', '.bzr', 'repository')),
 
618
            repo.bzrdir.transport.local_abspath('repository'))
 
619
        self.assertEqual(relpath, '')
 
620
 
 
621
    def test_open_containing_tree_branch_or_repository_shared_repo(self):
 
622
        self.make_repository('shared', shared=True)
 
623
        bzrdir.BzrDir.create_branch_convenience('shared/branch',
 
624
                                                force_new_tree=False)
 
625
        tree, branch, repo, relpath = \
 
626
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
627
                'shared/branch')
 
628
        self.assertEqual(tree, None)
 
629
        self.assertEqual(os.path.realpath('shared/branch'),
 
630
                         self.local_branch_path(branch))
 
631
        self.assertEqual(
 
632
            osutils.realpath(os.path.join('shared', '.bzr', 'repository')),
 
633
            repo.bzrdir.transport.local_abspath('repository'))
 
634
        self.assertEqual(relpath, '')
 
635
 
 
636
    def test_open_containing_tree_branch_or_repository_branch_subdir(self):
 
637
        self.make_branch_and_tree('foo')
 
638
        self.build_tree(['foo/bar/'])
 
639
        tree, branch, repo, relpath = \
 
640
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
641
                'foo/bar')
 
642
        self.assertEqual(os.path.realpath('foo'),
 
643
                         os.path.realpath(tree.basedir))
 
644
        self.assertEqual(os.path.realpath('foo'),
 
645
                         self.local_branch_path(branch))
 
646
        self.assertEqual(
 
647
            osutils.realpath(os.path.join('foo', '.bzr', 'repository')),
 
648
            repo.bzrdir.transport.local_abspath('repository'))
 
649
        self.assertEqual(relpath, 'bar')
 
650
 
 
651
    def test_open_containing_tree_branch_or_repository_repo_subdir(self):
 
652
        self.make_repository('bar')
 
653
        self.build_tree(['bar/baz/'])
 
654
        tree, branch, repo, relpath = \
 
655
            bzrdir.BzrDir.open_containing_tree_branch_or_repository(
 
656
                'bar/baz')
 
657
        self.assertEqual(tree, None)
 
658
        self.assertEqual(branch, None)
 
659
        self.assertEqual(
 
660
            osutils.realpath(os.path.join('bar', '.bzr', 'repository')),
 
661
            repo.bzrdir.transport.local_abspath('repository'))
 
662
        self.assertEqual(relpath, 'baz')
 
663
 
 
664
    def test_open_containing_from_transport(self):
 
665
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
 
666
                          get_transport(self.get_readonly_url('')))
 
667
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
 
668
                          get_transport(self.get_readonly_url('g/p/q')))
 
669
        control = bzrdir.BzrDir.create(self.get_url())
 
670
        branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
 
671
            get_transport(self.get_readonly_url('')))
 
672
        self.assertEqual('', relpath)
 
673
        branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
 
674
            get_transport(self.get_readonly_url('g/p/q')))
 
675
        self.assertEqual('g/p/q', relpath)
 
676
 
 
677
    def test_open_containing_tree_or_branch(self):
 
678
        self.make_branch_and_tree('topdir')
 
679
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
680
            'topdir/foo')
 
681
        self.assertEqual(os.path.realpath('topdir'),
 
682
                         os.path.realpath(tree.basedir))
 
683
        self.assertEqual(os.path.realpath('topdir'),
 
684
                         self.local_branch_path(branch))
 
685
        self.assertIs(tree.bzrdir, branch.bzrdir)
 
686
        self.assertEqual('foo', relpath)
 
687
        # opening from non-local should not return the tree
 
688
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
689
            self.get_readonly_url('topdir/foo'))
 
690
        self.assertEqual(None, tree)
 
691
        self.assertEqual('foo', relpath)
 
692
        # without a tree:
 
693
        self.make_branch('topdir/foo')
 
694
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
695
            'topdir/foo')
 
696
        self.assertIs(tree, None)
 
697
        self.assertEqual(os.path.realpath('topdir/foo'),
 
698
                         self.local_branch_path(branch))
 
699
        self.assertEqual('', relpath)
 
700
 
 
701
    def test_open_tree_or_branch(self):
 
702
        self.make_branch_and_tree('topdir')
 
703
        tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir')
 
704
        self.assertEqual(os.path.realpath('topdir'),
 
705
                         os.path.realpath(tree.basedir))
 
706
        self.assertEqual(os.path.realpath('topdir'),
 
707
                         self.local_branch_path(branch))
 
708
        self.assertIs(tree.bzrdir, branch.bzrdir)
 
709
        # opening from non-local should not return the tree
 
710
        tree, branch = bzrdir.BzrDir.open_tree_or_branch(
 
711
            self.get_readonly_url('topdir'))
 
712
        self.assertEqual(None, tree)
 
713
        # without a tree:
 
714
        self.make_branch('topdir/foo')
 
715
        tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir/foo')
 
716
        self.assertIs(tree, None)
 
717
        self.assertEqual(os.path.realpath('topdir/foo'),
 
718
                         self.local_branch_path(branch))
 
719
 
 
720
    def test_open_from_transport(self):
 
721
        # transport pointing at bzrdir should give a bzrdir with root transport
 
722
        # set to the given transport
 
723
        control = bzrdir.BzrDir.create(self.get_url())
 
724
        transport = get_transport(self.get_url())
 
725
        opened_bzrdir = bzrdir.BzrDir.open_from_transport(transport)
 
726
        self.assertEqual(transport.base, opened_bzrdir.root_transport.base)
 
727
        self.assertIsInstance(opened_bzrdir, bzrdir.BzrDir)
 
728
        
 
729
    def test_open_from_transport_no_bzrdir(self):
 
730
        transport = get_transport(self.get_url())
 
731
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport,
 
732
                          transport)
 
733
 
 
734
    def test_open_from_transport_bzrdir_in_parent(self):
 
735
        control = bzrdir.BzrDir.create(self.get_url())
 
736
        transport = get_transport(self.get_url())
 
737
        transport.mkdir('subdir')
 
738
        transport = transport.clone('subdir')
 
739
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport,
 
740
                          transport)
 
741
 
 
742
    def test_sprout_recursive(self):
 
743
        tree = self.make_branch_and_tree('tree1', format='dirstate-with-subtree')
 
744
        sub_tree = self.make_branch_and_tree('tree1/subtree',
 
745
            format='dirstate-with-subtree')
 
746
        tree.add_reference(sub_tree)
 
747
        self.build_tree(['tree1/subtree/file'])
 
748
        sub_tree.add('file')
 
749
        tree.commit('Initial commit')
 
750
        tree.bzrdir.sprout('tree2')
 
751
        self.failUnlessExists('tree2/subtree/file')
 
752
 
 
753
    def test_cloning_metadir(self):
 
754
        """Ensure that cloning metadir is suitable"""
 
755
        bzrdir = self.make_bzrdir('bzrdir')
 
756
        bzrdir.cloning_metadir()
 
757
        branch = self.make_branch('branch', format='knit')
 
758
        format = branch.bzrdir.cloning_metadir()
 
759
        self.assertIsInstance(format.workingtree_format,
 
760
            workingtree.WorkingTreeFormat3)
 
761
 
 
762
    def test_sprout_recursive_treeless(self):
 
763
        tree = self.make_branch_and_tree('tree1',
 
764
            format='dirstate-with-subtree')
 
765
        sub_tree = self.make_branch_and_tree('tree1/subtree',
 
766
            format='dirstate-with-subtree')
 
767
        tree.add_reference(sub_tree)
 
768
        self.build_tree(['tree1/subtree/file'])
 
769
        sub_tree.add('file')
 
770
        tree.commit('Initial commit')
 
771
        tree.bzrdir.destroy_workingtree()
 
772
        repo = self.make_repository('repo', shared=True,
 
773
            format='dirstate-with-subtree')
 
774
        repo.set_make_working_trees(False)
 
775
        tree.bzrdir.sprout('repo/tree2')
 
776
        self.failUnlessExists('repo/tree2/subtree')
 
777
        self.failIfExists('repo/tree2/subtree/file')
 
778
 
 
779
    def make_foo_bar_baz(self):
 
780
        foo = bzrdir.BzrDir.create_branch_convenience('foo').bzrdir
 
781
        bar = self.make_branch('foo/bar').bzrdir
 
782
        baz = self.make_branch('baz').bzrdir
 
783
        return foo, bar, baz
 
784
 
 
785
    def test_find_bzrdirs(self):
 
786
        foo, bar, baz = self.make_foo_bar_baz()
 
787
        transport = get_transport(self.get_url())
 
788
        self.assertEqualBzrdirs([baz, foo, bar],
 
789
                                bzrdir.BzrDir.find_bzrdirs(transport))
 
790
 
 
791
    def test_find_bzrdirs_list_current(self):
 
792
        def list_current(transport):
 
793
            return [s for s in transport.list_dir('') if s != 'baz']
 
794
 
 
795
        foo, bar, baz = self.make_foo_bar_baz()
 
796
        transport = get_transport(self.get_url())
 
797
        self.assertEqualBzrdirs([foo, bar],
 
798
                                bzrdir.BzrDir.find_bzrdirs(transport,
 
799
                                    list_current=list_current))
 
800
 
 
801
 
 
802
    def test_find_bzrdirs_evaluate(self):
 
803
        def evaluate(bzrdir):
 
804
            try:
 
805
                repo = bzrdir.open_repository()
 
806
            except NoRepositoryPresent:
 
807
                return True, bzrdir.root_transport.base
 
808
            else:
 
809
                return False, bzrdir.root_transport.base
 
810
 
 
811
        foo, bar, baz = self.make_foo_bar_baz()
 
812
        transport = get_transport(self.get_url())
 
813
        self.assertEqual([baz.root_transport.base, foo.root_transport.base],
 
814
                         list(bzrdir.BzrDir.find_bzrdirs(transport,
 
815
                                                         evaluate=evaluate)))
 
816
 
 
817
    def assertEqualBzrdirs(self, first, second):
 
818
        first = list(first)
 
819
        second = list(second)
 
820
        self.assertEqual(len(first), len(second))
 
821
        for x, y in zip(first, second):
 
822
            self.assertEqual(x.root_transport.base, y.root_transport.base)
 
823
 
 
824
    def test_find_branches(self):
 
825
        root = self.make_repository('', shared=True)
 
826
        foo, bar, baz = self.make_foo_bar_baz()
 
827
        qux = self.make_bzrdir('foo/qux')
 
828
        transport = get_transport(self.get_url())
 
829
        branches = bzrdir.BzrDir.find_branches(transport)
 
830
        self.assertEqual(baz.root_transport.base, branches[0].base)
 
831
        self.assertEqual(foo.root_transport.base, branches[1].base)
 
832
        self.assertEqual(bar.root_transport.base, branches[2].base)
 
833
 
 
834
        # ensure this works without a top-level repo
 
835
        branches = bzrdir.BzrDir.find_branches(transport.clone('foo'))
 
836
        self.assertEqual(foo.root_transport.base, branches[0].base)
 
837
        self.assertEqual(bar.root_transport.base, branches[1].base)
 
838
 
 
839
 
 
840
class TestMeta1DirFormat(TestCaseWithTransport):
 
841
    """Tests specific to the meta1 dir format."""
 
842
 
 
843
    def test_right_base_dirs(self):
 
844
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
845
        t = dir.transport
 
846
        branch_base = t.clone('branch').base
 
847
        self.assertEqual(branch_base, dir.get_branch_transport(None).base)
 
848
        self.assertEqual(branch_base,
 
849
                         dir.get_branch_transport(bzrlib.branch.BzrBranchFormat5()).base)
 
850
        repository_base = t.clone('repository').base
 
851
        self.assertEqual(repository_base, dir.get_repository_transport(None).base)
 
852
        self.assertEqual(repository_base,
 
853
                         dir.get_repository_transport(weaverepo.RepositoryFormat7()).base)
 
854
        checkout_base = t.clone('checkout').base
 
855
        self.assertEqual(checkout_base, dir.get_workingtree_transport(None).base)
 
856
        self.assertEqual(checkout_base,
 
857
                         dir.get_workingtree_transport(workingtree.WorkingTreeFormat3()).base)
 
858
 
 
859
    def test_meta1dir_uses_lockdir(self):
 
860
        """Meta1 format uses a LockDir to guard the whole directory, not a file."""
 
861
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
862
        t = dir.transport
 
863
        self.assertIsDirectory('branch-lock', t)
 
864
 
 
865
    def test_comparison(self):
 
866
        """Equality and inequality behave properly.
 
867
 
 
868
        Metadirs should compare equal iff they have the same repo, branch and
 
869
        tree formats.
 
870
        """
 
871
        mydir = bzrdir.format_registry.make_bzrdir('knit')
 
872
        self.assertEqual(mydir, mydir)
 
873
        self.assertFalse(mydir != mydir)
 
874
        otherdir = bzrdir.format_registry.make_bzrdir('knit')
 
875
        self.assertEqual(otherdir, mydir)
 
876
        self.assertFalse(otherdir != mydir)
 
877
        otherdir2 = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
 
878
        self.assertNotEqual(otherdir2, mydir)
 
879
        self.assertFalse(otherdir2 == mydir)
 
880
 
 
881
    def test_needs_conversion_different_working_tree(self):
 
882
        # meta1dirs need an conversion if any element is not the default.
 
883
        new_format = bzrdir.format_registry.make_bzrdir('dirstate')
 
884
        tree = self.make_branch_and_tree('tree', format='knit')
 
885
        self.assertTrue(tree.bzrdir.needs_format_conversion(
 
886
            new_format))
 
887
 
 
888
 
 
889
class TestFormat5(TestCaseWithTransport):
 
890
    """Tests specific to the version 5 bzrdir format."""
 
891
 
 
892
    def test_same_lockfiles_between_tree_repo_branch(self):
 
893
        # this checks that only a single lockfiles instance is created 
 
894
        # for format 5 objects
 
895
        dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
 
896
        def check_dir_components_use_same_lock(dir):
 
897
            ctrl_1 = dir.open_repository().control_files
 
898
            ctrl_2 = dir.open_branch().control_files
 
899
            ctrl_3 = dir.open_workingtree()._control_files
 
900
            self.assertTrue(ctrl_1 is ctrl_2)
 
901
            self.assertTrue(ctrl_2 is ctrl_3)
 
902
        check_dir_components_use_same_lock(dir)
 
903
        # and if we open it normally.
 
904
        dir = bzrdir.BzrDir.open(self.get_url())
 
905
        check_dir_components_use_same_lock(dir)
 
906
    
 
907
    def test_can_convert(self):
 
908
        # format 5 dirs are convertable
 
909
        dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
 
910
        self.assertTrue(dir.can_convert_format())
 
911
    
 
912
    def test_needs_conversion(self):
 
913
        # format 5 dirs need a conversion if they are not the default,
 
914
        # and they aren't
 
915
        dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
 
916
        # don't need to convert it to itself
 
917
        self.assertFalse(dir.needs_format_conversion(bzrdir.BzrDirFormat5()))
 
918
        # do need to convert it to the current default
 
919
        self.assertTrue(dir.needs_format_conversion(
 
920
            bzrdir.BzrDirFormat.get_default_format()))
 
921
 
 
922
 
 
923
class TestFormat6(TestCaseWithTransport):
 
924
    """Tests specific to the version 6 bzrdir format."""
 
925
 
 
926
    def test_same_lockfiles_between_tree_repo_branch(self):
 
927
        # this checks that only a single lockfiles instance is created 
 
928
        # for format 6 objects
 
929
        dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
930
        def check_dir_components_use_same_lock(dir):
 
931
            ctrl_1 = dir.open_repository().control_files
 
932
            ctrl_2 = dir.open_branch().control_files
 
933
            ctrl_3 = dir.open_workingtree()._control_files
 
934
            self.assertTrue(ctrl_1 is ctrl_2)
 
935
            self.assertTrue(ctrl_2 is ctrl_3)
 
936
        check_dir_components_use_same_lock(dir)
 
937
        # and if we open it normally.
 
938
        dir = bzrdir.BzrDir.open(self.get_url())
 
939
        check_dir_components_use_same_lock(dir)
 
940
    
 
941
    def test_can_convert(self):
 
942
        # format 6 dirs are convertable
 
943
        dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
944
        self.assertTrue(dir.can_convert_format())
 
945
    
 
946
    def test_needs_conversion(self):
 
947
        # format 6 dirs need an conversion if they are not the default.
 
948
        dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
949
        self.assertTrue(dir.needs_format_conversion(
 
950
            bzrdir.BzrDirFormat.get_default_format()))
 
951
 
 
952
 
 
953
class NotBzrDir(bzrlib.bzrdir.BzrDir):
 
954
    """A non .bzr based control directory."""
 
955
 
 
956
    def __init__(self, transport, format):
 
957
        self._format = format
 
958
        self.root_transport = transport
 
959
        self.transport = transport.clone('.not')
 
960
 
 
961
 
 
962
class NotBzrDirFormat(bzrlib.bzrdir.BzrDirFormat):
 
963
    """A test class representing any non-.bzr based disk format."""
 
964
 
 
965
    def initialize_on_transport(self, transport):
 
966
        """Initialize a new .not dir in the base directory of a Transport."""
 
967
        transport.mkdir('.not')
 
968
        return self.open(transport)
 
969
 
 
970
    def open(self, transport):
 
971
        """Open this directory."""
 
972
        return NotBzrDir(transport, self)
 
973
 
 
974
    @classmethod
 
975
    def _known_formats(self):
 
976
        return set([NotBzrDirFormat()])
 
977
 
 
978
    @classmethod
 
979
    def probe_transport(self, transport):
 
980
        """Our format is present if the transport ends in '.not/'."""
 
981
        if transport.has('.not'):
 
982
            return NotBzrDirFormat()
 
983
 
 
984
 
 
985
class TestNotBzrDir(TestCaseWithTransport):
 
986
    """Tests for using the bzrdir api with a non .bzr based disk format.
 
987
    
 
988
    If/when one of these is in the core, we can let the implementation tests
 
989
    verify this works.
 
990
    """
 
991
 
 
992
    def test_create_and_find_format(self):
 
993
        # create a .notbzr dir 
 
994
        format = NotBzrDirFormat()
 
995
        dir = format.initialize(self.get_url())
 
996
        self.assertIsInstance(dir, NotBzrDir)
 
997
        # now probe for it.
 
998
        bzrlib.bzrdir.BzrDirFormat.register_control_format(format)
 
999
        try:
 
1000
            found = bzrlib.bzrdir.BzrDirFormat.find_format(
 
1001
                get_transport(self.get_url()))
 
1002
            self.assertIsInstance(found, NotBzrDirFormat)
 
1003
        finally:
 
1004
            bzrlib.bzrdir.BzrDirFormat.unregister_control_format(format)
 
1005
 
 
1006
    def test_included_in_known_formats(self):
 
1007
        bzrlib.bzrdir.BzrDirFormat.register_control_format(NotBzrDirFormat)
 
1008
        try:
 
1009
            formats = bzrlib.bzrdir.BzrDirFormat.known_formats()
 
1010
            for format in formats:
 
1011
                if isinstance(format, NotBzrDirFormat):
 
1012
                    return
 
1013
            self.fail("No NotBzrDirFormat in %s" % formats)
 
1014
        finally:
 
1015
            bzrlib.bzrdir.BzrDirFormat.unregister_control_format(NotBzrDirFormat)
 
1016
 
 
1017
 
 
1018
class NonLocalTests(TestCaseWithTransport):
 
1019
    """Tests for bzrdir static behaviour on non local paths."""
 
1020
 
 
1021
    def setUp(self):
 
1022
        super(NonLocalTests, self).setUp()
 
1023
        self.vfs_transport_factory = MemoryServer
 
1024
    
 
1025
    def test_create_branch_convenience(self):
 
1026
        # outside a repo the default convenience output is a repo+branch_tree
 
1027
        format = bzrdir.format_registry.make_bzrdir('knit')
 
1028
        branch = bzrdir.BzrDir.create_branch_convenience(
 
1029
            self.get_url('foo'), format=format)
 
1030
        self.assertRaises(errors.NoWorkingTree,
 
1031
                          branch.bzrdir.open_workingtree)
 
1032
        branch.bzrdir.open_repository()
 
1033
 
 
1034
    def test_create_branch_convenience_force_tree_not_local_fails(self):
 
1035
        # outside a repo the default convenience output is a repo+branch_tree
 
1036
        format = bzrdir.format_registry.make_bzrdir('knit')
 
1037
        self.assertRaises(errors.NotLocalUrl,
 
1038
            bzrdir.BzrDir.create_branch_convenience,
 
1039
            self.get_url('foo'),
 
1040
            force_new_tree=True,
 
1041
            format=format)
 
1042
        t = get_transport(self.get_url('.'))
 
1043
        self.assertFalse(t.has('foo'))
 
1044
 
 
1045
    def test_clone(self):
 
1046
        # clone into a nonlocal path works
 
1047
        format = bzrdir.format_registry.make_bzrdir('knit')
 
1048
        branch = bzrdir.BzrDir.create_branch_convenience('local',
 
1049
                                                         format=format)
 
1050
        branch.bzrdir.open_workingtree()
 
1051
        result = branch.bzrdir.clone(self.get_url('remote'))
 
1052
        self.assertRaises(errors.NoWorkingTree,
 
1053
                          result.open_workingtree)
 
1054
        result.open_branch()
 
1055
        result.open_repository()
 
1056
 
 
1057
    def test_checkout_metadir(self):
 
1058
        # checkout_metadir has reasonable working tree format even when no
 
1059
        # working tree is present
 
1060
        self.make_branch('branch-knit2', format='dirstate-with-subtree')
 
1061
        my_bzrdir = bzrdir.BzrDir.open(self.get_url('branch-knit2'))
 
1062
        checkout_format = my_bzrdir.checkout_metadir()
 
1063
        self.assertIsInstance(checkout_format.workingtree_format,
 
1064
                              workingtree.WorkingTreeFormat3)
 
1065
 
 
1066
 
 
1067
class TestHTTPRedirections(object):
 
1068
    """Test redirection between two http servers.
 
1069
 
 
1070
    This MUST be used by daughter classes that also inherit from
 
1071
    TestCaseWithTwoWebservers.
 
1072
 
 
1073
    We can't inherit directly from TestCaseWithTwoWebservers or the
 
1074
    test framework will try to create an instance which cannot
 
1075
    run, its implementation being incomplete. 
 
1076
    """
 
1077
 
 
1078
    def create_transport_readonly_server(self):
 
1079
        return http_utils.HTTPServerRedirecting()
 
1080
 
 
1081
    def create_transport_secondary_server(self):
 
1082
        return http_utils.HTTPServerRedirecting()
 
1083
 
 
1084
    def setUp(self):
 
1085
        super(TestHTTPRedirections, self).setUp()
 
1086
        # The redirections will point to the new server
 
1087
        self.new_server = self.get_readonly_server()
 
1088
        # The requests to the old server will be redirected
 
1089
        self.old_server = self.get_secondary_server()
 
1090
        # Configure the redirections
 
1091
        self.old_server.redirect_to(self.new_server.host, self.new_server.port)
 
1092
 
 
1093
    def test_loop(self):
 
1094
        # Both servers redirect to each other creating a loop
 
1095
        self.new_server.redirect_to(self.old_server.host, self.old_server.port)
 
1096
        # Starting from either server should loop
 
1097
        old_url = self._qualified_url(self.old_server.host,
 
1098
                                      self.old_server.port)
 
1099
        oldt = self._transport(old_url)
 
1100
        self.assertRaises(errors.NotBranchError,
 
1101
                          bzrdir.BzrDir.open_from_transport, oldt)
 
1102
        new_url = self._qualified_url(self.new_server.host,
 
1103
                                      self.new_server.port)
 
1104
        newt = self._transport(new_url)
 
1105
        self.assertRaises(errors.NotBranchError,
 
1106
                          bzrdir.BzrDir.open_from_transport, newt)
 
1107
 
 
1108
    def test_qualifier_preserved(self):
 
1109
        wt = self.make_branch_and_tree('branch')
 
1110
        old_url = self._qualified_url(self.old_server.host,
 
1111
                                      self.old_server.port)
 
1112
        start = self._transport(old_url).clone('branch')
 
1113
        bdir = bzrdir.BzrDir.open_from_transport(start)
 
1114
        # Redirection should preserve the qualifier, hence the transport class
 
1115
        # itself.
 
1116
        self.assertIsInstance(bdir.root_transport, type(start))
 
1117
 
 
1118
 
 
1119
class TestHTTPRedirections_urllib(TestHTTPRedirections,
 
1120
                                  http_utils.TestCaseWithTwoWebservers):
 
1121
    """Tests redirections for urllib implementation"""
 
1122
 
 
1123
    _transport = HttpTransport_urllib
 
1124
 
 
1125
    def _qualified_url(self, host, port):
 
1126
        return 'http+urllib://%s:%s' % (host, port)
 
1127
 
 
1128
 
 
1129
 
 
1130
class TestHTTPRedirections_pycurl(TestWithTransport_pycurl,
 
1131
                                  TestHTTPRedirections,
 
1132
                                  http_utils.TestCaseWithTwoWebservers):
 
1133
    """Tests redirections for pycurl implementation"""
 
1134
 
 
1135
    def _qualified_url(self, host, port):
 
1136
        return 'http+pycurl://%s:%s' % (host, port)
 
1137
 
 
1138
 
 
1139
class TestHTTPRedirections_nosmart(TestHTTPRedirections,
 
1140
                                  http_utils.TestCaseWithTwoWebservers):
 
1141
    """Tests redirections for the nosmart decorator"""
 
1142
 
 
1143
    _transport = NoSmartTransportDecorator
 
1144
 
 
1145
    def _qualified_url(self, host, port):
 
1146
        return 'nosmart+http://%s:%s' % (host, port)
 
1147
 
 
1148
 
 
1149
class TestHTTPRedirections_readonly(TestHTTPRedirections,
 
1150
                                    http_utils.TestCaseWithTwoWebservers):
 
1151
    """Tests redirections for readonly decoratror"""
 
1152
 
 
1153
    _transport = ReadonlyTransportDecorator
 
1154
 
 
1155
    def _qualified_url(self, host, port):
 
1156
        return 'readonly+http://%s:%s' % (host, port)
 
1157
 
 
1158
 
 
1159
class TestDotBzrHidden(TestCaseWithTransport):
 
1160
 
 
1161
    ls = ['ls']
 
1162
    if sys.platform == 'win32':
 
1163
        ls = [os.environ['COMSPEC'], '/C', 'dir', '/B']
 
1164
 
 
1165
    def get_ls(self):
 
1166
        f = subprocess.Popen(self.ls, stdout=subprocess.PIPE,
 
1167
            stderr=subprocess.PIPE)
 
1168
        out, err = f.communicate()
 
1169
        self.assertEqual(0, f.returncode, 'Calling %s failed: %s'
 
1170
                         % (self.ls, err))
 
1171
        return out.splitlines()
 
1172
 
 
1173
    def test_dot_bzr_hidden(self):
 
1174
        if sys.platform == 'win32' and not win32utils.has_win32file:
 
1175
            raise TestSkipped('unable to make file hidden without pywin32 library')
 
1176
        b = bzrdir.BzrDir.create('.')
 
1177
        self.build_tree(['a'])
 
1178
        self.assertEquals(['a'], self.get_ls())
 
1179
 
 
1180
    def test_dot_bzr_hidden_with_url(self):
 
1181
        if sys.platform == 'win32' and not win32utils.has_win32file:
 
1182
            raise TestSkipped('unable to make file hidden without pywin32 library')
 
1183
        b = bzrdir.BzrDir.create(urlutils.local_path_to_url('.'))
 
1184
        self.build_tree(['a'])
 
1185
        self.assertEquals(['a'], self.get_ls())
 
1186
 
 
1187
 
 
1188
class _TestBzrDirFormat(bzrdir.BzrDirMetaFormat1):
 
1189
    """Test BzrDirFormat implementation for TestBzrDirSprout."""
 
1190
 
 
1191
    def _open(self, transport):
 
1192
        return _TestBzrDir(transport, self)
 
1193
 
 
1194
 
 
1195
class _TestBzrDir(bzrdir.BzrDirMeta1):
 
1196
    """Test BzrDir implementation for TestBzrDirSprout.
 
1197
    
 
1198
    When created a _TestBzrDir already has repository and a branch.  The branch
 
1199
    is a test double as well.
 
1200
    """
 
1201
 
 
1202
    def __init__(self, *args, **kwargs):
 
1203
        super(_TestBzrDir, self).__init__(*args, **kwargs)
 
1204
        self.test_branch = _TestBranch()
 
1205
        self.test_branch.repository = self.create_repository()
 
1206
 
 
1207
    def open_branch(self, unsupported=False):
 
1208
        return self.test_branch
 
1209
 
 
1210
    def cloning_metadir(self, require_stacking=False):
 
1211
        return _TestBzrDirFormat()
 
1212
 
 
1213
 
 
1214
class _TestBranch(bzrlib.branch.Branch):
 
1215
    """Test Branch implementation for TestBzrDirSprout."""
 
1216
 
 
1217
    def __init__(self, *args, **kwargs):
 
1218
        super(_TestBranch, self).__init__(*args, **kwargs)
 
1219
        self.calls = []
 
1220
        self._parent = None
 
1221
 
 
1222
    def sprout(self, *args, **kwargs):
 
1223
        self.calls.append('sprout')
 
1224
        return _TestBranch()
 
1225
 
 
1226
    def copy_content_into(self, destination, revision_id=None):
 
1227
        self.calls.append('copy_content_into')
 
1228
 
 
1229
    def get_parent(self):
 
1230
        return self._parent
 
1231
 
 
1232
    def set_parent(self, parent):
 
1233
        self._parent = parent
 
1234
 
 
1235
 
 
1236
class TestBzrDirSprout(TestCaseWithMemoryTransport):
 
1237
 
 
1238
    def test_sprout_uses_branch_sprout(self):
 
1239
        """BzrDir.sprout calls Branch.sprout.
 
1240
 
 
1241
        Usually, BzrDir.sprout should delegate to the branch's sprout method
 
1242
        for part of the work.  This allows the source branch to control the
 
1243
        choice of format for the new branch.
 
1244
        
 
1245
        There are exceptions, but this tests avoids them:
 
1246
          - if there's no branch in the source bzrdir,
 
1247
          - or if the stacking has been requested and the format needs to be
 
1248
            overridden to satisfy that.
 
1249
        """
 
1250
        # Make an instrumented bzrdir.
 
1251
        t = self.get_transport('source')
 
1252
        t.ensure_base()
 
1253
        source_bzrdir = _TestBzrDirFormat().initialize_on_transport(t)
 
1254
        # The instrumented bzrdir has a test_branch attribute that logs calls
 
1255
        # made to the branch contained in that bzrdir.  Initially the test
 
1256
        # branch exists but no calls have been made to it.
 
1257
        self.assertEqual([], source_bzrdir.test_branch.calls)
 
1258
 
 
1259
        # Sprout the bzrdir
 
1260
        target_url = self.get_url('target')
 
1261
        result = source_bzrdir.sprout(target_url, recurse='no')
 
1262
 
 
1263
        # The bzrdir called the branch's sprout method.
 
1264
        self.assertSubset(['sprout'], source_bzrdir.test_branch.calls)
 
1265
 
 
1266
    def test_sprout_parent(self):
 
1267
        grandparent_tree = self.make_branch('grandparent')
 
1268
        parent = grandparent_tree.bzrdir.sprout('parent').open_branch()
 
1269
        branch_tree = parent.bzrdir.sprout('branch').open_branch()
 
1270
        self.assertContainsRe(branch_tree.get_parent(), '/parent/$')