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