231
225
self.assertEqual([], self._logged_reports)
233
def test_32_lock_wait_succeed(self):
234
"""Succeed when trying to acquire a lock that gets released
236
One thread holds on a lock and then releases it; another
239
# This test sometimes fails like this:
240
# Traceback (most recent call last):
242
# File "/home/pqm/bzr-pqm-workdir/home/+trunk/bzrlib/tests/
243
# test_lockdir.py", line 247, in test_32_lock_wait_succeed
244
# self.assertEqual(1, len(self._logged_reports))
245
# AssertionError: not equal:
248
raise tests.TestSkipped("Test fails intermittently")
249
t = self.get_transport()
250
lf1 = LockDir(t, 'test_lock')
254
def wait_and_unlock():
257
unlocker = Thread(target=wait_and_unlock)
260
lf2 = LockDir(t, 'test_lock')
261
self.setup_log_reporter(lf2)
264
lf2.wait_lock(timeout=0.4, poll=0.1)
266
self.assertTrue(after - before <= 1.0)
270
# There should be only 1 report, even though it should have to
272
lock_base = lf2.transport.abspath(lf2.path)
273
self.assertEqual(1, len(self._logged_reports))
274
self.assertEqual('%s %s\n'
276
'Will continue to try until %s\n',
277
self._logged_reports[0][0])
278
args = self._logged_reports[0][1]
279
self.assertEqual('Unable to obtain', args[0])
280
self.assertEqual('lock %s' % (lock_base,), args[1])
281
self.assertStartsWith(args[2], 'held by ')
282
self.assertStartsWith(args[3], 'locked ')
283
self.assertEndsWith(args[3], ' ago')
284
self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
286
def test_34_lock_write_waits(self):
287
"""LockDir.lock_write() will wait for the lock."""
288
# the test suite sets the default to 0 to make deadlocks fail fast.
289
# change it for this test, as we want to try a manual deadlock.
290
raise tests.TestSkipped('Timing-sensitive test')
291
bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 300
292
t = self.get_transport()
293
lf1 = LockDir(t, 'test_lock')
297
def wait_and_unlock():
300
unlocker = Thread(target=wait_and_unlock)
303
lf2 = LockDir(t, 'test_lock')
304
self.setup_log_reporter(lf2)
312
# There should be only 1 report, even though it should have to
314
lock_base = lf2.transport.abspath(lf2.path)
315
self.assertEqual(1, len(self._logged_reports))
316
self.assertEqual('%s %s\n'
318
'Will continue to try until %s\n',
319
self._logged_reports[0][0])
320
args = self._logged_reports[0][1]
321
self.assertEqual('Unable to obtain', args[0])
322
self.assertEqual('lock %s' % (lock_base,), args[1])
323
self.assertStartsWith(args[2], 'held by ')
324
self.assertStartsWith(args[3], 'locked ')
325
self.assertEndsWith(args[3], ' ago')
326
self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
328
def test_35_wait_lock_changing(self):
329
"""LockDir.wait_lock() will report if the lock changes underneath.
331
This is the stages we want to happen:
333
0) Synchronization locks are created and locked.
334
1) Lock1 obtains the lockdir, and releases the 'check' lock.
335
2) Lock2 grabs the 'check' lock, and checks the lockdir.
336
It sees the lockdir is already acquired, reports the fact,
337
and unsets the 'checked' lock.
338
3) Thread1 blocks on acquiring the 'checked' lock, and then tells
339
Lock1 to release and acquire the lockdir. This resets the 'check'
341
4) Lock2 acquires the 'check' lock, and checks again. It notices
342
that the holder of the lock has changed, and so reports a new
344
5) Thread1 blocks on the 'checked' lock, this time, it completely
345
unlocks the lockdir, allowing Lock2 to acquire the lock.
348
raise tests.KnownFailure(
349
"timing dependency in lock tests (#213182)")
351
wait_to_check_lock = Lock()
352
wait_until_checked_lock = Lock()
354
wait_to_check_lock.acquire()
355
wait_until_checked_lock.acquire()
356
note('locked check and checked locks')
358
class LockDir1(LockDir):
359
"""Use the synchronization points for the first lock."""
361
def attempt_lock(self):
362
# Once we have acquired the lock, it is okay for
363
# the other lock to check it
365
return super(LockDir1, self).attempt_lock()
367
note('lock1: releasing check lock')
368
wait_to_check_lock.release()
370
class LockDir2(LockDir):
371
"""Use the synchronization points for the second lock."""
373
def attempt_lock(self):
374
note('lock2: waiting for check lock')
375
wait_to_check_lock.acquire()
376
note('lock2: acquired check lock')
378
return super(LockDir2, self).attempt_lock()
380
note('lock2: releasing checked lock')
381
wait_until_checked_lock.release()
383
t = self.get_transport()
384
lf1 = LockDir1(t, 'test_lock')
387
lf2 = LockDir2(t, 'test_lock')
388
self.setup_log_reporter(lf2)
390
def wait_and_switch():
392
# Block until lock2 has had a chance to check
393
note('lock1: waiting 1 for checked lock')
394
wait_until_checked_lock.acquire()
395
note('lock1: acquired for checked lock')
396
note('lock1: released lockdir')
398
note('lock1: acquiring lockdir')
399
# Create a new nonce, so the lock looks different.
400
lf1.nonce = osutils.rand_chars(20)
402
note('lock1: acquired lockdir')
404
# Block until lock2 has peeked again
405
note('lock1: waiting 2 for checked lock')
406
wait_until_checked_lock.acquire()
407
note('lock1: acquired for checked lock')
408
# Now unlock, and let lock 2 grab the lock
410
wait_to_check_lock.release()
412
unlocker = Thread(target=wait_and_switch)
415
# Wait and play against the other thread
416
lf2.wait_lock(timeout=20.0, poll=0.01)
421
# There should be 2 reports, because the lock changed
422
lock_base = lf2.transport.abspath(lf2.path)
423
self.assertEqual(2, len(self._logged_reports))
424
lock_url = lf2.transport.abspath(lf2.path)
425
self.assertEqual('%s %s\n'
427
'Will continue to try until %s, unless '
428
'you press Ctrl-C.\n'
429
'See "bzr help break-lock" for more.',
430
self._logged_reports[0][0])
431
args = self._logged_reports[0][1]
432
self.assertEqual('Unable to obtain', args[0])
433
self.assertEqual('lock %s' % (lock_base,), args[1])
434
self.assertStartsWith(args[2], 'held by ')
435
self.assertStartsWith(args[3], 'locked ')
436
self.assertEndsWith(args[3], ' ago')
437
self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
439
self.assertEqual('%s %s\n'
441
'Will continue to try until %s, unless '
442
'you press Ctrl-C.\n'
443
'See "bzr help break-lock" for more.',
444
self._logged_reports[1][0])
445
args = self._logged_reports[1][1]
446
self.assertEqual('Lock owner changed for', args[0])
447
self.assertEqual('lock %s' % (lock_base,), args[1])
448
self.assertStartsWith(args[2], 'held by ')
449
self.assertStartsWith(args[3], 'locked ')
450
self.assertEndsWith(args[3], ' ago')
451
self.assertContainsRe(args[4], r'\d\d:\d\d:\d\d')
453
227
def test_40_confirm_easy(self):
454
228
"""Confirm a lock that's already held"""
455
229
t = self.get_transport()