~bzr-pqm/bzr/bzr.dev

1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
1
# Copyright (C) 2006 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
16
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
17
"""Tests for the (un)lock interfaces on all working tree implemenations."""
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
18
4648.1.3 by Robert Collins
Improve behaviour of tests that have a reasonable excuse for causing locking issues on windows selftest.
19
import sys
20
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
21
from bzrlib import (
22
    branch,
23
    errors,
24
    lockdir,
25
    )
4648.1.3 by Robert Collins
Improve behaviour of tests that have a reasonable excuse for causing locking issues on windows selftest.
26
from bzrlib.tests import TestSkipped
4523.1.4 by Martin Pool
Rename remaining *_implementations tests
27
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
28
29
30
class TestWorkingTreeLocking(TestCaseWithWorkingTree):
31
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
32
    def test_trivial_lock_read_unlock(self):
33
        """Locking and unlocking should work trivially."""
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
34
        wt = self.make_branch_and_tree('.')
35
36
        self.assertFalse(wt.is_locked())
37
        self.assertFalse(wt.branch.is_locked())
38
        wt.lock_read()
39
        try:
40
            self.assertTrue(wt.is_locked())
41
            self.assertTrue(wt.branch.is_locked())
42
        finally:
43
            wt.unlock()
44
        self.assertFalse(wt.is_locked())
45
        self.assertFalse(wt.branch.is_locked())
46
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
47
    def test_trivial_lock_write_unlock(self):
48
        """Locking for write and unlocking should work trivially."""
49
        wt = self.make_branch_and_tree('.')
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
50
51
        self.assertFalse(wt.is_locked())
52
        self.assertFalse(wt.branch.is_locked())
53
        wt.lock_write()
54
        try:
55
            self.assertTrue(wt.is_locked())
56
            self.assertTrue(wt.branch.is_locked())
57
        finally:
58
            wt.unlock()
59
        self.assertFalse(wt.is_locked())
60
        self.assertFalse(wt.branch.is_locked())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
61
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
62
    def test_trivial_lock_tree_write_unlock(self):
63
        """Locking for tree write is ok when the branch is not locked."""
64
        wt = self.make_branch_and_tree('.')
65
66
        self.assertFalse(wt.is_locked())
67
        self.assertFalse(wt.branch.is_locked())
68
        wt.lock_tree_write()
69
        try:
70
            self.assertTrue(wt.is_locked())
71
            self.assertTrue(wt.branch.is_locked())
72
        finally:
73
            wt.unlock()
74
        self.assertFalse(wt.is_locked())
75
        self.assertFalse(wt.branch.is_locked())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
76
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
77
    def test_trivial_lock_tree_write_branch_read_locked(self):
78
        """It is ok to lock_tree_write when the branch is read locked."""
79
        wt = self.make_branch_and_tree('.')
80
81
        self.assertFalse(wt.is_locked())
82
        self.assertFalse(wt.branch.is_locked())
83
        wt.branch.lock_read()
84
        try:
85
            wt.lock_tree_write()
86
        except errors.ReadOnlyError:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
87
            # When ReadOnlyError is raised, it indicates that the
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
88
            # workingtree shares its lock with the branch, which is what
89
            # the git/hg/bzr0.6 formats do.
90
            # in this case, no lock should have been taken - but the tree
91
            # will have been locked because they share a lock. Unlocking
92
            # just the branch should make everything match again correctly.
93
            wt.branch.unlock()
94
            self.assertFalse(wt.is_locked())
95
            self.assertFalse(wt.branch.is_locked())
96
            return
97
        try:
98
            self.assertTrue(wt.is_locked())
99
            self.assertTrue(wt.branch.is_locked())
100
        finally:
101
            wt.unlock()
102
        self.assertFalse(wt.is_locked())
103
        self.assertTrue(wt.branch.is_locked())
104
        wt.branch.unlock()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
105
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
106
    def _test_unlock_with_lock_method(self, methodname):
107
        """Create a tree and then test its unlocking behaviour.
108
109
        :param methodname: The lock method to use to establish locks.
110
        """
4648.1.3 by Robert Collins
Improve behaviour of tests that have a reasonable excuse for causing locking issues on windows selftest.
111
        if sys.platform == "win32":
