Filtering support for actions

TODO: Add more tests.

Change-Id: I110c2073b82c4ffb3a1f02e152937451395a1e87
Implements: blueprint mistral-items-filtering
This commit is contained in:
hardik 2016-08-04 17:45:13 +05:30
parent 4bdda3b6ed
commit eebe77b20f
13 changed files with 510 additions and 90 deletions

View File

@ -29,6 +29,7 @@ from mistral import context
from mistral.db.v2 import api as db_api
from mistral import exceptions as exc
from mistral.services import actions
from mistral.utils import filter_utils
from mistral.utils import rest_utils
from mistral.workbook import parser as spec_parser
@ -138,11 +139,11 @@ class ActionsController(rest.RestController, hooks.HookController):
@wsme_pecan.wsexpose(resources.Actions, types.uuid, int, types.uniquelist,
types.list, types.uniquelist, wtypes.text,
wtypes.text, resources.SCOPE_TYPES, wtypes.text,
types.uniquelist, wtypes.text, wtypes.text,
wtypes.text, bool, wtypes.text)
wtypes.text, wtypes.text, wtypes.text, wtypes.text,
wtypes.text)
def get_all(self, marker=None, limit=None, sort_keys='name',
sort_dirs='asc', fields='', created_at=None, name=None,
scope=None, tag=None, tags=None, updated_at=None,
scope=None, tags=None, updated_at=None,
description=None, definition=None, is_system=None, input=None):
"""Return all actions.
@ -168,9 +169,6 @@ class ActionsController(rest.RestController, hooks.HookController):
:param input: Optional. Keep only resources with a specific input.
:param description: Optional. Keep only resources with a specific
description.
:param tag: Optional. Keep only resources with a specific tag. If it is
used with 'tags', it will be appended to the list of
matching tags.
:param tags: Optional. Keep only resources containing specific tags.
:param created_at: Optional. Keep only resources created at a specific
time and date.
@ -182,13 +180,7 @@ class ActionsController(rest.RestController, hooks.HookController):
"""
acl.enforce('actions:list', context.ctx())
if tag is not None:
if tags is None:
tags = [tag]
else:
tags.append(tag)
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
name=name,
scope=scope,

View File

@ -27,6 +27,7 @@ from mistral import context
from mistral.db.v2 import api as db_api
from mistral.engine.rpc_backend import rpc
from mistral import exceptions as exc
from mistral.utils import filter_utils
from mistral.utils import rest_utils
from mistral.workflow import states
from mistral.workflow import utils as wf_utils
@ -178,13 +179,12 @@ class ActionExecutionsController(rest.RestController):
@wsme_pecan.wsexpose(resources.ActionExecutions, types.uuid, int,
types.uniquelist, types.list, types.uniquelist,
wtypes.text, wtypes.text, wtypes.text,
types.uniquelist, wtypes.text, wtypes.text,
wtypes.text, types.uuid, wtypes.text, wtypes.text,
bool, types.jsontype, types.jsontype, types.jsontype,
wtypes.text)
wtypes.text, wtypes.text, wtypes.text, types.uuid,
wtypes.text, wtypes.text, bool, types.jsontype,
types.jsontype, types.jsontype, wtypes.text)
def get_all(self, marker=None, limit=None, sort_keys='created_at',
sort_dirs='asc', fields='', created_at=None, name=None,
tag=None, tags=None, updated_at=None, workflow_name=None,
tags=None, updated_at=None, workflow_name=None,
task_name=None, task_execution_id=None, state=None,
state_info=None, accepted=None, input=None, output=None,
params=None, description=None):
@ -224,9 +224,6 @@ class ActionExecutionsController(rest.RestController):
:param params: Optional. Keep only resources with specific parameters.
:param description: Optional. Keep only resources with a specific
description.
:param tag: Optional. Keep only resources with a specific tag. If it is
used with 'tags', it will be appended to the list of
matching tags.
:param tags: Optional. Keep only resources containing specific tags.
:param created_at: Optional. Keep only resources created at a specific
time and date.
@ -235,13 +232,7 @@ class ActionExecutionsController(rest.RestController):
"""
acl.enforce('action_executions:list', context.ctx())
if tag is not None:
if tags is None:
tags = [tag]
else:
tags.append(tag)
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
name=name,
tags=tags,
@ -299,13 +290,13 @@ class ActionExecutionsController(rest.RestController):
class TasksActionExecutionController(rest.RestController):
@wsme_pecan.wsexpose(resources.ActionExecutions, types.uuid, types.uuid,
int, types.uniquelist, types.list, types.uniquelist,
wtypes.text, wtypes.text, types.uniquelist,
wtypes.text, types.uniquelist, wtypes.text,
wtypes.text, wtypes.text, wtypes.text, wtypes.text,
wtypes.text, wtypes.text, bool, types.jsontype,
types.jsontype, types.jsontype, wtypes.text)
wtypes.text, bool, types.jsontype, types.jsontype,
types.jsontype, wtypes.text)
def get_all(self, task_execution_id, marker=None, limit=None,
sort_keys='created_at', sort_dirs='asc', fields='',
created_at=None, name=None, tag=None, tags=None,
created_at=None, name=None, tags=None,
updated_at=None, workflow_name=None, task_name=None,
state=None, state_info=None, accepted=None, input=None,
output=None, params=None, description=None):
@ -345,9 +336,6 @@ class TasksActionExecutionController(rest.RestController):
:param params: Optional. Keep only resources with specific parameters.
:param description: Optional. Keep only resources with a specific
description.
:param tag: Optional. Keep only resources with a specific tag. If it is
used with 'tags', it will be appended to the list of
matching tags.
:param tags: Optional. Keep only resources containing specific tags.
:param created_at: Optional. Keep only resources created at a specific
time and date.
@ -356,13 +344,7 @@ class TasksActionExecutionController(rest.RestController):
"""
acl.enforce('action_executions:list', context.ctx())
if tag is not None:
if tags is None:
tags = [tag]
else:
tags.append(tag)
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
name=name,
tags=tags,

