13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Tests for the (un)lock interfaces on all working tree implemenations."""
21
19
from bzrlib import (
25
from bzrlib.tests import TestSkipped
26
from bzrlib.tests.matchers import *
27
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
24
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
30
27
class TestWorkingTreeLocking(TestCaseWithWorkingTree):
44
41
self.assertFalse(wt.is_locked())
45
42
self.assertFalse(wt.branch.is_locked())
47
def test_lock_read_returns_unlocker(self):
48
wt = self.make_branch_and_tree('.')
49
self.assertThat(wt.lock_read, ReturnsUnlockable(wt))
51
44
def test_trivial_lock_write_unlock(self):
52
45
"""Locking for write and unlocking should work trivially."""
53
46
wt = self.make_branch_and_tree('.')
63
56
self.assertFalse(wt.is_locked())
64
57
self.assertFalse(wt.branch.is_locked())
66
def test_lock_write_returns_unlocker(self):
67
wt = self.make_branch_and_tree('.')
68
self.assertThat(wt.lock_write, ReturnsUnlockable(wt))
70
59
def test_trivial_lock_tree_write_unlock(self):
71
60
"""Locking for tree write is ok when the branch is not locked."""
72
61
wt = self.make_branch_and_tree('.')
82
71
self.assertFalse(wt.is_locked())
83
72
self.assertFalse(wt.branch.is_locked())
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))
89
74
def test_trivial_lock_tree_write_branch_read_locked(self):
90
75
"""It is ok to lock_tree_write when the branch is read locked."""
91
76
wt = self.make_branch_and_tree('.')
97
82
wt.lock_tree_write()
98
83
except errors.ReadOnlyError:
99
# When ReadOnlyError is raised, it indicates that the
84
# When ReadOnlyError is raised, it indicates that the
100
85
# workingtree shares its lock with the branch, which is what
101
86
# the git/hg/bzr0.6 formats do.
102
87
# in this case, no lock should have been taken - but the tree
114
99
self.assertFalse(wt.is_locked())
115
100
self.assertTrue(wt.branch.is_locked())
116
101
wt.branch.unlock()
118
103
def _test_unlock_with_lock_method(self, methodname):
119
104
"""Create a tree and then test its unlocking behaviour.
121
106
:param methodname: The lock method to use to establish locks.
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.
131
self.thisFailsStrictLockCheck()
132
108
# when unlocking the last lock count from tree_write_lock,
133
109
# the tree should do a flush().
134
110
# we test that by changing the inventory using set_root_id
135
111
tree = self.make_branch_and_tree('tree')
136
# prepare for a series of changes that will modify the
112
# prepare for a series of changes that will modify the
138
114
getattr(tree, methodname)()
139
115
# note that we dont have a try:finally here because of two reasons:
140
# firstly there will only be errors reported if the test fails, and
116
# firstly there will only be errors reported if the test fails, and
141
117
# when it fails thats ok as long as the test suite cleanup still works,
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
118
# which it will as the lock objects are released (thats where the
119
# warning comes from. Secondly, it is hard in this test to be
144
120
# sure that we've got the right interactions between try:finally
145
121
# and the lock/unlocks we are doing.
146
122
getattr(tree, methodname)()
147
123
# this should really do something within the public api
148
124
# e.g. mkdir('foo') but all the mutating methods at the
149
# moment trigger inventory writes and thus will not
125
# moment trigger inventory writes and thus will not
150
126
# let us trigger a read-when-dirty situation.
151
127
old_root = tree.get_root_id()
152
128
tree.set_root_id('new-root')
153
129
# to detect that the inventory is written by unlock, we
154
130
# first check that it was not written yet.
155
# TODO: This requires taking a read lock while we are holding the above
156
# write lock, which shouldn't actually be possible
157
131
reference_tree = tree.bzrdir.open_workingtree()
158
132
self.assertEqual(old_root, reference_tree.get_root_id())
159
133
# now unlock the second held lock, which should do nothing.
169
143
def test_unlock_from_tree_write_lock_flushes(self):
170
144
self._test_unlock_with_lock_method("lock_tree_write")
172
146
def test_unlock_from_write_lock_flushes(self):
173
147
self._test_unlock_with_lock_method("lock_write")
175
149
def test_unlock_branch_failures(self):
176
150
"""If the branch unlock fails the tree must still unlock."""
177
151
# The public interface for WorkingTree requires a branch, but
181
155
# in order to test that implementations which *do* unlock via the branch
182
156
# do so correctly, we unlock the branch after locking the working tree.
183
157
# The next unlock on working tree should trigger a LockNotHeld exception
184
# from the branch object, which must be exposed to the caller. To meet
158
# from the branch object, which must be exposed to the caller. To meet
185
159
# our object model - where locking a tree locks its branch, and
186
# unlocking a branch does not unlock a working tree, *even* for
160
# unlocking a branch does not unlock a working tree, *even* for
187
161
# all-in-one implementations like bzr 0.6, git, and hg, implementations
188
# must have some separate counter for each object, so our explicit
189
# unlock should trigger some error on all implementations, and
162
# must have some separate counter for each object, so our explicit
163
# unlock should trigger some error on all implementations, and
190
164
# requiring that to be LockNotHeld seems reasonable.
192
166
# we use this approach rather than decorating the Branch, because the
193
167
# public interface of WorkingTree does not permit altering the branch
194
# object - and we cannot tell which attribute might allow us to
168
# object - and we cannot tell which attribute might allow us to
195
169
# backdoor-in and change it reliably. For implementation specific tests
196
170
# we can do such skullduggery, but not for interface specific tests.
197
171
# And, its simpler :)