Revision 19b9ba9a test/ganeti.locking_unittest.py

b/test/ganeti.locking_unittest.py
27 27
import time
28 28
import Queue
29 29
import threading
30
import random
30 31

  
31 32
from ganeti import locking
32 33
from ganeti import errors
34
from ganeti import utils
33 35

  
34 36
import testutils
35 37

  
......
1422 1424
    self.GL.release(locking.LEVEL_CLUSTER, ['BGL'])
1423 1425

  
1424 1426

  
1427
class TestLockMonitor(_ThreadedTestCase):
1428
  def setUp(self):
1429
    _ThreadedTestCase.setUp(self)
1430
    self.lm = locking.LockMonitor()
1431

  
1432
  def testSingleThread(self):
1433
    locks = []
1434

  
1435
    for i in range(100):
1436
      name = "TestLock%s" % i
1437
      locks.append(locking.SharedLock(name, monitor=self.lm))
1438

  
1439
    self.assertEqual(len(self.lm._locks), len(locks))
1440

  
1441
    # Delete all locks
1442
    del locks[:]
1443

  
1444
    # The garbage collector might needs some time
1445
    def _CheckLocks():
1446
      if self.lm._locks:
1447
        raise utils.RetryAgain()
1448

  
1449
    utils.Retry(_CheckLocks, 0.1, 30.0)
1450

  
1451
    self.assertFalse(self.lm._locks)
1452

  
1453
  def testMultiThread(self):
1454
    locks = []
1455

  
1456
    def _CreateLock(prev, next, name):
1457
      prev.wait()
1458
      locks.append(locking.SharedLock(name, monitor=self.lm))
1459
      if next:
1460
        next.set()
1461

  
1462
    expnames = []
1463

  
1464
    first = threading.Event()
1465
    prev = first
1466

  
1467
    # Use a deterministic random generator
1468
    for i in random.Random(4263).sample(range(100), 33):
1469
      name = "MtTestLock%s" % i
1470
      expnames.append(name)
1471

  
1472
      ev = threading.Event()
1473
      self._addThread(target=_CreateLock, args=(prev, ev, name))
1474
      prev = ev
1475

  
1476
    # Add locks
1477
    first.set()
1478
    self._waitThreads()
1479

  
1480
    # Check order in which locks were added
1481
    self.assertEqual([i.name for i in locks], expnames)
1482

  
1483
    # Sync queries are not supported
1484
    self.assertRaises(NotImplementedError, self.lm.QueryLocks, ["name"], True)
1485

  
1486
    # Check query result
1487
    self.assertEqual(self.lm.QueryLocks(["name", "mode", "owner"], False),
1488
                     [[name, None, None] for name in utils.NiceSort(expnames)])
1489

  
1490
    # Test exclusive acquire
1491
    for tlock in locks[::4]:
1492
      tlock.acquire(shared=0)
1493
      try:
1494
        def _GetExpResult(name):
1495
          if tlock.name == name:
1496
            return [name, "exclusive", [threading.currentThread().getName()]]
1497
          return [name, None, None]
1498

  
1499
        self.assertEqual(self.lm.QueryLocks(["name", "mode", "owner"], False),
1500
                         [_GetExpResult(name)
1501
                          for name in utils.NiceSort(expnames)])
1502
      finally:
1503
        tlock.release()
1504

  
1505
    # Test shared acquire
1506
    def _Acquire(lock, shared, ev):
1507
      lock.acquire(shared=shared)
1508
      try:
1509
        ev.wait()
1510
      finally:
1511
        lock.release()
1512

  
1513
    for tlock1 in locks[::11]:
1514
      for tlock2 in locks[::-15]:
1515
        if tlock2 == tlock1:
1516
          continue
1517

  
1518
        for tlock3 in locks[::10]:
1519
          if tlock3 == tlock2:
1520
            continue
1521

  
1522
          ev = threading.Event()
1523

  
1524
          # Acquire locks
1525
          tthreads1 = []
1526
          for i in range(3):
1527
            tthreads1.append(self._addThread(target=_Acquire,
1528
                                             args=(tlock1, 1, ev)))
1529
          tthread2 = self._addThread(target=_Acquire, args=(tlock2, 1, ev))
1530
          tthread3 = self._addThread(target=_Acquire, args=(tlock3, 0, ev))
1531

  
1532
          # Check query result
1533
          for (name, mode, owner) in self.lm.QueryLocks(["name", "mode",
1534
                                                         "owner"], False):
1535
            if name == tlock1.name:
1536
              self.assertEqual(mode, "shared")
1537
              self.assertEqual(set(owner), set(i.getName() for i in tthreads1))
1538
              continue
1539

  
1540
            if name == tlock2.name:
1541
              self.assertEqual(mode, "shared")
1542
              self.assertEqual(owner, [tthread2.getName()])
1543
              continue
1544

  
1545
            if name == tlock3.name:
1546
              self.assertEqual(mode, "exclusive")
1547
              self.assertEqual(owner, [tthread3.getName()])
1548
              continue
1549

  
1550
            self.assert_(name in expnames)
1551
            self.assert_(mode is None)
1552
            self.assert_(owner is None)
1553

  
1554
          # Release locks again
1555
          ev.set()
1556

  
1557
          self._waitThreads()
1558

  
1559
          self.assertEqual(self.lm.QueryLocks(["name", "mode", "owner"], False),
1560
                           [[name, None, None]
1561
                            for name in utils.NiceSort(expnames)])
1562

  
1563
  def testDelete(self):
1564
    lock = locking.SharedLock("TestLock", monitor=self.lm)
1565

  
1566
    self.assertEqual(len(self.lm._locks), 1)
1567
    self.assertEqual(self.lm.QueryLocks(["name", "mode", "owner"], False),
1568
                     [[lock.name, None, None]])
1569

  
1570
    lock.delete()
1571

  
1572
    self.assertEqual(self.lm.QueryLocks(["name", "mode", "owner"], False),
1573
                     [[lock.name, "deleted", None]])
1574
    self.assertEqual(len(self.lm._locks), 1)
1575

  
1576

  
1425 1577
if __name__ == '__main__':
1426 1578
  testutils.GanetiTestProgram()

Also available in: Unified diff