~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_bzrdir.py

  • Committer: Alexander Belchenko
  • Date: 2007-04-14 12:17:31 UTC
  • mto: This revision was merged to the branch mainline in revision 2422.
  • Revision ID: bialix@ukr.net-20070414121731-jtc76rfulndihkh3
workingtree_implementations: make usage of symlinks optional

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.path
 
23
from StringIO import StringIO
 
24
 
 
25
from bzrlib import (
 
26
    bzrdir,
 
27
    errors,
 
28
    help_topics,
 
29
    repository,
 
30
    symbol_versioning,
 
31
    urlutils,
 
32
    workingtree,
 
33
    )
 
34
import bzrlib.branch
 
35
from bzrlib.errors import (NotBranchError,
 
36
                           UnknownFormatError,
 
37
                           UnsupportedFormatError,
 
38
                           )
 
39
from bzrlib.tests import (
 
40
    TestCase,
 
41
    TestCaseWithTransport,
 
42
    test_sftp_transport
 
43
    )
 
44
from bzrlib.tests.HttpServer import HttpServer
 
45
from bzrlib.tests.HTTPTestUtil import (
 
46
    TestCaseWithTwoWebservers,
 
47
    HTTPServerRedirecting,
 
48
    )
 
49
from bzrlib.tests.test_http import TestWithTransport_pycurl
 
50
from bzrlib.transport import get_transport
 
51
from bzrlib.transport.http._urllib import HttpTransport_urllib
 
52
from bzrlib.transport.memory import MemoryServer
 
53
from bzrlib.repofmt import knitrepo, weaverepo
 
54
 
 
55
 
 
56
class TestDefaultFormat(TestCase):
 
57
 
 
58
    def test_get_set_default_format(self):
 
59
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
60
        # default is BzrDirFormat6
 
61
        self.failUnless(isinstance(old_format, bzrdir.BzrDirMetaFormat1))
 
62
        self.applyDeprecated(symbol_versioning.zero_fourteen, 
 
63
                             bzrdir.BzrDirFormat.set_default_format, 
 
64
                             SampleBzrDirFormat())
 
65
        # creating a bzr dir should now create an instrumented dir.
 
66
        try:
 
67
            result = bzrdir.BzrDir.create('memory:///')
 
68
            self.failUnless(isinstance(result, SampleBzrDir))
 
69
        finally:
 
70
            self.applyDeprecated(symbol_versioning.zero_fourteen,
 
71
                bzrdir.BzrDirFormat.set_default_format, old_format)
 
72
        self.assertEqual(old_format, bzrdir.BzrDirFormat.get_default_format())
 
73
 
 
74
 
 
75
class TestFormatRegistry(TestCase):
 
76
 
 
77
    def make_format_registry(self):
 
78
        my_format_registry = bzrdir.BzrDirFormatRegistry()
 
79
        my_format_registry.register('weave', bzrdir.BzrDirFormat6,
 
80
            'Pre-0.8 format.  Slower and does not support checkouts or shared'
 
81
            ' repositories', deprecated=True)
 
82
        my_format_registry.register_lazy('lazy', 'bzrlib.bzrdir', 
 
83
            'BzrDirFormat6', 'Format registered lazily', deprecated=True)
 
84
        my_format_registry.register_metadir('knit',
 
85
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
86
            'Format using knits',
 
87
            )
 
88
        my_format_registry.set_default('knit')
 
89
        my_format_registry.register_metadir(
 
90
            'branch6',
 
91
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
92
            'Experimental successor to knit.  Use at your own risk.',
 
93
            branch_format='bzrlib.branch.BzrBranchFormat6')
 
94
        my_format_registry.register_metadir(
 
95
            'hidden format',
 
96
            'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
97
            'Experimental successor to knit.  Use at your own risk.',
 
98
            branch_format='bzrlib.branch.BzrBranchFormat6', hidden=True)
 
99
        my_format_registry.register('hiddenweave', bzrdir.BzrDirFormat6,
 
100
            'Pre-0.8 format.  Slower and does not support checkouts or shared'
 
101
            ' repositories', hidden=True)
 
102
        my_format_registry.register_lazy('hiddenlazy', 'bzrlib.bzrdir',
 
103
            'BzrDirFormat6', 'Format registered lazily', deprecated=True,
 
104
            hidden=True)
 
105
        return my_format_registry
 
106
 
 
107
    def test_format_registry(self):
 
108
        my_format_registry = self.make_format_registry()
 
109
        my_bzrdir = my_format_registry.make_bzrdir('lazy')
 
110
        self.assertIsInstance(my_bzrdir, bzrdir.BzrDirFormat6)
 
111
        my_bzrdir = my_format_registry.make_bzrdir('weave')
 
112
        self.assertIsInstance(my_bzrdir, bzrdir.BzrDirFormat6)
 
113
        my_bzrdir = my_format_registry.make_bzrdir('default')
 
114
        self.assertIsInstance(my_bzrdir.repository_format, 
 
115
            knitrepo.RepositoryFormatKnit1)
 
