~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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Test locks across all branch implemenations"""
18
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
19
from bzrlib import errors
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
20
from bzrlib.branch import BzrBranchFormat4
2018.5.164 by Andrew Bennetts
Deal with some more review comments.
21
from bzrlib.bzrdir import RemoteBzrDirFormat
2018.13.1 by Andrew Bennetts
Skip some branch_implementation tests that use branch.control_files if testing RemoteBranches.
22
from bzrlib.tests import TestSkipped
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.
23
from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
1711.8.7 by John Arbash Meinel
Renaming LockHelpers.py to lock_helpers.py
24
from bzrlib.tests.lock_helpers import TestPreventLocking, LockWrapper
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.
25
26
27
class TestBranchLocking(TestCaseWithBranch):
28
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
29
    def setUp(self):
30
        TestCaseWithBranch.setUp(self)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
31
        self.reduceLockdirTimeout()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
32
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.
33
    def get_instrumented_branch(self):
34
        """Get a Branch object which has been instrumented"""
35
        # TODO: jam 20060630 It may be that not all formats have a 
36
        # 'control_files' member. So we should fail gracefully if
37
        # not there. But assuming it has them lets us test the exact 
38
        # lock/unlock order.
39
        self.locks = []
40
        b = LockWrapper(self.locks, self.get_branch(), 'b')
41
        b.repository = LockWrapper(self.locks, b.repository, 'r')
42
        bcf = b.control_files
2018.5.166 by Andrew Bennetts
Small changes in response to Aaron's review.
43
        rcf = getattr(b.repository, 'control_files', None)
44
        if rcf is None:
45
            raise TestSkipped(
46
                "This tests depends on being able to instrument "
47
                "repository.control_files, but %r doesn't have control_files."
48
                % (b.repository,))
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.
49
50
        # Look out for branch types that reuse their control files
51
        self.combined_control = bcf is rcf
52
53
        b.control_files = LockWrapper(self.locks, b.control_files, 'bc')
54
        b.repository.control_files = \
55
            LockWrapper(self.locks, b.repository.control_files, 'rc')
56
        return b
57
58
    def test_01_lock_read(self):
59
        # Test that locking occurs in the correct order
60
        b = self.get_instrumented_branch()
61
62
        self.assertFalse(b.is_locked())
63
        self.assertFalse(b.repository.is_locked())
64
        b.lock_read()
65
        try:
66
            self.assertTrue(b.is_locked())
67
            self.assertTrue(b.repository.is_locked())
68
        finally:
69
            b.unlock()
70
        self.assertFalse(b.is_locked())
71
        self.assertFalse(b.repository.is_locked())
72
73
        self.assertEqual([('b', 'lr', True),
74
                          ('r', 'lr', True),
75
                          ('rc', 'lr', True),
76
                          ('bc', 'lr', True),
77
                          ('b', 'ul', True),
78
                          ('bc', 'ul', True),
79
                          ('r', 'ul', True),
80
                          ('rc', 'ul', True),
81
                         ], self.locks)
82
83
    def test_02_lock_write(self):
84
        # Test that locking occurs in the correct order
85
        b = self.get_instrumented_branch()
86
87
        self.assertFalse(b.is_locked())
88
        self.assertFalse(b.repository.is_locked())
89
        b.lock_write()
90
        try:
91
            self.assertTrue(b.is_locked())
92
            self.assertTrue(b.repository.is_locked())
93
        finally:
94
            b.unlock()
95
        self.assertFalse(b.is_locked())
96
        self.assertFalse(b.repository.is_locked())
97
98
        self.assertEqual([('b', 'lw', True),
99
                          ('r', 'lw', True),
100
                          ('rc', 'lw', True),
101
                          ('bc', 'lw', True),
102
                          ('b', 'ul', True),
103
                          ('bc', 'ul', True),
104
                          ('r', 'ul', True),
105
                          ('rc', 'ul', True),
106
                         ], self.locks)
107
108
    def test_03_lock_fail_unlock_repo(self):
109
        # Make sure branch.unlock() is called, even if there is a
110
        # failure while unlocking the repository.
111
        b = self.get_instrumented_branch()
112
        b.repository.disable_unlock()
113
114
        self.assertFalse(b.is_locked())
115
        self.assertFalse(b.repository.is_locked())
116
        b.lock_write()
117
        try:
118
            self.assertTrue(b.is_locked())
119
            self.assertTrue(b.repository.is_locked())
120
            self.assertRaises(TestPreventLocking, b.unlock)
121
            if self.combined_control:
122
                self.assertTrue(b.is_locked())
123
            else:
124
                self.assertFalse(b.is_locked())
125
            self.assertTrue(b.repository.is_locked())
126
127
            # We unlock the branch control files, even if 
128
            # we fail to unlock the repository
129
            self.assertEqual([('b', 'lw', True),
130
                              ('r', 'lw', True),
131
                              ('rc', 'lw', True),
132
                              ('bc', 'lw', True),
133
                              ('b', 'ul', True),
134
                              ('bc', 'ul', True),
135
                              ('r', 'ul', False), 
136
                             ], self.locks)
137
138
        finally:
139
            # For cleanup purposes, make sure we are unlocked
140
            b.repository._other.unlock()
141
142
    def test_04_lock_fail_unlock_control(self):
143
        # Make sure repository.unlock() is called, if we fail to unlock self
144
        b = self.get_instrumented_branch()
145
        b.control_files.disable_unlock()
146
147
        self.assertFalse(b.is_locked())
148
        self.assertFalse(b.repository.is_locked())
149
        b.lock_write()
150
        try:
151
            self.assertTrue(b.is_locked())
152
            self.assertTrue(b.repository.is_locked())
153
            self.assertRaises(TestPreventLocking, b.unlock)
154
            self.assertTrue(b.is_locked())
155
            if self.combined_control:
156
                self.assertTrue(b.repository.is_locked())
157
            else:
158
                self.assertFalse(b.repository.is_locked())
159
160
            # We unlock the repository even if 
161
            # we fail to unlock the control files
162
            self.assertEqual([('b', 'lw', True),
163
                              ('r', 'lw', True),
164
                              ('rc', 'lw', True),
165
                              ('bc', 'lw', True),
166
                              ('b', 'ul', True),
167
                              ('bc', 'ul', False),
168
                              ('r', 'ul', True), 
169
                              ('rc', 'ul', True), 
170
                             ], self.locks)
171
172
        finally:
173
            # For cleanup purposes, make sure we are unlocked
174
            b.control_files._other.unlock()
175
176
    def test_05_lock_read_fail_repo(self):
177
        # Test that the branch is not locked if it cannot lock the repository
178
        b = self.get_instrumented_branch()
179
        b.repository.disable_lock_read()
180
181
        self.assertRaises(TestPreventLocking, b.lock_read)
182
        self.assertFalse(b.is_locked())
183
        self.assertFalse(b.repository.is_locked())
184
185
        self.assertEqual([('b', 'lr', True),
186
                          ('r', 'lr', False), 
187
                         ], self.locks)
188
189
    def test_06_lock_write_fail_repo(self):
190
        # Test that the branch is not locked if it cannot lock the repository
191
        b = self.get_instrumented_branch()
192
        b.repository.disable_lock_write()
193
194
        self.assertRaises(TestPreventLocking, b.lock_write)
195
        self.assertFalse(b.is_locked())
196
        self.assertFalse(b.repository.is_locked())
197
198
        self.assertEqual([('b', 'lw', True),
199
                          ('r', 'lw', False), 
200
                         ], self.locks)
201
202
    def test_07_lock_read_fail_control(self):
203
        # Test the repository is unlocked if we can't lock self
204
        b = self.get_instrumented_branch()
205
        b.control_files.disable_lock_read()
206
207
        self.assertRaises(TestPreventLocking, b.lock_read)
208
        self.assertFalse(b.is_locked())
209
        self.assertFalse(b.repository.is_locked())
210
211
        self.assertEqual([('b', 'lr', True),
212
                          ('r', 'lr', True),
213
                          ('rc', 'lr', True),
214
                          ('bc', 'lr', False),
215
                          ('r', 'ul', True),
216
                          ('rc', 'ul', True),
217
                         ], self.locks)
218
219
    def test_08_lock_write_fail_control(self):
220
        # Test the repository is unlocked if we can't lock self
221
        b = self.get_instrumented_branch()
222
        b.control_files.disable_lock_write()
223
224
        self.assertRaises(TestPreventLocking, b.lock_write)
225
        self.assertFalse(b.is_locked())
226
        self.assertFalse(b.repository.is_locked())
227
228
        self.assertEqual([('b', 'lw', True),
229
                          ('r', 'lw', True),
230
                          ('rc', 'lw', True),
231
                          ('bc', 'lw', False),
232
                          ('r', 'ul', True),
233
                          ('rc', 'ul', True),
234
                         ], self.locks)
235
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
236
    def test_lock_write_returns_None_refuses_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
237
        branch = self.make_branch('b')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
238
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
239
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
240
            if token is not None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
241
                # This test does not apply, because this lockable supports
242
                # tokens.
243
                return
244
            self.assertRaises(errors.TokenLockingNotSupported,
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
245
                              branch.lock_write, token='token')
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
246
        finally:
247
            branch.unlock()
248
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
249
    def test_reentering_lock_write_raises_on_token_mismatch(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
250
        branch = self.make_branch('b')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
251
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
252
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
253
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
254
                # This test does not apply, because this lockable refuses
255
                # tokens.
256
                return
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
257
            different_branch_token = token + 'xxx'
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
258
            # Re-using the same lockable instance with a different branch token
259
            # will raise TokenMismatch.
260
            self.assertRaises(errors.TokenMismatch,
261
                              branch.lock_write,
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
262
                              token=different_branch_token)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
263
        finally:
264
            branch.unlock()
265
266
    def test_lock_write_with_nonmatching_token(self):
267
        branch = self.make_branch('b')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
268
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
269
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
270
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
271
                # This test does not apply, because this branch refuses
272
                # tokens.
273
                return
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
274
            different_branch_token = token + 'xxx'
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
275
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
276
            new_branch = branch.bzrdir.open_branch()
277
            # We only want to test the relocking abilities of branch, so use the
278
            # existing repository object which is already locked.
279
            new_branch.repository = branch.repository
280
            self.assertRaises(errors.TokenMismatch,
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
281
                              new_branch.lock_write,
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
282
                              token=different_branch_token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
283
        finally:
284
            branch.unlock()
285
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
286
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
287
    def test_lock_write_with_matching_token(self):
288
        """Test that a branch can be locked with a token, if it is already
