56
50
class TestControlDir(TestCaseWithControlDir):
57
# Many of these tests test for disk equality rather than checking
58
# for semantic equivalence. This works well for some tests but
59
# is not good at handling changes in representation or the addition
60
# or removal of control data. It would be nice to for instance:
61
# sprout a new branch, check that the nickname has been reset by hand
62
# and then set the nickname to match the source branch, at which point
63
# a semantic equivalence should pass
65
def assertDirectoriesEqual(self, source, target, ignore_list=[]):
66
"""Assert that the content of source and target are identical.
68
paths in ignore list will be completely ignored.
70
We ignore paths that represent data which is allowed to change during
71
a clone or sprout: for instance, inventory.knit contains gzip fragements
72
which have timestamps in them, and as we have read the inventory from
73
the source knit, the already-read data is recompressed rather than
74
reading it again, which leads to changed timestamps. This is ok though,
75
because the inventory.kndx file is not ignored, and the integrity of
76
knit joins is tested by test_knit and test_versionedfile.
78
:seealso: Additionally, assertRepositoryHasSameItems provides value
79
rather than representation checking of repositories for
85
dir = directories.pop()
86
for path in set(source.list_dir(dir) + target.list_dir(dir)):
87
path = dir + '/' + path
88
if path in ignore_list:
91
stat = source.stat(path)
92
except errors.NoSuchFile:
93
self.fail('%s not in source' % path)
94
if S_ISDIR(stat.st_mode):
95
self.assertTrue(S_ISDIR(target.stat(path).st_mode))
96
directories.append(path)
98
self.assertEqualDiff(source.get(path).read(),
99
target.get(path).read(),
100
"text for file %r differs:\n" % path)
102
def assertRepositoryHasSameItems(self, left_repo, right_repo):
103
"""require left_repo and right_repo to contain the same data."""
104
# XXX: TODO: Doesn't work yet, because we need to be able to compare
105
# local repositories to remote ones... but this is an as-yet unsolved
106
# aspect of format management and the Remote protocols...
107
# self.assertEqual(left_repo._format.__class__,
108
# right_repo._format.__class__)
109
left_repo.lock_read()
111
right_repo.lock_read()
114
all_revs = left_repo.all_revision_ids()
115
self.assertEqual(left_repo.all_revision_ids(),
116
right_repo.all_revision_ids())
117
for rev_id in left_repo.all_revision_ids():
118
self.assertEqual(left_repo.get_revision(rev_id),
119
right_repo.get_revision(rev_id))
120
# Assert the revision trees (and thus the inventories) are equal
121
sort_key = lambda rev_tree: rev_tree.get_revision_id()
122
rev_trees_a = sorted(
123
left_repo.revision_trees(all_revs), key=sort_key)
124
rev_trees_b = sorted(
125
right_repo.revision_trees(all_revs), key=sort_key)
126
for tree_a, tree_b in zip(rev_trees_a, rev_trees_b):
127
self.assertEqual([], list(tree_a.iter_changes(tree_b)))
129
text_index = left_repo._generate_text_key_index()
130
self.assertEqual(text_index,
131
right_repo._generate_text_key_index())
133
for file_id, revision_id in text_index.iterkeys():
134
desired_files.append(
135
(file_id, revision_id, (file_id, revision_id)))
136
left_texts = list(left_repo.iter_files_bytes(desired_files))
137
right_texts = list(right_repo.iter_files_bytes(desired_files))
140
self.assertEqual(left_texts, right_texts)
142
for rev_id in all_revs:
144
left_text = left_repo.get_signature_text(rev_id)
145
except NoSuchRevision:
147
right_text = right_repo.get_signature_text(rev_id)
148
self.assertEqual(left_text, right_text)
154
52
def skipIfNoWorkingTree(self, a_bzrdir):
155
53
"""Raises TestSkipped if a_bzrdir doesn't have a working tree.
265
163
self.assertRaises(errors.NoWorkingTree, dir.open_workingtree)
267
def test_clone_on_transport(self):
268
a_dir = self.make_bzrdir('source')
269
target_transport = a_dir.root_transport.clone('..').clone('target')
270
target = a_dir.clone_on_transport(target_transport)
271
self.assertNotEqual(a_dir.transport.base, target.transport.base)
272
self.assertDirectoriesEqual(a_dir.root_transport, target.root_transport,
273
['./.bzr/merge-hashes'])
275
def test_clone_bzrdir_empty(self):
276
dir = self.make_bzrdir('source')
277
target = dir.clone(self.get_url('target'))
278
self.assertNotEqual(dir.transport.base, target.transport.base)
279
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
280
['./.bzr/merge-hashes'])
282
def test_clone_bzrdir_empty_force_new_ignored(self):
283
# the force_new_repo parameter should have no effect on an empty
284
# bzrdir's clone logic
285
dir = self.make_bzrdir('source')
286
target = dir.clone(self.get_url('target'), force_new_repo=True)
287
self.assertNotEqual(dir.transport.base, target.transport.base)
288
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
289
['./.bzr/merge-hashes'])
291
def test_clone_bzrdir_repository(self):
292
tree = self.make_branch_and_tree('commit_tree')
293
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
295
tree.commit('revision 1', rev_id='1')
296
dir = self.make_bzrdir('source')
297
repo = dir.create_repository()
298
repo.fetch(tree.branch.repository)
299
self.assertTrue(repo.has_revision('1'))
300
target = dir.clone(self.get_url('target'))
301
self.assertNotEqual(dir.transport.base, target.transport.base)
302
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
304
'./.bzr/merge-hashes',
307
self.assertRepositoryHasSameItems(tree.branch.repository,
308
target.open_repository())
310
165
def test_clone_bzrdir_repository_under_shared(self):
311
166
tree = self.make_branch_and_tree('commit_tree')
312
167
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
382
237
self.assertFalse(branch.repository.make_working_trees())
383
238
self.assertTrue(branch.repository.is_shared())
385
def test_clone_bzrdir_repository_under_shared_force_new_repo(self):
386
tree = self.make_branch_and_tree('commit_tree')
387
self.build_tree(['commit_tree/foo'])
389
tree.commit('revision 1', rev_id='1')
390
dir = self.make_bzrdir('source')
391
repo = dir.create_repository()
392
repo.fetch(tree.branch.repository)
393
self.assertTrue(repo.has_revision('1'))
395
self.make_repository('target', shared=True)
396
except errors.IncompatibleFormat:
398
target = dir.clone(self.get_url('target/child'), force_new_repo=True)
399
self.assertNotEqual(dir.transport.base, target.transport.base)
400
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
401
['./.bzr/repository',
403
self.assertRepositoryHasSameItems(tree.branch.repository, repo)
405
240
def test_clone_bzrdir_repository_revision(self):
406
241
# test for revision limiting, [smoke test, not corner case checks].
407
242
# make a repository with some revisions,
441
276
tree_repo.get_signature_text(rev1),
442
277
target.repository.get_signature_text(rev1))
444
def test_clone_bzrdir_branch_and_repo(self):
445
tree = self.make_branch_and_tree('commit_tree')
446
self.build_tree(['commit_tree/foo'])
448
tree.commit('revision 1')
449
source = self.make_branch('source')
450
tree.branch.repository.copy_content_into(source.repository)
451
tree.branch.copy_content_into(source)
453
target = dir.clone(self.get_url('target'))
454
self.assertNotEqual(dir.transport.base, target.transport.base)
455
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
457
'./.bzr/basis-inventory-cache',
458
'./.bzr/checkout/stat-cache',
459
'./.bzr/merge-hashes',
463
self.assertRepositoryHasSameItems(
464
tree.branch.repository, target.open_repository())
466
279
def test_clone_bzrdir_branch_and_repo_into_shared_repo(self):
467
280
# by default cloning into a shared repo uses the shared repo.
468
281
tree = self.make_branch_and_tree('commit_tree')
483
296
self.assertEqual(source.revision_history(),
484
297
target.open_branch().revision_history())
486
def test_clone_bzrdir_branch_and_repo_into_shared_repo_force_new_repo(self):
487
# by default cloning into a shared repo uses the shared repo.
488
tree = self.make_branch_and_tree('commit_tree')
489
self.build_tree(['commit_tree/foo'])
491
tree.commit('revision 1')
492
source = self.make_branch('source')
493
tree.branch.repository.copy_content_into(source.repository)
494
tree.branch.copy_content_into(source)
496
self.make_repository('target', shared=True)
497
except errors.IncompatibleFormat:
500
target = dir.clone(self.get_url('target/child'), force_new_repo=True)
501
self.assertNotEqual(dir.transport.base, target.transport.base)
502
repo = target.open_repository()
503
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
504
['./.bzr/repository',
506
self.assertRepositoryHasSameItems(tree.branch.repository, repo)
508
def test_clone_bzrdir_branch_reference(self):
509
# cloning should preserve the reference status of the branch in a bzrdir
510
referenced_branch = self.make_branch('referencced')
511
dir = self.make_bzrdir('source')
513
reference = bzrlib.branch.BranchReferenceFormat().initialize(dir,
514
target_branch=referenced_branch)
515
except errors.IncompatibleFormat:
516
# this is ok too, not all formats have to support references.
518
target = dir.clone(self.get_url('target'))
519
self.assertNotEqual(dir.transport.base, target.transport.base)
520
self.assertDirectoriesEqual(dir.root_transport, target.root_transport)
522
299
def test_clone_bzrdir_branch_revision(self):
523
300
# test for revision limiting, [smoke test, not corner case checks].
524
301
# make a branch with some revisions,
536
313
target = dir.clone(self.get_url('target'), revision_id='1')
537
314
self.assertEqual('1', target.open_branch().last_revision())
539
def test_clone_bzrdir_tree_branch_repo(self):
540
tree = self.make_branch_and_tree('source')
541
self.build_tree(['source/foo'])
543
tree.commit('revision 1')
545
target = dir.clone(self.get_url('target'))
546
self.skipIfNoWorkingTree(target)
547
self.assertNotEqual(dir.transport.base, target.transport.base)
548
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
549
['./.bzr/stat-cache',
550
'./.bzr/checkout/dirstate',
551
'./.bzr/checkout/stat-cache',
552
'./.bzr/checkout/merge-hashes',
553
'./.bzr/merge-hashes',
556
self.assertRepositoryHasSameItems(tree.branch.repository,
557
target.open_repository())
558
target.open_workingtree().revert()
560
316
def test_clone_on_transport_preserves_repo_format(self):
561
317
if self.bzrdir_format == bzrdir.format_registry.make_bzrdir('default'):
576
332
target_repo = target_repo._real_repository
577
333
self.assertEqual(target_repo._format, source_branch.repository._format)
579
def test_revert_inventory(self):
580
tree = self.make_branch_and_tree('source')
581
self.build_tree(['source/foo'])
583
tree.commit('revision 1')
585
target = dir.clone(self.get_url('target'))
586
self.skipIfNoWorkingTree(target)
587
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
588
['./.bzr/stat-cache',
589
'./.bzr/checkout/dirstate',
590
'./.bzr/checkout/stat-cache',
591
'./.bzr/checkout/merge-hashes',
592
'./.bzr/merge-hashes',
595
self.assertRepositoryHasSameItems(tree.branch.repository,
596
target.open_repository())
598
target.open_workingtree().revert()
599
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
600
['./.bzr/stat-cache',
601
'./.bzr/checkout/dirstate',
602
'./.bzr/checkout/stat-cache',
603
'./.bzr/checkout/merge-hashes',
604
'./.bzr/merge-hashes',
607
self.assertRepositoryHasSameItems(tree.branch.repository,
608
target.open_repository())
610
def test_clone_bzrdir_tree_branch_reference(self):
611
# a tree with a branch reference (aka a checkout)
612
# should stay a checkout on clone.
613
referenced_branch = self.make_branch('referencced')
614
dir = self.make_bzrdir('source')
616
reference = bzrlib.branch.BranchReferenceFormat().initialize(dir,
617
target_branch=referenced_branch)
618
except errors.IncompatibleFormat:
619
# this is ok too, not all formats have to support references.
621
self.createWorkingTreeOrSkip(dir)
622
target = dir.clone(self.get_url('target'))
623
self.skipIfNoWorkingTree(target)
624
self.assertNotEqual(dir.transport.base, target.transport.base)
625
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
626
['./.bzr/stat-cache',
627
'./.bzr/checkout/stat-cache',
628
'./.bzr/checkout/merge-hashes',
629
'./.bzr/merge-hashes',
630
'./.bzr/repository/inventory.knit',
633
335
def test_clone_bzrdir_tree_revision(self):
634
336
# test for revision limiting, [smoke test, not corner case checks].
635
337
# make a tree with a revision with a last-revision
737
439
target.open_branch()
738
440
self.openWorkingTreeIfLocal(target)
740
def test_sprout_bzrdir_repository(self):
741
tree = self.make_branch_and_tree('commit_tree')
742
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
744
tree.commit('revision 1', rev_id='1')
745
dir = self.make_bzrdir('source')
746
repo = dir.create_repository()
747
repo.fetch(tree.branch.repository)
748
self.assertTrue(repo.has_revision('1'))
751
_mod_revision.is_null(_mod_revision.ensure_null(
752
dir.open_branch().last_revision())))
753
except errors.NotBranchError:
755
target = dir.sprout(self.get_url('target'))
756
self.assertNotEqual(dir.transport.base, target.transport.base)
757
# testing inventory isn't reasonable for repositories
758
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
764
'./.bzr/repository/inventory.knit',
767
local_inventory = dir.transport.local_abspath('inventory')
768
except errors.NotLocalUrl:
771
# If we happen to have a tree, we'll guarantee everything
772
# except for the tree root is the same.
773
inventory_f = file(local_inventory, 'rb')
774
self.addCleanup(inventory_f.close)
775
self.assertContainsRe(inventory_f.read(),
776
'<inventory format="5">\n</inventory>\n')
778
if e.errno != errno.ENOENT:
781
442
def test_sprout_bzrdir_with_repository_to_shared(self):
782
443
tree = self.make_branch_and_tree('commit_tree')
783
444
self.build_tree(['commit_tree/foo'])
882
543
target = self.sproutOrSkip(dir, self.get_url('target'), revision_id='2')
883
544
raise TestSkipped('revision limiting not strict yet')
885
def test_sprout_bzrdir_branch_and_repo(self):
886
tree = self.make_branch_and_tree('commit_tree')
887
self.build_tree(['commit_tree/foo'])
889
tree.commit('revision 1')
890
source = self.make_branch('source')
891
tree.branch.repository.copy_content_into(source.repository)
892
tree.bzrdir.open_branch().copy_content_into(source)
894
target = dir.sprout(self.get_url('target'))
895
self.assertNotEqual(dir.transport.base, target.transport.base)
896
target_repo = target.open_repository()
897
self.assertRepositoryHasSameItems(source.repository, target_repo)
898
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
900
'./.bzr/basis-inventory-cache',
901
'./.bzr/branch/branch.conf',
902
'./.bzr/branch/parent',
904
'./.bzr/checkout/inventory',
905
'./.bzr/checkout/stat-cache',
913
546
def test_sprout_bzrdir_branch_and_repo_shared(self):
914
547
# sprouting a branch with a repo into a shared repo uses the shared
1034
667
target = dir.sprout(self.get_url('target'), revision_id='1')
1035
668
self.assertEqual('1', target.open_branch().last_revision())
1037
def test_sprout_bzrdir_tree_branch_repo(self):
1038
tree = self.make_branch_and_tree('source')
1039
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
1041
tree.commit('revision 1')
1043
target = self.sproutOrSkip(dir, self.get_url('target'))
1044
self.assertNotEqual(dir.transport.base, target.transport.base)
1045
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
1047
'./.bzr/branch/branch.conf',
1048
'./.bzr/branch/parent',
1049
'./.bzr/checkout/dirstate',
1050
'./.bzr/checkout/stat-cache',
1051
'./.bzr/checkout/inventory',
1054
'./.bzr/repository',
1055
'./.bzr/stat-cache',
1057
self.assertRepositoryHasSameItems(
1058
tree.branch.repository, target.open_repository())
1060
670
def test_sprout_bzrdir_tree_branch_reference(self):
1061
671
# sprouting should create a repository if needed and a sprouted branch.
1062
672
# the tree state should not be copied.
1393
1003
network_name = format.network_name()
1394
1004
self.assertEqual(real_dir._format.network_name(), network_name)
1396
registry = bzrdir.network_format_registry
1006
registry = controldir.network_format_registry
1397
1007
network_name = format.network_name()
1398
1008
looked_up_format = registry.get(network_name)
1399
self.assertEqual(format.__class__, looked_up_format.__class__)
1010
issubclass(format.__class__, looked_up_format.__class__))
1400
1011
# The network name must be a byte string.
1401
1012
self.assertIsInstance(network_name, str)
1403
1014
def test_open_not_bzrdir(self):
1404
1015
# test the formats specific behaviour for no-content or similar dirs.
1405
self.assertRaises(NotBranchError,
1016
self.assertRaises(errors.NotBranchError,
1406
1017
self.bzrdir_format.open,
1407
1018
transport.get_transport(self.get_readonly_url()))
1802
1413
text = dir._format.get_format_description()
1803
1414
self.failUnless(len(text))
1805
def test_retire_bzrdir(self):
1806
bd = self.make_bzrdir('.')
1807
transport = bd.root_transport
1808
# must not overwrite existing directories
1809
self.build_tree(['.bzr.retired.0/', '.bzr.retired.0/junk',],
1810
transport=transport)
1811
self.failUnless(transport.has('.bzr'))
1813
self.failIf(transport.has('.bzr'))
1814
self.failUnless(transport.has('.bzr.retired.1'))
1816
def test_retire_bzrdir_limited(self):
1817
bd = self.make_bzrdir('.')
1818
transport = bd.root_transport
1819
# must not overwrite existing directories
1820
self.build_tree(['.bzr.retired.0/', '.bzr.retired.0/junk',],
1821
transport=transport)
1822
self.failUnless(transport.has('.bzr'))
1823
self.assertRaises((errors.FileExists, errors.DirectoryNotEmpty),
1824
bd.retire_bzrdir, limit=0)
1827
1417
class TestBreakLock(TestCaseWithControlDir):