[Checkins] SVN: gocept.zeoraid/trunk/src/gocept/zeoraid/ - Added tests for getName and getSize

Christian Theune ct at gocept.com
Thu Jan 10 07:45:25 EST 2008


Log message for revision 82778:
  - Added tests for getName and getSize
  - refactored the `self.open == True` check into a decorator
  - refactored the apply_single_storage method
  

Changed:
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
  U   gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py

-=-
Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py	2008-01-10 11:00:33 UTC (rev 82777)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/storage.py	2008-01-10 12:45:24 UTC (rev 82778)
@@ -21,6 +21,14 @@
 import gocept.zeoraid.compatibility
 
 
+def ensure_open_storage(method):
+    def check_open(self, *args, **kw):
+        if self.closed:
+            raise gocept.zeoraid.interfaces.RAIDClosedError("Storage has been closed.")
+        return method(self, *args, **kw)
+    return check_open
+
+
 class RAIDStorage(object):
     """The RAID storage is a drop-in replacement for the client storages that
     are configured.
@@ -372,10 +380,8 @@
     # IRAIDStorage
 
     # XXX
+    @ensure_open_storage
     def raid_status(self):
-        if self.closed:
-            raise gocept.zeoraid.interfaces.RAIDClosedError(
-                "Storage has been closed.")
         if self.storages_recovering:
             return 'recovering'
         if not self.storages_degraded:
@@ -385,25 +391,19 @@
         return 'degraded'
 
     # XXX
+    @ensure_open_storage
     def raid_details(self):
-        if self.closed:
-            raise gocept.zeoraid.interfaces.RAIDClosedError(
-                "Storage has been closed.")
         return [self.storages_optimal, self.storages_recovering, self.storages_degraded]
 
     # XXX
+    @ensure_open_storage
     def raid_disable(self, name):
-        if self.closed:
-            # XXX refactor into decorator
-            raise gocept.zeoraid.interfaces.RAIDClosedError(
-                "Storage has been closed.")
         self._degrade_storage(name, fail=False)
         return 'disabled %r' % name
 
     # XXX
+    @ensure_open_storage
     def raid_recover(self, name):
-        if self.closed:
-            raise gocept.zeoraid.interfaces.RAIDClosedError("Storage has been closed.")
         if name not in self.storages_degraded:
             return
         self.storages_degraded.remove(name)
@@ -431,31 +431,31 @@
         if not self.storages_optimal and fail:
             raise gocept.zeoraid.interfaces.RAIDError("No storages remain.")
 
+    @ensure_open_storage
     def _apply_single_storage(self, method_name, *args, **kw):
-        if self.closed:
-            raise gocept.zeoraid.interfaces.RAIDClosedError("Storage has been closed.")
-        storages = self.storages_optimal[:]
-        if not storages:
-            raise gocept.zeoraid.interfaces.RAIDError("RAID storage is failed.")
-
-        while storages:
+        # Try to find a storage that we can talk to. Stop after we found a reliable result.
+        for name in self.storages_optimal[:]:
             # XXX storage might be degraded by now, need to check.
-            name = self.storages_optimal[0]
             storage = self.storages[name]
+            method = getattr(storage, method_name)
             try:
-                # Make random/hashed selection of read storage
-                method = getattr(storage, method_name)
-                return method(*args, **kw)
+                result = method(*args, **kw)
             except ZEO.ClientStorage.ClientDisconnected:
                 # XXX find other possible exceptions
-                self._degrade_storage(name)
+                pass
             else:
-                if not storage.is_connected():
-                    self._degrade_storage(name)
+                if storage.is_connected():
+                    # We have a result that is reliable.
+                    return result
+            # There was no result or it is not reliable, the storage needs to
+            # be degraded and we try another storage.
+            self._degrade_storage(name)
 
+        # We could not determine a result from any storage.
+        raise gocept.zeoraid.interfaces.RAIDError("RAID storage is failed.")
+
+    @ensure_open_storage
     def _apply_all_storages(self, method_name, *args, **kw):
-        if self.closed:
-            raise gocept.zeoraid.interfaces.RAIDClosedError("Storage has been closed.")
         # kw might contain special parameters. We need to do this
         # to avoid interfering with the actual arguments that we proxy.
         expect_connected = kw.pop('_raid_expect_connected', True)

Modified: gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py
===================================================================
--- gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py	2008-01-10 11:00:33 UTC (rev 82777)
+++ gocept.zeoraid/trunk/src/gocept/zeoraid/tests/test_basics.py	2008-01-10 12:45:24 UTC (rev 82778)
@@ -99,10 +99,20 @@
             self.assert_(zope.interface.verify.verifyObject(iface,
                                                             self._storage))
 
+    def check_getname(self):
+        self.assertEquals('teststorage', self._storage.getName())
+        self._storage.close()
+        self.assertEquals('teststorage', self._storage.getName())
+
+
 class FailingStorageTestsBase(unittest.TestCase):
 
     backend_count = None
 
+    def _backend(self, index):
+        return self._storage.storages[
+            self._storage.storages_optimal[index]]
+
     def setUp(self):
         # Ensure compatibility
         gocept.zeoraid.compatibility.setup()
@@ -135,41 +145,34 @@
         # XXX wait for servers to come down
 
 
-class FailingStorageTests1Backend(FailingStorageTestsBase):
+class FailingStorageTests2Backends(FailingStorageTestsBase):
 
-    backend_count = 1
+    backend_count = 2
 
     def test_close(self):
         self._storage.close()
         self.assertEquals(self._storage.closed, True)
-
-    def test_double_close(self):
+        # Calling close() multiple times is allowed (and a no-op):
         self._storage.close()
         self.assertEquals(self._storage.closed, True)
+
+    def test_close_degrading(self):
+        # See the comment on `test_close_failing`.
+        self._storage.storages[self._storage.storages_optimal[0]].fail('close')
         self._storage.close()
-        self.assertEquals(self._storage.closed, True)
+        self.assertEquals([], self._storage.storages_degraded)
+        self.assertEquals(True, self._storage.closed)
 
     def test_close_failing(self):
         # Even though we make the server-side storage fail, we do not get
         # receive an error or a degradation because the result of the failure
         # is that the connection is closed. This is actually what we wanted.
         # Unfortunately that means that an error can be hidden while closing.
-        self._storage.storages[self._storage.storages_optimal[0]].fail('close')
+        self._backend(0).fail('close')
+        self._backend(1).fail('close')
         self._storage.close()
         self.assertEquals(True, self._storage.closed)
 
-
-class FailingStorageTests2Backends(FailingStorageTestsBase):
-
-    backend_count = 2
-
-    def test_close_degrading(self):
-        # See the comment on `test_close_failing`.
-        self._storage.storages[self._storage.storages_optimal[0]].fail('close')
-        self._storage.close()
-        self.assertEquals([], self._storage.storages_degraded)
-        self.assertEquals(True, self._storage.closed)
-
     def test_close_server_missing(self):
         # See the comment on `test_close_failing`.
         forker.shutdown_zeo_server(self._servers[0])
@@ -178,7 +181,27 @@
         self.assertEquals([], self._storage.storages_degraded)
         self.assertEquals(True, self._storage.closed)
 
+    def test_getsize(self):
+        self.assertEquals(32, self._backend(0).getSize())
+        self.assertEquals(32, self._backend(1).getSize())
+        self.assertEquals(32, self._storage.getSize())
+        self._storage.close()
+        self.assertRaises(gocept.zeoraid.interfaces.RAIDClosedError,
+                          self._storage.getSize)
 
+    def test_getsize_degrading(self):
+        self._backend(0).fail('getSize')
+        # This doesn't get noticed because ClientStorage already knows
+        # the answer and caches it. Therefore calling getSize can never
+        # degrade or fail a RAID.
+        self.assertEquals(32, self._storage.getSize())
+        self.assertEquals('optimal', self._storage.raid_status())
+
+        self._backend(1).fail('getSize')
+        self.assertEquals(32, self._storage.getSize())
+        self.assertEquals('optimal', self._storage.raid_status())
+
+
 class ZEOReplicationStorageTests(ZEOStorageBackendTests,
                                  ReplicationStorageTests,
                                  ThreadTests.ThreadTests):
@@ -188,7 +211,6 @@
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(ZEOReplicationStorageTests, "check"))
-    suite.addTest(unittest.makeSuite(FailingStorageTests1Backend))
     suite.addTest(unittest.makeSuite(FailingStorageTests2Backends))
     return suite
 



More information about the Checkins mailing list