Rev 2781: Add reasonably comprehensive tests for path last modified and per file graph behaviour. in http://people.ubuntu.com/~robertc/baz2.0/commit
Robert Collins
robertc at robertcollins.net
Tue Sep 4 04:53:17 BST 2007
At http://people.ubuntu.com/~robertc/baz2.0/commit
------------------------------------------------------------
revno: 2781
revision-id: robertc at robertcollins.net-20070904035307-y5jacs7zl15v2nvo
parent: robertc at robertcollins.net-20070903221720-9k1y25x0x60rk38b
committer: Robert Collins <robertc at robertcollins.net>
branch nick: commit
timestamp: Tue 2007-09-04 13:53:07 +1000
message:
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
modified:
bzrlib/bzrdir.py bzrdir.py-20060131065624-156dfea39c4387cb
bzrlib/inventory.py inventory.py-20050309040759-6648b84ca2005b37
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/repository_implementations/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py 2007-08-20 05:48:40 +0000
+++ b/bzrlib/bzrdir.py 2007-09-04 03:53:07 +0000
@@ -35,6 +35,7 @@
import bzrlib
from bzrlib import (
errors,
+ graph,
lockable_files,
lockdir,
registry,
@@ -1934,18 +1935,24 @@
w = Weave(file_id)
self.text_weaves[file_id] = w
text_changed = False
- previous_entries = ie.find_previous_heads(parent_invs,
- None,
- None,
- entry_vf=w)
- for old_revision in previous_entries:
- # if this fails, its a ghost ?
- assert old_revision in self.converted_revs, \
- "Revision {%s} not in converted_revs" % old_revision
+ parent_candiate_entries = ie.parent_candidates(parent_invs)
+ for old_revision in parent_candiate_entries.keys():
+ # if this fails, its a ghost ?
+ assert old_revision in self.converted_revs, \
+ "Revision {%s} not in converted_revs" % old_revision
+ heads = graph.Graph(self).heads(parent_candiate_entries.keys())
+ # XXX: Note that this is unordered - and this is tolerable because
+ # the previous code was also unordered.
+ previous_entries = dict((head, parent_candiate_entries[head]) for head
+ in heads)
self.snapshot_ie(previous_entries, ie, w, rev_id)
del ie.text_id
assert getattr(ie, 'revision', None) is not None
+ def get_parents(self, revision_ids):
+ for revision_id in revision_ids:
+ yield self.revisions[revision_id].parent_ids
+
def snapshot_ie(self, previous_revisions, ie, w, rev_id):
# TODO: convert this logic, which is ~= snapshot to
# a call to:. This needs the path figured out. rather than a work_tree
=== modified file 'bzrlib/inventory.py'
--- a/bzrlib/inventory.py 2007-09-03 01:57:12 +0000
+++ b/bzrlib/inventory.py 2007-09-04 03:53:07 +0000
@@ -167,7 +167,6 @@
"""Find possible per-file graph parents.
This is currently defined by:
- - The kind has not changed (* not sure why this is a clause *)
- Select the last changed revision in the parent inventory.
- Do deal with a short lived bug in bzr 0.8's development two entries
that have the same last changed but different 'x' bit settings are
@@ -180,9 +179,6 @@
if self.file_id in inv:
ie = inv[self.file_id]
assert ie.file_id == self.file_id
- if ie.kind != self.kind:
- # Can't be a candidate if the kind has changed.
- continue
if ie.revision in candidates:
# same revision value in two different inventories:
# correct possible inconsistencies:
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2007-08-29 01:16:53 +0000
+++ b/bzrlib/tests/__init__.py 2007-09-04 03:53:07 +0000
@@ -2613,6 +2613,17 @@
return self.__class__.__name__
+class _SymlinkFeature(Feature):
+
+ def _probe(self):
+ return osutils.has_symlinks()
+
+ def feature_name(self):
+ return 'symlinks'
+
+SymlinkFeature = _SymlinkFeature()
+
+
class TestScenarioApplier(object):
"""A tool to apply scenarios to tests."""
=== modified file 'bzrlib/tests/repository_implementations/test_commit_builder.py'
--- a/bzrlib/tests/repository_implementations/test_commit_builder.py 2007-08-28 01:58:42 +0000
+++ b/bzrlib/tests/repository_implementations/test_commit_builder.py 2007-09-04 03:53:07 +0000
@@ -16,6 +16,9 @@
"""Tests for repository commit builder."""
+from errno import EISDIR
+import os
+
from bzrlib import inventory
from bzrlib.errors import NonAsciiRevisionId, CannotSetRevisionId
from bzrlib.repository import CommitBuilder
@@ -173,3 +176,268 @@
self.addCleanup(basis_tree.unlock)
self.assertEqual(rev_id, basis_tree.inventory.root.revision)
+ def _get_revtrees(self, tree, revision_ids):
+ trees = list(tree.branch.repository.revision_trees(revision_ids))
+ for tree in trees:
+ tree.lock_read()
+ self.addCleanup(tree.unlock)
+ return trees
+
+ def test_last_modified_revision_after_commit_root_unchanged(self):
+ # commiting without changing the root does not change the
+ # last modified except on non-rich-root-repositories.
+ tree = self.make_branch_and_tree('.')
+ rev1 = tree.commit('')
+ rev2 = tree.commit('')
+ tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
+ self.assertEqual(rev1, tree1.inventory.root.revision)
+ if tree.branch.repository.supports_rich_root():
+ self.assertEqual(rev1, tree2.inventory.root.revision)
+ else:
+ self.assertEqual(rev2, tree2.inventory.root.revision)
+
+ def _add_commit_check_unchanged(self, tree, name):
+ tree.add([name], [name + 'id'])
+ rev1 = tree.commit('')
+ rev2 = tree.commit('')
+ tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
+ self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
+ self.assertEqual(rev1, tree2.inventory[name + 'id'].revision)
+ self.assertFileAncestry([rev1], tree, name)
+
+ def test_last_modified_revision_after_commit_dir_unchanged(self):
+ # committing without changing a dir does not change the last modified.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['dir/'])
+ self._add_commit_check_unchanged(tree, 'dir')
+
+ def test_last_modified_revision_after_commit_dir_contents_unchanged(self):
+ # committing without changing a dir does not change the last modified
+ # of the dir even the dirs contents are changed.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['dir/'])
+ tree.add(['dir'], ['dirid'])
+ rev1 = tree.commit('')
+ self.build_tree(['dir/content'])
+ tree.add(['dir/content'], ['contentid'])
+ rev2 = tree.commit('')
+ tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
+ self.assertEqual(rev1, tree1.inventory['dirid'].revision)
+ self.assertEqual(rev1, tree2.inventory['dirid'].revision)
+ self.assertFileAncestry([rev1], tree, 'dir')
+
+ def test_last_modified_revision_after_commit_file_unchanged(self):
+ # committing without changing a file does not change the last modified.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['file'])
+ self._add_commit_check_unchanged(tree, 'file')
+
+ def test_last_modified_revision_after_commit_link_unchanged(self):
+ # committing without changing a link does not change the last modified.
+ self.requireFeature(tests.SymlinkFeature)
+ tree = self.make_branch_and_tree('.')
+ os.symlink('target', 'link')
+ self._add_commit_check_unchanged(tree, 'link')
+
+ def _add_commit_renamed_check_changed(self, tree, name):
+ def rename():
+ tree.rename_one(name, 'new_' + name)
+ self._add_commit_change_check_changed(tree, name, rename)
+
+ def test_last_modified_revision_after_rename_dir_changes(self):
+ # renaming a dir changes the last modified.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['dir/'])
+ self._add_commit_renamed_check_changed(tree, 'dir')
+
+ def test_last_modified_revision_after_rename_file_changes(self):
+ # renaming a file changes the last modified.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['file'])
+ self._add_commit_renamed_check_changed(tree, 'file')
+
+ def test_last_modified_revision_after_rename_link_changes(self):
+ # renaming a link changes the last modified.
+ self.requireFeature(tests.SymlinkFeature)
+ tree = self.make_branch_and_tree('.')
+ os.symlink('target', 'link')
+ self._add_commit_renamed_check_changed(tree, 'link')
+
+ def _add_commit_reparent_check_changed(self, tree, name):
+ self.build_tree(['newparent/'])
+ tree.add(['newparent'])
+ def reparent():
+ tree.rename_one(name, 'newparent/new_' + name)
+ self._add_commit_change_check_changed(tree, name, reparent)
+
+ def test_last_modified_revision_after_reparent_dir_changes(self):
+ # reparenting a dir changes the last modified.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['dir/'])
+ self._add_commit_reparent_check_changed(tree, 'dir')
+
+ def test_last_modified_revision_after_reparent_file_changes(self):
+ # reparenting a file changes the last modified.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['file'])
+ self._add_commit_reparent_check_changed(tree, 'file')
+
+ def test_last_modified_revision_after_reparent_link_changes(self):
+ # reparenting a link changes the last modified.
+ self.requireFeature(tests.SymlinkFeature)
+ tree = self.make_branch_and_tree('.')
+ os.symlink('target', 'link')
+ self._add_commit_reparent_check_changed(tree, 'link')
+
+ def _add_commit_change_check_changed(self, tree, name, changer):
+ tree.add([name], [name + 'id'])
+ rev1 = tree.commit('')
+ changer()
+ rev2 = tree.commit('')
+ tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
+ self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
+ self.assertEqual(rev2, tree2.inventory[name + 'id'].revision)
+ self.assertFileAncestry([rev1, rev2], tree, name)
+
+ def assertFileAncestry(self, ancestry, tree, name, alt_ancestry=None):
+ # all the changes that have occured should be in the ancestry
+ # (closest to a public per-file graph API we have today)
+ tree.lock_read()
+ self.addCleanup(tree.unlock)
+ vw = tree.branch.repository.weave_store.get_weave(name + 'id',
+ tree.branch.repository.get_transaction())
+ result = vw.get_ancestry([ancestry[-1]])
+ if alt_ancestry is None:
+ self.assertEqual(ancestry, result)
+ else:
+ self.assertSubset([tuple(result)],
+ [tuple(ancestry), tuple(alt_ancestry)])
+
+ def test_last_modified_revision_after_content_file_changes(self):
+ # altering a file changes the last modified.
+ tree = self.make_branch_and_tree('.')
+ self.build_tree(['file'])
+ def change_file():
+ tree.put_file_bytes_non_atomic('fileid', 'new content')
+ self._add_commit_change_check_changed(tree, 'file', change_file)
+
+ def test_last_modified_revision_after_content_link_changes(self):
+ # changing a link changes the last modified.
+ self.requireFeature(tests.SymlinkFeature)
+ tree = self.make_branch_and_tree('.')
+ os.symlink('target', 'link')
+ def change_link():
+ os.unlink('link')
+ os.symlink('newtarget', 'link')
+ self._add_commit_change_check_changed(tree, 'link', change_link)
+
+ def _commit_sprout(self, tree, name):
+ tree.add([name], [name + 'id'])
+ rev_id = tree.commit('')
+ return rev_id, tree.bzrdir.sprout('t2').open_workingtree()
+
+ def _rename_in_tree(self, tree, name):
+ tree.rename_one(name, 'new_' + name)
+ return tree.commit('')
+
+ def _commit_sprout_rename_merge(self, tree1, name):
+ rev1, tree2 = self._commit_sprout(tree1, name)
+ # change both sides equally
+ rev2 = self._rename_in_tree(tree1, name)
+ rev3 = self._rename_in_tree(tree2, name)
+ tree1.merge_from_branch(tree2.branch)
+ rev4 = tree1.commit('')
+ tree3, = self._get_revtrees(tree1, [rev4])
+ self.assertEqual(rev4, tree3.inventory[name + 'id'].revision)
+ self.assertFileAncestry([rev1, rev2, rev3, rev4], tree1, name,
+ [rev1, rev3, rev2, rev4])
+
+ def test_last_modified_revision_after_merge_dir_changes(self):
+ # merge a dir changes the last modified.
+ tree1 = self.make_branch_and_tree('t1')
+ self.build_tree(['t1/dir/'])
+ self._commit_sprout_rename_merge(tree1, 'dir')
+
+ def test_last_modified_revision_after_merge_file_changes(self):
+ # merge a file changes the last modified.
+ tree1 = self.make_branch_and_tree('t1')
+ self.build_tree(['t1/file'])
+ self._commit_sprout_rename_merge(tree1, 'file')
+
+ def test_last_modified_revision_after_merge_link_changes(self):
+ # merge a link changes the last modified.
+ self.requireFeature(tests.SymlinkFeature)
+ tree1 = self.make_branch_and_tree('t1')
+ os.symlink('target', 't1/link')
+ self._commit_sprout_rename_merge(tree1, 'link')
+
+ def _commit_sprout_rename_merge_converged(self, tree1, name):
+ rev1, tree2 = self._commit_sprout(tree1, name)
+ # change on the other side to merge back
+ rev2 = self._rename_in_tree(tree2, name)
+ tree1.merge_from_branch(tree2.branch)
+ rev3 = tree1.commit('')
+ tree3, = self._get_revtrees(tree1, [rev2])
+ self.assertEqual(rev2, tree3.inventory[name + 'id'].revision)
+ self.assertFileAncestry([rev1, rev2], tree1, name)
+
+ def test_last_modified_revision_after_converged_merge_dir_changes(self):
+ # merge a dir changes the last modified.
+ tree1 = self.make_branch_and_tree('t1')
+ self.build_tree(['t1/dir/'])
+ self._commit_sprout_rename_merge_converged(tree1, 'dir')
+
+ def test_last_modified_revision_after_converged_merge_file_changes(self):
+ # merge a file changes the last modified.
+ tree1 = self.make_branch_and_tree('t1')
+ self.build_tree(['t1/file'])
+ self._commit_sprout_rename_merge_converged(tree1, 'file')
+
+ def test_last_modified_revision_after_converged_merge_link_changes(self):
+ # merge a link changes the last modified.
+ self.requireFeature(tests.SymlinkFeature)
+ tree1 = self.make_branch_and_tree('t1')
+ os.symlink('target', 't1/link')
+ self._commit_sprout_rename_merge_converged(tree1, 'link')
+
+ def make_dir(self, name):
+ self.build_tree([name + '/'])
+
+ def make_file(self, name):
+ self.build_tree([name])
+
+ def make_link(self, name):
+ self.requireFeature(tests.SymlinkFeature)
+ os.symlink('target', name)
+
+ def _check_kind_change(self, make_before, make_after):
+ tree = self.make_branch_and_tree('.')
+ path = 'name'
+ make_before(path)
+ def change_kind():
+ try:
+ os.unlink(path)
+ except OSError, e:
+ if e.errno != EISDIR:
+ raise
+ os.rmdir(path)
+ make_after(path)
+ self._add_commit_change_check_changed(tree, path, change_kind)
+
+ def test_last_modified_dir_file(self):
+ self._check_kind_change(self.make_dir, self.make_file)
+
+ def test_last_modified_dir_link(self):
+ self._check_kind_change(self.make_dir, self.make_link)
+
+ def test_last_modified_link_file(self):
+ self._check_kind_change(self.make_link, self.make_file)
+
+ def test_last_modified_link_dir(self):
+ self._check_kind_change(self.make_link, self.make_dir)
+
+ def test_last_modified_file_dir(self):
+ self._check_kind_change(self.make_file, self.make_dir)
+
+ def test_last_modified_file_link(self):
+ self._check_kind_change(self.make_file, self.make_link)
More information about the bazaar-commits
mailing list