Support quit-unlock in lock_machine.py.
Add support for the case when the program exits, all the machine
it lockes will be uplocked. It also maintains the functionality that
you can lock it manually and you have to lock it manually too.
It does not increase the race chance compared with the original one.
It just enlarges the critical section length.

Test: lock_machine_test.py passed.
      The quit-then-unlock lock works as intended.

PRESUBMIT=passed
R=asharif,llozano,shenhan
APPROVED=asharif
DELTA=129  (116 added, 1 deleted, 12 changed)
OCL=63805-p2
RCL=64061-p2
RDATE=2012/11/14 16:09:23


P4 change: 42799301
diff --git a/v14/lock_machine_test.py b/v14/lock_machine_test.py
index 22488de..5688a0f 100644
--- a/v14/lock_machine_test.py
+++ b/v14/lock_machine_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.6
+#!/usr/bin/python
 #
 # Copyright 2010 Google Inc. All Rights Reserved.
 
@@ -9,20 +9,29 @@
 
 __author__ = "asharif@google.com (Ahmad Sharif)"
 
+from multiprocessing import Process
+import time
+import unittest
 
 import lock_machine
-import unittest
+
+
+def LockAndSleep(machine):
+  lock_machine.Machine(machine, auto=True).Lock(exclusive=True)
+  time.sleep(1)
 
 
 class MachineTest(unittest.TestCase):
   def setUp(self):
     pass
 
-
   def testRepeatedUnlock(self):
     mach = lock_machine.Machine("qqqraymes.mtv")
     for i in range(10):
       self.assertFalse(mach.Unlock())
+    mach = lock_machine.Machine("qqqraymes.mtv", auto=True)
+    for i in range(10):
+      self.assertFalse(mach.Unlock())
 
   def testLockUnlock(self):
     mach = lock_machine.Machine("otter.mtv", "/tmp")
@@ -30,6 +39,11 @@
       self.assertTrue(mach.Lock(exclusive=True))
       self.assertTrue(mach.Unlock(exclusive=True))
 
+    mach = lock_machine.Machine("otter.mtv", "/tmp", True)
+    for i in range(10):
+      self.assertTrue(mach.Lock(exclusive=True))
+      self.assertTrue(mach.Unlock(exclusive=True))
+
   def testSharedLock(self):
     mach = lock_machine.Machine("chrotomation.mtv")
     for i in range(10):
@@ -39,6 +53,14 @@
     self.assertTrue(mach.Lock(exclusive=True))
     self.assertTrue(mach.Unlock(exclusive=True))
 
+    mach = lock_machine.Machine("chrotomation.mtv", auto=True)
+    for i in range(10):
+      self.assertTrue(mach.Lock(exclusive=False))
+    for i in range(10):
+      self.assertTrue(mach.Unlock(exclusive=False))
+    self.assertTrue(mach.Lock(exclusive=True))
+    self.assertTrue(mach.Unlock(exclusive=True))
+
   def testExclusiveLock(self):
     mach = lock_machine.Machine("atree.mtv")
     self.assertTrue(mach.Lock(exclusive=True))
@@ -47,6 +69,13 @@
       self.assertFalse(mach.Lock(exclusive=False))
     self.assertTrue(mach.Unlock(exclusive=True))
 
+    mach = lock_machine.Machine("atree.mtv", auto=True)
+    self.assertTrue(mach.Lock(exclusive=True))
+    for i in range(10):
+      self.assertFalse(mach.Lock(exclusive=True))
+      self.assertFalse(mach.Lock(exclusive=False))
+    self.assertTrue(mach.Unlock(exclusive=True))
+
   def testExclusiveState(self):
     mach = lock_machine.Machine("testExclusiveState")
     self.assertTrue(mach.Lock(exclusive=True))
@@ -54,5 +83,29 @@
       self.assertFalse(mach.Lock(exclusive=False))
     self.assertTrue(mach.Unlock(exclusive=True))
 
+    mach = lock_machine.Machine("testExclusiveState", auto=True)
+    self.assertTrue(mach.Lock(exclusive=True))
+    for i in range(10):
+      self.assertFalse(mach.Lock(exclusive=False))
+    self.assertTrue(mach.Unlock(exclusive=True))
+
+  def testAutoLockGone(self):
+    mach = lock_machine.Machine("lockgone", auto=True)
+    p = Process(target=LockAndSleep, args=("lockgone",))
+    p.start()
+    time.sleep(1.1)
+    p.join()
+    self.assertTrue(mach.Lock(exclusive=True))
+
+  def testAutoLockFromOther(self):
+    mach = lock_machine.Machine("other_lock", auto=True)
+    p = Process(target=LockAndSleep, args=("other_lock",))
+    p.start()
+    time.sleep(0.5)
+    self.assertFalse(mach.Lock(exclusive=True))
+    p.join()
+    time.sleep(0.6)
+    self.assertTrue(mach.Lock(exclusive=True))
+
 if __name__ == "__main__":
   unittest.main()