~bzr-pqm/bzr/bzr.dev

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