View File

@ -23,6 +23,7 @@ from mistral.api.controllers.v2 import types
from mistral import context
from mistral.db.v2 import api as db_api
from mistral.services import triggers
from mistral.utils import filter_utils
from mistral.utils import rest_utils
LOG = logging.getLogger(__name__)
@ -130,7 +131,7 @@ class CronTriggersController(rest.RestController):
"""
acl.enforce('cron_triggers:list', context.ctx())
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
name=name,
updated_at=updated_at,

View File

@ -25,6 +25,7 @@ from mistral.api.controllers.v2 import types
from mistral import context
from mistral.db.v2 import api as db_api
from mistral import exceptions as exceptions
from mistral.utils import filter_utils
from mistral.utils import rest_utils
@ -71,7 +72,7 @@ class EnvironmentController(rest.RestController):
"""
acl.enforce('environments:list', context.ctx())
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
name=name,
updated_at=updated_at,

View File

@ -29,6 +29,7 @@ from mistral.db.v2 import api as db_api
from mistral.engine.rpc_backend import rpc
from mistral import exceptions as exc
from mistral.services import workflows as wf_service
from mistral.utils import filter_utils
from mistral.utils import rest_utils
from mistral.workflow import states
@ -260,7 +261,7 @@ class ExecutionsController(rest.RestController):
"""
acl.enforce('executions:list', context.ctx())
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
workflow_name=workflow_name,
workflow_id=workflow_id,

View File

@ -28,6 +28,7 @@ from mistral import context
from mistral.db.v2 import api as db_api
from mistral.engine.rpc_backend import rpc
from mistral import exceptions as exc
from mistral.utils import filter_utils
from mistral.utils import rest_utils
from mistral.workbook import parser as spec_parser
from mistral.workflow import data_flow
@ -93,7 +94,7 @@ class TaskExecutionsController(rest.RestController):
"""
acl.enforce('executions:list', context.ctx())
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
task_execution_id=task_execution_id,
created_at=created_at,
workflow_name=workflow_name,
@ -196,7 +197,7 @@ class TasksController(rest.RestController):
"""
acl.enforce('tasks:list', context.ctx())
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
workflow_name=workflow_name,
workflow_id=workflow_id,
@ -339,7 +340,7 @@ class ExecutionTasksController(rest.RestController):
"""
acl.enforce('tasks:list', context.ctx())
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
workflow_execution_id=workflow_execution_id,
created_at=created_at,
workflow_name=workflow_name,

View File