116
        my_bzrdir = my_format_registry.make_bzrdir('knit')
 
117
        self.assertIsInstance(my_bzrdir.repository_format, 
 
118
            knitrepo.RepositoryFormatKnit1)
 
119
        my_bzrdir = my_format_registry.make_bzrdir('branch6')
 
120
        self.assertIsInstance(my_bzrdir.get_branch_format(),
 
121
                              bzrlib.branch.BzrBranchFormat6)
 
122
 
 
123
    def test_get_help(self):
 
124
        my_format_registry = self.make_format_registry()
 
125
        self.assertEqual('Format registered lazily',
 
126
                         my_format_registry.get_help('lazy'))
 
127
        self.assertEqual('Format using knits', 
 
128
                         my_format_registry.get_help('knit'))
 
129
        self.assertEqual('Format using knits', 
 
130
                         my_format_registry.get_help('default'))
 
131
        self.assertEqual('Pre-0.8 format.  Slower and does not support'
 
132
                         ' checkouts or shared repositories', 
 
133
                         my_format_registry.get_help('weave'))
 
134
        
 
135
    def test_help_topic(self):
 
136
        topics = help_topics.HelpTopicRegistry()
 
137
        topics.register('formats', self.make_format_registry().help_topic, 
 
138
                        'Directory formats')
 
139
        topic = topics.get_detail('formats')
 
140
        new, deprecated = topic.split('Deprecated formats')
 
141
        self.assertContainsRe(new, 'Bazaar directory formats')
 
142
        self.assertContainsRe(new, 
 
143
            '  knit/default:\n    \(native\) Format using knits\n')
 
144
        self.assertContainsRe(deprecated, 
 
145
            '  lazy:\n    \(native\) Format registered lazily\n')
 
146
        self.assertNotContainsRe(new, 'hidden')
 
147
 
 
148
    def test_set_default_repository(self):
 
149
        default_factory = bzrdir.format_registry.get('default')
 
150
        old_default = [k for k, v in bzrdir.format_registry.iteritems()
 
151
                       if v == default_factory and k != 'default'][0]
 
152
        bzrdir.format_registry.set_default_repository('dirstate-with-subtree')
 
153
        try:
 
154
            self.assertIs(bzrdir.format_registry.get('dirstate-with-subtree'),
 
155
                          bzrdir.format_registry.get('default'))
 
156
            self.assertIs(
 
157
                repository.RepositoryFormat.get_default_format().__class__,
 
158
                knitrepo.RepositoryFormatKnit3)
 
159
        finally:
 
160
            bzrdir.format_registry.set_default_repository(old_default)
 
161
 
 
162
 
 
163
class SampleBranch(bzrlib.branch.Branch):
 
164
    """A dummy branch for guess what, dummy use."""
 
165
 
 
166
    def __init__(self, dir):
 
167
        self.bzrdir = dir
 
168
 
 
169
 
 
170
class SampleBzrDir(bzrdir.BzrDir):
 
171
    """A sample BzrDir implementation to allow testing static methods."""
 
172
 
 
173
    def create_repository(self, shared=False):
 
174
        """See BzrDir.create_repository."""
 
175
        return "A repository"
 
176
 
 
177
    def open_repository(self):
 
178
        """See BzrDir.open_repository."""
 
179
        return "A repository"
 
180
 
 
181
    def create_branch(self):
 
182
        """See BzrDir.create_branch."""
 
183
        return SampleBranch(self)
 
184
 
 
185
    def create_workingtree(self):
 
186
        """See BzrDir.create_workingtree."""
 
187
        return "A tree"
 
188
 
 
189
 
 
190
class SampleBzrDirFormat(bzrdir.BzrDirFormat):
 
191
    """A sample format
 
192
 
 
193
    this format is initializable, unsupported to aid in testing the 
 
194
    open and open_downlevel routines.
 
195
    """
 
196
 
 
197
    def get_format_string(self):
 
198
        """See BzrDirFormat.get_format_string()."""
 
199
        return "Sample .bzr dir format."
 
200
 
 
201
    def initialize(self, url):
 
202
        """Create a bzr dir."""
 
203
        t = get_transport(url)
 
204
        t.mkdir('.bzr')
 
205
        t.put_bytes('.bzr/branch-format', self.get_format_string())
 
206
        return SampleBzrDir(t, self)
 
207
 
 
208
    def is_supported(self):
 
209
        return False
 
210
 
 
211
    def open(self, transport, _found=None):
 
212
        return "opened branch."
 
213
 
 
214
 
 
215
class TestBzrDirFormat(TestCaseWithTransport):
 
216
    """Tests for the BzrDirFormat facility."""
 
217
 
 
218
    def test_find_format(self):
 
219
        # is the right format object found for a branch?
 
220
        # create a branch with a few known format objects.
 
221
        # this is not quite the same as 
 
222
        t = get_transport(self.get_url())
 
223
        self.build_tree(["foo/", "bar/"], transport=t)
 
224
        def check_format(format, url):
 
225
            format.initialize(url)
 
226
            t = get_transport(url)
 
