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

tests: Add integration tests for endpoint minion pool options and inventory

Adds test for endpoint_destination_minion_pool_options index route and
endpoint_inventory CSV route.

Implement BaseEndpointInventoryExportProvider for TestExportProvider, so
the scheduler can find a worker advertising PROVIDER_TYPE_ENDPOINT_INVENTORY_EXPORT,
making the endpoint_inventory.py index route testable.

Fixes serializer mismatch in wsgi.py for Fault / OverLimitFault,
avoiding a potential KeyError if the requested content type is not
"application/json" (e.g.: endpoint_inventory CSV endpoint requests the
"text/csv" content type). Error responses are always JSON.
Claudiu Belu 1 месяц назад
Родитель
Сommit
1ab303a58c

+ 7 - 8
coriolis/api/wsgi.py

@@ -1241,10 +1241,10 @@ class Fault(webob.exc.HTTPException):
             if retry:
                 fault_data[fault_name]['retryAfter'] = retry
 
-        content_type = req.best_match_content_type()
-        serializer = {
-            'application/json': JSONDictSerializer(),
-        }[content_type]
+        # Error responses are always JSON, regardless of what content type the
+        # client requested (e.g.: 'text/csv' for CSV-producing endpoints).
+        content_type = 'application/json'
+        serializer = JSONDictSerializer()
 
         body = serializer.serialize(fault_data)
         if isinstance(body, six.text_type):
@@ -1313,7 +1313,6 @@ class OverLimitFault(webob.exc.HTTPException):
     @webob.dec.wsgify(RequestClass=Request)
     def __call__(self, request):
         """Serializes the wrapped exception conforming to our error format."""
-        content_type = request.best_match_content_type()
 
         def translate(msg):
             locale = request.best_match_language()
@@ -1324,9 +1323,9 @@ class OverLimitFault(webob.exc.HTTPException):
         self.content['overLimitFault']['details'] = \
             translate(self.content['overLimitFault']['details'])
 
-        serializer = {
-            'application/json': JSONDictSerializer(),
-        }[content_type]
+        # Error responses are always JSON, regardless of what content
+        # type the client requested.
+        serializer = JSONDictSerializer()
 
         content = serializer.serialize(self.content)
         self.wrapped_exc.body = content

+ 15 - 0
coriolis/tests/integration/test_endpoints.py

@@ -10,6 +10,8 @@ Exercises endpoint-related operations via the Coriolis REST API:
 - get_storage (list and default)
 - get_source_environment_options
 - get_target_environment_options
+- get_destination_minion_pool_options
+- get_inventory_csv
 - endpoint_instances.list and endpoint_instances.get
 """
 
@@ -94,6 +96,19 @@ class EndpointCapabilitiesTest(base.CoriolisIntegrationTestBase):
         self.assertTrue(
             len(options) > 0, "Expected at least one destination option")
 
+    def test_list_destination_minion_pool_options(self):
+        options = self._client.endpoint_destination_minion_pool_options.list(
+            self._dst_endpoint.id)
+        self.assertIsInstance(options, list)
+        self.assertTrue(
+            len(options) > 0,
+            "Expected at least one destination minion pool option")
+
+    def test_get_inventory_csv(self):
+        csv_content = self._client.endpoints.get_inventory_csv(
+            self._src_endpoint.id, source_environment={})
+        self.assertTrue(csv_content, "Expected non-empty inventory CSV")
+
     def test_list_instances(self):
         instances = self._client.endpoint_instances.list(
             self._src_endpoint.id, env={})

+ 27 - 0
coriolis/tests/integration/test_provider/exp.py

@@ -8,6 +8,8 @@ Uses Replicator (via SSH to a Docker data-minion container) to deploy and
 manage the coriolis-replicator service and perform disk replication.
 """
 
+import csv
+import io
 import os
 import uuid
 
@@ -18,6 +20,7 @@ import paramiko
 from coriolis import events
 from coriolis.providers import backup_writers
 from coriolis.providers.base import BaseEndpointInstancesProvider
+from coriolis.providers.base import BaseEndpointInventoryExportProvider
 from coriolis.providers.base import BaseEndpointSourceOptionsProvider
 from coriolis.providers.base import BaseReplicaExportProvider
 from coriolis.providers.base import BaseReplicaExportValidationProvider
@@ -40,6 +43,7 @@ _TEST_NIC = {
 
 class TestExportProvider(
         BaseEndpointInstancesProvider,
+        BaseEndpointInventoryExportProvider,
         BaseEndpointSourceOptionsProvider,
         BaseUpdateSourceReplicaProvider,
         BaseReplicaExportProvider,
@@ -121,6 +125,29 @@ class TestExportProvider(
                      instance_name):
         return self._instance_info(source_environment)
 
+    # BaseEndpointInventoryExportProvider
+
+    def export_instance_inventory(
+            self, ctxt, connection_info, source_environment):
+        instance = self._instance_info(source_environment)
+        output = io.StringIO()
+
+        writer = csv.writer(output)
+        writer.writerow([
+            "VM ID", "VM Name", "Guest OS", "Num CPUs", "Memory (MB)",
+            "NIC Count",
+        ])
+        writer.writerow([
+            instance["id"],
+            instance["name"],
+            instance["os_type"],
+            instance["num_cpu"],
+            instance["memory_mb"],
+            len(instance["devices"]["nics"]),
+        ])
+
+        return output.getvalue()
+
     def _instance_info(self, source_environment):
         device = source_environment.get("block_device_path", "")
         name = os.path.basename(device) if device else "test-instance"