Add option to create mistral execution from workbook
Change-Id: I637ff8cd73c788c519a1af5962fd923a6a12d0da
This commit is contained in:
parent
bd50e1eda0
commit
546bed4c6d
@ -268,6 +268,9 @@
|
||||
# (floating point value)
|
||||
#manila_share_delete_poll_interval = 2.0
|
||||
|
||||
# mistral execution timeout (integer value)
|
||||
#mistral_execution_timeout = 200
|
||||
|
||||
# Delay between creating Monasca metrics and polling for its elements.
|
||||
# (floating point value)
|
||||
#monasca_metric_create_prepoll_delay = 15.0
|
||||
|
@ -44,3 +44,35 @@
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
MistralExecutions.list_executions:
|
||||
-
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 50
|
||||
concurrency: 10
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
MistralExecutions.create_execution_from_workbook:
|
||||
-
|
||||
args:
|
||||
definition: "~/.rally/extra/mistral_wb.yaml"
|
||||
workflow_name: "wf1"
|
||||
do_delete: true
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 50
|
||||
concurrency: 10
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
@ -25,6 +25,7 @@ from rally.plugins.openstack.scenarios.heat import utils as heat_utils
|
||||
from rally.plugins.openstack.scenarios.ironic import utils as ironic_utils
|
||||
from rally.plugins.openstack.scenarios.magnum import utils as magnum_utils
|
||||
from rally.plugins.openstack.scenarios.manila import utils as manila_utils
|
||||
from rally.plugins.openstack.scenarios.mistral import utils as mistral_utils
|
||||
from rally.plugins.openstack.scenarios.monasca import utils as monasca_utils
|
||||
from rally.plugins.openstack.scenarios.murano import utils as murano_utils
|
||||
from rally.plugins.openstack.scenarios.nova import utils as nova_utils
|
||||
@ -48,6 +49,7 @@ def list_opts():
|
||||
ironic_utils.IRONIC_BENCHMARK_OPTS,
|
||||
magnum_utils.MAGNUM_BENCHMARK_OPTS,
|
||||
manila_utils.MANILA_BENCHMARK_OPTS,
|
||||
mistral_utils.MISTRAL_BENCHMARK_OPTS,
|
||||
monasca_utils.MONASCA_BENCHMARK_OPTS,
|
||||
murano_utils.MURANO_BENCHMARK_OPTS,
|
||||
nova_utils.NOVA_BENCHMARK_OPTS,
|
||||
|
@ -736,10 +736,32 @@ class SwiftContainer(SwiftMixin):
|
||||
|
||||
# MISTRAL
|
||||
|
||||
@base.resource("mistral", "workbooks", order=1100, tenant_resource=True)
|
||||
class MistralWorkbooks(SynchronizedDeletion, base.ResourceManager):
|
||||
_mistral_order = get_order(1100)
|
||||
|
||||
|
||||
class MistralMixin(SynchronizedDeletion, base.ResourceManager):
|
||||
|
||||
def delete(self):
|
||||
self._manager().delete(self.raw_resource.name)
|
||||
self._manager().delete(self.raw_resource["id"])
|
||||
|
||||
|
||||
@base.resource("mistral", "workbooks", order=next(_mistral_order),
|
||||
tenant_resource=True)
|
||||
class MistralWorkbooks(MistralMixin):
|
||||
def delete(self):
|
||||
self._manager().delete(self.raw_resource["name"])
|
||||
|
||||
|
||||
@base.resource("mistral", "workflows", order=next(_mistral_order),
|
||||
tenant_resource=True)
|
||||
class MistralWorkflows(MistralMixin):
|
||||
pass
|
||||
|
||||
|
||||
@base.resource("mistral", "executions", order=next(_mistral_order),
|
||||
tenant_resource=True)
|
||||
class MistralExecutions(MistralMixin):
|
||||
pass
|
||||
|
||||
|
||||
# MURANO
|
||||
|
92
rally/plugins/openstack/scenarios/mistral/executions.py
Normal file
92
rally/plugins/openstack/scenarios/mistral/executions.py
Normal file
@ -0,0 +1,92 @@
|
||||
# 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 yaml
|
||||
|
||||
from rally import consts
|
||||
from rally.plugins.openstack import scenario
|
||||
from rally.plugins.openstack.scenarios.mistral import utils
|
||||
from rally.task import types
|
||||
from rally.task import validation
|
||||
|
||||
|
||||
"""Scenarios for Mistral execution."""
|
||||
|
||||
|
||||
@validation.required_clients("mistral")
|
||||
@validation.required_openstack(users=True)
|
||||
@validation.required_services(consts.Service.MISTRAL)
|
||||
@scenario.configure(name="MistralExecutions.list_executions",
|
||||
context={"cleanup": ["mistral"]})
|
||||
class ListExecutions(utils.MistralScenario):
|
||||
|
||||
def run(self, marker="", limit=None, sort_keys="", sort_dirs=""):
|
||||
"""Scenario test mistral execution-list command.
|
||||
|
||||
This simple scenario tests the Mistral execution-list
|
||||
command by listing all the executions.
|
||||
:param marker: The last execution uuid of the previous page, displays
|
||||
list of executions after "marker".
|
||||
:param limit: number Maximum number of executions to return in a single
|
||||
result.
|
||||
:param sort_keys: id,description
|
||||
:param sort_dirs: [SORT_DIRS] Comma-separated list of sort directions.
|
||||
Default: asc.
|
||||
"""
|
||||
self._list_executions(marker=marker, limit=limit,
|
||||
sort_keys=sort_keys, sort_dirs=sort_dirs)
|
||||
|
||||
|
||||
@validation.required_parameters("definition")
|
||||
@validation.file_exists("definition")
|
||||
@types.convert(definition={"type": "file"})
|
||||
@validation.required_clients("mistral")
|
||||
@validation.required_openstack(users=True)
|
||||
@validation.required_services(consts.Service.MISTRAL)
|
||||
@validation.workbook_contains_workflow("definition", "workflow_name")
|
||||
@scenario.configure(
|
||||
name="MistralExecutions.create_execution_from_workbook",
|
||||
context={"cleanup": ["mistral"]})
|
||||
class CreateExecutionFromWorkbook(utils.MistralScenario):
|
||||
|
||||
def run(self, definition, workflow_name=None, do_delete=False):
|
||||
"""Scenario tests execution creation and deletion.
|
||||
|
||||
This scenario is a very useful tool to measure the
|
||||
"mistral execution-create" and "mistral execution-delete"
|
||||
commands performance.
|
||||
:param definition: string (yaml string) representation of given file
|
||||
content (Mistral workbook definition)
|
||||
:param workflow_name: string the workflow name to execute. Should be
|
||||
one of the to workflows in the definition. If no
|
||||
workflow_name is passed, one of the workflows in
|
||||
the definition will be taken.
|
||||
|
||||
:param do_delete: if False than it allows to check performance
|
||||
in "create only" mode.
|
||||
"""
|
||||
|
||||
wb = self._create_workbook(definition)
|
||||
wb_def = yaml.safe_load(wb.definition)
|
||||
|
||||
if not workflow_name:
|
||||
workflow_name = six.next(six.iterkeys(wb_def["workflows"]))
|
||||
|
||||
workflow_identifier = ".".join([wb.name, workflow_name])
|
||||
ex = self._create_execution(workflow_identifier)
|
||||
|
||||
if do_delete:
|
||||
self._delete_workbook(wb.name)
|
||||
self._delete_execution(ex)
|
@ -13,10 +13,23 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
import yaml
|
||||
|
||||
from rally.plugins.openstack import scenario
|
||||
from rally.task import atomic
|
||||
from rally.task import utils
|
||||
|
||||
MISTRAL_BENCHMARK_OPTS = [
|
||||
cfg.IntOpt(
|
||||
"mistral_execution_timeout",
|
||||
default=200,
|
||||
help="mistral execution timeout")
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
benchmark_group = cfg.OptGroup(name="benchmark", title="benchmark options")
|
||||
CONF.register_opts(MISTRAL_BENCHMARK_OPTS, group=benchmark_group)
|
||||
|
||||
|
||||
class MistralScenario(scenario.OpenStackScenario):
|
||||
@ -24,7 +37,10 @@ class MistralScenario(scenario.OpenStackScenario):
|
||||
|
||||
@atomic.action_timer("mistral.list_workbooks")
|
||||
def _list_workbooks(self):
|
||||
"""Gets list of existing workbooks."""
|
||||
"""Gets list of existing workbooks.
|
||||
|
||||
:returns: workbook list
|
||||
"""
|
||||
return self.clients("mistral").workbooks.list()
|
||||
|
||||
@atomic.action_timer("mistral.create_workbook")
|
||||
@ -48,3 +64,41 @@ class MistralScenario(scenario.OpenStackScenario):
|
||||
:param wb_name: the name of workbook that would be deleted.
|
||||
"""
|
||||
self.clients("mistral").workbooks.delete(wb_name)
|
||||
|
||||
@atomic.action_timer("mistral.list_executions")
|
||||
def _list_executions(self, marker="", limit=None, sort_keys="",
|
||||
sort_dirs=""):
|
||||
"""Gets list of existing executions.
|
||||
|
||||
:returns: execution list
|
||||
"""
|
||||
|
||||
return self.clients("mistral").executions.list(
|
||||
marker=marker, limit=limit, sort_keys=sort_keys,
|
||||
sort_dirs=sort_dirs)
|
||||
|
||||
@atomic.action_timer("mistral.create_execution")
|
||||
def _create_execution(self, workflow_identifier):
|
||||
"""Create a new execution.
|
||||
|
||||
:param workflow_identifier: name or id of the workflow to execute
|
||||
:returns: executions object
|
||||
"""
|
||||
|
||||
execution = self.clients("mistral").executions.create(
|
||||
workflow_identifier)
|
||||
|
||||
execution = utils.wait_for_status(
|
||||
execution, ready_statuses=["SUCCESS"], failure_statuses=["ERROR"],
|
||||
update_resource=utils.get_from_manager(),
|
||||
timeout=CONF.benchmark.mistral_execution_timeout)
|
||||
|
||||
return execution
|
||||
|
||||
@atomic.action_timer("mistral.delete_execution")
|
||||
def _delete_execution(self, execution):
|
||||
"""Delete the given execution.
|
||||
|
||||
:param ex: the execution that would be deleted.
|
||||
"""
|
||||
self.clients("mistral").executions.delete(execution.id)
|
||||
|
@ -38,9 +38,9 @@ class ListWorkbooks(utils.MistralScenario):
|
||||
self._list_workbooks()
|
||||
|
||||
|
||||
@types.convert(definition={"type": "file"})
|
||||
@validation.file_exists("definition")
|
||||
@validation.required_parameters("definition")
|
||||
@validation.file_exists("definition")
|
||||
@types.convert(definition={"type": "file"})
|
||||
@validation.required_clients("mistral")
|
||||
@validation.required_openstack(users=True)
|
||||
@validation.required_services(consts.Service.MISTRAL)
|
||||
@ -62,4 +62,4 @@ class CreateWorkbook(utils.MistralScenario):
|
||||
wb = self._create_workbook(definition)
|
||||
|
||||
if do_delete:
|
||||
self._delete_workbook(wb.name)
|
||||
self._delete_workbook(wb.name)
|
||||
|
@ -21,6 +21,7 @@ import re
|
||||
from glanceclient import exc as glance_exc
|
||||
from novaclient import exceptions as nova_exc
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from rally.common.i18n import _
|
||||
from rally.common import objects
|
||||
@ -727,3 +728,30 @@ def validate_heat_template(config, clients, deployment, *param_names):
|
||||
msg = (_("Heat template validation failed on %(path)s. "
|
||||
"Original error message: %(msg)s.") % dct)
|
||||
return ValidationResult(False, msg)
|
||||
|
||||
|
||||
@validator
|
||||
def workbook_contains_workflow(config, clients, deployment, workbook,
|
||||
workflow_name):
|
||||
"""Validate that workflow exist in workbook when workflow is passed
|
||||
|
||||
:param workbook: parameter containing the workbook definition
|
||||
:param workflow_name: parameter containing the workflow name
|
||||
"""
|
||||
|
||||
wf_name = config.get("args", {}).get(workflow_name)
|
||||
if wf_name:
|
||||
wb_path = config.get("args", {}).get(workbook)
|
||||
wb_path = os.path.expanduser(wb_path)
|
||||
file_result = _file_access_ok(config.get("args", {}).get(workbook),
|
||||
os.R_OK, workbook)
|
||||
if not file_result.is_valid:
|
||||
return file_result
|
||||
|
||||
with open(wb_path, "r") as wb_def:
|
||||
wb_def = yaml.safe_load(wb_def)
|
||||
if wf_name not in wb_def["workflows"]:
|
||||
return ValidationResult(
|
||||
False,
|
||||
"workflow '{}' not found in the definition '{}'".format(
|
||||
wf_name, wb_def))
|
||||
|
@ -0,0 +1,27 @@
|
||||
{
|
||||
"MistralExecutions.create_execution_from_workbook": [
|
||||
{
|
||||
"args": {
|
||||
"definition": "rally-jobs/extra/mistral_wb.yaml",
|
||||
"workflow_name": "wf1",
|
||||
"do_delete": true
|
||||
},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 20,
|
||||
"concurrency": 5
|
||||
},
|
||||
"context": {
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 2
|
||||
}
|
||||
},
|
||||
"sla": {
|
||||
"failure_rate": {
|
||||
"max": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
---
|
||||
MistralExecutions.create_execution_from_workbook:
|
||||
-
|
||||
args:
|
||||
definition: rally-jobs/extra/mistral_wb.yaml
|
||||
workflow_name: wf1
|
||||
do_delete: true
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 20
|
||||
concurrency: 5
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
|
26
samples/tasks/scenarios/mistral/create-delete-execution.json
Normal file
26
samples/tasks/scenarios/mistral/create-delete-execution.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"MistralExecutions.create_execution_from_workbook": [
|
||||
{
|
||||
"args": {
|
||||
"definition": "rally-jobs/extra/mistral_wb.yaml",
|
||||
"do_delete": true
|
||||
},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 20,
|
||||
"concurrency": 5
|
||||
},
|
||||
"context": {
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 2
|
||||
}
|
||||
},
|
||||
"sla": {
|
||||
"failure_rate": {
|
||||
"max": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
18
samples/tasks/scenarios/mistral/create-delete-execution.yaml
Normal file
18
samples/tasks/scenarios/mistral/create-delete-execution.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
MistralExecutions.create_execution_from_workbook:
|
||||
-
|
||||
args:
|
||||
definition: rally-jobs/extra/mistral_wb.yaml
|
||||
do_delete: true
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 20
|
||||
concurrency: 5
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"MistralExecutions.create_execution_from_workbook": [
|
||||
{
|
||||
"args": {
|
||||
"definition": "rally-jobs/extra/mistral_wb.yaml",
|
||||
"workflow_name": "wf1"
|
||||
},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 20,
|
||||
"concurrency": 5
|
||||
},
|
||||
"context": {
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 2
|
||||
}
|
||||
},
|
||||
"sla": {
|
||||
"failure_rate": {
|
||||
"max": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
---
|
||||
MistralExecutions.create_execution_from_workbook:
|
||||
-
|
||||
args:
|
||||
definition: rally-jobs/extra/mistral_wb.yaml
|
||||
workflow_name: wf1
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 20
|
||||
concurrency: 5
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
25
samples/tasks/scenarios/mistral/create-execution.json
Normal file
25
samples/tasks/scenarios/mistral/create-execution.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"MistralExecutions.create_execution_from_workbook": [
|
||||
{
|
||||
"args": {
|
||||
"definition": "rally-jobs/extra/mistral_wb.yaml"
|
||||
},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 20,
|
||||
"concurrency": 5
|
||||
},
|
||||
"context": {
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 2
|
||||
}
|
||||
},
|
||||
"sla": {
|
||||
"failure_rate": {
|
||||
"max": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
16
samples/tasks/scenarios/mistral/create-execution.yaml
Normal file
16
samples/tasks/scenarios/mistral/create-execution.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
MistralExecutions.create_execution_from_workbook:
|
||||
-
|
||||
args:
|
||||
definition: rally-jobs/extra/mistral_wb.yaml
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 20
|
||||
concurrency: 5
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
22
samples/tasks/scenarios/mistral/list-executions.json
Normal file
22
samples/tasks/scenarios/mistral/list-executions.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"MistralExecutions.list_executions": [
|
||||
{
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 50,
|
||||
"concurrency": 10
|
||||
},
|
||||
"context": {
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 2
|
||||
}
|
||||
},
|
||||
"sla": {
|
||||
"failure_rate": {
|
||||
"max": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
14
samples/tasks/scenarios/mistral/list-executions.yaml
Normal file
14
samples/tasks/scenarios/mistral/list-executions.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
MistralExecutions.list_executions:
|
||||
-
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 50
|
||||
concurrency: 10
|
||||
context:
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 2
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
@ -119,6 +119,20 @@ class Magnum(ResourceManager):
|
||||
return result
|
||||
|
||||
|
||||
class Mistral(ResourceManager):
|
||||
|
||||
REQUIRED_SERVICE = consts.Service.MISTRAL
|
||||
|
||||
def list_workbooks(self):
|
||||
return self.client.workbooks.list()
|
||||
|
||||
def list_workflows(self):
|
||||
return self.client.workflows.list()
|
||||
|
||||
def list_executions(self):
|
||||
return self.client.executions.list()
|
||||
|
||||
|
||||
class Nova(ResourceManager):
|
||||
|
||||
REQUIRED_SERVICE = consts.Service.NOVA
|
||||
|
@ -318,6 +318,18 @@ class FakeWorkbook(FakeResource):
|
||||
self.workbook = mock.MagicMock()
|
||||
|
||||
|
||||
class FakeWorkflow(FakeResource):
|
||||
def __init__(self, manager=None):
|
||||
super(FakeWorkflow, self).__init__(manager)
|
||||
self.workflow = mock.MagicMock()
|
||||
|
||||
|
||||
class FakeExecution(FakeResource):
|
||||
def __init__(self, manager=None):
|
||||
super(FakeExecution, self).__init__(manager)
|
||||
self.execution = mock.MagicMock()
|
||||
|
||||
|
||||
class FakeObject(FakeResource):
|
||||
pass
|
||||
|
||||
@ -939,6 +951,27 @@ class FakeWorkbookManager(FakeManager):
|
||||
return [self.workbook]
|
||||
|
||||
|
||||
class FakeWorkflowManager(FakeManager):
|
||||
def __init__(self):
|
||||
super(FakeWorkflowManager, self).__init__()
|
||||
self.workflow = FakeWorkflow()
|
||||
|
||||
def list(self):
|
||||
return [self.workflow]
|
||||
|
||||
|
||||
class FakeExecutionManager(FakeManager):
|
||||
def __init__(self):
|
||||
super(FakeExecutionManager, self).__init__()
|
||||
self.execution = FakeExecution()
|
||||
|
||||
def list(self):
|
||||
return [self.execution]
|
||||
|
||||
def create(self):
|
||||
return self.execution
|
||||
|
||||
|
||||
class FakeObjectManager(FakeManager):
|
||||
|
||||
def get_account(self, **kwargs):
|
||||
@ -1505,6 +1538,8 @@ class FakeMistralClient(object):
|
||||
|
||||
def __init__(self):
|
||||
self.workbook = FakeWorkbookManager()
|
||||
self.workflow = FakeWorkflowManager()
|
||||
self.execution = FakeExecutionManager()
|
||||
|
||||
|
||||
class FakeSwiftClient(FakeObjectManager):
|
||||
|
@ -760,6 +760,36 @@ class ManilaSecurityServiceTestCase(test.TestCase):
|
||||
"fake_id")
|
||||
|
||||
|
||||
class MistralMixinTestCase(test.TestCase):
|
||||
|
||||
def test_delete(self):
|
||||
mistral = resources.MistralMixin()
|
||||
mistral._service = "mistral"
|
||||
mistral.user = mock.MagicMock()
|
||||
mistral._resource = "some_resources"
|
||||
mistral.raw_resource = {"id": "TEST_ID"}
|
||||
mistral.user.mistral().some_resources.delete.return_value = None
|
||||
|
||||
mistral.delete()
|
||||
mistral.user.mistral().some_resources.delete.assert_called_once_with(
|
||||
"TEST_ID")
|
||||
|
||||
|
||||
class MistralWorkbookTestCase(test.TestCase):
|
||||
|
||||
def test_delete(self):
|
||||
mistral = resources.MistralWorkbooks()
|
||||
mistral._service = "mistral"
|
||||
mistral.user = mock.MagicMock()
|
||||
mistral._resource = "some_resources"
|
||||
mistral.raw_resource = {"name": "TEST_NAME"}
|
||||
mistral.user.mistral().some_resources.delete.return_value = None
|
||||
|
||||
mistral.delete()
|
||||
mistral.user.mistral().some_resources.delete.assert_called_once_with(
|
||||
"TEST_NAME")
|
||||
|
||||
|
||||
class FuelEnvironmentTestCase(test.TestCase):
|
||||
|
||||
def test_id(self):
|
||||
|
@ -0,0 +1,162 @@
|
||||
# Copyright 2016: Nokia Inc.
|
||||
# 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 mock
|
||||
|
||||
from rally.plugins.openstack.scenarios.mistral import executions
|
||||
from tests.unit import test
|
||||
|
||||
BASE = "rally.plugins.openstack.scenarios.mistral.executions"
|
||||
MISTRAL_WBS_BASE = "rally.plugins.openstack.scenarios.mistral.workbooks"
|
||||
|
||||
|
||||
WB_DEFINITION = """---
|
||||
version: 2.0
|
||||
name: wb
|
||||
workflows:
|
||||
wf1:
|
||||
type: direct
|
||||
tasks:
|
||||
noop_task:
|
||||
action: std.noop
|
||||
wf2:
|
||||
type: direct
|
||||
tasks:
|
||||
noop_task:
|
||||
action: std.noop
|
||||
wf3:
|
||||
type: direct
|
||||
tasks:
|
||||
noop_task:
|
||||
action: std.noop
|
||||
wf4:
|
||||
type: direct
|
||||
tasks:
|
||||
noop_task:
|
||||
action: std.noop
|
||||
"""
|
||||
|
||||
WB_DEF_ONE_WF = """---
|
||||
version: 2.0
|
||||
name: wb
|
||||
workflows:
|
||||
wf1:
|
||||
type: direct
|
||||
tasks:
|
||||
noop_task:
|
||||
action: std.noop
|
||||
"""
|
||||
|
||||
WB = type("obj", (object,), {"name": "wb", "definition": WB_DEFINITION})()
|
||||
WB_ONE_WF = (
|
||||
type("obj", (object,), {"name": "wb", "definition": WB_DEF_ONE_WF})()
|
||||
)
|
||||
|
||||
|
||||
class MistralExecutionsTestCase(test.ScenarioTestCase):
|
||||
|
||||
@mock.patch("%s.ListExecutions._list_executions" % BASE)
|
||||
def test_list_executions(self, mock__list_executions):
|
||||
executions.ListExecutions(self.context).run()
|
||||
self.assertEqual(1, mock__list_executions.called)
|
||||
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_workbook" % BASE,
|
||||
return_value=WB)
|
||||
def test_create_execution(self, mock__create_workbook,
|
||||
mock__create_execution):
|
||||
|
||||
executions.CreateExecutionFromWorkbook(self.context).run(WB_DEFINITION)
|
||||
|
||||
self.assertEqual(1, mock__create_workbook.called)
|
||||
self.assertEqual(1, mock__create_execution.called)
|
||||
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_workbook" % BASE,
|
||||
return_value=WB)
|
||||
def test_create_execution_with_wf_name(self, mock__create_workbook,
|
||||
mock__create_execution):
|
||||
|
||||
executions.CreateExecutionFromWorkbook(self.context).run(
|
||||
WB_DEFINITION, "wf4")
|
||||
|
||||
self.assertEqual(1, mock__create_workbook.called)
|
||||
self.assertEqual(1, mock__create_execution.called)
|
||||
|
||||
# we concatenate workbook name with the workflow name in the test
|
||||
# the workbook name is not random because we mock the method that
|
||||
# adds the random part
|
||||
mock__create_execution.assert_called_once_with("wb.wf4")
|
||||
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._delete_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._delete_workbook" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_workbook" % BASE,
|
||||
return_value=WB)
|
||||
def test_create_delete_execution(
|
||||
self, mock__create_workbook, mock__create_execution,
|
||||
mock__delete_workbook, mock__delete_execution):
|
||||
|
||||
executions.CreateExecutionFromWorkbook(self.context).run(
|
||||
WB_DEFINITION, do_delete=True)
|
||||
|
||||
self.assertEqual(1, mock__create_workbook.called)
|
||||
self.assertEqual(1, mock__create_execution.called)
|
||||
self.assertEqual(1, mock__delete_workbook.called)
|
||||
self.assertEqual(1, mock__delete_execution.called)
|
||||
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._delete_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._delete_workbook" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_workbook" % BASE,
|
||||
return_value=WB)
|
||||
def test_create_delete_execution_with_wf_name(
|
||||
self, mock__create_workbook, mock__create_execution,
|
||||
mock__delete_workbook, mock__delete_execution):
|
||||
|
||||
executions.CreateExecutionFromWorkbook(self.context).run(
|
||||
WB_DEFINITION, "wf4", do_delete=True)
|
||||
|
||||
self.assertEqual(1, mock__create_workbook.called)
|
||||
self.assertEqual(1, mock__create_execution.called)
|
||||
self.assertEqual(1, mock__delete_workbook.called)
|
||||
self.assertEqual(1, mock__delete_execution.called)
|
||||
|
||||
# we concatenate workbook name with the workflow name in the test
|
||||
# the workbook name is not random because we mock the method that
|
||||
# adds the random part
|
||||
mock__create_execution.assert_called_once_with("wb.wf4")
|
||||
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._delete_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._delete_workbook" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_execution" % BASE)
|
||||
@mock.patch("%s.CreateExecutionFromWorkbook._create_workbook" % BASE,
|
||||
return_value=WB_ONE_WF)
|
||||
def test_create_delete_execution_without_wf_name(
|
||||
self, mock__create_workbook, mock__create_execution,
|
||||
mock__delete_workbook, mock__delete_execution):
|
||||
|
||||
executions.CreateExecutionFromWorkbook(self.context).run(
|
||||
WB_DEF_ONE_WF, do_delete=True)
|
||||
|
||||
self.assertEqual(1, mock__create_workbook.called)
|
||||
self.assertEqual(1, mock__create_execution.called)
|
||||
self.assertEqual(1, mock__delete_workbook.called)
|
||||
self.assertEqual(1, mock__delete_execution.called)
|
||||
|
||||
# we concatenate workbook name with the workflow name in the test
|
||||
# the workbook name is not random because we mock the method that
|
||||
# adds the random part
|
||||
mock__create_execution.assert_called_once_with("wb.wf1")
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from rally.plugins.openstack.scenarios.mistral import utils
|
||||
from tests.unit import fakes
|
||||
from tests.unit import test
|
||||
|
||||
MISTRAL_UTILS = "rally.plugins.openstack.scenarios.mistral.utils"
|
||||
@ -27,21 +28,77 @@ class MistralScenarioTestCase(test.ScenarioTestCase):
|
||||
self.assertEqual(
|
||||
self.clients("mistral").workbooks.list.return_value,
|
||||
return_wbs_list)
|
||||
self._test_atomic_action_timer(scenario.atomic_actions(),
|
||||
"mistral.list_workbooks")
|
||||
self._test_atomic_action_timer(
|
||||
scenario.atomic_actions(),
|
||||
"mistral.list_workbooks"
|
||||
)
|
||||
|
||||
def test_create_workbook(self):
|
||||
definition = "version: \"2.0\"\nname: wb"
|
||||
scenario = utils.MistralScenario(context=self.context)
|
||||
self.assertEqual(scenario._create_workbook(definition),
|
||||
self.clients("mistral").workbooks.create.return_value)
|
||||
self._test_atomic_action_timer(scenario.atomic_actions(),
|
||||
"mistral.create_workbook")
|
||||
self.assertEqual(
|
||||
self.clients("mistral").workbooks.create.return_value,
|
||||
scenario._create_workbook(definition)
|
||||
)
|
||||
self._test_atomic_action_timer(
|
||||
scenario.atomic_actions(),
|
||||
"mistral.create_workbook"
|
||||
)
|
||||
|
||||
def test_delete_workbook(self):
|
||||
scenario = utils.MistralScenario(context=self.context)
|
||||
scenario._delete_workbook("wb_name")
|
||||
self.clients("mistral").workbooks.delete.assert_called_once_with(
|
||||
"wb_name")
|
||||
self._test_atomic_action_timer(scenario.atomic_actions(),
|
||||
"mistral.delete_workbook")
|
||||
"wb_name"
|
||||
)
|
||||
self._test_atomic_action_timer(
|
||||
scenario.atomic_actions(),
|
||||
"mistral.delete_workbook"
|
||||
)
|
||||
|
||||
def test_list_executions(self):
|
||||
scenario = utils.MistralScenario(context=self.context)
|
||||
return_executions_list = scenario._list_executions()
|
||||
self.assertEqual(
|
||||
return_executions_list,
|
||||
self.clients("mistral").executions.list.return_value
|
||||
)
|
||||
self._test_atomic_action_timer(
|
||||
scenario.atomic_actions(),
|
||||
"mistral.list_executions"
|
||||
)
|
||||
|
||||
def test_create_execution(self):
|
||||
scenario = utils.MistralScenario(context=self.context)
|
||||
|
||||
mock_wait_for_status = self.mock_wait_for_status.mock
|
||||
wf_name = "fake_wf_name"
|
||||
mock_create_exec = self.clients("mistral").executions.create
|
||||
|
||||
self.assertEqual(
|
||||
mock_wait_for_status.return_value,
|
||||
scenario._create_execution("%s" % wf_name)
|
||||
)
|
||||
|
||||
mock_create_exec.assert_called_once_with(wf_name)
|
||||
|
||||
args, kwargs = mock_wait_for_status.call_args
|
||||
self.assertEqual(mock_create_exec.return_value, args[0])
|
||||
self.assertEqual(["ERROR"], kwargs["failure_statuses"])
|
||||
self.assertEqual(["SUCCESS"], kwargs["ready_statuses"])
|
||||
self._test_atomic_action_timer(
|
||||
scenario.atomic_actions(),
|
||||
"mistral.create_execution"
|
||||
)
|
||||
|
||||
def test_delete_execution(self):
|
||||
scenario = utils.MistralScenario(context=self.context)
|
||||
execution = fakes.FakeMistralClient().execution.create()
|
||||
scenario._delete_execution(execution)
|
||||
self.clients("mistral").executions.delete.assert_called_once_with(
|
||||
execution.id
|
||||
)
|
||||
self._test_atomic_action_timer(
|
||||
scenario.atomic_actions(),
|
||||
"mistral.delete_execution"
|
||||
)
|
@ -974,3 +974,44 @@ class ValidatorsTestCase(test.TestCase):
|
||||
config = {"context": {"api_versions": {"nova": {"version": 2}}}}
|
||||
self.assertEqual(validator(config, clients, None).is_valid,
|
||||
valid)
|
||||
|
||||
@mock.patch(
|
||||
"yaml.safe_load",
|
||||
return_value={
|
||||
"version": "2.0",
|
||||
"name": "wb",
|
||||
"workflows": {
|
||||
"wf1": {
|
||||
"type": "direct",
|
||||
"tasks": {
|
||||
"t1": {
|
||||
"action": "std.noop"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@mock.patch(MODULE + "os.access")
|
||||
@mock.patch(MODULE + "open")
|
||||
def test_workbook_contains_workflow(self, mock_open, mock_access,
|
||||
mock_safe_load):
|
||||
|
||||
validator = self._unwrap_validator(
|
||||
validation.workbook_contains_workflow, "definition",
|
||||
"workflow_name")
|
||||
clients = mock.MagicMock()
|
||||
|
||||
context = {
|
||||
"args": {
|
||||
"definition": "fake_path1",
|
||||
"workflow_name": "wf1"
|
||||
}
|
||||
}
|
||||
|
||||
result = validator(context, clients, None)
|
||||
self.assertTrue(result.is_valid)
|
||||
|
||||
self.assertEqual(1, mock_open.called)
|
||||
self.assertEqual(1, mock_access.called)
|
||||
self.assertEqual(1, mock_safe_load.called)
|
||||
|
Loading…
Reference in New Issue
Block a user