112
            raise TestSkipped("don't use oslocks on win32 in unix manner")
113
        # This helper takes a write lock on the source tree, then opens a
114
        # second copy and tries to grab a read lock. This works on Unix and is
115
        # a reasonable way to detect when the file is actually written to, but
116
        # it won't work (as a test) on Windows. It might be nice to instead
117
        # stub out the functions used to write and that way do both less work
118
        # and also be able to execute on Windows.
4523.4.17 by John Arbash Meinel
Now we got to the per-workingtree tests, etc.
119
        self.thisFailsStrictLockCheck()
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
120
        # when unlocking the last lock count from tree_write_lock,
121
        # the tree should do a flush().
122
        # we test that by changing the inventory using set_root_id
123
        tree = self.make_branch_and_tree('tree')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
124
        # prepare for a series of changes that will modify the
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
125
        # inventory
126
        getattr(tree, methodname)()
127
        # note that we dont have a try:finally here because of two reasons:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
128
        # firstly there will only be errors reported if the test fails, and
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
129
        # when it fails thats ok as long as the test suite cleanup still works,
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
130
        # which it will as the lock objects are released (thats where the
131
        # warning comes from.  Secondly, it is hard in this test to be
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
132
        # sure that we've got the right interactions between try:finally
133
        # and the lock/unlocks we are doing.
134
        getattr(tree, methodname)()
135
        # this should really do something within the public api
136
        # e.g. mkdir('foo') but all the mutating methods at the
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
137
        # moment trigger inventory writes and thus will not
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
138
        # let us trigger a read-when-dirty situation.
139
        old_root = tree.get_root_id()
140
        tree.set_root_id('new-root')
141
        # to detect that the inventory is written by unlock, we
142
        # first check that it was not written yet.
4523.4.17 by John Arbash Meinel
Now we got to the per-workingtree tests, etc.
143
        # TODO: This requires taking a read lock while we are holding the above
144
        #       write lock, which shouldn't actually be possible
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
145
        reference_tree = tree.bzrdir.open_workingtree()
146
        self.assertEqual(old_root, reference_tree.get_root_id())
147
        # now unlock the second held lock, which should do nothing.
148
        tree.unlock()
149
        reference_tree = tree.bzrdir.open_workingtree()
150
        self.assertEqual(old_root, reference_tree.get_root_id())
151
        # unlocking the first lock we took will now flush.
152
        tree.unlock()
153
        # and check it was written using another reference tree
154
        reference_tree = tree.bzrdir.open_workingtree()
155
        self.assertEqual('new-root', reference_tree.get_root_id())
156
157
    def test_unlock_from_tree_write_lock_flushes(self):
158
        self._test_unlock_with_lock_method("lock_tree_write")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
159
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
160
    def test_unlock_from_write_lock_flushes(self):
161
        self._test_unlock_with_lock_method("lock_write")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
162
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
163
    def test_unlock_branch_failures(self):
164
        """If the branch unlock fails the tree must still unlock."""
165
        # The public interface for WorkingTree requires a branch, but
166
        # does not require that the working tree use the branch - its
167
        # implementation specific how the WorkingTree, Branch, and Repository
168
        # hang together.
169
        # in order to test that implementations which *do* unlock via the branch
170
        # do so correctly, we unlock the branch after locking the working tree.
171
        # The next unlock on working tree should trigger a LockNotHeld exception
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
172
        # from the branch object, which must be exposed to the caller. To meet
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
173
        # our object model - where locking a tree locks its branch, and
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
174
        # unlocking a branch does not unlock a working tree, *even* for
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
175
        # all-in-one implementations like bzr 0.6, git, and hg, implementations
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
176
        # must have some separate counter for each object, so our explicit
177
        # unlock should trigger some error on all implementations, and
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
178
        # requiring that to be LockNotHeld seems reasonable.
179
        #
180
        # we use this approach rather than decorating the Branch, because the
181
        # public interface of WorkingTree does not permit altering the branch
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
182
        # object - and we cannot tell which attribute might allow us to
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
183
        # backdoor-in and change it reliably. For implementation specific tests
184
        # we can do such skullduggery, but not for interface specific tests.
185
        # And, its simpler :)
