From 1a6f5d0e5fb2d179e976f629a5426ae1d474b159 Mon Sep 17 00:00:00 2001 From: Tobias Urdin Date: Thu, 14 Oct 2021 13:27:20 +0000 Subject: [PATCH] Added sorting and marker for pagination of actions This solves the sorting and marker for pagination when listing actions. Change-Id: I9bb15642585af22ad354dd4f8f2253a47129639e --- mistral/api/controllers/v2/action.py | 37 ++++++++++--- mistral/tests/unit/api/v2/test_actions.py | 55 +++++++++++++++++++ ...n-api-sorting-marker-fcc3e20038e0b7ae.yaml | 8 +++ 3 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 releasenotes/notes/v2-action-api-sorting-marker-fcc3e20038e0b7ae.yaml diff --git a/mistral/api/controllers/v2/action.py b/mistral/api/controllers/v2/action.py index 644e8fd5b..11d79aede 100644 --- a/mistral/api/controllers/v2/action.py +++ b/mistral/api/controllers/v2/action.py @@ -228,7 +228,7 @@ class ActionsController(rest.RestController, hooks.HookController): _delete_action_definition() @rest_utils.wrap_wsme_controller_exception - @wsme_pecan.wsexpose(resources.Actions, types.uuid, int, types.uniquelist, + @wsme_pecan.wsexpose(resources.Actions, wtypes.text, int, types.uniquelist, types.list, types.uniquelist, wtypes.text, wtypes.text, resources.SCOPE_TYPES, wtypes.text, wtypes.text, wtypes.text, wtypes.text, @@ -327,17 +327,36 @@ class ActionsController(rest.RestController, hooks.HookController): ) # Apply sorting. - def compare_(a_d1, a_d2): - # TODO(rakhmerov): Implement properly - return 0 + def action_descriptor_sort(a_ds, keys, dirs): + def compare_(a_d1, a_d2): + for key, dir in zip(keys, dirs): + a_d1 = getattr(a_d1, key, a_d1.name) + a_d2 = getattr(a_d2, key, a_d2.name) - action_descriptors = sorted( - action_descriptors, - key=functools.cmp_to_key(compare_) - ) + if a_d1 is None and a_d2 is None: + ret = 0 + elif a_d1 is None and a_d2 is not None: + ret = -1 + elif a_d1 is not None and a_d2 is None: + ret = 1 + else: + ret = (a_d1 > a_d2) - (a_d1 < a_d2) + if ret: + return ret * (1 if dir == 'asc' else -1) + return 0 + return sorted(a_ds, key=functools.cmp_to_key(compare_)) + + action_descriptors = action_descriptor_sort(action_descriptors, + sort_keys, sort_dirs) + start = 0 + for i, a_d in enumerate(action_descriptors): + if a_d.name == marker: + start = i + break if limit and limit > 0: - action_descriptors = action_descriptors[0:limit] + end = start + limit + action_descriptors = action_descriptors[start:end] action_resources = [ _action_descriptor_to_resource(a_d) diff --git a/mistral/tests/unit/api/v2/test_actions.py b/mistral/tests/unit/api/v2/test_actions.py index d124a25ad..b2df98b50 100644 --- a/mistral/tests/unit/api/v2/test_actions.py +++ b/mistral/tests/unit/api/v2/test_actions.py @@ -28,6 +28,36 @@ from mistral_lib.actions.providers import composite from mistral_lib import utils +ADHOC_ACTION_YAML_A = """ +--- +version: '2.0' + +a_action: + description: My super cool action. + tags: ['test', 'v2'] + base: std.echo + base-input: + output: "{$.str1}{$.str2}" + input: + - str1 + - str2 +""" + +ADHOC_ACTION_YAML_B = """ +--- +version: '2.0' + +b_action: + description: My super cool action. + tags: ['test', 'v2'] + base: std.echo + base-input: + output: "{$.str1}{$.str2}" + input: + - str1 + - str2 +""" + ADHOC_ACTION_YAML = """ --- version: '2.0' @@ -324,6 +354,8 @@ class TestActionsController(base.APITest): def test_get_all(self): # Create an adhoc action for the purpose of the test. + adhoc_actions.create_actions(ADHOC_ACTION_YAML_B) + adhoc_actions.create_actions(ADHOC_ACTION_YAML_A) adhoc_actions.create_actions(ADHOC_ACTION_YAML) resp = self.app.get('/v2/actions') @@ -332,6 +364,11 @@ class TestActionsController(base.APITest): actions_json = resp.json['actions'] + # Verify they are sorted alphabetically + self.assertEqual(actions_json[0]['name'], 'a_action') + self.assertEqual(actions_json[1]['name'], 'b_action') + self.assertEqual(actions_json[2]['name'], 'my_action') + # There will be 'std.' actions and the one we've just created. self.assertGreater(len(actions_json), 1) @@ -443,6 +480,24 @@ class TestActionsController(base.APITest): set(expected_dict.items()).issubset(set(param_dict.items())) ) + def test_get_all_pagination_marker(self): + adhoc_actions.create_actions(ADHOC_ACTION_YAML_B) + adhoc_actions.create_actions(ADHOC_ACTION_YAML_A) + adhoc_actions.create_actions(ADHOC_ACTION_YAML) + + resp = self.app.get('/v2/actions?limit=1') + + self.assertEqual(200, resp.status_int) + self.assertEqual(1, len(resp.json['actions'])) + self.assertEqual(resp.json['actions'][0]['name'], 'a_action') + + resp = self.app.get('/v2/actions?marker=my_action&limit=2') + + self.assertEqual(200, resp.status_int) + self.assertEqual(2, len(resp.json['actions'])) + self.assertEqual(resp.json['actions'][0]['name'], 'my_action') + self.assertEqual(resp.json['actions'][1]['name'], 'std.async_noop') + def test_get_all_pagination_limit_negative(self): resp = self.app.get( '/v2/actions?limit=-1&sort_keys=id,name&sort_dirs=asc,asc', diff --git a/releasenotes/notes/v2-action-api-sorting-marker-fcc3e20038e0b7ae.yaml b/releasenotes/notes/v2-action-api-sorting-marker-fcc3e20038e0b7ae.yaml new file mode 100644 index 000000000..33d84bce6 --- /dev/null +++ b/releasenotes/notes/v2-action-api-sorting-marker-fcc3e20038e0b7ae.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + The ``/v2/actions`` endpoint now alphabetically sorts the results by default + and also supports the ``sort_keys`` query parameter to sort actions. + - | + The ``/v2/actions`` endpoint now supports the ``marker`` query parameter + which can be used to set the start position of the pagination.