* use new format of a runner section
the schemas of existing plugins are changed to not include "type"
* use "contexts" key instead of "context"
note: the database model still operates the word "context". hope it
will be fixed soon while extendind abilities of contexts
* use new format of a hook section
Change-Id: I2ef6ba7a24b542fb001bce378cadf8c83c774b01
465 lines
19 KiB
Python
465 lines
19 KiB
Python
# Copyright 2013: Mirantis 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.
|
|
|
|
"""Tests for db.task layer."""
|
|
|
|
import collections
|
|
import datetime as dt
|
|
|
|
import ddt
|
|
import mock
|
|
|
|
from rally.common import objects
|
|
from rally import consts
|
|
from rally import exceptions
|
|
from tests.unit import test
|
|
|
|
|
|
@ddt.ddt
|
|
class TaskTestCase(test.TestCase):
|
|
def setUp(self):
|
|
super(TaskTestCase, self).setUp()
|
|
self.task = {
|
|
"uuid": "00ef46a2-c5b8-4aea-a5ca-0f54a10cbca1",
|
|
"status": consts.TaskStatus.INIT,
|
|
"validation_result": {},
|
|
}
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_create")
|
|
def test_init_with_create(self, mock_task_create):
|
|
mock_task_create.return_value = self.task
|
|
task = objects.Task(status=consts.TaskStatus.CRASHED)
|
|
mock_task_create.assert_called_once_with({
|
|
"status": consts.TaskStatus.CRASHED})
|
|
self.assertEqual(task["uuid"], self.task["uuid"])
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_create")
|
|
def test_init_without_create(self, mock_task_create):
|
|
task = objects.Task(task=self.task)
|
|
self.assertFalse(mock_task_create.called)
|
|
self.assertEqual(task["uuid"], self.task["uuid"])
|
|
|
|
@mock.patch("rally.common.objects.task.uuid.uuid4",
|
|
return_value="some_uuid")
|
|
@mock.patch("rally.common.objects.task.db.task_create")
|
|
def test_init_with_fake_true(self, mock_task_create, mock_uuid4):
|
|
task = objects.Task(temporary=True)
|
|
self.assertFalse(mock_task_create.called)
|
|
self.assertTrue(mock_uuid4.called)
|
|
self.assertEqual(task["uuid"], mock_uuid4.return_value)
|
|
|
|
@mock.patch("rally.common.db.api.task_get")
|
|
def test_get(self, mock_task_get):
|
|
mock_task_get.return_value = self.task
|
|
task = objects.Task.get(self.task["uuid"])
|
|
mock_task_get.assert_called_once_with(self.task["uuid"],
|
|
detailed=False)
|
|
self.assertEqual(task["uuid"], self.task["uuid"])
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_get_status")
|
|
def test_get_status(self, mock_task_get_status):
|
|
task = objects.Task(task=self.task)
|
|
status = task.get_status(task["uuid"])
|
|
self.assertEqual(status, mock_task_get_status.return_value)
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_delete")
|
|
@mock.patch("rally.common.objects.task.db.task_create")
|
|
def test_create_and_delete(self, mock_task_create, mock_task_delete):
|
|
mock_task_create.return_value = self.task
|
|
task = objects.Task()
|
|
task.delete()
|
|
mock_task_delete.assert_called_once_with(
|
|
self.task["uuid"], status=None)
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_delete")
|
|
@mock.patch("rally.common.objects.task.db.task_create")
|
|
def test_create_and_delete_status(self, mock_task_create,
|
|
mock_task_delete):
|
|
mock_task_create.return_value = self.task
|
|
task = objects.Task()
|
|
task.delete(status=consts.TaskStatus.FINISHED)
|
|
mock_task_delete.assert_called_once_with(
|
|
self.task["uuid"], status=consts.TaskStatus.FINISHED)
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_delete")
|
|
def test_delete_by_uuid(self, mock_task_delete):
|
|
objects.Task.delete_by_uuid(self.task["uuid"])
|
|
mock_task_delete.assert_called_once_with(
|
|
self.task["uuid"], status=None)
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_delete")
|
|
def test_delete_by_uuid_status(self, mock_task_delete):
|
|
objects.Task.delete_by_uuid(self.task["uuid"],
|
|
consts.TaskStatus.FINISHED)
|
|
mock_task_delete.assert_called_once_with(
|
|
self.task["uuid"], status=consts.TaskStatus.FINISHED)
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_list",
|
|
return_value=[{"uuid": "a",
|
|
"created_at": "b",
|
|
"status": consts.TaskStatus.CRASHED,
|
|
"tag": "d",
|
|
"deployment_name": "some_name"}])
|
|
def list(self, mock_db_task_list):
|
|
tasks = objects.Task.list(status="somestatus")
|
|
mock_db_task_list.assert_called_once_with("somestatus", None)
|
|
self.assertIs(type(tasks), list)
|
|
self.assertIsInstance(tasks[0], objects.Task)
|
|
self.assertEqual(mock_db_task_list.return_value["uuis"],
|
|
tasks[0]["uuid"])
|
|
|
|
@mock.patch("rally.common.objects.deploy.db.task_update")
|
|
@mock.patch("rally.common.objects.task.db.task_create")
|
|
def test_update(self, mock_task_create, mock_task_update):
|
|
mock_task_create.return_value = self.task
|
|
mock_task_update.return_value = {"opt": "val2"}
|
|
deploy = objects.Task(opt="val1")
|
|
deploy._update({"opt": "val2"})
|
|
mock_task_update.assert_called_once_with(
|
|
self.task["uuid"], {"opt": "val2"})
|
|
self.assertEqual(deploy["opt"], "val2")
|
|
|
|
@ddt.data(
|
|
{
|
|
"status": "some_status", "allowed_statuses": ("s_1", "s_2")
|
|
},
|
|
{
|
|
"status": "some_status", "allowed_statuses": None
|
|
}
|
|
)
|
|
@ddt.unpack
|
|
@mock.patch("rally.common.objects.task.db.task_update_status")
|
|
@mock.patch("rally.common.objects.task.db.task_update")
|
|
def test_update_status(self, mock_task_update, mock_task_update_status,
|
|
status, allowed_statuses):
|
|
task = objects.Task(task=self.task)
|
|
task.update_status(consts.TaskStatus.FINISHED, allowed_statuses)
|
|
if allowed_statuses:
|
|
self.assertFalse(mock_task_update.called)
|
|
mock_task_update_status.assert_called_once_with(
|
|
self.task["uuid"],
|
|
consts.TaskStatus.FINISHED,
|
|
allowed_statuses
|
|
)
|
|
else:
|
|
self.assertFalse(mock_task_update_status.called)
|
|
mock_task_update.assert_called_once_with(
|
|
self.task["uuid"],
|
|
{"status": consts.TaskStatus.FINISHED},
|
|
)
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_update")
|
|
def test_update_verification_log(self, mock_task_update):
|
|
mock_task_update.return_value = self.task
|
|
task = objects.Task(task=self.task)
|
|
task.set_validation_failed({"a": "fake"})
|
|
mock_task_update.assert_called_once_with(
|
|
self.task["uuid"],
|
|
{"status": consts.TaskStatus.VALIDATION_FAILED,
|
|
"validation_result": {"a": "fake"}}
|
|
)
|
|
|
|
@mock.patch("rally.common.objects.task.db.deployment_get")
|
|
def test_to_dict(self, mock_deployment_get):
|
|
workloads = [{"created_at": dt.datetime.now(),
|
|
"updated_at": dt.datetime.now()}]
|
|
self.task.update({"deployment_uuid": "deployment_uuid",
|
|
"deployment_name": "deployment_name",
|
|
"created_at": dt.datetime.now(),
|
|
"updated_at": dt.datetime.now()})
|
|
|
|
mock_deployment_get.return_value = {"name": "deployment_name"}
|
|
|
|
task = objects.Task(task=self.task)
|
|
serialized_task = task.to_dict()
|
|
|
|
mock_deployment_get.assert_called_once_with(
|
|
self.task["deployment_uuid"])
|
|
self.assertEqual(self.task, serialized_task)
|
|
|
|
self.task["subtasks"] = [{"workloads": workloads}]
|
|
|
|
@mock.patch("rally.common.db.api.task_get")
|
|
def test_get_detailed(self, mock_task_get):
|
|
mock_task_get.return_value = {"results": [{
|
|
"created_at": dt.datetime.now(),
|
|
"updated_at": dt.datetime.now()}]}
|
|
task_detailed = objects.Task.get("task_id", detailed=True)
|
|
mock_task_get.assert_called_once_with("task_id", detailed=True)
|
|
self.assertEqual(mock_task_get.return_value, task_detailed.task)
|
|
|
|
@mock.patch("rally.common.objects.task.db.task_update")
|
|
def test_set_failed(self, mock_task_update):
|
|
mock_task_update.return_value = self.task
|
|
task = objects.Task(task=self.task)
|
|
task.set_failed("foo_type", "foo_error_message", "foo_trace")
|
|
mock_task_update.assert_called_once_with(
|
|
self.task["uuid"],
|
|
{"status": consts.TaskStatus.CRASHED,
|
|
"validation_result": {"etype": "foo_type",
|
|
"msg": "foo_error_message",
|
|
"trace": "foo_trace"}},
|
|
)
|
|
|
|
@mock.patch("rally.common.objects.task.Subtask")
|
|
def test_add_subtask(self, mock_subtask):
|
|
task = objects.Task(task=self.task)
|
|
subtask = task.add_subtask(title="foo")
|
|
mock_subtask.assert_called_once_with(
|
|
self.task["uuid"], title="foo", context=None, description=None)
|
|
self.assertIs(subtask, mock_subtask.return_value)
|
|
|
|
@ddt.data(
|
|
{
|
|
"soft": True, "status": consts.TaskStatus.INIT
|
|
},
|
|
{
|
|
"soft": True, "status": consts.TaskStatus.VALIDATING,
|
|
"soft": True, "status": consts.TaskStatus.ABORTED
|
|
},
|
|
{
|
|
"soft": True, "status": consts.TaskStatus.FINISHED
|
|
},
|
|
{
|
|
"soft": True, "status": consts.TaskStatus.CRASHED
|
|
},
|
|
{
|
|
"soft": False, "status": consts.TaskStatus.ABORTED
|
|
},
|
|
{
|
|
"soft": False, "status": consts.TaskStatus.FINISHED
|
|
},
|
|
{
|
|
"soft": False, "status": consts.TaskStatus.CRASHED
|
|
}
|
|
)
|
|
@ddt.unpack
|
|
def test_abort_with_finished_states(self, soft, status):
|
|
task = objects.Task(mock.MagicMock(), fake=True)
|
|
task.get_status = mock.MagicMock(return_value=status)
|
|
task.update_status = mock.MagicMock()
|
|
|
|
self.assertRaises(exceptions.RallyException, task.abort, soft)
|
|
|
|
self.assertEqual(1, task.get_status.call_count)
|
|
self.assertFalse(task.update_status.called)
|
|
|
|
@ddt.data(True, False)
|
|
def test_abort_with_running_state(self, soft):
|
|
task = objects.Task(mock.MagicMock(), fake=True)
|
|
task.get_status = mock.MagicMock(return_value="running")
|
|
task.update_status = mock.MagicMock()
|
|
|
|
task.abort(soft)
|
|
if soft:
|
|
status = consts.TaskStatus.SOFT_ABORTING
|
|
else:
|
|
status = consts.TaskStatus.ABORTING
|
|
|
|
task.update_status.assert_called_once_with(
|
|
status,
|
|
allowed_statuses=(consts.TaskStatus.RUNNING,
|
|
consts.TaskStatus.SOFT_ABORTING)
|
|
)
|
|
|
|
|
|
class SubtaskTestCase(test.TestCase):
|
|
|
|
def setUp(self):
|
|
super(SubtaskTestCase, self).setUp()
|
|
self.subtask = {
|
|
"task_uuid": "00ef46a2-c5b8-4aea-a5ca-0f54a10cbca1",
|
|
"uuid": "00ef46a2-c5b8-4aea-a5ca-0f54a10cbca2",
|
|
"title": "foo",
|
|
}
|
|
|
|
@mock.patch("rally.common.objects.task.db.subtask_create")
|
|
def test_init(self, mock_subtask_create):
|
|
mock_subtask_create.return_value = self.subtask
|
|
subtask = objects.Subtask("bar", title="foo")
|
|
mock_subtask_create.assert_called_once_with(
|
|
"bar", title="foo", context=None, description=None)
|
|
self.assertEqual(subtask["uuid"], self.subtask["uuid"])
|
|
|
|
@mock.patch("rally.common.objects.task.db.subtask_update")
|
|
@mock.patch("rally.common.objects.task.db.subtask_create")
|
|
def test_update_status(self, mock_subtask_create, mock_subtask_update):
|
|
mock_subtask_create.return_value = self.subtask
|
|
subtask = objects.Subtask("bar", title="foo")
|
|
subtask.update_status(consts.SubtaskStatus.FINISHED)
|
|
mock_subtask_update.assert_called_once_with(
|
|
self.subtask["uuid"], {"status": consts.SubtaskStatus.FINISHED})
|
|
|
|
@mock.patch("rally.common.objects.task.Workload")
|
|
@mock.patch("rally.common.objects.task.db.subtask_create")
|
|
def test_add_workload(self, mock_subtask_create, mock_workload):
|
|
mock_subtask_create.return_value = self.subtask
|
|
subtask = objects.Subtask("bar", title="foo")
|
|
|
|
name = "w"
|
|
description = "descr"
|
|
position = 0
|
|
runner_type = "runner"
|
|
runner = {}
|
|
context = {"users": {}}
|
|
sla = {"failure_rate": {"max": 0}}
|
|
args = {"arg": "xxx"}
|
|
hooks = [{"foo": "bar"}]
|
|
|
|
workload = subtask.add_workload(
|
|
name, description=description, position=position,
|
|
runner_type=runner_type, runner=runner, context=context, sla=sla,
|
|
args=args, hooks=hooks)
|
|
mock_workload.assert_called_once_with(
|
|
task_uuid=self.subtask["task_uuid"],
|
|
subtask_uuid=self.subtask["uuid"], name=name,
|
|
description=description, position=position,
|
|
runner_type=runner_type, runner=runner,
|
|
context=context, sla=sla, args=args,
|
|
hooks=[{"config": h} for h in hooks])
|
|
self.assertIs(workload, mock_workload.return_value)
|
|
|
|
|
|
class WorkloadTestCase(test.TestCase):
|
|
|
|
def setUp(self):
|
|
super(WorkloadTestCase, self).setUp()
|
|
self.workload = {
|
|
"task_uuid": "00ef46a2-c5b8-4aea-a5ca-0f54a10cbca1",
|
|
"subtask_uuid": "00ef46a2-c5b8-4aea-a5ca-0f54a10cbca2",
|
|
"uuid": "00ef46a2-c5b8-4aea-a5ca-0f54a10cbca3",
|
|
}
|
|
|
|
@mock.patch("rally.common.objects.task.db.workload_create")
|
|
def test_init(self, mock_workload_create):
|
|
mock_workload_create.return_value = self.workload
|
|
name = "w"
|
|
description = "descr"
|
|
position = 0
|
|
runner_type = "constant"
|
|
runner = {"times": 3}
|
|
context = {"users": {}}
|
|
sla = {"failure_rate": {"max": 0}}
|
|
args = {"arg": "xxx"}
|
|
hooks = [{"config": {"foo": "bar"}}]
|
|
workload = objects.Workload("uuid1", "uuid2", name=name,
|
|
description=description, position=position,
|
|
runner=runner, runner_type=runner_type,
|
|
context=context, sla=sla,
|
|
args=args, hooks=hooks)
|
|
mock_workload_create.assert_called_once_with(
|
|
task_uuid="uuid1", subtask_uuid="uuid2", name=name, hooks=hooks,
|
|
description=description, position=position, runner=runner,
|
|
runner_type="constant", context=context, sla=sla, args=args)
|
|
self.assertEqual(workload["uuid"], self.workload["uuid"])
|
|
|
|
@mock.patch("rally.common.objects.task.db.workload_data_create")
|
|
@mock.patch("rally.common.objects.task.db.workload_create")
|
|
def test_add_workload_data(self, mock_workload_create,
|
|
mock_workload_data_create):
|
|
mock_workload_create.return_value = self.workload
|
|
workload = objects.Workload("uuid1", "uuid2", name="w",
|
|
description="descr", position=0,
|
|
runner_type="foo", runner={}, context=None,
|
|
sla=None, args=None, hooks=[])
|
|
|
|
workload.add_workload_data(0, {"data": "foo"})
|
|
mock_workload_data_create.assert_called_once_with(
|
|
self.workload["task_uuid"], self.workload["uuid"],
|
|
0, {"data": "foo"})
|
|
|
|
@mock.patch("rally.common.objects.task.db.workload_set_results")
|
|
@mock.patch("rally.common.objects.task.db.workload_create")
|
|
def test_set_results(self, mock_workload_create,
|
|
mock_workload_set_results):
|
|
mock_workload_create.return_value = self.workload
|
|
name = "w"
|
|
description = "descr"
|
|
position = 0
|
|
runner_type = "constant"
|
|
runner = {"times": 3}
|
|
context = {"users": {}}
|
|
sla = {"failure_rate": {"max": 0}}
|
|
args = {"arg": "xxx"}
|
|
load_duration = 88
|
|
full_duration = 99
|
|
start_time = 1231231277.22
|
|
sla_results = []
|
|
hooks = []
|
|
workload = objects.Workload("uuid1", "uuid2", name=name,
|
|
description=description, position=position,
|
|
runner=runner, runner_type=runner_type,
|
|
context=context, sla=sla, args=args,
|
|
hooks=hooks)
|
|
|
|
workload.set_results(load_duration=load_duration,
|
|
full_duration=full_duration,
|
|
start_time=start_time, sla_results=sla_results)
|
|
mock_workload_set_results.assert_called_once_with(
|
|
workload_uuid=self.workload["uuid"],
|
|
subtask_uuid=self.workload["subtask_uuid"],
|
|
task_uuid=self.workload["task_uuid"],
|
|
load_duration=load_duration, full_duration=full_duration,
|
|
start_time=start_time, sla_results=sla_results,
|
|
hooks_results=None)
|
|
|
|
def test_to_task(self):
|
|
workload = {
|
|
"id": 777,
|
|
"uuid": "uuiiidd",
|
|
"task_uuid": "task-uuid",
|
|
"subtask_uuid": "subtask-uuid",
|
|
"name": "Foo.bar",
|
|
"description": "Make something useful (or not).",
|
|
"position": 3,
|
|
"runner_type": "constant",
|
|
"runner": {"times": 3},
|
|
"contexts": {"users": {}},
|
|
"sla": {"failure_rate": {"max": 0}},
|
|
"args": {"key1": "value1"},
|
|
"hooks": [{"config": {
|
|
"action": ["foo", {"arg1": "v1"}],
|
|
"trigger": ["bar", {"arg2": "v2"}]
|
|
}}],
|
|
"sla_results": {"sla": []},
|
|
"context_execution": {},
|
|
"start_time": "2997.23.12",
|
|
"load_duration": 42,
|
|
"full_duration": 37,
|
|
"min_duration": 1,
|
|
"max_duration": 2,
|
|
"total_iteration_count": 7,
|
|
"failed_iteration_count": 2,
|
|
"statistics": {},
|
|
"pass_sla": False
|
|
}
|
|
expected_task = collections.OrderedDict([
|
|
("version", 2),
|
|
("title", "A cropped version of a bigger task."),
|
|
("description", "Auto-generated task from a single workload "
|
|
"(uuid=%s)" % workload["uuid"]),
|
|
("subtasks",
|
|
[collections.OrderedDict([
|
|
("title", workload["name"]),
|
|
("description", workload["description"]),
|
|
("scenario", {workload["name"]: workload["args"]}),
|
|
("contexts", workload["contexts"]),
|
|
("runner", {"constant": {"times": 3}}),
|
|
("hooks", [{"action": {"foo": {"arg1": "v1"}},
|
|
"trigger": {"bar": {"arg2": "v2"}},
|
|
"description": None}]),
|
|
("sla", workload["sla"])])])])
|
|
self.assertEqual(expected_task, objects.Workload.to_task(workload))
|