227
            found_format = bzrdir.BzrDirFormat.find_format(t)
 
228
            self.failUnless(isinstance(found_format, format.__class__))
 
229
        check_format(bzrdir.BzrDirFormat5(), "foo")
 
230
        check_format(bzrdir.BzrDirFormat6(), "bar")
 
231
        
 
232
    def test_find_format_nothing_there(self):
 
233
        self.assertRaises(NotBranchError,
 
234
                          bzrdir.BzrDirFormat.find_format,
 
235
                          get_transport('.'))
 
236
 
 
237
    def test_find_format_unknown_format(self):
 
238
        t = get_transport(self.get_url())
 
239
        t.mkdir('.bzr')
 
240
        t.put_bytes('.bzr/branch-format', '')
 
241
        self.assertRaises(UnknownFormatError,
 
242
                          bzrdir.BzrDirFormat.find_format,
 
243
                          get_transport('.'))
 
244
 
 
245
    def test_register_unregister_format(self):
 
246
        format = SampleBzrDirFormat()
 
247
        url = self.get_url()
 
248
        # make a bzrdir
 
249
        format.initialize(url)
 
250
        # register a format for it.
 
251
        bzrdir.BzrDirFormat.register_format(format)
 
252
        # which bzrdir.Open will refuse (not supported)
 
253
        self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open, url)
 
254
        # which bzrdir.open_containing will refuse (not supported)
 
255
        self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open_containing, url)
 
256
        # but open_downlevel will work
 
257
        t = get_transport(url)
 
258
        self.assertEqual(format.open(t), bzrdir.BzrDir.open_unsupported(url))
 
259
        # unregister the format
 
260
        bzrdir.BzrDirFormat.unregister_format(format)
 
261
        # now open_downlevel should fail too.
 
262
        self.assertRaises(UnknownFormatError, bzrdir.BzrDir.open_unsupported, url)
 
263
 
 
264
    def test_create_repository(self):
 
265
        format = SampleBzrDirFormat()
 
266
        repo = bzrdir.BzrDir.create_repository(self.get_url(), format=format)
 
267
        self.assertEqual('A repository', repo)
 
268
 
 
269
    def test_create_repository_shared(self):
 
270
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
271
        repo = bzrdir.BzrDir.create_repository('.', shared=True)
 
272
        self.assertTrue(repo.is_shared())
 
273
 
 
274
    def test_create_repository_nonshared(self):
 
275
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
276
        repo = bzrdir.BzrDir.create_repository('.')
 
277
        self.assertFalse(repo.is_shared())
 
278
 
 
279
    def test_create_repository_under_shared(self):
 
280
        # an explicit create_repository always does so.
 
281
        # we trust the format is right from the 'create_repository test'
 
282
        format = bzrdir.format_registry.make_bzrdir('knit')
 
283
        self.make_repository('.', shared=True, format=format)
 
284
        repo = bzrdir.BzrDir.create_repository(self.get_url('child'),
 
285
                                               format=format)
 
286
        self.assertTrue(isinstance(repo, repository.Repository))
 
287
        self.assertTrue(repo.bzrdir.root_transport.base.endswith('child/'))
 
288
 
 
289
    def test_create_branch_and_repo_uses_default(self):
 
290
        format = SampleBzrDirFormat()
 
291
        branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url(), 
 
292
                                                      format=format)
 
293
        self.assertTrue(isinstance(branch, SampleBranch))
 
294
 
 
295
    def test_create_branch_and_repo_under_shared(self):
 
296
        # creating a branch and repo in a shared repo uses the
 
297
        # shared repository
 
298
        format = bzrdir.format_registry.make_bzrdir('knit')
 
299
        self.make_repository('.', shared=True, format=format)
 
300
        branch = bzrdir.BzrDir.create_branch_and_repo(
 
301
            self.get_url('child'), format=format)
 
302
        self.assertRaises(errors.NoRepositoryPresent,
 
303
                          branch.bzrdir.open_repository)
 
304
 
 
305
    def test_create_branch_and_repo_under_shared_force_new(self):
 
306
        # creating a branch and repo in a shared repo can be forced to 
 
307
        # make a new repo
 
308
        format = bzrdir.format_registry.make_bzrdir('knit')
 
309
        self.make_repository('.', shared=True, format=format)
 
310
        branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'),
 
311
                                                      force_new_repo=True,
 
312
                                                      format=format)
 
313
        branch.bzrdir.open_repository()
 
314
 
 
315
    def test_create_standalone_working_tree(self):
 
316
        format = SampleBzrDirFormat()
 
317
        # note this is deliberately readonly, as this failure should 
 
318
        # occur before any writes.
 
319
        self.assertRaises(errors.NotLocalUrl,
 
320
                          bzrdir.BzrDir.create_standalone_workingtree,
 
321
                          self.get_readonly_url(), format=format)
 
322
        tree = bzrdir.BzrDir.create_standalone_workingtree('.', 
 
323
                                                           format=format)
 
324
        self.assertEqual('A tree', tree)
 
