1
# Copyright (C) 2006-2013, 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Tests for the BzrDir facility and any format specific tests.
19
For interface contract tests, see tests/per_bzr_dir.
35
revision as _mod_revision,
37
transport as _mod_transport,
49
import breezy.bzr.branch
50
from ..bzr.fullhistory import BzrBranchFormat5
51
from ..errors import (
53
NoColocatedBranchSupport,
55
UnsupportedFormatError,
59
TestCaseWithMemoryTransport,
60
TestCaseWithTransport,
67
from ..transport import (
71
from ..transport.http._urllib import HttpTransport_urllib
72
from ..transport.nosmart import NoSmartTransportDecorator
73
from ..transport.readonly import ReadonlyTransportDecorator
74
from ..bzr import knitrepo, knitpack_repo
77
class TestDefaultFormat(TestCase):
79
def test_get_set_default_format(self):
80
old_format = bzrdir.BzrDirFormat.get_default_format()
81
# default is BzrDirMetaFormat1
82
self.assertIsInstance(old_format, bzrdir.BzrDirMetaFormat1)
83
controldir.ControlDirFormat._set_default_format(SampleBzrDirFormat())
84
# creating a bzr dir should now create an instrumented dir.
86
result = bzrdir.BzrDir.create('memory:///')
87
self.assertIsInstance(result, SampleBzrDir)
89
controldir.ControlDirFormat._set_default_format(old_format)
90
self.assertEqual(old_format, bzrdir.BzrDirFormat.get_default_format())
93
class DeprecatedBzrDirFormat(bzrdir.BzrDirFormat):
94
"""A deprecated bzr dir format."""
97
class TestFormatRegistry(TestCase):
99
def make_format_registry(self):
100
my_format_registry = controldir.ControlDirFormatRegistry()
101
my_format_registry.register('deprecated', DeprecatedBzrDirFormat,
102
'Some format. Slower and unawesome and deprecated.',
104
my_format_registry.register_lazy('lazy', 'breezy.tests.test_bzrdir',
105
'DeprecatedBzrDirFormat', 'Format registered lazily',
107
bzr.register_metadir(my_format_registry, 'knit',
108
'breezy.bzr.knitrepo.RepositoryFormatKnit1',
109
'Format using knits',
111
my_format_registry.set_default('knit')
112
bzr.register_metadir(my_format_registry,
114
'breezy.bzr.knitrepo.RepositoryFormatKnit3',
115
'Experimental successor to knit. Use at your own risk.',
116
branch_format='breezy.bzr.branch.BzrBranchFormat6',
118
bzr.register_metadir(my_format_registry,
120
'breezy.bzr.knitrepo.RepositoryFormatKnit3',
121
'Experimental successor to knit. Use at your own risk.',
122
branch_format='breezy.bzr.branch.BzrBranchFormat6', hidden=True)
123
my_format_registry.register('hiddendeprecated', DeprecatedBzrDirFormat,
124
'Old format. Slower and does not support things. ', hidden=True)
125
my_format_registry.register_lazy('hiddenlazy', 'breezy.tests.test_bzrdir',
126
'DeprecatedBzrDirFormat', 'Format registered lazily',
127
deprecated=True, hidden=True)
128
return my_format_registry
130
def test_format_registry(self):
131
my_format_registry = self.make_format_registry()
132
my_bzrdir = my_format_registry.make_controldir('lazy')
133
self.assertIsInstance(my_bzrdir, DeprecatedBzrDirFormat)
134
my_bzrdir = my_format_registry.make_controldir('deprecated')
135
self.assertIsInstance(my_bzrdir, DeprecatedBzrDirFormat)
136
my_bzrdir = my_format_registry.make_controldir('default')
137
self.assertIsInstance(my_bzrdir.repository_format,
138
knitrepo.RepositoryFormatKnit1)
139
my_bzrdir = my_format_registry.make_controldir('knit')
140
self.assertIsInstance(my_bzrdir.repository_format,
141
knitrepo.RepositoryFormatKnit1)
142
my_bzrdir = my_format_registry.make_controldir('branch6')
143
self.assertIsInstance(my_bzrdir.get_branch_format(),
144
breezy.bzr.branch.BzrBranchFormat6)
146
def test_get_help(self):
147
my_format_registry = self.make_format_registry()
148
self.assertEqual('Format registered lazily',
149
my_format_registry.get_help('lazy'))
150
self.assertEqual('Format using knits',
151
my_format_registry.get_help('knit'))
152
self.assertEqual('Format using knits',
153
my_format_registry.get_help('default'))
154
self.assertEqual('Some format. Slower and unawesome and deprecated.',
155
my_format_registry.get_help('deprecated'))
157
def test_help_topic(self):
158
topics = help_topics.HelpTopicRegistry()
159
registry = self.make_format_registry()
160
topics.register('current-formats', registry.help_topic,
162
topics.register('other-formats', registry.help_topic,
164
new = topics.get_detail('current-formats')
165
rest = topics.get_detail('other-formats')
166
experimental, deprecated = rest.split('Deprecated formats')
167
self.assertContainsRe(new, 'formats-help')
168
self.assertContainsRe(new,
169
':knit:\n \\(native\\) \\(default\\) Format using knits\n')
170
self.assertContainsRe(experimental,
171
':branch6:\n \\(native\\) Experimental successor to knit')
172
self.assertContainsRe(deprecated,
173
':lazy:\n \\(native\\) Format registered lazily\n')
174
self.assertNotContainsRe(new, 'hidden')
176
def test_set_default_repository(self):
177
default_factory = controldir.format_registry.get('default')
178
old_default = [k for k, v in controldir.format_registry.iteritems()
179
if v == default_factory and k != 'default'][0]
180
controldir.format_registry.set_default_repository('dirstate-with-subtree')
182
self.assertIs(controldir.format_registry.get('dirstate-with-subtree'),
183
controldir.format_registry.get('default'))
185
repository.format_registry.get_default().__class__,
186
knitrepo.RepositoryFormatKnit3)
188
controldir.format_registry.set_default_repository(old_default)
190
def test_aliases(self):
191
a_registry = controldir.ControlDirFormatRegistry()
192
a_registry.register('deprecated', DeprecatedBzrDirFormat,
193
'Old format. Slower and does not support stuff',
195
a_registry.register('deprecatedalias', DeprecatedBzrDirFormat,
196
'Old format. Slower and does not support stuff',
197
deprecated=True, alias=True)
198
self.assertEqual(frozenset(['deprecatedalias']), a_registry.aliases())
201
class SampleBranch(breezy.branch.Branch):
202
"""A dummy branch for guess what, dummy use."""
204
def __init__(self, dir):
205
self.controldir = dir
208
class SampleRepository(breezy.repository.Repository):
211
def __init__(self, dir):
212
self.controldir = dir
215
class SampleBzrDir(bzrdir.BzrDir):
216
"""A sample BzrDir implementation to allow testing static methods."""
218
def create_repository(self, shared=False):
219
"""See ControlDir.create_repository."""
220
return "A repository"
222
def open_repository(self):
223
"""See ControlDir.open_repository."""
224
return SampleRepository(self)
226
def create_branch(self, name=None):
227
"""See ControlDir.create_branch."""
229
raise NoColocatedBranchSupport(self)
230
return SampleBranch(self)
232
def create_workingtree(self):
233
"""See ControlDir.create_workingtree."""
237
class SampleBzrDirFormat(bzrdir.BzrDirFormat):
240
this format is initializable, unsupported to aid in testing the
241
open and open_downlevel routines.
244
def get_format_string(self):
245
"""See BzrDirFormat.get_format_string()."""
246
return "Sample .bzr dir format."
248
def initialize_on_transport(self, t):
249
"""Create a bzr dir."""
251
t.put_bytes('.bzr/branch-format', self.get_format_string())
252
return SampleBzrDir(t, self)
254
def is_supported(self):
257
def open(self, transport, _found=None):
258
return "opened branch."
261
def from_string(cls, format_string):
265
class BzrDirFormatTest1(bzrdir.BzrDirMetaFormat1):
268
def get_format_string():
269
return "Test format 1"
272
class BzrDirFormatTest2(bzrdir.BzrDirMetaFormat1):
275
def get_format_string():
276
return "Test format 2"
279
class TestBzrDirFormat(TestCaseWithTransport):
280
"""Tests for the BzrDirFormat facility."""
282
def test_find_format(self):
283
# is the right format object found for a branch?
284
# create a branch with a few known format objects.
285
bzr.BzrProber.formats.register(BzrDirFormatTest1.get_format_string(),
287
self.addCleanup(bzr.BzrProber.formats.remove,
288
BzrDirFormatTest1.get_format_string())
289
bzr.BzrProber.formats.register(BzrDirFormatTest2.get_format_string(),
291
self.addCleanup(bzr.BzrProber.formats.remove,
292
BzrDirFormatTest2.get_format_string())
293
t = self.get_transport()
294
self.build_tree(["foo/", "bar/"], transport=t)
295
def check_format(format, url):
296
format.initialize(url)
297
t = _mod_transport.get_transport_from_path(url)
298
found_format = bzrdir.BzrDirFormat.find_format(t)
299
self.assertIsInstance(found_format, format.__class__)
300
check_format(BzrDirFormatTest1(), "foo")
301
check_format(BzrDirFormatTest2(), "bar")
303
def test_find_format_nothing_there(self):
304
self.assertRaises(NotBranchError,
305
bzrdir.BzrDirFormat.find_format,
306
_mod_transport.get_transport_from_path('.'))
308
def test_find_format_unknown_format(self):
309
t = self.get_transport()
311
t.put_bytes('.bzr/branch-format', '')
312
self.assertRaises(UnknownFormatError,
313
bzrdir.BzrDirFormat.find_format,
314
_mod_transport.get_transport_from_path('.'))
316
def test_register_unregister_format(self):
317
format = SampleBzrDirFormat()
320
format.initialize(url)
321
# register a format for it.
322
bzr.BzrProber.formats.register(format.get_format_string(), format)
323
# which bzrdir.Open will refuse (not supported)
324
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open, url)
325
# which bzrdir.open_containing will refuse (not supported)
326
self.assertRaises(UnsupportedFormatError, bzrdir.BzrDir.open_containing, url)
327
# but open_downlevel will work
328
t = _mod_transport.get_transport_from_url(url)
329
self.assertEqual(format.open(t), bzrdir.BzrDir.open_unsupported(url))
330
# unregister the format
331
bzr.BzrProber.formats.remove(format.get_format_string())
332
# now open_downlevel should fail too.
333
self.assertRaises(UnknownFormatError, bzrdir.BzrDir.open_unsupported, url)
335
def test_create_branch_and_repo_uses_default(self):
336
format = SampleBzrDirFormat()
337
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url(),
339
self.assertTrue(isinstance(branch, SampleBranch))
341
def test_create_branch_and_repo_under_shared(self):
342
# creating a branch and repo in a shared repo uses the
344
format = controldir.format_registry.make_controldir('knit')
345
self.make_repository('.', shared=True, format=format)
346
branch = bzrdir.BzrDir.create_branch_and_repo(
347
self.get_url('child'), format=format)
348
self.assertRaises(errors.NoRepositoryPresent,
349
branch.controldir.open_repository)
351
def test_create_branch_and_repo_under_shared_force_new(self):
352
# creating a branch and repo in a shared repo can be forced to
354
format = controldir.format_registry.make_controldir('knit')
355
self.make_repository('.', shared=True, format=format)
356
branch = bzrdir.BzrDir.create_branch_and_repo(self.get_url('child'),
359
branch.controldir.open_repository()
361
def test_create_standalone_working_tree(self):
362
format = SampleBzrDirFormat()
363
# note this is deliberately readonly, as this failure should
364
# occur before any writes.
365
self.assertRaises(errors.NotLocalUrl,
366
bzrdir.BzrDir.create_standalone_workingtree,
367
self.get_readonly_url(), format=format)
368
tree = bzrdir.BzrDir.create_standalone_workingtree('.',
370
self.assertEqual('A tree', tree)
372
def test_create_standalone_working_tree_under_shared_repo(self):
373
# create standalone working tree always makes a repo.
374
format = controldir.format_registry.make_controldir('knit')
375
self.make_repository('.', shared=True, format=format)
376
# note this is deliberately readonly, as this failure should
377
# occur before any writes.
378
self.assertRaises(errors.NotLocalUrl,
379
bzrdir.BzrDir.create_standalone_workingtree,
380
self.get_readonly_url('child'), format=format)
381
tree = bzrdir.BzrDir.create_standalone_workingtree('child',
383
tree.controldir.open_repository()
385
def test_create_branch_convenience(self):
386
# outside a repo the default convenience output is a repo+branch_tree
387
format = controldir.format_registry.make_controldir('knit')
388
branch = bzrdir.BzrDir.create_branch_convenience('.', format=format)
389
branch.controldir.open_workingtree()
390
branch.controldir.open_repository()
392
def test_create_branch_convenience_possible_transports(self):
393
"""Check that the optional 'possible_transports' is recognized"""
394
format = controldir.format_registry.make_controldir('knit')
395
t = self.get_transport()
396
branch = bzrdir.BzrDir.create_branch_convenience(
397
'.', format=format, possible_transports=[t])
398
branch.controldir.open_workingtree()
399
branch.controldir.open_repository()
401
def test_create_branch_convenience_root(self):
402
"""Creating a branch at the root of a fs should work."""
403
self.vfs_transport_factory = memory.MemoryServer
404
# outside a repo the default convenience output is a repo+branch_tree
405
format = controldir.format_registry.make_controldir('knit')
406
branch = bzrdir.BzrDir.create_branch_convenience(self.get_url(),
408
self.assertRaises(errors.NoWorkingTree,
409
branch.controldir.open_workingtree)
410
branch.controldir.open_repository()
412
def test_create_branch_convenience_under_shared_repo(self):
413
# inside a repo the default convenience output is a branch+ follow the
415
format = controldir.format_registry.make_controldir('knit')
416
self.make_repository('.', shared=True, format=format)
417
branch = bzrdir.BzrDir.create_branch_convenience('child',
419
branch.controldir.open_workingtree()
420
self.assertRaises(errors.NoRepositoryPresent,
421
branch.controldir.open_repository)
423
def test_create_branch_convenience_under_shared_repo_force_no_tree(self):
424
# inside a repo the default convenience output is a branch+ follow the
425
# repo tree policy but we can override that
426
format = controldir.format_registry.make_controldir('knit')
427
self.make_repository('.', shared=True, format=format)
428
branch = bzrdir.BzrDir.create_branch_convenience('child',
429
force_new_tree=False, format=format)
430
self.assertRaises(errors.NoWorkingTree,
431
branch.controldir.open_workingtree)
432
self.assertRaises(errors.NoRepositoryPresent,
433
branch.controldir.open_repository)
435
def test_create_branch_convenience_under_shared_repo_no_tree_policy(self):
436
# inside a repo the default convenience output is a branch+ follow the
438
format = controldir.format_registry.make_controldir('knit')
439
repo = self.make_repository('.', shared=True, format=format)
440
repo.set_make_working_trees(False)
441
branch = bzrdir.BzrDir.create_branch_convenience('child',
443
self.assertRaises(errors.NoWorkingTree,
444
branch.controldir.open_workingtree)
445
self.assertRaises(errors.NoRepositoryPresent,
446
branch.controldir.open_repository)
448
def test_create_branch_convenience_under_shared_repo_no_tree_policy_force_tree(self):
449
# inside a repo the default convenience output is a branch+ follow the
450
# repo tree policy but we can override that
451
format = controldir.format_registry.make_controldir('knit')
452
repo = self.make_repository('.', shared=True, format=format)
453
repo.set_make_working_trees(False)
454
branch = bzrdir.BzrDir.create_branch_convenience('child',
455
force_new_tree=True, format=format)
456
branch.controldir.open_workingtree()
457
self.assertRaises(errors.NoRepositoryPresent,
458
branch.controldir.open_repository)
460
def test_create_branch_convenience_under_shared_repo_force_new_repo(self):
461
# inside a repo the default convenience output is overridable to give
463
format = controldir.format_registry.make_controldir('knit')
464
self.make_repository('.', shared=True, format=format)
465
branch = bzrdir.BzrDir.create_branch_convenience('child',
466
force_new_repo=True, format=format)
467
branch.controldir.open_repository()
468
branch.controldir.open_workingtree()
471
class TestRepositoryAcquisitionPolicy(TestCaseWithTransport):
473
def test_acquire_repository_standalone(self):
474
"""The default acquisition policy should create a standalone branch."""
475
my_bzrdir = self.make_controldir('.')
476
repo_policy = my_bzrdir.determine_repository_policy()
477
repo, is_new = repo_policy.acquire_repository()
478
self.assertEqual(repo.controldir.root_transport.base,
479
my_bzrdir.root_transport.base)
480
self.assertFalse(repo.is_shared())
482
def test_determine_stacking_policy(self):
483
parent_bzrdir = self.make_controldir('.')
484
child_bzrdir = self.make_controldir('child')
485
parent_bzrdir.get_config().set_default_stack_on('http://example.org')
486
repo_policy = child_bzrdir.determine_repository_policy()
487
self.assertEqual('http://example.org', repo_policy._stack_on)
489
def test_determine_stacking_policy_relative(self):
490
parent_bzrdir = self.make_controldir('.')
491
child_bzrdir = self.make_controldir('child')
492
parent_bzrdir.get_config().set_default_stack_on('child2')
493
repo_policy = child_bzrdir.determine_repository_policy()
494
self.assertEqual('child2', repo_policy._stack_on)
495
self.assertEqual(parent_bzrdir.root_transport.base,
496
repo_policy._stack_on_pwd)
498
def prepare_default_stacking(self, child_format='1.6'):
499
parent_bzrdir = self.make_controldir('.')
500
child_branch = self.make_branch('child', format=child_format)
501
parent_bzrdir.get_config().set_default_stack_on(child_branch.base)
502
new_child_transport = parent_bzrdir.transport.clone('child2')
503
return child_branch, new_child_transport
505
def test_clone_on_transport_obeys_stacking_policy(self):
506
child_branch, new_child_transport = self.prepare_default_stacking()
507
new_child = child_branch.controldir.clone_on_transport(new_child_transport)
508
self.assertEqual(child_branch.base,
509
new_child.open_branch().get_stacked_on_url())
511
def test_default_stacking_with_stackable_branch_unstackable_repo(self):
512
# Make stackable source branch with an unstackable repo format.
513
source_bzrdir = self.make_controldir('source')
514
knitpack_repo.RepositoryFormatKnitPack1().initialize(source_bzrdir)
515
source_branch = breezy.bzr.branch.BzrBranchFormat7().initialize(
517
# Make a directory with a default stacking policy
518
parent_bzrdir = self.make_controldir('parent')
519
stacked_on = self.make_branch('parent/stacked-on', format='pack-0.92')
520
parent_bzrdir.get_config().set_default_stack_on(stacked_on.base)
521
# Clone source into directory
522
target = source_bzrdir.clone(self.get_url('parent/target'))
524
def test_format_initialize_on_transport_ex_stacked_on(self):
525
# trunk is a stackable format. Note that its in the same server area
526
# which is what launchpad does, but not sufficient to exercise the
528
trunk = self.make_branch('trunk', format='1.9')
529
t = self.get_transport('stacked')
530
old_fmt = controldir.format_registry.make_controldir('pack-0.92')
531
repo_name = old_fmt.repository_format.network_name()
532
# Should end up with a 1.9 format (stackable)
533
repo, control, require_stacking, repo_policy = \
534
old_fmt.initialize_on_transport_ex(t,
535
repo_format_name=repo_name, stacked_on='../trunk',
538
# Repositories are open write-locked
539
self.assertTrue(repo.is_write_locked())
540
self.addCleanup(repo.unlock)
542
repo = control.open_repository()
543
self.assertIsInstance(control, bzrdir.BzrDir)
544
opened = bzrdir.BzrDir.open(t.base)
545
if not isinstance(old_fmt, remote.RemoteBzrDirFormat):
546
self.assertEqual(control._format.network_name(),
547
old_fmt.network_name())
548
self.assertEqual(control._format.network_name(),
549
opened._format.network_name())
550
self.assertEqual(control.__class__, opened.__class__)
551
self.assertLength(1, repo._fallback_repositories)
553
def test_sprout_obeys_stacking_policy(self):
554
child_branch, new_child_transport = self.prepare_default_stacking()
555
new_child = child_branch.controldir.sprout(new_child_transport.base)
556
self.assertEqual(child_branch.base,
557
new_child.open_branch().get_stacked_on_url())
559
def test_clone_ignores_policy_for_unsupported_formats(self):
560
child_branch, new_child_transport = self.prepare_default_stacking(
561
child_format='pack-0.92')
562
new_child = child_branch.controldir.clone_on_transport(new_child_transport)
563
self.assertRaises(branch.UnstackableBranchFormat,
564
new_child.open_branch().get_stacked_on_url)
566
def test_sprout_ignores_policy_for_unsupported_formats(self):
567
child_branch, new_child_transport = self.prepare_default_stacking(
568
child_format='pack-0.92')
569
new_child = child_branch.controldir.sprout(new_child_transport.base)
570
self.assertRaises(branch.UnstackableBranchFormat,
571
new_child.open_branch().get_stacked_on_url)
573
def test_sprout_upgrades_format_if_stacked_specified(self):
574
child_branch, new_child_transport = self.prepare_default_stacking(
575
child_format='pack-0.92')
576
new_child = child_branch.controldir.sprout(new_child_transport.base,
578
self.assertEqual(child_branch.controldir.root_transport.base,
579
new_child.open_branch().get_stacked_on_url())
580
repo = new_child.open_repository()
581
self.assertTrue(repo._format.supports_external_lookups)
582
self.assertFalse(repo.supports_rich_root())
584
def test_clone_on_transport_upgrades_format_if_stacked_on_specified(self):
585
child_branch, new_child_transport = self.prepare_default_stacking(
586
child_format='pack-0.92')
587
new_child = child_branch.controldir.clone_on_transport(new_child_transport,
588
stacked_on=child_branch.controldir.root_transport.base)
589
self.assertEqual(child_branch.controldir.root_transport.base,
590
new_child.open_branch().get_stacked_on_url())
591
repo = new_child.open_repository()
592
self.assertTrue(repo._format.supports_external_lookups)
593
self.assertFalse(repo.supports_rich_root())
595
def test_sprout_upgrades_to_rich_root_format_if_needed(self):
596
child_branch, new_child_transport = self.prepare_default_stacking(
597
child_format='rich-root-pack')
598
new_child = child_branch.controldir.sprout(new_child_transport.base,
600
repo = new_child.open_repository()
601
self.assertTrue(repo._format.supports_external_lookups)
602
self.assertTrue(repo.supports_rich_root())
604
def test_add_fallback_repo_handles_absolute_urls(self):
605
stack_on = self.make_branch('stack_on', format='1.6')
606
repo = self.make_repository('repo', format='1.6')
607
policy = bzrdir.UseExistingRepository(repo, stack_on.base)
608
policy._add_fallback(repo)
610
def test_add_fallback_repo_handles_relative_urls(self):
611
stack_on = self.make_branch('stack_on', format='1.6')
612
repo = self.make_repository('repo', format='1.6')
613
policy = bzrdir.UseExistingRepository(repo, '.', stack_on.base)
614
policy._add_fallback(repo)
616
def test_configure_relative_branch_stacking_url(self):
617
stack_on = self.make_branch('stack_on', format='1.6')
618
stacked = self.make_branch('stack_on/stacked', format='1.6')
619
policy = bzrdir.UseExistingRepository(stacked.repository,
621
policy.configure_branch(stacked)
622
self.assertEqual('..', stacked.get_stacked_on_url())
624
def test_relative_branch_stacking_to_absolute(self):
625
stack_on = self.make_branch('stack_on', format='1.6')
626
stacked = self.make_branch('stack_on/stacked', format='1.6')
627
policy = bzrdir.UseExistingRepository(stacked.repository,
628
'.', self.get_readonly_url('stack_on'))
629
policy.configure_branch(stacked)
630
self.assertEqual(self.get_readonly_url('stack_on'),
631
stacked.get_stacked_on_url())
634
class ChrootedTests(TestCaseWithTransport):
635
"""A support class that provides readonly urls outside the local namespace.
637
This is done by checking if self.transport_server is a MemoryServer. if it
638
is then we are chrooted already, if it is not then an HttpServer is used
643
super(ChrootedTests, self).setUp()
644
if not self.vfs_transport_factory == memory.MemoryServer:
645
self.transport_readonly_server = http_server.HttpServer
647
def local_branch_path(self, branch):
648
return os.path.realpath(urlutils.local_path_from_url(branch.base))
650
def test_open_containing(self):
651
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
652
self.get_readonly_url(''))
653
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_containing,
654
self.get_readonly_url('g/p/q'))
655
control = bzrdir.BzrDir.create(self.get_url())
656
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url(''))
657
self.assertEqual('', relpath)
658
branch, relpath = bzrdir.BzrDir.open_containing(self.get_readonly_url('g/p/q'))
659
self.assertEqual('g/p/q', relpath)
661
def test_open_containing_tree_branch_or_repository_empty(self):
662
self.assertRaises(errors.NotBranchError,
663
bzrdir.BzrDir.open_containing_tree_branch_or_repository,
664
self.get_readonly_url(''))
666
def test_open_containing_tree_branch_or_repository_all(self):
667
self.make_branch_and_tree('topdir')
668
tree, branch, repo, relpath = \
669
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
671
self.assertEqual(os.path.realpath('topdir'),
672
os.path.realpath(tree.basedir))
673
self.assertEqual(os.path.realpath('topdir'),
674
self.local_branch_path(branch))
676
osutils.realpath(os.path.join('topdir', '.bzr', 'repository')),
677
repo.controldir.transport.local_abspath('repository'))
678
self.assertEqual(relpath, 'foo')
680
def test_open_containing_tree_branch_or_repository_no_tree(self):
681
self.make_branch('branch')
682
tree, branch, repo, relpath = \
683
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
685
self.assertEqual(tree, None)
686
self.assertEqual(os.path.realpath('branch'),
687
self.local_branch_path(branch))
689
osutils.realpath(os.path.join('branch', '.bzr', 'repository')),
690
repo.controldir.transport.local_abspath('repository'))
691
self.assertEqual(relpath, 'foo')
693
def test_open_containing_tree_branch_or_repository_repo(self):
694
self.make_repository('repo')
695
tree, branch, repo, relpath = \
696
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
698
self.assertEqual(tree, None)
699
self.assertEqual(branch, None)
701
osutils.realpath(os.path.join('repo', '.bzr', 'repository')),
702
repo.controldir.transport.local_abspath('repository'))
703
self.assertEqual(relpath, '')
705
def test_open_containing_tree_branch_or_repository_shared_repo(self):
706
self.make_repository('shared', shared=True)
707
bzrdir.BzrDir.create_branch_convenience('shared/branch',
708
force_new_tree=False)
709
tree, branch, repo, relpath = \
710
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
712
self.assertEqual(tree, None)
713
self.assertEqual(os.path.realpath('shared/branch'),
714
self.local_branch_path(branch))
716
osutils.realpath(os.path.join('shared', '.bzr', 'repository')),
717
repo.controldir.transport.local_abspath('repository'))
718
self.assertEqual(relpath, '')
720
def test_open_containing_tree_branch_or_repository_branch_subdir(self):
721
self.make_branch_and_tree('foo')
722
self.build_tree(['foo/bar/'])
723
tree, branch, repo, relpath = \
724
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
726
self.assertEqual(os.path.realpath('foo'),
727
os.path.realpath(tree.basedir))
728
self.assertEqual(os.path.realpath('foo'),
729
self.local_branch_path(branch))
731
osutils.realpath(os.path.join('foo', '.bzr', 'repository')),
732
repo.controldir.transport.local_abspath('repository'))
733
self.assertEqual(relpath, 'bar')
735
def test_open_containing_tree_branch_or_repository_repo_subdir(self):
736
self.make_repository('bar')
737
self.build_tree(['bar/baz/'])
738
tree, branch, repo, relpath = \
739
bzrdir.BzrDir.open_containing_tree_branch_or_repository(
741
self.assertEqual(tree, None)
742
self.assertEqual(branch, None)
744
osutils.realpath(os.path.join('bar', '.bzr', 'repository')),
745
repo.controldir.transport.local_abspath('repository'))
746
self.assertEqual(relpath, 'baz')
748
def test_open_containing_from_transport(self):
749
self.assertRaises(NotBranchError,
750
bzrdir.BzrDir.open_containing_from_transport,
751
_mod_transport.get_transport_from_url(self.get_readonly_url('')))
752
self.assertRaises(NotBranchError,
753
bzrdir.BzrDir.open_containing_from_transport,
754
_mod_transport.get_transport_from_url(
755
self.get_readonly_url('g/p/q')))
756
control = bzrdir.BzrDir.create(self.get_url())
757
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
758
_mod_transport.get_transport_from_url(
759
self.get_readonly_url('')))
760
self.assertEqual('', relpath)
761
branch, relpath = bzrdir.BzrDir.open_containing_from_transport(
762
_mod_transport.get_transport_from_url(
763
self.get_readonly_url('g/p/q')))
764
self.assertEqual('g/p/q', relpath)
766
def test_open_containing_tree_or_branch(self):
767
self.make_branch_and_tree('topdir')
768
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
770
self.assertEqual(os.path.realpath('topdir'),
771
os.path.realpath(tree.basedir))
772
self.assertEqual(os.path.realpath('topdir'),
773
self.local_branch_path(branch))
774
self.assertIs(tree.controldir, branch.controldir)
775
self.assertEqual('foo', relpath)
776
# opening from non-local should not return the tree
777
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
778
self.get_readonly_url('topdir/foo'))
779
self.assertEqual(None, tree)
780
self.assertEqual('foo', relpath)
782
self.make_branch('topdir/foo')
783
tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
785
self.assertIs(tree, None)
786
self.assertEqual(os.path.realpath('topdir/foo'),
787
self.local_branch_path(branch))
788
self.assertEqual('', relpath)
790
def test_open_tree_or_branch(self):
791
self.make_branch_and_tree('topdir')
792
tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir')
793
self.assertEqual(os.path.realpath('topdir'),
794
os.path.realpath(tree.basedir))
795
self.assertEqual(os.path.realpath('topdir'),
796
self.local_branch_path(branch))
797
self.assertIs(tree.controldir, branch.controldir)
798
# opening from non-local should not return the tree
799
tree, branch = bzrdir.BzrDir.open_tree_or_branch(
800
self.get_readonly_url('topdir'))
801
self.assertEqual(None, tree)
803
self.make_branch('topdir/foo')
804
tree, branch = bzrdir.BzrDir.open_tree_or_branch('topdir/foo')
805
self.assertIs(tree, None)
806
self.assertEqual(os.path.realpath('topdir/foo'),
807
self.local_branch_path(branch))
809
def test_open_from_transport(self):
810
# transport pointing at bzrdir should give a bzrdir with root transport
811
# set to the given transport
812
control = bzrdir.BzrDir.create(self.get_url())
813
t = self.get_transport()
814
opened_bzrdir = bzrdir.BzrDir.open_from_transport(t)
815
self.assertEqual(t.base, opened_bzrdir.root_transport.base)
816
self.assertIsInstance(opened_bzrdir, bzrdir.BzrDir)
818
def test_open_from_transport_no_bzrdir(self):
819
t = self.get_transport()
820
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport, t)
822
def test_open_from_transport_bzrdir_in_parent(self):
823
control = bzrdir.BzrDir.create(self.get_url())
824
t = self.get_transport()
826
t = t.clone('subdir')
827
self.assertRaises(NotBranchError, bzrdir.BzrDir.open_from_transport, t)
829
def test_sprout_recursive(self):
830
tree = self.make_branch_and_tree('tree1',
831
format='development-subtree')
832
sub_tree = self.make_branch_and_tree('tree1/subtree',
833
format='development-subtree')
834
sub_tree.set_root_id('subtree-root')
835
tree.add_reference(sub_tree)
836
self.build_tree(['tree1/subtree/file'])
838
tree.commit('Initial commit')
839
tree2 = tree.controldir.sprout('tree2').open_workingtree()
841
self.addCleanup(tree2.unlock)
842
self.assertPathExists('tree2/subtree/file')
843
self.assertEqual('tree-reference', tree2.kind('subtree-root'))
845
def test_cloning_metadir(self):
846
"""Ensure that cloning metadir is suitable"""
847
bzrdir = self.make_controldir('bzrdir')
848
bzrdir.cloning_metadir()
849
branch = self.make_branch('branch', format='knit')
850
format = branch.controldir.cloning_metadir()
851
self.assertIsInstance(format.workingtree_format,
852
workingtree_4.WorkingTreeFormat6)
854
def test_sprout_recursive_treeless(self):
855
tree = self.make_branch_and_tree('tree1',
856
format='development-subtree')
857
sub_tree = self.make_branch_and_tree('tree1/subtree',
858
format='development-subtree')
859
tree.add_reference(sub_tree)
860
self.build_tree(['tree1/subtree/file'])
862
tree.commit('Initial commit')
863
# The following line force the orhaning to reveal bug #634470
864
tree.branch.get_config_stack().set(
865
'bzr.transform.orphan_policy', 'move')
866
tree.controldir.destroy_workingtree()
867
# FIXME: subtree/.bzr is left here which allows the test to pass (or
868
# fail :-( ) -- vila 20100909
869
repo = self.make_repository('repo', shared=True,
870
format='development-subtree')
871
repo.set_make_working_trees(False)
872
# FIXME: we just deleted the workingtree and now we want to use it ????
873
# At a minimum, we should use tree.branch below (but this fails too
874
# currently) or stop calling this test 'treeless'. Specifically, I've
875
# turn the line below into an assertRaises when 'subtree/.bzr' is
876
# orphaned and sprout tries to access the branch there (which is left
877
# by bzrdir.BzrDirMeta1.destroy_workingtree when it ignores the
878
# [DeletingParent('Not deleting', u'subtree', None)] conflict). See bug
879
# #634470. -- vila 20100909
880
self.assertRaises(errors.NotBranchError,
881
tree.controldir.sprout, 'repo/tree2')
882
# self.assertPathExists('repo/tree2/subtree')
883
# self.assertPathDoesNotExist('repo/tree2/subtree/file')
885
def make_foo_bar_baz(self):
886
foo = bzrdir.BzrDir.create_branch_convenience('foo').controldir
887
bar = self.make_branch('foo/bar').controldir
888
baz = self.make_branch('baz').controldir
891
def test_find_controldirs(self):
892
foo, bar, baz = self.make_foo_bar_baz()
893
t = self.get_transport()
894
self.assertEqualBzrdirs([baz, foo, bar], bzrdir.BzrDir.find_controldirs(t))
896
def make_fake_permission_denied_transport(self, transport, paths):
897
"""Create a transport that raises PermissionDenied for some paths."""
900
raise errors.PermissionDenied(path)
902
path_filter_server = pathfilter.PathFilteringServer(transport, filter)
903
path_filter_server.start_server()
904
self.addCleanup(path_filter_server.stop_server)
905
path_filter_transport = pathfilter.PathFilteringTransport(
906
path_filter_server, '.')
907
return (path_filter_server, path_filter_transport)
909
def assertBranchUrlsEndWith(self, expect_url_suffix, actual_bzrdirs):
910
"""Check that each branch url ends with the given suffix."""
911
for actual_bzrdir in actual_bzrdirs:
912
self.assertEndsWith(actual_bzrdir.user_url, expect_url_suffix)
914
def test_find_controldirs_permission_denied(self):
915
foo, bar, baz = self.make_foo_bar_baz()
916
t = self.get_transport()
917
path_filter_server, path_filter_transport = \
918
self.make_fake_permission_denied_transport(t, ['foo'])
920
self.assertBranchUrlsEndWith('/baz/',
921
bzrdir.BzrDir.find_controldirs(path_filter_transport))
923
smart_transport = self.make_smart_server('.',
924
backing_server=path_filter_server)
925
self.assertBranchUrlsEndWith('/baz/',
926
bzrdir.BzrDir.find_controldirs(smart_transport))
928
def test_find_controldirs_list_current(self):
929
def list_current(transport):
930
return [s for s in transport.list_dir('') if s != 'baz']
932
foo, bar, baz = self.make_foo_bar_baz()
933
t = self.get_transport()
934
self.assertEqualBzrdirs(
936
bzrdir.BzrDir.find_controldirs(t, list_current=list_current))
938
def test_find_controldirs_evaluate(self):
939
def evaluate(bzrdir):
941
repo = bzrdir.open_repository()
942
except errors.NoRepositoryPresent:
943
return True, bzrdir.root_transport.base
945
return False, bzrdir.root_transport.base
947
foo, bar, baz = self.make_foo_bar_baz()
948
t = self.get_transport()
949
self.assertEqual([baz.root_transport.base, foo.root_transport.base],
950
list(bzrdir.BzrDir.find_controldirs(t, evaluate=evaluate)))
952
def assertEqualBzrdirs(self, first, second):
954
second = list(second)
955
self.assertEqual(len(first), len(second))
956
for x, y in zip(first, second):
957
self.assertEqual(x.root_transport.base, y.root_transport.base)
959
def test_find_branches(self):
960
root = self.make_repository('', shared=True)
961
foo, bar, baz = self.make_foo_bar_baz()
962
qux = self.make_controldir('foo/qux')
963
t = self.get_transport()
964
branches = bzrdir.BzrDir.find_branches(t)
965
self.assertEqual(baz.root_transport.base, branches[0].base)
966
self.assertEqual(foo.root_transport.base, branches[1].base)
967
self.assertEqual(bar.root_transport.base, branches[2].base)
969
# ensure this works without a top-level repo
970
branches = bzrdir.BzrDir.find_branches(t.clone('foo'))
971
self.assertEqual(foo.root_transport.base, branches[0].base)
972
self.assertEqual(bar.root_transport.base, branches[1].base)
975
class TestMissingRepoBranchesSkipped(TestCaseWithMemoryTransport):
977
def test_find_controldirs_missing_repo(self):
978
t = self.get_transport()
979
arepo = self.make_repository('arepo', shared=True)
980
abranch_url = arepo.user_url + '/abranch'
981
abranch = bzrdir.BzrDir.create(abranch_url).create_branch()
982
t.delete_tree('arepo/.bzr')
983
self.assertRaises(errors.NoRepositoryPresent,
984
branch.Branch.open, abranch_url)
985
self.make_branch('baz')
986
for actual_bzrdir in bzrdir.BzrDir.find_branches(t):
987
self.assertEndsWith(actual_bzrdir.user_url, '/baz/')
990
class TestMeta1DirFormat(TestCaseWithTransport):
991
"""Tests specific to the meta1 dir format."""
993
def test_right_base_dirs(self):
994
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
996
branch_base = t.clone('branch').base
997
self.assertEqual(branch_base, dir.get_branch_transport(None).base)
998
self.assertEqual(branch_base,
999
dir.get_branch_transport(BzrBranchFormat5()).base)
1000
repository_base = t.clone('repository').base
1001
self.assertEqual(repository_base, dir.get_repository_transport(None).base)
1002
repository_format = repository.format_registry.get_default()
1003
self.assertEqual(repository_base,
1004
dir.get_repository_transport(repository_format).base)
1005
checkout_base = t.clone('checkout').base
1006
self.assertEqual(checkout_base, dir.get_workingtree_transport(None).base)
1007
self.assertEqual(checkout_base,
1008
dir.get_workingtree_transport(workingtree_3.WorkingTreeFormat3()).base)
1010
def test_meta1dir_uses_lockdir(self):
1011
"""Meta1 format uses a LockDir to guard the whole directory, not a file."""
1012
dir = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
1014
self.assertIsDirectory('branch-lock', t)
1016
def test_comparison(self):
1017
"""Equality and inequality behave properly.
1019
Metadirs should compare equal iff they have the same repo, branch and
1022
mydir = controldir.format_registry.make_controldir('knit')
1023
self.assertEqual(mydir, mydir)
1024
self.assertFalse(mydir != mydir)
1025
otherdir = controldir.format_registry.make_controldir('knit')
1026
self.assertEqual(otherdir, mydir)
1027
self.assertFalse(otherdir != mydir)
1028
otherdir2 = controldir.format_registry.make_controldir('development-subtree')
1029
self.assertNotEqual(otherdir2, mydir)
1030
self.assertFalse(otherdir2 == mydir)
1032
def test_with_features(self):
1033
tree = self.make_branch_and_tree('tree', format='2a')
1034
tree.controldir.update_feature_flags({"bar": "required"})
1035
self.assertRaises(bzrdir.MissingFeature, bzrdir.BzrDir.open, 'tree')
1036
bzrdir.BzrDirMetaFormat1.register_feature('bar')
1037
self.addCleanup(bzrdir.BzrDirMetaFormat1.unregister_feature, 'bar')
1038
dir = bzrdir.BzrDir.open('tree')
1039
self.assertEqual("required", dir._format.features.get("bar"))
1040
tree.controldir.update_feature_flags({"bar": None, "nonexistant": None})
1041
dir = bzrdir.BzrDir.open('tree')
1042
self.assertEqual({}, dir._format.features)
1044
def test_needs_conversion_different_working_tree(self):
1045
# meta1dirs need an conversion if any element is not the default.
1046
new_format = controldir.format_registry.make_controldir('dirstate')
1047
tree = self.make_branch_and_tree('tree', format='knit')
1048
self.assertTrue(tree.controldir.needs_format_conversion(
1051
def test_initialize_on_format_uses_smart_transport(self):
1052
self.setup_smart_server_with_call_log()
1053
new_format = controldir.format_registry.make_controldir('dirstate')
1054
transport = self.get_transport('target')
1055
transport.ensure_base()
1056
self.reset_smart_call_log()
1057
instance = new_format.initialize_on_transport(transport)
1058
self.assertIsInstance(instance, remote.RemoteBzrDir)
1059
rpc_count = len(self.hpss_calls)
1060
# This figure represent the amount of work to perform this use case. It
1061
# is entirely ok to reduce this number if a test fails due to rpc_count
1062
# being too low. If rpc_count increases, more network roundtrips have
1063
# become necessary for this use case. Please do not adjust this number
1064
# upwards without agreement from bzr's network support maintainers.
1065
self.assertEqual(2, rpc_count)
1068
class NonLocalTests(TestCaseWithTransport):
1069
"""Tests for bzrdir static behaviour on non local paths."""
1072
super(NonLocalTests, self).setUp()
1073
self.vfs_transport_factory = memory.MemoryServer
1075
def test_create_branch_convenience(self):
1076
# outside a repo the default convenience output is a repo+branch_tree
1077
format = controldir.format_registry.make_controldir('knit')
1078
branch = bzrdir.BzrDir.create_branch_convenience(
1079
self.get_url('foo'), format=format)
1080
self.assertRaises(errors.NoWorkingTree,
1081
branch.controldir.open_workingtree)
1082
branch.controldir.open_repository()
1084
def test_create_branch_convenience_force_tree_not_local_fails(self):
1085
# outside a repo the default convenience output is a repo+branch_tree
1086
format = controldir.format_registry.make_controldir('knit')
1087
self.assertRaises(errors.NotLocalUrl,
1088
bzrdir.BzrDir.create_branch_convenience,
1089
self.get_url('foo'),
1090
force_new_tree=True,
1092
t = self.get_transport()
1093
self.assertFalse(t.has('foo'))
1095
def test_clone(self):
1096
# clone into a nonlocal path works
1097
format = controldir.format_registry.make_controldir('knit')
1098
branch = bzrdir.BzrDir.create_branch_convenience('local',
1100
branch.controldir.open_workingtree()
1101
result = branch.controldir.clone(self.get_url('remote'))
1102
self.assertRaises(errors.NoWorkingTree,
1103
result.open_workingtree)
1104
result.open_branch()
1105
result.open_repository()
1107
def test_checkout_metadir(self):
1108
# checkout_metadir has reasonable working tree format even when no
1109
# working tree is present
1110
self.make_branch('branch-knit2', format='dirstate-with-subtree')
1111
my_bzrdir = bzrdir.BzrDir.open(self.get_url('branch-knit2'))
1112
checkout_format = my_bzrdir.checkout_metadir()
1113
self.assertIsInstance(checkout_format.workingtree_format,
1114
workingtree_4.WorkingTreeFormat4)
1117
class TestHTTPRedirections(object):
1118
"""Test redirection between two http servers.
1120
This MUST be used by daughter classes that also inherit from
1121
TestCaseWithTwoWebservers.
1123
We can't inherit directly from TestCaseWithTwoWebservers or the
1124
test framework will try to create an instance which cannot
1125
run, its implementation being incomplete.
1128
def create_transport_readonly_server(self):
1129
# We don't set the http protocol version, relying on the default
1130
return http_utils.HTTPServerRedirecting()
1132
def create_transport_secondary_server(self):
1133
# We don't set the http protocol version, relying on the default
1134
return http_utils.HTTPServerRedirecting()
1137
super(TestHTTPRedirections, self).setUp()
1138
# The redirections will point to the new server
1139
self.new_server = self.get_readonly_server()
1140
# The requests to the old server will be redirected
1141
self.old_server = self.get_secondary_server()
1142
# Configure the redirections
1143
self.old_server.redirect_to(self.new_server.host, self.new_server.port)
1145
def test_loop(self):
1146
# Both servers redirect to each other creating a loop
1147
self.new_server.redirect_to(self.old_server.host, self.old_server.port)
1148
# Starting from either server should loop
1149
old_url = self._qualified_url(self.old_server.host,
1150
self.old_server.port)
1151
oldt = self._transport(old_url)
1152
self.assertRaises(errors.NotBranchError,
1153
bzrdir.BzrDir.open_from_transport, oldt)
1154
new_url = self._qualified_url(self.new_server.host,
1155
self.new_server.port)
1156
newt = self._transport(new_url)
1157
self.assertRaises(errors.NotBranchError,
1158
bzrdir.BzrDir.open_from_transport, newt)
1160
def test_qualifier_preserved(self):
1161
wt = self.make_branch_and_tree('branch')
1162
old_url = self._qualified_url(self.old_server.host,
1163
self.old_server.port)
1164
start = self._transport(old_url).clone('branch')
1165
bdir = bzrdir.BzrDir.open_from_transport(start)
1166
# Redirection should preserve the qualifier, hence the transport class
1168
self.assertIsInstance(bdir.root_transport, type(start))
1171
class TestHTTPRedirections_urllib(TestHTTPRedirections,
1172
http_utils.TestCaseWithTwoWebservers):
1173
"""Tests redirections for urllib implementation"""
1175
_transport = HttpTransport_urllib
1177
def _qualified_url(self, host, port):
1178
result = 'http+urllib://%s:%s' % (host, port)
1179
self.permit_url(result)
1184
class TestHTTPRedirections_nosmart(TestHTTPRedirections,
1185
http_utils.TestCaseWithTwoWebservers):
1186
"""Tests redirections for the nosmart decorator"""
1188
_transport = NoSmartTransportDecorator
1190
def _qualified_url(self, host, port):
1191
result = 'nosmart+http://%s:%s' % (host, port)
1192
self.permit_url(result)
1196
class TestHTTPRedirections_readonly(TestHTTPRedirections,
1197
http_utils.TestCaseWithTwoWebservers):
1198
"""Tests redirections for readonly decoratror"""
1200
_transport = ReadonlyTransportDecorator
1202
def _qualified_url(self, host, port):
1203
result = 'readonly+http://%s:%s' % (host, port)
1204
self.permit_url(result)
1208
class TestDotBzrHidden(TestCaseWithTransport):
1211
if sys.platform == 'win32':
1212
ls = [os.environ['COMSPEC'], '/C', 'dir', '/B']
1215
f = subprocess.Popen(self.ls, stdout=subprocess.PIPE,
1216
stderr=subprocess.PIPE)
1217
out, err = f.communicate()
1218
self.assertEqual(0, f.returncode, 'Calling %s failed: %s'
1220
return out.splitlines()
1222
def test_dot_bzr_hidden(self):
1223
if sys.platform == 'win32' and not win32utils.has_win32file:
1224
raise TestSkipped('unable to make file hidden without pywin32 library')
1225
b = bzrdir.BzrDir.create('.')
1226
self.build_tree(['a'])
1227
self.assertEqual(['a'], self.get_ls())
1229
def test_dot_bzr_hidden_with_url(self):
1230
if sys.platform == 'win32' and not win32utils.has_win32file:
1231
raise TestSkipped('unable to make file hidden without pywin32 library')
1232
b = bzrdir.BzrDir.create(urlutils.local_path_to_url('.'))
1233
self.build_tree(['a'])
1234
self.assertEqual(['a'], self.get_ls())
1237
class _TestBzrDirFormat(bzrdir.BzrDirMetaFormat1):
1238
"""Test BzrDirFormat implementation for TestBzrDirSprout."""
1240
def _open(self, transport):
1241
return _TestBzrDir(transport, self)
1244
class _TestBzrDir(bzrdir.BzrDirMeta1):
1245
"""Test BzrDir implementation for TestBzrDirSprout.
1247
When created a _TestBzrDir already has repository and a branch. The branch
1248
is a test double as well.
1251
def __init__(self, *args, **kwargs):
1252
super(_TestBzrDir, self).__init__(*args, **kwargs)
1253
self.test_branch = _TestBranch(self.transport)
1254
self.test_branch.repository = self.create_repository()
1256
def open_branch(self, unsupported=False, possible_transports=None):
1257
return self.test_branch
1259
def cloning_metadir(self, require_stacking=False):
1260
return _TestBzrDirFormat()
1263
class _TestBranchFormat(breezy.branch.BranchFormat):
1264
"""Test Branch format for TestBzrDirSprout."""
1267
class _TestBranch(breezy.branch.Branch):
1268
"""Test Branch implementation for TestBzrDirSprout."""
1270
def __init__(self, transport, *args, **kwargs):
1271
self._format = _TestBranchFormat()
1272
self._transport = transport
1273
self.base = transport.base
1274
super(_TestBranch, self).__init__(*args, **kwargs)
1278
def sprout(self, *args, **kwargs):
1279
self.calls.append('sprout')
1280
return _TestBranch(self._transport)
1282
def copy_content_into(self, destination, revision_id=None):
1283
self.calls.append('copy_content_into')
1285
def last_revision(self):
1286
return _mod_revision.NULL_REVISION
1288
def get_parent(self):
1291
def _get_config(self):
1292
return config.TransportConfig(self._transport, 'branch.conf')
1294
def _get_config_store(self):
1295
return config.BranchStore(self)
1297
def set_parent(self, parent):
1298
self._parent = parent
1300
def lock_read(self):
1301
return lock.LogicalLockResult(self.unlock)
1307
class TestBzrDirSprout(TestCaseWithMemoryTransport):
1309
def test_sprout_uses_branch_sprout(self):
1310
"""BzrDir.sprout calls Branch.sprout.
1312
Usually, BzrDir.sprout should delegate to the branch's sprout method
1313
for part of the work. This allows the source branch to control the
1314
choice of format for the new branch.
1316
There are exceptions, but this tests avoids them:
1317
- if there's no branch in the source bzrdir,
1318
- or if the stacking has been requested and the format needs to be
1319
overridden to satisfy that.
1321
# Make an instrumented bzrdir.
1322
t = self.get_transport('source')
1324
source_bzrdir = _TestBzrDirFormat().initialize_on_transport(t)
1325
# The instrumented bzrdir has a test_branch attribute that logs calls
1326
# made to the branch contained in that bzrdir. Initially the test
1327
# branch exists but no calls have been made to it.
1328
self.assertEqual([], source_bzrdir.test_branch.calls)
1331
target_url = self.get_url('target')
1332
result = source_bzrdir.sprout(target_url, recurse='no')
1334
# The bzrdir called the branch's sprout method.
1335
self.assertSubset(['sprout'], source_bzrdir.test_branch.calls)
1337
def test_sprout_parent(self):
1338
grandparent_tree = self.make_branch('grandparent')
1339
parent = grandparent_tree.controldir.sprout('parent').open_branch()
1340
branch_tree = parent.controldir.sprout('branch').open_branch()
1341
self.assertContainsRe(branch_tree.get_parent(), '/parent/$')
1344
class TestBzrDirHooks(TestCaseWithMemoryTransport):
1346
def test_pre_open_called(self):
1348
bzrdir.BzrDir.hooks.install_named_hook('pre_open', calls.append, None)
1349
transport = self.get_transport('foo')
1350
url = transport.base
1351
self.assertRaises(errors.NotBranchError, bzrdir.BzrDir.open, url)
1352
self.assertEqual([transport.base], [t.base for t in calls])
1354
def test_pre_open_actual_exceptions_raised(self):
1356
def fail_once(transport):
1359
raise errors.BzrError("fail")
1360
bzrdir.BzrDir.hooks.install_named_hook('pre_open', fail_once, None)
1361
transport = self.get_transport('foo')
1362
url = transport.base
1363
err = self.assertRaises(errors.BzrError, bzrdir.BzrDir.open, url)
1364
self.assertEqual('fail', err._preformatted_string)
1366
def test_post_repo_init(self):
1367
from ..controldir import RepoInitHookParams
1369
bzrdir.BzrDir.hooks.install_named_hook('post_repo_init',
1371
self.make_repository('foo')
1372
self.assertLength(1, calls)
1374
self.assertIsInstance(params, RepoInitHookParams)
1375
self.assertTrue(hasattr(params, 'controldir'))
1376
self.assertTrue(hasattr(params, 'repository'))
1378
def test_post_repo_init_hook_repr(self):
1380
bzrdir.BzrDir.hooks.install_named_hook('post_repo_init',
1381
lambda params: param_reprs.append(repr(params)), None)
1382
self.make_repository('foo')
1383
self.assertLength(1, param_reprs)
1384
param_repr = param_reprs[0]
1385
self.assertStartsWith(param_repr, '<RepoInitHookParams for ')
1388
class TestGenerateBackupName(TestCaseWithMemoryTransport):
1389
# FIXME: This may need to be unified with test_osutils.TestBackupNames or
1390
# moved to per_bzrdir or per_transport for better coverage ?
1394
super(TestGenerateBackupName, self).setUp()
1395
self._transport = self.get_transport()
1396
bzrdir.BzrDir.create(self.get_url(),
1397
possible_transports=[self._transport])
1398
self._bzrdir = bzrdir.BzrDir.open_from_transport(self._transport)
1401
self.assertEqual("a.~1~", self._bzrdir._available_backup_name("a"))
1403
def test_exiting(self):
1404
self._transport.put_bytes("a.~1~", "some content")
1405
self.assertEqual("a.~2~", self._bzrdir._available_backup_name("a"))
1408
class TestMeta1DirColoFormat(TestCaseWithTransport):
1409
"""Tests specific to the meta1 dir with colocated branches format."""
1411
def test_supports_colo(self):
1412
format = bzrdir.BzrDirMetaFormat1Colo()
1413
self.assertTrue(format.colocated_branches)
1415
def test_upgrade_from_2a(self):
1416
tree = self.make_branch_and_tree('.', format='2a')
1417
format = bzrdir.BzrDirMetaFormat1Colo()
1418
self.assertTrue(tree.controldir.needs_format_conversion(format))
1419
converter = tree.controldir._format.get_converter(format)
1420
result = converter.convert(tree.controldir, None)
1421
self.assertIsInstance(result._format, bzrdir.BzrDirMetaFormat1Colo)
1422
self.assertFalse(result.needs_format_conversion(format))
1424
def test_downgrade_to_2a(self):
1425
tree = self.make_branch_and_tree('.', format='development-colo')
1426
format = bzrdir.BzrDirMetaFormat1()
1427
self.assertTrue(tree.controldir.needs_format_conversion(format))
1428
converter = tree.controldir._format.get_converter(format)
1429
result = converter.convert(tree.controldir, None)
1430
self.assertIsInstance(result._format, bzrdir.BzrDirMetaFormat1)
1431
self.assertFalse(result.needs_format_conversion(format))
1433
def test_downgrade_to_2a_too_many_branches(self):
1434
tree = self.make_branch_and_tree('.', format='development-colo')
1435
tree.controldir.create_branch(name="another-colocated-branch")
1436
converter = tree.controldir._format.get_converter(
1437
bzrdir.BzrDirMetaFormat1())
1438
result = converter.convert(tree.controldir, bzrdir.BzrDirMetaFormat1())
1439
self.assertIsInstance(result._format, bzrdir.BzrDirMetaFormat1)
1441
def test_nested(self):
1442
tree = self.make_branch_and_tree('.', format='development-colo')
1443
tree.controldir.create_branch(name='foo')
1444
tree.controldir.create_branch(name='fool/bla')
1446
errors.ParentBranchExists, tree.controldir.create_branch,
1449
def test_parent(self):
1450
tree = self.make_branch_and_tree('.', format='development-colo')
1451
tree.controldir.create_branch(name='fool/bla')
1452
tree.controldir.create_branch(name='foo/bar')
1454
errors.AlreadyBranchError, tree.controldir.create_branch,
1458
class SampleBzrFormat(bzrdir.BzrFormat):
1461
def get_format_string(cls):
1462
return "First line\n"
1465
class TestBzrFormat(TestCase):
1466
"""Tests for BzrFormat."""
1468
def test_as_string(self):
1469
format = SampleBzrFormat()
1470
format.features = {"foo": "required"}
1471
self.assertEqual(format.as_string(),
1474
format.features["another"] = "optional"
1475
self.assertEqual(format.as_string(),
1478
"optional another\n")
1480
def test_network_name(self):
1481
# The network string should include the feature info
1482
format = SampleBzrFormat()
1483
format.features = {"foo": "required"}
1485
"First line\nrequired foo\n",
1486
format.network_name())
1488
def test_from_string_no_features(self):
1490
format = SampleBzrFormat.from_string(
1492
self.assertEqual({}, format.features)
1494
def test_from_string_with_feature(self):
1496
format = SampleBzrFormat.from_string(
1497
"First line\nrequired foo\n")
1498
self.assertEqual("required", format.features.get("foo"))
1500
def test_from_string_format_string_mismatch(self):
1501
# The first line has to match the format string
1502
self.assertRaises(AssertionError, SampleBzrFormat.from_string,
1503
"Second line\nrequired foo\n")
1505
def test_from_string_missing_space(self):
1506
# At least one space is required in the feature lines
1507
self.assertRaises(errors.ParseFormatError, SampleBzrFormat.from_string,
1508
"First line\nfoo\n")
1510
def test_from_string_with_spaces(self):
1511
# Feature with spaces (in case we add stuff like this in the future)
1512
format = SampleBzrFormat.from_string(
1513
"First line\nrequired foo with spaces\n")
1514
self.assertEqual("required", format.features.get("foo with spaces"))
1517
format1 = SampleBzrFormat()
1518
format1.features = {"nested-trees": "optional"}
1519
format2 = SampleBzrFormat()
1520
format2.features = {"nested-trees": "optional"}
1521
self.assertEqual(format1, format1)
1522
self.assertEqual(format1, format2)
1523
format3 = SampleBzrFormat()
1524
self.assertNotEqual(format1, format3)
1526
def test_check_support_status_optional(self):
1527
# Optional, so silently ignore
1528
format = SampleBzrFormat()
1529
format.features = {"nested-trees": "optional"}
1530
format.check_support_status(True)
1531
self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
1532
SampleBzrFormat.register_feature("nested-trees")
1533
format.check_support_status(True)
1535
def test_check_support_status_required(self):
1536
# Optional, so trigger an exception
1537
format = SampleBzrFormat()
1538
format.features = {"nested-trees": "required"}
1539
self.assertRaises(bzrdir.MissingFeature, format.check_support_status,
1541
self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
1542
SampleBzrFormat.register_feature("nested-trees")
1543
format.check_support_status(True)
1545
def test_check_support_status_unknown(self):
1546
# treat unknown necessity as required
1547
format = SampleBzrFormat()
1548
format.features = {"nested-trees": "unknown"}
1549
self.assertRaises(bzrdir.MissingFeature, format.check_support_status,
1551
self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
1552
SampleBzrFormat.register_feature("nested-trees")
1553
format.check_support_status(True)
1555
def test_feature_already_registered(self):
1556
# a feature can only be registered once
1557
self.addCleanup(SampleBzrFormat.unregister_feature, "nested-trees")
1558
SampleBzrFormat.register_feature("nested-trees")
1559
self.assertRaises(bzrdir.FeatureAlreadyRegistered,
1560
SampleBzrFormat.register_feature, "nested-trees")
1562
def test_feature_with_space(self):
1563
# spaces are not allowed in feature names
1564
self.assertRaises(ValueError, SampleBzrFormat.register_feature,