[master 2/4] Manage backing store more independently in loop backed test cases.

mulkieran installerbot-noreply at redhat.com
Fri May 22 15:14:49 UTC 2015


From: mulhern <amulhern at redhat.com>

* Make the backing store before starting to use the loop devices so there
is less elapsed time between finding a free loop device and actually using
it. Get rid of it if there is a failure in locating a free loop device
or using it.

* Make self._loopMap a list of pairs, since we never do random access
anyway.

* Make the names of our temp files that back the loop devices less likely
to be reused by adding a random string to their names.

* Don't give up on deleting all loop devices the first time one loop
device is not succesfully removed.

* Give every loop device a minimum of three deletion attempts
before teardown gives up. This is apallingly ad-hoc, but almost works.
As many deletion attempts as needed is sometimes infinitely too many.

Signed-off-by: mulhern <amulhern at redhat.com>
---
 tests/loopbackedtestcase.py | 50 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 36 insertions(+), 14 deletions(-)

diff --git a/tests/loopbackedtestcase.py b/tests/loopbackedtestcase.py
index 9451ed1..d60ba01 100644
--- a/tests/loopbackedtestcase.py
+++ b/tests/loopbackedtestcase.py
@@ -1,13 +1,13 @@
 import unittest
 import os
+import random
 import subprocess
 
 from blivet.size import Size
 
-def makeLoopDev(device_name, file_name, num_blocks=102400, block_size=1024):
-    """ Set up a loop device with a backing store.
+def makeStore(file_name, num_blocks=102400, block_size=1024):
+    """ Set up the backing store for a loop device.
 
-        :param str device_name: the path of the loop device
         :param str file_name: the path of the backing file
         :param int num_blocks: the size of file_name in number of blocks
         :param int block_size: the number of bytes in a block
@@ -23,6 +23,13 @@ def makeLoopDev(device_name, file_name, num_blocks=102400, block_size=1024):
     if rc:
         raise OSError("dd failed creating the file %s" % file_name)
 
+def makeLoopDev(device_name, file_name):
+    """ Set up a loop device with a backing store.
+
+        :param str device_name: the path of the loop device
+        :param str file_name: the path of the backing file
+    """
+
     proc = subprocess.Popen(["losetup", device_name, file_name],
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     while True:
@@ -33,7 +40,7 @@ def makeLoopDev(device_name, file_name, num_blocks=102400, block_size=1024):
     if rc:
         raise OSError("losetup failed setting up the loop device %s" % device_name)
 
-def removeLoopDev(device_name, file_name):
+def removeLoopDev(device_name):
     proc = subprocess.Popen(["losetup", "-d", device_name],
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     while True:
@@ -44,8 +51,6 @@ def removeLoopDev(device_name, file_name):
     if rc:
         raise OSError("losetup failed removing the loop device %s" % device_name)
 
-    os.unlink(file_name)
-
 def getFreeLoopDev():
     # There's a race condition here where another process could grab the loop
     # device losetup gives us before we have time to set it up, but that's just
@@ -72,7 +77,7 @@ class LoopBackedTestCase(unittest.TestCase):
     DEFAULT_BLOCK_SIZE = Size("1 KiB")
     DEFAULT_STORE_SIZE = Size("100 MiB")
     _DEFAULT_DEVICE_SPEC = [DEFAULT_STORE_SIZE, DEFAULT_STORE_SIZE]
-    _STORE_FILE_TEMPLATE = 'test-virtdev%d'
+    _STORE_FILE_TEMPLATE = 'test-virtdev%d-%s'
     _STORE_FILE_PATH = '/var/tmp'
 
     def __init__(self, methodName='runTest', deviceSpec=None, block_size=None):
@@ -88,7 +93,7 @@ def __init__(self, methodName='runTest', deviceSpec=None, block_size=None):
         """
         unittest.TestCase.__init__(self, methodName=methodName)
         self._deviceSpec = deviceSpec or self._DEFAULT_DEVICE_SPEC
-        self._loopMap = {}
+        self._loopMap = []
         self.loopDevices = []
         self.block_size = block_size or self.DEFAULT_BLOCK_SIZE
 
@@ -96,14 +101,31 @@ def __init__(self, methodName='runTest', deviceSpec=None, block_size=None):
             raise ValueError("Every device size must be a multiple of the block size.")
 
     def setUp(self):
+        random_str = '%06x' % random.randrange(16**6)
         for index, size in enumerate(self._deviceSpec):
-            store = os.path.join(self._STORE_FILE_PATH, self._STORE_FILE_TEMPLATE % index)
-            dev = getFreeLoopDev()
+            store = os.path.join(self._STORE_FILE_PATH, self._STORE_FILE_TEMPLATE % (index, random_str))
             num_blocks = int(size / self.block_size)
-            makeLoopDev(dev, store, num_blocks=num_blocks, block_size=int(self.block_size))
-            self._loopMap[dev] = store
+            makeStore(store, num_blocks, int(self.block_size))
+
+            dev = None
+            try:
+                dev = getFreeLoopDev()
+                makeLoopDev(dev, store)
+            except OSError:
+                os.unlink(store)
+                raise
+
+            self._loopMap.append((dev, store))
             self.loopDevices.append(dev)
 
     def tearDown(self):
-        for (dev, store) in iter(self._loopMap.items()):
-            removeLoopDev(dev, store)
+        l = len(self._loopMap)
+        for _ in range(3 * l):
+            if not self._loopMap:
+                break
+            dev, store = self._loopMap.pop(0)
+            try:
+                removeLoopDev(dev)
+                os.unlink(store)
+            except OSError:
+                self._loopMap.append((dev, store))


-- 
To view this commit on github, visit https://github.com/rhinstaller/blivet/commit/7723f3ce65b5049a4b9b650f35ab83f26d629d87


More information about the anaconda-patches mailing list