186
        wt = self.make_branch_and_tree('.')
187
188
        self.assertFalse(wt.is_locked())
189
        self.assertFalse(wt.branch.is_locked())
190
        wt.lock_write()
191
        self.assertTrue(wt.is_locked())
192
        self.assertTrue(wt.branch.is_locked())
193
194
        # manually unlock the branch, preparing a LockNotHeld error.
195
        wt.branch.unlock()
196
        # the branch *may* still be locked here, if its an all-in-one
1852.4.6 by Robert Collins
Review feedback.
197
        # implementation because there is a single lock object with three
198
        # references on it, and unlocking the branch only drops this by two
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
199
        self.assertRaises(errors.LockNotHeld, wt.unlock)
200
        # but now, the tree must be unlocked
201
        self.assertFalse(wt.is_locked())
202
        # and the branch too.
203
        self.assertFalse(wt.branch.is_locked())
204
205
    def test_failing_to_lock_branch_does_not_lock(self):
206
        """If the branch cannot be locked, dont lock the tree."""
207
        # Many implementations treat read-locks as non-blocking, but some
208
        # treat them as blocking with writes.. Accordingly we test this by
209
        # opening the branch twice, and locking the branch for write in the
210
        # second instance.  Our lock contract requires separate instances to
211
        # mutually exclude if a lock is exclusive at all: If we get no error
212
        # locking, the test still passes.
213
        wt = self.make_branch_and_tree('.')
214
        branch_copy = branch.Branch.open('.')
215
        branch_copy.lock_write()
216
        try:
217
            try:
218
                wt.lock_read()
1852.4.5 by Robert Collins
Change bare except in working tree locking tests to catch LockError only.
219
            except errors.LockError:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
220
                # any error here means the locks are exclusive in some
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
221
                # manner
222
                self.assertFalse(wt.is_locked())
223
                self.assertFalse(wt.branch.is_locked())
224
                return
225
            else:
226
                # no error - the branch allows read locks while writes
227
                # are taken, just pass.
228
                wt.unlock()
229
        finally:
230
            branch_copy.unlock()
231
232
    def test_failing_to_lock_write_branch_does_not_lock(self):
233
        """If the branch cannot be write locked, dont lock the tree."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
234
        # all implementations of branch are required to treat write
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
235
        # locks as blocking (compare to repositories which are not required
236
        # to do so).
237
        # Accordingly we test this by opening the branch twice, and locking the
238
        # branch for write in the second instance.  Our lock contract requires
239
        # separate instances to mutually exclude.
240
        wt = self.make_branch_and_tree('.')
241
        branch_copy = branch.Branch.open('.')
242
        branch_copy.lock_write()
243
        try:
244
            try:
3287.4.2 by Martin Pool
Change more tests to use reduceLockdirTimeout
245
                self.assertRaises(errors.LockError, wt.lock_write)
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
246
                self.assertFalse(wt.is_locked())
247
                self.assertFalse(wt.branch.is_locked())
248
            finally:
249
                if wt.is_locked():
250
                    wt.unlock()
251
        finally:
252
            branch_copy.unlock()
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
253
254
    def test_failing_to_lock_tree_write_branch_does_not_lock(self):
255
        """If the branch cannot be read locked, dont lock the tree."""
256
        # Many implementations treat read-locks as non-blocking, but some
257
        # treat them as blocking with writes.. Accordingly we test this by
258
        # opening the branch twice, and locking the branch for write in the
259
        # second instance.  Our lock contract requires separate instances to
260
        # mutually exclude if a lock is exclusive at all: If we get no error
261
        # locking, the test still passes.
262
        wt = self.make_branch_and_tree('.')
263
        branch_copy = branch.Branch.open('.')
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
264
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
265
        branch_copy.lock_write()
266
        try:
267
            try:
268
                wt.lock_tree_write()
269
            except errors.LockError:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
270
                # any error here means the locks are exclusive in some
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
271
                # manner
272
                self.assertFalse(wt.is_locked())
273
                self.assertFalse(wt.branch.is_locked())
274
                return
275
            else:
276
                # no error - the branch allows read locks while writes
277
                # are taken, just pass.
278
                wt.unlock()
279
        finally:
280
            branch_copy.unlock()