~bzr-pqm/bzr/bzr.dev

5218.2.2 by John Arbash Meinel
Bring in the global chk change, which includes some more bzr.dev code.
1
# Copyright (C) 2006, 2008, 2009, 2010 Canonical Ltd
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.
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
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
27
from bzrlib.tests.matchers import *
4523.1.4 by Martin Pool
Rename remaining *_implementations tests
28
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.
29
30
31
class TestWorkingTreeLocking(TestCaseWithWorkingTree):
32
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
33
    def test_trivial_lock_read_unlock(self):
34
        """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.
35
        wt = self.make_branch_and_tree('.')
36
37
        self.assertFalse(wt.is_locked())
38
        self.assertFalse(wt.branch.is_locked())
39
        wt.lock_read()
40
        try:
41
            self.assertTrue(wt.is_locked())
42
            self.assertTrue(wt.branch.is_locked())
43
        finally:
44
            wt.unlock()
45
        self.assertFalse(wt.is_locked())
46
        self.assertFalse(wt.branch.is_locked())
47
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
48
    def test_lock_read_returns_unlocker(self):
49
        wt = self.make_branch_and_tree('.')
50
        self.assertThat(wt.lock_read, ReturnsUnlockable(wt))
51
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
52
    def test_trivial_lock_write_unlock(self):
53
        """Locking for write and unlocking should work trivially."""
54
        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.
55
56
        self.assertFalse(wt.is_locked())
57
        self.assertFalse(wt.branch.is_locked())
58
        wt.lock_write()
59
        try:
60
            self.assertTrue(wt.is_locked())
61
            self.assertTrue(wt.branch.is_locked())
62
        finally:
63
            wt.unlock()
64
        self.assertFalse(wt.is_locked())
65
        self.assertFalse(wt.branch.is_locked())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
66
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
67
    def test_lock_write_returns_unlocker(self):
68
        wt = self.make_branch_and_tree('.')
69
        self.assertThat(wt.lock_write, ReturnsUnlockable(wt))
70
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
71
    def test_trivial_lock_tree_write_unlock(self):
72
        """Locking for tree write is ok when the branch is not locked."""
73
        wt = self.make_branch_and_tree('.')
74
75
        self.assertFalse(wt.is_locked())
76
        self.assertFalse(wt.branch.is_locked())
77
        wt.lock_tree_write()
78
        try:
79
            self.assertTrue(wt.is_locked())
80
            self.assertTrue(wt.branch.is_locked())
81
        finally:
82
            wt.unlock()
83
        self.assertFalse(wt.is_locked())
84
        self.assertFalse(wt.branch.is_locked())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
85
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
86
    def test_lock_tree_write_returns_unlocker(self):
87
        wt = self.make_branch_and_tree('.')
88
        self.assertThat(wt.lock_tree_write, ReturnsUnlockable(wt))
89
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
90
    def test_trivial_lock_tree_write_branch_read_locked(self):
91
        """It is ok to lock_tree_write when the branch is read locked."""
92
        wt = self.make_branch_and_tree('.')
93
94
        self.assertFalse(wt.is_locked())
95
        self.assertFalse(wt.branch.is_locked())
96
        wt.branch.lock_read()
97
        try:
98
            wt.lock_tree_write()
99
        except errors.ReadOnlyError:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
100
            # When ReadOnlyError is raised, it indicates that the
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
101
            # workingtree shares its lock with the branch, which is what
102
            # the git/hg/bzr0.6 formats do.
103
            # in this case, no lock should have been taken - but the tree
104
            # will have been locked because they share a lock. Unlocking
105
            # just the branch should make everything match again correctly.
106
            wt.branch.unlock()
107
            self.assertFalse(wt.is_locked())
108
            self.assertFalse(wt.branch.is_locked())
109
            return
110
        try:
111
            self.assertTrue(wt.is_locked())
112
            self.assertTrue(wt.branch.is_locked())
113
        finally:
114
            wt.unlock()
115
        self.assertFalse(wt.is_locked())
116
        self.assertTrue(wt.branch.is_locked())
117
        wt.branch.unlock()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
118
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
119
    def _test_unlock_with_lock_method(self, methodname):
120
        """Create a tree and then test its unlocking behaviour.
