Browse Source

Update unit tests, covering pagination

Lucian Petrut 1 week ago
parent
commit
fdc023e111

+ 10 - 10
coriolis/api/common.py

@@ -13,8 +13,8 @@ def get_paging_params(req):
 
 
 def get_sort_params(req,
-                    default_key='created_at',
-                    default_dir='desc'):
+                    default_keys=('created_at', 'id'),
+                    default_dirs=('desc', 'desc')):
     """Retrieves sort keys/directions parameters.
 
     Processes the parameters to create a list of sort keys and sort directions
@@ -25,10 +25,10 @@ def get_sort_params(req,
     The input parameters are not modified.
 
     :param req: coriolis.api.wsgi.Request object
-    :param default_key: default sort key value, added to the list if no
-                        'sort_key' parameters are supplied
-    :param default_dir: default sort dir value, added to the list if no
-                        'sort_dir' parameters are supplied
+    :param default_keys: default sort key values, added to the list if no
+                         'sort_key' parameters are supplied
+    :param default_dirs: default sort dir values, added to the list if no
+                         'sort_dir' parameters are supplied
     :returns: list of sort keys, list of sort dirs
     """
     params = req.params.copy()
@@ -38,8 +38,8 @@ def get_sort_params(req,
         sort_keys.append(params.pop('sort_key').strip())
     while 'sort_dir' in params:
         sort_dirs.append(params.pop('sort_dir').strip())
-    if len(sort_keys) == 0 and default_key:
-        sort_keys.append(default_key)
-    if len(sort_dirs) == 0 and default_dir:
-        sort_dirs.append(default_dir)
+    if len(sort_keys) == 0 and default_keys:
+        sort_keys.extend(default_keys)
+    if len(sort_dirs) == 0 and default_dirs:
+        sort_dirs.extend(default_dirs)
     return sort_keys, sort_dirs

+ 43 - 0
coriolis/tests/api/test_common.py

@@ -0,0 +1,43 @@
+# Copyright 2026 Cloudbase Solutions Srl
+# All Rights Reserved.
+
+import webob
+
+from coriolis.api import common
+from coriolis.tests import test_base
+
+
+class ApiCommonTestCase(test_base.CoriolisBaseTestCase):
+    def test_get_paging_params(self):
+        req = webob.Request.blank('/some-path?marker=fake-marker&limit=10')
+
+        marker, limit = common.get_paging_params(req)
+
+        self.assertEqual("fake-marker", marker)
+        self.assertEqual(10, limit)
+
+    def test_get_paging_params_unspecified(self):
+        req = webob.Request.blank('/some-path')
+
+        marker, limit = common.get_paging_params(req)
+
+        self.assertIsNone(marker)
+        self.assertIsNone(limit)
+
+    def test_get_sort_params(self):
+        req = webob.Request.blank(
+            '/some-path?'
+            'sort_key=key0&sort_dir=dir0&sort_key=key1&sort_dir=dir1')
+
+        sort_keys, sort_dirs = common.get_sort_params(req)
+
+        self.assertEqual(["key0", "key1"], sort_keys)
+        self.assertEqual(["dir0", "dir1"], sort_dirs)
+
+    def test_get_sort_params_unspecified(self):
+        req = webob.Request.blank('/some-path?')
+
+        sort_keys, sort_dirs = common.get_sort_params(req)
+
+        self.assertEqual(["created_at", "id"], sort_keys)
+        self.assertEqual(["desc", "desc"], sort_dirs)

+ 18 - 2
coriolis/tests/api/v1/test_transfer_tasks_executions.py

@@ -73,17 +73,28 @@ class TransferTasksExecutionControllerTestCase(test_base.CoriolisBaseTestCase):
             mock_context, transfer_id, id)
         mock_single.assert_not_called()
 
