~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:
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
45
            self.combined_branch = False
46
        else:
47
            # Look out for branch types that reuse their control files
48
            self.combined_control = bcf is rcf
49
        try:
50
            b.control_files = LockWrapper(self.locks, b.control_files, 'bc')
51
        except AttributeError:
52
            # RemoteBranch seems to trigger this.
53
            raise TestSkipped("Could not instrument branch control files.")
54
        if self.combined_control:
55
            # instrument the repository control files too to ensure its worked
56
            # with correctly. When they are not shared, we trust the repository
57
            # API and only instrument the repository itself. 
58
            b.repository.control_files = \
59
                LockWrapper(self.locks, b.repository.control_files, 'rc')
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.
60
        return b
61
62
    def test_01_lock_read(self):
63
        # Test that locking occurs in the correct order
64
        b = self.get_instrumented_branch()
65
66
        self.assertFalse(b.is_locked())
67
        self.assertFalse(b.repository.is_locked())
68
        b.lock_read()
69
        try:
70
            self.assertTrue(b.is_locked())
71
            self.assertTrue(b.repository.is_locked())
72
        finally:
73
            b.unlock()
74
        self.assertFalse(b.is_locked())
75
        self.assertFalse(b.repository.is_locked())
76
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
77
        if self.combined_control:
78
            self.assertEqual([('b', 'lr', True),
79
                              ('r', 'lr', True),
80
                              ('rc', 'lr', True),
81
                              ('bc', 'lr', True),
82
                              ('b', 'ul', True),
83
                              ('bc', 'ul', True),
84
                              ('r', 'ul', True),
85
                              ('rc', 'ul', True),
86
                             ], self.locks)
87
        else:
88
            self.assertEqual([('b', 'lr', True),
89
                              ('r', 'lr', True),
90
                              ('bc', 'lr', True),
91
                              ('b', 'ul', True),
92
                              ('bc', 'ul', True),
93
                              ('r', 'ul', True),
94
                             ], self.locks)
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.
95
96
    def test_02_lock_write(self):
97
        # Test that locking occurs in the correct order
98
        b = self.get_instrumented_branch()
99
100
        self.assertFalse(b.is_locked())
101
        self.assertFalse(b.repository.is_locked())
102
        b.lock_write()
103
        try:
104
            self.assertTrue(b.is_locked())
105
            self.assertTrue(b.repository.is_locked())
106
        finally:
107
            b.unlock()
108
        self.assertFalse(b.is_locked())
109
        self.assertFalse(b.repository.is_locked())
110
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
111
        if self.combined_control:
112
            self.assertEqual([('b', 'lw', True),
113
                              ('r', 'lw', True),
114
                              ('rc', 'lw', True),
115
                              ('bc', 'lw', True),
116
                              ('b', 'ul', True),
117
                              ('bc', 'ul', True),
118
                              ('r', 'ul', True),
119
                              ('rc', 'ul', True),
120
                             ], self.locks)
121
        else:
122
            self.assertEqual([('b', 'lw', True),
123
                              ('r', 'lw', True),
124
                              ('bc', 'lw', True),
125
                              ('b', 'ul', True),
126
                              ('bc', 'ul', True),
127
                              ('r', 'ul', True),
128
                             ], self.locks)
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.
129
130
    def test_03_lock_fail_unlock_repo(self):
131
        # Make sure branch.unlock() is called, even if there is a
132
        # failure while unlocking the repository.
133
        b = self.get_instrumented_branch()
134
        b.repository.disable_unlock()
135
136
        self.assertFalse(b.is_locked())
137
        self.assertFalse(b.repository.is_locked())
138
        b.lock_write()
139
        try:
140
            self.assertTrue(b.is_locked())
141
            self.assertTrue(b.repository.is_locked())
142
            self.assertRaises(TestPreventLocking, b.unlock)
143
            if self.combined_control:
144
                self.assertTrue(b.is_locked())
145
            else:
146
                self.assertFalse(b.is_locked())
147
            self.assertTrue(b.repository.is_locked())
148
149
            # We unlock the branch control files, even if 
150
            # we fail to unlock the repository
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
151
            if self.combined_control:
152
                self.assertEqual([('b', 'lw', True),
153
                                  ('r', 'lw', True),
154
                                  ('rc', 'lw', True),
155
                                  ('bc', 'lw', True),
156
                                  ('b', 'ul', True),
157
                                  ('bc', 'ul', True),
158
                                  ('r', 'ul', False),
159
                                 ], self.locks)
