57
50
class TestControlDir(TestCaseWithControlDir):
58
# Many of these tests test for disk equality rather than checking
59
# for semantic equivalence. This works well for some tests but
60
# is not good at handling changes in representation or the addition
61
# or removal of control data. It would be nice to for instance:
62
# sprout a new branch, check that the nickname has been reset by hand
63
# and then set the nickname to match the source branch, at which point
64
# a semantic equivalence should pass
66
def assertDirectoriesEqual(self, source, target, ignore_list=[]):
67
"""Assert that the content of source and target are identical.
69
paths in ignore list will be completely ignored.
71
We ignore paths that represent data which is allowed to change during
72
a clone or sprout: for instance, inventory.knit contains gzip fragements
73
which have timestamps in them, and as we have read the inventory from
74
the source knit, the already-read data is recompressed rather than
75
reading it again, which leads to changed timestamps. This is ok though,
76
because the inventory.kndx file is not ignored, and the integrity of
77
knit joins is tested by test_knit and test_versionedfile.
79
:seealso: Additionally, assertRepositoryHasSameItems provides value
80
rather than representation checking of repositories for
86
dir = directories.pop()
87
for path in set(source.list_dir(dir) + target.list_dir(dir)):
88
path = dir + '/' + path
89
if path in ignore_list:
92
stat = source.stat(path)
93
except errors.NoSuchFile:
94
self.fail('%s not in source' % path)
95
if S_ISDIR(stat.st_mode):
96
self.assertTrue(S_ISDIR(target.stat(path).st_mode))
97
directories.append(path)
99
self.assertEqualDiff(source.get(path).read(),
100
target.get(path).read(),
101
"text for file %r differs:\n" % path)
103
def assertRepositoryHasSameItems(self, left_repo, right_repo):
104
"""require left_repo and right_repo to contain the same data."""
105
# XXX: TODO: Doesn't work yet, because we need to be able to compare
106
# local repositories to remote ones... but this is an as-yet unsolved
107
# aspect of format management and the Remote protocols...
108
# self.assertEqual(left_repo._format.__class__,
109
# right_repo._format.__class__)
110
left_repo.lock_read()
112
right_repo.lock_read()
115
all_revs = left_repo.all_revision_ids()
116
self.assertEqual(left_repo.all_revision_ids(),
117
right_repo.all_revision_ids())
118
for rev_id in left_repo.all_revision_ids():
119
self.assertEqual(left_repo.get_revision(rev_id),
120
right_repo.get_revision(rev_id))
121
# Assert the revision trees (and thus the inventories) are equal
122
sort_key = lambda rev_tree: rev_tree.get_revision_id()
123
rev_trees_a = sorted(
124
left_repo.revision_trees(all_revs), key=sort_key)
125
rev_trees_b = sorted(
126
right_repo.revision_trees(all_revs), key=sort_key)
127
for tree_a, tree_b in zip(rev_trees_a, rev_trees_b):
128
self.assertEqual([], list(tree_a.iter_changes(tree_b)))
130
text_index = left_repo._generate_text_key_index()
131
self.assertEqual(text_index,
132
right_repo._generate_text_key_index())
134
for file_id, revision_id in text_index.iterkeys():
135
desired_files.append(
136
(file_id, revision_id, (file_id, revision_id)))
137
left_texts = list(left_repo.iter_files_bytes(desired_files))
138
right_texts = list(right_repo.iter_files_bytes(desired_files))
141
self.assertEqual(left_texts, right_texts)
143
for rev_id in all_revs:
145
left_text = left_repo.get_signature_text(rev_id)
146
except NoSuchRevision:
148
right_text = right_repo.get_signature_text(rev_id)
149
self.assertEqual(left_text, right_text)
155
52
def skipIfNoWorkingTree(self, a_bzrdir):
156
53
"""Raises TestSkipped if a_bzrdir doesn't have a working tree.
266
163
self.assertRaises(errors.NoWorkingTree, dir.open_workingtree)
268
def test_clone_on_transport(self):
269
a_dir = self.make_bzrdir('source')
270
target_transport = a_dir.root_transport.clone('..').clone('target')
271
target = a_dir.clone_on_transport(target_transport)
272
self.assertNotEqual(a_dir.transport.base, target.transport.base)
273
self.assertDirectoriesEqual(a_dir.root_transport, target.root_transport,
274
['./.bzr/merge-hashes'])
276
def test_clone_bzrdir_empty(self):
277
dir = self.make_bzrdir('source')
278
target = dir.clone(self.get_url('target'))
279
self.assertNotEqual(dir.transport.base, target.transport.base)
280
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
281
['./.bzr/merge-hashes'])
283
def test_clone_bzrdir_empty_force_new_ignored(self):
284
# the force_new_repo parameter should have no effect on an empty
285
# bzrdir's clone logic
286
dir = self.make_bzrdir('source')
287
target = dir.clone(self.get_url('target'), force_new_repo=True)
288
self.assertNotEqual(dir.transport.base, target.transport.base)
289
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
290
['./.bzr/merge-hashes'])
292
def test_clone_bzrdir_repository(self):
293
tree = self.make_branch_and_tree('commit_tree')
294
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
296
tree.commit('revision 1', rev_id='1')
297
dir = self.make_bzrdir('source')
298
repo = dir.create_repository()
299
repo.fetch(tree.branch.repository)
300
self.assertTrue(repo.has_revision('1'))
301
target = dir.clone(self.get_url('target'))
302
self.assertNotEqual(dir.transport.base, target.transport.base)
303
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
305
'./.bzr/merge-hashes',
308
self.assertRepositoryHasSameItems(tree.branch.repository,
309
target.open_repository())
311
165
def test_clone_bzrdir_repository_under_shared(self):
312
166
tree = self.make_branch_and_tree('commit_tree')
313
167
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
383
237
self.assertFalse(branch.repository.make_working_trees())
384
238
self.assertTrue(branch.repository.is_shared())
386
def test_clone_bzrdir_repository_under_shared_force_new_repo(self):
387
tree = self.make_branch_and_tree('commit_tree')
388
self.build_tree(['commit_tree/foo'])
390
tree.commit('revision 1', rev_id='1')
391
dir = self.make_bzrdir('source')
392
repo = dir.create_repository()
393
repo.fetch(tree.branch.repository)
394
self.assertTrue(repo.has_revision('1'))
396
self.make_repository('target', shared=True)
397
except errors.IncompatibleFormat:
399
target = dir.clone(self.get_url('target/child'), force_new_repo=True)
400
self.assertNotEqual(dir.transport.base, target.transport.base)
401
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
402
['./.bzr/repository',
404
self.assertRepositoryHasSameItems(tree.branch.repository, repo)
406
240
def test_clone_bzrdir_repository_revision(self):
407
241
# test for revision limiting, [smoke test, not corner case checks].
408
242
# make a repository with some revisions,
442
276
tree_repo.get_signature_text(rev1),
443
277
target.repository.get_signature_text(rev1))
445
def test_clone_bzrdir_branch_and_repo(self):
446
tree = self.make_branch_and_tree('commit_tree')
447
self.build_tree(['commit_tree/foo'])
449
tree.commit('revision 1')
450
source = self.make_branch('source')
451
tree.branch.repository.copy_content_into(source.repository)
452
tree.branch.copy_content_into(source)
454
target = dir.clone(self.get_url('target'))
455
self.assertNotEqual(dir.transport.base, target.transport.base)
456
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
458
'./.bzr/basis-inventory-cache',
459
'./.bzr/checkout/stat-cache',
460
'./.bzr/merge-hashes',
464
self.assertRepositoryHasSameItems(
465
tree.branch.repository, target.open_repository())
467
279
def test_clone_bzrdir_branch_and_repo_into_shared_repo(self):
468
280
# by default cloning into a shared repo uses the shared repo.
469
281
tree = self.make_branch_and_tree('commit_tree')
484
296
self.assertEqual(source.revision_history(),
485
297
target.open_branch().revision_history())
487
def test_clone_bzrdir_branch_and_repo_into_shared_repo_force_new_repo(self):
488
# by default cloning into a shared repo uses the shared repo.
489
tree = self.make_branch_and_tree('commit_tree')
490
self.build_tree(['commit_tree/foo'])
492
tree.commit('revision 1')
493
source = self.make_branch('source')
494
tree.branch.repository.copy_content_into(source.repository)
495
tree.branch.copy_content_into(source)
497
self.make_repository('target', shared=True)
498
except errors.IncompatibleFormat:
501
target = dir.clone(self.get_url('target/child'), force_new_repo=True)
502
self.assertNotEqual(dir.transport.base, target.transport.base)
503
repo = target.open_repository()
504
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
505
['./.bzr/repository',
507
self.assertRepositoryHasSameItems(tree.branch.repository, repo)
509
def test_clone_bzrdir_branch_reference(self):
510
# cloning should preserve the reference status of the branch in a bzrdir
511
referenced_branch = self.make_branch('referencced')
512
dir = self.make_bzrdir('source')
514
reference = bzrlib.branch.BranchReferenceFormat().initialize(dir,
515
target_branch=referenced_branch)
516
except errors.IncompatibleFormat:
517
# this is ok too, not all formats have to support references.
519
target = dir.clone(self.get_url('target'))
520
self.assertNotEqual(dir.transport.base, target.transport.base)
521
self.assertDirectoriesEqual(dir.root_transport, target.root_transport)
523
299
def test_clone_bzrdir_branch_revision(self):
524
300
# test for revision limiting, [smoke test, not corner case checks].
525
301
# make a branch with some revisions,
537
313
target = dir.clone(self.get_url('target'), revision_id='1')
538
314
self.assertEqual('1', target.open_branch().last_revision())
540
def test_clone_bzrdir_tree_branch_repo(self):
541
tree = self.make_branch_and_tree('source')
542
self.build_tree(['source/foo'])
544
tree.commit('revision 1')
546
target = dir.clone(self.get_url('target'))
547
self.skipIfNoWorkingTree(target)
548
self.assertNotEqual(dir.transport.base, target.transport.base)
549
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
550
['./.bzr/stat-cache',
551
'./.bzr/checkout/dirstate',
552
'./.bzr/checkout/stat-cache',
553
'./.bzr/checkout/merge-hashes',
554
'./.bzr/merge-hashes',
557
self.assertRepositoryHasSameItems(tree.branch.repository,
558
target.open_repository())
559
target.open_workingtree().revert()
561
316
def test_clone_on_transport_preserves_repo_format(self):
562
317
if self.bzrdir_format == bzrdir.format_registry.make_bzrdir('default'):
577
332
target_repo = target_repo._real_repository
578
333
self.assertEqual(target_repo._format, source_branch.repository._format)
580
def test_revert_inventory(self):
581
tree = self.make_branch_and_tree('source')
582
self.build_tree(['source/foo'])
584
tree.commit('revision 1')
586
target = dir.clone(self.get_url('target'))
587
self.skipIfNoWorkingTree(target)
588
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
589
['./.bzr/stat-cache',
590
'./.bzr/checkout/dirstate',
591
'./.bzr/checkout/stat-cache',
592
'./.bzr/checkout/merge-hashes',
593
'./.bzr/merge-hashes',
596
self.assertRepositoryHasSameItems(tree.branch.repository,
597
target.open_repository())
599
target.open_workingtree().revert()
600
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
601
['./.bzr/stat-cache',
602
'./.bzr/checkout/dirstate',
603
'./.bzr/checkout/stat-cache',
604
'./.bzr/checkout/merge-hashes',
605
'./.bzr/merge-hashes',
608
self.assertRepositoryHasSameItems(tree.branch.repository,
609
target.open_repository())
611
def test_clone_bzrdir_tree_branch_reference(self):
612
# a tree with a branch reference (aka a checkout)
613
# should stay a checkout on clone.
614
referenced_branch = self.make_branch('referencced')
615
dir = self.make_bzrdir('source')
617
reference = bzrlib.branch.BranchReferenceFormat().initialize(dir,
618
target_branch=referenced_branch)
619
except errors.IncompatibleFormat:
620
# this is ok too, not all formats have to support references.
622
self.createWorkingTreeOrSkip(dir)
623
target = dir.clone(self.get_url('target'))
624
self.skipIfNoWorkingTree(target)
625
self.assertNotEqual(dir.transport.base, target.transport.base)
626
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
627
['./.bzr/stat-cache',
628
'./.bzr/checkout/stat-cache',
629
'./.bzr/checkout/merge-hashes',
630
'./.bzr/merge-hashes',
631
'./.bzr/repository/inventory.knit',
634
335
def test_clone_bzrdir_tree_revision(self):
635
336
# test for revision limiting, [smoke test, not corner case checks].
636
337
# make a tree with a revision with a last-revision
739
440
target.open_branch()
740
441
self.openWorkingTreeIfLocal(target)
742
def test_sprout_bzrdir_repository(self):
743
tree = self.make_branch_and_tree('commit_tree')
744
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
746
tree.commit('revision 1', rev_id='1')
747
dir = self.make_bzrdir('source')
748
repo = dir.create_repository()
749
repo.fetch(tree.branch.repository)
750
self.assertTrue(repo.has_revision('1'))
753
_mod_revision.is_null(_mod_revision.ensure_null(
754
dir.open_branch().last_revision())))
755
except errors.NotBranchError:
757
target = dir.sprout(self.get_url('target'))
758
self.assertNotEqual(dir.transport.base, target.transport.base)
759
# testing inventory isn't reasonable for repositories
760
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
766
'./.bzr/repository/inventory.knit',
769
local_inventory = dir.transport.local_abspath('inventory')
770
except errors.NotLocalUrl:
773
# If we happen to have a tree, we'll guarantee everything
774
# except for the tree root is the same.
775
inventory_f = file(local_inventory, 'rb')
776
self.addCleanup(inventory_f.close)
777
self.assertContainsRe(inventory_f.read(),
778
'<inventory format="5">\n</inventory>\n')
780
if e.errno != errno.ENOENT:
783
443
def test_sprout_bzrdir_with_repository_to_shared(self):
784
444
tree = self.make_branch_and_tree('commit_tree')
785
445
self.build_tree(['commit_tree/foo'])
884
544
target = self.sproutOrSkip(dir, self.get_url('target'), revision_id='2')
885
545
raise TestSkipped('revision limiting not strict yet')
887
def test_sprout_bzrdir_branch_and_repo(self):
888
tree = self.make_branch_and_tree('commit_tree')
889
self.build_tree(['commit_tree/foo'])
891
tree.commit('revision 1')
892
source = self.make_branch('source')
893
tree.branch.repository.copy_content_into(source.repository)
894
tree.bzrdir.open_branch().copy_content_into(source)
896
target = dir.sprout(self.get_url('target'))
897
self.assertNotEqual(dir.transport.base, target.transport.base)
898
target_repo = target.open_repository()
899
self.assertRepositoryHasSameItems(source.repository, target_repo)
900
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
902
'./.bzr/basis-inventory-cache',
903
'./.bzr/branch/branch.conf',
904
'./.bzr/branch/parent',
906
'./.bzr/checkout/inventory',
907
'./.bzr/checkout/stat-cache',
915
547
def test_sprout_bzrdir_branch_and_repo_shared(self):
916
548
# sprouting a branch with a repo into a shared repo uses the shared
1036
668
target = dir.sprout(self.get_url('target'), revision_id='1')
1037
669
self.assertEqual('1', target.open_branch().last_revision())
1039
def test_sprout_bzrdir_tree_branch_repo(self):
1040
tree = self.make_branch_and_tree('source')
1041
self.build_tree(['foo'], transport=tree.bzrdir.transport.clone('..'))
1043
tree.commit('revision 1')
1045
target = self.sproutOrSkip(dir, self.get_url('target'))
1046
self.assertNotEqual(dir.transport.base, target.transport.base)
1047
self.assertDirectoriesEqual(dir.root_transport, target.root_transport,
1049
'./.bzr/branch/branch.conf',
1050
'./.bzr/branch/parent',
1051
'./.bzr/checkout/dirstate',
1052
'./.bzr/checkout/stat-cache',
1053
'./.bzr/checkout/inventory',
1056
'./.bzr/repository',
1057
'./.bzr/stat-cache',
1059
self.assertRepositoryHasSameItems(
1060
tree.branch.repository, target.open_repository())
1062
671
def test_sprout_bzrdir_tree_branch_reference(self):
1063
672
# sprouting should create a repository if needed and a sprouted branch.
1064
673
# the tree state should not be copied.
1804
1413
text = dir._format.get_format_description()
1805
1414
self.failUnless(len(text))
1807
def test_retire_bzrdir(self):
1808
bd = self.make_bzrdir('.')
1809
transport = bd.root_transport
1810
# must not overwrite existing directories
1811
self.build_tree(['.bzr.retired.0/', '.bzr.retired.0/junk',],
1812
transport=transport)
1813
self.failUnless(transport.has('.bzr'))
1815
self.failIf(transport.has('.bzr'))
1816
self.failUnless(transport.has('.bzr.retired.1'))
1818
def test_retire_bzrdir_limited(self):
1819
bd = self.make_bzrdir('.')
1820
transport = bd.root_transport
1821
# must not overwrite existing directories
1822
self.build_tree(['.bzr.retired.0/', '.bzr.retired.0/junk',],
1823
transport=transport)
1824
self.failUnless(transport.has('.bzr'))
1825
self.assertRaises((errors.FileExists, errors.DirectoryNotEmpty),
1826
bd.retire_bzrdir, limit=0)
1829
1417
class TestBreakLock(TestCaseWithControlDir):