+    @mock.patch("coriolis.api.common.get_paging_params")
+    @mock.patch("coriolis.api.common.get_sort_params")
     @mock.patch.object(transfer_tasks_execution_view, 'collection')
     @mock.patch.object(api.API, 'get_executions')
     def test_index(
         self,
         mock_get_executions,
-        mock_collection
+        mock_collection,
+        mock_get_sort_params,
+        mock_get_paging_params,
     ):
         mock_req = mock.Mock()
         mock_context = mock.Mock()
         mock_req.environ = {'coriolis.context': mock_context}
         transfer_id = mock.sentinel.transfer_id
+        mock_get_sort_params.return_value = (
+            mock.sentinel.sort_keys,
+            mock.sentinel.sort_dirs)
+        mock_get_paging_params.return_value = (
+            mock.sentinel.marker,
+            mock.sentinel.limit,
+        )
 
         result = self.transfer_api.index(mock_req, transfer_id)
 
@@ -95,7 +106,12 @@ class TransferTasksExecutionControllerTestCase(test_base.CoriolisBaseTestCase):
         mock_context.can.assert_called_once_with(
             "migration:transfer_executions:list")
         mock_get_executions.assert_called_once_with(
-            mock_context, transfer_id, include_tasks=False)
+            mock_context, transfer_id, include_tasks=False,
+            marker=mock.sentinel.marker,
+            limit=mock.sentinel.limit,
+            sort_keys=mock.sentinel.sort_keys,
+            sort_dirs=mock.sentinel.sort_dirs,
+        )
         mock_collection.assert_called_once_with(
             mock_get_executions.return_value)
 

+ 16 - 1
coriolis/tests/api/v1/test_transfers.py

@@ -84,6 +84,8 @@ class TransferControllerTestCase(test_base.CoriolisBaseTestCase):
             include_task_info=mock_get_bool_url_arg.return_value)
         mock_single.assert_not_called()
 
+    @mock.patch("coriolis.api.common.get_paging_params")
+    @mock.patch("coriolis.api.common.get_sort_params")
     @mock.patch.object(transfer_view, 'collection')
     @mock.patch.object(api.API, 'get_transfers')
     @mock.patch.object(api_utils, 'get_bool_url_arg')
@@ -92,10 +94,19 @@ class TransferControllerTestCase(test_base.CoriolisBaseTestCase):
         mock_get_bool_url_arg,
         mock_get_transfers,
         mock_collection,
+        mock_get_sort_params,
+        mock_get_paging_params,
     ):
         mock_req = mock.Mock()
         mock_context = mock.Mock()
         mock_req.environ = {'coriolis.context': mock_context}
+        mock_get_sort_params.return_value = (
+            mock.sentinel.sort_keys,
+            mock.sentinel.sort_dirs)
+        mock_get_paging_params.return_value = (
+            mock.sentinel.marker,
+            mock.sentinel.limit,
+        )
 
         mock_get_bool_url_arg.side_effect = [False, False]
 
@@ -116,7 +127,11 @@ class TransferControllerTestCase(test_base.CoriolisBaseTestCase):
         mock_get_transfers.assert_called_once_with(
             mock_context,
             include_tasks_executions=False,
-            include_task_info=False
+            include_task_info=False,
+            marker=mock.sentinel.marker,
+            limit=mock.sentinel.limit,
+            sort_keys=mock.sentinel.sort_keys,
+            sort_dirs=mock.sentinel.sort_dirs,
         )
         mock_collection.assert_called_once_with(
             mock_get_transfers.return_value)

+ 7 - 1
coriolis/tests/conductor/rpc/test_client.py

@@ -37,6 +37,10 @@ class ConductorClientTestCase(test_base.CoriolisRPCClientTestCase):
         super(ConductorClientTestCase, self).setUp()
         self.client = client.ConductorClient()
 
