~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
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
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
4523.1.5 by Vincent Ladeuil
Fixed as asked in review.
23
from bzrlib.tests.lock_helpers import TestPreventLocking, LockWrapper
4523.1.1 by Martin Pool
Rename tests.branch_implementations to per_branch
24
from bzrlib.tests.per_branch.test_branch import TestCaseWithBranch
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"""
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
35
        # TODO: jam 20060630 It may be that not all formats have a
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.
36
        # 'control_files' member. So we should fail gracefully if
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
37
        # not there. But assuming it has them lets us test the exact
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.
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
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
57
            # API and only instrument the repository itself.
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
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())
4634.85.11 by Andrew Bennetts
Suppress most errors from Branch.unlock too.
142
            self.assertLogsError(TestPreventLocking, b.unlock)
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.
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
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
149
            # We unlock the branch control files, even if
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.
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):
4288.1.11 by Robert Collins
Hopefully fix locking tests to match the new code (and still be good statements of intent).
174
        # Make sure repository.unlock() is not called, if we fail to unlock
175
        # self leaving ourselves still locked, so that attempts to recover
176
        # don't encounter an unlocked 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.
177
        b = self.get_instrumented_branch()
178
        b.control_files.disable_unlock()
179
180
        self.assertFalse(b.is_locked())
181
        self.assertFalse(b.repository.is_locked())
182
        b.lock_write()
183
        try:
184
            self.assertTrue(b.is_locked())
185
            self.assertTrue(b.repository.is_locked())
4634.85.11 by Andrew Bennetts
Suppress most errors from Branch.unlock too.
186
            self.assertLogsError(TestPreventLocking, b.unlock)
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.
187
            self.assertTrue(b.is_locked())
4288.1.11 by Robert Collins
Hopefully fix locking tests to match the new code (and still be good statements of intent).
188
            self.assertTrue(b.repository.is_locked())
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.
189
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
190
            # We unlock the repository even if
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.
191
            # we fail to unlock the control files
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
192
            if self.combined_control:
193
                self.assertEqual([('b', 'lw', True),
194
                                  ('r', 'lw', True),
195
                                  ('rc', 'lw', True),
196
                                  ('bc', 'lw', True),
197
                                  ('b', 'ul', True),
198
                                  ('bc', 'ul', False),
199
                                  ('r', 'ul', True),
200
                                  ('rc', 'ul', True),
201
                                 ], self.locks)
202
            else:
203
                self.assertEqual([('b', 'lw', True),
204
                                  ('r', 'lw', True),
205
                                  ('bc', 'lw', True),
206
                                  ('b', 'ul', True),
207
                                  ('bc', 'ul', False),
208
                                 ], 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.
209
210
        finally:
211
            # For cleanup purposes, make sure we are unlocked
212
            b.control_files._other.unlock()
213
214
    def test_05_lock_read_fail_repo(self):
215
        # Test that the branch is not locked if it cannot lock the repository
216
        b = self.get_instrumented_branch()
217
        b.repository.disable_lock_read()
218
219
        self.assertRaises(TestPreventLocking, b.lock_read)
220
        self.assertFalse(b.is_locked())
221
        self.assertFalse(b.repository.is_locked())
222
223
        self.assertEqual([('b', 'lr', True),
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
224
                          ('r', 'lr', False),
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.
225
                         ], self.locks)
226
227
    def test_06_lock_write_fail_repo(self):
228
        # Test that the branch is not locked if it cannot lock the repository
229
        b = self.get_instrumented_branch()
230
        b.repository.disable_lock_write()
231
232
        self.assertRaises(TestPreventLocking, b.lock_write)
233
        self.assertFalse(b.is_locked())
234
        self.assertFalse(b.repository.is_locked())
235
236
        self.assertEqual([('b', 'lw', True),
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
237
                          ('r', 'lw', False),
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.
238
                         ], self.locks)
239
240
    def test_07_lock_read_fail_control(self):
241
        # Test the repository is unlocked if we can't lock self
242
        b = self.get_instrumented_branch()
243
        b.control_files.disable_lock_read()
244
245
        self.assertRaises(TestPreventLocking, b.lock_read)
246
        self.assertFalse(b.is_locked())
247
        self.assertFalse(b.repository.is_locked())
248
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
249
        if self.combined_control:
250
            self.assertEqual([('b', 'lr', True),
251
                              ('r', 'lr', True),
252
                              ('rc', 'lr', True),
253
                              ('bc', 'lr', False),
254
                              ('r', 'ul', True),
255
                              ('rc', 'ul', True),
256
                             ], self.locks)
257
        else:
258
            self.assertEqual([('b', 'lr', True),
259
                              ('r', 'lr', True),
260
                              ('bc', 'lr', False),
261
                              ('r', 'ul', True),
262
                             ], 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.
263
264
    def test_08_lock_write_fail_control(self):
265
        # Test the repository is unlocked if we can't lock self
266
        b = self.get_instrumented_branch()
267
        b.control_files.disable_lock_write()
268
269
        self.assertRaises(TestPreventLocking, b.lock_write)
270
        self.assertFalse(b.is_locked())
271
        self.assertFalse(b.repository.is_locked())
3015.2.14 by Robert Collins
Make branch_implementations.test_locking honour the repository API more.
272
        if self.combined_control:
273
            self.assertEqual([('b', 'lw', True),
274
                              ('r', 'lw', True),
275
                              ('rc', 'lw', True),
276
                              ('bc', 'lw', False),
277
                              ('r', 'ul', True),
278
                              ('rc', 'ul', True),
279
                             ], self.locks)
280
        else:
281
            self.assertEqual([('b', 'lw', True),
282
                              ('r', 'lw', True),
283
                              ('bc', 'lw', False),
284
                              ('r', 'ul', True),
285
                             ], 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.
286
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).
287
    def test_lock_write_returns_None_refuses_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
288
        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).
289
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
290
        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).
291
            if token is not None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
292
                # This test does not apply, because this lockable supports
293
                # tokens.
294
                return
295
            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).
296
                              branch.lock_write, token='token')
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
297
        finally:
298
            branch.unlock()
299
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
300
    def test_reentering_lock_write_raises_on_token_mismatch(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
301
        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).
302
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
303
        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).
304
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
305
                # This test does not apply, because this lockable refuses
306
                # tokens.
307
                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).
308
            different_branch_token = token + 'xxx'
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
309
            # Re-using the same lockable instance with a different branch token
310
            # will raise TokenMismatch.
311
            self.assertRaises(errors.TokenMismatch,
312
                              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).
313
                              token=different_branch_token)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
314
        finally:
315
            branch.unlock()
316
317
    def test_lock_write_with_nonmatching_token(self):
318
        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).
319
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
320
        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).
321
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
322
                # This test does not apply, because this branch refuses
323
                # tokens.
324
                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).
325
            different_branch_token = token + 'xxx'
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
326
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
327
            new_branch = branch.bzrdir.open_branch()
328
            # We only want to test the relocking abilities of branch, so use the
329
            # existing repository object which is already locked.
330
            new_branch.repository = branch.repository
331
            self.assertRaises(errors.TokenMismatch,
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
332
                              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).
333
                              token=different_branch_token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
334
        finally:
335
            branch.unlock()
336
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
337
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
338
    def test_lock_write_with_matching_token(self):
339
        """Test that a branch can be locked with a token, if it is already