325
 
 
326
    def test_create_standalone_working_tree_under_shared_repo(self):
 
327
        # create standalone working tree always makes a repo.
 
328
        format = bzrdir.format_registry.make_bzrdir('knit')
 
329
        self.make_repository('.', shared=True, format=format)
 
330
        # note this is deliberately readonly, as this failure should 
 
331
        # occur before any writes.
 
332
        self.assertRaises(errors.NotLocalUrl,
 
333
                          bzrdir.BzrDir.create_standalone_workingtree,
 
334
                          self.get_readonly_url('child'), format=format)
 
335
        tree = bzrdir.BzrDir.create_standalone_workingtree('child', 
 
336
            format=format)
 
337
        tree.bzrdir.open_repository()
 
338
 
 
339
    def test_create_branch_convenience(self):
 
340
        # outside a repo the default convenience output is a repo+branch_tree
 
341
        format = bzrdir.format_registry.make_bzrdir('knit')
 
342
        branch = bzrdir.BzrDir.create_branch_convenience('.', format=format)
 
343
        branch.bzrdir.open_workingtree()
 
344
        branch.bzrdir.open_repository()
 
345
 
 
346
    def test_create_branch_convenience_root(self):
 
347
        """Creating a branch at the root of a fs should work."""
 
348
        self.vfs_transport_factory = MemoryServer
 
349
        # outside a repo the default convenience output is a repo+branch_tree
 
350
        format = bzrdir.format_registry.make_bzrdir('knit')
 
351
        branch = bzrdir.BzrDir.create_branch_convenience(self.get_url(), 
 
352
                                                         format=format)
 
353
        self.assertRaises(errors.NoWorkingTree,
 
354
                          branch.bzrdir.open_workingtree)
 
355
        branch.bzrdir.open_repository()
 
356
 
 
357
    def test_create_branch_convenience_under_shared_repo(self):
 
358
        # inside a repo the default convenience output is a branch+ follow the
 
359
        # repo tree policy
 
360
        format = bzrdir.format_registry.make_bzrdir('knit')
 
361
        self.make_repository('.', shared=True, format=format)
 
362
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
363
            format=format)
 
364
        branch.bzrdir.open_workingtree()
 
365
        self.assertRaises(errors.NoRepositoryPresent,
 
366
                          branch.bzrdir.open_repository)
 
367
            
 
368
    def test_create_branch_convenience_under_shared_repo_force_no_tree(self):
 
369
        # inside a repo the default convenience output is a branch+ follow the
 
370
        # repo tree policy but we can override that
 
371
        format = bzrdir.format_registry.make_bzrdir('knit')
 
372
        self.make_repository('.', shared=True, format=format)
 
373
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
374
            force_new_tree=False, format=format)
 
375
        self.assertRaises(errors.NoWorkingTree,
 
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_no_tree_policy(self):
 
381
        # inside a repo the default convenience output is a branch+ follow the
 
382
        # repo tree policy
 
383
        format = bzrdir.format_registry.make_bzrdir('knit')
 
384
        repo = self.make_repository('.', shared=True, format=format)
 
385
        repo.set_make_working_trees(False)
 
386
        branch = bzrdir.BzrDir.create_branch_convenience('child', 
 
387
                                                         format=format)
 
388
        self.assertRaises(errors.NoWorkingTree,
 
389
                          branch.bzrdir.open_workingtree)
 
390
        self.assertRaises(errors.NoRepositoryPresent,
 
391
                          branch.bzrdir.open_repository)
 
392
 
 
393
    def test_create_branch_convenience_under_shared_repo_no_tree_policy_force_tree(self):
 
394
        # inside a repo the default convenience output is a branch+ follow the
 
395
        # repo tree policy but we can override that
 
396
        format = bzrdir.format_registry.make_bzrdir('knit')
 
397
        repo = self.make_repository('.', shared=True, format=format)
 
398
        repo.set_make_working_trees(False)
 
399
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
400
            force_new_tree=True, format=format)
 
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_force_new_repo(self):
 
406
        # inside a repo the default convenience output is overridable to give
 
407
        # repo+branch+tree
 
408
        format = bzrdir.format_registry.make_bzrdir('knit')
 
409
        self.make_repository('.', shared=True, format=format)
 
410
        branch = bzrdir.BzrDir.create_branch_convenience('child',
 
411
            force_new_repo=True, format=format)
 
412
        branch.bzrdir.open_repository()
 
413
        branch.bzrdir.open_workingtree()
 
414
 
 
415
 
 
416
class ChrootedTests(TestCaseWithTransport):
 
417
    """A support class that provides readonly urls outside the local namespace.
 
418
 
 
419
    This is done by checking if self.transport_server is a MemoryServer. if it
 
420
    is then we are chrooted already, if it is not then an HttpServer is used
 
421
    for readonly urls.
 
422
    """
 
423
 
 
424
    def setUp(self):
 
425
        super(ChrootedTests, self).setUp()
 
426
        if not self.vfs_transport_factory == MemoryServer:
 
427
            self.transport_readonly_server = HttpServer
 
