[MERGE] Makeing WorkingTree nicer to derive from.

Martin Pool mbp at canonical.com
Fri Jul 21 09:52:11 BST 2006


On 16 Jul 2006, Robert Collins <robertc at robertcollins.net> wrote:

Just some detail-oriented comments while we're still discussing it.

> +    def test_unlock_branch_failures(self):
> +        """If the branch unlock fails the tree must still unlock."""
> +        # The public interface for WorkingTree requires a branch, but
> +        # does not require that the working tree use the branch - its
> +        # implementation specific how the WorkingTree, Branch, and Repository
> +        # hang together.
> +        # in order to test that implementations which *do* unlock via the branch
> +        # do so correctly, we unlock the branch after locking the working tree.
> +        # The next unlock on working tree should trigger a LockNotHeld exception
> +        # from the branch object, which must be exposed to the caller. To meet 
> +        # our object model - where locking a tree locks its branch, and
> +        # unlocking a branch does not unlock a working tree, *even* for 
> +        # all-in-one implementations like bzr 0.6, git, and hg, implementations
> +        # must have some separate counter for each object, so our explicit 
> +        # unlock should trigger some error on all implementations, and 
> +        # requiring that to be LockNotHeld seems reasonable.
> +        #
> +        # we use this approach rather than decorating the Branch, because the
> +        # public interface of WorkingTree does not permit altering the branch
> +        # object - and we cannot tell which attribute might allow us to 
> +        # backdoor-in and change it reliably. For implementation specific tests
> +        # we can do such skullduggery, but not for interface specific tests.
> +        # And, its simpler :)
> +        wt = self.make_branch_and_tree('.')
> +
> +        self.assertFalse(wt.is_locked())
> +        self.assertFalse(wt.branch.is_locked())
> +        wt.lock_write()
> +        self.assertTrue(wt.is_locked())
> +        self.assertTrue(wt.branch.is_locked())
> +

> +        # manually unlock the branch, preparing a LockNotHeld error.
> +        wt.branch.unlock()
> +        # the branch *may* still be locked here, if its an all-in-one
> +        # implementation
> +        self.assertRaises(errors.LockNotHeld, wt.unlock)

Uh, so if it's still held it won't raise the exception, will it

> +        # but now, the tree must be unlocked
> +        self.assertFalse(wt.is_locked())
> +        # and the branch too.
> +        self.assertFalse(wt.branch.is_locked())
> +

> +    def test_failing_to_lock_branch_does_not_lock(self):
> +        """If the branch cannot be locked, dont lock the tree."""

I think you can afford to say _does_not_lock_tree, and similarly below. :-)

> +        # Many implementations treat read-locks as non-blocking, but some
> +        # treat them as blocking with writes.. Accordingly we test this by
> +        # opening the branch twice, and locking the branch for write in the
> +        # second instance.  Our lock contract requires separate instances to
> +        # mutually exclude if a lock is exclusive at all: If we get no error
> +        # locking, the test still passes.
> +        wt = self.make_branch_and_tree('.')
> +        branch_copy = branch.Branch.open('.')
> +        branch_copy.lock_write()
> +        try:
> +            try:
> +                wt.lock_read()
> +            except:
> +                # any error here means the locks are exclusive in some 
> +                # manner
> +                self.assertFalse(wt.is_locked())
> +                self.assertFalse(wt.branch.is_locked())
> +                return

Consider KeyboardInterrupt, and the rule against bare excepts.  I think
in every case we should get a LockError; if any of the classes allow a
bare IOError up we should fix them.

-- 
Martin




More information about the bazaar mailing list