Make context plugins decide how to map their data for scenario
Previously to have only one user and its context during the run of scenario we had hack inside base runner to map full context for scenario. This patch makes context classes resposible for that. E.g. you can implement method that will somehow map resources of context for each run of scenario. Fix context.__init__() methods they shouldn't change context object. There are 3 great benifits of this change: - You don't need hacks to map resources created by context for scenarios, which will be crucial for other projects - You don't need hacks to make mapping strategies configurable e.g. pick users randomly or 1 by 1 and so on - Rally framework depends less on OpenStack stuff Change-Id: Ie5915cd35b27cb1988465ba33179721bf61224c7
This commit is contained in:
@@ -63,9 +63,6 @@ class ImageGenerator(context.Context):
|
||||
"additionalProperties": False
|
||||
}
|
||||
|
||||
def __init__(self, ctx):
|
||||
super(ImageGenerator, self).__init__(ctx)
|
||||
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `Images`"))
|
||||
def setup(self):
|
||||
image_url = self.config["image_url"]
|
||||
|
||||
@@ -18,6 +18,7 @@ from rally.common import log as logging
|
||||
from rally.common import objects
|
||||
from rally.common import utils as rutils
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack.context.keystone import users
|
||||
from rally.task import context
|
||||
|
||||
|
||||
@@ -27,8 +28,9 @@ LOG = logging.getLogger(__name__)
|
||||
# NOTE(boris-42): This context should be hidden for now and used only by
|
||||
# benchmark engine. In future during various refactoring of
|
||||
# validation system and rally CI testing we will make it public
|
||||
|
||||
@context.configure(name="existing_users", order=99, hidden=True)
|
||||
class ExistingUsers(context.Context):
|
||||
class ExistingUsers(users.UserContextMixin, context.Context):
|
||||
"""This context supports using existing users in Rally.
|
||||
|
||||
It uses information about deployment to properly
|
||||
@@ -42,13 +44,11 @@ class ExistingUsers(context.Context):
|
||||
# this is used only by benchmark engine
|
||||
CONFIG_SCHEMA = {}
|
||||
|
||||
def __init__(self, ctx):
|
||||
super(ExistingUsers, self).__init__(ctx)
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `existing_users`"))
|
||||
def setup(self):
|
||||
self.context["users"] = []
|
||||
self.context["tenants"] = {}
|
||||
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `existing_users`"))
|
||||
def setup(self):
|
||||
for user in self.config:
|
||||
user_endpoint = objects.Endpoint(**user)
|
||||
user_kclient = osclients.Clients(user_endpoint).keystone()
|
||||
|
||||
@@ -40,7 +40,6 @@ class RoleGenerator(context.Context):
|
||||
|
||||
def __init__(self, ctx):
|
||||
super(RoleGenerator, self).__init__(ctx)
|
||||
self.context["roles"] = []
|
||||
self.endpoint = self.context["admin"]["endpoint"]
|
||||
|
||||
def _add_role(self, admin_endpoint, context_role):
|
||||
@@ -83,9 +82,8 @@ class RoleGenerator(context.Context):
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `roles`"))
|
||||
def setup(self):
|
||||
"""Add roles to all users."""
|
||||
for name in self.config:
|
||||
role = self._add_role(self.endpoint, name)
|
||||
self.context["roles"].append(role)
|
||||
self.context["roles"] = [self._add_role(self.endpoint, name)
|
||||
for name in self.config]
|
||||
|
||||
@rutils.log_task_wrapper(LOG.info, _("Exit context: `roles`"))
|
||||
def cleanup(self):
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import random
|
||||
import uuid
|
||||
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
|
||||
from rally.common import broker
|
||||
from rally.common.i18n import _
|
||||
@@ -52,8 +54,28 @@ CONF.register_opts(USER_CONTEXT_OPTS,
|
||||
title="benchmark context options"))
|
||||
|
||||
|
||||
class UserContextMixin(object):
|
||||
|
||||
def map_for_scenario(self, context_obj):
|
||||
"""Pass only context of one user and related to it tenant to scenario.
|
||||
|
||||
We are choosing on each iteration one user
|
||||
|
||||
"""
|
||||
scenario_ctx = {}
|
||||
for key, value in six.iteritems(context_obj):
|
||||
if key not in ["users", "tenants"]:
|
||||
scenario_ctx[key] = value
|
||||
|
||||
user = random.choice(context_obj["users"])
|
||||
tenant = context_obj["tenants"][user["tenant_id"]]
|
||||
scenario_ctx["user"], scenario_ctx["tenant"] = user, tenant
|
||||
|
||||
return scenario_ctx
|
||||
|
||||
|
||||
@context.configure(name="users", order=100)
|
||||
class UserGenerator(context.Context):
|
||||
class UserGenerator(UserContextMixin, context.Context):
|
||||
"""Context class for generating temporary users/tenants for benchmarks."""
|
||||
|
||||
CONFIG_SCHEMA = {
|
||||
@@ -95,14 +117,7 @@ class UserGenerator(context.Context):
|
||||
|
||||
def __init__(self, context):
|
||||
super(UserGenerator, self).__init__(context)
|
||||
self.context["users"] = []
|
||||
self.context["tenants"] = {}
|
||||
self.endpoint = self.context["admin"]["endpoint"]
|
||||
# NOTE(boris-42): I think this is the best place for adding logic when
|
||||
# we are using pre created users or temporary. So we
|
||||
# should rename this class s/UserGenerator/UserContext/
|
||||
# and change a bit logic of populating lists of users
|
||||
# and tenants
|
||||
|
||||
def _remove_default_security_group(self):
|
||||
"""Delete default security group for tenants."""
|
||||
@@ -254,6 +269,9 @@ class UserGenerator(context.Context):
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `users`"))
|
||||
def setup(self):
|
||||
"""Create tenants and users, using the broker pattern."""
|
||||
self.context["users"] = []
|
||||
self.context["tenants"] = {}
|
||||
|
||||
threads = self.config["resource_management_workers"]
|
||||
|
||||
LOG.debug("Creating %(tenants)d tenants using %(threads)s threads" %
|
||||
|
||||
@@ -86,12 +86,10 @@ class SaharaCluster(context.Context):
|
||||
"flavor_id"]
|
||||
}
|
||||
|
||||
def __init__(self, ctx):
|
||||
super(SaharaCluster, self).__init__(ctx)
|
||||
self.context["sahara_clusters"] = {}
|
||||
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `Sahara Cluster`"))
|
||||
def setup(self):
|
||||
self.context["sahara_clusters"] = {}
|
||||
|
||||
wait_dict = {}
|
||||
|
||||
for user, tenant_id in rutils.iterate_per_tenants(
|
||||
|
||||
@@ -86,8 +86,8 @@ class SaharaEDP(context.Context):
|
||||
"output_type", "output_url_prefix"]
|
||||
}
|
||||
|
||||
def __init__(self, ctx):
|
||||
super(SaharaEDP, self).__init__(ctx)
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `Sahara EDP`"))
|
||||
def setup(self):
|
||||
self.context["sahara_output_conf"] = {
|
||||
"output_type": self.config["output_type"],
|
||||
"output_url_prefix": self.config["output_url_prefix"]
|
||||
@@ -95,9 +95,6 @@ class SaharaEDP(context.Context):
|
||||
self.context["sahara_mains"] = {}
|
||||
self.context["sahara_libs"] = {}
|
||||
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `Sahara EDP`"))
|
||||
def setup(self):
|
||||
|
||||
input_type = self.config["input_type"]
|
||||
input_url = self.config["input_url"]
|
||||
mains = self.config.get("mains", [])
|
||||
|
||||
@@ -58,10 +58,6 @@ class SaharaImage(context.Context):
|
||||
"additionalProperties": False
|
||||
}
|
||||
|
||||
def __init__(self, ctx):
|
||||
super(SaharaImage, self).__init__(ctx)
|
||||
self.context["sahara_images"] = {}
|
||||
|
||||
def _create_image(self, hadoop_version, image_url, plugin_name, user,
|
||||
user_name):
|
||||
scenario = glance_utils.GlanceScenario({"user": user})
|
||||
@@ -78,9 +74,10 @@ class SaharaImage(context.Context):
|
||||
|
||||
@rutils.log_task_wrapper(LOG.info, _("Enter context: `Sahara Image`"))
|
||||
def setup(self):
|
||||
self.context["sahara_images"] = {}
|
||||
|
||||
# The user may want to use the existing image. In this case he should
|
||||
# make sure that the image is public and has all required metadata.
|
||||
|
||||
image_uuid = self.config.get("image_uuid")
|
||||
|
||||
self.context["need_sahara_image_cleanup"] = not image_uuid
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
import abc
|
||||
import copy
|
||||
|
||||
import jsonschema
|
||||
import six
|
||||
@@ -84,6 +85,8 @@ class Context(plugin.Plugin, functional.FunctionalMixin):
|
||||
|
||||
@classmethod
|
||||
def validate(cls, config, non_hidden=False):
|
||||
# TODO(boris-42): This is going to be replaced with common validation
|
||||
# mechanism (generalization of scenario validation)
|
||||
if non_hidden and cls._meta_get("hidden"):
|
||||
raise exceptions.PluginNotFound(name=cls.get_name(),
|
||||
namespace="context")
|
||||
@@ -95,11 +98,40 @@ class Context(plugin.Plugin, functional.FunctionalMixin):
|
||||
|
||||
@abc.abstractmethod
|
||||
def setup(self):
|
||||
"""Set context of benchmark."""
|
||||
"""Prepare environment for test.
|
||||
|
||||
This method is executed only once before load generation.
|
||||
|
||||
self.config contains input arguments of this context
|
||||
self.context contains information that will be passed to scenario
|
||||
|
||||
The goal of this method is to perform all operation to prepare
|
||||
environment and store information to self.context that is required
|
||||
by scenario.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def cleanup(self):
|
||||
"""Clean context of benchmark."""
|
||||
"""Clean up environment after load generation.
|
||||
|
||||
This method is run once after load generation is done to cleanup
|
||||
environment.
|
||||
|
||||
self.config contains input arguments of this context
|
||||
self.context contains information that was passed to scenario
|
||||
"""
|
||||
|
||||
def map_for_scenario(self, context_obj):
|
||||
"""Maps global context to context that is used by scenario.
|
||||
|
||||
This method is run each time to create scenario context which is
|
||||
actually just sub set of global context.
|
||||
|
||||
One of sample where this method is useful is users context.
|
||||
We have set of users and tenants but each scenario should have access
|
||||
to context of single user in single tenant.
|
||||
"""
|
||||
return context_obj
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
@@ -145,6 +177,26 @@ class ContextManager(object):
|
||||
LOG.error("Context %s failed during cleanup." % ctx.get_name())
|
||||
LOG.exception(e)
|
||||
|
||||
def map_for_scenario(self):
|
||||
"""Returns scenario's specific context from full context.
|
||||
|
||||
Each context class is able to map context object data as it want.
|
||||
E.g. users context will pick one user and it's tenant for each
|
||||
scenario run.
|
||||
|
||||
This method iterates over all context classes used in task
|
||||
and performs transformation of each of them to full context, order of
|
||||
transformation is the same as order of context creation.
|
||||
"""
|
||||
# NOTE(boris-42): Original context_obj is read only and should not
|
||||
# be modified
|
||||
context_obj = copy.deepcopy(self.context_obj)
|
||||
|
||||
for ctx in self._get_sorted_context_lst():
|
||||
context_obj = ctx.map_for_scenario(context_obj)
|
||||
|
||||
return context_obj
|
||||
|
||||
def __enter__(self):
|
||||
try:
|
||||
self.setup()
|
||||
|
||||
@@ -16,16 +16,15 @@
|
||||
import abc
|
||||
import collections
|
||||
import multiprocessing
|
||||
import random
|
||||
import time
|
||||
|
||||
import jsonschema
|
||||
import six
|
||||
|
||||
from rally.common import log as logging
|
||||
from rally.common.plugin import plugin
|
||||
from rally.common import utils as rutils
|
||||
from rally import consts
|
||||
from rally.task import context
|
||||
from rally.task.scenarios import base as scenario_base
|
||||
from rally.task import types
|
||||
from rally.task import utils
|
||||
@@ -44,28 +43,18 @@ def format_result_on_timeout(exc, timeout):
|
||||
}
|
||||
|
||||
|
||||
def _get_scenario_context(context):
|
||||
scenario_ctx = {}
|
||||
for key, value in six.iteritems(context):
|
||||
if key not in ["users", "tenants"]:
|
||||
scenario_ctx[key] = value
|
||||
|
||||
if "users" in context:
|
||||
user = random.choice(context["users"])
|
||||
tenant = context["tenants"][user["tenant_id"]]
|
||||
scenario_ctx["user"], scenario_ctx["tenant"] = user, tenant
|
||||
|
||||
return scenario_ctx
|
||||
def _get_scenario_context(context_obj):
|
||||
return context.ContextManager(context_obj).map_for_scenario()
|
||||
|
||||
|
||||
def _run_scenario_once(args):
|
||||
iteration, cls, method_name, context, kwargs = args
|
||||
iteration, cls, method_name, context_obj, kwargs = args
|
||||
|
||||
LOG.info("Task %(task)s | ITER: %(iteration)s START" %
|
||||
{"task": context["task"]["uuid"], "iteration": iteration})
|
||||
{"task": context_obj["task"]["uuid"], "iteration": iteration})
|
||||
|
||||
context["iteration"] = iteration
|
||||
scenario = cls(context=context)
|
||||
context_obj["iteration"] = iteration
|
||||
scenario = cls(context_obj)
|
||||
|
||||
error = []
|
||||
scenario_output = {"errors": "", "data": {}}
|
||||
@@ -80,7 +69,7 @@ def _run_scenario_once(args):
|
||||
finally:
|
||||
status = "Error %s: %s" % tuple(error[0:2]) if error else "OK"
|
||||
LOG.info("Task %(task)s | ITER: %(iteration)s END: %(status)s" %
|
||||
{"task": context["task"]["uuid"], "iteration": iteration,
|
||||
{"task": context_obj["task"]["uuid"], "iteration": iteration,
|
||||
"status": status})
|
||||
|
||||
return {"duration": timer.duration() - scenario.idle_duration(),
|
||||
|
||||
@@ -1508,6 +1508,13 @@ class FakeContext(context.Context):
|
||||
"additionalProperties": False
|
||||
}
|
||||
|
||||
def __init__(self, context_obj=None):
|
||||
context_obj = context_obj or {}
|
||||
context_obj.setdefault("config", {})
|
||||
context_obj["config"].setdefault("fake", None)
|
||||
context_obj.setdefault("task", mock.MagicMock())
|
||||
super(FakeContext, self).__init__(context_obj)
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
@@ -1535,9 +1542,7 @@ class FakeUserContext(FakeContext):
|
||||
tenants = {"uuid": {"name": "tenant"}}
|
||||
|
||||
def __init__(self, ctx):
|
||||
ctx.setdefault("task", mock.MagicMock())
|
||||
super(FakeUserContext, self).__init__(ctx)
|
||||
|
||||
self.context.setdefault("admin", FakeUserContext.admin)
|
||||
self.context.setdefault("users", [FakeUserContext.user])
|
||||
self.context.setdefault("tenants", FakeUserContext.tenants)
|
||||
|
||||
@@ -33,8 +33,7 @@ class ConstantScenarioRunnerTestCase(test.TestCase):
|
||||
self.config = {"times": 4, "concurrency": 2,
|
||||
"timeout": 2, "type": "constant",
|
||||
"max_cpu_count": 2}
|
||||
self.context = fakes.FakeUserContext({"task":
|
||||
{"uuid": "uuid"}}).context
|
||||
self.context = fakes.FakeContext({"task": {"uuid": "uuid"}}).context
|
||||
self.args = {"a": 1}
|
||||
self.task = mock.MagicMock()
|
||||
|
||||
@@ -235,8 +234,7 @@ class ConstantForDurationScenarioRunnerTestCase(test.TestCase):
|
||||
super(ConstantForDurationScenarioRunnerTestCase, self).setUp()
|
||||
self.config = {"duration": 0, "concurrency": 2,
|
||||
"timeout": 2, "type": "constant_for_duration"}
|
||||
self.context = fakes.FakeUserContext({"task":
|
||||
{"uuid": "uuid"}}).context
|
||||
self.context = fakes.FakeContext({"task": {"uuid": "uuid"}}).context
|
||||
self.args = {"a": 1}
|
||||
|
||||
def test_validate(self):
|
||||
|
||||
@@ -132,13 +132,11 @@ class RPSScenarioRunnerTestCase(test.TestCase):
|
||||
|
||||
@mock.patch(RUNNERS + "rps.time.sleep")
|
||||
def test__run_scenario(self, mock_sleep):
|
||||
context = fakes.FakeUserContext({}).context
|
||||
context["task"] = {"uuid": "fake_uuid"}
|
||||
|
||||
config = {"times": 20, "rps": 20, "timeout": 5, "max_concurrency": 15}
|
||||
runner_obj = rps.RPSScenarioRunner(self.task, config)
|
||||
|
||||
runner_obj._run_scenario(fakes.FakeScenario, "do_it", context, {})
|
||||
runner_obj._run_scenario(fakes.FakeScenario, "do_it",
|
||||
fakes.FakeContext({}).context, {})
|
||||
|
||||
self.assertEqual(len(runner_obj.result_queue), config["times"])
|
||||
|
||||
@@ -147,28 +145,23 @@ class RPSScenarioRunnerTestCase(test.TestCase):
|
||||
|
||||
@mock.patch(RUNNERS + "rps.time.sleep")
|
||||
def test__run_scenario_exception(self, mock_sleep):
|
||||
context = fakes.FakeUserContext({}).context
|
||||
context["task"] = {"uuid": "fake_uuid"}
|
||||
|
||||
config = {"times": 4, "rps": 10}
|
||||
runner_obj = rps.RPSScenarioRunner(self.task, config)
|
||||
|
||||
runner_obj._run_scenario(fakes.FakeScenario, "something_went_wrong",
|
||||
context, {})
|
||||
fakes.FakeContext({}).context, {})
|
||||
self.assertEqual(len(runner_obj.result_queue), config["times"])
|
||||
for result in runner_obj.result_queue:
|
||||
self.assertIsNotNone(runner.ScenarioRunnerResult(result))
|
||||
|
||||
@mock.patch(RUNNERS + "rps.time.sleep")
|
||||
def test__run_scenario_aborted(self, mock_sleep):
|
||||
context = fakes.FakeUserContext({}).context
|
||||
context["task"] = {"uuid": "fake_uuid"}
|
||||
|
||||
config = {"times": 20, "rps": 20, "timeout": 5}
|
||||
runner_obj = rps.RPSScenarioRunner(self.task, config)
|
||||
|
||||
runner_obj.abort()
|
||||
runner_obj._run_scenario(fakes.FakeScenario, "do_it", context, {})
|
||||
runner_obj._run_scenario(fakes.FakeScenario, "do_it",
|
||||
fakes.FakeUser().context, {})
|
||||
|
||||
self.assertEqual(len(runner_obj.result_queue), 0)
|
||||
|
||||
@@ -184,8 +177,6 @@ class RPSScenarioRunnerTestCase(test.TestCase):
|
||||
def test_that_cpu_count_is_adjusted_properly(
|
||||
self, mock__join_processes, mock__create_process_pool,
|
||||
mock__log_debug_info, mock_cpu_count, mock_queue):
|
||||
context = fakes.FakeUserContext({}).context
|
||||
context["task"] = {"uuid": "fake_uuid"}
|
||||
|
||||
samples = [
|
||||
{
|
||||
@@ -260,7 +251,8 @@ class RPSScenarioRunnerTestCase(test.TestCase):
|
||||
|
||||
runner_obj = rps.RPSScenarioRunner(self.task, sample["input"])
|
||||
|
||||
runner_obj._run_scenario(fakes.FakeScenario, "do_it", context, {})
|
||||
runner_obj._run_scenario(fakes.FakeScenario, "do_it",
|
||||
fakes.FakeUser().context, {})
|
||||
|
||||
mock_cpu_count.assert_called_once_with()
|
||||
mock__log_debug_info.assert_called_once_with(
|
||||
@@ -283,9 +275,6 @@ class RPSScenarioRunnerTestCase(test.TestCase):
|
||||
mock_queue.return_value)
|
||||
|
||||
def test_abort(self):
|
||||
context = fakes.FakeUserContext({}).context
|
||||
context["task"] = {"uuid": "fake_uuid"}
|
||||
|
||||
config = {"times": 4, "rps": 10}
|
||||
runner_obj = rps.RPSScenarioRunner(self.task, config)
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@ from tests.unit import test
|
||||
|
||||
class SerialScenarioRunnerTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SerialScenarioRunnerTestCase, self).setUp()
|
||||
|
||||
@mock.patch("rally.task.runner._run_scenario_once")
|
||||
def test__run_scenario(self, mock__run_scenario_once):
|
||||
times = 5
|
||||
@@ -36,7 +33,7 @@ class SerialScenarioRunnerTestCase(test.TestCase):
|
||||
runner = serial.SerialScenarioRunner(mock.MagicMock(),
|
||||
{"times": times})
|
||||
runner._run_scenario(fakes.FakeScenario, "do_it",
|
||||
fakes.FakeUserContext({}).context, {})
|
||||
fakes.FakeContext().context, {})
|
||||
self.assertEqual(len(runner.result_queue), times)
|
||||
results = list(runner.result_queue)
|
||||
self.assertEqual(results, expected_results)
|
||||
@@ -46,7 +43,7 @@ class SerialScenarioRunnerTestCase(test.TestCase):
|
||||
{"times": 5})
|
||||
runner.abort()
|
||||
runner._run_scenario(fakes.FakeScenario, "do_it",
|
||||
fakes.FakeUserContext({}).context, {})
|
||||
fakes.FakeContext().context, {})
|
||||
self.assertEqual(len(runner.result_queue), 0)
|
||||
|
||||
def test_abort(self):
|
||||
|
||||
@@ -34,25 +34,6 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
tenants[str(id_)] = {"name": str(id_)}
|
||||
return tenants
|
||||
|
||||
@mock.patch("%s.images.context.Context.__init__" % CTX)
|
||||
def test_init(self, mock_context___init__):
|
||||
context = {}
|
||||
context["task"] = mock.MagicMock()
|
||||
context["config"] = {
|
||||
"images": {
|
||||
"image_url": "mock_url",
|
||||
"image_type": "qcow2",
|
||||
"image_container": "bare",
|
||||
"images_per_tenant": 4,
|
||||
"image_name": "some_name",
|
||||
"min_ram": 128,
|
||||
"min_disk": 1,
|
||||
}
|
||||
}
|
||||
|
||||
images.ImageGenerator(context)
|
||||
mock_context___init__.assert_called_once_with(context)
|
||||
|
||||
def test_init_validation(self):
|
||||
context = {}
|
||||
context["task"] = mock.MagicMock()
|
||||
|
||||
@@ -24,6 +24,42 @@ from tests.unit import test
|
||||
CTX = "rally.plugins.openstack.context.keystone.users"
|
||||
|
||||
|
||||
class UserContextMixinTestCase(test.TestCase):
|
||||
|
||||
@mock.patch("%s.random.choice" % CTX, side_effect=lambda x: x[1])
|
||||
def test_map_for_scenario(self, mock_choice):
|
||||
users_ = []
|
||||
tenants = {}
|
||||
|
||||
for i in range(2):
|
||||
tenants[str(i)] = {"name": str(i)}
|
||||
for j in range(3):
|
||||
users_.append({"id": "%s_%s" % (i, j),
|
||||
"tenant_id": str(i), "endpoint": "endpoint"})
|
||||
|
||||
context = {
|
||||
"admin": mock.MagicMock(),
|
||||
"users": users_,
|
||||
"tenants": tenants,
|
||||
"some_random_key": {
|
||||
"nested": mock.MagicMock(),
|
||||
"one_more": 10
|
||||
}
|
||||
}
|
||||
chosen_tenant = context["tenants"][context["users"][1]["tenant_id"]]
|
||||
expected_context = {
|
||||
"admin": context["admin"],
|
||||
"user": context["users"][1],
|
||||
"tenant": chosen_tenant,
|
||||
"some_random_key": context["some_random_key"]
|
||||
}
|
||||
|
||||
self.assertEqual(
|
||||
expected_context,
|
||||
users.UserContextMixin().map_for_scenario(context)
|
||||
)
|
||||
|
||||
|
||||
class UserGeneratorTestCase(test.TestCase):
|
||||
|
||||
tenants_num = 1
|
||||
@@ -42,6 +78,7 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
}
|
||||
},
|
||||
"admin": {"endpoint": mock.MagicMock()},
|
||||
"users": [],
|
||||
"task": {"uuid": "task_id"}
|
||||
}
|
||||
|
||||
@@ -54,6 +91,10 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
self.osclients_patcher.stop()
|
||||
super(UserGeneratorTestCase, self).tearDown()
|
||||
|
||||
def test_is_user_context_mixin_subclass(self):
|
||||
self.assertTrue(
|
||||
issubclass(users.UserGenerator, users.UserContextMixin))
|
||||
|
||||
@mock.patch("%s.network.wrap" % CTX)
|
||||
def test__remove_default_security_group_not_needed(self, mock_wrap):
|
||||
services = {"compute": consts.Service.NOVA}
|
||||
@@ -148,8 +189,8 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
nova_admin.networks.list.return_value = networks
|
||||
nova_admin.networks.get = fake_get_network
|
||||
user_generator = users.UserGenerator(self.context)
|
||||
user_generator.context["tenants"] = {"t1": dict(id="t1", name="t1"),
|
||||
"t2": dict(id="t2", name="t2")}
|
||||
user_generator.context["tenants"] = {"t1": {"id": "t1", "name": "t1"},
|
||||
"t2": {"id": "t2", "name": "t2"}}
|
||||
user_generator._remove_associated_networks()
|
||||
mock_check_service_status.assert_called_once_with(mock.ANY,
|
||||
"nova-network")
|
||||
@@ -175,8 +216,8 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
nova_admin.networks.get = fake_get_network
|
||||
nova_admin.networks.disassociate.side_effect = Exception()
|
||||
user_generator = users.UserGenerator(self.context)
|
||||
user_generator.context["tenants"] = {"t1": dict(id="t1", name="t1"),
|
||||
"t2": dict(id="t2", name="t2")}
|
||||
user_generator.context["tenants"] = {"t1": {"id": "t1", "name": "t1"},
|
||||
"t2": {"id": "t2", "name": "t2"}}
|
||||
user_generator._remove_associated_networks()
|
||||
mock_check_service_status.assert_called_once_with(mock.ANY,
|
||||
"nova-network")
|
||||
@@ -196,8 +237,8 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
@mock.patch("%s.keystone" % CTX)
|
||||
def test__create_users(self, mock_keystone, mock_sleep):
|
||||
user_generator = users.UserGenerator(self.context)
|
||||
user_generator.context["tenants"] = {"t1": dict(id="t1", name="t1"),
|
||||
"t2": dict(id="t2", name="t2")}
|
||||
user_generator.context["tenants"] = {"t1": {"id": "t1", "name": "t1"},
|
||||
"t2": {"id": "t2", "name": "t2"}}
|
||||
user_generator.config["users_per_tenant"] = 2
|
||||
users_ = user_generator._create_users()
|
||||
self.assertEqual(4, len(users_))
|
||||
@@ -208,8 +249,8 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
@mock.patch("%s.keystone" % CTX)
|
||||
def test__delete_tenants(self, mock_keystone):
|
||||
user_generator = users.UserGenerator(self.context)
|
||||
user_generator.context["tenants"] = {"t1": dict(id="t1", name="t1"),
|
||||
"t2": dict(id="t2", name="t2")}
|
||||
user_generator.context["tenants"] = {"t1": {"id": "t1", "name": "t1"},
|
||||
"t2": {"id": "t2", "name": "t2"}}
|
||||
user_generator._delete_tenants()
|
||||
self.assertEqual(len(user_generator.context["tenants"]), 0)
|
||||
|
||||
@@ -218,8 +259,8 @@ class UserGeneratorTestCase(test.TestCase):
|
||||
wrapped_keystone = mock_keystone.wrap.return_value
|
||||
wrapped_keystone.delete_project.side_effect = Exception()
|
||||
user_generator = users.UserGenerator(self.context)
|
||||
user_generator.context["tenants"] = {"t1": dict(id="t1", name="t1"),
|
||||
"t2": dict(id="t2", name="t2")}
|
||||
user_generator.context["tenants"] = {"t1": {"id": "t1", "name": "t1"},
|
||||
"t2": {"id": "t2", "name": "t2"}}
|
||||
user_generator._delete_tenants()
|
||||
self.assertEqual(len(user_generator.context["tenants"]), 0)
|
||||
|
||||
|
||||
@@ -41,10 +41,11 @@ class BaseContextTestCase(test.TestCase):
|
||||
|
||||
def test_init_empty_context(self):
|
||||
ctx0 = {
|
||||
"task": mock.MagicMock()
|
||||
"task": mock.MagicMock(),
|
||||
"config": {"fake": "test"}
|
||||
}
|
||||
ctx = fakes.FakeContext(ctx0)
|
||||
self.assertEqual(ctx.config, {})
|
||||
self.assertEqual(ctx.config, ctx0["config"]["fake"])
|
||||
self.assertEqual(ctx.task, ctx0["task"])
|
||||
self.assertEqual(ctx.context, ctx0)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from tests.unit import test
|
||||
BASE = "rally.task.runner."
|
||||
|
||||
|
||||
class ScenarioHelpersTestCase(test.TestCase):
|
||||
class ScenarioRunnerHelpersTestCase(test.TestCase):
|
||||
|
||||
@mock.patch(BASE + "utils.format_exc")
|
||||
def test_format_result_on_timeout(self, mock_format_exc):
|
||||
@@ -47,47 +47,27 @@ class ScenarioHelpersTestCase(test.TestCase):
|
||||
expected)
|
||||
mock_format_exc.assert_called_once_with(mock_exc)
|
||||
|
||||
@mock.patch(BASE + "random.choice", side_effect=lambda x: x[1])
|
||||
def test_get_scenario_context(self, mock_choice):
|
||||
@mock.patch(BASE + "context.ContextManager")
|
||||
def test_get_scenario_context(self, mock_context_manager):
|
||||
mock_context_obj = mock.MagicMock()
|
||||
mock_map_for_scenario = (
|
||||
mock_context_manager.return_value.map_for_scenario)
|
||||
|
||||
users = []
|
||||
tenants = {}
|
||||
self.assertEqual(mock_map_for_scenario.return_value,
|
||||
runner._get_scenario_context(mock_context_obj))
|
||||
|
||||
for i in range(2):
|
||||
tenants[str(i)] = dict(name=str(i))
|
||||
for j in range(3):
|
||||
users.append({"id": "%s_%s" % (i, j),
|
||||
"tenant_id": str(i), "endpoint": "endpoint"})
|
||||
|
||||
context = {
|
||||
"admin": mock.MagicMock(),
|
||||
"users": users,
|
||||
"tenants": tenants,
|
||||
"some_random_key": {
|
||||
"nested": mock.MagicMock(),
|
||||
"one_more": 10
|
||||
}
|
||||
}
|
||||
chosen_tenant = context["tenants"][context["users"][1]["tenant_id"]]
|
||||
expected_context = {
|
||||
"admin": context["admin"],
|
||||
"user": context["users"][1],
|
||||
"tenant": chosen_tenant,
|
||||
"some_random_key": context["some_random_key"]
|
||||
}
|
||||
|
||||
self.assertEqual(expected_context,
|
||||
runner._get_scenario_context(context))
|
||||
mock_context_manager.assert_called_once_with(mock_context_obj)
|
||||
mock_map_for_scenario.assert_called_once_with()
|
||||
|
||||
def test_run_scenario_once_internal_logic(self):
|
||||
context = runner._get_scenario_context(
|
||||
fakes.FakeUserContext({}).context)
|
||||
fakes.FakeContext({}).context)
|
||||
scenario_cls = mock.MagicMock()
|
||||
args = (2, scenario_cls, "test", context, {})
|
||||
runner._run_scenario_once(args)
|
||||
|
||||
expected_calls = [
|
||||
mock.call(context=context),
|
||||
mock.call(context),
|
||||
mock.call().test(),
|
||||
mock.call().idle_duration(),
|
||||
mock.call().idle_duration(),
|
||||
@@ -97,9 +77,7 @@ class ScenarioHelpersTestCase(test.TestCase):
|
||||
|
||||
@mock.patch(BASE + "rutils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_run_scenario_once_without_scenario_output(self, mock_timer):
|
||||
context = runner._get_scenario_context(
|
||||
fakes.FakeUserContext({}).context)
|
||||
args = (1, fakes.FakeScenario, "do_it", context, {})
|
||||
args = (1, fakes.FakeScenario, "do_it", mock.MagicMock(), {})
|
||||
result = runner._run_scenario_once(args)
|
||||
|
||||
expected_result = {
|
||||
@@ -114,9 +92,7 @@ class ScenarioHelpersTestCase(test.TestCase):
|
||||
|
||||
@mock.patch(BASE + "rutils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_run_scenario_once_with_scenario_output(self, mock_timer):
|
||||
context = runner._get_scenario_context(
|
||||
fakes.FakeUserContext({}).context)
|
||||
args = (1, fakes.FakeScenario, "with_output", context, {})
|
||||
args = (1, fakes.FakeScenario, "with_output", mock.MagicMock(), {})
|
||||
result = runner._run_scenario_once(args)
|
||||
|
||||
expected_result = {
|
||||
@@ -131,9 +107,8 @@ class ScenarioHelpersTestCase(test.TestCase):
|
||||
|
||||
@mock.patch(BASE + "rutils.Timer", side_effect=fakes.FakeTimer)
|
||||
def test_run_scenario_once_exception(self, mock_timer):
|
||||
context = runner._get_scenario_context(
|
||||
fakes.FakeUserContext({}).context)
|
||||
args = (1, fakes.FakeScenario, "something_went_wrong", context, {})
|
||||
args = (1, fakes.FakeScenario, "something_went_wrong",
|
||||
mock.MagicMock(), {})
|
||||
result = runner._run_scenario_once(args)
|
||||
expected_error = result.pop("error")
|
||||
expected_result = {
|
||||
|
||||
Reference in New Issue
Block a user