~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
    errors,
21
    tests,
22
    )
23
from bzrlib.tests import (
24
    lock_helpers,
25
    per_branch,
26
    )
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
27
from bzrlib.tests.matchers import *
5010.2.16 by Vincent Ladeuil
Fix imports in per_branch/test_locking.py.
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')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
294
        token = branch.lock_write().branch_token
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')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
307
        token = branch.lock_write().branch_token
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')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
324
        token = branch.lock_write().branch_token
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')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
347
        token = branch.lock_write().branch_token
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')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
371
        token = branch.lock_write().branch_token
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')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
393
        token = branch.lock_write().branch_token
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
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
399
        self.assertRaises(errors.TokenMismatch, branch.lock_write, token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
400
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
    def test_lock_write_reenter_with_token(self):
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
402
        branch = self.make_branch('b')
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
403
        token = branch.lock_write().branch_token
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
404
        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).
405
            if token is None:
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
406
                # This test does not apply, because this lockable refuses
407
                # tokens.
408
                return
409
            # 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).
410
            branch.lock_write(token=token)
2018.5.75 by Andrew Bennetts
Add Repository.{dont_,}leave_lock_in_place.
411
            branch.unlock()
412
        finally:
413
            branch.unlock()
414
        # The lock should be unlocked on disk.  Verify that with a new lock
415
        # instance.
416
        new_branch = branch.bzrdir.open_branch()
417
        # Calling lock_write now should work, rather than raise LockContention.
418
        new_branch.lock_write()
419
        new_branch.unlock()
420
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
421
    def test_leave_lock_in_place(self):
422
        branch = self.make_branch('b')
423
        # Lock the branch, then use leave_lock_in_place so that when we
424
        # 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
425
        token = branch.lock_write().branch_token
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
426
        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).
427
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
428
                # This test does not apply, because this repository refuses lock
429
                # 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).
430
                self.assertRaises(NotImplementedError,
431
                                  branch.leave_lock_in_place)
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
432
                return
433
            branch.leave_lock_in_place()
434
        finally:
435
            branch.unlock()
436
        # We should be unable to relock the repo.
437
        self.assertRaises(errors.LockContention, branch.lock_write)
4327.1.11 by Vincent Ladeuil
Fix the last 6 lock-related failures.
438
        # Cleanup
439
        branch.lock_write(token)
440
        branch.dont_leave_lock_in_place()
441
        branch.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
442
443
    def test_dont_leave_lock_in_place(self):
444
        branch = self.make_branch('b')
445
        # Create a lock on disk.
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
446
        token = branch.lock_write().branch_token
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
447
        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).
448
            if token is None:
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
449
                # This test does not apply, because this branch refuses lock
450
                # tokens.
451
                self.assertRaises(NotImplementedError,
452
                                  branch.dont_leave_lock_in_place)
453
                return
454
            try:
455
                branch.leave_lock_in_place()
456
            except NotImplementedError:
457
                # This branch doesn't support this API.
458
                return
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
459
            try:
460
                branch.repository.leave_lock_in_place()
461
            except NotImplementedError:
462
                # This repo doesn't support leaving locks around,
463
                # assume it is essentially lock-free.
464
                repo_token = None
465
            else:
466
                repo_token = branch.repository.lock_write()
467
                branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
468
        finally:
469
            branch.unlock()
470
        # Reacquire the lock (with a different branch object) by using the
471
        # tokens.
472
        new_branch = branch.bzrdir.open_branch()
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
473
        if repo_token is not None:
474
            # We have to explicitly lock the repository first.
475
            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).
476
        new_branch.lock_write(token=token)
3015.2.5 by Robert Collins
Handle repositories that cannot be remotely locked in branch_implementations.test_locking.
477
        if repo_token is not None:
478
            # Now we don't need our own repository lock anymore (the branch is
479
            # holding it for us).
480
            new_branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
481
        # Call dont_leave_lock_in_place, so that the lock will be released by
482
        # this instance, even though the lock wasn't originally acquired by it.
483
        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.
484
        if repo_token is not None:
485
            new_branch.repository.dont_leave_lock_in_place()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
486
        new_branch.unlock()
2018.15.1 by Andrew Bennetts
All branch_implementations/test_locking tests passing.
487
        # Now the branch (and repository) is unlocked.  Test this by locking it
488
        # without tokens.
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
489
        branch.lock_write()
490
        branch.unlock()
491
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
492
    def test_lock_read_then_unlock(self):
493
        # Calling lock_read then unlocking should work without errors.
494
        branch = self.make_branch('b')
495
        branch.lock_read()
496
        branch.unlock()
497
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
498
    def test_lock_read_returns_unlockable(self):
499
        branch = self.make_branch('b')
500
        self.assertThat(branch.lock_read, ReturnsUnlockable(branch))
501
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
502
    def test_lock_write_locks_repo_too(self):
503
        branch = self.make_branch('b')
504
        branch = branch.bzrdir.open_branch()
505
        branch.lock_write()
506
        try:
3015.2.15 by Robert Collins
Review feedback.
507
            # 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.
508
            self.assertTrue(branch.repository.is_write_locked())
509
            # Does the repository type actually lock?
510
            if not branch.repository.get_physical_lock_status():
511
                # The test was successfully applied, so it was applicable.
512
                return
513
            # Now the branch.repository is physically locked, so we can't lock
514
            # it with a new repository instance.
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
515
            new_repo = branch.bzrdir.open_repository()
516
            self.assertRaises(errors.LockContention, new_repo.lock_write)
517
            # We can call lock_write on the original repository object though,
518
            # because it is already locked.
519
            branch.repository.lock_write()
520
            branch.repository.unlock()
521
        finally:
522
            branch.unlock()
3692.1.2 by Andrew Bennetts
Fix regression introduced by fix, and add a test for that regression.
523
5200.3.3 by Robert Collins
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
524
    def test_lock_write_returns_unlockable(self):
525
        branch = self.make_branch('b')
526
        self.assertThat(branch.lock_write, ReturnsUnlockable(branch))
527
5241.1.1 by Andrew Bennetts
Fix AttributeError in RemoteBranch.lock_write after lock_read.
528
    def test_lock_write_raises_in_lock_read(self):
529
        branch = self.make_branch('b')
530
        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.
531
        self.addCleanup(branch.unlock)
5241.1.1 by Andrew Bennetts
Fix AttributeError in RemoteBranch.lock_write after lock_read.
532
        err = self.assertRaises(errors.ReadOnlyError, branch.lock_write)
533
3692.1.2 by Andrew Bennetts
Fix regression introduced by fix, and add a test for that regression.
534
    def test_lock_and_unlock_leaves_repo_unlocked(self):
535
        branch = self.make_branch('b')
536
        branch.lock_write()
537
        branch.unlock()
538
        self.assertRaises(errors.LockNotHeld, branch.repository.unlock)
539