160
            else:
161
                self.assertEqual([('b', 'lw', True),
162
                                  ('r', 'lw', True),
163
                                  ('bc', 'lw', True),
164
                                  ('b', 'ul', True),
165
                                  ('bc', 'ul', True),
166
                                  ('r', 'ul', False),
167
                                 ], self.locks)
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.
168
169
        finally:
170
            # For cleanup purposes, make sure we are unlocked
171
            b.repository._other.unlock()
172
173
    def test_04_lock_fail_unlock_control(self):
174
        # Make sure repository.unlock() is called, if we fail to unlock self
175
        b = self.get_instrumented_branch()
176
        b.control_files.disable_unlock()
177
178
        self.assertFalse(b.is_locked())
179
        self.assertFalse(b.repository.is_locked())
180
        b.lock_write()
181
        try:
182
            self.assertTrue(b.is_locked())
183
            self.assertTrue(b.repository.is_locked())
184
            self.assertRaises(TestPreventLocking, b.unlock)
185
            self.assertTrue(b.is_locked())
186
            if self.combined_control:
187
                self.assertTrue(b.repository.is_locked())
188
            else:
189
                self.assertFalse(b.repository.is_locked())
190
191
            # We unlock the repository even if 
192
            # we fail to unlock the control files
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
193
            if self.combined_control:
194
                self.assertEqual([('b', 'lw', True),
195
                                  ('r', 'lw', True),
196
                                  ('rc', 'lw', True),
197
                                  ('bc', 'lw', True),
198
                                  ('b', 'ul', True),
199
                                  ('bc', 'ul', False),
200
                                  ('r', 'ul', True),
201
                                  ('rc', 'ul', True),
202
                                 ], self.locks)
203
            else:
204
                self.assertEqual([('b', 'lw', True),
205
                                  ('r', 'lw', True),
206
                                  ('bc', 'lw', True),
207
                                  ('b', 'ul', True),
208
                                  ('bc', 'ul', False),
209
                                  ('r', 'ul', True),
210
                                 ], self.locks)
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.
211
212
        finally:
213
            # For cleanup purposes, make sure we are unlocked
214
            b.control_files._other.unlock()
215
216
    def test_05_lock_read_fail_repo(self):
217
        # Test that the branch is not locked if it cannot lock the repository
218
        b = self.get_instrumented_branch()
219
        b.repository.disable_lock_read()
220
221
        self.assertRaises(TestPreventLocking, b.lock_read)
222
        self.assertFalse(b.is_locked())
223
        self.assertFalse(b.repository.is_locked())
224
225
        self.assertEqual([('b', 'lr', True),
226
                          ('r', 'lr', False), 
227
                         ], self.locks)
228
229
    def test_06_lock_write_fail_repo(self):
230
        # Test that the branch is not locked if it cannot lock the repository
231
        b = self.get_instrumented_branch()
232
        b.repository.disable_lock_write()
233
234
        self.assertRaises(TestPreventLocking, b.lock_write)
235
        self.assertFalse(b.is_locked())
236
        self.assertFalse(b.repository.is_locked())
237
238
        self.assertEqual([('b', 'lw', True),
239
                          ('r', 'lw', False), 
240
                         ], self.locks)
241
242
    def test_07_lock_read_fail_control(self):
243
        # Test the repository is unlocked if we can't lock self
244
        b = self.get_instrumented_branch()
245
        b.control_files.disable_lock_read()
246
247
        self.assertRaises(TestPreventLocking, b.lock_read)
248
        self.assertFalse(b.is_locked())
249
        self.assertFalse(b.repository.is_locked())
250
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
251
        if self.combined_control:
252
            self.assertEqual([('b', 'lr', True),
253
                              ('r', 'lr', True),
254
                              ('rc', 'lr', True),
255
                              ('bc', 'lr', False),
256
                              ('r', 'ul', True),
257
                              ('rc', 'ul', True),
258
                             ], self.locks)
259
        else:
260
            self.assertEqual([('b', 'lr', True),
261
                              ('r', 'lr', True),
262
                              ('bc', 'lr', False),
263
                              ('r', 'ul', True),
264
                             ], self.locks)
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.
265
266
    def test_08_lock_write_fail_control(self):
