1
# (C) 2005 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)
393
class TestFormat5(TestCaseWithTransport):
394
"""Tests specific to the version 5 bzrdir format."""
396
def test_same_lockfiles_between_tree_repo_branch(self):
397
# this checks that only a single lockfiles instance is created
398
# for format 5 objects
399
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
400
def check_dir_components_use_same_lock(dir):
401
ctrl_1 = dir.open_repository().control_files
402
ctrl_2 = dir.open_branch().control_files
403
ctrl_3 = dir.open_workingtree()._control_files
404
self.assertTrue(ctrl_1 is ctrl_2)
405
self.assertTrue(ctrl_2 is ctrl_3)
406
check_dir_components_use_same_lock(dir)
407
# and if we open it normally.
408
dir = bzrdir.BzrDir.open(self.get_url())
409
check_dir_components_use_same_lock(dir)
411
def test_can_convert(self):
412
# format 5 dirs are convertable
413
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
414
self.assertTrue(dir.can_convert_format())
416
def test_needs_conversion(self):
417
# format 5 dirs need a conversion if they are not the default.
418
# and they start of not the default.
419
old_format = bzrdir.BzrDirFormat.get_default_format()
420
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirFormat5())
422
dir = bzrdir.BzrDirFormat5().initialize(self.get_url())
423
self.assertFalse(dir.needs_format_conversion())
425
bzrdir.BzrDirFormat.set_default_format(old_format)
426
self.assertTrue(dir.needs_format_conversion())
429
class TestFormat6(TestCaseWithTransport):
430
"""Tests specific to the version 6 bzrdir format."""
432
def test_same_lockfiles_between_tree_repo_branch(self):
433
# this checks that only a single lockfiles instance is created
434
# for format 6 objects
435
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
436
def check_dir_components_use_same_lock(dir):
437
ctrl_1 = dir.open_repository().control_files
438
ctrl_2 = dir.open_branch().control_files
439
ctrl_3 = dir.open_workingtree()._control_files
440
self.assertTrue(ctrl_1 is ctrl_2)
441
self.assertTrue(ctrl_2 is ctrl_3)
442
check_dir_components_use_same_lock(dir)
443
# and if we open it normally.
444
dir = bzrdir.BzrDir.open(self.get_url())
445
check_dir_components_use_same_lock(dir)
447
def test_can_convert(self):
448
# format 6 dirs are convertable
449
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
450
self.assertTrue(dir.can_convert_format())
452
def test_needs_conversion(self):
453
# format 6 dirs need an conversion if they are not the default.
454
old_format = bzrdir.BzrDirFormat.get_default_format()
455
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
457
dir = bzrdir.BzrDirFormat6().initialize(self.get_url())
458
self.assertTrue(dir.needs_format_conversion())
460
bzrdir.BzrDirFormat.set_default_format(old_format)
461
self.assertFalse(dir.needs_format_conversion())
464
class NonLocalTests(TestCaseWithTransport):
465
"""Tests for bzrdir static behaviour on non local paths."""
468
super(NonLocalTests, self).setUp()
469
self.transport_server = MemoryServer
471
def test_create_branch_convenience(self):
472
# outside a repo the default convenience output is a repo+branch_tree
473
old_format = bzrdir.BzrDirFormat.get_default_format()
474
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
476
branch = bzrdir.BzrDir.create_branch_convenience(self.get_url('foo'))
477
self.assertRaises(errors.NoWorkingTree,
478
branch.bzrdir.open_workingtree)
479
branch.bzrdir.open_repository()
481
bzrdir.BzrDirFormat.set_default_format(old_format)
483
def test_create_branch_convenience_force_tree_not_local_fails(self):
484
# outside a repo the default convenience output is a repo+branch_tree
485
old_format = bzrdir.BzrDirFormat.get_default_format()
486
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
488
self.assertRaises(errors.NotLocalUrl,
489
bzrdir.BzrDir.create_branch_convenience,
492
t = get_transport(self.get_url('.'))
493
self.assertFalse(t.has('foo'))
495
bzrdir.BzrDirFormat.set_default_format(old_format)
497
def test_clone(self):
498
# clone into a nonlocal path works
499
old_format = bzrdir.BzrDirFormat.get_default_format()
500
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
502
branch = bzrdir.BzrDir.create_branch_convenience('local')
504
bzrdir.BzrDirFormat.set_default_format(old_format)
505
branch.bzrdir.open_workingtree()
506
result = branch.bzrdir.clone(self.get_url('remote'))
507
self.assertRaises(errors.NoWorkingTree,
508
result.open_workingtree)
510
result.open_repository()