428
 
 
429
    def test_open_containing(self):
 
430
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
 
431
                          self.get_readonly_url(''))
 
432
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
 
433
                          self.get_readonly_url('g/p/q'))
 
434
        control = bzrdir.BzrDir.create(self.get_url())
 
435
        branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url(''))
 
436
        self.assertEqual('', relpath)
 
437
        branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url('g/p/q'))
 
438
        self.assertEqual('g/p/q', relpath)
 
439
 
 
440
    def test_open_containing_from_transport(self):
 
441
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
 
442
                          get_transport(self.get_readonly_url('')))
 
443
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
 
444
                          get_transport(self.get_readonly_url('g/p/q')))
 
445
        control = bzrdir.BzrDir.create(self.get_url())
 
446
        branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
 
447
            get_transport(self.get_readonly_url('')))
 
448
        self.assertEqual('', relpath)
 
449
        branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
 
450
            get_transport(self.get_readonly_url('g/p/q')))
 
451
        self.assertEqual('g/p/q', relpath)
 
452
 
 
453
    def test_open_containing_tree_or_branch(self):
 
454
        def local_branch_path(branch):
 
455
             return os.path.realpath(
 
456
                urlutils.local_path_from_url(branch.base))
 
457
 
 
458
        self.make_branch_and_tree('topdir')
 
459
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
460
            'topdir/foo')
 
461
        self.assertEqual(os.path.realpath('topdir'),
 
462
                         os.path.realpath(tree.basedir))
 
463
        self.assertEqual(os.path.realpath('topdir'),
 
464
                         local_branch_path(branch))
 
465
        self.assertIs(tree.bzrdir, branch.bzrdir)
 
466
        self.assertEqual('foo', relpath)
 
467
        # opening from non-local should not return the tree
 
468
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
469
            self.get_readonly_url('topdir/foo'))
 
470
        self.assertEqual(None, tree)
 
471
        self.assertEqual('foo', relpath)
 
472
        # without a tree:
 
473
        self.make_branch('topdir/foo')
 
474
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
475
            'topdir/foo')
 
476
        self.assertIs(tree, None)
 
477
        self.assertEqual(os.path.realpath('topdir/foo'),
 
478
                         local_branch_path(branch))
 
479
        self.assertEqual('', relpath)
 
480
 
 
481
    def test_open_from_transport(self):
 
482
        # transport pointing at bzrdir should give a bzrdir with root transport
 
483
        # set to the given transport
 
484
        control = bzrdir.BzrDir.create(self.get_url())
 
485
        transport = get_transport(self.get_url())
 
486
        opened_bzrdir = bzrdir.BzrDir.open_from_transport(transport)
 
487
        self.assertEqual(transport.base, opened_bzrdir.root_transport.base)
 
488
        self.assertIsInstance(opened_bzrdir, bzrdir.BzrDir)
 
489
        
 
490
    def test_open_from_transport_no_bzrdir(self):
 
491
        transport = get_transport(self.get_url())
 
492
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport,
 
493
                          transport)
 
494
 
 
495
    def test_open_from_transport_bzrdir_in_parent(self):
 
496
        control = bzrdir.BzrDir.create(self.get_url())
 
497
        transport = get_transport(self.get_url())
 
498
        transport.mkdir('subdir')
 
499
        transport = transport.clone('subdir')
 
500
        self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport,
 
501
                          transport)
 
502
 
 
503
    def test_sprout_recursive(self):
 
504
        tree = self.make_branch_and_tree('tree1', format='dirstate-with-subtree')
 
505
        sub_tree = self.make_branch_and_tree('tree1/subtree',
 
506
            format='dirstate-with-subtree')
 
507
        tree.add_reference(sub_tree)
 
508
        self.build_tree(['tree1/subtree/file'])
 
509
        sub_tree.add('file')
 
510
        tree.commit('Initial commit')
 
511
        tree.bzrdir.sprout('tree2')
 
512
        self.failUnlessExists('tree2/subtree/file')
 
513
 
 
514
    def test_cloning_metadir(self):
 
515
        """Ensure that cloning metadir is suitable"""
 
516
        bzrdir = self.make_bzrdir('bzrdir')
 
517
        bzrdir.cloning_metadir()
 
518
        branch = self.make_branch('branch', format='knit')
 
519
        format = branch.bzrdir.cloning_metadir()
 
520
        self.assertIsInstance(format.workingtree_format,
 
521
            workingtree.WorkingTreeFormat3)
 
522
 
 
523
    def test_sprout_recursive_treeless(self):
 
524
        tree = self.make_branch_and_tree('tree1',
 
525
            format='dirstate-with-subtree')
 
526
        sub_tree = self.make_branch_and_tree('tree1/subtree',
 
527
            format='dirstate-with-subtree')
 
528
        tree.add_reference(sub_tree)
 
529
        self.build_tree(['tree1/subtree/file'])
 
530
        sub_tree.add('file')
 
531
        tree.commit('Initial commit')
 
532
        tree.bzrdir.destroy_workingtree()
 
