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.tests.test_sftp_transport import TestCaseWithSFTPServer
34
from bzrlib.transport import get_transport
35
from bzrlib.transport.http import HttpServer
36
from bzrlib.transport.memory import MemoryServer
37
import bzrlib.workingtree as workingtree
40
class TestDefaultFormat(TestCase):
42
def test_get_set_default_format(self):
43
old_format = bzrdir.BzrDirFormat.get_default_format()
44
# default is BzrDirFormat6
45
self.failUnless(isinstance(old_format, bzrdir.BzrDirFormat6))
46
bzrdir.BzrDirFormat.set_default_format(SampleBzrDirFormat())
47
# creating a bzr dir should now create an instrumented dir.
49
result = bzrdir.BzrDir.create('memory:/')
50
self.failUnless(isinstance(result, SampleBzrDir))
52
bzrdir.BzrDirFormat.set_default_format(old_format)
53
self.assertEqual(old_format, bzrdir.BzrDirFormat.get_default_format())
56
class SampleBranch(bzrlib.branch.Branch):
57
"""A dummy branch for guess what, dummy use."""
59
def __init__(self, dir):
63
class SampleBzrDir(bzrdir.BzrDir):
64
"""A sample BzrDir implementation to allow testing static methods."""
66
def create_repository(self):
67
"""See BzrDir.create_repository."""
70
def open_repository(self):
71
"""See BzrDir.open_repository."""
74
def create_branch(self):
75
"""See BzrDir.create_branch."""
76
return SampleBranch(self)
78
def create_workingtree(self):
79
"""See BzrDir.create_workingtree."""
83
class SampleBzrDirFormat(bzrdir.BzrDirFormat):
86
this format is initializable, unsupported to aid in testing the
87
open and open_downlevel routines.
90
def get_format_string(self):
91
"""See BzrDirFormat.get_format_string()."""
92
return "Sample .bzr dir format."
94
def initialize(self, url):
95
"""Create a bzr dir."""
96
t = get_transport(url)
98
t.put('.bzr/branch-format', StringIO(self.get_format_string()))
99
return SampleBzrDir(t, self)
101
def is_supported(self):
104
def open(self, transport, _found=None):
105
return "opened branch."
108
class TestBzrDirFormat(TestCaseWithTransport):
109
"""Tests for the BzrDirFormat facility."""
111
def test_find_format(self):
112
# is the right format object found for a branch?
113
# create a branch with a few known format objects.
114
# this is not quite the same as
115
t = get_transport(self.get_url())
116
self.build_tree(["foo/", "bar/"], transport=t)
117
def check_format(format, url):
118
format.initialize(url)
119
t = get_transport(url)
120
found_format = bzrdir.BzrDirFormat.find_format(t)
121
self.failUnless(isinstance(found_format, format.__class__))
122
check_format(bzrdir.BzrDirFormat5(), "foo")
123
check_format(bzrdir.BzrDirFormat6(), "bar")
125
def test_find_format_nothing_there(self):
126
self.assertRaises(NotBranchError,
127
bzrdir.BzrDirFormat.find_format,
130
def test_find_format_unknown_format(self):
131
t = get_transport(self.get_url())
133
t.put('.bzr/branch-format', StringIO())
134
self.assertRaises(UnknownFormatError,
135
bzrdir.BzrDirFormat.find_format,
138
def test_register_unregister_format(self):
139
format = SampleBzrDirFormat()
142
format.initialize(url)
143
# register a format for it.
144
bzrdir.BzrDirFormat.register_format(format)
145
# which bzrdir.Open will refuse (not supported)
146
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open, url)
147
# which bzrdir.open_containing will refuse (not supported)
148
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open_containing, url)
149
# but open_downlevel will work
150
t = get_transport(url)
151
self.assertEqual(format.open(t), bzrdir.BzrDir.open_unsupported(url))
152
# unregister the format
153
bzrdir.BzrDirFormat.unregister_format(format)
154
# now open_downlevel should fail too.
155
self.assertRaises(UnknownFormatError, bzrdir.BzrDir.open_unsupported, url)
157
def test_create_repository(self):
158
format = SampleBzrDirFormat()
159
old_format = bzrdir.BzrDirFormat.get_default_format()
160
bzrdir.BzrDirFormat.set_default_format(format)
162
repo = bzrdir.BzrDir.create_repository(self.get_url())
163
self.assertEqual('A repository', repo)
165
bzrdir.BzrDirFormat.set_default_format(old_format)
167
def test_create_repository_under_shared(self):
168
# an explicit create_repository always does so.
169
# we trust the format is right from the 'create_repository test'
170
old_format = bzrdir.BzrDirFormat.get_default_format()
171
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
173
self.make_repository('.', shared=True)
174
repo = bzrdir.BzrDir.create_repository(self.get_url('child'))
175
self.assertTrue(isinstance(repo, repository.Repository))
176
self.assertTrue(repo.bzrdir.root_transport.base.endswith('child/'))
178
bzrdir.BzrDirFormat.set_default_format(old_format)
180
def test_create_branch_and_repo_uses_default(self):
181
format = SampleBzrDirFormat()
182
old_format = bzrdir.BzrDirFormat.get_default_format()
183
bzrdir.BzrDirFormat.set_default_format(format)
185
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url())
186
self.assertTrue(isinstance(branch, SampleBranch))
188
bzrdir.BzrDirFormat.set_default_format(old_format)
190
def test_create_branch_and_repo_under_shared(self):
191
# creating a branch and repo in a shared repo uses the
193
old_format = bzrdir.BzrDirFormat.get_default_format()
194
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
196
self.make_repository('.', shared=True)
197
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'))
198
self.assertRaises(errors.NoRepositoryPresent,
199
branch.bzrdir.open_repository)
201
bzrdir.BzrDirFormat.set_default_format(old_format)
203
def test_create_branch_and_repo_under_shared_force_new(self):
204
# creating a branch and repo in a shared repo can be forced to
206
old_format = bzrdir.BzrDirFormat.get_default_format()
207
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
209
self.make_repository('.', shared=True)
210
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'),
212
branch.bzrdir.open_repository()
214
bzrdir.BzrDirFormat.set_default_format(old_format)
216
def test_create_standalone_working_tree(self):
217
format = SampleBzrDirFormat()
218
old_format = bzrdir.BzrDirFormat.get_default_format()
219
bzrdir.BzrDirFormat.set_default_format(format)
221
# note this is deliberately readonly, as this failure should
222
# occur before any writes.
223
self.assertRaises(errors.NotLocalUrl,
224
bzrdir.BzrDir.create_standalone_workingtree,
225
self.get_readonly_url())
226
tree = bzrdir.BzrDir.create_standalone_workingtree('.')
227
self.assertEqual('A tree', tree)
229
bzrdir.BzrDirFormat.set_default_format(old_format)
231
def test_create_standalone_working_tree_under_shared_repo(self):
232
# create standalone working tree always makes a repo.
233
old_format = bzrdir.BzrDirFormat.get_default_format()
234
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
236
self.make_repository('.', shared=True)
237
# note this is deliberately readonly, as this failure should
238
# occur before any writes.
239
self.assertRaises(errors.NotLocalUrl,
240
bzrdir.BzrDir.create_standalone_workingtree,
241
self.get_readonly_url('child'))
242
tree = bzrdir.BzrDir.create_standalone_workingtree('child')
243
tree.bzrdir.open_repository()
245
bzrdir.BzrDirFormat.set_default_format(old_format)
247
def test_create_branch_convenience(self):
248
# outside a repo the default convenience output is a repo+branch_tree
249
old_format = bzrdir.BzrDirFormat.get_default_format()
250
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
252
branch = bzrdir.BzrDir.create_branch_convenience('.')
253
branch.bzrdir.open_workingtree()
254
branch.bzrdir.open_repository()
256
bzrdir.BzrDirFormat.set_default_format(old_format)
258
def test_create_branch_convenience_under_shared_repo(self):
259
# inside a repo the default convenience output is a branch+ follow the
261
old_format = bzrdir.BzrDirFormat.get_default_format()
262
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
264
self.make_repository('.', shared=True)
265
branch = bzrdir.BzrDir.create_branch_convenience('child')
266
branch.bzrdir.open_workingtree()
267
self.assertRaises(errors.NoRepositoryPresent,
268
branch.bzrdir.open_repository)
270
bzrdir.BzrDirFormat.set_default_format(old_format)
272
def test_create_branch_convenience_under_shared_repo_force_no_tree(self):
273
# inside a repo the default convenience output is a branch+ follow the
274
# repo tree policy but we can override that
275
old_format = bzrdir.BzrDirFormat.get_default_format()
276
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
278
self.make_repository('.', shared=True)
279
branch = bzrdir.BzrDir.create_branch_convenience('child',
280
force_new_tree=False)
281
self.assertRaises(errors.NoWorkingTree,
282
branch.bzrdir.open_workingtree)
283
self.assertRaises(errors.NoRepositoryPresent,
284
branch.bzrdir.open_repository)
286
bzrdir.BzrDirFormat.set_default_format(old_format)
288
def test_create_branch_convenience_under_shared_repo_no_tree_policy(self):
289
# inside a repo the default convenience output is a branch+ follow the
291
old_format = bzrdir.BzrDirFormat.get_default_format()
292
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
294
repo = self.make_repository('.', shared=True)
295
repo.set_make_working_trees(False)
296
branch = bzrdir.BzrDir.create_branch_convenience('child')
297
self.assertRaises(errors.NoWorkingTree,
298
branch.bzrdir.open_workingtree)
299
self.assertRaises(errors.NoRepositoryPresent,
300
branch.bzrdir.open_repository)
302
bzrdir.BzrDirFormat.set_default_format(old_format)
304
def test_create_branch_convenience_under_shared_repo_no_tree_policy_force_tree(self):
305
# inside a repo the default convenience output is a branch+ follow the
306
# repo tree policy but we can override that
307
old_format = bzrdir.BzrDirFormat.get_default_format()
308
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
310
repo = self.make_repository('.', shared=True)
311
repo.set_make_working_trees(False)
312
branch = bzrdir.BzrDir.create_branch_convenience('child',
314
branch.bzrdir.open_workingtree()
315
self.assertRaises(errors.NoRepositoryPresent,
316
branch.bzrdir.open_repository)
318
bzrdir.BzrDirFormat.set_default_format(old_format)
320
def test_create_branch_convenience_under_shared_repo_force_new_repo(self):
321
# inside a repo the default convenience output is overridable to give
323
old_format = bzrdir.BzrDirFormat.get_default_format()
324
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
326
self.make_repository('.', shared=True)
327
branch = bzrdir.BzrDir.create_branch_convenience('child',
329
branch.bzrdir.open_repository()
330
branch.bzrdir.open_workingtree()
332
bzrdir.BzrDirFormat.set_default_format(old_format)
335
class ChrootedTests(TestCaseWithTransport):
336
"""A support class that provides readonly urls outside the local namespace.
338
This is done by checking if self.transport_server is a MemoryServer. if it
339
is then we are chrooted already, if it is not then an HttpServer is used
344
super(ChrootedTests, self).setUp()
345
if not self.transport_server == MemoryServer:
346
self.transport_readonly_server = HttpServer
348
def test_open_containing(self):
349
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
350
self.get_readonly_url(''))
351
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
352
self.get_readonly_url('g/p/q'))
353
control = bzrdir.BzrDir.create(self.get_url())
354
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url(''))
355
self.assertEqual('', relpath)
356
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url('g/p/q'))
357
self.assertEqual('g/p/q', relpath)
359
def test_open_containing_from_transport(self):
360
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
361
get_transport(self.get_readonly_url('')))
362
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing_from_transport,
363
get_transport(self.get_readonly_url('g/p/q')))
364
control = bzrdir.BzrDir.create(self.get_url())
365
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
366
get_transport(self.get_readonly_url('')))
367
self.assertEqual('', relpath)
368
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
369
get_transport(self.get_readonly_url('g/p/q')))
370
self.assertEqual('g/p/q', relpath)
373
class TestMeta1DirFormat(TestCaseWithTransport):
374
"""Tests specific to the meta1 dir format."""
376
def test_right_base_dirs(self):
377
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
379
branch_base = t.clone('branch').base
380
self.assertEqual(branch_base, dir.get_branch_transport(None).base)
381
self.assertEqual(branch_base,
382
dir.get_branch_transport(bzrlib.branch.BzrBranchFormat5()).base)
383
repository_base = t.clone('repository').base
384
self.assertEqual(repository_base, dir.get_repository_transport(None).base)
385
self.assertEqual(repository_base,
386
dir.get_repository_transport(repository.RepositoryFormat7()).base)
387
checkout_base = t.clone('checkout').base
388
self.assertEqual(checkout_base, dir.get_workingtree_transport(None).base)
389
self.assertEqual(checkout_base,
390
dir.get_workingtree_transport(workingtree.WorkingTreeFormat3()).base)
392
def test_meta1dir_uses_lockdir(self):
393
"""Meta1 format uses a LockDir to guard the whole directory, not a file."""
394
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
396
self.assertIsDirectory('branch-lock', t)
399
class TestFormat5(TestCaseWithTransport):
400
"""Tests specific to the version 5 bzrdir format."""
402
def test_same_lockfiles_between_tree_repo_branch(self):
403
# this checks that only a single lockfiles instance is created
404
# for format 5 objects
405
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
406
def check_dir_components_use_same_lock(dir):
407
ctrl_1 = dir.open_repository().control_files
408
ctrl_2 = dir.open_branch().control_files
409
ctrl_3 = dir.open_workingtree()._control_files
410
self.assertTrue(ctrl_1 is ctrl_2)
411
self.assertTrue(ctrl_2 is ctrl_3)
412
check_dir_components_use_same_lock(dir)
413
# and if we open it normally.
414
dir = bzrdir.BzrDir.open(self.get_url())
415
check_dir_components_use_same_lock(dir)
417
def test_can_convert(self):
418
# format 5 dirs are convertable
419
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
420
self.assertTrue(dir.can_convert_format())
422
def test_needs_conversion(self):
423
# format 5 dirs need a conversion if they are not the default.
424
# and they start of not the default.
425
old_format = bzrdir.BzrDirFormat.get_default_format()
426
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirFormat5())
428
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
429
self.assertFalse(dir.needs_format_conversion())
431
bzrdir.BzrDirFormat.set_default_format(old_format)
432
self.assertTrue(dir.needs_format_conversion())
435
class TestFormat6(TestCaseWithTransport):
436
"""Tests specific to the version 6 bzrdir format."""
438
def test_same_lockfiles_between_tree_repo_branch(self):
439
# this checks that only a single lockfiles instance is created
440
# for format 6 objects
441
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
442
def check_dir_components_use_same_lock(dir):
443
ctrl_1 = dir.open_repository().control_files
444
ctrl_2 = dir.open_branch().control_files
445
ctrl_3 = dir.open_workingtree()._control_files
446
self.assertTrue(ctrl_1 is ctrl_2)
447
self.assertTrue(ctrl_2 is ctrl_3)
448
check_dir_components_use_same_lock(dir)
449
# and if we open it normally.
450
dir = bzrdir.BzrDir.open(self.get_url())
451
check_dir_components_use_same_lock(dir)
453
def test_can_convert(self):
454
# format 6 dirs are convertable
455
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
456
self.assertTrue(dir.can_convert_format())
458
def test_needs_conversion(self):
459
# format 6 dirs need an conversion if they are not the default.
460
old_format = bzrdir.BzrDirFormat.get_default_format()
461
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
463
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
464
self.assertTrue(dir.needs_format_conversion())
466
bzrdir.BzrDirFormat.set_default_format(old_format)
467
self.assertFalse(dir.needs_format_conversion())
470
class NonLocalTests(TestCaseWithTransport):
471
"""Tests for bzrdir static behaviour on non local paths."""
474
super(NonLocalTests, self).setUp()
475
self.transport_server = MemoryServer
477
def test_create_branch_convenience(self):
478
# outside a repo the default convenience output is a repo+branch_tree
479
old_format = bzrdir.BzrDirFormat.get_default_format()
480
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
482
branch = bzrdir.BzrDir.create_branch_convenience(self.get_url('foo'))
483
self.assertRaises(errors.NoWorkingTree,
484
branch.bzrdir.open_workingtree)
485
branch.bzrdir.open_repository()
487
bzrdir.BzrDirFormat.set_default_format(old_format)
489
def test_create_branch_convenience_force_tree_not_local_fails(self):
490
# outside a repo the default convenience output is a repo+branch_tree
491
old_format = bzrdir.BzrDirFormat.get_default_format()
492
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
494
self.assertRaises(errors.NotLocalUrl,
495
bzrdir.BzrDir.create_branch_convenience,
498
t = get_transport(self.get_url('.'))
499
self.assertFalse(t.has('foo'))
501
bzrdir.BzrDirFormat.set_default_format(old_format)
503
def test_clone(self):
504
# clone into a nonlocal path works
505
old_format = bzrdir.BzrDirFormat.get_default_format()
506
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
508
branch = bzrdir.BzrDir.create_branch_convenience('local')
510
bzrdir.BzrDirFormat.set_default_format(old_format)
511
branch.bzrdir.open_workingtree()
512
result = branch.bzrdir.clone(self.get_url('remote'))
513
self.assertRaises(errors.NoWorkingTree,
514
result.open_workingtree)
516
result.open_repository()