267
        # Test the repository is unlocked if we can't lock self
268
        b = self.get_instrumented_branch()
269
        b.control_files.disable_lock_write()
270
271
        self.assertRaises(TestPreventLocking, b.lock_write)
272
        self.assertFalse(b.is_locked())
273
        self.assertFalse(b.repository.is_locked())
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
274
        if self.combined_control:
275
            self.assertEqual([('b', 'lw', True),
276
                              ('r', 'lw', True),
277
                              ('rc', 'lw', True),
278
                              ('bc', 'lw', False),
279
                              ('r', 'ul', True),
280
                              ('rc', 'ul', True),
281
                             ], self.locks)
282
        else:
283
            self.assertEqual([('b', 'lw', True),
284
                              ('r', 'lw', True),
285
                              ('bc', 'lw', False),
286
                              ('r', 'ul', True),
287
                             ], self.locks)
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.
288
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).
289
    def test_lock_write_returns_None_refuses_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
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 not None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
294
                # This test does not apply, because this lockable supports
295
                # tokens.
296
                return
297
            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).
298
                              branch.lock_write, token='token')
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
299
        finally:
300
            branch.unlock()
301
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
302
    def test_reentering_lock_write_raises_on_token_mismatch(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
303
        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).
304
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
305
        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).
306
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
307
                # This test does not apply, because this lockable refuses
308
                # tokens.
309
                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).
310
            different_branch_token = token + 'xxx'
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
311
            # Re-using the same lockable instance with a different branch token
312
            # will raise TokenMismatch.
313
            self.assertRaises(errors.TokenMismatch,
314
                              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).
315
                              token=different_branch_token)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
316
        finally:
317
            branch.unlock()
318
319
    def test_lock_write_with_nonmatching_token(self):
320
        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).
321
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
322
        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).
323
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
324
                # This test does not apply, because this branch refuses
325
                # tokens.
326
                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).
327
            different_branch_token = token + 'xxx'
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
328
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
329
            new_branch = branch.bzrdir.open_branch()
330
            # We only want to test the relocking abilities of branch, so use the
331
            # existing repository object which is already locked.
332
            new_branch.repository = branch.repository
333
            self.assertRaises(errors.TokenMismatch,
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
334
                              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).
335
                              token=different_branch_token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
336
        finally:
337
            branch.unlock()
338
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
339
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
340
    def test_lock_write_with_matching_token(self):
341
        """Test that a branch can be locked with a token, if it is already
342
        locked by that token."""
343
        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).
344
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
345
        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).
346
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
347
                # This test does not apply, because this branch refuses tokens.
348
                return
349
            # The same instance will accept a second lock_write if the specified
350
            # 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).
351
            branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
352
            branch.unlock()
353
            # Calling lock_write on a new instance for the same lockable will
354
            # also succeed.
355
            new_branch = branch.bzrdir.open_branch()
356
            # We only want to test the relocking abilities of branch, so use the
357
            # existing repository object which is already locked.
358
            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).
359
            new_branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
360
            new_branch.unlock()
361
        finally:
362
            branch.unlock()
363
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).
364
    def test_unlock_after_lock_write_with_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
365
        # 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.
366
        # passed some tokens), then unlock should not physically release it.
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
367
        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).
368
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
369
        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).
370
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
371
                # This test does not apply, because this lockable refuses
372
                # tokens.
373
                return
374
            new_branch = branch.bzrdir.open_branch()
375
            # We only want to test the relocking abilities of branch, so use the
376
            # existing repository object which is already locked.
377
            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).
378
            new_branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
379
            new_branch.unlock()
380
            self.assertTrue(branch.get_physical_lock_status()) #XXX
381
        finally:
382
            branch.unlock()
383
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).
384
    def test_lock_write_with_token_fails_when_unlocked(self):
385
        # First, lock and then unlock to get superficially valid tokens.  This
386
        # mimics a likely programming error, where a caller accidentally tries
387
        # to lock with a token that is no longer valid (because the original
388
        # lock was released).
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
389
        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).
390
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
391
        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).
392
        if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
393
            # This test does not apply, because this lockable refuses
394
            # tokens.
395
            return
396
397
        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).
398
                          branch.lock_write, token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
399
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).
400
    def test_lock_write_reenter_with_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
401
        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).
402
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
403
        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).