+        self._mock_pagination_args = dict(
+            marker="mock_marker", limit=5,
+            sort_keys=["mock_column"], sort_dirs=["desc"])
+
     def test_create_endpoint(self):
         args = {
             "name": "mock_name",
@@ -161,7 +165,8 @@ class ConductorClientTestCase(test_base.CoriolisRPCClientTestCase):
     def test_get_transfer_tasks_executions(self):
         args = {
             "transfer_id": "mock_transfer_id",
-            "include_tasks": False
+            "include_tasks": False,
+            **self._mock_pagination_args,
         }
         self._test(self.client.get_transfer_tasks_executions, args)
 
@@ -205,6 +210,7 @@ class ConductorClientTestCase(test_base.CoriolisRPCClientTestCase):
         args = {
             "include_tasks_executions": False,
             "include_task_info": False,
+            **self._mock_pagination_args,
         }
         self._test(self.client.get_transfers, args)
 

+ 11 - 4
coriolis/tests/conductor/rpc/test_server.py

@@ -37,6 +37,9 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
         self.server = server.ConductorServerEndpoint()
         self._licensing_client = mock.Mock()
         self.server._licensing_client = self._licensing_client
+        self._mock_pagination_args = dict(
+            marker="mock_marker", limit=5,
+            sort_keys=["mock_column"], sort_dirs=["desc"])
 
     @mock.patch.object(
         rpc_worker_client.WorkerClient, "from_service_definition"
@@ -1447,7 +1450,8 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             mock.sentinel.context,
             mock.sentinel.transfer_id,
             mock.sentinel.execution_id,
-            include_task_info=False
+            include_task_info=False,
+            **self._mock_pagination_args,
         )
 
         self.assertEqual(
@@ -1459,7 +1463,8 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             mock.sentinel.transfer_id,
             mock.sentinel.execution_id,
             include_task_info=False,
-            to_dict=True
+            **self._mock_pagination_args,
+            to_dict=True,
         )
 
     @mock.patch.object(db_api, "get_transfer_tasks_execution")
@@ -1675,7 +1680,8 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
         result = self.server.get_transfers(
             mock.sentinel.context,
             include_tasks_executions=False,
-            include_task_info=False
+            include_task_info=False,
+            **self._mock_pagination_args,
         )
 
         self.assertEqual(
@@ -1686,7 +1692,8 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             mock.sentinel.context,
             include_tasks_executions=False,
             include_task_info=False,
-            to_dict=True
+            to_dict=True,
+            **self._mock_pagination_args,
         )
 
     @mock.patch.object(server.ConductorServerEndpoint, '_get_transfer')

+ 68 - 0
coriolis/tests/db/test_api.py

@@ -326,6 +326,74 @@ class DBAPITestCase(BaseDBAPITestCase):
         self.assertEqual(result.id, valid_endpoint.id)
         self.assertIsNotNone(result.deleted_at)
 
+class DBAPISortParamsTestCase(BaseDBAPITestCase):
+    def test_invalid_sort_dirs(self):
+        self.assertRaises(
+            exception.InvalidInput,
+            api.process_sort_params,
+            sort_keys=["created_at", "id"],
+            sort_dirs=["asc", "descending"],
+        )
+
+    def test_too_many_sort_dirs(self):
+        self.assertRaises(
+            exception.InvalidInput,
+            api.process_sort_params,
+            sort_keys=["id"],
+            sort_dirs=["asc", "asc"],
+        )
+
+    def test_unmodified_input(self):
+        sort_keys = ["created_at", "id"]
+        sort_dirs = ["desc", "desc"]
+
+        ret_keys, ret_dirs = api.process_sort_params(
+            sort_keys, sort_dirs)
+
+        self.assertEqual(sort_keys, ret_keys)
+        self.assertEqual(sort_dirs, ret_dirs)
+
+    def test_unmatched_input(self):
+        sort_keys = ["created_at", "id"]
+        sort_dirs = ["asc"]
+        exp_dirs = ["asc", "asc"]
+
+        ret_keys, ret_dirs = api.process_sort_params(
+            sort_keys, sort_dirs)
+
+        self.assertEqual(sort_keys, ret_keys)
+        self.assertEqual(exp_dirs, ret_dirs)
+
+    def test_default_keys_appended(self):
+        sort_keys = ["created_at"]
+        sort_dirs = ["asc"]
+        exp_sort_keys = ["created_at", "id"]
+        exp_dirs = ["asc", "asc"]
+
+        ret_keys, ret_dirs = api.process_sort_params(
+            sort_keys, sort_dirs,
+            default_keys=["id"],
+            default_dir="asc",
+        )
+
+        self.assertEqual(exp_sort_keys, ret_keys)
+        self.assertEqual(exp_dirs, ret_dirs)
+
+    def test_default_keys_without_input(self):
+        sort_keys = None
+        sort_dirs = None
+        exp_sort_keys = ["id"]
+        exp_dirs = ["asc"]
+
+        ret_keys, ret_dirs = api.process_sort_params(
+            sort_keys, sort_dirs,
+            default_keys=["id"],
+            default_dir="asc",
+        )
+
+        self.assertEqual(exp_sort_keys, ret_keys)
+        self.assertEqual(exp_dirs, ret_dirs)
+
 
 class EndpointDBAPITestCase(BaseDBAPITestCase):
 

+ 15 - 5
coriolis/tests/transfer_tasks_executions/test_api.py

@@ -48,13 +48,23 @@ class APITestCase(test_base.CoriolisBaseTestCase):
                 self.ctxt, self.transfer_id, self.execution_id, force))
 
     def test_get_executions(self):
