/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/branch_implementations/test_locking.py

First attempt to merge .dev and resolve the conflicts (but tests are 
failing)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Test locks across all branch implemenations"""
18
18
 
 
19
from bzrlib import errors
 
20
from bzrlib.branch import BzrBranchFormat4
 
21
from bzrlib.bzrdir import RemoteBzrDirFormat
 
22
from bzrlib.tests import TestSkipped
19
23
from bzrlib.tests.branch_implementations.test_branch import TestCaseWithBranch
20
24
from bzrlib.tests.lock_helpers import TestPreventLocking, LockWrapper
21
25
 
22
26
 
23
27
class TestBranchLocking(TestCaseWithBranch):
24
28
 
 
29
    def setUp(self):
 
30
        TestCaseWithBranch.setUp(self)
 
31
        self.reduceLockdirTimeout()
 
32
 
25
33
    def get_instrumented_branch(self):
26
34
        """Get a Branch object which has been instrumented"""
27
35
        # TODO: jam 20060630 It may be that not all formats have a 
32
40
        b = LockWrapper(self.locks, self.get_branch(), 'b')
33
41
        b.repository = LockWrapper(self.locks, b.repository, 'r')
34
42
        bcf = b.control_files
35
 
        rcf = b.repository.control_files
36
 
 
37
 
        # Look out for branch types that reuse their control files
38
 
        self.combined_control = bcf is rcf
39
 
 
40
 
        b.control_files = LockWrapper(self.locks, b.control_files, 'bc')
41
 
        b.repository.control_files = \
42
 
            LockWrapper(self.locks, b.repository.control_files, 'rc')
 
43
        rcf = getattr(b.repository, 'control_files', None)
 
44
        if rcf is None:
 
45
            self.combined_branch = False
 
46
        else:
 
47
            # Look out for branch types that reuse their control files
 
48
            self.combined_control = bcf is rcf
 
49
        try:
 
50
            b.control_files = LockWrapper(self.locks, b.control_files, 'bc')
 
51
        except AttributeError:
 
52
            # RemoteBranch seems to trigger this.
 
53
            raise TestSkipped("Could not instrument branch control files.")
 
54
        if self.combined_control:
 
55
            # instrument the repository control files too to ensure its worked
 
56
            # with correctly. When they are not shared, we trust the repository
 
57
            # API and only instrument the repository itself. 
 
58
            b.repository.control_files = \
 
59
                LockWrapper(self.locks, b.repository.control_files, 'rc')
43
60
        return b
44
61
 
45
62
    def test_01_lock_read(self):
57
74
        self.assertFalse(b.is_locked())
58
75
        self.assertFalse(b.repository.is_locked())
59
76
 
60
 
        self.assertEqual([('b', 'lr', True),
61
 
                          ('r', 'lr', True),
62
 
                          ('rc', 'lr', True),
63
 
                          ('bc', 'lr', True),
64
 
                          ('b', 'ul', True),
65
 
                          ('bc', 'ul', True),
66
 
                          ('r', 'ul', True),
67
 
                          ('rc', 'ul', True),
68
 
                         ], self.locks)
 
77
        if self.combined_control:
 
78
            self.assertEqual([('b', 'lr', True),
 
79
                              ('r', 'lr', True),
 
80
                              ('rc', 'lr', True),
 
81
                              ('bc', 'lr', True),
 
82
                              ('b', 'ul', True),
 
83
                              ('bc', 'ul', True),
 
84
                              ('r', 'ul', True),
 
85
                              ('rc', 'ul', True),
 
86
                             ], self.locks)
 
87
        else:
 
88
            self.assertEqual([('b', 'lr', True),
 
89
                              ('r', 'lr', True),
 
90
                              ('bc', 'lr', True),
 
91
                              ('b', 'ul', True),
 
92
                              ('bc', 'ul', True),
 
93
                              ('r', 'ul', True),
 
94
                             ], self.locks)
69
95
 
70
96
    def test_02_lock_write(self):
71
97
        # Test that locking occurs in the correct order
82
108
        self.assertFalse(b.is_locked())
83
109
        self.assertFalse(b.repository.is_locked())
84
110
 
85
 
        self.assertEqual([('b', 'lw', True),
86
 
                          ('r', 'lw', True),
87
 
                          ('rc', 'lw', True),
88
 
                          ('bc', 'lw', True),
89
 
                          ('b', 'ul', True),
90
 
                          ('bc', 'ul', True),
91
 
                          ('r', 'ul', True),
92
 
                          ('rc', 'ul', True),
93
 
                         ], self.locks)
 
111
        if self.combined_control:
 
112
            self.assertEqual([('b', 'lw', True),
 
113
                              ('r', 'lw', True),
 
114
                              ('rc', 'lw', True),
 
115
                              ('bc', 'lw', True),
 
116
                              ('b', 'ul', True),
 
117
                              ('bc', 'ul', True),
 
118
                              ('r', 'ul', True),
 
119
                              ('rc', 'ul', True),
 
120
                             ], self.locks)
 
121
        else:
 
122
            self.assertEqual([('b', 'lw', True),
 
123
                              ('r', 'lw', True),
 
124
                              ('bc', 'lw', True),
 
125
                              ('b', 'ul', True),
 
126
                              ('bc', 'ul', True),
 
127
                              ('r', 'ul', True),
 
128
                             ], self.locks)
94
129
 
95
130
    def test_03_lock_fail_unlock_repo(self):
96
131
        # Make sure branch.unlock() is called, even if there is a
113
148
 
114
149
            # We unlock the branch control files, even if 
115
150
            # we fail to unlock the repository
116
 
            self.assertEqual([('b', 'lw', True),
117
 
                              ('r', 'lw', True),
118
 
                              ('rc', 'lw', True),
119
 
                              ('bc', 'lw', True),
120
 
                              ('b', 'ul', True),
121
 
                              ('bc', 'ul', True),
122
 
                              ('r', 'ul', False), 
123
 
                             ], self.locks)
 
151
            if self.combined_control:
 
152
                self.assertEqual([('b', 'lw', True),
 
153
                                  ('r', 'lw', True),
 
154
                                  ('rc', 'lw', True),
 
155
                                  ('bc', 'lw', True),
 
156
                                  ('b', 'ul', True),
 
157
                                  ('bc', 'ul', True),
 
158
                                  ('r', 'ul', False),
 
159
                                 ], self.locks)
 
160
            else:
 
161
                self.assertEqual([('b', 'lw', True),
 
162
                                  ('r', 'lw', True),
 
163
                                  ('bc', 'lw', True),
 
164
                                  ('b', 'ul', True),
 
165
                                  ('bc', 'ul', True),
 
166
                                  ('r', 'ul', False),
 
167
                                 ], self.locks)
124
168
 
125
169
        finally:
126
170
            # For cleanup purposes, make sure we are unlocked
146
190
 
147
191
            # We unlock the repository even if 
148
192
            # we fail to unlock the control files
149
 
            self.assertEqual([('b', 'lw', True),
150
 
                              ('r', 'lw', True),
151
 
                              ('rc', 'lw', True),
152
 
                              ('bc', 'lw', True),
153
 
                              ('b', 'ul', True),
154
 
                              ('bc', 'ul', False),
155
 
                              ('r', 'ul', True), 
156
 
                              ('rc', 'ul', True), 
157
 
                             ], self.locks)
 
193
            if self.combined_control:
 
194
                self.assertEqual([('b', 'lw', True),
 
195
                                  ('r', 'lw', True),
 
196
                                  ('rc', 'lw', True),
 
197
                                  ('bc', 'lw', True),
 
198
                                  ('b', 'ul', True),
 
199
                                  ('bc', 'ul', False),
 
200
                                  ('r', 'ul', True),
 
201
                                  ('rc', 'ul', True),
 
202
                                 ], self.locks)
 
203
            else:
 
204
                self.assertEqual([('b', 'lw', True),
 
205
                                  ('r', 'lw', True),
 
206
                                  ('bc', 'lw', True),
 
207
                                  ('b', 'ul', True),
 
208
                                  ('bc', 'ul', False),
 
209
                                  ('r', 'ul', True),
 
210
                                 ], self.locks)
158
211
 
159
212
        finally:
160
213
            # For cleanup purposes, make sure we are unlocked
195
248
        self.assertFalse(b.is_locked())
196
249
        self.assertFalse(b.repository.is_locked())
197
250
 
198
 
        self.assertEqual([('b', 'lr', True),
199
 
                          ('r', 'lr', True),
200
 
                          ('rc', 'lr', True),
201
 
                          ('bc', 'lr', False),
202
 
                          ('r', 'ul', True),
203
 
                          ('rc', 'ul', True),
204
 
                         ], self.locks)
 
251
        if self.combined_control:
 
252
            self.assertEqual([('b', 'lr', True),
 
253
                              ('r', 'lr', True),
 
254
                              ('rc', 'lr', True),
 
255
                              ('bc', 'lr', False),
 
256
                              ('r', 'ul', True),
 
257
                              ('rc', 'ul', True),
 
258
                             ], self.locks)
 
259
        else:
 
260
            self.assertEqual([('b', 'lr', True),
 
261
                              ('r', 'lr', True),
 
262
                              ('bc', 'lr', False),
 
263
                              ('r', 'ul', True),
 
264
                             ], self.locks)
205
265
 
206
266
    def test_08_lock_write_fail_control(self):
207
267
        # Test the repository is unlocked if we can't lock self
211
271
        self.assertRaises(TestPreventLocking, b.lock_write)
212
272
        self.assertFalse(b.is_locked())
213
273
        self.assertFalse(b.repository.is_locked())
214
 
 
215
 
        self.assertEqual([('b', 'lw', True),
216
 
                          ('r', 'lw', True),
217
 
                          ('rc', 'lw', True),
218
 
                          ('bc', 'lw', False),
219
 
                          ('r', 'ul', True),
220
 
                          ('rc', 'ul', True),
221
 
                         ], self.locks)
222
 
 
 
274
        if self.combined_control:
 
275
            self.assertEqual([('b', 'lw', True),
 
276
                              ('r', 'lw', True),
 
277
                              ('rc', 'lw', True),
 
278
                              ('bc', 'lw', False),
 
279
                              ('r', 'ul', True),
 
280
                              ('rc', 'ul', True),
 
281
                             ], self.locks)
 
282
        else:
 
283
            self.assertEqual([('b', 'lw', True),
 
284
                              ('r', 'lw', True),
 
285
                              ('bc', 'lw', False),
 
286
                              ('r', 'ul', True),
 
287
                             ], self.locks)
 
288
 
 
289
    def test_lock_write_returns_None_refuses_token(self):
 
290
        branch = self.make_branch('b')
 
291
        token = branch.lock_write()
 
292
        try:
 
293
            if token is not None:
 
294
                # This test does not apply, because this lockable supports
 
295
                # tokens.
 
296
                return
 
297
            self.assertRaises(errors.TokenLockingNotSupported,
 
298
                              branch.lock_write, token='token')
 
299
        finally:
 
300
            branch.unlock()
 
301
 
 
302
    def test_reentering_lock_write_raises_on_token_mismatch(self):
 
303
        branch = self.make_branch('b')
 
304
        token = branch.lock_write()
 
305
        try:
 
306
            if token is None:
 
307
                # This test does not apply, because this lockable refuses
 
308
                # tokens.
 
309
                return
 
310
            different_branch_token = token + 'xxx'
 
311
            # Re-using the same lockable instance with a different branch token
 
312
            # will raise TokenMismatch.
 
313
            self.assertRaises(errors.TokenMismatch,
 
314
                              branch.lock_write,
 
315
                              token=different_branch_token)
 
316
        finally:
 
317
            branch.unlock()
 
318
 
 
319
    def test_lock_write_with_nonmatching_token(self):
 
320
        branch = self.make_branch('b')
 
321
        token = branch.lock_write()
 
322
        try:
 
323
            if token is None:
 
324
                # This test does not apply, because this branch refuses
 
325
                # tokens.
 
326
                return
 
327
            different_branch_token = token + 'xxx'
 
328
 
 
329
            new_branch = branch.bzrdir.open_branch()
 
330
            # We only want to test the relocking abilities of branch, so use the
 
331
            # existing repository object which is already locked.
 
332
            new_branch.repository = branch.repository
 
333
            self.assertRaises(errors.TokenMismatch,
 
334
                              new_branch.lock_write,
 
335
                              token=different_branch_token)
 
336
        finally:
 
337
            branch.unlock()
 
338
 
 
339
 
 
340
    def test_lock_write_with_matching_token(self):
 
341
        """Test that a branch can be locked with a token, if it is already
 
