/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
1
# Copyright (C) 2006 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Test locks across all branch implemenations"""
18
2381.1.1 by Robert Collins
Split out hpss test fixes which dont depend on new or altered API's.
19
from bzrlib import errors
20
from bzrlib.branch import BzrBranchFormat4
21
from bzrlib.tests import TestSkipped
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
22
from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
1711.8.7 by John Arbash Meinel
Renaming LockHelpers.py to lock_helpers.py
23
from bzrlib.tests.lock_helpers import TestPreventLocking, LockWrapper
1711.8.5 by John Arbash Meinel
Move the new locking tests into their own files, and move the helper functions into a test helper.
24
25
26
class TestBranchLocking(TestCaseWithBranch):
27
2381.1.1 by Robert Collins
Split out hpss test fixes which dont depend on new or altered API's.
28
    def setUp(self):
29
        TestCaseWithBranch.setUp(self)
30
        self.reduceLockdirTimeout()
31
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
    def get_instrumented_branch(self):
33
        """Get a Branch object which has been instrumented"""
34
        # TODO: jam 20060630 It may be that not all formats have a 
35
        # 'control_files' member. So we should fail gracefully if
36
        # not there. But assuming it has them lets us test the exact 
37
        # lock/unlock order.
38
        self.locks = []
39
        b = LockWrapper(self.locks, self.get_branch(), 'b')
40
        b.repository = LockWrapper(self.locks, b.repository, 'r')
41
        bcf = b.control_files
42
        rcf = b.repository.control_files
43
44
        # Look out for branch types that reuse their control files
45
        self.combined_control = bcf is rcf
46
47
        b.control_files = LockWrapper(self.locks, b.control_files, 'bc')
48
        b.repository.control_files = \
49
            LockWrapper(self.locks, b.repository.control_files, 'rc')
50
        return b
51
52
    def test_01_lock_read(self):
53
        # Test that locking occurs in the correct order
54
        b = self.get_instrumented_branch()
55
56
        self.assertFalse(b.is_locked())
57
        self.assertFalse(b.repository.is_locked())
58
        b.lock_read()
59
        try:
60
            self.assertTrue(b.is_locked())
61
            self.assertTrue(b.repository.is_locked())
62
        finally:
63
            b.unlock()
64
        self.assertFalse(b.is_locked())
65
        self.assertFalse(b.repository.is_locked())
66
67
        self.assertEqual([('b', 'lr', True),
68
                          ('r', 'lr', True),
69
                          ('rc', 'lr', True),
70
                          ('bc', 'lr', True),
71
                          ('b', 'ul', True),
72
                          ('bc', 'ul', True),
73
                          ('r', 'ul', True),
74
                          ('rc', 'ul', True),
75
                         ], self.locks)
76
77
    def test_02_lock_write(self):
78
        # Test that locking occurs in the correct order
79
        b = self.get_instrumented_branch()
80
81
        self.assertFalse(b.is_locked())
82
        self.assertFalse(b.repository.is_locked())
83
        b.lock_write()
84
        try:
85
            self.assertTrue(b.is_locked())
86
            self.assertTrue(b.repository.is_locked())
87
        finally:
88
            b.unlock()
89
        self.assertFalse(b.is_locked())
90
        self.assertFalse(b.repository.is_locked())
91
92
        self.assertEqual([('b', 'lw', True),
93
                          ('r', 'lw', True),
94
                          ('rc', 'lw', True),
95
                          ('bc', 'lw', True),
96
                          ('b', 'ul', True),
97
                          ('bc', 'ul', True),
98
                          ('r', 'ul', True),
99
                          ('rc', 'ul', True),
100
                         ], self.locks)
101
102
    def test_03_lock_fail_unlock_repo(self):
103
        # Make sure branch.unlock() is called, even if there is a
104
        # failure while unlocking the repository.
105
        b = self.get_instrumented_branch()
106
        b.repository.disable_unlock()
107
108
        self.assertFalse(b.is_locked())
109
        self.assertFalse(b.repository.is_locked())
110
        b.lock_write()
111
        try:
112
            self.assertTrue(b.is_locked())
113
            self.assertTrue(b.repository.is_locked())
114
            self.assertRaises(TestPreventLocking, b.unlock)
115
            if self.combined_control:
116
                self.assertTrue(b.is_locked())
117
            else:
118
                self.assertFalse(b.is_locked())
119
            self.assertTrue(b.repository.is_locked())
120
121
            # We unlock the branch control files, even if 
122
            # we fail to unlock the repository
123
            self.assertEqual([('b', 'lw', True),
124
                              ('r', 'lw', True),
125
                              ('rc', 'lw', True),
126
                              ('bc', 'lw', True),
127
                              ('b', 'ul', True),
128
                              ('bc', 'ul', True),
129
                              ('r', 'ul', False), 
130
                             ], self.locks)
131
132
        finally:
133
            # For cleanup purposes, make sure we are unlocked
134
            b.repository._other.unlock()
135
136
    def test_04_lock_fail_unlock_control(self):
137
        # Make sure repository.unlock() is called, if we fail to unlock self
138
        b = self.get_instrumented_branch()
139
        b.control_files.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())
147
            self.assertRaises(TestPreventLocking, b.unlock)
148
            self.assertTrue(b.is_locked())
149
            if self.combined_control:
150
                self.assertTrue(b.repository.is_locked())
151
            else:
152
                self.assertFalse(b.repository.is_locked())
153
154
            # We unlock the repository even if 
155
            # we fail to unlock the control files
156
            self.assertEqual([('b', 'lw', True),
157
                              ('r', 'lw', True),
158
                              ('rc', 'lw', True),
159
                              ('bc', 'lw', True),
160
                              ('b', 'ul', True),
161
                              ('bc', 'ul', False),
162
                              ('r', 'ul', True), 
163
                              ('rc', 'ul', True), 
164
                             ], self.locks)
165
166
        finally:
167
            # For cleanup purposes, make sure we are unlocked
168
            b.control_files._other.unlock()
169
170
    def test_05_lock_read_fail_repo(self):
171
        # Test that the branch is not locked if it cannot lock the repository
172
        b = self.get_instrumented_branch()
173
        b.repository.disable_lock_read()
174
175
        self.assertRaises(TestPreventLocking, b.lock_read)
176
        self.assertFalse(b.is_locked())
177
        self.assertFalse(b.repository.is_locked())
178
179
        self.assertEqual([('b', 'lr', True),
180
                          ('r', 'lr', False), 
181
                         ], self.locks)
182
183
    def test_06_lock_write_fail_repo(self):
184
        # Test that the branch is not locked if it cannot lock the repository
185
        b = self.get_instrumented_branch()
186
        b.repository.disable_lock_write()
187
188
        self.assertRaises(TestPreventLocking, b.lock_write)
189
        self.assertFalse(b.is_locked())
190
        self.assertFalse(b.repository.is_locked())
191
192
        self.assertEqual([('b', 'lw', True),
193
                          ('r', 'lw', False), 
194
                         ], self.locks)
195
196
    def test_07_lock_read_fail_control(self):
197
        # Test the repository is unlocked if we can't lock self
198
        b = self.get_instrumented_branch()
199
        b.control_files.disable_lock_read()
200
201
        self.assertRaises(TestPreventLocking, b.lock_read)
202
        self.assertFalse(b.is_locked())
203
        self.assertFalse(b.repository.is_locked())
204
205
        self.assertEqual([('b', 'lr', True),
206
                          ('r', 'lr', True),
207
                          ('rc', 'lr', True),
208
                          ('bc', 'lr', False),
209
                          ('r', 'ul', True),
210
                          ('rc', 'ul', True),
211
                         ], self.locks)
212
213
    def test_08_lock_write_fail_control(self):
214
        # Test the repository is unlocked if we can't lock self
215
        b = self.get_instrumented_branch()
216
        b.control_files.disable_lock_write()
217
218
        self.assertRaises(TestPreventLocking, b.lock_write)
219
        self.assertFalse(b.is_locked())
220
        self.assertFalse(b.repository.is_locked())
221
222
        self.assertEqual([('b', 'lw', True),
223
                          ('r', 'lw', True),
224
                          ('rc', 'lw', True),
225
                          ('bc', 'lw', False),
226
                          ('r', 'ul', True),
227
                          ('rc', 'ul', True),
228
                         ], self.locks)