533
        repo = self.make_repository('repo', shared=True,
 
534
            format='dirstate-with-subtree')
 
535
        repo.set_make_working_trees(False)
 
536
        tree.bzrdir.sprout('repo/tree2')
 
537
        self.failUnlessExists('repo/tree2/subtree')
 
538
        self.failIfExists('repo/tree2/subtree/file')
 
539
 
 
540
 
 
541
class TestMeta1DirFormat(TestCaseWithTransport):
 
542
    """Tests specific to the meta1 dir format."""
 
543
 
 
544
    def test_right_base_dirs(self):
 
545
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
546
        t = dir.transport
 
547
        branch_base = t.clone('branch').base
 
548
        self.assertEqual(branch_base, dir.get_branch_transport(None).base)
 
549
        self.assertEqual(branch_base,
 
550
                         dir.get_branch_transport(bzrlib.branch.BzrBranchFormat5()).base)
 
551
        repository_base = t.clone('repository').base
 
552
        self.assertEqual(repository_base, dir.get_repository_transport(None).base)
 
553
        self.assertEqual(repository_base,
 
554
                         dir.get_repository_transport(weaverepo.RepositoryFormat7()).base)
 
555
        checkout_base = t.clone('checkout').base
 
556
        self.assertEqual(checkout_base, dir.get_workingtree_transport(None).base)
 
557
        self.assertEqual(checkout_base,
 
558
                         dir.get_workingtree_transport(workingtree.WorkingTreeFormat3()).base)
 
559
 
 
560
    def test_meta1dir_uses_lockdir(self):
 
561
        """Meta1 format uses a LockDir to guard the whole directory, not a file."""
 
562
        dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
 
563
        t = dir.transport
 
564
        self.assertIsDirectory('branch-lock', t)
 
565
 
 
566
    def test_comparison(self):
 
567
        """Equality and inequality behave properly.
 
568
 
 
569
        Metadirs should compare equal iff they have the same repo, branch and
 
570
        tree formats.
 
571
        """
 
572
        mydir = bzrdir.format_registry.make_bzrdir('knit')
 
573
        self.assertEqual(mydir, mydir)
 
574
        self.assertFalse(mydir != mydir)
 
575
        otherdir = bzrdir.format_registry.make_bzrdir('knit')
 
576
        self.assertEqual(otherdir, mydir)
 
577
        self.assertFalse(otherdir != mydir)
 
578
        otherdir2 = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
 
579
        self.assertNotEqual(otherdir2, mydir)
 
580
        self.assertFalse(otherdir2 == mydir)
 
581
 
 
582
    def test_needs_conversion_different_working_tree(self):
 
583
        # meta1dirs need an conversion if any element is not the default.
 
584
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
585
        # test with 
 
586
        new_default = bzrdir.format_registry.make_bzrdir('dirstate')
 
587
        bzrdir.BzrDirFormat._set_default_format(new_default)
 
588
        try:
 
589
            tree = self.make_branch_and_tree('tree', format='knit')
 
590
            self.assertTrue(tree.bzrdir.needs_format_conversion())
 
591
        finally:
 
592
            bzrdir.BzrDirFormat._set_default_format(old_format)
 
593
 
 
594
 
 
595
class TestFormat5(TestCaseWithTransport):
 
596
    """Tests specific to the version 5 bzrdir format."""
 
597
 
 
598
    def test_same_lockfiles_between_tree_repo_branch(self):
 
599
        # this checks that only a single lockfiles instance is created 
 
600
        # for format 5 objects
 
601
        dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
 
602
        def check_dir_components_use_same_lock(dir):
 
603
            ctrl_1 = dir.open_repository().control_files
 
604
            ctrl_2 = dir.open_branch().control_files
 
605
            ctrl_3 = dir.open_workingtree()._control_files
 
606
            self.assertTrue(ctrl_1 is ctrl_2)
 
607
            self.assertTrue(ctrl_2 is ctrl_3)
 
608
        check_dir_components_use_same_lock(dir)
 
609
        # and if we open it normally.
 
610
        dir = bzrdir.BzrDir.open(self.get_url())
 
611
        check_dir_components_use_same_lock(dir)
 
612
    
 
613
    def test_can_convert(self):
 
614
        # format 5 dirs are convertable
 
615
        dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
 
616
        self.assertTrue(dir.can_convert_format())
 
617
    
 
618
    def test_needs_conversion(self):
 
619
        # format 5 dirs need a conversion if they are not the default.
 
620
        # and they start of not the default.
 
621
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
622
        bzrdir.BzrDirFormat._set_default_format(bzrdir.BzrDirFormat5())
 
623
        try:
 
624
            dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
 
625
            self.assertFalse(dir.needs_format_conversion())
 
626
        finally:
 
627
            bzrdir.BzrDirFormat._set_default_format(old_format)
 
628
        self.assertTrue(dir.needs_format_conversion())
 
629
 
 
630
 
 
631
class TestFormat6(TestCaseWithTransport):
 
632
    """Tests specific to the version 6 bzrdir format."""
 