121
122
        :param methodname: The lock method to use to establish locks.
123
        """
4648.1.3 by Robert Collins
Improve behaviour of tests that have a reasonable excuse for causing locking issues on windows selftest.
124
        if sys.platform == "win32":
125
            raise TestSkipped("don't use oslocks on win32 in unix manner")
126
        # This helper takes a write lock on the source tree, then opens a
127
        # second copy and tries to grab a read lock. This works on Unix and is
128
        # a reasonable way to detect when the file is actually written to, but
129
        # it won't work (as a test) on Windows. It might be nice to instead
130
        # stub out the functions used to write and that way do both less work
131
        # and also be able to execute on Windows.
4523.4.17 by John Arbash Meinel
Now we got to the per-workingtree tests, etc.
132
        self.thisFailsStrictLockCheck()
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
133
        # when unlocking the last lock count from tree_write_lock,
134
        # the tree should do a flush().
135
        # we test that by changing the inventory using set_root_id
136
        tree = self.make_branch_and_tree('tree')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
137
        # 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
138
        # inventory
139
        getattr(tree, methodname)()
140
        # 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
141
        # 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
142
        # 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
143
        # which it will as the lock objects are released (thats where the
144
        # 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
145
        # sure that we've got the right interactions between try:finally
146
        # and the lock/unlocks we are doing.
147
        getattr(tree, methodname)()
148
        # this should really do something within the public api
149
        # e.g. mkdir('foo') but all the mutating methods at the
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
150
        # moment trigger inventory writes and thus will not
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
151
        # let us trigger a read-when-dirty situation.
152
        old_root = tree.get_root_id()
153
        tree.set_root_id('new-root')
154
        # to detect that the inventory is written by unlock, we
155
        # first check that it was not written yet.
4523.4.17 by John Arbash Meinel
Now we got to the per-workingtree tests, etc.
156
        # TODO: This requires taking a read lock while we are holding the above
157
        #       write lock, which shouldn't actually be possible
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
158
        reference_tree = tree.bzrdir.open_workingtree()
159
        self.assertEqual(old_root, reference_tree.get_root_id())
160
        # now unlock the second held lock, which should do nothing.
161
        tree.unlock()
162
        reference_tree = tree.bzrdir.open_workingtree()
163
        self.assertEqual(old_root, reference_tree.get_root_id())
164
        # unlocking the first lock we took will now flush.
165
        tree.unlock()
166
        # and check it was written using another reference tree
167
        reference_tree = tree.bzrdir.open_workingtree()
168
        self.assertEqual('new-root', reference_tree.get_root_id())
169
170
    def test_unlock_from_tree_write_lock_flushes(self):
171
        self._test_unlock_with_lock_method("lock_tree_write")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
172
1986.5.3 by Robert Collins
New method ``WorkingTree.flush()`` which will write the current memory
173
    def test_unlock_from_write_lock_flushes(self):
174
        self._test_unlock_with_lock_method("lock_write")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
175
1852.4.3 by Robert Collins
Alter working tree lock and unlock tests to test via the interface rather than via unpublished internals.
176
    def test_unlock_branch_failures(self):
177
        """If the branch unlock fails the tree must still unlock."""
178
        # The public interface for WorkingTree requires a branch, but
179
        # does not require that the working tree use the branch - its
180
        # implementation specific how the WorkingTree, Branch, and Repository
181
        # hang together.
182
        # in order to test that implementations which *do* unlock via the branch
183
        # do so correctly, we unlock the branch after locking the working tree.
184
        # The next unlock on working tree should trigger a LockNotHeld exception
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
185
        # 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.
186
        # our object model - where locking a tree locks its branch, and
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
187
        # 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.
188
        # 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
189
        # must have some separate counter for each object, so our explicit
190
        # 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.
191
        # requiring that to be LockNotHeld seems reasonable.
192
        #
193
        # we use this approach rather than decorating the Branch, because the
194
        # public interface of WorkingTree does not permit altering the branch
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
195
        # 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.
196
        # backdoor-in and change it reliably. For implementation specific tests
197
        # we can do such skullduggery, but not for interface specific tests.
198
        # And, its simpler :)
199
        wt = self.make_branch_and_tree('.')
200
201
        self.assertFalse(wt.is_locked())
202
        self.assertFalse(wt.branch.is_locked())
203
        wt.lock_write()
204
        self.assertTrue(wt.is_locked())
205
        self.assertTrue(wt.branch.is_locked())
206
207
        # manually unlock the branch, preparing a LockNotHeld error.
208
        wt.branch.unlock()
209
        # the branch *may* still be locked here, if its an all-in-one
1852.4.6 by Robert Collins
Review feedback.
210
        # implementation because there is a single lock object with three
211
        # 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.
212
        self.assertRaises(errors.LockNotHeld, wt.unlock)
213
        # but now, the tree must be unlocked
214
        self.assertFalse(wt.is_locked())
215
        # and the branch too.
216
        self.assertFalse(wt.branch.is_locked())
217
218
    def test_failing_to_lock_branch_does_not_lock(self):
219
        """If the branch cannot be locked, dont lock the tree."""
220
        # Many implementations treat read-locks as non-blocking, but some
221
        # treat them as blocking with writes.. Accordingly we test this by
222
        # opening the branch twice, and locking the branch for write in the
223
        # second instance.  Our lock contract requires separate instances to
224
        # mutually exclude if a lock is exclusive at all: If we get no error
225
        # locking, the test still passes.
226
        wt = self.make_branch_and_tree('.')
227
        branch_copy = branch.Branch.open('.')
228
        branch_copy.lock_write()
229
        try:
230
            try:
231
                wt.lock_read()
1852.4.5 by Robert Collins
Change bare except in working tree locking tests to catch LockError only.
232
            except errors.LockError:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
233
                # 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.
234
                # manner
235
                self.assertFalse(wt.is_locked())
236
                self.assertFalse(wt.branch.is_locked())
237
                return
238
            else:
239
                # no error - the branch allows read locks while writes
240
                # are taken, just pass.
241
                wt.unlock()
242
        finally:
243
            branch_copy.unlock()
244
245
    def test_failing_to_lock_write_branch_does_not_lock(self):
246
        """If the branch cannot be write locked, dont lock the tree."""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
247
        # 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.
248
        # locks as blocking (compare to repositories which are not required
249
        # to do so).
250
        # Accordingly we test this by opening the branch twice, and locking the
251
        # branch for write in the second instance.  Our lock contract requires
252
        # separate instances to mutually exclude.
253
        wt = self.make_branch_and_tree('.')
254
        branch_copy = branch.Branch.open('.')
255
        branch_copy.lock_write()
256
        try:
257
            try:
3287.4.2 by Martin Pool
Change more tests to use reduceLockdirTimeout
258
                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.
259
                self.assertFalse(wt.is_locked())
260
                self.assertFalse(wt.branch.is_locked())
261
            finally:
262
                if wt.is_locked():
263
                    wt.unlock()
264
        finally:
265
            branch_copy.unlock()
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
266
267
    def test_failing_to_lock_tree_write_branch_does_not_lock(self):
268
        """If the branch cannot be read locked, dont lock the tree."""
269
        # Many implementations treat read-locks as non-blocking, but some
270
        # treat them as blocking with writes.. Accordingly we test this by
271
        # opening the branch twice, and locking the branch for write in the
272
        # second instance.  Our lock contract requires separate instances to
273
        # mutually exclude if a lock is exclusive at all: If we get no error
274
        # locking, the test still passes.
275
        wt = self.make_branch_and_tree('.')
276
        branch_copy = branch.Branch.open('.')
1957.1.17 by John Arbash Meinel
Change tests that expect locking to fail to timeout sooner.
277
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
278
        branch_copy.lock_write()
279
        try:
280
            try:
281
                wt.lock_tree_write()
282
            except errors.LockError:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
283
                # any error here means the locks are exclusive in some
1997.1.1 by Robert Collins
Add WorkingTree.lock_tree_write.
284
                # manner
285
                self.assertFalse(wt.is_locked())
286
                self.assertFalse(wt.branch.is_locked())
287
                return
288
            else:
289
                # no error - the branch allows read locks while writes
290
                # are taken, just pass.
291
                wt.unlock()
292
        finally:
293
            branch_copy.unlock()