229
2279.7.7 by Andrew Bennetts
LockDir, Repository and Branch lock token changes from the hpss branch.
230
    def test_lock_write_returns_None_refuses_tokens(self):
231
        branch = self.make_branch('b')
232
        tokens = branch.lock_write()
233
        try:
234
            if tokens is not None:
235
                # This test does not apply, because this lockable supports
236
                # tokens.
237
                return
238
            self.assertRaises(errors.TokenLockingNotSupported,
239
                              branch.lock_write, tokens=('token','token'))
240
        finally:
241
            branch.unlock()
242
243
    def test_reentering_lock_write_raises_on_token_mismatch(self):
244
        branch = self.make_branch('b')
245
        tokens = branch.lock_write()
246
        try:
247
            if tokens is None:
248
                # This test does not apply, because this lockable refuses
249
                # tokens.
250
                return
251
            branch_token, repo_token = tokens
252
            different_branch_token = branch_token + 'xxx'
253
            different_repo_token = repo_token + 'xxx'
254
            # Re-using the same lockable instance with a different branch token
255
            # will raise TokenMismatch.
256
            self.assertRaises(errors.TokenMismatch,
257
                              branch.lock_write,
258
                              tokens=(different_branch_token, repo_token))
259
            # Similarly for a different repository token.
260
            self.assertRaises(errors.TokenMismatch,
261
                              branch.lock_write,
262
                              tokens=(branch_token, different_repo_token))
263
        finally:
264
            branch.unlock()
265
266
    def test_lock_write_with_nonmatching_token(self):
267
        branch = self.make_branch('b')
268
        tokens = branch.lock_write()
269
        try:
270
            if tokens is None:
271
                # This test does not apply, because this branch refuses
272
                # tokens.
273
                return
274
            branch_token, repo_token = tokens
275
            different_branch_token = branch_token + 'xxx'
276
            different_repo_token = repo_token + 'xxx'
277
278
            new_branch = branch.bzrdir.open_branch()
279
            # We only want to test the relocking abilities of branch, so use the
280
            # existing repository object which is already locked.
281
            new_branch.repository = branch.repository
282
            self.assertRaises(errors.TokenMismatch,
283
                              new_branch.lock_write,
284
                              tokens=(different_branch_token, repo_token))
285
            self.assertRaises(errors.TokenMismatch,
286
                              new_branch.lock_write,
287
                              tokens=(branch_token, different_repo_token))
288
        finally:
289
            branch.unlock()
290
291
292
    def test_lock_write_with_matching_token(self):
293
        """Test that a branch can be locked with a token, if it is already
294
        locked by that token."""
295
        branch = self.make_branch('b')
296
        tokens = branch.lock_write()
297
        try:
298
            if tokens is None:
299
                # This test does not apply, because this branch refuses tokens.
300
                return
301
            # The same instance will accept a second lock_write if the specified
302
            # token matches.
303
            branch.lock_write(tokens=tokens)
304
            branch.unlock()
305
            # Calling lock_write on a new instance for the same lockable will
306
            # also succeed.
307
            new_branch = branch.bzrdir.open_branch()
308
            # We only want to test the relocking abilities of branch, so use the
309
            # existing repository object which is already locked.
310
            new_branch.repository = branch.repository
311
            new_branch.lock_write(tokens=tokens)
312
            new_branch.unlock()
313
        finally:
314
            branch.unlock()
315
316
    def test_unlock_after_lock_write_with_tokens(self):
317
        # If lock_write did not physically acquire the lock (because it was
318
        # passed some tokens), then unlock should not physically release it.
319
        branch = self.make_branch('b')
320
        tokens = branch.lock_write()
321
        try:
322
            if tokens is None:
323
                # This test does not apply, because this lockable refuses
324
                # tokens.
325
                return
326
            new_branch = branch.bzrdir.open_branch()
327
            # We only want to test the relocking abilities of branch, so use the
328
            # existing repository object which is already locked.
329
            new_branch.repository = branch.repository
330
            new_branch.lock_write(tokens=tokens)
331
            new_branch.unlock()
332
            self.assertTrue(branch.get_physical_lock_status()) #XXX
333
        finally:
334
            branch.unlock()
335
336
    def test_lock_write_with_tokens_fails_when_unlocked(self):
337
        # Lock and unlock to get superficially valid tokens.  This mimics a
