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