Просмотр исходного кода

integration: Various test fixes and cleanup

- Refactor Importer / Exporter class references. They are now referenced
  through the harness. This will allow them to be swapped in the future.
- Refactor Importer / Exporter connection info.
- Correctly skip Import provider that does not support minion pools.
  This needs to be done earlier, so the minion pool isn't created on a
  provider that do not support them.
- raise AssertionError instead of using cls.fail.
Claudiu Belu 3 недель назад
Родитель
Сommit
47eb5f71f7

+ 21 - 15
coriolis/tests/integration/base.py

@@ -29,6 +29,7 @@ import oslo_messaging as messaging
 from coriolis import constants
 from coriolis import constants
 from coriolis import context
 from coriolis import context
 from coriolis.db import api as db_api
 from coriolis.db import api as db_api
+from coriolis import exception
 from coriolis.providers import factory as providers_factory
 from coriolis.providers import factory as providers_factory
 from coriolis.tests.integration import harness
 from coriolis.tests.integration import harness
 from coriolis.tests.integration import utils as test_utils
 from coriolis.tests.integration import utils as test_utils
@@ -64,7 +65,11 @@ class CoriolisIntegrationTestBase(test_base.CoriolisBaseTestCase):
         cls._lock_path = cls._harness.lock_path
         cls._lock_path = cls._harness.lock_path
         cls._api_port = cls._harness.api_port
         cls._api_port = cls._harness.api_port
         cls._exp_platform = cls._harness.exp_provider_platform
         cls._exp_platform = cls._harness.exp_provider_platform
+        cls._exp_conn_info = cls._harness.exp_conn_info
+
         cls._imp_platform = cls._harness.imp_provider_platform
         cls._imp_platform = cls._harness.imp_provider_platform
+        cls._imp_conn_info = cls._harness.imp_conn_info
+
         cls._client = cls.get_client()
         cls._client = cls.get_client()
 
 
     def setUp(self):
     def setUp(self):
@@ -202,7 +207,7 @@ class CoriolisIntegrationTestBase(test_base.CoriolisBaseTestCase):
             time.sleep(1)
             time.sleep(1)
         pool = db_api.get_minion_pool(ctxt, pool_id)
         pool = db_api.get_minion_pool(ctxt, pool_id)
         last = pool.status if pool else "not found"
         last = pool.status if pool else "not found"
-        cls.fail(
+        raise AssertionError(
             "Pool %s did not reach one of %r within %ds (last: %s)"
             "Pool %s did not reach one of %r within %ds (last: %s)"
             % (pool_id, terminal_statuses, timeout, last)
             % (pool_id, terminal_statuses, timeout, last)
         )
         )
@@ -252,20 +257,14 @@ class ReplicaIntegrationTestBase(CoriolisIntegrationTestBase):
             name="test-src",
             name="test-src",
             endpoint_type=cls._exp_platform,
             endpoint_type=cls._exp_platform,
             description="integration source endpoint",
             description="integration source endpoint",
-            connection_info={
-                "pkey_path": cls._harness.ssh_key_path,
-                "role": "source",
-            },
+            connection_info=cls._exp_conn_info,
         )
         )
 
 
         cls._dst_endpoint = cls._create_endpoint(
         cls._dst_endpoint = cls._create_endpoint(
             name="test-dest",
             name="test-dest",
             endpoint_type=cls._imp_platform,
             endpoint_type=cls._imp_platform,
             description="integration destination endpoint",
             description="integration destination endpoint",
-            connection_info={
-                "pkey_path": cls._harness.ssh_key_path,
-                "role": "destination",
-            },
+            connection_info=cls._imp_conn_info,
         )
         )
 
 
         # Create minion pool if needed.
         # Create minion pool if needed.
@@ -277,7 +276,7 @@ class ReplicaIntegrationTestBase(CoriolisIntegrationTestBase):
 
 
             pool_obj = cls._wait_for_pool(pool.id, MINION_ALLOCATED_TERMINAL)
             pool_obj = cls._wait_for_pool(pool.id, MINION_ALLOCATED_TERMINAL)
             if pool_obj.status != constants.MINION_POOL_STATUS_ALLOCATED:
             if pool_obj.status != constants.MINION_POOL_STATUS_ALLOCATED:
-                cls.fail(
+                raise AssertionError(
                     "Pool did not reach ALLOCATED (got %s)" % pool_obj.status,
                     "Pool did not reach ALLOCATED (got %s)" % pool_obj.status,
                 )
                 )
 
 