338
        # likely programming error, where a caller accidentally tries to lock
339
        # with tokens that are no longer valid (because the original lock was
340
        # released).
341
        branch = self.make_branch('b')
342
        tokens = branch.lock_write()
343
        branch.unlock()
344
        if tokens is None:
345
            # This test does not apply, because this lockable refuses
346
            # tokens.
347
            return
348
349
        self.assertRaises(errors.TokenMismatch,
350
                          branch.lock_write, tokens=tokens)
351
352
    def test_lock_write_reenter_with_tokens(self):
353
        branch = self.make_branch('b')
354
        tokens = branch.lock_write()
355
        try:
356
            if tokens is None:
357
                # This test does not apply, because this lockable refuses
358
                # tokens.
359
                return
360
            # Relock with a token.
361
            branch.lock_write(tokens=tokens)
362
            branch.unlock()
363
        finally:
364
            branch.unlock()
365
        # The lock should be unlocked on disk.  Verify that with a new lock
366
        # instance.
367
        new_branch = branch.bzrdir.open_branch()
368
        # Calling lock_write now should work, rather than raise LockContention.
369
        new_branch.lock_write()
370
        new_branch.unlock()
371
372
    def test_leave_lock_in_place(self):
373
        branch = self.make_branch('b')
374
        # Lock the branch, then use leave_lock_in_place so that when we
375
        # unlock the branch the lock is still held on disk.
376
        tokens = branch.lock_write()
377
        try:
378
            if tokens is None:
379
                # This test does not apply, because this repository refuses lock
380
                # tokens.
381
                self.assertRaises(NotImplementedError, branch.leave_lock_in_place)
382
                return
383
            branch.leave_lock_in_place()
384
        finally:
385
            branch.unlock()
386
        # We should be unable to relock the repo.
387
        self.assertRaises(errors.LockContention, branch.lock_write)
388
389
    def test_dont_leave_lock_in_place(self):
390
        branch = self.make_branch('b')
391
        # Create a lock on disk.
392
        tokens = branch.lock_write()
393
        try:
394
            if tokens is None:
395
                # This test does not apply, because this branch refuses lock
396
                # tokens.
397
                self.assertRaises(NotImplementedError,
398
                                  branch.dont_leave_lock_in_place)
399
                return
400
            try:
401
                branch.leave_lock_in_place()
402
            except NotImplementedError:
403
                # This branch doesn't support this API.
404
                return
405
            branch.repository.leave_lock_in_place()
406
        finally:
407
            branch.unlock()
408
        # Reacquire the lock (with a different branch object) by using the
409
        # tokens.
410
        new_branch = branch.bzrdir.open_branch()
411
        new_branch.lock_write(tokens=tokens)
412
        # Call dont_leave_lock_in_place, so that the lock will be released by
413
        # this instance, even though the lock wasn't originally acquired by it.
414
        new_branch.dont_leave_lock_in_place()
415
        new_branch.repository.dont_leave_lock_in_place()
416
        new_branch.unlock()
417
        # Now the branch (and repository) is unlocked.  Test this by locking it
418
        # without tokens.
419
        branch.lock_write()
420
        branch.unlock()
421
2381.1.1 by Robert Collins
Split out hpss test fixes which dont depend on new or altered API's.
422
    def test_lock_read_then_unlock(self):
423
        # Calling lock_read then unlocking should work without errors.
424
        branch = self.make_branch('b')
425
        branch.lock_read()
426
        branch.unlock()
427
428
    def test_lock_write_locks_repo_too(self):
429
        if isinstance(self.branch_format, BzrBranchFormat4):
430
            # Branch format 4 is combined with the repository, so this test
431
            # doesn't apply.
432
            return
433
        branch = self.make_branch('b')
434
        branch = branch.bzrdir.open_branch()
435
        branch.lock_write()
436
        try:
437
            # Now the branch.repository is locked, so we can't lock it with a new
438
            # repository without a token.
439
            new_repo = branch.bzrdir.open_repository()
440
            self.assertRaises(errors.LockContention, new_repo.lock_write)
441
            # We can call lock_write on the original repository object though,
442
            # because it is already locked.
443
            branch.repository.lock_write()
444
            branch.repository.unlock()
445
        finally:
446
            branch.unlock()