404
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
405
                # This test does not apply, because this lockable refuses
406
                # tokens.
407
                return
408
            # 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).
409
            branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
410
            branch.unlock()
411
        finally:
412
            branch.unlock()
413
        # The lock should be unlocked on disk.  Verify that with a new lock
414
        # instance.
415
        new_branch = branch.bzrdir.open_branch()
416
        # Calling lock_write now should work, rather than raise LockContention.
417
        new_branch.lock_write()
418
        new_branch.unlock()
419
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
420
    def test_leave_lock_in_place(self):
421
        branch = self.make_branch('b')
422
        # Lock the branch, then use leave_lock_in_place so that when we
423
        # 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).
424
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
425
        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).
426
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
427
                # This test does not apply, because this repository refuses lock
428
                # 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).
429
                self.assertRaises(NotImplementedError,
430
                                  branch.leave_lock_in_place)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
431
                return
432
            branch.leave_lock_in_place()
433
        finally:
434
            branch.unlock()
435
        # We should be unable to relock the repo.
436
        self.assertRaises(errors.LockContention, branch.lock_write)
437
438
    def test_dont_leave_lock_in_place(self):
439
        branch = self.make_branch('b')
440
        # 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).
441
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
442
        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).
443
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
444
                # This test does not apply, because this branch refuses lock
445
                # tokens.
446
                self.assertRaises(NotImplementedError,
447
                                  branch.dont_leave_lock_in_place)
448
                return
449
            try:
450
                branch.leave_lock_in_place()
451
            except NotImplementedError:
452
                # This branch doesn't support this API.
453
                return
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
454
            try:
455
                branch.repository.leave_lock_in_place()
456
            except NotImplementedError:
457
                # This repo doesn't support leaving locks around,
458
                # assume it is essentially lock-free.
459
                repo_token = None
460
            else:
461
                repo_token = branch.repository.lock_write()
462
                branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
463
        finally:
464
            branch.unlock()
465
        # Reacquire the lock (with a different branch object) by using the
466
        # tokens.
467
        new_branch = branch.bzrdir.open_branch()
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
468
        if repo_token is not None:
469
            # We have to explicitly lock the repository first.
470
            new_branch.repository.lock_write(token=repo_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).
471
        new_branch.lock_write(token=token)
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
472
        if repo_token is not None:
473
            # Now we don't need our own repository lock anymore (the branch is
474
            # holding it for us).
475
            new_branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
476
        # Call dont_leave_lock_in_place, so that the lock will be released by
477
        # this instance, even though the lock wasn't originally acquired by it.
478
        new_branch.dont_leave_lock_in_place()
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
479
        if repo_token is not None:
480
            new_branch.repository.dont_leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
481
        new_branch.unlock()
2018.15.1 by Andrew Bennetts
All branch_implementations/test_locking tests passing.
482
        # Now the branch (and repository) is unlocked.  Test this by locking it
483
        # without tokens.
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
484
        branch.lock_write()
485
        branch.unlock()
486
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
487
    def test_lock_read_then_unlock(self):
488
        # Calling lock_read then unlocking should work without errors.
489
        branch = self.make_branch('b')
490
        branch.lock_read()
491
        branch.unlock()
492
493
    def test_lock_write_locks_repo_too(self):
494
        if isinstance(self.branch_format, BzrBranchFormat4):
495
            # Branch format 4 is combined with the repository, so this test
496
            # doesn't apply.
497
            return
498
        branch = self.make_branch('b')
499
        branch = branch.bzrdir.open_branch()
500
        branch.lock_write()
501
        try:
3015.2.15 by Robert Collins
Review feedback.
502
            # The branch should have asked the repository to lock.
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
503
            self.assertTrue(branch.repository.is_write_locked())
504
            # Does the repository type actually lock?
505
            if not branch.repository.get_physical_lock_status():
506
                # The test was successfully applied, so it was applicable.
507
                return
508
            # Now the branch.repository is physically locked, so we can't lock
509
            # it with a new repository instance.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
510
            new_repo = branch.bzrdir.open_repository()
511
            self.assertRaises(errors.LockContention, new_repo.lock_write)
512
            # We can call lock_write on the original repository object though,
513
            # because it is already locked.
514
            branch.repository.lock_write()
515
            branch.repository.unlock()
516
        finally:
517
            branch.unlock()