633
 
 
634
    def test_same_lockfiles_between_tree_repo_branch(self):
 
635
        # this checks that only a single lockfiles instance is created 
 
636
        # for format 6 objects
 
637
        dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
638
        def check_dir_components_use_same_lock(dir):
 
639
            ctrl_1 = dir.open_repository().control_files
 
640
            ctrl_2 = dir.open_branch().control_files
 
641
            ctrl_3 = dir.open_workingtree()._control_files
 
642
            self.assertTrue(ctrl_1 is ctrl_2)
 
643
            self.assertTrue(ctrl_2 is ctrl_3)
 
644
        check_dir_components_use_same_lock(dir)
 
645
        # and if we open it normally.
 
646
        dir = bzrdir.BzrDir.open(self.get_url())
 
647
        check_dir_components_use_same_lock(dir)
 
648
    
 
649
    def test_can_convert(self):
 
650
        # format 6 dirs are convertable
 
651
        dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
652
        self.assertTrue(dir.can_convert_format())
 
653
    
 
654
    def test_needs_conversion(self):
 
655
        # format 6 dirs need an conversion if they are not the default.
 
656
        old_format = bzrdir.BzrDirFormat.get_default_format()
 
657
        bzrdir.BzrDirFormat._set_default_format(bzrdir.BzrDirMetaFormat1())
 
658
        try:
 
659
            dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
 
660
            self.assertTrue(dir.needs_format_conversion())
 
661
        finally:
 
662
            bzrdir.BzrDirFormat._set_default_format(old_format)
 
663
 
 
664
 
 
665
class NotBzrDir(bzrlib.bzrdir.BzrDir):
 
666
    """A non .bzr based control directory."""
 
667
 
 
668
    def __init__(self, transport, format):
 
669
        self._format = format
 
670
        self.root_transport = transport
 
671
        self.transport = transport.clone('.not')
 
672
 
 
673
 
 
674
class NotBzrDirFormat(bzrlib.bzrdir.BzrDirFormat):
 
675
    """A test class representing any non-.bzr based disk format."""
 
676
 
 
677
    def initialize_on_transport(self, transport):
 
678
        """Initialize a new .not dir in the base directory of a Transport."""
 
679
        transport.mkdir('.not')
 
680
        return self.open(transport)
 
681
 
 
682
    def open(self, transport):
 
683
        """Open this directory."""
 
684
        return NotBzrDir(transport, self)
 
685
 
 
686
    @classmethod
 
687
    def _known_formats(self):
 
688
        return set([NotBzrDirFormat()])
 
689
 
 
690
    @classmethod
 
691
    def probe_transport(self, transport):
 
692
        """Our format is present if the transport ends in '.not/'."""
 
693
        if transport.has('.not'):
 
694
            return NotBzrDirFormat()
 
695
 
 
696
 
 
697
class TestNotBzrDir(TestCaseWithTransport):
 
698
    """Tests for using the bzrdir api with a non .bzr based disk format.
 
699
    
 
700
    If/when one of these is in the core, we can let the implementation tests
 
701
    verify this works.
 
702
    """
 
703
 
 
704
    def test_create_and_find_format(self):
 
705
        # create a .notbzr dir 
 
706
        format = NotBzrDirFormat()
 
707
        dir = format.initialize(self.get_url())
 
708
        self.assertIsInstance(dir, NotBzrDir)
 
709
        # now probe for it.
 
710
        bzrlib.bzrdir.BzrDirFormat.register_control_format(format)
 
711
        try:
 
712
            found = bzrlib.bzrdir.BzrDirFormat.find_format(
 
713
                get_transport(self.get_url()))
 
714
            self.assertIsInstance(found, NotBzrDirFormat)
 
715
        finally:
 
716
            bzrlib.bzrdir.BzrDirFormat.unregister_control_format(format)
 
717
 
 
718
    def test_included_in_known_formats(self):
 
719
        bzrlib.bzrdir.BzrDirFormat.register_control_format(NotBzrDirFormat)
 
720
        try:
 
721
            formats = bzrlib.bzrdir.BzrDirFormat.known_formats()
 
722
            for format in formats:
 
723
                if isinstance(format, NotBzrDirFormat):
 
724
                    return
 
725
            self.fail("No NotBzrDirFormat in %s" % formats)
 
726
        finally:
 
727
            bzrlib.bzrdir.BzrDirFormat.unregister_control_format(NotBzrDirFormat)
 
728
 
 
729
 
 
730
class NonLocalTests(TestCaseWithTransport):
 
731
    """Tests for bzrdir static behaviour on non local paths."""
 
732
 
 
733
    def setUp(self):
 
734
        super(NonLocalTests, self).setUp()
 
735
        self.vfs_transport_factory = MemoryServer
 
736
    
 
737
    def test_create_branch_convenience(self):
 
738
        # outside a repo the default convenience output is a repo+branch_tree
 
739
        format = bzrdir.format_registry.make_bzrdir('knit')
 
740
        branch = bzrdir.BzrDir.create_branch_convenience(
 
741
            self.get_url('foo'), format=format)
 
