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