340
        locked by that token."""
341
        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).
342
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
343
        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).
344
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
345
                # This test does not apply, because this branch refuses tokens.
346
                return
347
            # The same instance will accept a second lock_write if the specified
348
            # 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).
349
            branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
350
            branch.unlock()
351
            # Calling lock_write on a new instance for the same lockable will
352
            # also succeed.
353
            new_branch = branch.bzrdir.open_branch()
354
            # We only want to test the relocking abilities of branch, so use the
355
            # existing repository object which is already locked.
356
            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).
357
            new_branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
358
            new_branch.unlock()
359
        finally:
360
            branch.unlock()
361
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).
362
    def test_unlock_after_lock_write_with_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
363
        # 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.
364
        # passed some tokens), then unlock should not physically release it.
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
365
        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).
366
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
367
        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).
368
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
369
                # This test does not apply, because this lockable refuses
370
                # tokens.
371
                return
372
            new_branch = branch.bzrdir.open_branch()
373
            # We only want to test the relocking abilities of branch, so use the
374
            # existing repository object which is already locked.
375
            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).
376
            new_branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
377
            new_branch.unlock()
378
            self.assertTrue(branch.get_physical_lock_status()) #XXX
379
        finally:
380
            branch.unlock()
381
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).
382
    def test_lock_write_with_token_fails_when_unlocked(self):
383
        # First, lock and then unlock to get superficially valid tokens.  This
384
        # mimics a likely programming error, where a caller accidentally tries
385
        # to lock with a token that is no longer valid (because the original
386
        # lock was released).
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
387
        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).
388
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
389
        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).
390
        if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
391
            # This test does not apply, because this lockable refuses
392
            # tokens.
393
            return
394
395
        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).
396
                          branch.lock_write, token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
397
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
    def test_lock_write_reenter_with_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
399
        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).
400
        token = branch.lock_write()
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
401
        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).
402
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
403
                # This test does not apply, because this lockable refuses
404
                # tokens.
405
                return
406
            # 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).
407
            branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
408
            branch.unlock()
409
        finally:
410
            branch.unlock()
411
        # The lock should be unlocked on disk.  Verify that with a new lock
412
        # instance.
413
        new_branch = branch.bzrdir.open_branch()
414
        # Calling lock_write now should work, rather than raise LockContention.
415
        new_branch.lock_write()
416
        new_branch.unlock()
417
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
418
    def test_leave_lock_in_place(self):
419
        branch = self.make_branch('b')
420
        # Lock the branch, then use leave_lock_in_place so that when we
421
        # 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).
422
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
423
        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).
424
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
425
                # This test does not apply, because this repository refuses lock
426
                # 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).
427
                self.assertRaises(NotImplementedError,
428
                                  branch.leave_lock_in_place)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
429
                return
430
            branch.leave_lock_in_place()
431
        finally:
432
            branch.unlock()
433
        # We should be unable to relock the repo.
434
        self.assertRaises(errors.LockContention, branch.lock_write)
4327.1.11 by Vincent Ladeuil
Fix the last 6 lock-related failures.
435
        # Cleanup
436
        branch.lock_write(token)
437
        branch.dont_leave_lock_in_place()
438
        branch.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
439
440
    def test_dont_leave_lock_in_place(self):
441
        branch = self.make_branch('b')
442
        # 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).
443
        token = branch.lock_write()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
444
        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).
445
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
446
                # This test does not apply, because this branch refuses lock
447
                # tokens.
448
                self.assertRaises(NotImplementedError,
449
                                  branch.dont_leave_lock_in_place)
450
                return
451
            try:
452
                branch.leave_lock_in_place()
453
            except NotImplementedError:
454
                # This branch doesn't support this API.
455
                return
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
456
            try:
457
                branch.repository.leave_lock_in_place()
458
            except NotImplementedError:
459
                # This repo doesn't support leaving locks around,
460
                # assume it is essentially lock-free.
461
                repo_token = None
462
            else:
463
                repo_token = branch.repository.lock_write()
464
                branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
465
        finally:
466
            branch.unlock()
467
        # Reacquire the lock (with a different branch object) by using the
468
        # tokens.
469
        new_branch = branch.bzrdir.open_branch()
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
470
        if repo_token is not None:
471
            # We have to explicitly lock the repository first.
472
            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).
473
        new_branch.lock_write(token=token)
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
474
        if repo_token is not None:
475
            # Now we don't need our own repository lock anymore (the branch is
476
            # holding it for us).
477
            new_branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
478
        # Call dont_leave_lock_in_place, so that the lock will be released by
479
        # this instance, even though the lock wasn't originally acquired by it.
480
        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.
481
        if repo_token is not None:
482
            new_branch.repository.dont_leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
483
        new_branch.unlock()
2018.15.1 by Andrew Bennetts
All branch_implementations/test_locking tests passing.
484
        # Now the branch (and repository) is unlocked.  Test this by locking it
485
        # without tokens.
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
486
        branch.lock_write()
487
        branch.unlock()
488
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
489
    def test_lock_read_then_unlock(self):
490
        # Calling lock_read then unlocking should work without errors.
491
        branch = self.make_branch('b')
492
        branch.lock_read()
493
        branch.unlock()
494
495
    def test_lock_write_locks_repo_too(self):
496
        if isinstance(self.branch_format, BzrBranchFormat4):
497
            # Branch format 4 is combined with the repository, so this test
498
            # doesn't apply.
499
            return
500
        branch = self.make_branch('b')
501
        branch = branch.bzrdir.open_branch()
502
        branch.lock_write()
503
        try:
3015.2.15 by Robert Collins
Review feedback.
504
            # 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.
505
            self.assertTrue(branch.repository.is_write_locked())
506
            # Does the repository type actually lock?
507
            if not branch.repository.get_physical_lock_status():
508
                # The test was successfully applied, so it was applicable.
509
                return
510
            # Now the branch.repository is physically locked, so we can't lock
511
            # it with a new repository instance.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
512
            new_repo = branch.bzrdir.open_repository()
513
            self.assertRaises(errors.LockContention, new_repo.lock_write)
514
            # We can call lock_write on the original repository object though,
515
            # because it is already locked.
516
            branch.repository.lock_write()
517
            branch.repository.unlock()
518
        finally:
519
            branch.unlock()
3692.1.2 by Andrew Bennetts
Fix regression introduced by fix, and add a test for that regression.
520
521
    def test_lock_and_unlock_leaves_repo_unlocked(self):
522
        branch = self.make_branch('b')
523
        branch.lock_write()
524
        branch.unlock()
525
        self.assertRaises(errors.LockNotHeld, branch.repository.unlock)
526