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