[core] Refactor validation
* do not save validation errors from CLI layer to database. It includes such redundant data as IOError (when task file doesn't exist) * include validation at task start by default. It is bad sign to allow starting tasks without validation. Change-Id: I0d30ff31fb6fbc467ef3cda01e7de1f46c5f79fe
This commit is contained in:
parent
7cfe24b249
commit
8b28bdee7b
65
rally/api.py
65
rally/api.py
|
@ -241,6 +241,7 @@ class _Task(object):
|
|||
task["results"] = objects.Task.extend_results(task["results"])
|
||||
return task
|
||||
|
||||
# TODO(andreykurilin): move it to some kind of utils
|
||||
@classmethod
|
||||
def render_template(cls, task_template, template_dir="./", **kwargs):
|
||||
"""Render jinja2 task template to Rally input task.
|
||||
|
@ -346,40 +347,78 @@ class _Task(object):
|
|||
tag=tag)
|
||||
|
||||
@classmethod
|
||||
def validate(cls, deployment, config, task_instance=None):
|
||||
def validate(cls, deployment, config, task_instance=None, task=None):
|
||||
"""Validate a task config against specified deployment.
|
||||
|
||||
:param deployment: UUID or name of the deployment
|
||||
:param deployment: UUID or name of the deployment (will be ignored in
|
||||
case of transmitting task_instance or task arguments)
|
||||
:param config: a dict with a task configuration
|
||||
:param task_instance: DEPRECATED. Use "task" argument to transmit task
|
||||
uuid instead
|
||||
"""
|
||||
if task_instance is not None:
|
||||
LOG.warning("Transmitting task object in `task validate` is "
|
||||
"deprecated since Rally 0.10. To use pre-created "
|
||||
"task, transmit task UUID instead via `task` "
|
||||
"argument.")
|
||||
task = objects.Task.get(task_instance["uuid"])
|
||||
deployment = task["deployment_uuid"]
|
||||
elif task:
|
||||
task = objects.Task.get(task)
|
||||
deployment = task["deployment_uuid"]
|
||||
else:
|
||||
task = objects.Task(deployment_uuid=deployment, temporary=True)
|
||||
deployment = objects.Deployment.get(deployment)
|
||||
task = task_instance or objects.Task(
|
||||
deployment_uuid=deployment["uuid"], temporary=True)
|
||||
benchmark_engine = engine.TaskEngine(config, task, deployment)
|
||||
|
||||
benchmark_engine = engine.TaskEngine(config, task, deployment)
|
||||
benchmark_engine.validate()
|
||||
|
||||
@classmethod
|
||||
def start(cls, deployment, config, task=None, abort_on_sla_failure=False):
|
||||
"""Start a task.
|
||||
"""Validate and start a task.
|
||||
|
||||
Task is a list of benchmarks that will be called one by one, results of
|
||||
execution will be stored in DB.
|
||||
|
||||
:param deployment: UUID or name of the deployment
|
||||
:param deployment: UUID or name of the deployment (will be ignored in
|
||||
case of transmitting existing task)
|
||||
:param config: a dict with a task configuration
|
||||
:param task: Task object. If None, it will be created
|
||||
:param task: Task UUID to use pre-created task. If None, new task will
|
||||
be created
|
||||
:param abort_on_sla_failure: If set to True, the task execution will
|
||||
stop when any SLA check for it fails
|
||||
"""
|
||||
if task and isinstance(task, objects.Task):
|
||||
LOG.warning("Transmitting task object in `task start` is "
|
||||
"deprecated since Rally 0.10. To use pre-created "
|
||||
"task, transmit task UUID instead.")
|
||||
if task.is_temporary:
|
||||
raise ValueError(_(
|
||||
"Unable to run a temporary task. Please check your code."))
|
||||
task = objects.Task.get(task["uuid"])
|
||||
elif task is not None:
|
||||
task = objects.Task.get(task)
|
||||
|
||||
if task is not None:
|
||||
deployment = task["deployment_uuid"]
|
||||
|
||||
deployment = objects.Deployment.get(deployment)
|
||||
if deployment["status"] != consts.DeployStatus.DEPLOY_FINISHED:
|
||||
raise exceptions.DeploymentNotFinishedStatus(
|
||||
name=deployment["name"],
|
||||
uuid=deployment["uuid"],
|
||||
status=deployment["status"])
|
||||
|
||||
task = task or objects.Task(deployment_uuid=deployment["uuid"])
|
||||
if task is None:
|
||||
task = objects.Task(deployment_uuid=deployment["uuid"])
|
||||
|
||||
if task.is_temporary:
|
||||
raise ValueError(_(
|
||||
"Unable to run a temporary task. Please check your code."))
|
||||
benchmark_engine = engine.TaskEngine(
|
||||
config, task, deployment,
|
||||
abort_on_sla_failure=abort_on_sla_failure)
|
||||
|
||||
benchmark_engine.validate()
|
||||
|
||||
LOG.info("Task %s config is valid." % task["uuid"])
|
||||
LOG.info("Benchmark Task %s on Deployment %s" % (task["uuid"],
|
||||
deployment["uuid"]))
|
||||
|
||||
|
@ -393,6 +432,8 @@ class _Task(object):
|
|||
deployment.update_status(consts.DeployStatus.DEPLOY_INCONSISTENT)
|
||||
raise
|
||||
|
||||
return task["uuid"], task.get_status(task["uuid"])
|
||||
|
||||
@classmethod
|
||||
def abort(cls, task_uuid, soft=False, async=True):
|
||||
"""Abort running task.
|
||||
|
|
|
@ -19,7 +19,6 @@ from __future__ import print_function
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
import webbrowser
|
||||
|
||||
import jsonschema
|
||||
|
@ -47,7 +46,7 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class FailedToLoadTask(exceptions.RallyException):
|
||||
msg_fmt = _("Failed to load task")
|
||||
msg_fmt = _("Invalid %(source)s passed:\n\n\t %(msg)s")
|
||||
|
||||
|
||||
class TaskCommands(object):
|
||||
|
@ -55,101 +54,86 @@ class TaskCommands(object):
|
|||
|
||||
"""
|
||||
|
||||
def _load_task(self, api, task_file, task_args=None, task_args_file=None):
|
||||
"""Load tasks template from file and render it with passed args.
|
||||
def _load_and_validate_task(self, api, task_file, args_file=None,
|
||||
raw_args=None):
|
||||
"""Load, render and validate tasks template from file with passed args.
|
||||
|
||||
:param task_file: Path to file with input task
|
||||
:param task_args: JSON or YAML representation of dict with args that
|
||||
will be used to render input task with jinja2
|
||||
:param task_args_file: Path to file with JSON or YAML representation
|
||||
of dict, that will be used to render input
|
||||
with jinja2. If both specified task_args and
|
||||
task_args_file they will be merged. task_args
|
||||
has bigger priority so it will update values
|
||||
from task_args_file.
|
||||
:param raw_args: JSON or YAML representation of dict with args that
|
||||
will be used to render input task with jinja2
|
||||
:param args_file: Path to file with JSON or YAML representation
|
||||
of dict, that will be used to render input with jinja2. If both
|
||||
specified task_args and task_args_file they will be merged.
|
||||
raw_args has bigger priority so it will update values
|
||||
from args_file.
|
||||
:returns: Str with loaded and rendered task
|
||||
"""
|
||||
|
||||
print(cliutils.make_header("Preparing input task"))
|
||||
|
||||
def print_invalid_header(source_name, args):
|
||||
print(_("Invalid %(source)s passed: \n\n %(args)s \n")
|
||||
% {"source": source_name, "args": args},
|
||||
file=sys.stderr)
|
||||
|
||||
def parse_task_args(src_name, args):
|
||||
try:
|
||||
kw = args and yaml.safe_load(args)
|
||||
kw = {} if kw is None else kw
|
||||
except yaml.ParserError as e:
|
||||
print_invalid_header(src_name, args)
|
||||
print(_("%(source)s has to be YAML or JSON. Details:"
|
||||
"\n\n%(err)s\n")
|
||||
% {"source": src_name, "err": e},
|
||||
file=sys.stderr)
|
||||
raise TypeError()
|
||||
|
||||
if not isinstance(kw, dict):
|
||||
print_invalid_header(src_name, args)
|
||||
print(_("%(src)s has to be dict, actually %(src_type)s\n")
|
||||
% {"src": src_name, "src_type": type(kw)},
|
||||
file=sys.stderr)
|
||||
raise TypeError()
|
||||
return kw
|
||||
|
||||
try:
|
||||
kw = {}
|
||||
if task_args_file:
|
||||
with open(task_args_file) as f:
|
||||
kw.update(parse_task_args("task_args_file", f.read()))
|
||||
kw.update(parse_task_args("task_args", task_args))
|
||||
except TypeError:
|
||||
raise FailedToLoadTask()
|
||||
|
||||
if not os.path.isfile(task_file):
|
||||
raise FailedToLoadTask(source="--task",
|
||||
msg="File '%s' doesn't exist." % task_file)
|
||||
with open(task_file) as f:
|
||||
input_task = f.read()
|
||||
task_dir = os.path.expanduser(os.path.dirname(task_file)) or "./"
|
||||
|
||||
task_args = {}
|
||||
if args_file:
|
||||
if not os.path.isfile(args_file):
|
||||
raise FailedToLoadTask(
|
||||
source="--task-args-file",
|
||||
msg="File '%s' doesn't exist." % args_file)
|
||||
with open(args_file) as f:
|
||||
try:
|
||||
task_args.update(yaml.safe_load(f.read()))
|
||||
except yaml.ParserError as e:
|
||||
raise FailedToLoadTask(
|
||||
source="--task-args-file",
|
||||
msg="File '%s' has to be YAML or JSON. Details:\n\n%s"
|
||||
% (args_file, e))
|
||||
if raw_args:
|
||||
try:
|
||||
input_task = f.read()
|
||||
task_dir = os.path.expanduser(
|
||||
os.path.dirname(task_file)) or "./"
|
||||
rendered_task = api.task.render_template(input_task,
|
||||
task_dir, **kw)
|
||||
except Exception as e:
|
||||
print(_("Failed to render task template:\n%(task)s\n%(err)s\n")
|
||||
% {"task": input_task, "err": e},
|
||||
file=sys.stderr)
|
||||
raise FailedToLoadTask()
|
||||
data = yaml.safe_load(raw_args)
|
||||
if isinstance(data, (six.text_type, six.string_types)):
|
||||
raise yaml.ParserError("String '%s' doesn't look like a "
|
||||
"dictionary." % raw_args)
|
||||
task_args.update(data)
|
||||
except yaml.ParserError as e:
|
||||
args = [keypair.split("=", 1)
|
||||
for keypair in raw_args.split(",")]
|
||||
if len([a for a in args if len(a) != 1]) != len(args):
|
||||
raise FailedToLoadTask(
|
||||
source="--task-args",
|
||||
msg="Value has to be YAML or JSON. Details:\n\n%s" % e)
|
||||
else:
|
||||
task_args.update(dict(args))
|
||||
|
||||
print(_("Task is:\n%s\n") % rendered_task)
|
||||
try:
|
||||
parsed_task = yaml.safe_load(rendered_task)
|
||||
|
||||
except Exception as e:
|
||||
print(_("Wrong format of rendered input task. It should be "
|
||||
"YAML or JSON.\n%s") % e,
|
||||
file=sys.stderr)
|
||||
raise FailedToLoadTask()
|
||||
|
||||
print(_("Task syntax is correct :)"))
|
||||
return parsed_task
|
||||
|
||||
def _load_and_validate_task(self, api, task, task_args, task_args_file,
|
||||
deployment, task_instance=None):
|
||||
try:
|
||||
input_task = self._load_task(api, task, task_args, task_args_file)
|
||||
except Exception as err:
|
||||
if task_instance:
|
||||
task_instance.set_validation_failed({
|
||||
"etype": err.__class__.__name__,
|
||||
"msg": str(err),
|
||||
"trace": json.dumps(traceback.format_exc())})
|
||||
raise
|
||||
api.task.validate(deployment, input_task, task_instance)
|
||||
print(_("Task config is valid :)"))
|
||||
return input_task
|
||||
rendered_task = api.task.render_template(input_task, task_dir,
|
||||
**task_args)
|
||||
except Exception as e:
|
||||
raise FailedToLoadTask(
|
||||
source="--task",
|
||||
msg="Failed to render task template.\n\n%s" % e)
|
||||
|
||||
print(_("Task is:\n%s\n") % rendered_task.strip())
|
||||
try:
|
||||
parsed_task = yaml.safe_load(rendered_task)
|
||||
except Exception as e:
|
||||
raise FailedToLoadTask(
|
||||
source="--task",
|
||||
msg="Wrong format of rendered input task. It should be YAML or"
|
||||
" JSON. Details:\n\n%s" % e)
|
||||
|
||||
print(_("Task syntax is correct :)"))
|
||||
return parsed_task
|
||||
|
||||
@cliutils.args("--deployment", dest="deployment", type=str,
|
||||
metavar="<uuid>", required=False,
|
||||
help="UUID or name of a deployment.")
|
||||
@cliutils.args("--task", "--filename", metavar="<path>",
|
||||
dest="task_file",
|
||||
help="Path to the input task file.")
|
||||
@cliutils.args("--task-args", metavar="<json>", dest="task_args",
|
||||
help="Input task args (JSON dict). These args are used "
|
||||
|
@ -160,7 +144,7 @@ class TaskCommands(object):
|
|||
"to render the Jinja2 template in the input task.")
|
||||
@envutils.with_default_deployment(cli_arg_name="deployment")
|
||||
@plugins.ensure_plugins_are_loaded
|
||||
def validate(self, api, task, deployment=None, task_args=None,
|
||||
def validate(self, api, task_file, deployment=None, task_args=None,
|
||||
task_args_file=None):
|
||||
"""Validate a task configuration file.
|
||||
|
||||
|
@ -171,7 +155,7 @@ class TaskCommands(object):
|
|||
be merged. task_args has a higher priority so it will override
|
||||
values from task_args_file.
|
||||
|
||||
:param task: Path to the input task file.
|
||||
:param task_file: Path to the input task file.
|
||||
:param task_args: Input task args (JSON dict). These args are
|
||||
used to render the Jinja2 template in the
|
||||
input task.
|
||||
|
@ -181,19 +165,20 @@ class TaskCommands(object):
|
|||
the input task.
|
||||
:param deployment: UUID or name of the deployment
|
||||
"""
|
||||
try:
|
||||
self._load_and_validate_task(api, task, task_args, task_args_file,
|
||||
deployment)
|
||||
|
||||
except (exceptions.InvalidTaskException, FailedToLoadTask) as e:
|
||||
print(e, file=sys.stderr)
|
||||
return(1)
|
||||
task = self._load_and_validate_task(api, task_file, raw_args=task_args,
|
||||
args_file=task_args_file)
|
||||
|
||||
api.task.validate(deployment, config=task)
|
||||
|
||||
print(_("Task config is valid :)"))
|
||||
|
||||
@cliutils.args("--deployment", dest="deployment", type=str,
|
||||
metavar="<uuid>", required=False,
|
||||
help="UUID or name of a deployment.")
|
||||
@cliutils.args("--task", "--filename", metavar="<path>",
|
||||
help="Path to the input task file")
|
||||
dest="task_file",
|
||||
help="Path to the input task file.")
|
||||
@cliutils.args("--task-args", dest="task_args", metavar="<json>",
|
||||
help="Input task args (JSON dict). These args are used "
|
||||
"to render the Jinja2 template in the input task.")
|
||||
|
@ -210,7 +195,7 @@ class TaskCommands(object):
|
|||
"any SLA check for it fails.")
|
||||
@envutils.with_default_deployment(cli_arg_name="deployment")
|
||||
@plugins.ensure_plugins_are_loaded
|
||||
def start(self, api, task, deployment=None, task_args=None,
|
||||
def start(self, api, task_file, deployment=None, task_args=None,
|
||||
task_args_file=None, tag=None, do_use=False,
|
||||
abort_on_sla_failure=False):
|
||||
"""Start benchmark task.
|
||||
|
@ -219,7 +204,7 @@ class TaskCommands(object):
|
|||
be merged. task_args has a higher priority so it will override
|
||||
values from task_args_file.
|
||||
|
||||
:param task: Path to the input task file.
|
||||
:param task_file: Path to the input task file.
|
||||
:param task_args: Input task args (JSON dict). These args are
|
||||
used to render the Jinja2 template in the
|
||||
input task.
|
||||
|
@ -236,18 +221,18 @@ class TaskCommands(object):
|
|||
for it fails
|
||||
"""
|
||||
|
||||
input_task = self._load_and_validate_task(api, task_file,
|
||||
raw_args=task_args,
|
||||
args_file=task_args_file)
|
||||
print("Running Rally version", version.version_string())
|
||||
|
||||
try:
|
||||
task_instance = api.task.create(deployment, tag)
|
||||
|
||||
print("Running Rally version", version.version_string())
|
||||
input_task = self._load_and_validate_task(
|
||||
api, task, task_args, task_args_file, deployment,
|
||||
task_instance=task_instance)
|
||||
|
||||
print(cliutils.make_header(
|
||||
_("Task %(tag)s %(uuid)s: started")
|
||||
% {"uuid": task_instance["uuid"],
|
||||
"tag": task_instance["tag"]}))
|
||||
_("Task %(tag)s %(uuid)s: started")
|
||||
% {"uuid": task_instance["uuid"],
|
||||
"tag": task_instance["tag"]}))
|
||||
print("Benchmarking... This can take a while...\n")
|
||||
print("To track task status use:\n")
|
||||
print("\trally task status\n\tor\n\trally task detailed\n")
|
||||
|
@ -255,20 +240,14 @@ class TaskCommands(object):
|
|||
if do_use:
|
||||
self.use(api, task_instance["uuid"])
|
||||
|
||||
api.task.start(deployment, input_task, task=task_instance,
|
||||
api.task.start(deployment, input_task, task=task_instance["uuid"],
|
||||
abort_on_sla_failure=abort_on_sla_failure)
|
||||
self.detailed(api, task_id=task_instance["uuid"])
|
||||
|
||||
except exceptions.DeploymentNotFinishedStatus as e:
|
||||
print(_("Cannot start a task on unfinished deployment: %s") % e)
|
||||
return 1
|
||||
except (exceptions.InvalidTaskException, FailedToLoadTask) as e:
|
||||
task_instance.set_validation_failed({
|
||||
"etype": type(e).__name__,
|
||||
"msg": str(e),
|
||||
"trace": json.dumps(traceback.format_exc())})
|
||||
print(e, file=sys.stderr)
|
||||
return(1)
|
||||
|
||||
self.detailed(api, task_id=task_instance["uuid"])
|
||||
|
||||
@cliutils.args("--uuid", type=str, dest="task_id", help="UUID of task.")
|
||||
@envutils.with_default_task_id
|
||||
|
|
|
@ -389,6 +389,8 @@ class Task(object):
|
|||
def _update(self, values):
|
||||
if not self.is_temporary:
|
||||
self.task = db.task_update(self.task["uuid"], values)
|
||||
else:
|
||||
self.task.update(values)
|
||||
|
||||
def update_status(self, status, allowed_statuses=None):
|
||||
if allowed_statuses:
|
||||
|
|
|
@ -20,10 +20,11 @@ import os.path
|
|||
|
||||
import ddt
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
import rally
|
||||
from rally import api
|
||||
from rally.cli.commands import task
|
||||
from rally.common import yamlutils as yaml
|
||||
from rally import consts
|
||||
from rally import exceptions
|
||||
from tests.unit import fakes
|
||||
|
@ -41,86 +42,136 @@ class TaskCommandsTestCase(test.TestCase):
|
|||
with mock.patch("rally.api.API.check_db_revision"):
|
||||
self.real_api = api.API()
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile")
|
||||
@mock.patch("rally.cli.commands.task.open", create=True)
|
||||
def test__load_task(self, mock_open):
|
||||
def test__load_and_validate_task(self, mock_open, mock_isfile):
|
||||
input_task = "{'ab': {{test}}}"
|
||||
input_args = "{'test': 2}"
|
||||
|
||||
# NOTE(boris-42): Such order of files is because we are reading
|
||||
# file with args before file with template.
|
||||
mock_open.side_effect = [
|
||||
mock.mock_open(read_data="{'test': 1}").return_value,
|
||||
mock.mock_open(read_data=input_task).return_value
|
||||
mock.mock_open(read_data=input_task).return_value,
|
||||
mock.mock_open(read_data="{'test': 1}").return_value
|
||||
]
|
||||
task_conf = self.task._load_task(
|
||||
self.real_api, "in_task", task_args_file="in_args_path")
|
||||
task_conf = self.task._load_and_validate_task(
|
||||
self.real_api, "in_task", args_file="in_args_path")
|
||||
self.assertEqual({"ab": 1}, task_conf)
|
||||
|
||||
mock_open.side_effect = [
|
||||
mock.mock_open(read_data=input_task).return_value
|
||||
]
|
||||
task_conf = self.task._load_task(
|
||||
self.real_api, "in_task", task_args=input_args)
|
||||
task_conf = self.task._load_and_validate_task(
|
||||
self.real_api, "in_task", raw_args=input_args)
|
||||
self.assertEqual(task_conf, {"ab": 2})
|
||||
|
||||
mock_open.side_effect = [
|
||||
mock.mock_open(read_data="{'test': 1}").return_value,
|
||||
mock.mock_open(read_data=input_task).return_value
|
||||
|
||||
mock.mock_open(read_data=input_task).return_value,
|
||||
mock.mock_open(read_data="{'test': 1}").return_value
|
||||
]
|
||||
task_conf = self.task._load_task(
|
||||
self.real_api, "in_task", task_args=input_args,
|
||||
task_args_file="any_file")
|
||||
task_conf = self.task._load_and_validate_task(
|
||||
self.real_api, "in_task", raw_args=input_args,
|
||||
args_file="any_file")
|
||||
self.assertEqual(task_conf, {"ab": 2})
|
||||
|
||||
@mock.patch("rally.cli.commands.task.open", create=True)
|
||||
def test__load_task_wrong_task_args_file(self, mock_open):
|
||||
mock_open.side_effect = [
|
||||
mock.mock_open(read_data="{'test': {}").return_value
|
||||
mock.mock_open(read_data=input_task).return_value,
|
||||
mock.mock_open(read_data="{'test': 1}").return_value
|
||||
]
|
||||
self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_task,
|
||||
self.fake_api, "in_task",
|
||||
task_args_file="in_args_path")
|
||||
task_conf = self.task._load_and_validate_task(
|
||||
self.real_api, "in_task", raw_args="test=2",
|
||||
args_file="any_file")
|
||||
self.assertEqual(task_conf, {"ab": 2})
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile")
|
||||
def test__load_task_wrong_task_args_file(self, mock_isfile):
|
||||
mock_isfile.side_effect = (True, False)
|
||||
# use real file to avoid mocking open
|
||||
task_file = __file__
|
||||
|
||||
e = self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_and_validate_task,
|
||||
self.fake_api, task_file=task_file,
|
||||
args_file="in_args_path")
|
||||
self.assertEqual("Invalid --task-args-file passed:\n\n\t File "
|
||||
"'in_args_path' doesn't exist.", e.format_message())
|
||||
|
||||
@mock.patch("rally.cli.commands.task.yaml.safe_load")
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile")
|
||||
def test__load_task_wrong_input_task_args(self, mock_isfile,
|
||||
mock_safe_load):
|
||||
mock_safe_load.side_effect = yaml.ParserError("foo")
|
||||
mock_isfile.side_effect = (True, False)
|
||||
# use real file to avoid mocking open
|
||||
task_file = __file__
|
||||
|
||||
e = self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_and_validate_task, self.real_api,
|
||||
task_file, raw_args="{'test': {}")
|
||||
self.assertEqual("Invalid --task-args passed:\n\n\t Value has to be "
|
||||
"YAML or JSON. Details:\n\nfoo", e.format_message())
|
||||
mock_safe_load.assert_called_once_with("{'test': {}")
|
||||
|
||||
# the case #2
|
||||
mock_safe_load.reset_mock()
|
||||
mock_isfile.side_effect = (True, False)
|
||||
e = self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_and_validate_task, self.real_api,
|
||||
task_file, raw_args="[]")
|
||||
self.assertEqual("Invalid --task-args passed:\n\n\t Value has to be "
|
||||
"YAML or JSON. Details:\n\nfoo", e.format_message())
|
||||
mock_safe_load.assert_called_once_with("[]")
|
||||
|
||||
# the case #3
|
||||
mock_safe_load.reset_mock()
|
||||
mock_isfile.side_effect = (True, False)
|
||||
e = self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_and_validate_task, self.real_api,
|
||||
task_file, raw_args="foo")
|
||||
self.assertEqual("Invalid --task-args passed:\n\n\t Value has to be "
|
||||
"YAML or JSON. Details:\n\nfoo", e.format_message())
|
||||
mock_safe_load.assert_called_once_with("foo")
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile")
|
||||
@mock.patch("rally.cli.commands.task.open", create=True)
|
||||
def test__load_task_wrong_task_args_file_exception(self, mock_open):
|
||||
mock_open.side_effect = IOError
|
||||
self.assertRaises(IOError, self.task._load_task, self.fake_api,
|
||||
"in_task", task_args_file="in_args_path")
|
||||
def test__load_task_task_render_raise_exc(self, mock_open, mock_isfile):
|
||||
mock_isfile.side_effect = (True, False)
|
||||
|
||||
def test__load_task_wrong_input_task_args(self):
|
||||
self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_task, self.real_api, "in_task",
|
||||
"{'test': {}")
|
||||
self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_task, self.real_api, "in_task", "[]")
|
||||
|
||||
@mock.patch("rally.cli.commands.task.open", create=True)
|
||||
def test__load_task_task_render_raise_exc(self, mock_open):
|
||||
mock_open.side_effect = [
|
||||
mock.mock_open(read_data="{'test': {{t}}}").return_value
|
||||
]
|
||||
self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_task, self.real_api, "in_task")
|
||||
e = self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_and_validate_task, self.real_api,
|
||||
"in_task")
|
||||
self.assertEqual("Invalid --task passed:\n\n\t Failed to render task "
|
||||
"template.\n\nPlease specify template task argument: "
|
||||
"t", e.format_message())
|
||||
|
||||
@mock.patch("rally.cli.commands.task.yaml")
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile")
|
||||
@mock.patch("rally.cli.commands.task.open", create=True)
|
||||
def test__load_task_task_not_in_yaml(self, mock_open):
|
||||
def test__load_task_task_not_in_yaml(self, mock_open, mock_isfile,
|
||||
mock_yaml):
|
||||
mock_open.side_effect = [
|
||||
mock.mock_open(read_data="{'test': {}").return_value
|
||||
]
|
||||
self.fake_api.task.render_template.return_value = "||"
|
||||
mock_isfile.side_effect = (True, )
|
||||
mock_yaml.safe_load.side_effect = Exception("ERROR!!!PANIC!!!")
|
||||
|
||||
self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_task, self.fake_api, "in_task")
|
||||
e = self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_and_validate_task, self.fake_api,
|
||||
"in_task")
|
||||
self.assertEqual("Invalid --task passed:\n\n\t Wrong format of "
|
||||
"rendered input task. It should be YAML or JSON. "
|
||||
"Details:\n\nERROR!!!PANIC!!!", e.format_message())
|
||||
|
||||
def test_load_task_including_other_template(self):
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
def test_load_task_including_other_template(self, mock_isfile):
|
||||
other_template_path = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..", "..", "..", "..", "samples/tasks/scenarios/nova/boot.json")
|
||||
os.path.dirname(rally.__file__), os.pardir,
|
||||
"samples/tasks/scenarios/nova/boot.json")
|
||||
input_task = "{%% include \"%s\" %%}" % os.path.basename(
|
||||
other_template_path)
|
||||
expect = self.task._load_task(self.real_api, other_template_path)
|
||||
expect = self.task._load_and_validate_task(self.real_api,
|
||||
other_template_path)
|
||||
|
||||
with mock.patch("rally.cli.commands.task.open",
|
||||
create=True) as mock_open:
|
||||
|
@ -129,42 +180,29 @@ class TaskCommandsTestCase(test.TestCase):
|
|||
]
|
||||
input_task_file = os.path.join(
|
||||
os.path.dirname(other_template_path), "input_task.json")
|
||||
actual = self.task._load_task(self.real_api, input_task_file)
|
||||
actual = self.task._load_and_validate_task(self.real_api,
|
||||
input_task_file)
|
||||
self.assertEqual(expect, actual)
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_task",
|
||||
return_value={"uuid": "some_uuid"})
|
||||
def test__load_and_validate_task(self, mock__load_task,
|
||||
mock_os_path_isfile):
|
||||
deployment = "some_deployment_uuid"
|
||||
self.fake_api.task.validate.return_value = fakes.FakeTask()
|
||||
self.task._load_and_validate_task(self.fake_api, "some_task",
|
||||
"task_args", "task_args_file",
|
||||
deployment)
|
||||
mock__load_task.assert_called_once_with(
|
||||
self.fake_api, "some_task", "task_args", "task_args_file")
|
||||
self.fake_api.task.validate.assert_called_once_with(
|
||||
deployment, mock__load_task.return_value, None)
|
||||
|
||||
def test__load_and_validate_file(self):
|
||||
deployment = "some_deployment_uuid"
|
||||
self.assertRaises(IOError, self.task._load_and_validate_task,
|
||||
self.fake_api, "some_task", "task_args",
|
||||
"task_args_file", deployment)
|
||||
def test__load_and_validate_file_failed(self):
|
||||
e = self.assertRaises(task.FailedToLoadTask,
|
||||
self.task._load_and_validate_task,
|
||||
api=self.fake_api, task_file="some_task",
|
||||
raw_args="task_args", args_file="task_args_file")
|
||||
self.assertEqual("Invalid --task passed:\n\n\t File 'some_task' "
|
||||
"doesn't exist.", e.format_message())
|
||||
|
||||
@mock.patch("rally.cli.commands.task.version")
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands.use")
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands.detailed")
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_task",
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_and_validate_task",
|
||||
return_value={"some": "json"})
|
||||
def test_start(self, mock__load_task, mock_detailed, mock_use,
|
||||
mock_os_path_isfile, mock_version):
|
||||
def test_start(self, mock__load_and_validate_task, mock_detailed, mock_use,
|
||||
mock_version):
|
||||
deployment_id = "e0617de9-77d1-4875-9b49-9d5789e29f20"
|
||||
task_path = "path_to_config.json"
|
||||
self.fake_api.task.create.return_value = fakes.FakeTask(
|
||||
uuid="some_new_uuid", tag="tag")
|
||||
fake_task = fakes.FakeTask(uuid="some_new_uuid", tag="tag")
|
||||
self.fake_api.task.create.return_value = fake_task
|
||||
self.fake_api.task.validate.return_value = fakes.FakeTask(
|
||||
some="json", uuid="some_uuid", temporary=True)
|
||||
|
||||
|
@ -173,26 +211,25 @@ class TaskCommandsTestCase(test.TestCase):
|
|||
self.fake_api.task.create.assert_called_once_with(
|
||||
deployment_id, None)
|
||||
self.fake_api.task.start.assert_called_once_with(
|
||||
deployment_id, mock__load_task.return_value,
|
||||
task=self.fake_api.task.validate.return_value,
|
||||
deployment_id, mock__load_and_validate_task.return_value,
|
||||
task=fake_task["uuid"],
|
||||
abort_on_sla_failure=False)
|
||||
mock__load_task.assert_called_once_with(
|
||||
self.fake_api, task_path, None, None)
|
||||
mock__load_and_validate_task.assert_called_once_with(
|
||||
self.fake_api, task_path, args_file=None, raw_args=None)
|
||||
mock_use.assert_called_once_with(self.fake_api, "some_new_uuid")
|
||||
mock_detailed.assert_called_once_with(self.fake_api,
|
||||
task_id="some_new_uuid")
|
||||
task_id=fake_task["uuid"])
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands.detailed")
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_task",
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_and_validate_task",
|
||||
return_value="some_config")
|
||||
def test_start_on_unfinished_deployment(
|
||||
self, mock__load_task, mock_detailed, mock_os_path_isfile):
|
||||
def test_start_on_unfinished_deployment(self, mock__load_and_validate_task,
|
||||
mock_detailed):
|
||||
deployment_id = "e0617de9-77d1-4875-9b49-9d5789e29f20"
|
||||
deployment_name = "xxx_name"
|
||||
task_path = "path_to_config.json"
|
||||
self.fake_api.task.create.return_value = fakes.FakeTask(
|
||||
uuid="some_new_uuid", tag="tag")
|
||||
fake_task = fakes.FakeTask(uuid="some_new_uuid", tag="tag")
|
||||
self.fake_api.task.create.return_value = fake_task
|
||||
|
||||
exc = exceptions.DeploymentNotFinishedStatus(
|
||||
name=deployment_name,
|
||||
|
@ -201,13 +238,14 @@ class TaskCommandsTestCase(test.TestCase):
|
|||
self.fake_api.task.create.side_effect = exc
|
||||
self.assertEqual(1, self.task.start(self.fake_api, task_path,
|
||||
deployment="any", tag="some_tag"))
|
||||
self.assertFalse(mock_detailed.called)
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands.detailed")
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_task",
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_and_validate_task",
|
||||
return_value="some_config")
|
||||
def test_start_with_task_args(self, mock__load_task, mock_detailed,
|
||||
mock_os_path_isfile):
|
||||
def test_start_with_task_args(self, mock__load_and_validate_task,
|
||||
mock_detailed):
|
||||
fake_task = fakes.FakeTask(uuid="new_uuid", tag="some_tag")
|
||||
self.fake_api.task.create.return_value = fakes.FakeTask(
|
||||
uuid="new_uuid", tag="some_tag")
|
||||
self.fake_api.task.validate.return_value = fakes.FakeTask(
|
||||
|
@ -219,17 +257,18 @@ class TaskCommandsTestCase(test.TestCase):
|
|||
self.task.start(self.fake_api, task_path, deployment="any",
|
||||
task_args=task_args, task_args_file=task_args_file,
|
||||
tag="some_tag")
|
||||
mock__load_task.assert_called_once_with(
|
||||
self.fake_api, task_path, task_args, task_args_file)
|
||||
self.fake_api.task.validate.assert_called_once_with(
|
||||
"any", mock__load_task.return_value, {})
|
||||
|
||||
mock__load_and_validate_task.assert_called_once_with(
|
||||
self.fake_api, task_path, raw_args=task_args,
|
||||
args_file=task_args_file)
|
||||
|
||||
self.fake_api.task.start.assert_called_once_with(
|
||||
"any", mock__load_task.return_value,
|
||||
task=self.fake_api.task.create.return_value,
|
||||
"any", mock__load_and_validate_task.return_value,
|
||||
task=fake_task["uuid"],
|
||||
abort_on_sla_failure=False)
|
||||
mock_detailed.assert_called_once_with(
|
||||
self.fake_api,
|
||||
task_id=self.fake_api.task.create.return_value["uuid"])
|
||||
task_id=fake_task["uuid"])
|
||||
self.fake_api.task.create.assert_called_once_with("any", "some_tag")
|
||||
|
||||
@mock.patch("rally.cli.commands.task.envutils.get_global")
|
||||
|
@ -238,25 +277,41 @@ class TaskCommandsTestCase(test.TestCase):
|
|||
self.assertRaises(exceptions.InvalidArgumentsException,
|
||||
self.task.start, "path_to_config.json", None)
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_task",
|
||||
return_value={"some": "json"})
|
||||
def test_start_invalid_task(self, mock__load_task, mock_os_path_isfile):
|
||||
self.fake_api.task.create.return_value = fakes.FakeTask(
|
||||
temporary=False, tag="tag", uuid="uuid")
|
||||
exc = exceptions.InvalidTaskException
|
||||
self.fake_api.task.start.side_effect = exc
|
||||
result = self.task.start(self.fake_api, "task_path", "deployment",
|
||||
tag="tag")
|
||||
self.assertEqual(1, result)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands.detailed")
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_and_validate_task")
|
||||
def test_start_invalid_task(self, mock__load_and_validate_task,
|
||||
mock_detailed):
|
||||
task_obj = fakes.FakeTask(temporary=False, tag="tag", uuid="uuid")
|
||||
self.fake_api.task.create.return_value = task_obj
|
||||
exc = exceptions.InvalidTaskException("foo")
|
||||
|
||||
mock__load_and_validate_task.side_effect = exc
|
||||
|
||||
self.assertRaises(exceptions.InvalidTaskException,
|
||||
self.task.start, self.fake_api, "task_path",
|
||||
"deployment", tag="tag")
|
||||
|
||||
self.assertFalse(self.fake_api.task.create.called)
|
||||
self.assertFalse(self.fake_api.task.start.called)
|
||||
|
||||
# the case 2
|
||||
task_cfg = {"some": "json"}
|
||||
mock__load_and_validate_task.side_effect = (task_cfg, )
|
||||
self.fake_api.task.start.side_effect = KeyError()
|
||||
|
||||
self.assertRaises(KeyError,
|
||||
self.task.start, self.fake_api, "task_path",
|
||||
"deployment", tag="tag")
|
||||
|
||||
self.fake_api.task.create.assert_called_once_with("deployment", "tag")
|
||||
|
||||
self.fake_api.task.start.assert_called_once_with(
|
||||
"deployment", mock__load_task.return_value,
|
||||
task=self.fake_api.task.create.return_value,
|
||||
"deployment", task_cfg,
|
||||
task=task_obj["uuid"],
|
||||
abort_on_sla_failure=False)
|
||||
|
||||
self.assertFalse(mock_detailed.called)
|
||||
|
||||
def test_abort(self):
|
||||
test_uuid = "17860c43-2274-498d-8669-448eff7b073f"
|
||||
self.task.abort(self.fake_api, test_uuid)
|
||||
|
@ -894,35 +949,37 @@ class TaskCommandsTestCase(test.TestCase):
|
|||
create=True)
|
||||
def test_validate(self, mock_open, mock_os_path_isfile):
|
||||
self.fake_api.task.render_template = self.real_api.task.render_template
|
||||
self.task.validate(self.fake_api, "path_to_config.json", "fake_id")
|
||||
self.fake_api.task.validate.assert_called_once_with(
|
||||
"fake_id", {"some": "json"}, None)
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_task",
|
||||
self.task.validate(self.fake_api, "path_to_config.json", "fake_id")
|
||||
|
||||
self.fake_api.task.validate.assert_called_once_with(
|
||||
"fake_id", {"some": "json"})
|
||||
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_and_validate_task",
|
||||
side_effect=task.FailedToLoadTask)
|
||||
def test_validate_failed_to_load_task(self, mock__load_task,
|
||||
mock_os_path_isfile):
|
||||
def test_validate_failed_to_load_task(self, mock__load_and_validate_task):
|
||||
args = "args"
|
||||
args_file = "args_file"
|
||||
|
||||
result = self.task.validate(self.real_api,
|
||||
"path_to_task", "fake_deployment_id",
|
||||
task_args=args, task_args_file=args_file)
|
||||
self.assertEqual(1, result)
|
||||
mock__load_task.assert_called_once_with(
|
||||
self.real_api, "path_to_task", args, args_file)
|
||||
mock__load_and_validate_task.side_effect = KeyError("foo")
|
||||
|
||||
@mock.patch("rally.cli.commands.task.os.path.isfile", return_value=True)
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_task")
|
||||
def test_validate_invalid(self, mock__load_task, mock_os_path_isfile):
|
||||
exc = exceptions.InvalidTaskException
|
||||
self.assertRaises(KeyError, self.task.validate, self.real_api,
|
||||
"path_to_task", "fake_deployment_id",
|
||||
task_args=args, task_args_file=args_file)
|
||||
self.assertFalse(self.fake_api.task.validate.called)
|
||||
|
||||
mock__load_and_validate_task.assert_called_once_with(
|
||||
self.real_api, "path_to_task", raw_args=args, args_file=args_file)
|
||||
|
||||
@mock.patch("rally.cli.commands.task.TaskCommands._load_and_validate_task")
|
||||
def test_validate_invalid(self, mock__load_and_validate_task):
|
||||
exc = exceptions.InvalidTaskException("foo")
|
||||
self.fake_api.task.validate.side_effect = exc
|
||||
result = self.task.validate(self.fake_api,
|
||||
"path_to_task", "deployment")
|
||||
self.assertEqual(1, result)
|
||||
self.assertRaises(exceptions.InvalidTaskException,
|
||||
self.task.validate, self.fake_api, "path_to_task",
|
||||
"deployment")
|
||||
self.fake_api.task.validate.assert_called_once_with(
|
||||
"deployment", mock__load_task.return_value, None)
|
||||
"deployment", mock__load_and_validate_task.return_value)
|
||||
|
||||
@mock.patch("rally.common.fileutils._rewrite_env_file")
|
||||
def test_use(self, mock__rewrite_env_file):
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import itertools
|
||||
import multiprocessing
|
||||
import random
|
||||
import re
|
||||
|
@ -1840,7 +1841,6 @@ class FakeUserContext(FakeContext):
|
|||
|
||||
|
||||
class FakeDeployment(dict):
|
||||
update_status = mock.Mock()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
namespace = kwargs.pop("namespace", "openstack")
|
||||
|
@ -1849,6 +1849,7 @@ class FakeDeployment(dict):
|
|||
"users": kwargs.pop("users", [])}],
|
||||
"default": [{"admin": None, "users": []}]}
|
||||
dict.__init__(self, **kwargs)
|
||||
self.update_status = mock.Mock()
|
||||
|
||||
def get_platforms(self):
|
||||
return [platform for platform in self["credentials"]]
|
||||
|
@ -1857,18 +1858,16 @@ class FakeDeployment(dict):
|
|||
return self["credentials"][namespace][0]
|
||||
|
||||
|
||||
class FakeTask(dict):
|
||||
class FakeTask(dict, object):
|
||||
|
||||
def __init__(self, task=None, temporary=False, **kwargs):
|
||||
self.is_temporary = temporary
|
||||
self.task = task or kwargs
|
||||
self.set_failed = mock.Mock()
|
||||
self.set_validation_failed = mock.Mock()
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key in self:
|
||||
return self[key]
|
||||
return self.task[key]
|
||||
task = task or {}
|
||||
for k, v in itertools.chain(task.items(), kwargs.items()):
|
||||
self[k] = v
|
||||
self.task = self
|
||||
|
||||
def to_dict(self):
|
||||
return self
|
||||
|
|
|
@ -53,31 +53,77 @@ class TaskAPITestCase(test.TestCase):
|
|||
def setUp(self):
|
||||
super(TaskAPITestCase, self).setUp()
|
||||
self.task_uuid = "b0d9cd6c-2c94-4417-a238-35c7019d0257"
|
||||
self.task = {
|
||||
"uuid": self.task_uuid,
|
||||
}
|
||||
self.task = {"uuid": self.task_uuid}
|
||||
|
||||
@mock.patch("rally.api.objects.Task")
|
||||
@mock.patch("rally.api.objects.Deployment.get",
|
||||
return_value=fakes.FakeDeployment(uuid="deployment_uuid",
|
||||
admin="fake_admin",
|
||||
users=["fake_user"]))
|
||||
@mock.patch("rally.api.objects.Deployment.get")
|
||||
@mock.patch("rally.api.engine.TaskEngine")
|
||||
def test_validate(
|
||||
self, mock_task_engine, mock_deployment_get, mock_task):
|
||||
api._Task.validate(mock_deployment_get.return_value["uuid"], "config")
|
||||
def test_validate(self, mock_task_engine, mock_deployment_get, mock_task):
|
||||
fake_deployment = fakes.FakeDeployment(
|
||||
uuid="deployment_uuid_1", admin="fake_admin", users=["fake_user"])
|
||||
mock_deployment_get.return_value = fake_deployment
|
||||
|
||||
mock_task_engine.assert_has_calls([
|
||||
mock.call("config", mock_task.return_value,
|
||||
mock_deployment_get.return_value),
|
||||
mock.call().validate()
|
||||
])
|
||||
#######################################################################
|
||||
# The case #1 -- create temporary task
|
||||
#######################################################################
|
||||
api._Task.validate(fake_deployment["uuid"], "config")
|
||||
|
||||
mock_task_engine.assert_called_once_with(
|
||||
"config", mock_task.return_value, fake_deployment),
|
||||
mock_task_engine.return_value.validate.assert_called_once_with()
|
||||
|
||||
mock_task.assert_called_once_with(
|
||||
temporary=True,
|
||||
deployment_uuid=mock_deployment_get.return_value["uuid"])
|
||||
temporary=True, deployment_uuid=fake_deployment["uuid"])
|
||||
mock_deployment_get.assert_called_once_with(fake_deployment["uuid"])
|
||||
self.assertFalse(mock_task.get.called)
|
||||
|
||||
#######################################################################
|
||||
# The case #2 -- validate pre-created task
|
||||
#######################################################################
|
||||
mock_task_engine.reset_mock()
|
||||
mock_task.reset_mock()
|
||||
mock_deployment_get.reset_mock()
|
||||
|
||||
fake_task = fakes.FakeTask(deployment_uuid="deployment_uuid_2")
|
||||
mock_task.get.return_value = fake_task
|
||||
|
||||
task_uuid = "task-id"
|
||||
|
||||
api._Task.validate(fake_deployment["uuid"], "config", task=task_uuid)
|
||||
|
||||
mock_task_engine.assert_called_once_with("config", fake_task,
|
||||
fake_deployment)
|
||||
mock_task_engine.return_value.validate.assert_called_once_with()
|
||||
|
||||
self.assertFalse(mock_task.called)
|
||||
# check that deployment uuid is taken from task
|
||||
mock_deployment_get.assert_called_once_with(
|
||||
mock_deployment_get.return_value["uuid"])
|
||||
fake_task["deployment_uuid"])
|
||||
|
||||
mock_task.get.assert_called_once_with(task_uuid)
|
||||
|
||||
#######################################################################
|
||||
# The case #3 -- validate deprecated way for pre-created task
|
||||
#######################################################################
|
||||
mock_task_engine.reset_mock()
|
||||
mock_task.reset_mock()
|
||||
mock_deployment_get.reset_mock()
|
||||
|
||||
task_instance = fakes.FakeTask(uuid="task-id")
|
||||
|
||||
api._Task.validate(fake_deployment["uuid"], "config",
|
||||
task_instance=task_instance)
|
||||
|
||||
mock_task_engine.assert_called_once_with("config", fake_task,
|
||||
fake_deployment)
|
||||
mock_task_engine.return_value.validate.assert_called_once_with()
|
||||
|
||||
self.assertFalse(mock_task.called)
|
||||
# check that deployment uuid is taken from task
|
||||
mock_deployment_get.assert_called_once_with(
|
||||
fake_task["deployment_uuid"])
|
||||
|
||||
mock_task.get.assert_called_once_with(task_instance["uuid"])
|
||||
|
||||
@mock.patch("rally.api.objects.Task")
|
||||
@mock.patch("rally.api.objects.Deployment",
|
||||
|
@ -170,16 +216,22 @@ class TaskAPITestCase(test.TestCase):
|
|||
self.assertRaises(exceptions.DeploymentNotFinishedStatus,
|
||||
api._Task.create, deployment_id, tag)
|
||||
|
||||
@mock.patch("rally.api.objects.Task",
|
||||
return_value=fakes.FakeTask(uuid="some_uuid"))
|
||||
@mock.patch("rally.api.objects.Deployment.get",
|
||||
return_value=fakes.FakeDeployment(uuid="deployment_uuid",
|
||||
admin="fake_admin",
|
||||
users=["fake_user"]))
|
||||
@mock.patch("rally.api.objects.Task")
|
||||
@mock.patch("rally.api.objects.Deployment.get")
|
||||
@mock.patch("rally.api.engine.TaskEngine")
|
||||
def test_start(self, mock_task_engine, mock_deployment_get,
|
||||
mock_task):
|
||||
api._Task.start(mock_deployment_get.return_value["uuid"], "config")
|
||||
fake_task = fakes.FakeTask(uuid="some_uuid")
|
||||
fake_task.get_status = mock.Mock()
|
||||
mock_task.return_value = fake_task
|
||||
mock_deployment_get.return_value = fakes.FakeDeployment(
|
||||
uuid="deployment_uuid", admin="fake_admin", users=["fake_user"],
|
||||
status=consts.DeployStatus.DEPLOY_FINISHED)
|
||||
|
||||
self.assertEqual(
|
||||
(fake_task["uuid"], fake_task.get_status.return_value),
|
||||
api._Task.start(mock_deployment_get.return_value["uuid"], "config")
|
||||
)
|
||||
|
||||
mock_task_engine.assert_has_calls([
|
||||
mock.call("config", mock_task.return_value,
|
||||
|
@ -194,29 +246,52 @@ class TaskAPITestCase(test.TestCase):
|
|||
mock_deployment_get.assert_called_once_with(
|
||||
mock_deployment_get.return_value["uuid"])
|
||||
|
||||
@mock.patch("rally.api.objects.Task",
|
||||
return_value=fakes.FakeTask(uuid="some_uuid", task={},
|
||||
temporary=True))
|
||||
@mock.patch("rally.api.objects.Deployment.get",
|
||||
return_value=fakes.FakeDeployment(uuid="deployment_uuid",
|
||||
admin="fake_admin",
|
||||
users=["fake_user"]))
|
||||
def test_start_temporary_task(self, mock_deployment_get,
|
||||
mock_task):
|
||||
@mock.patch("rally.api.objects.Deployment.get")
|
||||
def test_start_temporary_task(self, mock_deployment_get):
|
||||
fake_deployment = fakes.FakeDeployment(
|
||||
uuid="deployment_uuid", admin="fake_admin", users=["fake_user"],
|
||||
status=consts.DeployStatus.DEPLOY_FINISHED,
|
||||
name="foo")
|
||||
mock_deployment_get.return_value = fake_deployment
|
||||
fake_task = objects.Task(task={"deployment_uuid": "deployment_uuid",
|
||||
"uuid": "some_uuid"}, temporary=True)
|
||||
|
||||
self.assertRaises(ValueError, api._Task.start,
|
||||
mock_deployment_get.return_value["uuid"], "config")
|
||||
fake_deployment, "config", task=fake_task)
|
||||
|
||||
@mock.patch("rally.api.objects.task.db.task_get")
|
||||
@mock.patch("rally.api.objects.Deployment.get")
|
||||
def test_start_with_inconsistent_deployment(self, mock_deployment_get,
|
||||
mock_task_get):
|
||||
deployment_uuid = "deployment_uuid"
|
||||
fake_deployment = fakes.FakeDeployment(
|
||||
uuid=deployment_uuid, admin="fake_admin", users=["fake_user"],
|
||||
status=consts.DeployStatus.DEPLOY_INCONSISTENT,
|
||||
name="foo")
|
||||
mock_deployment_get.return_value = fake_deployment
|
||||
fake_task_dict = {"deployment_uuid": deployment_uuid,
|
||||
"uuid": "some_uuid"}
|
||||
fake_task = objects.Task(task=fake_task_dict)
|
||||
mock_task_get.return_value = fake_task_dict
|
||||
|
||||
self.assertRaises(exceptions.DeploymentNotFinishedStatus,
|
||||
api._Task.start, deployment_uuid, "config",
|
||||
task=fake_task)
|
||||
|
||||
@mock.patch("rally.api.objects.Task")
|
||||
@mock.patch("rally.api.objects.Deployment.get")
|
||||
@mock.patch("rally.api.engine.TaskEngine")
|
||||
def test_start_exception(self, mock_task_engine, mock_deployment_get,
|
||||
mock_task):
|
||||
fake_deployment = fakes.FakeDeployment(
|
||||
status=consts.DeployStatus.DEPLOY_FINISHED,
|
||||
name="foo", uuid="deployment_uuid")
|
||||
mock_deployment_get.return_value = fake_deployment
|
||||
mock_task.return_value.is_temporary = False
|
||||
mock_task_engine.return_value.run.side_effect = TypeError
|
||||
self.assertRaises(TypeError, api._Task.start, "deployment_uuid",
|
||||
"config")
|
||||
mock_deployment_get().update_status.assert_called_once_with(
|
||||
fake_deployment.update_status.assert_called_once_with(
|
||||
consts.DeployStatus.DEPLOY_INCONSISTENT)
|
||||
|
||||
@ddt.data(True, False)
|
||||
|
|
Loading…
Reference in New Issue