1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
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.
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.
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
17
"""Tests for the BzrDir facility and any format specific tests.
19
For interface contract tests, see tests/bzr_dir_implementations.
24
from StringIO import StringIO
39
from bzrlib.errors import (NotBranchError,
41
UnsupportedFormatError,
43
from bzrlib.tests import (
45
TestCaseWithMemoryTransport,
46
TestCaseWithTransport,
50
from bzrlib.tests.http_server import HttpServer
51
from bzrlib.tests.http_utils import (
52
TestCaseWithTwoWebservers,
53
HTTPServerRedirecting,
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.repofmt import knitrepo, weaverepo
62
class TestDefaultFormat(TestCase):
64
def test_get_set_default_format(self):
65
old_format = bzrdir.BzrDirFormat.get_default_format()
66
# default is BzrDirFormat6
67
self.failUnless(isinstance(old_format, bzrdir.BzrDirMetaFormat1))
68
bzrdir.BzrDirFormat._set_default_format(SampleBzrDirFormat())
69
# creating a bzr dir should now create an instrumented dir.
71
result = bzrdir.BzrDir.create('memory:///')
72
self.failUnless(isinstance(result, SampleBzrDir))
74
bzrdir.BzrDirFormat._set_default_format(old_format)
75
self.assertEqual(old_format, bzrdir.BzrDirFormat.get_default_format())
78
class TestFormatRegistry(TestCase):
80
def make_format_registry(self):
81
my_format_registry = bzrdir.BzrDirFormatRegistry()
82
my_format_registry.register('weave', bzrdir.BzrDirFormat6,
83
'Pre-0.8 format. Slower and does not support checkouts or shared'
84
' repositories', deprecated=True)
85
my_format_registry.register_lazy('lazy', 'bzrlib.bzrdir',
86
'BzrDirFormat6', 'Format registered lazily', deprecated=True)
87
my_format_registry.register_metadir('knit',
88
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
91
my_format_registry.set_default('knit')
92
my_format_registry.register_metadir(
94
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
95
'Experimental successor to knit. Use at your own risk.',
96
branch_format='bzrlib.branch.BzrBranchFormat6',
98
my_format_registry.register_metadir(
100
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
101
'Experimental successor to knit. Use at your own risk.',
102
branch_format='bzrlib.branch.BzrBranchFormat6', hidden=True)
103
my_format_registry.register('hiddenweave', bzrdir.BzrDirFormat6,
104
'Pre-0.8 format. Slower and does not support checkouts or shared'
105
' repositories', hidden=True)
106
my_format_registry.register_lazy('hiddenlazy', 'bzrlib.bzrdir',
107
'BzrDirFormat6', 'Format registered lazily', deprecated=True,
109
return my_format_registry
111
def test_format_registry(self):
112
my_format_registry = self.make_format_registry()
113
my_bzrdir = my_format_registry.make_bzrdir('lazy')
114
self.assertIsInstance(my_bzrdir, bzrdir.BzrDirFormat6)
115
my_bzrdir = my_format_registry.make_bzrdir('weave')
116
self.assertIsInstance(my_bzrdir, bzrdir.BzrDirFormat6)
117
my_bzrdir = my_format_registry.make_bzrdir('default')
118
self.assertIsInstance(my_bzrdir.repository_format,
119
knitrepo.RepositoryFormatKnit1)
120
my_bzrdir = my_format_registry.make_bzrdir('knit')
121
self.assertIsInstance(my_bzrdir.repository_format,
122
knitrepo.RepositoryFormatKnit1)
123
my_bzrdir = my_format_registry.make_bzrdir('branch6')
124
self.assertIsInstance(my_bzrdir.get_branch_format(),
125
bzrlib.branch.BzrBranchFormat6)
127
def test_get_help(self):
128
my_format_registry = self.make_format_registry()
129
self.assertEqual('Format registered lazily',
130
my_format_registry.get_help('lazy'))
131
self.assertEqual('Format using knits',
132
my_format_registry.get_help('knit'))
133
self.assertEqual('Format using knits',
134
my_format_registry.get_help('default'))
135
self.assertEqual('Pre-0.8 format. Slower and does not support'
136
' checkouts or shared repositories',
137
my_format_registry.get_help('weave'))
139
def test_help_topic(self):
140
topics = help_topics.HelpTopicRegistry()
141
topics.register('formats', self.make_format_registry().help_topic,
143
topic = topics.get_detail('formats')
144
new, rest = topic.split('Experimental formats')
145
experimental, deprecated = rest.split('Deprecated formats')
146
self.assertContainsRe(new, 'These formats can be used')
147
self.assertContainsRe(new,
148
':knit:\n \(native\) \(default\) Format using knits\n')
149
self.assertContainsRe(experimental,
150
':branch6:\n \(native\) Experimental successor to knit')
151
self.assertContainsRe(deprecated,
152
':lazy:\n \(native\) Format registered lazily\n')
153
self.assertNotContainsRe(new, 'hidden')
155
def test_set_default_repository(self):
156
default_factory = bzrdir.format_registry.get('default')
157
old_default = [k for k, v in bzrdir.format_registry.iteritems()
158
if v == default_factory and k != 'default'][0]
159
bzrdir.format_registry.set_default_repository('dirstate-with-subtree')
161
self.assertIs(bzrdir.format_registry.get('dirstate-with-subtree'),
162
bzrdir.format_registry.get('default'))
164
repository.RepositoryFormat.get_default_format().__class__,
165
knitrepo.RepositoryFormatKnit3)
167
bzrdir.format_registry.set_default_repository(old_default)
169
def test_aliases(self):
170
a_registry = bzrdir.BzrDirFormatRegistry()
171
a_registry.register('weave', bzrdir.BzrDirFormat6,
172
'Pre-0.8 format. Slower and does not support checkouts or shared'
173
' repositories', deprecated=True)
174
a_registry.register('weavealias', bzrdir.BzrDirFormat6,
175
'Pre-0.8 format. Slower and does not support checkouts or shared'
176
' repositories', deprecated=True, alias=True)
177
self.assertEqual(frozenset(['weavealias']), a_registry.aliases())
180
class SampleBranch(bzrlib.branch.Branch):
181
"""A dummy branch for guess what, dummy use."""
183
def __init__(self, dir):
187
class SampleBzrDir(bzrdir.BzrDir):
188
"""A sample BzrDir implementation to allow testing static methods."""
190
def create_repository(self, shared=False):
191
"""See BzrDir.create_repository."""
192
return "A repository"
194
def open_repository(self):
195
"""See BzrDir.open_repository."""
196
return "A repository"
198
def create_branch(self):
199
"""See BzrDir.create_branch."""
200
return SampleBranch(self)
202
def create_workingtree(self):
203
"""See BzrDir.create_workingtree."""
207
class SampleBzrDirFormat(bzrdir.BzrDirFormat):
210
this format is initializable, unsupported to aid in testing the
211
open and open_downlevel routines.
214
def get_format_string(self):
215
"""See BzrDirFormat.get_format_string()."""
216
return "Sample .bzr dir format."
218
def initialize_on_transport(self, t):
219
"""Create a bzr dir."""
221
t.put_bytes('.bzr/branch-format', self.get_format_string())
222
return SampleBzrDir(t, self)
224
def is_supported(self):
227
def open(self, transport, _found=None):
228
return "opened branch."
231
class TestBzrDirFormat(TestCaseWithTransport):
232
"""Tests for the BzrDirFormat facility."""
234
def test_find_format(self):
235
# is the right format object found for a branch?
236
# create a branch with a few known format objects.
237
# this is not quite the same as
238
t = get_transport(self.get_url())
239
self.build_tree(["foo/", "bar/"], transport=t)
240
def check_format(format, url):
241
format.initialize(url)
242
t = get_transport(url)
243
found_format = bzrdir.BzrDirFormat.find_format(t)
244
self.failUnless(isinstance(found_format, format.__class__))
245
check_format(bzrdir.BzrDirFormat5(), "foo")
246
check_format(bzrdir.BzrDirFormat6(), "bar")
248
def test_find_format_nothing_there(self):
249
self.assertRaises(NotBranchError,
250
bzrdir.BzrDirFormat.find_format,
253
def test_find_format_unknown_format(self):
254
t = get_transport(self.get_url())
256
t.put_bytes('.bzr/branch-format', '')
257
self.assertRaises(UnknownFormatError,
258
bzrdir.BzrDirFormat.find_format,
261
def test_register_unregister_format(self):
262
format = SampleBzrDirFormat()
265
format.initialize(url)
266
# register a format for it.
267
bzrdir.BzrDirFormat.register_format(format)
268
# which bzrdir.Open will refuse (not supported)
269
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open, url)
270
# which bzrdir.open_containing will refuse (not supported)
271
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open_containing, url)
272
# but open_downlevel will work
273
t = get_transport(url)
274
self.assertEqual(format.open(t), bzrdir.BzrDir.open_unsupported(url))
275
# unregister the format
276
bzrdir.BzrDirFormat.unregister_format(format)
277
# now open_downlevel should fail too.
278
self.assertRaises(UnknownFormatError, bzrdir.BzrDir.open_unsupported, url)
280
def test_create_branch_and_repo_uses_default(self):
281
format = SampleBzrDirFormat()
282
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url(),
284
self.assertTrue(isinstance(branch, SampleBranch))
286
def test_create_branch_and_repo_under_shared(self):
287
# creating a branch and repo in a shared repo uses the
289
format = bzrdir.format_registry.make_bzrdir('knit')
290
self.make_repository('.', shared=True, format=format)
291
branch = bzrdir.BzrDir.create_branch_and_repo(
292
self.get_url('child'), format=format)
293
self.assertRaises(errors.NoRepositoryPresent,
294
branch.bzrdir.open_repository)
296
def test_create_branch_and_repo_under_shared_force_new(self):
297
# creating a branch and repo in a shared repo can be forced to
299
format = bzrdir.format_registry.make_bzrdir('knit')
300
self.make_repository('.', shared=True, format=format)
301
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'),
304
branch.bzrdir.open_repository()
306
def test_create_standalone_working_tree(self):
307
format = SampleBzrDirFormat()
308
# note this is deliberately readonly, as this failure should
309
# occur before any writes.
310
self.assertRaises(errors.NotLocalUrl,
311
bzrdir.BzrDir.create_standalone_workingtree,
312
self.get_readonly_url(), format=format)
313
tree = bzrdir.BzrDir.create_standalone_workingtree('.',
315
self.assertEqual('A tree', tree)
317
def test_create_standalone_working_tree_under_shared_repo(self):
318
# create standalone working tree always makes a repo.
319
format = bzrdir.format_registry.make_bzrdir('knit')
320
self.make_repository('.', shared=True, format=format)
321
# note this is deliberately readonly, as this failure should
322
# occur before any writes.
323
self.assertRaises(errors.NotLocalUrl,
324
bzrdir.BzrDir.create_standalone_workingtree,
325
self.get_readonly_url('child'), format=format)
326
tree = bzrdir.BzrDir.create_standalone_workingtree('child',
328
tree.bzrdir.open_repository()
330
def test_create_branch_convenience(self):
331
# outside a repo the default convenience output is a repo+branch_tree
332
format = bzrdir.format_registry.make_bzrdir('knit')
333
branch = bzrdir.BzrDir.create_branch_convenience('.', format=format)
334
branch.bzrdir.open_workingtree()
335
branch.bzrdir.open_repository()
337
def test_create_branch_convenience_possible_transports(self):
338
"""Check that the optional 'possible_transports' is recognized"""
339
format = bzrdir.format_registry.make_bzrdir('knit')
340
t = self.get_transport()
341
branch = bzrdir.BzrDir.create_branch_convenience(
342
'.', format=format, possible_transports=[t])
343
branch.bzrdir.open_workingtree()
344
branch.bzrdir.open_repository()
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(),
353
self.assertRaises(errors.NoWorkingTree,
354
branch.bzrdir.open_workingtree)
355
branch.bzrdir.open_repository()
357
def test_create_branch_convenience_under_shared_repo(self):
358
# inside a repo the default convenience output is a branch+ follow the
360
format = bzrdir.format_registry.make_bzrdir('knit')
361
self.make_repository('.', shared=True, format=format)
362
branch = bzrdir.BzrDir.create_branch_convenience('child',
364
branch.bzrdir.open_workingtree()
365
self.assertRaises(errors.NoRepositoryPresent,
366
branch.bzrdir.open_repository)
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)
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
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',
388
self.assertRaises(errors.NoWorkingTree,
389
branch.bzrdir.open_workingtree)
390
self.assertRaises(errors.NoRepositoryPresent,
391
branch.bzrdir.open_repository)
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)
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
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()
416
class TestRepositoryAcquisitionPolicy(TestCaseWithTransport):
418
def test_acquire_repository_standalone(self):
419
"""The default acquisition policy should create a standalone branch."""
420
my_bzrdir = self.make_bzrdir('.')
421
repo_policy = my_bzrdir.determine_repository_policy()
422
repo = repo_policy.acquire_repository()
423
self.assertEqual(repo.bzrdir.root_transport.base,
424
my_bzrdir.root_transport.base)
425
self.assertFalse(repo.is_shared())
428
def test_determine_stacking_policy(self):
429
parent_bzrdir = self.make_bzrdir('.')
430
child_bzrdir = self.make_bzrdir('child')
431
parent_bzrdir.get_config().set_default_stack_on('http://example.org')
432
repo_policy = child_bzrdir.determine_repository_policy()
433
self.assertEqual('http://example.org', repo_policy._stack_on)
435
def test_determine_stacking_policy_relative(self):
436
parent_bzrdir = self.make_bzrdir('.')
437
child_bzrdir = self.make_bzrdir('child')
438
parent_bzrdir.get_config().set_default_stack_on('child2')
439
repo_policy = child_bzrdir.determine_repository_policy()
440
self.assertEqual('child2', repo_policy._stack_on)
441
self.assertEqual(parent_bzrdir.root_transport.base,
442
repo_policy._stack_on_pwd)
444
def prepare_default_stacking(self):
445
parent_bzrdir = self.make_bzrdir('.')
446
child_branch = self.make_branch('child', format='development1')
447
parent_bzrdir.get_config().set_default_stack_on(child_branch.base)
448
new_child_transport = parent_bzrdir.transport.clone('child2')
449
return child_branch, new_child_transport
451
def test_clone_on_transport_obeys_stacking_policy(self):
452
child_branch, new_child_transport = self.prepare_default_stacking()
453
new_child = child_branch.bzrdir.clone_on_transport(new_child_transport)
454
self.assertEqual(child_branch.base,
455
new_child.open_branch().get_stacked_on_url())
457
def test_sprout_obeys_stacking_policy(self):
458
child_branch, new_child_transport = self.prepare_default_stacking()
459
new_child = child_branch.bzrdir.sprout(new_child_transport.base)
460
self.assertEqual(child_branch.base,
461
new_child.open_branch().get_stacked_on_url())
463
def test_add_fallback_repo_handles_absolute_urls(self):
464
stack_on = self.make_branch('stack_on', format='development1')
465
repo = self.make_repository('repo', format='development1')
466
policy = bzrdir.UseExistingRepository(repo, stack_on.base)
467
policy._add_fallback(repo)
469
def test_add_fallback_repo_handles_relative_urls(self):
470
stack_on = self.make_branch('stack_on', format='development1')
471
repo = self.make_repository('repo', format='development1')
472
policy = bzrdir.UseExistingRepository(repo, '.', stack_on.base)
473
policy._add_fallback(repo)
475
def test_configure_relative_branch_stacking_url(self):
476
stack_on = self.make_branch('stack_on', format='development1')
477
stacked = self.make_branch('stack_on/stacked', format='development1')
478
policy = bzrdir.UseExistingRepository(stacked.repository,
480
policy.configure_branch(stacked)
481
self.assertEqual('..', stacked.get_stacked_on_url())
483
def test_relative_branch_stacking_to_absolute(self):
484
stack_on = self.make_branch('stack_on', format='development1')
485
stacked = self.make_branch('stack_on/stacked', format='development1')
486
policy = bzrdir.UseExistingRepository(stacked.repository,
487
'.', self.get_readonly_url('stack_on'))
488
policy.configure_branch(stacked)
489
self.assertEqual(self.get_readonly_url('stack_on'),
490
stacked.get_stacked_on_url())
493
class ChrootedTests(TestCaseWithTransport):
494
"""A support class that provides readonly urls outside the local namespace.
496
This is done by checking if self.transport_server is a MemoryServer. if it
497
is then we are chrooted already, if it is not then an HttpServer is used
502
super(ChrootedTests, self).setUp()
503
if not self.vfs_transport_factory == MemoryServer:
504
self.transport_readonly_server = HttpServer
506
def local_branch_path(self, branch):
507
return os.path.realpath(urlutils.local_path_from_url(branch.base))
509
def test_open_containing(self):
510
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
511
self.get_readonly_url(''))
512
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
513
self.get_readonly_url('g/p/q'))
514
control = bzrdir.BzrDir.create(self.get_url())
515
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url(''))
516
self.assertEqual('', relpath)
517
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url('g/p/q'))
518
self.assertEqual('g/p/q', relpath)
520
def test_open_containing_tree_branch_or_repository_empty(self):
521
self.assertRaises(errors.NotBranchError,
522
bzrdir.BzrDir.open_containing_tree_branch_or_repository,
523
self.get_readonly_url(''))
525
def test_open_containing_tree_branch_or_repository_all(self):
526
self.make_branch_and_tree('topdir')
527
tree, branch, repo, relpath = \
528
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
530
self.assertEqual(os.path.realpath('topdir'),
531
os.path.realpath(tree.basedir))
532
self.assertEqual(os.path.realpath('topdir'),
533
self.local_branch_path(branch))
535
os.path.realpath(os.path.join('topdir', '.bzr', 'repository')),
536
repo.bzrdir.transport.local_abspath('repository'))
537
self.assertEqual(relpath, 'foo')
539
def test_open_containing_tree_branch_or_repository_no_tree(self):
540
self.make_branch('branch')
541
tree, branch, repo, relpath = \
542
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
544
self.assertEqual(tree, None)
545
self.assertEqual(os.path.realpath('branch'),
546
self.local_branch_path(branch))
548
os.path.realpath(os.path.join('branch', '.bzr', 'repository')),
549
repo.bzrdir.transport.local_abspath('repository'))
550
self.assertEqual(relpath, 'foo')
552
def test_open_containing_tree_branch_or_repository_repo(self):
553
self.make_repository('repo')
554
tree, branch, repo, relpath = \
555
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
557
self.assertEqual(tree, None)
558
self.assertEqual(branch, None)
560
os.path.realpath(os.path.join('repo', '.bzr', 'repository')),
561
repo.bzrdir.transport.local_abspath('repository'))
562
self.assertEqual(relpath, '')
564
def test_open_containing_tree_branch_or_repository_shared_repo(self):
565
self.make_repository('shared', shared=True)
566
bzrdir.BzrDir.create_branch_convenience('shared/branch',
567
force_new_tree=False)
568
tree, branch, repo, relpath = \
569
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
571
self.assertEqual(tree, None)
572
self.assertEqual(os.path.realpath('shared/branch'),
573
self.local_branch_path(branch))
575
os.path.realpath(os.path.join('shared', '.bzr', 'repository')),
576
repo.bzrdir.transport.local_abspath('repository'))
577
self.assertEqual(relpath, '')
579
def test_open_containing_tree_branch_or_repository_branch_subdir(self):
580
self.make_branch_and_tree('foo')
581
self.build_tree(['foo/bar/'])
582
tree, branch, repo, relpath = \
583
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
585
self.assertEqual(os.path.realpath('foo'),
586
os.path.realpath(tree.basedir))
587
self.assertEqual(os.path.realpath('foo'),
588
self.local_branch_path(branch))
590
os.path.realpath(os.path.join('foo', '.bzr', 'repository')),
591
repo.bzrdir.transport.local_abspath('repository'))
592
self.assertEqual(relpath, 'bar')
594
def test_open_containing_tree_branch_or_repository_repo_subdir(self):
595
self.make_repository('bar')
596
self.build_tree(['bar/baz/'])
597
tree, branch, repo, relpath = \
598
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
600
self.assertEqual(tree, None)
601
self.assertEqual(branch, None)
603
os.path.realpath(os.path.join('bar', '.bzr', 'repository')),
604
repo.bzrdir.transport.local_abspath('repository'))
605
self.assertEqual(relpath, 'baz')
607
def test_open_containing_from_transport(self):
608
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
609
get_transport(self.get_readonly_url('')))
610
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
611
get_transport(self.get_readonly_url('g/p/q')))
612
control = bzrdir.BzrDir.create(self.get_url())
613
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
614
get_transport(self.get_readonly_url('')))
615
self.assertEqual('', relpath)
616
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
617
get_transport(self.get_readonly_url('g/p/q')))
618
self.assertEqual('g/p/q', relpath)
620
def test_open_containing_tree_or_branch(self):
621
self.make_branch_and_tree('topdir')
622
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
624
self.assertEqual(os.path.realpath('topdir'),
625
os.path.realpath(tree.basedir))
626
self.assertEqual(os.path.realpath('topdir'),
627
self.local_branch_path(branch))
628
self.assertIs(tree.bzrdir, branch.bzrdir)
629
self.assertEqual('foo', relpath)
630
# opening from non-local should not return the tree
631
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
632
self.get_readonly_url('topdir/foo'))
633
self.assertEqual(None, tree)
634
self.assertEqual('foo', relpath)
636
self.make_branch('topdir/foo')
637
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
639
self.assertIs(tree, None)
640
self.assertEqual(os.path.realpath('topdir/foo'),
641
self.local_branch_path(branch))
642
self.assertEqual('', relpath)
644
def test_open_tree_or_branch(self):
645
self.make_branch_and_tree('topdir')
646
tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir')
647
self.assertEqual(os.path.realpath('topdir'),
648
os.path.realpath(tree.basedir))
649
self.assertEqual(os.path.realpath('topdir'),
650
self.local_branch_path(branch))
651
self.assertIs(tree.bzrdir, branch.bzrdir)
652
# opening from non-local should not return the tree
653
tree, branch = bzrdir.BzrDir.open_tree_or_branch(
654
self.get_readonly_url('topdir'))
655
self.assertEqual(None, tree)
657
self.make_branch('topdir/foo')
658
tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir/foo')
659
self.assertIs(tree, None)
660
self.assertEqual(os.path.realpath('topdir/foo'),
661
self.local_branch_path(branch))
663
def test_open_from_transport(self):
664
# transport pointing at bzrdir should give a bzrdir with root transport
665
# set to the given transport
666
control = bzrdir.BzrDir.create(self.get_url())
667
transport = get_transport(self.get_url())
668
opened_bzrdir = bzrdir.BzrDir.open_from_transport(transport)
669
self.assertEqual(transport.base, opened_bzrdir.root_transport.base)
670
self.assertIsInstance(opened_bzrdir, bzrdir.BzrDir)
672
def test_open_from_transport_no_bzrdir(self):
673
transport = get_transport(self.get_url())
674
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport,
677
def test_open_from_transport_bzrdir_in_parent(self):
678
control = bzrdir.BzrDir.create(self.get_url())
679
transport = get_transport(self.get_url())
680
transport.mkdir('subdir')
681
transport = transport.clone('subdir')
682
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport,
685
def test_sprout_recursive(self):
686
tree = self.make_branch_and_tree('tree1', format='dirstate-with-subtree')
687
sub_tree = self.make_branch_and_tree('tree1/subtree',
688
format='dirstate-with-subtree')
689
tree.add_reference(sub_tree)
690
self.build_tree(['tree1/subtree/file'])
692
tree.commit('Initial commit')
693
tree.bzrdir.sprout('tree2')
694
self.failUnlessExists('tree2/subtree/file')
696
def test_cloning_metadir(self):
697
"""Ensure that cloning metadir is suitable"""
698
bzrdir = self.make_bzrdir('bzrdir')
699
bzrdir.cloning_metadir()
700
branch = self.make_branch('branch', format='knit')
701
format = branch.bzrdir.cloning_metadir()
702
self.assertIsInstance(format.workingtree_format,
703
workingtree.WorkingTreeFormat3)
705
def test_sprout_recursive_treeless(self):
706
tree = self.make_branch_and_tree('tree1',
707
format='dirstate-with-subtree')
708
sub_tree = self.make_branch_and_tree('tree1/subtree',
709
format='dirstate-with-subtree')
710
tree.add_reference(sub_tree)
711
self.build_tree(['tree1/subtree/file'])
713
tree.commit('Initial commit')
714
tree.bzrdir.destroy_workingtree()
715
repo = self.make_repository('repo', shared=True,
716
format='dirstate-with-subtree')
717
repo.set_make_working_trees(False)
718
tree.bzrdir.sprout('repo/tree2')
719
self.failUnlessExists('repo/tree2/subtree')
720
self.failIfExists('repo/tree2/subtree/file')
722
def make_foo_bar_baz(self):
723
foo = bzrdir.BzrDir.create_branch_convenience('foo').bzrdir
724
bar = self.make_branch('foo/bar').bzrdir
725
baz = self.make_branch('baz').bzrdir
728
def test_find_bzrdirs(self):
729
foo, bar, baz = self.make_foo_bar_baz()
730
transport = get_transport(self.get_url())
731
self.assertEqualBzrdirs([baz, foo, bar],
732
bzrdir.BzrDir.find_bzrdirs(transport))
734
def test_find_bzrdirs_list_current(self):
735
def list_current(transport):
736
return [s for s in transport.list_dir('') if s != 'baz']
738
foo, bar, baz = self.make_foo_bar_baz()
739
transport = get_transport(self.get_url())
740
self.assertEqualBzrdirs([foo, bar],
741
bzrdir.BzrDir.find_bzrdirs(transport,
742
list_current=list_current))
745
def test_find_bzrdirs_evaluate(self):
746
def evaluate(bzrdir):
748
repo = bzrdir.open_repository()
749
except NoRepositoryPresent:
750
return True, bzrdir.root_transport.base
752
return False, bzrdir.root_transport.base
754
foo, bar, baz = self.make_foo_bar_baz()
755
transport = get_transport(self.get_url())
756
self.assertEqual([baz.root_transport.base, foo.root_transport.base],
757
list(bzrdir.BzrDir.find_bzrdirs(transport,
760
def assertEqualBzrdirs(self, first, second):
762
second = list(second)
763
self.assertEqual(len(first), len(second))
764
for x, y in zip(first, second):
765
self.assertEqual(x.root_transport.base, y.root_transport.base)
767
def test_find_branches(self):
768
root = self.make_repository('', shared=True)
769
foo, bar, baz = self.make_foo_bar_baz()
770
qux = self.make_bzrdir('foo/qux')
771
transport = get_transport(self.get_url())
772
branches = bzrdir.BzrDir.find_branches(transport)
773
self.assertEqual(baz.root_transport.base, branches[0].base)
774
self.assertEqual(foo.root_transport.base, branches[1].base)
775
self.assertEqual(bar.root_transport.base, branches[2].base)
777
# ensure this works without a top-level repo
778
branches = bzrdir.BzrDir.find_branches(transport.clone('foo'))
779
self.assertEqual(foo.root_transport.base, branches[0].base)
780
self.assertEqual(bar.root_transport.base, branches[1].base)
783
class TestMeta1DirFormat(TestCaseWithTransport):
784
"""Tests specific to the meta1 dir format."""
786
def test_right_base_dirs(self):
787
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
789
branch_base = t.clone('branch').base
790
self.assertEqual(branch_base, dir.get_branch_transport(None).base)
791
self.assertEqual(branch_base,
792
dir.get_branch_transport(bzrlib.branch.BzrBranchFormat5()).base)
793
repository_base = t.clone('repository').base
794
self.assertEqual(repository_base, dir.get_repository_transport(None).base)
795
self.assertEqual(repository_base,
796
dir.get_repository_transport(weaverepo.RepositoryFormat7()).base)
797
checkout_base = t.clone('checkout').base
798
self.assertEqual(checkout_base, dir.get_workingtree_transport(None).base)
799
self.assertEqual(checkout_base,
800
dir.get_workingtree_transport(workingtree.WorkingTreeFormat3()).base)
802
def test_meta1dir_uses_lockdir(self):
803
"""Meta1 format uses a LockDir to guard the whole directory, not a file."""
804
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
806
self.assertIsDirectory('branch-lock', t)
808
def test_comparison(self):
809
"""Equality and inequality behave properly.
811
Metadirs should compare equal iff they have the same repo, branch and
814
mydir = bzrdir.format_registry.make_bzrdir('knit')
815
self.assertEqual(mydir, mydir)
816
self.assertFalse(mydir != mydir)
817
otherdir = bzrdir.format_registry.make_bzrdir('knit')
818
self.assertEqual(otherdir, mydir)
819
self.assertFalse(otherdir != mydir)
820
otherdir2 = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
821
self.assertNotEqual(otherdir2, mydir)
822
self.assertFalse(otherdir2 == mydir)
824
def test_needs_conversion_different_working_tree(self):
825
# meta1dirs need an conversion if any element is not the default.
826
old_format = bzrdir.BzrDirFormat.get_default_format()
828
new_default = bzrdir.format_registry.make_bzrdir('dirstate')
829
bzrdir.BzrDirFormat._set_default_format(new_default)
831
tree = self.make_branch_and_tree('tree', format='knit')
832
self.assertTrue(tree.bzrdir.needs_format_conversion())
834
bzrdir.BzrDirFormat._set_default_format(old_format)
837
class TestFormat5(TestCaseWithTransport):
838
"""Tests specific to the version 5 bzrdir format."""
840
def test_same_lockfiles_between_tree_repo_branch(self):
841
# this checks that only a single lockfiles instance is created
842
# for format 5 objects
843
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
844
def check_dir_components_use_same_lock(dir):
845
ctrl_1 = dir.open_repository().control_files
846
ctrl_2 = dir.open_branch().control_files
847
ctrl_3 = dir.open_workingtree()._control_files
848
self.assertTrue(ctrl_1 is ctrl_2)
849
self.assertTrue(ctrl_2 is ctrl_3)
850
check_dir_components_use_same_lock(dir)
851
# and if we open it normally.
852
dir = bzrdir.BzrDir.open(self.get_url())
853
check_dir_components_use_same_lock(dir)
855
def test_can_convert(self):
856
# format 5 dirs are convertable
857
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
858
self.assertTrue(dir.can_convert_format())
860
def test_needs_conversion(self):
861
# format 5 dirs need a conversion if they are not the default.
862
# and they start of not the default.
863
old_format = bzrdir.BzrDirFormat.get_default_format()
864
bzrdir.BzrDirFormat._set_default_format(bzrdir.BzrDirFormat5())
866
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
867
self.assertFalse(dir.needs_format_conversion())
869
bzrdir.BzrDirFormat._set_default_format(old_format)
870
self.assertTrue(dir.needs_format_conversion())
873
class TestFormat6(TestCaseWithTransport):
874
"""Tests specific to the version 6 bzrdir format."""
876
def test_same_lockfiles_between_tree_repo_branch(self):
877
# this checks that only a single lockfiles instance is created
878
# for format 6 objects
879
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
880
def check_dir_components_use_same_lock(dir):
881
ctrl_1 = dir.open_repository().control_files
882
ctrl_2 = dir.open_branch().control_files
883
ctrl_3 = dir.open_workingtree()._control_files
884
self.assertTrue(ctrl_1 is ctrl_2)
885
self.assertTrue(ctrl_2 is ctrl_3)
886
check_dir_components_use_same_lock(dir)
887
# and if we open it normally.
888
dir = bzrdir.BzrDir.open(self.get_url())
889
check_dir_components_use_same_lock(dir)
891
def test_can_convert(self):
892
# format 6 dirs are convertable
893
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
894
self.assertTrue(dir.can_convert_format())
896
def test_needs_conversion(self):
897
# format 6 dirs need an conversion if they are not the default.
898
old_format = bzrdir.BzrDirFormat.get_default_format()
899
bzrdir.BzrDirFormat._set_default_format(bzrdir.BzrDirMetaFormat1())
901
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
902
self.assertTrue(dir.needs_format_conversion())
904
bzrdir.BzrDirFormat._set_default_format(old_format)
907
class NotBzrDir(bzrlib.bzrdir.BzrDir):
908
"""A non .bzr based control directory."""
910
def __init__(self, transport, format):
911
self._format = format
912
self.root_transport = transport
913
self.transport = transport.clone('.not')
916
class NotBzrDirFormat(bzrlib.bzrdir.BzrDirFormat):
917
"""A test class representing any non-.bzr based disk format."""
919
def initialize_on_transport(self, transport):
920
"""Initialize a new .not dir in the base directory of a Transport."""
921
transport.mkdir('.not')
922
return self.open(transport)
924
def open(self, transport):
925
"""Open this directory."""
926
return NotBzrDir(transport, self)
929
def _known_formats(self):
930
return set([NotBzrDirFormat()])
933
def probe_transport(self, transport):
934
"""Our format is present if the transport ends in '.not/'."""
935
if transport.has('.not'):
936
return NotBzrDirFormat()
939
class TestNotBzrDir(TestCaseWithTransport):
940
"""Tests for using the bzrdir api with a non .bzr based disk format.
942
If/when one of these is in the core, we can let the implementation tests
946
def test_create_and_find_format(self):
947
# create a .notbzr dir
948
format = NotBzrDirFormat()
949
dir = format.initialize(self.get_url())
950
self.assertIsInstance(dir, NotBzrDir)
952
bzrlib.bzrdir.BzrDirFormat.register_control_format(format)
954
found = bzrlib.bzrdir.BzrDirFormat.find_format(
955
get_transport(self.get_url()))
956
self.assertIsInstance(found, NotBzrDirFormat)
958
bzrlib.bzrdir.BzrDirFormat.unregister_control_format(format)
960
def test_included_in_known_formats(self):
961
bzrlib.bzrdir.BzrDirFormat.register_control_format(NotBzrDirFormat)
963
formats = bzrlib.bzrdir.BzrDirFormat.known_formats()
964
for format in formats:
965
if isinstance(format, NotBzrDirFormat):
967
self.fail("No NotBzrDirFormat in %s" % formats)
969
bzrlib.bzrdir.BzrDirFormat.unregister_control_format(NotBzrDirFormat)
972
class NonLocalTests(TestCaseWithTransport):
973
"""Tests for bzrdir static behaviour on non local paths."""
976
super(NonLocalTests, self).setUp()
977
self.vfs_transport_factory = MemoryServer
979
def test_create_branch_convenience(self):
980
# outside a repo the default convenience output is a repo+branch_tree
981
format = bzrdir.format_registry.make_bzrdir('knit')
982
branch = bzrdir.BzrDir.create_branch_convenience(
983
self.get_url('foo'), format=format)
984
self.assertRaises(errors.NoWorkingTree,
985
branch.bzrdir.open_workingtree)
986
branch.bzrdir.open_repository()
988
def test_create_branch_convenience_force_tree_not_local_fails(self):
989
# outside a repo the default convenience output is a repo+branch_tree
990
format = bzrdir.format_registry.make_bzrdir('knit')
991
self.assertRaises(errors.NotLocalUrl,
992
bzrdir.BzrDir.create_branch_convenience,
996
t = get_transport(self.get_url('.'))
997
self.assertFalse(t.has('foo'))
999
def test_clone(self):
1000
# clone into a nonlocal path works
1001
format = bzrdir.format_registry.make_bzrdir('knit')
1002
branch = bzrdir.BzrDir.create_branch_convenience('local',
1004
branch.bzrdir.open_workingtree()
1005
result = branch.bzrdir.clone(self.get_url('remote'))
1006
self.assertRaises(errors.NoWorkingTree,
1007
result.open_workingtree)
1008
result.open_branch()
1009
result.open_repository()
1011
def test_checkout_metadir(self):
1012
# checkout_metadir has reasonable working tree format even when no
1013
# working tree is present
1014
self.make_branch('branch-knit2', format='dirstate-with-subtree')
1015
my_bzrdir = bzrdir.BzrDir.open(self.get_url('branch-knit2'))
1016
checkout_format = my_bzrdir.checkout_metadir()
1017
self.assertIsInstance(checkout_format.workingtree_format,
1018
workingtree.WorkingTreeFormat3)
1021
class TestHTTPRedirectionLoop(object):
1022
"""Test redirection loop between two http servers.
1024
This MUST be used by daughter classes that also inherit from
1025
TestCaseWithTwoWebservers.
1027
We can't inherit directly from TestCaseWithTwoWebservers or the
1028
test framework will try to create an instance which cannot
1029
run, its implementation being incomplete.
1032
# Should be defined by daughter classes to ensure redirection
1033
# still use the same transport implementation (not currently
1034
# enforced as it's a bit tricky to get right (see the FIXME
1035
# in BzrDir.open_from_transport for the unique use case so
1039
def create_transport_readonly_server(self):
1040
return HTTPServerRedirecting()
1042
def create_transport_secondary_server(self):
1043
return HTTPServerRedirecting()
1046
# Both servers redirect to each server creating a loop
1047
super(TestHTTPRedirectionLoop, self).setUp()
1048
# The redirections will point to the new server
1049
self.new_server = self.get_readonly_server()
1050
# The requests to the old server will be redirected
1051
self.old_server = self.get_secondary_server()
1052
# Configure the redirections
1053
self.old_server.redirect_to(self.new_server.host, self.new_server.port)
1054
self.new_server.redirect_to(self.old_server.host, self.old_server.port)
1056
def _qualified_url(self, host, port):
1057
return 'http+%s://%s:%s' % (self._qualifier, host, port)
1059
def test_loop(self):
1060
# Starting from either server should loop
1061
old_url = self._qualified_url(self.old_server.host,
1062
self.old_server.port)
1063
oldt = self._transport(old_url)
1064
self.assertRaises(errors.NotBranchError,
1065
bzrdir.BzrDir.open_from_transport, oldt)
1066
new_url = self._qualified_url(self.new_server.host,
1067
self.new_server.port)
1068
newt = self._transport(new_url)
1069
self.assertRaises(errors.NotBranchError,
1070
bzrdir.BzrDir.open_from_transport, newt)
1073
class TestHTTPRedirections_urllib(TestHTTPRedirectionLoop,
1074
TestCaseWithTwoWebservers):
1075
"""Tests redirections for urllib implementation"""
1077
_qualifier = 'urllib'
1078
_transport = HttpTransport_urllib
1082
class TestHTTPRedirections_pycurl(TestWithTransport_pycurl,
1083
TestHTTPRedirectionLoop,
1084
TestCaseWithTwoWebservers):
1085
"""Tests redirections for pycurl implementation"""
1087
_qualifier = 'pycurl'
1090
class TestDotBzrHidden(TestCaseWithTransport):
1093
if sys.platform == 'win32':
1094
ls = [os.environ['COMSPEC'], '/C', 'dir', '/B']
1097
f = subprocess.Popen(self.ls, stdout=subprocess.PIPE,
1098
stderr=subprocess.PIPE)
1099
out, err = f.communicate()
1100
self.assertEqual(0, f.returncode, 'Calling %s failed: %s'
1102
return out.splitlines()
1104
def test_dot_bzr_hidden(self):
1105
if sys.platform == 'win32' and not win32utils.has_win32file:
1106
raise TestSkipped('unable to make file hidden without pywin32 library')
1107
b = bzrdir.BzrDir.create('.')
1108
self.build_tree(['a'])
1109
self.assertEquals(['a'], self.get_ls())
1111
def test_dot_bzr_hidden_with_url(self):
1112
if sys.platform == 'win32' and not win32utils.has_win32file:
1113
raise TestSkipped('unable to make file hidden without pywin32 library')
1114
b = bzrdir.BzrDir.create(urlutils.local_path_to_url('.'))
1115
self.build_tree(['a'])
1116
self.assertEquals(['a'], self.get_ls())
1119
class _TestBzrDirFormat(bzrdir.BzrDirMetaFormat1):
1120
"""Test BzrDirFormat implementation for TestBzrDirSprout."""
1122
def _open(self, transport):
1123
return _TestBzrDir(transport, self)
1126
class _TestBzrDir(bzrdir.BzrDirMeta1):
1127
"""Test BzrDir implementation for TestBzrDirSprout.
1129
When created a _TestBzrDir already has repository and a branch. The branch
1130
is a test double as well.
1133
def __init__(self, *args, **kwargs):
1134
super(_TestBzrDir, self).__init__(*args, **kwargs)
1135
self.test_branch = _TestBranch()
1136
self.test_branch.repository = self.create_repository()
1138
def open_branch(self, unsupported=False):
1139
return self.test_branch
1141
def cloning_metadir(self):
1142
return _TestBzrDirFormat()
1145
class _TestBranch(bzrlib.branch.Branch):
1146
"""Test Branch implementation for TestBzrDirSprout."""
1148
def __init__(self, *args, **kwargs):
1149
super(_TestBranch, self).__init__(*args, **kwargs)
1152
def sprout(self, *args, **kwargs):
1153
self.calls.append('sprout')
1156
class TestBzrDirSprout(TestCaseWithMemoryTransport):
1158
def test_sprout_uses_branch_sprout(self):
1159
"""BzrDir.sprout calls Branch.sprout.
1161
Usually, BzrDir.sprout should delegate to the branch's sprout method
1162
for part of the work. This allows the source branch to control the
1163
choice of format for the new branch.
1165
There are exceptions, but this tests avoids them:
1166
- if there's no branch in the source bzrdir,
1167
- or if the stacking has been requested and the format needs to be
1168
overridden to satisfy that.
1170
# Make an instrumented bzrdir.
1171
t = self.get_transport('source')
1173
source_bzrdir = _TestBzrDirFormat().initialize_on_transport(t)
1174
# The instrumented bzrdir has a test_branch attribute that logs calls
1175
# made to the branch contained in that bzrdir. Initially the test
1176
# branch exists but no calls have been made to it.
1177
self.assertEqual([], source_bzrdir.test_branch.calls)
1180
target_url = self.get_url('target')
1181
result = source_bzrdir.sprout(target_url, recurse='no')
1183
# The bzrdir called the branch's sprout method.
1184
self.assertEqual(['sprout'], source_bzrdir.test_branch.calls)