~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_bzrdir.py

  • Committer: Aaron Bentley
  • Date: 2007-12-20 20:44:45 UTC
  • mto: This revision was merged to the branch mainline in revision 3235.
  • Revision ID: abentley@panoramicfeedback.com-20071220204445-9o2f10gvvd8e4rks
Implement hard-link support for branch and checkout

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