@@ -300,10 +299,13 @@ class ReplicaIntegrationTestBase(CoriolisIntegrationTestBase):
         test_utils.write_test_pattern(self._src_device, 8192)
         test_utils.write_test_pattern(self._src_device, 8192)
 
 
         # Create transfer replica.
         # Create transfer replica.
+        # Use basename as instance name; real VM names do not contain slashes,
+        # and some providers use the name as is in resource indentifiers.
+        instance_name = os.path.basename(self._src_device)
         self._transfer = self._create_transfer(
         self._transfer = self._create_transfer(
             self._src_endpoint.id,
             self._src_endpoint.id,
             self._dst_endpoint.id,
             self._dst_endpoint.id,
-            instances=[self._src_device],
+            instances=[instance_name],
             destination_minion_pool_id=self._pool_id,
             destination_minion_pool_id=self._pool_id,
             source_environment={"block_device_path": self._src_device},
             source_environment={"block_device_path": self._src_device},
             destination_environment={"devices": [self._dst_device]},
             destination_environment={"devices": [self._dst_device]},
@@ -498,16 +500,20 @@ class MinionPoolTestBase(CoriolisIntegrationTestBase):
 
 
     @classmethod
     @classmethod
     def setUpClass(cls):
     def setUpClass(cls):
-        super().setUpClass()
-
+        # Check before super(), so that ReplicaIntegrationTestBase.setUpClass
+        # does not attempt pool creation against a provider that doesn't
+        # support it.
+        h = harness._IntegrationHarness.get()
         available = providers_factory.get_available_providers()
         available = providers_factory.get_available_providers()
-        imp_types = available.get(cls._imp_platform, {}).get("types", [])
+        imp_types = available.get(h.imp_provider_platform, {}).get("types", [])
         if constants.PROVIDER_TYPE_DESTINATION_MINION_POOL not in imp_types:
         if constants.PROVIDER_TYPE_DESTINATION_MINION_POOL not in imp_types:
             raise unittest.SkipTest(
             raise unittest.SkipTest(
                 "Import provider '%s' does not support minion pools"
                 "Import provider '%s' does not support minion pools"
-                % cls._imp_platform
+                % h.imp_provider_platform
             )
             )
 
 
+        super().setUpClass()
+
 
 
 class MinionPoolReplicaTestBase(
 class MinionPoolReplicaTestBase(
         MinionPoolTestBase, ReplicaIntegrationTestBase):
         MinionPoolTestBase, ReplicaIntegrationTestBase):

+ 16 - 5
coriolis/tests/integration/harness.py

@@ -76,11 +76,11 @@ _TEST_IMPORT_PROVIDER = (
 _TEST_PROJECT_ID = 'integration-project'
 _TEST_PROJECT_ID = 'integration-project'
 
 
 
 
-def _provider_platform(dotted_path):
-    """Return the ``platform`` attribute of the class at *dotted_path*."""
+def _get_provider(dotted_path):
+    """Return the class at the *dotted_path*."""
     module_path, class_name = dotted_path.rsplit('.', 1)
     module_path, class_name = dotted_path.rsplit('.', 1)
     cls = getattr(importlib.import_module(module_path), class_name)
     cls = getattr(importlib.import_module(module_path), class_name)
-    return cls.platform
+    return cls
 
 
 
 
 class DaemonCherootWorker(cheroot_threadpool.WorkerThread):
 class DaemonCherootWorker(cheroot_threadpool.WorkerThread):
@@ -302,8 +302,19 @@ class _IntegrationHarness:
         # Policy enforcer: reset so it re-reads the new CONF (no policy file).
         # Policy enforcer: reset so it re-reads the new CONF (no policy file).
         policy_module.reset()
         policy_module.reset()
 
 
-        self.exp_provider_platform = _provider_platform(_TEST_EXPORT_PROVIDER)
-        self.imp_provider_platform = _provider_platform(_TEST_IMPORT_PROVIDER)
+        self.exp_provider_class = _get_provider(_TEST_EXPORT_PROVIDER)
+        self.exp_provider_platform = self.exp_provider_class.platform
+        self.exp_conn_info = {
+            "pkey_path": self.ssh_key_path,
+            "role": "source",
+        }
+
+        self.imp_provider_class = _get_provider(_TEST_IMPORT_PROVIDER)
+        self.imp_provider_platform = self.imp_provider_class.platform
+        self.imp_conn_info = {
+            "pkey_path": self.ssh_key_path,
+            "role": "destination",
+        }
 
 
         self._wsgi_server = None
         self._wsgi_server = None
         self._wsgi_server_thread = None
         self._wsgi_server_thread = None

+ 2 - 6
coriolis/tests/integration/test_endpoints.py

@@ -23,16 +23,12 @@ class EndpointCapabilitiesTest(base.CoriolisIntegrationTestBase):
         self._src_endpoint = self._create_endpoint(
         self._src_endpoint = self._create_endpoint(
             name="cap-src",
             name="cap-src",
             endpoint_type=self._exp_platform,
             endpoint_type=self._exp_platform,
-            connection_info={
-                "pkey_path": self._harness.ssh_key_path,
-            },
+            connection_info=self._exp_conn_info,
         )
         )
         self._dst_endpoint = self._create_endpoint(
         self._dst_endpoint = self._create_endpoint(
             name="cap-dest",
             name="cap-dest",
             endpoint_type=self._imp_platform,
             endpoint_type=self._imp_platform,
-            connection_info={
-                "pkey_path": self._harness.ssh_key_path,
-            },
+            connection_info=self._imp_conn_info,
         )
         )
 
 
     def test_validate_connection(self):
     def test_validate_connection(self):

+ 3 - 4
coriolis/tests/integration/test_failure_recovery.py

@@ -4,8 +4,8 @@
 """
 """
 Integration test for failure handling and cleanup.
 Integration test for failure handling and cleanup.
 
 
-Patches TestImportProvider.deploy_replica_target_resources to raise an
-exception, triggers a transfer execution, and asserts that:
+Patches the active import provider's deploy_replica_target_resources to raise
+an exception, triggers a transfer execution, and asserts that:
   1. The execution reaches ERROR status.
   1. The execution reaches ERROR status.
   2. Cleanup tasks (delete_replica_source_resources) ran so the replicator
   2. Cleanup tasks (delete_replica_source_resources) ran so the replicator
      process is no longer alive.
      process is no longer alive.
@@ -16,7 +16,6 @@ Must be run as root; requires the scsi_debug kernel module.
 from unittest import mock
 from unittest import mock
 
 
 from coriolis.tests.integration import base
 from coriolis.tests.integration import base
-from coriolis.tests.integration.test_provider import imp
 
 
 
 
 class TransferFailureIntegrationTest(base.ReplicaIntegrationTestBase):
 class TransferFailureIntegrationTest(base.ReplicaIntegrationTestBase):
@@ -27,7 +26,7 @@ class TransferFailureIntegrationTest(base.ReplicaIntegrationTestBase):
         injected_error = Exception("injected target resource failure")
         injected_error = Exception("injected target resource failure")
 
 
         with mock.patch.object(
         with mock.patch.object(
-            imp.TestImportProvider,
+            self._harness.imp_provider_class,
             "deploy_replica_target_resources",
             "deploy_replica_target_resources",
             side_effect=injected_error,
             side_effect=injected_error,
         ):
         ):

+ 0 - 1
coriolis/tests/integration/test_smoke.py

@@ -51,7 +51,6 @@ class HarnessSmokeTest(base.CoriolisIntegrationTestBase):
         instances = ["smoke-instance"]
         instances = ["smoke-instance"]
         transfer = self._create_transfer(
         transfer = self._create_transfer(
             src.id, dst.id, instances=instances,
             src.id, dst.id, instances=instances,
-            destination_environment={"devices": ["foo"]},
         )
         )
 
 
         self.assertEqual(src.id, transfer.origin_endpoint_id)
         self.assertEqual(src.id, transfer.origin_endpoint_id)

+ 1 - 2
coriolis/tests/integration/transfers/test_executions.py

@@ -7,7 +7,6 @@ Integration tests for the transfer executions.
 
 
 from coriolis import constants
 from coriolis import constants
 from coriolis.tests.integration import base
 from coriolis.tests.integration import base
-from coriolis.tests.integration.test_provider import imp
 
 
 
 
 class TransferExecutionsTests(base.ReplicaIntegrationTestBase):
 class TransferExecutionsTests(base.ReplicaIntegrationTestBase):
@@ -93,7 +92,7 @@ class TransferExecutionsTests(base.ReplicaIntegrationTestBase):
         """
         """
         # Artificially bump the execution time of a transfer.
         # Artificially bump the execution time of a transfer.
         self._patch_add_delay(
         self._patch_add_delay(
-            imp.TestImportProvider,
+            self._harness.imp_provider_class,
             "deploy_replica_target_resources",
             "deploy_replica_target_resources",
         )
         )