@ -28,6 +28,7 @@ from mistral.api.hooks import content_type as ct_hook
from mistral import context
from mistral.db.v2 import api as db_api
from mistral.services import workbooks
from mistral.utils import filter_utils
from mistral.utils import rest_utils
from mistral.workbook import parser as spec_parser
@ -95,11 +96,10 @@ class WorkbooksController(rest.RestController, hooks.HookController):
@wsme_pecan.wsexpose(resources.Workbooks, types.uuid, int,
types.uniquelist, types.list, types.uniquelist,
wtypes.text, wtypes.text, wtypes.text,
resources.SCOPE_TYPES, wtypes.text, types.uniquelist,
wtypes.text)
resources.SCOPE_TYPES, wtypes.text, wtypes.text)
def get_all(self, marker=None, limit=None, sort_keys='created_at',
sort_dirs='asc', fields='', created_at=None,
definition=None, name=None, scope=None, tag=None, tags=None,
definition=None, name=None, scope=None, tags=None,
updated_at=None):
"""Return a list of workbooks.
@ -119,9 +119,6 @@ class WorkbooksController(rest.RestController, hooks.HookController):
:param name: Optional. Keep only resources with a specific name.
:param definition: Optional. Keep only resources with a specific
definition.
:param tag: Optional. Keep only resources with a specific tag. If it is
used with 'tags', it will be appended to the list of
matching tags.
:param tags: Optional. Keep only resources containing specific tags.
:param scope: Optional. Keep only resources with a specific scope.
:param created_at: Optional. Keep only resources created at a specific
@ -134,13 +131,7 @@ class WorkbooksController(rest.RestController, hooks.HookController):
"""
acl.enforce('workbooks:list', context.ctx())
if tag is not None:
if tags is None:
tags = [tag]
else:
tags.append(tag)
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
definition=definition,
name=name,

View File