742
        self.assertRaises(errors.NoWorkingTree,
 
743
                          branch.bzrdir.open_workingtree)
 
744
        branch.bzrdir.open_repository()
 
745
 
 
746
    def test_create_branch_convenience_force_tree_not_local_fails(self):
 
747
        # outside a repo the default convenience output is a repo+branch_tree
 
748
        format = bzrdir.format_registry.make_bzrdir('knit')
 
749
        self.assertRaises(errors.NotLocalUrl,
 
750
            bzrdir.BzrDir.create_branch_convenience,
 
751
            self.get_url('foo'),
 
752
            force_new_tree=True,
 
753
            format=format)
 
754
        t = get_transport(self.get_url('.'))
 
755
        self.assertFalse(t.has('foo'))
 
756
 
 
757
    def test_clone(self):
 
758
        # clone into a nonlocal path works
 
759
        format = bzrdir.format_registry.make_bzrdir('knit')
 
760
        branch = bzrdir.BzrDir.create_branch_convenience('local',
 
761
                                                         format=format)
 
762
        branch.bzrdir.open_workingtree()
 
763
        result = branch.bzrdir.clone(self.get_url('remote'))
 
764
        self.assertRaises(errors.NoWorkingTree,
 
765
                          result.open_workingtree)
 
766
        result.open_branch()
 
767
        result.open_repository()
 
768
 
 
769
    def test_checkout_metadir(self):
 
770
        # checkout_metadir has reasonable working tree format even when no
 
771
        # working tree is present
 
772
        self.make_branch('branch-knit2', format='dirstate-with-subtree')
 
773
        my_bzrdir = bzrdir.BzrDir.open(self.get_url('branch-knit2'))
 
774
        checkout_format = my_bzrdir.checkout_metadir()
 
775
        self.assertIsInstance(checkout_format.workingtree_format,
 
776
                              workingtree.WorkingTreeFormat3)
 
777
 
 
778
 
 
779
class TestHTTPRedirectionLoop(object):
 
780
    """Test redirection loop between two http servers.
 
781
 
 
782
    This MUST be used by daughter classes that also inherit from
 
783
    TestCaseWithTwoWebservers.
 
784
 
 
785
    We can't inherit directly from TestCaseWithTwoWebservers or the
 
786
    test framework will try to create an instance which cannot
 
787
    run, its implementation being incomplete. 
 
788
    """
 
789
 
 
790
    # Should be defined by daughter classes to ensure redirection
 
791
    # still use the same transport implementation (not currently
 
792
    # enforced as it's a bit tricky to get right (see the FIXME
 
793
    # in BzrDir.open_from_transport for the unique use case so
 
794
    # far)
 
795
    _qualifier = None
 
796
 
 
797
    def create_transport_readonly_server(self):
 
798
        return HTTPServerRedirecting()
 
799
 
 
800
    def create_transport_secondary_server(self):
 
801
        return HTTPServerRedirecting()
 
802
 
 
803
    def setUp(self):
 
804
        # Both servers redirect to each server creating a loop
 
805
        super(TestHTTPRedirectionLoop, self).setUp()
 
806
        # The redirections will point to the new server
 
807
        self.new_server = self.get_readonly_server()
 
808
        # The requests to the old server will be redirected
 
809
        self.old_server = self.get_secondary_server()
 
810
        # Configure the redirections
 
811
        self.old_server.redirect_to(self.new_server.host, self.new_server.port)
 
812
        self.new_server.redirect_to(self.old_server.host, self.old_server.port)
 
813
 
 
814
    def _qualified_url(self, host, port):
 
815
        return 'http+%s://%s:%s' % (self._qualifier, host, port)
 
816
 
 
817
    def test_loop(self):
 
818
        # Starting from either server should loop
 
819
        old_url = self._qualified_url(self.old_server.host, 
 
820
                                      self.old_server.port)
 
821
        oldt = self._transport(old_url)
 
822
        self.assertRaises(errors.NotBranchError,
 
823
                          bzrdir.BzrDir.open_from_transport, oldt)
 
824
        new_url = self._qualified_url(self.new_server.host, 
 
825
                                      self.new_server.port)
 
826
        newt = self._transport(new_url)
 
827
        self.assertRaises(errors.NotBranchError,
 
828
                          bzrdir.BzrDir.open_from_transport, newt)
 
829
 
 
830
 
 
831
class TestHTTPRedirections_urllib(TestHTTPRedirectionLoop,
 
832
                                  TestCaseWithTwoWebservers):
 
833
    """Tests redirections for urllib implementation"""
 
834
 
 
835
    _qualifier = 'urllib'
 
836
    _transport = HttpTransport_urllib
 
837
 
 
838
 
 
839
 
 
840
class TestHTTPRedirections_pycurl(TestWithTransport_pycurl,
 
841
                                  TestHTTPRedirectionLoop,
 
842
                                  TestCaseWithTwoWebservers):
 
843
    """Tests redirections for pycurl implementation"""
 
844
 
 
845
    _qualifier = 'pycurl'