289
        locked by that token."""
290
        branch = self.make_branch('b')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
291
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
292
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
293
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
294
                # This test does not apply, because this branch refuses tokens.
295
                return
296
            # The same instance will accept a second lock_write if the specified
297
            # token matches.
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
298
            branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
299
            branch.unlock()
300
            # Calling lock_write on a new instance for the same lockable will
301
            # also succeed.
302
            new_branch = branch.bzrdir.open_branch()
303
            # We only want to test the relocking abilities of branch, so use the
304
            # existing repository object which is already locked.
305
            new_branch.repository = branch.repository
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
306
            new_branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
307
            new_branch.unlock()
308
        finally:
309
            branch.unlock()
310
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
311
    def test_unlock_after_lock_write_with_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
312
        # If lock_write did not physically acquire the lock (because it was
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
313
        # passed some tokens), then unlock should not physically release it.
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
314
        branch = self.make_branch('b')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
315
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
316
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
317
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
318
                # This test does not apply, because this lockable refuses
319
                # tokens.
320
                return
321
            new_branch = branch.bzrdir.open_branch()
322
            # We only want to test the relocking abilities of branch, so use the
323
            # existing repository object which is already locked.
324
            new_branch.repository = branch.repository
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
325
            new_branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
326
            new_branch.unlock()
327
            self.assertTrue(branch.get_physical_lock_status()) #XXX
328
        finally:
329
            branch.unlock()
330
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
331
    def test_lock_write_with_token_fails_when_unlocked(self):
332
        # First, lock and then unlock to get superficially valid tokens.  This
333
        # mimics a likely programming error, where a caller accidentally tries
334
        # to lock with a token that is no longer valid (because the original
335
        # lock was released).
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
336
        branch = self.make_branch('b')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
337
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
338
        branch.unlock()
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
339
        if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
340
            # This test does not apply, because this lockable refuses
341
            # tokens.
342
            return
343
344
        self.assertRaises(errors.TokenMismatch,
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
345
                          branch.lock_write, token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
346
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
347
    def test_lock_write_reenter_with_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
348
        branch = self.make_branch('b')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
349
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
350
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
351
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
352
                # This test does not apply, because this lockable refuses
353
                # tokens.
354
                return
355
            # Relock with a token.
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
356
            branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
357
            branch.unlock()
358
        finally:
359
            branch.unlock()
360
        # The lock should be unlocked on disk.  Verify that with a new lock
361
        # instance.
362
        new_branch = branch.bzrdir.open_branch()
363
        # Calling lock_write now should work, rather than raise LockContention.
364
        new_branch.lock_write()
365
        new_branch.unlock()
366
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
367
    def test_leave_lock_in_place(self):
368
        branch = self.make_branch('b')
369
        # Lock the branch, then use leave_lock_in_place so that when we
370
        # unlock the branch the lock is still held on disk.
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
371
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
372
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
373
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
374
                # This test does not apply, because this repository refuses lock
375
                # tokens.
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
376
                self.assertRaises(NotImplementedError,
377
                                  branch.leave_lock_in_place)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
378
                return
379
            branch.leave_lock_in_place()
380
        finally:
381
            branch.unlock()
382
        # We should be unable to relock the repo.
383
        self.assertRaises(errors.LockContention, branch.lock_write)
384
385
    def test_dont_leave_lock_in_place(self):
386
        branch = self.make_branch('b')
387
        # Create a lock on disk.
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
388
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
389
        try:
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
390
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
391
                # This test does not apply, because this branch refuses lock
392
                # tokens.
393
                self.assertRaises(NotImplementedError,
394
                                  branch.dont_leave_lock_in_place)
395
                return
396
            try:
397
                branch.leave_lock_in_place()
398
            except NotImplementedError:
399
                # This branch doesn't support this API.
400
                return
401
            branch.repository.leave_lock_in_place()
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
402
            repo_token = branch.repository.lock_write()
403
            branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
404
        finally:
405
            branch.unlock()
406
        # Reacquire the lock (with a different branch object) by using the
407
        # tokens.
408
        new_branch = branch.bzrdir.open_branch()
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
409
        # We have to explicitly lock the repository first.
410
        new_branch.repository.lock_write(token=repo_token)
411
        new_branch.lock_write(token=token)
412
        # Now we don't need our own repository lock anymore (the branch is
413
        # holding it for us).
414
        new_branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
415
        # Call dont_leave_lock_in_place, so that the lock will be released by
416
        # this instance, even though the lock wasn't originally acquired by it.
417
        new_branch.dont_leave_lock_in_place()
418
        new_branch.repository.dont_leave_lock_in_place()
419
        new_branch.unlock()
2018.15.1 by Andrew Bennetts
All branch_implementations/test_locking tests passing.
420
        # Now the branch (and repository) is unlocked.  Test this by locking it
421
        # without tokens.
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
422
        branch.lock_write()
423
        branch.unlock()
424
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
425
    def test_lock_read_then_unlock(self):
426
        # Calling lock_read then unlocking should work without errors.
427
        branch = self.make_branch('b')
428
        branch.lock_read()
429
        branch.unlock()
430
431
    def test_lock_write_locks_repo_too(self):
432
        if isinstance(self.branch_format, BzrBranchFormat4):
433
            # Branch format 4 is combined with the repository, so this test
434
            # doesn't apply.
435
            return
436
        branch = self.make_branch('b')
437
        branch = branch.bzrdir.open_branch()
438
        branch.lock_write()
439
        try:
440
            # Now the branch.repository is locked, so we can't lock it with a new
441
            # repository without a token.
442
            new_repo = branch.bzrdir.open_repository()
443
            self.assertRaises(errors.LockContention, new_repo.lock_write)
444
            # We can call lock_write on the original repository object though,
445
            # because it is already locked.
446
            branch.repository.lock_write()
447
            branch.repository.unlock()
448
        finally:
449
            branch.unlock()