@ -32,6 +32,7 @@ from mistral import context
from mistral.db.v2 import api as db_api
from mistral import exceptions as exc
from mistral.services import workflows
from mistral.utils import filter_utils
from mistral.utils import rest_utils
from mistral.workbook import parser as spec_parser
@ -169,11 +170,11 @@ class WorkflowsController(rest.RestController, hooks.HookController):
@wsme_pecan.wsexpose(resources.Workflows, types.uuid, int,
types.uniquelist, types.list, types.uniquelist,
wtypes.text, wtypes.text, wtypes.text, wtypes.text,
types.uniquelist, resources.SCOPE_TYPES, types.uuid,
wtypes.text, wtypes.text)
resources.SCOPE_TYPES, types.uuid, wtypes.text,
wtypes.text)
def get_all(self, marker=None, limit=None, sort_keys='created_at',
sort_dirs='asc', fields='', name=None, input=None,
definition=None, tag=None, tags=None, scope=None,
definition=None, tags=None, scope=None,
project_id=None, created_at=None, updated_at=None):
"""Return a list of workflows.
@ -194,9 +195,6 @@ class WorkflowsController(rest.RestController, hooks.HookController):
:param input: Optional. Keep only resources with a specific input.
:param definition: Optional. Keep only resources with a specific
definition.
:param tag: Optional. Keep only resources with a specific tag. If it is
used with 'tags', it will be appended to the list of
matching tags.
:param tags: Optional. Keep only resources containing specific tags.
:param scope: Optional. Keep only resources with a specific scope.
:param project_id: Optional. The same as the requester project_id
@ -208,13 +206,7 @@ class WorkflowsController(rest.RestController, hooks.HookController):
"""
acl.enforce('workflows:list', context.ctx())
if tag is not None:
if tags is None:
tags = [tag]
else:
tags.append(tag)
filters = rest_utils.filters_to_dict(
filters = filter_utils.create_filters_from_request_params(
created_at=created_at,
name=name,
scope=scope,

View File

@ -30,6 +30,7 @@ from sqlalchemy.sql.expression import Insert
from mistral.db.sqlalchemy import base as b
from mistral.db.sqlalchemy import model_base as mb
from mistral.db.sqlalchemy import sqlite_lock
from mistral.db.v2.sqlalchemy import filters as db_filters
from mistral.db.v2.sqlalchemy import models
from mistral import exceptions as exc
from mistral.services import security
@ -173,7 +174,7 @@ def _delete_all(model, session=None, **kwargs):
def _get_collection(model, insecure=False, limit=None, marker=None,
sort_keys=None, sort_dirs=None, fields=None, **kwargs):
sort_keys=None, sort_dirs=None, fields=None, **filters):
columns = (
tuple([getattr(model, f) for f in fields if hasattr(model, f)])
if fields else ()
@ -181,21 +182,7 @@ def _get_collection(model, insecure=False, limit=None, marker=None,
query = (b.model_query(model, *columns) if insecure
else _secure_query(model, *columns))
query = query.filter_by(**kwargs)
tags = kwargs.pop('tags', None)
# To match the tag list, a resource must contain at least all of the
# tags present in the filter parameter.
if tags:
tag_attr = getattr(model, 'tags')
if len(tags) == 1:
expr = tag_attr.contains(tags)
else:
expr = sa.and_(*[tag_attr.contains(tag) for tag in tags])
query = query.filter(expr)
query = db_filters.apply_filters(query, model, **filters)
query = _paginate_query(
model,

View File

@ -0,0 +1,63 @@
# Copyright 2016 NEC Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import six
import sqlalchemy as sa
def apply_filters(query, model, **filters):
filter_dict = {}
for key, value in six.iteritems(filters):
column_attr = getattr(model, key)
if isinstance(value, dict):
if 'in' in value:
query = query.filter(column_attr.in_(value['in']))
elif 'nin' in value:
query = query.filter(~column_attr.in_(value['nin']))
elif 'neq' in value:
query = query.filter(column_attr != value['neq'])
elif 'gt' in value:
query = query.filter(column_attr > value['gt'])
elif 'gte' in value:
query = query.filter(column_attr >= value['gte'])
elif 'lt' in value:
query = query.filter(column_attr < value['lt'])
elif 'lte' in value:
query = query.filter(column_attr <= value['lte'])
elif 'eq' in value:
query = query.filter(column_attr == value['eq'])
else:
filter_dict[key] = value
# We need to handle tag case seprately. As tag datatype is MutableList.
# TODO(hparekh): Need to think how can we get rid of this.
tags = filters.pop('tags', None)
# To match the tag list, a resource must contain at least all of the
# tags present in the filter parameter.
if tags:
tag_attr = getattr(model, 'tags')
if not isinstance(tags, list):
expr = tag_attr.contains(tags)
else:
expr = sa.and_(*[tag_attr.contains(tag) for tag in tags])
query = query.filter(expr)
if filter_dict:
query = query.filter_by(**filter_dict)
return query

View File

@ -26,6 +26,7 @@ from mistral.db.v2.sqlalchemy import models as db_models
from mistral import exceptions as exc
from mistral.services import security
from mistral.tests.unit import base as test_base
from mistral.utils import filter_utils
user_context = test_base.get_context(default=False)
@ -567,6 +568,15 @@ ACTION_DEFINITIONS = [
'attributes': None,
'project_id': '<default-project>'
},
{
'name': 'action3',
'description': 'Action #3',
'is_system': False,
'tags': ['mc', 'abc'],
'action_class': 'mypackage.my_module.Action3',
'attributes': None,
'project_id': '<default-project>'
},
]
@ -605,6 +615,157 @@ class ActionDefinitionTest(SQLAlchemyTest):
ACTION_DEFINITIONS[0]
)
def test_filter_action_definitions_by_equal_value(self):
db_api.create_action_definition(ACTION_DEFINITIONS[0])
db_api.create_action_definition(ACTION_DEFINITIONS[1])
created2 = db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'is_system',
False,
'eq'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(1, len(fetched))
self.assertEqual(created2, fetched[0])
def test_filter_action_definitions_by_notEqual_value(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'is_system',
False,
'neq'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(2, len(fetched))
self.assertEqual(created0, fetched[0])
self.assertEqual(created1, fetched[1])
def test_filter_action_definitions_by_greaterThan_value(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
created2 = db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'created_at',
created0['created_at'],
'gt'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(2, len(fetched))
self.assertEqual(created1, fetched[0])
self.assertEqual(created2, fetched[1])
def test_filter_action_definitions_by_greaterThanEqual_value(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
created2 = db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'created_at',
created0['created_at'],
'gte'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(3, len(fetched))
self.assertEqual(created0, fetched[0])
self.assertEqual(created1, fetched[1])
self.assertEqual(created2, fetched[2])
def test_filter_action_definitions_by_lessThan_value(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
created2 = db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'created_at',
created2['created_at'],
'lt'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(2, len(fetched))
self.assertEqual(created0, fetched[0])
self.assertEqual(created1, fetched[1])
def test_filter_action_definitions_by_lessThanEqual_value(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
created2 = db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'created_at',
created2['created_at'],
'lte'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(3, len(fetched))
self.assertEqual(created0, fetched[0])
self.assertEqual(created1, fetched[1])
self.assertEqual(created2, fetched[2])
def test_filter_action_definitions_by_values_in_list(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'created_at',
[created0['created_at'], created1['created_at']],
'in'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(2, len(fetched))
self.assertEqual(created0, fetched[0])
self.assertEqual(created1, fetched[1])
def test_filter_action_definitions_by_values_notin_list(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
created2 = db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'created_at',
[created0['created_at'], created1['created_at']],
'nin'
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(1, len(fetched))
self.assertEqual(created2, fetched[0])
def test_filter_action_definitions_by_multiple_columns(self):
created0 = db_api.create_action_definition(ACTION_DEFINITIONS[0])
created1 = db_api.create_action_definition(ACTION_DEFINITIONS[1])
db_api.create_action_definition(ACTION_DEFINITIONS[2])
_filter = filter_utils.create_or_update_filter(
'created_at',
[created0['created_at'], created1['created_at']],
'in'
)
_filter = filter_utils.create_or_update_filter(
'is_system',
True,
'neq',
_filter
)
fetched = db_api.get_action_definitions(**_filter)
self.assertEqual(0, len(fetched))
def test_update_action_definition_with_name(self):
created = db_api.create_action_definition(ACTION_DEFINITIONS[0])

View File

@ -0,0 +1,91 @@
# Copyright 2016 NEC Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import six
def create_filters_from_request_params(**params):
"""Create filters from REST request parameters.
:param req_params: REST request parameters.
:return: filters dictionary.
"""
filters = {}
for column, data in six.iteritems(params):
if data is not None:
if isinstance(data, six.string_types):
f_type, value = _extract_filter_type_and_value(data)
create_or_update_filter(column, value, f_type, filters)
else:
create_or_update_filter(column, data, _filter=filters)
return filters
def create_or_update_filter(column, value, filter_type='eq', _filter=None):
"""Create or Update filter.
:param column: Column name by which user want to filter.
:param value: Column value.
:param filter_type: filter type. Filter type can be
'eq', 'neq', 'gt', 'gte', 'lte', 'in',
'lt', 'nin'. Default is 'eq'.
:parma _filter: Optional. If provided same filter dictionary will
be updated.
:return: filter dictionary.
"""
if _filter is None:
_filter = {}
_filter[column] = {filter_type: value}
return _filter
def _extract_filter_type_and_value(data):
"""Extract filter type and its value from the data.
:param data: REST parameter value from which filter type and
value can be get. It should be in format of
'filter_type:value'.
:return: filter type and value.
"""
if data.startswith("in:"):
value = list(six.text_type(data[3:]).split(","))
filter_type = 'in'
elif data.startswith("nin:"):
value = list(six.text_type(data[4:]).split(","))
filter_type = 'nin'
elif data.startswith("neq:"):
value = six.text_type(data[4:])
filter_type = 'neq'
elif data.startswith("gt:"):
value = six.text_type(data[3:])
filter_type = 'gt'
elif data.startswith("gte:"):
value = six.text_type(data[4:])
filter_type = 'gte'
elif data.startswith("lt:"):
value = six.text_type(data[3:])
filter_type = 'lt'
elif data.startswith("lte:"):
value = six.text_type(data[4:])
filter_type = 'lte'
elif data.startswith("eq:"):
value = six.text_type(data[3:])
filter_type = 'eq'
else:
value = data
filter_type = 'eq'
return filter_type, value

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import datetime
from oslo_log import log as logging
from tempest.lib import exceptions
from tempest import test
@ -125,6 +126,162 @@ class ActionTestsV2(base.TestCase):
context.resp_body.get('faultstring')
)
@test.attr(type='smoke')
def test_get_list_actions_equalto_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
resp, body = self.client.get_list_obj(
'actions?is_system=False'
)
self.assertEqual(200, resp.status)
self.assertNotEqual([], body['actions'])
for act in body['actions']:
self.assertFalse(act['is_system'])
@test.attr(type='smoke')
def test_get_list_actions_notEqualto_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
resp, body = self.client.get_list_obj(
'actions?is_system=neq:False'
)
self.assertEqual(200, resp.status)
self.assertNotEqual([], body['actions'])
for act in body['actions']:
self.assertTrue(act['is_system'])
@test.attr(type='smoke')
def test_get_list_actions_inList_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
created_acts = [action['name'] for action in body['actions']]
_, body = self.client.get_object('actions', created_acts[0])
time = body['created_at']
resp, body = self.client.get_list_obj(
'actions?created_at=in:' + time.replace(' ', '%20')
)
self.assertEqual(200, resp.status)
action_names = [action['name'] for action in body['actions']]
self.assertListEqual(created_acts, action_names)
@test.attr(type='smoke')
def test_get_list_actions_notinList_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
created_acts = [action['name'] for action in body['actions']]
_, body = self.client.get_object('actions', created_acts[0])
time = body['created_at']
resp, body = self.client.get_list_obj(
'actions?created_at=nin:' + time.replace(' ', '%20')
)
self.assertEqual(200, resp.status)
action_names = [action['name'] for action in body['actions']]
for act in created_acts:
self.assertNotIn(act, action_names)
@test.attr(type='smoke')
def test_get_list_actions_greaterThan_filter(self):
time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
resp, body = self.client.get_list_obj(
'actions?created_at=gt:' + time.replace(' ', '%20')
)
self.assertEqual(200, resp.status)
self.assertEqual([], body['actions'])
@test.attr(type='smoke')
def test_get_list_actions_greaterThanEqualto_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
created_acts = [action['name'] for action in body['actions']]
_, body = self.client.get_object('actions', created_acts[0])
time = body['created_at']
resp, body = self.client.get_list_obj(
'actions?created_at=gte:' + time.replace(' ', '%20')
)
actions = [action['name'] for action in body['actions']]
self.assertEqual(200, resp.status)
self.assertIn(created_acts[0], actions)
@test.attr(type='smoke')
def test_get_list_actions_lessThan_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
created_acts = [action['name'] for action in body['actions']]
_, body = self.client.get_object('actions', created_acts[0])
time = body['created_at']
resp, body = self.client.get_list_obj(
'actions?created_at=lt:' + time.replace(' ', '%20')
)
actions = [action['name'] for action in body['actions']]
self.assertEqual(200, resp.status)
self.assertNotIn(created_acts[0], actions)
@test.attr(type='smoke')
def test_get_list_actions_lessThanEqualto_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
created_acts = [action['name'] for action in body['actions']]
_, body = self.client.get_object('actions', created_acts[0])
time = body['created_at']
resp, body = self.client.get_list_obj(
'actions?created_at=lte:' + time.replace(' ', '%20')
)
actions = [action['name'] for action in body['actions']]
self.assertEqual(200, resp.status)
self.assertIn(created_acts[0], actions)
@test.attr(type='smoke')
def test_get_list_actions_multiple_filter(self):
resp, body = self.client.create_action('action_v2.yaml')
self.assertEqual(201, resp.status)
created_acts = [action['name'] for action in body['actions']]
_, body = self.client.get_object('actions', created_acts[0])
time = body['created_at']
resp, body = self.client.get_list_obj(
'actions?created_at=lte:' + time.replace(' ', '%20') +
'&is_system=False'
)
actions = [action['name'] for action in body['actions']]
self.assertEqual(200, resp.status)
self.assertIn(created_acts[0], actions)
@test.attr(type='negative')
def test_get_list_actions_invalid_filter(self):
self.assertRaises(
exceptions.BadRequest,
self.client.get_list_obj,
'actions?is_system<False'
)
self.assertRaises(
exceptions.BadRequest,
self.client.get_list_obj,
'actions?is_system!=False'
)
self.assertRaises(
exceptions.BadRequest,
self.client.get_list_obj,
'actions?created_at>2016-02-23%2008:51:26'
)
@test.attr(type='sanity')
def test_create_and_delete_few_actions(self):
resp, body = self.client.create_action('action_v2.yaml')