342
        locked by that token."""
 
343
        branch = self.make_branch('b')
 
344
        token = branch.lock_write()
 
345
        try:
 
346
            if token is None:
 
347
                # This test does not apply, because this branch refuses tokens.
 
348
                return
 
349
            # The same instance will accept a second lock_write if the specified
 
350
            # token matches.
 
351
            branch.lock_write(token=token)
 
352
            branch.unlock()
 
353
            # Calling lock_write on a new instance for the same lockable will
 
354
            # also succeed.
 
355
            new_branch = branch.bzrdir.open_branch()
 
356
            # We only want to test the relocking abilities of branch, so use the
 
357
            # existing repository object which is already locked.
 
358
            new_branch.repository = branch.repository
 
359
            new_branch.lock_write(token=token)
 
360
            new_branch.unlock()
 
361
        finally:
 
362
            branch.unlock()
 
363
 
 
364
    def test_unlock_after_lock_write_with_token(self):
 
365
        # If lock_write did not physically acquire the lock (because it was
 
366
        # passed some tokens), then unlock should not physically release it.
 
367
        branch = self.make_branch('b')
 
368
        token = branch.lock_write()
 
369
        try:
 
370
            if token is None:
 
371
                # This test does not apply, because this lockable refuses
 
372
                # tokens.
 
373
                return
 
374
            new_branch = branch.bzrdir.open_branch()
 
375
            # We only want to test the relocking abilities of branch, so use the
 
376
            # existing repository object which is already locked.
 
377
            new_branch.repository = branch.repository
 
378
            new_branch.lock_write(token=token)
 
379
            new_branch.unlock()
 
380
            self.assertTrue(branch.get_physical_lock_status()) #XXX
 
381
        finally:
 
382
            branch.unlock()
 
383
 
 
384
    def test_lock_write_with_token_fails_when_unlocked(self):
 
385
        # First, lock and then unlock to get superficially valid tokens.  This
 
386
        # mimics a likely programming error, where a caller accidentally tries
 
387
        # to lock with a token that is no longer valid (because the original
 
388
        # lock was released).
 
389
        branch = self.make_branch('b')
 
390
        token = branch.lock_write()
 
391
        branch.unlock()
 
392
        if token is None:
 
393
            # This test does not apply, because this lockable refuses
 
394
            # tokens.
 
395
            return
 
396
 
 
397
        self.assertRaises(errors.TokenMismatch,
 
398
                          branch.lock_write, token=token)
 
399
 
 
400
    def test_lock_write_reenter_with_token(self):
 
401
        branch = self.make_branch('b')
 
402
        token = branch.lock_write()
 
403
        try:
 
404
            if token is None:
 
405
                # This test does not apply, because this lockable refuses
 
406
                # tokens.
 
407
                return
 
408
            # Relock with a token.
 
409
            branch.lock_write(token=token)
 
410
            branch.unlock()
 
411
        finally:
 
412
            branch.unlock()
 
413
        # The lock should be unlocked on disk.  Verify that with a new lock
 
414
        # instance.
 
415
        new_branch = branch.bzrdir.open_branch()
 
416
        # Calling lock_write now should work, rather than raise LockContention.
 
417
        new_branch.lock_write()
 
418
        new_branch.unlock()
 
419
 
 
420
    def test_leave_lock_in_place(self):
 
421
        branch = self.make_branch('b')
 
422
        # Lock the branch, then use leave_lock_in_place so that when we
 
423
        # unlock the branch the lock is still held on disk.
 
424
        token = branch.lock_write()
 
425
        try:
 
426
            if token is None:
 
427
                # This test does not apply, because this repository refuses lock
 
428
                # tokens.
 
429
                self.assertRaises(NotImplementedError,
 
430
                                  branch.leave_lock_in_place)
 
431
                return
 
432
            branch.leave_lock_in_place()
 
433
        finally:
 
434
            branch.unlock()
 
435
        # We should be unable to relock the repo.
 
436
        self.assertRaises(errors.LockContention, branch.lock_write)
 
437
 
 
438
    def test_dont_leave_lock_in_place(self):
 
439
        branch = self.make_branch('b')
 
440
        # Create a lock on disk.
 
441
        token = branch.lock_write()
 
442
        try:
 
443
            if token is None:
 
444
                # This test does not apply, because this branch refuses lock
 
445
                # tokens.
 
446
                self.assertRaises(NotImplementedError,
 
447
                                  branch.dont_leave_lock_in_place)
 
448
                return
 
449
            try:
 
450
                branch.leave_lock_in_place()
 
451
            except NotImplementedError:
 
452
                # This branch doesn't support this API.
 
453
                return
 
454
            try:
 
455
                branch.repository.leave_lock_in_place()
 
456
            except NotImplementedError:
 
457
                # This repo doesn't support leaving locks around,
 
458
                # assume it is essentially lock-free.
 
459
                repo_token = None
 
460
            else:
 
461
                repo_token = branch.repository.lock_write()
 
462
                branch.repository.unlock()
 
463
        finally:
 
464
            branch.unlock()
 
465
        # Reacquire the lock (with a different branch object) by using the
 
466
        # tokens.
 
467
        new_branch = branch.bzrdir.open_branch()
 
468
        if repo_token is not None:
 
469
            # We have to explicitly lock the repository first.
 
470
            new_branch.repository.lock_write(token=repo_token)
 
471
        new_branch.lock_write(token=token)
 
472
        if repo_token is not None:
 
473
            # Now we don't need our own repository lock anymore (the branch is
 
474
            # holding it for us).
 
475
            new_branch.repository.unlock()
 
476
        # Call dont_leave_lock_in_place, so that the lock will be released by
 
477
        # this instance, even though the lock wasn't originally acquired by it.
 
478
        new_branch.dont_leave_lock_in_place()
 
479
        if repo_token is not None:
 
480
            new_branch.repository.dont_leave_lock_in_place()
 
481
        new_branch.unlock()
 
482
        # Now the branch (and repository) is unlocked.  Test this by locking it
 
483
        # without tokens.
 
484
        branch.lock_write()
 
485
        branch.unlock()
 
486
 
 
487
    def test_lock_read_then_unlock(self):
 
488
        # Calling lock_read then unlocking should work without errors.
 
489
        branch = self.make_branch('b')
 
490
        branch.lock_read()
 
491
        branch.unlock()
 
492
 
 
493
    def test_lock_write_locks_repo_too(self):
 
494
        if isinstance(self.branch_format, BzrBranchFormat4):
 
495
            # Branch format 4 is combined with the repository, so this test
 
496
            # doesn't apply.
 
497
            return
 
498
        branch = self.make_branch('b')
 
499
        branch = branch.bzrdir.open_branch()
 
500
        branch.lock_write()
 
501
        try:
 
502
            # The branch should have asked the repository to lock.
 
503
            self.assertTrue(branch.repository.is_write_locked())
 
504
            # Does the repository type actually lock?
 
505
            if not branch.repository.get_physical_lock_status():
 
506
                # The test was successfully applied, so it was applicable.
 
507
                return
 
508
            # Now the branch.repository is physically locked, so we can't lock
 
509
            # it with a new repository instance.
 
510
            new_repo = branch.bzrdir.open_repository()
 
511
            self.assertRaises(errors.LockContention, new_repo.lock_write)
 
512
            # We can call lock_write on the original repository object though,
 
513
            # because it is already locked.
 
514
            branch.repository.lock_write()
 
515
            branch.repository.unlock()
 
516
        finally:
 
517
            branch.unlock()