-        include_tasks = mock.sentinel.include_tasks
-
-        result = self.api.get_executions(self.ctxt, self.transfer_id,
-                                         include_tasks)
+        result = self.api.get_executions(
+            self.ctxt, self.transfer_id,
+            mock.sentinel.include_tasks,
+            mock.sentinel.marker,
+            mock.sentinel.limit,
+            mock.sentinel.sort_keys,
+            mock.sentinel.sort_dirs,
+        )
 
         self.rpc_client.get_transfer_tasks_executions.assert_called_once_with(
-            self.ctxt, self.transfer_id, include_tasks)
+            self.ctxt, self.transfer_id,
+            mock.sentinel.include_tasks,
+            mock.sentinel.marker,
+            mock.sentinel.limit,
+            mock.sentinel.sort_keys,
+            mock.sentinel.sort_dirs,
+        )
         self.assertEqual(
             result, self.rpc_client.get_transfer_tasks_executions.return_value)
 

+ 9 - 2
coriolis/tests/transfers/test_api.py

@@ -17,6 +17,9 @@ class APITestCase(test_base.CoriolisBaseTestCase):
         self.api._rpc_client = self.rpc_client
         self.ctxt = mock.sentinel.ctxt
         self.transfer_id = mock.sentinel.transfer_id
+        self._mock_pagination_args = dict(
+            marker="mock_marker", limit=5,
+            sort_keys=["mock_column"], sort_dirs=["desc"])
 
     def test_create(self):
         origin_endpoint_id = mock.sentinel.origin_endpoint_id
@@ -66,10 +69,14 @@ class APITestCase(test_base.CoriolisBaseTestCase):
 
     def test_get_transfers(self):
         result = self.api.get_transfers(
-            self.ctxt, include_tasks_executions=False, include_task_info=False)
+            self.ctxt, include_tasks_executions=False, include_task_info=False,
+            **self._mock_pagination_args,
+        )
 
         self.rpc_client.get_transfers.assert_called_once_with(
-            self.ctxt, False, include_task_info=False)
+            self.ctxt, False, include_task_info=False,
+            **self._mock_pagination_args,
+        )
         self.assertEqual(result, self.rpc_client.get_transfers.return_value)
 
     def test_get_transfer(self):