1
# Copyright (C) 2005, 2006 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.
22
from StringIO import StringIO
25
import bzrlib.bzrdir as bzrdir
26
import bzrlib.errors as errors
27
from bzrlib.errors import (NotBranchError,
29
UnsupportedFormatError,
31
import bzrlib.repository as repository
32
from bzrlib.tests import TestCase, TestCaseWithTransport
33
from bzrlib.transport import get_transport
34
from bzrlib.transport.http import HttpServer
35
from bzrlib.transport.memory import MemoryServer
36
import bzrlib.workingtree as workingtree
39
class TestDefaultFormat(TestCase):
41
def test_get_set_default_format(self):
42
old_format = bzrdir.BzrDirFormat.get_default_format()
43
# default is BzrDirFormat6
44
self.failUnless(isinstance(old_format, bzrdir.BzrDirMetaFormat1))
45
bzrdir.BzrDirFormat.set_default_format(SampleBzrDirFormat())
46
# creating a bzr dir should now create an instrumented dir.
48
result = bzrdir.BzrDir.create('memory:/')
49
self.failUnless(isinstance(result, SampleBzrDir))
51
bzrdir.BzrDirFormat.set_default_format(old_format)
52
self.assertEqual(old_format, bzrdir.BzrDirFormat.get_default_format())
55
class SampleBranch(bzrlib.branch.Branch):
56
"""A dummy branch for guess what, dummy use."""
58
def __init__(self, dir):
62
class SampleBzrDir(bzrdir.BzrDir):
63
"""A sample BzrDir implementation to allow testing static methods."""
65
def create_repository(self):
66
"""See BzrDir.create_repository."""
69
def open_repository(self):
70
"""See BzrDir.open_repository."""
73
def create_branch(self):
74
"""See BzrDir.create_branch."""
75
return SampleBranch(self)
77
def create_workingtree(self):
78
"""See BzrDir.create_workingtree."""
82
class SampleBzrDirFormat(bzrdir.BzrDirFormat):
85
this format is initializable, unsupported to aid in testing the
86
open and open_downlevel routines.
89
def get_format_string(self):
90
"""See BzrDirFormat.get_format_string()."""
91
return "Sample .bzr dir format."
93
def initialize(self, url):
94
"""Create a bzr dir."""
95
t = get_transport(url)
97
t.put('.bzr/branch-format', StringIO(self.get_format_string()))
98
return SampleBzrDir(t, self)
100
def is_supported(self):
103
def open(self, transport, _found=None):
104
return "opened branch."
107
class TestBzrDirFormat(TestCaseWithTransport):
108
"""Tests for the BzrDirFormat facility."""
110
def test_find_format(self):
111
# is the right format object found for a branch?
112
# create a branch with a few known format objects.
113
# this is not quite the same as
114
t = get_transport(self.get_url())
115
self.build_tree(["foo/", "bar/"], transport=t)
116
def check_format(format, url):
117
format.initialize(url)
118
t = get_transport(url)
119
found_format = bzrdir.BzrDirFormat.find_format(t)
120
self.failUnless(isinstance(found_format, format.__class__))
121
check_format(bzrdir.BzrDirFormat5(), "foo")
122
check_format(bzrdir.BzrDirFormat6(), "bar")
124
def test_find_format_nothing_there(self):
125
self.assertRaises(NotBranchError,
126
bzrdir.BzrDirFormat.find_format,
129
def test_find_format_unknown_format(self):
130
t = get_transport(self.get_url())
132
t.put('.bzr/branch-format', StringIO())
133
self.assertRaises(UnknownFormatError,
134
bzrdir.BzrDirFormat.find_format,
137
def test_register_unregister_format(self):
138
format = SampleBzrDirFormat()
141
format.initialize(url)
142
# register a format for it.
143
bzrdir.BzrDirFormat.register_format(format)
144
# which bzrdir.Open will refuse (not supported)
145
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open, url)
146
# which bzrdir.open_containing will refuse (not supported)
147
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open_containing, url)
148
# but open_downlevel will work
149
t = get_transport(url)
150
self.assertEqual(format.open(t), bzrdir.BzrDir.open_unsupported(url))
151
# unregister the format
152
bzrdir.BzrDirFormat.unregister_format(format)
153
# now open_downlevel should fail too.
154
self.assertRaises(UnknownFormatError, bzrdir.BzrDir.open_unsupported, url)
156
def test_create_repository(self):
157
format = SampleBzrDirFormat()
158
old_format = bzrdir.BzrDirFormat.get_default_format()
159
bzrdir.BzrDirFormat.set_default_format(format)
161
repo = bzrdir.BzrDir.create_repository(self.get_url())
162
self.assertEqual('A repository', repo)
164
bzrdir.BzrDirFormat.set_default_format(old_format)
166
def test_create_repository_under_shared(self):
167
# an explicit create_repository always does so.
168
# we trust the format is right from the 'create_repository test'
169
old_format = bzrdir.BzrDirFormat.get_default_format()
170
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
172
self.make_repository('.', shared=True)
173
repo = bzrdir.BzrDir.create_repository(self.get_url('child'))
174
self.assertTrue(isinstance(repo, repository.Repository))
175
self.assertTrue(repo.bzrdir.root_transport.base.endswith('child/'))
177
bzrdir.BzrDirFormat.set_default_format(old_format)
179
def test_create_branch_and_repo_uses_default(self):
180
format = SampleBzrDirFormat()
181
old_format = bzrdir.BzrDirFormat.get_default_format()
182
bzrdir.BzrDirFormat.set_default_format(format)
184
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url())
185
self.assertTrue(isinstance(branch, SampleBranch))
187
bzrdir.BzrDirFormat.set_default_format(old_format)
189
def test_create_branch_and_repo_under_shared(self):
190
# creating a branch and repo in a shared repo uses the
192
old_format = bzrdir.BzrDirFormat.get_default_format()
193
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
195
self.make_repository('.', shared=True)
196
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'))
197
self.assertRaises(errors.NoRepositoryPresent,
198
branch.bzrdir.open_repository)
200
bzrdir.BzrDirFormat.set_default_format(old_format)
202
def test_create_branch_and_repo_under_shared_force_new(self):
203
# creating a branch and repo in a shared repo can be forced to
205
old_format = bzrdir.BzrDirFormat.get_default_format()
206
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
208
self.make_repository('.', shared=True)
209
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'),
211
branch.bzrdir.open_repository()
213
bzrdir.BzrDirFormat.set_default_format(old_format)
215
def test_create_standalone_working_tree(self):
216
format = SampleBzrDirFormat()
217
old_format = bzrdir.BzrDirFormat.get_default_format()
218
bzrdir.BzrDirFormat.set_default_format(format)
220
# note this is deliberately readonly, as this failure should
221
# occur before any writes.
222
self.assertRaises(errors.NotLocalUrl,
223
bzrdir.BzrDir.create_standalone_workingtree,
224
self.get_readonly_url())
225
tree = bzrdir.BzrDir.create_standalone_workingtree('.')
226
self.assertEqual('A tree', tree)
228
bzrdir.BzrDirFormat.set_default_format(old_format)
230
def test_create_standalone_working_tree_under_shared_repo(self):
231
# create standalone working tree always makes a repo.
232
old_format = bzrdir.BzrDirFormat.get_default_format()
233
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
235
self.make_repository('.', shared=True)
236
# note this is deliberately readonly, as this failure should
237
# occur before any writes.
238
self.assertRaises(errors.NotLocalUrl,
239
bzrdir.BzrDir.create_standalone_workingtree,
240
self.get_readonly_url('child'))
241
tree = bzrdir.BzrDir.create_standalone_workingtree('child')
242
tree.bzrdir.open_repository()
244
bzrdir.BzrDirFormat.set_default_format(old_format)
246
def test_create_branch_convenience(self):
247
# outside a repo the default convenience output is a repo+branch_tree
248
old_format = bzrdir.BzrDirFormat.get_default_format()
249
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
251
branch = bzrdir.BzrDir.create_branch_convenience('.')
252
branch.bzrdir.open_workingtree()
253
branch.bzrdir.open_repository()
255
bzrdir.BzrDirFormat.set_default_format(old_format)
257
def test_create_branch_convenience_under_shared_repo(self):
258
# inside a repo the default convenience output is a branch+ follow the
260
old_format = bzrdir.BzrDirFormat.get_default_format()
261
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
263
self.make_repository('.', shared=True)
264
branch = bzrdir.BzrDir.create_branch_convenience('child')
265
branch.bzrdir.open_workingtree()
266
self.assertRaises(errors.NoRepositoryPresent,
267
branch.bzrdir.open_repository)
269
bzrdir.BzrDirFormat.set_default_format(old_format)
271
def test_create_branch_convenience_under_shared_repo_force_no_tree(self):
272
# inside a repo the default convenience output is a branch+ follow the
273
# repo tree policy but we can override that
274
old_format = bzrdir.BzrDirFormat.get_default_format()
275
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
277
self.make_repository('.', shared=True)
278
branch = bzrdir.BzrDir.create_branch_convenience('child',
279
force_new_tree=False)
280
self.assertRaises(errors.NoWorkingTree,
281
branch.bzrdir.open_workingtree)
282
self.assertRaises(errors.NoRepositoryPresent,
283
branch.bzrdir.open_repository)
285
bzrdir.BzrDirFormat.set_default_format(old_format)
287
def test_create_branch_convenience_under_shared_repo_no_tree_policy(self):
288
# inside a repo the default convenience output is a branch+ follow the
290
old_format = bzrdir.BzrDirFormat.get_default_format()
291
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
293
repo = self.make_repository('.', shared=True)
294
repo.set_make_working_trees(False)
295
branch = bzrdir.BzrDir.create_branch_convenience('child')
296
self.assertRaises(errors.NoWorkingTree,
297
branch.bzrdir.open_workingtree)
298
self.assertRaises(errors.NoRepositoryPresent,
299
branch.bzrdir.open_repository)
301
bzrdir.BzrDirFormat.set_default_format(old_format)
303
def test_create_branch_convenience_under_shared_repo_no_tree_policy_force_tree(self):
304
# inside a repo the default convenience output is a branch+ follow the
305
# repo tree policy but we can override that
306
old_format = bzrdir.BzrDirFormat.get_default_format()
307
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
309
repo = self.make_repository('.', shared=True)
310
repo.set_make_working_trees(False)
311
branch = bzrdir.BzrDir.create_branch_convenience('child',
313
branch.bzrdir.open_workingtree()
314
self.assertRaises(errors.NoRepositoryPresent,
315
branch.bzrdir.open_repository)
317
bzrdir.BzrDirFormat.set_default_format(old_format)
319
def test_create_branch_convenience_under_shared_repo_force_new_repo(self):
320
# inside a repo the default convenience output is overridable to give
322
old_format = bzrdir.BzrDirFormat.get_default_format()
323
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
325
self.make_repository('.', shared=True)
326
branch = bzrdir.BzrDir.create_branch_convenience('child',
328
branch.bzrdir.open_repository()
329
branch.bzrdir.open_workingtree()
331
bzrdir.BzrDirFormat.set_default_format(old_format)
334
class ChrootedTests(TestCaseWithTransport):
335
"""A support class that provides readonly urls outside the local namespace.
337
This is done by checking if self.transport_server is a MemoryServer. if it
338
is then we are chrooted already, if it is not then an HttpServer is used
343
super(ChrootedTests, self).setUp()
344
if not self.transport_server == MemoryServer:
345
self.transport_readonly_server = HttpServer
347
def test_open_containing(self):
348
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
349
self.get_readonly_url(''))
350
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
351
self.get_readonly_url('g/p/q'))
352
control = bzrdir.BzrDir.create(self.get_url())
353
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url(''))
354
self.assertEqual('', relpath)
355
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url('g/p/q'))
356
self.assertEqual('g/p/q', relpath)
358
def test_open_containing_from_transport(self):
359
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
360
get_transport(self.get_readonly_url('')))
361
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
362
get_transport(self.get_readonly_url('g/p/q')))
363
control = bzrdir.BzrDir.create(self.get_url())
364
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
365
get_transport(self.get_readonly_url('')))
366
self.assertEqual('', relpath)
367
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
368
get_transport(self.get_readonly_url('g/p/q')))
369
self.assertEqual('g/p/q', relpath)
372
class TestMeta1DirFormat(TestCaseWithTransport):
373
"""Tests specific to the meta1 dir format."""
375
def test_right_base_dirs(self):
376
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
378
branch_base = t.clone('branch').base
379
self.assertEqual(branch_base, dir.get_branch_transport(None).base)
380
self.assertEqual(branch_base,
381
dir.get_branch_transport(bzrlib.branch.BzrBranchFormat5()).base)
382
repository_base = t.clone('repository').base
383
self.assertEqual(repository_base, dir.get_repository_transport(None).base)
384
self.assertEqual(repository_base,
385
dir.get_repository_transport(repository.RepositoryFormat7()).base)
386
checkout_base = t.clone('checkout').base
387
self.assertEqual(checkout_base, dir.get_workingtree_transport(None).base)
388
self.assertEqual(checkout_base,
389
dir.get_workingtree_transport(workingtree.WorkingTreeFormat3()).base)
391
def test_meta1dir_uses_lockdir(self):
392
"""Meta1 format uses a LockDir to guard the whole directory, not a file."""
393
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
395
self.assertIsDirectory('branch-lock', t)
398
class TestFormat5(TestCaseWithTransport):
399
"""Tests specific to the version 5 bzrdir format."""
401
def test_same_lockfiles_between_tree_repo_branch(self):
402
# this checks that only a single lockfiles instance is created
403
# for format 5 objects
404
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
405
def check_dir_components_use_same_lock(dir):
406
ctrl_1 = dir.open_repository().control_files
407
ctrl_2 = dir.open_branch().control_files
408
ctrl_3 = dir.open_workingtree()._control_files
409
self.assertTrue(ctrl_1 is ctrl_2)
410
self.assertTrue(ctrl_2 is ctrl_3)
411
check_dir_components_use_same_lock(dir)
412
# and if we open it normally.
413
dir = bzrdir.BzrDir.open(self.get_url())
414
check_dir_components_use_same_lock(dir)
416
def test_can_convert(self):
417
# format 5 dirs are convertable
418
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
419
self.assertTrue(dir.can_convert_format())
421
def test_needs_conversion(self):
422
# format 5 dirs need a conversion if they are not the default.
423
# and they start of not the default.
424
old_format = bzrdir.BzrDirFormat.get_default_format()
425
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirFormat5())
427
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
428
self.assertFalse(dir.needs_format_conversion())
430
bzrdir.BzrDirFormat.set_default_format(old_format)
431
self.assertTrue(dir.needs_format_conversion())
434
class TestFormat6(TestCaseWithTransport):
435
"""Tests specific to the version 6 bzrdir format."""
437
def test_same_lockfiles_between_tree_repo_branch(self):
438
# this checks that only a single lockfiles instance is created
439
# for format 6 objects
440
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
441
def check_dir_components_use_same_lock(dir):
442
ctrl_1 = dir.open_repository().control_files
443
ctrl_2 = dir.open_branch().control_files
444
ctrl_3 = dir.open_workingtree()._control_files
445
self.assertTrue(ctrl_1 is ctrl_2)
446
self.assertTrue(ctrl_2 is ctrl_3)
447
check_dir_components_use_same_lock(dir)
448
# and if we open it normally.
449
dir = bzrdir.BzrDir.open(self.get_url())
450
check_dir_components_use_same_lock(dir)
452
def test_can_convert(self):
453
# format 6 dirs are convertable
454
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
455
self.assertTrue(dir.can_convert_format())
457
def test_needs_conversion(self):
458
# format 6 dirs need an conversion if they are not the default.
459
old_format = bzrdir.BzrDirFormat.get_default_format()
460
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
462
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
463
self.assertTrue(dir.needs_format_conversion())
465
bzrdir.BzrDirFormat.set_default_format(old_format)
468
class NonLocalTests(TestCaseWithTransport):
469
"""Tests for bzrdir static behaviour on non local paths."""
472
super(NonLocalTests, self).setUp()
473
self.transport_server = MemoryServer
475
def test_create_branch_convenience(self):
476
# outside a repo the default convenience output is a repo+branch_tree
477
old_format = bzrdir.BzrDirFormat.get_default_format()
478
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
480
branch = bzrdir.BzrDir.create_branch_convenience(self.get_url('foo'))
481
self.assertRaises(errors.NoWorkingTree,
482
branch.bzrdir.open_workingtree)
483
branch.bzrdir.open_repository()
485
bzrdir.BzrDirFormat.set_default_format(old_format)
487
def test_create_branch_convenience_force_tree_not_local_fails(self):
488
# outside a repo the default convenience output is a repo+branch_tree
489
old_format = bzrdir.BzrDirFormat.get_default_format()
490
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
492
self.assertRaises(errors.NotLocalUrl,
493
bzrdir.BzrDir.create_branch_convenience,
496
t = get_transport(self.get_url('.'))
497
self.assertFalse(t.has('foo'))
499
bzrdir.BzrDirFormat.set_default_format(old_format)
501
def test_clone(self):
502
# clone into a nonlocal path works
503
old_format = bzrdir.BzrDirFormat.get_default_format()
504
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
506
branch = bzrdir.BzrDir.create_branch_convenience('local')
508
bzrdir.BzrDirFormat.set_default_format(old_format)
509
branch.bzrdir.open_workingtree()
510
result = branch.bzrdir.clone(self.get_url('remote'))
511
self.assertRaises(errors.NoWorkingTree,
512
result.open_workingtree)
514
result.open_repository()