Port Senlin and others scenarios to new style

Since current scenario implementation transforms method to class
at runtime, it is reasonable to have class-based scenario
implementation which will be much simpler to use behind the scenes.

This class should be based on Scenario and do not break compatibility.
The only required method is run() which is actually a body of scenario.

This patch contains changes in following groups (scenarios and tests):
/senlin/
/swift/
/tempest/
/vm/
/watcher/
/zaqar/

and modules:

rally/plugins/openstack/context/vm/custom_image.py
tests/unit/test_docstrings.py

Change-Id: Ia7f33d7c279991232286b34abe199d125b92f023
This commit is contained in:
astaroverov 2016-09-01 15:20:15 +03:00
parent c10c5f9c88
commit eb66136085
16 changed files with 400 additions and 296 deletions

View File

@ -153,7 +153,9 @@ class BaseCustomImageGenerator(context.Context):
flavor_id = types.Flavor.transform( flavor_id = types.Flavor.transform(
clients=clients, resource_config=self.config["flavor"]) clients=clients, resource_config=self.config["flavor"])
vm_scenario = vmtasks.VMTasks(self.context, clients=clients) vm_scenario = vmtasks.BootRuncommandDeleteCustomImage(
self.context,
clients=clients)
glance_wrap = glance_wrapper.wrap(admin_clients.glance, self) glance_wrap = glance_wrapper.wrap(admin_clients.glance, self)

View File

@ -16,15 +16,18 @@ from rally.plugins.openstack.scenarios.senlin import utils
from rally.task import validation from rally.task import validation
class SenlinClusters(utils.SenlinScenario): """Scenarios for Senlin clusters."""
"""Benchmark scenarios for Senlin clusters."""
@validation.required_openstack(admin=True)
@validation.required_services(consts.Service.SENLIN) @validation.required_openstack(admin=True)
@validation.required_contexts("profiles") @validation.required_services(consts.Service.SENLIN)
@scenario.configure(context={"cleanup": ["senlin"]}) @validation.required_contexts("profiles")
def create_and_delete_cluster(self, desired_capacity=0, min_size=0, @scenario.configure(context={"cleanup": ["senlin"]},
max_size=-1, timeout=3600, metadata=None): name="SenlinClusters.create_and_delete_cluster")
class CreateAndDeleteCluster(utils.SenlinScenario):
def run(self, desired_capacity=0, min_size=0,
max_size=-1, timeout=3600, metadata=None):
"""Create a cluster and then delete it. """Create a cluster and then delete it.
Measure the "senlin cluster-create" and "senlin cluster-delete" Measure the "senlin cluster-create" and "senlin cluster-delete"
@ -38,7 +41,8 @@ class SenlinClusters(utils.SenlinScenario):
:param timeout: The timeout value in seconds for cluster creation :param timeout: The timeout value in seconds for cluster creation
:param metadata: A set of key value pairs to associate with the cluster :param metadata: A set of key value pairs to associate with the cluster
""" """
profile_id = self.context["tenant"]["profile"] profile_id = self.context["tenant"]["profile"]
cluster = self._create_cluster(profile_id, desired_capacity, cluster = self._create_cluster(profile_id, desired_capacity,
min_size, max_size, timeout, metadata) min_size, max_size, timeout, metadata)
self._delete_cluster(cluster) self._delete_cluster(cluster)

View File

@ -22,15 +22,17 @@ from rally.task import atomic
from rally.task import validation from rally.task import validation
class SwiftObjects(utils.SwiftScenario): """Scenarios for Swift Objects."""
"""Benchmark scenarios for Swift Objects."""
@validation.required_services(consts.Service.SWIFT)
@validation.required_openstack(users=True) @validation.required_services(consts.Service.SWIFT)
@scenario.configure(context={"cleanup": ["swift"]}) @validation.required_openstack(users=True)
def create_container_and_object_then_list_objects( @scenario.configure(context={"cleanup": ["swift"]},
self, objects_per_container=1, name="SwiftObjects.create_container"
object_size=1024, **kwargs): "_and_object_then_list_objects")
class CreateContainerAndObjectThenListObjects(utils.SwiftScenario):
def run(self, objects_per_container=1, object_size=1024, **kwargs):
"""Create container and objects then list all objects. """Create container and objects then list all objects.
:param objects_per_container: int, number of objects to upload :param objects_per_container: int, number of objects to upload
@ -53,12 +55,15 @@ class SwiftObjects(utils.SwiftScenario):
atomic_action=False) atomic_action=False)
self._list_objects(container_name) self._list_objects(container_name)
@validation.required_services(consts.Service.SWIFT)
@validation.required_openstack(users=True) @validation.required_services(consts.Service.SWIFT)
@scenario.configure(context={"cleanup": ["swift"]}) @validation.required_openstack(users=True)
def create_container_and_object_then_delete_all( @scenario.configure(context={"cleanup": ["swift"]},
self, objects_per_container=1, name="SwiftObjects.create_container"
object_size=1024, **kwargs): "_and_object_then_delete_all")
class CreateContainerAndObjectThenDeleteAll(utils.SwiftScenario):
def run(self, objects_per_container=1, object_size=1024, **kwargs):
"""Create container and objects then delete everything created. """Create container and objects then delete everything created.
:param objects_per_container: int, number of objects to upload :param objects_per_container: int, number of objects to upload
@ -89,12 +94,15 @@ class SwiftObjects(utils.SwiftScenario):
atomic_action=False) atomic_action=False)
self._delete_container(container_name) self._delete_container(container_name)
@validation.required_services(consts.Service.SWIFT)
@validation.required_openstack(users=True) @validation.required_services(consts.Service.SWIFT)
@scenario.configure(context={"cleanup": ["swift"]}) @validation.required_openstack(users=True)
def create_container_and_object_then_download_object( @scenario.configure(context={"cleanup": ["swift"]},
self, objects_per_container=1, name="SwiftObjects.create_container"
object_size=1024, **kwargs): "_and_object_then_download_object")
class CreateContainerAndObjectThenDownloadObject(utils.SwiftScenario):
def run(self, objects_per_container=1, object_size=1024, **kwargs):
"""Create container and objects then download all objects. """Create container and objects then download all objects.
:param objects_per_container: int, number of objects to upload :param objects_per_container: int, number of objects to upload
@ -124,11 +132,16 @@ class SwiftObjects(utils.SwiftScenario):
self._download_object(container_name, object_name, self._download_object(container_name, object_name,
atomic_action=False) atomic_action=False)
@validation.required_services(consts.Service.SWIFT)
@validation.required_openstack(users=True) @validation.required_services(consts.Service.SWIFT)
@scenario.configure(context={"swift_objects": {}}) @validation.required_openstack(users=True)
def list_objects_in_containers(self): @scenario.configure(context={"swift_objects": {}},
name="SwiftObjects.list_objects_in_containers")
class ListObjectsInContainers(utils.SwiftScenario):
def run(self):
"""List objects in all containers.""" """List objects in all containers."""
containers = self._list_containers()[1] containers = self._list_containers()[1]
key_suffix = "container" key_suffix = "container"
@ -139,11 +152,17 @@ class SwiftObjects(utils.SwiftScenario):
for container in containers: for container in containers:
self._list_objects(container["name"], atomic_action=False) self._list_objects(container["name"], atomic_action=False)
@validation.required_services(consts.Service.SWIFT)
@validation.required_openstack(users=True) @validation.required_services(consts.Service.SWIFT)
@scenario.configure(context={"swift_objects": {}}) @validation.required_openstack(users=True)
def list_and_download_objects_in_containers(self): @scenario.configure(context={"swift_objects": {}},
name="SwiftObjects.list_and_"
"download_objects_in_containers")
class ListAndDownloadObjectsInContainers(utils.SwiftScenario):
def run(self):
"""List and download objects in all containers.""" """List and download objects in all containers."""
containers = self._list_containers()[1] containers = self._list_containers()[1]
list_key_suffix = "container" list_key_suffix = "container"
@ -169,4 +188,4 @@ class SwiftObjects(utils.SwiftScenario):
for container_name, objects in objects_dict.items(): for container_name, objects in objects_dict.items():
for obj in objects: for obj in objects:
self._download_object(container_name, obj["name"], self._download_object(container_name, obj["name"],
atomic_action=False) atomic_action=False)

View File

@ -19,31 +19,38 @@ from rally.plugins.openstack.scenarios.tempest import utils
from rally.task import validation from rally.task import validation
class TempestScenario(scenario.OpenStackScenario): """Scenarios that launch Tempest tests."""
"""Benchmark scenarios that launch Tempest tests."""
@validation.tempest_tests_exists()
@validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}},
name="TempestScenario.single_test")
class SingleTest(scenario.OpenStackScenario):
@validation.tempest_tests_exists()
@validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}})
@utils.tempest_log_wrapper @utils.tempest_log_wrapper
def single_test(self, test_name, log_file, tempest_conf=None): def run(self, test_name, log_file, tempest_conf=None):
"""Launch a single Tempest test by its name. """Launch a single Tempest test by its name.
:param test_name: name of tempest scenario for launching :param test_name: name of tempest scenario for launching
:param log_file: name of file for junitxml results :param log_file: name of file for junitxml results
:param tempest_conf: User specified tempest.conf location :param tempest_conf: User specified tempest.conf location
""" """
if (not test_name.startswith("tempest.api.") if (not test_name.startswith("tempest.api.") and
and test_name.split(".")[0] in consts.TempestTestsAPI): test_name.split(".")[0] in consts.TempestTestsAPI):
test_name = "tempest.api." + test_name test_name = "tempest.api." + test_name
self.context["verifier"].run(test_name, log_file=log_file, self.context["verifier"].run(test_name, log_file=log_file,
tempest_conf=tempest_conf) tempest_conf=tempest_conf)
@validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}}) @validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}},
name="TempestScenario.all")
class All(scenario.OpenStackScenario):
@utils.tempest_log_wrapper @utils.tempest_log_wrapper
def all(self, log_file, tempest_conf=None): def run(self, log_file, tempest_conf=None):
"""Launch all discovered Tempest tests by their names. """Launch all discovered Tempest tests by their names.
:param log_file: name of file for junitxml results :param log_file: name of file for junitxml results
@ -53,11 +60,15 @@ class TempestScenario(scenario.OpenStackScenario):
self.context["verifier"].run("", log_file=log_file, self.context["verifier"].run("", log_file=log_file,
tempest_conf=tempest_conf) tempest_conf=tempest_conf)
@validation.tempest_set_exists()
@validation.required_openstack(admin=True) @validation.tempest_set_exists()
@scenario.configure(context={"tempest": {}}) @validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}},
name="TempestScenario.set")
class Set(scenario.OpenStackScenario):
@utils.tempest_log_wrapper @utils.tempest_log_wrapper
def set(self, set_name, log_file, tempest_conf=None): def run(self, set_name, log_file, tempest_conf=None):
"""Launch all Tempest tests from a given set. """Launch all Tempest tests from a given set.
:param set_name: set name of tempest scenarios for launching :param set_name: set name of tempest scenarios for launching
@ -75,11 +86,15 @@ class TempestScenario(scenario.OpenStackScenario):
self.context["verifier"].run(testr_arg, log_file=log_file, self.context["verifier"].run(testr_arg, log_file=log_file,
tempest_conf=tempest_conf) tempest_conf=tempest_conf)
@validation.tempest_tests_exists()
@validation.required_openstack(admin=True) @validation.tempest_tests_exists()
@scenario.configure(context={"tempest": {}}) @validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}},
name="TempestScenario.list_of_tests")
class ListOfTests(scenario.OpenStackScenario):
@utils.tempest_log_wrapper @utils.tempest_log_wrapper
def list_of_tests(self, test_names, log_file, tempest_conf=None): def run(self, test_names, log_file, tempest_conf=None):
"""Launch all Tempest tests from a given list of their names. """Launch all Tempest tests from a given list of their names.
:param test_names: list of tempest scenarios for launching :param test_names: list of tempest scenarios for launching
@ -90,10 +105,14 @@ class TempestScenario(scenario.OpenStackScenario):
self.context["verifier"].run(" ".join(test_names), log_file=log_file, self.context["verifier"].run(" ".join(test_names), log_file=log_file,
tempest_conf=tempest_conf) tempest_conf=tempest_conf)
@validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}}) @validation.required_openstack(admin=True)
@scenario.configure(context={"tempest": {}},
name="TempestScenario.specific_regex")
class SpecificRegex(scenario.OpenStackScenario):
@utils.tempest_log_wrapper @utils.tempest_log_wrapper
def specific_regex(self, regex, log_file, tempest_conf=None): def run(self, regex, log_file, tempest_conf=None):
"""Launch Tempest tests whose names match a given regular expression. """Launch Tempest tests whose names match a given regular expression.
:param regex: regexp to match Tempest test names against :param regex: regexp to match Tempest test names against
@ -102,4 +121,4 @@ class TempestScenario(scenario.OpenStackScenario):
""" """
self.context["verifier"].run(regex, log_file=log_file, self.context["verifier"].run(regex, log_file=log_file,
tempest_conf=tempest_conf) tempest_conf=tempest_conf)

View File

@ -27,46 +27,36 @@ from rally.task import atomic
from rally.task import types from rally.task import types
from rally.task import validation from rally.task import validation
"""Scenarios that are to be run inside VM instances."""
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class VMTasks(vm_utils.VMScenario): @types.convert(image={"type": "glance_image"},
"""Benchmark scenarios that are to be run inside VM instances.""" flavor={"type": "nova_flavor"})
@validation.image_valid_on_flavor("flavor", "image")
@validation.valid_command("command")
@validation.number("port", minval=1, maxval=65535, nullable=True,
integer_only=True)
@validation.external_network_exists("floating_network")
@validation.required_services(consts.Service.NOVA, consts.Service.CINDER)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["nova", "cinder"],
"keypair": {}, "allow_ssh": {}},
name="VMTasks.boot_runcommand_delete")
class BootRuncommandDelete(vm_utils.VMScenario):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(VMTasks, self).__init__(*args, **kwargs) super(BootRuncommandDelete, self).__init__(*args, **kwargs)
@types.convert(image={"type": "glance_image"}, def run(self, image, flavor, username, password=None, command=None,
flavor={"type": "nova_flavor"}) volume_args=None, floating_network=None, port=22,
@validation.image_valid_on_flavor("flavor", "image") use_floating_ip=True, force_delete=False, wait_for_ping=True,
@validation.valid_command("command") max_log_length=None, **kwargs):
@validation.number("port", minval=1, maxval=65535, nullable=True,
integer_only=True)
@validation.external_network_exists("floating_network")
@validation.required_services(consts.Service.NOVA, consts.Service.CINDER)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["nova", "cinder"],
"keypair": {}, "allow_ssh": {}})
def boot_runcommand_delete(self, image, flavor,
username,
password=None,
command=None,
volume_args=None,
floating_network=None,
port=22,
use_floating_ip=True,
force_delete=False,
wait_for_ping=True,
max_log_length=None,
**kwargs):
"""Boot a server, run script specified in command and delete server. """Boot a server, run script specified in command and delete server.
Example Script in samples/tasks/support/instance_dd_test.sh
The script to be executed is provided like command['remote_path'] or
command['local_path'] and interpreter in command['interpreter']
respectively.
:param image: glance image name to use for the vm :param image: glance image name to use for the vm
:param flavor: VM flavor name :param flavor: VM flavor name
:param username: ssh username on server, str :param username: ssh username on server, str
@ -223,46 +213,60 @@ class VMTasks(vm_utils.VMScenario):
for chart in charts: for chart in charts:
self.add_output(**{chart_type: chart}) self.add_output(**{chart_type: chart})
@types.convert(image={"type": "glance_image"},
flavor={"type": "nova_flavor"}) @types.convert(image={"type": "glance_image"},
@validation.number("port", minval=1, maxval=65535, nullable=True, flavor={"type": "nova_flavor"})
integer_only=True) @validation.number("port", minval=1, maxval=65535, nullable=True,
@validation.valid_command("command") integer_only=True)
@validation.external_network_exists("floating_network") @validation.valid_command("command")
@validation.required_services(consts.Service.NOVA, consts.Service.CINDER) @validation.external_network_exists("floating_network")
@validation.required_openstack(users=True) @validation.required_services(consts.Service.NOVA, consts.Service.CINDER)
@validation.required_contexts("image_command_customizer") @validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["nova", "cinder"], @validation.required_contexts("image_command_customizer")
"keypair": {}, "allow_ssh": {}}) @scenario.configure(context={"cleanup": ["nova", "cinder"],
def boot_runcommand_delete_custom_image(self, **kwargs): "keypair": {}, "allow_ssh": {}},
name="VMTasks.boot_runcommand_delete_custom_image")
class BootRuncommandDeleteCustomImage(vm_utils.VMScenario):
def __init__(self, *args, **kwargs):
super(BootRuncommandDeleteCustomImage, self).__init__(*args, **kwargs)
def run(self, **kwargs):
"""Boot a server from a custom image, run a command that outputs JSON. """Boot a server from a custom image, run a command that outputs JSON.
Example Script in rally-jobs/extra/install_benchmark.sh Example Script in rally-jobs/extra/install_benchmark.sh
""" """
boot_runcommand_delete = BootRuncommandDelete(self.context)
return self.boot_runcommand_delete( return boot_runcommand_delete.run(
image=self.context["tenant"]["custom_image"]["id"], **kwargs) image=self.context["tenant"]["custom_image"]["id"], **kwargs)
@scenario.configure(context={"cleanup": ["nova", "heat"],
"keypair": {}, "network": {}}) @scenario.configure(context={"cleanup": ["nova", "heat"],
def runcommand_heat(self, workload, template, files, parameters): "keypair": {}, "network": {}},
name="VMTasks.runcommand_heat")
class RuncommandHeat(vm_utils.VMScenario):
def __init__(self, *args, **kwargs):
super(RuncommandHeat, self).__init__(*args, **kwargs)
def run(self, workload, template, files, parameters):
"""Run workload on stack deployed by heat. """Run workload on stack deployed by heat.
Workload can be either file or resource: Workload can be either file or resource:
.. code-block: json .. code-block: json
{"file": "/path/to/file.sh"} {"file": "/path/to/file.sh"}
{"resource": ["package.module", "workload.py"]} {"resource": ["package.module", "workload.py"]}
Also it should contain "username" key. Also it should contain "username" key.
Given file will be uploaded to `gate_node` and started. This script Given file will be uploaded to `gate_node` and started. This script
should print `key` `value` pairs separated by colon. These pairs will should print `key` `value` pairs separated by colon. These pairs will
be presented in results. be presented in results.
Gate node should be accessible via ssh with keypair `key_name`, so Gate node should be accessible via ssh with keypair `key_name`, so
heat template should accept parameter `key_name`. heat template should accept parameter `key_name`.
:param workload: workload to run :param workload: workload to run
:param template: path to heat template file :param template: path to heat template file
@ -310,4 +314,4 @@ class VMTasks(vm_utils.VMScenario):
"data": { "data": {
"cols": ["key", "value"], "cols": ["key", "value"],
"rows": rows}} "rows": rows}}
) )

View File

@ -17,15 +17,18 @@ from rally.task import types
from rally.task import validation from rally.task import validation
class Watcher(utils.WatcherScenario): """Scenarios for Watcher servers."""
"""Benchmark scenarios for Watcher servers."""
@types.convert(strategy={"type": "watcher_strategy"},
goal={"type": "watcher_goal"}) @types.convert(strategy={"type": "watcher_strategy"},
@validation.required_services(consts.Service.WATCHER) goal={"type": "watcher_goal"})
@validation.required_openstack(admin=True) @validation.required_services(consts.Service.WATCHER)
@scenario.configure(context={"admin_cleanup": ["watcher"]}) @validation.required_openstack(admin=True)
def create_audit_template_and_delete(self, goal, strategy, extra=None): @scenario.configure(context={"admin_cleanup": ["watcher"]},
name="Watcher.create_audit_template_and_delete")
class CreateAuditTemplateAndDelete(utils.WatcherScenario):
def run(self, goal, strategy, extra=None):
"""Create audit template and delete it. """Create audit template and delete it.
:param goal: The goal audit template is based on :param goal: The goal audit template is based on
@ -39,11 +42,14 @@ class Watcher(utils.WatcherScenario):
audit_template = self._create_audit_template(goal, strategy, extra) audit_template = self._create_audit_template(goal, strategy, extra)
self._delete_audit_template(audit_template.uuid) self._delete_audit_template(audit_template.uuid)
@validation.required_services(consts.Service.WATCHER)
@scenario.configure() @validation.required_services(consts.Service.WATCHER)
def list_audit_templates(self, name=None, goal=None, strategy=None, @scenario.configure(name="Watcher.list_audit_templates")
limit=None, sort_key=None, sort_dir=None, class ListAuditTemplates(utils.WatcherScenario):
detail=False):
def run(self, name=None, goal=None, strategy=None,
limit=None, sort_key=None, sort_dir=None,
detail=False):
"""List existing audit templates. """List existing audit templates.
Audit templates are being created by Audit Template Context. Audit templates are being created by Audit Template Context.
@ -69,10 +75,14 @@ class Watcher(utils.WatcherScenario):
limit=limit, sort_key=sort_key, limit=limit, sort_key=sort_key,
sort_dir=sort_dir, detail=detail) sort_dir=sort_dir, detail=detail)
@validation.required_services(consts.Service.WATCHER)
@validation.required_contexts("audit_templates") @validation.required_services(consts.Service.WATCHER)
@scenario.configure(context={"admin_cleanup": ["watcher"]}) @validation.required_contexts("audit_templates")
def create_audit_and_delete(self): @scenario.configure(context={"admin_cleanup": ["watcher"]},
name="Watcher.create_audit_and_delete")
class CreateAuditAndDelete(utils.WatcherScenario):
def run(self):
"""Create and delete audit. """Create and delete audit.
Create Audit, wait until whether Audit is in SUCCEEDED state or in Create Audit, wait until whether Audit is in SUCCEEDED state or in
@ -81,4 +91,4 @@ class Watcher(utils.WatcherScenario):
audit_template_uuid = self.context["audit_templates"][0] audit_template_uuid = self.context["audit_templates"][0]
audit = self._create_audit(audit_template_uuid) audit = self._create_audit(audit_template_uuid)
self._delete_audit(audit) self._delete_audit(audit)

View File

@ -19,14 +19,17 @@ from rally.plugins.openstack import scenario
from rally.plugins.openstack.scenarios.zaqar import utils as zutils from rally.plugins.openstack.scenarios.zaqar import utils as zutils
class ZaqarBasic(zutils.ZaqarScenario): """Scenarios for Zaqar."""
"""Benchmark scenarios for Zaqar."""
@scenario.configure(context={"cleanup": ["zaqar"]},
name="ZaqarBasic.create_queue")
class CreateQueue(zutils.ZaqarScenario):
@scenario.configure(context={"cleanup": ["zaqar"]})
@logging.log_deprecated_args( @logging.log_deprecated_args(
"The 'name_length' argument to create_queue is ignored", "The 'name_length' argument to create_queue is ignored",
"0.1.2", ["name_length"], once=True) "0.1.2", ["name_length"], once=True)
def create_queue(self, name_length=None, **kwargs): def run(self, name_length=None, **kwargs):
"""Create a Zaqar queue with a random name. """Create a Zaqar queue with a random name.
:param kwargs: other optional parameters to create queues like :param kwargs: other optional parameters to create queues like
@ -34,12 +37,16 @@ class ZaqarBasic(zutils.ZaqarScenario):
""" """
self._queue_create(**kwargs) self._queue_create(**kwargs)
@scenario.configure(context={"cleanup": ["zaqar"]})
@scenario.configure(context={"cleanup": ["zaqar"]},
name="ZaqarBasic.producer_consumer")
class ProducerConsumer(zutils.ZaqarScenario):
@logging.log_deprecated_args( @logging.log_deprecated_args(
"The 'name_length' argument to producer_consumer is ignored", "The 'name_length' argument to producer_consumer is ignored",
"0.1.2", ["name_length"], once=True) "0.1.2", ["name_length"], once=True)
def producer_consumer(self, name_length=None, def run(self, name_length=None,
min_msg_count=50, max_msg_count=200, **kwargs): min_msg_count=50, max_msg_count=200, **kwargs):
"""Serial message producer/consumer. """Serial message producer/consumer.
Creates a Zaqar queue with random name, sends a set of messages Creates a Zaqar queue with random name, sends a set of messages
@ -57,4 +64,4 @@ class ZaqarBasic(zutils.ZaqarScenario):
in range(msg_count)] in range(msg_count)]
self._messages_post(queue, messages, min_msg_count, max_msg_count) self._messages_post(queue, messages, min_msg_count, max_msg_count)
self._messages_list(queue) self._messages_list(queue)
self._queue_delete(queue) self._queue_delete(queue)

View File

@ -62,26 +62,26 @@ class BaseCustomImageContextVMTestCase(test.TestCase):
} }
}) })
@mock.patch("%s.vmtasks.VMTasks" % BASE)
@mock.patch("%s.osclients.Clients" % BASE) @mock.patch("%s.osclients.Clients" % BASE)
@mock.patch("%s.types.GlanceImage.transform" % BASE, return_value="image") @mock.patch("%s.types.GlanceImage.transform" % BASE, return_value="image")
@mock.patch("%s.types.Flavor.transform" % BASE, return_value="flavor") @mock.patch("%s.types.Flavor.transform" % BASE, return_value="flavor")
@mock.patch("rally.plugins.openstack.wrappers.glance.wrap") @mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
@mock.patch("%s.vmtasks.BootRuncommandDeleteCustomImage" % BASE)
def test_create_one_image( def test_create_one_image(
self, mock_glance_wrap, mock_flavor_transform, self, mock_scenario, mock_glance_wrap, mock_flavor_transform,
mock_glance_image_transform, mock_clients, mock_vm_tasks): mock_glance_image_transform, mock_clients
):
ip = {"ip": "foo_ip", "id": "foo_id", "is_floating": True} ip = {"ip": "foo_ip", "id": "foo_id", "is_floating": True}
fake_server = mock.Mock() fake_server = mock.Mock()
fake_image = mock.MagicMock( fake_image = mock.MagicMock(
to_dict=mock.MagicMock(return_value={"id": "image"})) to_dict=mock.MagicMock(return_value={"id": "image"}))
mock_vm_scenario = mock_vm_tasks.return_value = mock.MagicMock( scenario = mock_scenario.return_value = mock.MagicMock(
_create_image=mock.MagicMock(return_value=fake_image), _create_image=mock.MagicMock(return_value=fake_image),
_boot_server_with_fip=mock.MagicMock( _boot_server_with_fip=mock.MagicMock(
return_value=(fake_server, ip)) return_value=(fake_server, ip))
) )
generator_ctx = TestImageGenerator(self.context) generator_ctx = TestImageGenerator(self.context)
generator_ctx._customize_image = mock.MagicMock() generator_ctx._customize_image = mock.MagicMock()
@ -103,47 +103,47 @@ class BaseCustomImageContextVMTestCase(test.TestCase):
mock_glance_image_transform.assert_called_once_with( mock_glance_image_transform.assert_called_once_with(
clients=mock_clients.return_value, clients=mock_clients.return_value,
resource_config={"name": "image"}) resource_config={"name": "image"})
mock_vm_tasks.assert_called_once_with( mock_scenario.assert_called_once_with(
self.context, clients=mock_clients.return_value) self.context, clients=mock_clients.return_value)
mock_vm_scenario._boot_server_with_fip.assert_called_once_with( scenario._boot_server_with_fip.assert_called_once_with(
image="image", flavor="flavor", image="image", flavor="flavor",
floating_network="floating", floating_network="floating",
key_name="keypair_name", security_groups=["secgroup_name"], key_name="keypair_name", security_groups=["secgroup_name"],
userdata=None, foo_arg="foo_value") userdata=None, foo_arg="foo_value")
mock_vm_scenario._stop_server.assert_called_once_with(fake_server) scenario._stop_server.assert_called_once_with(fake_server)
generator_ctx._customize_image.assert_called_once_with( generator_ctx._customize_image.assert_called_once_with(
fake_server, ip, user) fake_server, ip, user)
mock_vm_scenario._create_image.assert_called_once_with(fake_server) scenario._create_image.assert_called_once_with(fake_server)
mock_glance_wrap.return_value.set_visibility.assert_called_once_with( mock_glance_wrap.return_value.set_visibility.assert_called_once_with(
fake_image) fake_image)
mock_vm_scenario._delete_server_with_fip.assert_called_once_with( scenario._delete_server_with_fip.assert_called_once_with(
fake_server, ip) fake_server, ip)
self.assertEqual({"id": "image"}, custom_image) self.assertEqual({"id": "image"}, custom_image)
@mock.patch("%s.vmtasks.VMTasks" % BASE)
@mock.patch("%s.osclients.Clients" % BASE) @mock.patch("%s.osclients.Clients" % BASE)
@mock.patch("%s.types.GlanceImage.transform" % BASE, @mock.patch("%s.types.GlanceImage.transform" % BASE,
return_value="image") return_value="image")
@mock.patch("%s.types.Flavor.transform" % BASE, @mock.patch("%s.types.Flavor.transform" % BASE,
return_value="flavor") return_value="flavor")
@mock.patch("rally.plugins.openstack.wrappers.glance.wrap") @mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
@mock.patch("%s.vmtasks.BootRuncommandDeleteCustomImage" % BASE)
def test_create_one_image_cleanup( def test_create_one_image_cleanup(
self, mock_glance_wrap, mock_flavor_transform, self, mock_scenario, mock_glance_wrap, mock_flavor_transform,
mock_glance_image_transform, mock_clients, mock_glance_image_transform, mock_clients
mock_vm_tasks): ):
ip = {"ip": "foo_ip", "id": "foo_id", "is_floating": True} ip = {"ip": "foo_ip", "id": "foo_id", "is_floating": True}
fake_server = mock.Mock() fake_server = mock.Mock()
fake_image = mock.MagicMock( fake_image = mock.MagicMock(
to_dict=mock.MagicMock(return_value={"id": "image"})) to_dict=mock.MagicMock(return_value={"id": "image"}))
mock_vm_scenario = mock_vm_tasks.return_value = mock.MagicMock( scenario = mock_scenario.return_value = mock.MagicMock(
_create_image=mock.MagicMock(return_value=fake_image), _create_image=mock.MagicMock(return_value=fake_image),
_boot_server_with_fip=mock.MagicMock( _boot_server_with_fip=mock.MagicMock(
return_value=(fake_server, ip)), return_value=(fake_server, ip)),
@ -167,7 +167,7 @@ class BaseCustomImageContextVMTestCase(test.TestCase):
generator_ctx._customize_image.assert_called_once_with( generator_ctx._customize_image.assert_called_once_with(
fake_server, ip, user) fake_server, ip, user)
mock_vm_scenario._delete_server_with_fip.assert_called_once_with( scenario._delete_server_with_fip.assert_called_once_with(
fake_server, ip) fake_server, ip)
@mock.patch("%s.nova_utils.NovaScenario" % BASE) @mock.patch("%s.nova_utils.NovaScenario" % BASE)

View File

@ -21,13 +21,12 @@ class SenlinClustersTestCase(test.ScenarioTestCase):
def test_create_and_delete_cluster(self): def test_create_and_delete_cluster(self):
mock_cluster = mock.Mock() mock_cluster = mock.Mock()
self.context["tenant"] = {"profile": "fake_profile_id"} self.context["tenant"] = {"profile": "fake_profile_id"}
scenario = clusters.SenlinClusters(self.context) scenario = clusters.CreateAndDeleteCluster(self.context)
scenario._create_cluster = mock.Mock(return_value=mock_cluster) scenario._create_cluster = mock.Mock(return_value=mock_cluster)
scenario._delete_cluster = mock.Mock() scenario._delete_cluster = mock.Mock()
scenario.create_and_delete_cluster(desired_capacity=1, min_size=0, scenario.run(desired_capacity=1, min_size=0,
max_size=3, timeout=60, max_size=3, timeout=60, metadata={"k2": "v2"})
metadata={"k2": "v2"})
scenario._create_cluster.assert_called_once_with("fake_profile_id", scenario._create_cluster.assert_called_once_with("fake_profile_id",
1, 0, 3, 60, 1, 0, 3, 60,

View File

@ -24,14 +24,13 @@ from tests.unit import test
class SwiftObjectsTestCase(test.ScenarioTestCase): class SwiftObjectsTestCase(test.ScenarioTestCase):
def test_create_container_and_object_then_list_objects(self): def test_create_container_and_object_then_list_objects(self):
scenario = objects.SwiftObjects(self.context) scenario = objects.CreateContainerAndObjectThenListObjects(
self.context)
scenario._create_container = mock.MagicMock(return_value="AA") scenario._create_container = mock.MagicMock(return_value="AA")
scenario._upload_object = mock.MagicMock() scenario._upload_object = mock.MagicMock()
scenario._list_objects = mock.MagicMock() scenario._list_objects = mock.MagicMock()
scenario.create_container_and_object_then_list_objects( scenario.run(objects_per_container=5, object_size=100)
objects_per_container=5,
object_size=100)
self.assertEqual(1, scenario._create_container.call_count) self.assertEqual(1, scenario._create_container.call_count)
self.assertEqual(5, scenario._upload_object.call_count) self.assertEqual(5, scenario._upload_object.call_count)
@ -41,16 +40,14 @@ class SwiftObjectsTestCase(test.ScenarioTestCase):
"swift.create_5_objects") "swift.create_5_objects")
def test_create_container_and_object_then_delete_all(self): def test_create_container_and_object_then_delete_all(self):
scenario = objects.SwiftObjects(self.context) scenario = objects.CreateContainerAndObjectThenDeleteAll(self.context)
scenario._create_container = mock.MagicMock(return_value="BB") scenario._create_container = mock.MagicMock(return_value="BB")
scenario._upload_object = mock.MagicMock( scenario._upload_object = mock.MagicMock(
side_effect=[("etaaag", "ooobj_%i" % i) for i in range(3)]) side_effect=[("etaaag", "ooobj_%i" % i) for i in range(3)])
scenario._delete_object = mock.MagicMock() scenario._delete_object = mock.MagicMock()
scenario._delete_container = mock.MagicMock() scenario._delete_container = mock.MagicMock()
scenario.create_container_and_object_then_delete_all( scenario.run(objects_per_container=3, object_size=10)
objects_per_container=3,
object_size=10)
self.assertEqual(1, scenario._create_container.call_count) self.assertEqual(1, scenario._create_container.call_count)
self.assertEqual(3, scenario._upload_object.call_count) self.assertEqual(3, scenario._upload_object.call_count)
@ -65,15 +62,15 @@ class SwiftObjectsTestCase(test.ScenarioTestCase):
"swift.delete_3_objects") "swift.delete_3_objects")
def test_create_container_and_object_then_download_object(self): def test_create_container_and_object_then_download_object(self):
scenario = objects.SwiftObjects(self.context) scenario = objects.CreateContainerAndObjectThenDownloadObject(
self.context
)
scenario._create_container = mock.MagicMock(return_value="CC") scenario._create_container = mock.MagicMock(return_value="CC")
scenario._upload_object = mock.MagicMock( scenario._upload_object = mock.MagicMock(
side_effect=[("etaaaag", "obbbj_%i" % i) for i in range(2)]) side_effect=[("etaaaag", "obbbj_%i" % i) for i in range(2)])
scenario._download_object = mock.MagicMock() scenario._download_object = mock.MagicMock()
scenario.create_container_and_object_then_download_object( scenario.run(objects_per_container=2, object_size=50)
objects_per_container=2,
object_size=50)
self.assertEqual(1, scenario._create_container.call_count) self.assertEqual(1, scenario._create_container.call_count)
self.assertEqual(2, scenario._upload_object.call_count) self.assertEqual(2, scenario._upload_object.call_count)
@ -89,12 +86,12 @@ class SwiftObjectsTestCase(test.ScenarioTestCase):
@ddt.data(1, 5) @ddt.data(1, 5)
def test_list_objects_in_containers(self, num_cons): def test_list_objects_in_containers(self, num_cons):
con_list = [{"name": "cooon_%s" % i} for i in range(num_cons)] con_list = [{"name": "cooon_%s" % i} for i in range(num_cons)]
scenario = objects.SwiftObjects() scenario = objects.ListObjectsInContainers(self.context)
scenario._list_containers = mock.MagicMock(return_value=("header", scenario._list_containers = mock.MagicMock(return_value=("header",
con_list)) con_list))
scenario._list_objects = mock.MagicMock() scenario._list_objects = mock.MagicMock()
scenario.list_objects_in_containers() scenario.run()
scenario._list_containers.assert_called_once_with() scenario._list_containers.assert_called_once_with()
con_calls = [mock.call(container["name"], atomic_action=False) con_calls = [mock.call(container["name"], atomic_action=False)
for container in con_list] for container in con_list]
@ -111,14 +108,14 @@ class SwiftObjectsTestCase(test.ScenarioTestCase):
def test_list_and_download_objects_in_containers(self, num_cons, num_objs): def test_list_and_download_objects_in_containers(self, num_cons, num_objs):
con_list = [{"name": "connn_%s" % i} for i in range(num_cons)] con_list = [{"name": "connn_%s" % i} for i in range(num_cons)]
obj_list = [{"name": "ooobj_%s" % i} for i in range(num_objs)] obj_list = [{"name": "ooobj_%s" % i} for i in range(num_objs)]
scenario = objects.SwiftObjects() scenario = objects.ListAndDownloadObjectsInContainers(self.context)
scenario._list_containers = mock.MagicMock(return_value=("header", scenario._list_containers = mock.MagicMock(return_value=("header",
con_list)) con_list))
scenario._list_objects = mock.MagicMock(return_value=("header", scenario._list_objects = mock.MagicMock(return_value=("header",
obj_list)) obj_list))
scenario._download_object = mock.MagicMock() scenario._download_object = mock.MagicMock()
scenario.list_and_download_objects_in_containers() scenario.run()
scenario._list_containers.assert_called_once_with() scenario._list_containers.assert_called_once_with()
con_calls = [mock.call(container["name"], atomic_action=False) con_calls = [mock.call(container["name"], atomic_action=False)
for container in con_list] for container in con_list]
@ -146,13 +143,12 @@ class SwiftObjectsTestCase(test.ScenarioTestCase):
def test_functional_create_container_and_object_then_list_objects(self): def test_functional_create_container_and_object_then_list_objects(self):
names_list = ["AA", "BB", "CC", "DD"] names_list = ["AA", "BB", "CC", "DD"]
scenario = objects.SwiftObjects(self.context) scenario = objects.CreateContainerAndObjectThenListObjects(
self.context)
scenario.generate_random_name = mock.MagicMock(side_effect=names_list) scenario.generate_random_name = mock.MagicMock(side_effect=names_list)
scenario._list_objects = mock.MagicMock() scenario._list_objects = mock.MagicMock()
scenario.create_container_and_object_then_list_objects( scenario.run(objects_per_container=3, object_size=100)
objects_per_container=3,
object_size=100)
scenario._list_objects.assert_called_once_with("AA") scenario._list_objects.assert_called_once_with("AA")
@ -162,14 +158,12 @@ class SwiftObjectsTestCase(test.ScenarioTestCase):
def test_functional_create_container_and_object_then_delete_all(self): def test_functional_create_container_and_object_then_delete_all(self):
names_list = ["111", "222", "333", "444", "555"] names_list = ["111", "222", "333", "444", "555"]
scenario = objects.SwiftObjects(self.context) scenario = objects.CreateContainerAndObjectThenDeleteAll(self.context)
scenario.generate_random_name = mock.MagicMock(side_effect=names_list) scenario.generate_random_name = mock.MagicMock(side_effect=names_list)
scenario._delete_object = mock.MagicMock() scenario._delete_object = mock.MagicMock()
scenario._delete_container = mock.MagicMock() scenario._delete_container = mock.MagicMock()
scenario.create_container_and_object_then_delete_all( scenario.run(objects_per_container=4, object_size=240)
objects_per_container=4,
object_size=240)
scenario._delete_object.assert_has_calls( scenario._delete_object.assert_has_calls(
[mock.call("111", name, [mock.call("111", name,
@ -184,13 +178,12 @@ class SwiftObjectsTestCase(test.ScenarioTestCase):
def test_functional_create_container_and_object_then_download_object(self): def test_functional_create_container_and_object_then_download_object(self):
names_list = ["aaa", "bbb", "ccc", "ddd", "eee", "fff"] names_list = ["aaa", "bbb", "ccc", "ddd", "eee", "fff"]
scenario = objects.SwiftObjects(self.context) scenario = objects.CreateContainerAndObjectThenDownloadObject(
self.context)
scenario.generate_random_name = mock.MagicMock(side_effect=names_list) scenario.generate_random_name = mock.MagicMock(side_effect=names_list)
scenario._download_object = mock.MagicMock() scenario._download_object = mock.MagicMock()
scenario.create_container_and_object_then_download_object( scenario.run(objects_per_container=5, object_size=750)
objects_per_container=5,
object_size=750)
scenario._download_object.assert_has_calls( scenario._download_object.assert_has_calls(
[mock.call("aaa", name, [mock.call("aaa", name,

View File

@ -36,8 +36,6 @@ class TempestScenarioTestCase(test.TestCase):
self.context = test.get_test_context() self.context = test.get_test_context()
self.context.update({"verifier": self.verifier, self.context.update({"verifier": self.verifier,
"tmp_results_dir": "/dev"}) "tmp_results_dir": "/dev"})
self.scenario = tempest.TempestScenario(self.context)
self.scenario._add_atomic_actions = mock.MagicMock()
def get_tests_launcher_cmd(self, tests): def get_tests_launcher_cmd(self, tests):
return ("%(venv)s testr run --subunit --parallel --concurrency 0 " return ("%(venv)s testr run --subunit --parallel --concurrency 0 "
@ -55,10 +53,13 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_single_test(self, mock_tempest_resources_context, def test_single_test(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.SingleTest(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_test = "tempest.api.fake.test" fake_test = "tempest.api.fake.test"
self.scenario.single_test(test_name=fake_test) scenario.run(test_name=fake_test)
expected_call = self.get_tests_launcher_cmd([fake_test]) expected_call = self.get_tests_launcher_cmd([fake_test])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -71,10 +72,13 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_single_test_negative(self, mock_tempest_resources_context, def test_single_test_negative(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.SingleTest(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_test = "tempest.api.network" fake_test = "tempest.api.network"
self.scenario.single_test(test_name=fake_test) scenario.run(test_name=fake_test)
expected_call = self.get_tests_launcher_cmd([fake_test]) expected_call = self.get_tests_launcher_cmd([fake_test])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -88,9 +92,12 @@ class TempestScenarioTestCase(test.TestCase):
def test_single_test_without_prefix(self, mock_tempest_resources_context, def test_single_test_without_prefix(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_subprocess, mock_tempfile,
mock_isfile): mock_isfile):
scenario = tempest.SingleTest(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.single_test("network") scenario.run("network")
expected_call = self.get_tests_launcher_cmd(["tempest.api.network"]) expected_call = self.get_tests_launcher_cmd(["tempest.api.network"])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -103,9 +110,12 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_all(self, mock_tempest_resources_context, def test_all(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.All(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.all() scenario.run()
expected_call = self.get_tests_launcher_cmd([]) expected_call = self.get_tests_launcher_cmd([])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -118,9 +128,12 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_smoke(self, mock_tempest_resources_context, def test_set_smoke(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.Set(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.set("smoke") scenario.run("smoke")
expected_call = self.get_tests_launcher_cmd(["smoke"]) expected_call = self.get_tests_launcher_cmd(["smoke"])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -133,9 +146,12 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_full(self, mock_tempest_resources_context, def test_set_full(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.Set(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.set("full") scenario.run("full")
expected_call = self.get_tests_launcher_cmd([]) expected_call = self.get_tests_launcher_cmd([])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -147,6 +163,9 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_from_list(self, mock_tempest_resources_context, def test_set_from_list(self, mock_tempest_resources_context,
mock_tempfile, mock_isfile): mock_tempfile, mock_isfile):
scenario = tempest.Set(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_scenarios = ["network", "volume", "baremetal", fake_scenarios = ["network", "volume", "baremetal",
@ -155,7 +174,7 @@ class TempestScenarioTestCase(test.TestCase):
"telemetry", "queuing", "orchestration"] "telemetry", "queuing", "orchestration"]
for fake_scenario in fake_scenarios: for fake_scenario in fake_scenarios:
with mock.patch(VERIFIER + ".subprocess") as mock_subprocess: with mock.patch(VERIFIER + ".subprocess") as mock_subprocess:
self.scenario.set(fake_scenario) scenario.run(fake_scenario)
fake_test = "tempest.api." + fake_scenario fake_test = "tempest.api." + fake_scenario
expected_call = self.get_tests_launcher_cmd([fake_test]) expected_call = self.get_tests_launcher_cmd([fake_test])
@ -169,9 +188,12 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_set_selective(self, mock_tempest_resources_context, def test_set_selective(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.Set(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
self.scenario.set("network") scenario.run("network")
expected_call = self.get_tests_launcher_cmd(["tempest.api.network"]) expected_call = self.get_tests_launcher_cmd(["tempest.api.network"])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -184,10 +206,13 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_list_of_tests(self, mock_tempest_resources_context, def test_list_of_tests(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.ListOfTests(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
fake_tests = ["tempest.fake.test1", "tempest.fake.test2"] fake_tests = ["tempest.fake.test1", "tempest.fake.test2"]
self.scenario.list_of_tests(fake_tests) scenario.run(fake_tests)
expected_call = self.get_tests_launcher_cmd(fake_tests) expected_call = self.get_tests_launcher_cmd(fake_tests)
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(
@ -200,10 +225,13 @@ class TempestScenarioTestCase(test.TestCase):
@mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext") @mock.patch(TEMPEST_DIR + ".config.TempestResourcesContext")
def test_specific_regex(self, mock_tempest_resources_context, def test_specific_regex(self, mock_tempest_resources_context,
mock_subprocess, mock_tempfile, mock_isfile): mock_subprocess, mock_tempfile, mock_isfile):
scenario = tempest.SpecificRegex(self.context)
scenario._add_atomic_actions = mock.MagicMock()
mock_tempfile.NamedTemporaryFile().name = "/dev/null" mock_tempfile.NamedTemporaryFile().name = "/dev/null"
regex = "tempest.fake.test1" regex = "tempest.fake.test1"
self.scenario.specific_regex(regex) scenario.run(regex)
expected_call = self.get_tests_launcher_cmd([regex]) expected_call = self.get_tests_launcher_cmd([regex])
mock_subprocess.check_call.assert_called_once_with( mock_subprocess.check_call.assert_called_once_with(

View File

@ -32,7 +32,7 @@ class TempestLogWrappersTestCase(test.TestCase):
context = test.get_test_context() context = test.get_test_context()
context.update({"tmp_results_dir": "/tmp/dir", "verifier": verifier}) context.update({"tmp_results_dir": "/tmp/dir", "verifier": verifier})
self.scenario = tempest.TempestScenario(context) self.scenario = tempest.SingleTest(context)
self.scenario._add_atomic_actions = mock.MagicMock() self.scenario._add_atomic_actions = mock.MagicMock()
@mock.patch(TS + ".utils.tempfile") @mock.patch(TS + ".utils.tempfile")
@ -65,7 +65,7 @@ class TempestLogWrappersTestCase(test.TestCase):
total={"time": "0.1"}, tests={}) total={"time": "0.1"}, tests={})
context = test.get_test_context() context = test.get_test_context()
context.update({"tmp_results_dir": "/tmp/dir", "verifier": verifier}) context.update({"tmp_results_dir": "/tmp/dir", "verifier": verifier})
scenario = tempest.TempestScenario(context) scenario = tempest.SingleTest(context)
target_func = mock.MagicMock() target_func = mock.MagicMock()
target_func.__name__ = "target_func" target_func.__name__ = "target_func"

View File

@ -21,6 +21,9 @@ from rally.plugins.openstack.scenarios.vm import vmtasks
from tests.unit import test from tests.unit import test
BASE = "rally.plugins.openstack.scenarios.vm.vmtasks"
@ddt.ddt @ddt.ddt
class VMTasksTestCase(test.ScenarioTestCase): class VMTasksTestCase(test.ScenarioTestCase):
@ -28,49 +31,50 @@ class VMTasksTestCase(test.ScenarioTestCase):
super(VMTasksTestCase, self).setUp() super(VMTasksTestCase, self).setUp()
self.context.update({"user": {"keypair": {"name": "keypair_name"}, self.context.update({"user": {"keypair": {"name": "keypair_name"},
"credential": mock.MagicMock()}}) "credential": mock.MagicMock()}})
self.scenario = vmtasks.VMTasks(context=self.context)
def create_env(self, scenario):
self.ip = {"id": "foo_id", "ip": "foo_ip", "is_floating": True} self.ip = {"id": "foo_id", "ip": "foo_ip", "is_floating": True}
self.scenario._boot_server_with_fip = mock.Mock( scenario._boot_server_with_fip = mock.Mock(
return_value=("foo_server", self.ip)) return_value=("foo_server", self.ip))
self.scenario._wait_for_ping = mock.Mock() scenario._wait_for_ping = mock.Mock()
self.scenario._delete_server_with_fip = mock.Mock() scenario._delete_server_with_fip = mock.Mock()
self.scenario._create_volume = mock.Mock( scenario._create_volume = mock.Mock(
return_value=mock.Mock(id="foo_volume")) return_value=mock.Mock(id="foo_volume"))
self.scenario._run_command = mock.MagicMock( scenario._run_command = mock.MagicMock(
return_value=(0, "{\"foo\": 42}", "foo_err")) return_value=(0, "{\"foo\": 42}", "foo_err"))
self.scenario.add_output = mock.Mock() scenario.add_output = mock.Mock()
return scenario
def test_boot_runcommand_delete(self): def test_boot_runcommand_delete(self):
self.scenario._run_command = mock.MagicMock( scenario = self.create_env(vmtasks.BootRuncommandDelete(self.context))
scenario._run_command = mock.MagicMock(
return_value=(0, "{\"foo\": 42}", "foo_err")) return_value=(0, "{\"foo\": 42}", "foo_err"))
self.scenario.boot_runcommand_delete( scenario.run("foo_image", "foo_flavor",
"foo_image", "foo_flavor", command={"script_file": "foo_script",
command={"script_file": "foo_script", "interpreter": "foo_interpreter"},
"interpreter": "foo_interpreter"}, username="foo_username",
username="foo_username", password="foo_password",
password="foo_password", use_floating_ip="use_fip",
use_floating_ip="use_fip", floating_network="ext_network",
floating_network="ext_network", force_delete="foo_force",
force_delete="foo_force", volume_args={"size": 16},
volume_args={"size": 16}, foo_arg="foo_value")
foo_arg="foo_value")
self.scenario._create_volume.assert_called_once_with( scenario._create_volume.assert_called_once_with(16, imageRef=None)
16, imageRef=None) scenario._boot_server_with_fip.assert_called_once_with(
self.scenario._boot_server_with_fip.assert_called_once_with(
"foo_image", "foo_flavor", key_name="keypair_name", "foo_image", "foo_flavor", key_name="keypair_name",
use_floating_ip="use_fip", floating_network="ext_network", use_floating_ip="use_fip", floating_network="ext_network",
block_device_mapping={"vdrally": "foo_volume:::1"}, block_device_mapping={"vdrally": "foo_volume:::1"},
foo_arg="foo_value") foo_arg="foo_value")
self.scenario._wait_for_ping.assert_called_once_with("foo_ip") scenario._wait_for_ping.assert_called_once_with("foo_ip")
self.scenario._run_command.assert_called_once_with( scenario._run_command.assert_called_once_with(
"foo_ip", 22, "foo_username", "foo_password", "foo_ip", 22, "foo_username", "foo_password",
command={"script_file": "foo_script", command={"script_file": "foo_script",
"interpreter": "foo_interpreter"}) "interpreter": "foo_interpreter"})
self.scenario._delete_server_with_fip.assert_called_once_with( scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete="foo_force") "foo_server", self.ip, force_delete="foo_force")
self.scenario.add_output.assert_called_once_with( scenario.add_output.assert_called_once_with(
additive={"title": "Command output", "chart_plugin": "Lines", additive={"title": "Command output", "chart_plugin": "Lines",
"data": [["foo", 42.0]]}) "data": [["foo", 42.0]]})
@ -93,7 +97,9 @@ class VMTasksTestCase(test.ScenarioTestCase):
@ddt.unpack @ddt.unpack
def test_boot_runcommand_delete_add_output(self, output, def test_boot_runcommand_delete_add_output(self, output,
expected=None, raises=None): expected=None, raises=None):
self.scenario._run_command.return_value = output scenario = self.create_env(vmtasks.BootRuncommandDelete(self.context))
scenario._run_command.return_value = output
kwargs = {"command": {"remote_path": "foo"}, kwargs = {"command": {"remote_path": "foo"},
"username": "foo_username", "username": "foo_username",
"password": "foo_password", "password": "foo_password",
@ -103,48 +109,50 @@ class VMTasksTestCase(test.ScenarioTestCase):
"volume_args": {"size": 16}, "volume_args": {"size": 16},
"foo_arg": "foo_value"} "foo_arg": "foo_value"}
if raises: if raises:
self.assertRaises(raises, self.scenario.boot_runcommand_delete, self.assertRaises(raises, scenario.run,
"foo_image", "foo_flavor", **kwargs) "foo_image", "foo_flavor", **kwargs)
self.assertFalse(self.scenario.add_output.called) self.assertFalse(scenario.add_output.called)
else: else:
self.scenario.boot_runcommand_delete("foo_image", "foo_flavor", scenario.run("foo_image", "foo_flavor", **kwargs)
**kwargs)
calls = [mock.call(**kw) for kw in expected] calls = [mock.call(**kw) for kw in expected]
self.scenario.add_output.assert_has_calls(calls, any_order=True) scenario.add_output.assert_has_calls(calls, any_order=True)
self.scenario._create_volume.assert_called_once_with( scenario._create_volume.assert_called_once_with(16, imageRef=None)
16, imageRef=None) scenario._boot_server_with_fip.assert_called_once_with(
self.scenario._boot_server_with_fip.assert_called_once_with(
"foo_image", "foo_flavor", key_name="keypair_name", "foo_image", "foo_flavor", key_name="keypair_name",
use_floating_ip="use_fip", floating_network="ext_network", use_floating_ip="use_fip", floating_network="ext_network",
block_device_mapping={"vdrally": "foo_volume:::1"}, block_device_mapping={"vdrally": "foo_volume:::1"},
foo_arg="foo_value") foo_arg="foo_value")
self.scenario._run_command.assert_called_once_with( scenario._run_command.assert_called_once_with(
"foo_ip", 22, "foo_username", "foo_password", "foo_ip", 22, "foo_username", "foo_password",
command={"remote_path": "foo"}) command={"remote_path": "foo"})
self.scenario._delete_server_with_fip.assert_called_once_with( scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete="foo_force") "foo_server", self.ip, force_delete="foo_force")
def test_boot_runcommand_delete_command_timeouts(self): def test_boot_runcommand_delete_command_timeouts(self):
self.scenario._run_command.side_effect = exceptions.SSHTimeout() scenario = self.create_env(vmtasks.BootRuncommandDelete(self.context))
scenario._run_command.side_effect = exceptions.SSHTimeout()
self.assertRaises(exceptions.SSHTimeout, self.assertRaises(exceptions.SSHTimeout,
self.scenario.boot_runcommand_delete, scenario.run,
"foo_image", "foo_flavor", "foo_interpreter", "foo_image", "foo_flavor", "foo_interpreter",
"foo_script", "foo_username") "foo_script", "foo_username")
self.scenario._delete_server_with_fip.assert_called_once_with( scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete=False) "foo_server", self.ip, force_delete=False)
self.assertFalse(self.scenario.add_output.called) self.assertFalse(scenario.add_output.called)
def test_boot_runcommand_delete_ping_wait_timeouts(self): def test_boot_runcommand_delete_ping_wait_timeouts(self):
self.scenario._wait_for_ping.side_effect = exceptions.TimeoutException( scenario = self.create_env(vmtasks.BootRuncommandDelete(self.context))
scenario._wait_for_ping.side_effect = exceptions.TimeoutException(
resource_type="foo_resource", resource_type="foo_resource",
resource_name="foo_name", resource_name="foo_name",
resource_id="foo_id", resource_id="foo_id",
desired_status="foo_desired_status", desired_status="foo_desired_status",
resource_status="foo_resource_status") resource_status="foo_resource_status")
exc = self.assertRaises(exceptions.TimeoutException, exc = self.assertRaises(exceptions.TimeoutException,
self.scenario.boot_runcommand_delete, scenario.run,
"foo_image", "foo_flavor", "foo_interpreter", "foo_image", "foo_flavor", "foo_interpreter",
"foo_script", "foo_username", "foo_script", "foo_username",
wait_for_ping=True) wait_for_ping=True)
@ -154,22 +162,25 @@ class VMTasksTestCase(test.ScenarioTestCase):
self.assertEqual(exc.kwargs["desired_status"], "foo_desired_status") self.assertEqual(exc.kwargs["desired_status"], "foo_desired_status")
self.assertEqual(exc.kwargs["resource_status"], "foo_resource_status") self.assertEqual(exc.kwargs["resource_status"], "foo_resource_status")
self.scenario._delete_server_with_fip.assert_called_once_with( scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete=False) "foo_server", self.ip, force_delete=False)
self.assertFalse(self.scenario.add_output.called) self.assertFalse(scenario.add_output.called)
@mock.patch("rally.plugins.openstack.scenarios.vm.vmtasks.json") @mock.patch("%s.json" % BASE)
def test_boot_runcommand_delete_json_fails(self, mock_json): def test_boot_runcommand_delete_json_fails(self, mock_json):
scenario = self.create_env(vmtasks.BootRuncommandDelete(self.context))
mock_json.loads.side_effect = ValueError() mock_json.loads.side_effect = ValueError()
self.assertRaises(exceptions.ScriptError, self.assertRaises(exceptions.ScriptError,
self.scenario.boot_runcommand_delete, scenario.run,
"foo_image", "foo_flavor", "foo_interpreter", "foo_image", "foo_flavor", "foo_interpreter",
"foo_script", "foo_username") "foo_script", "foo_username")
self.scenario._delete_server_with_fip.assert_called_once_with( scenario._delete_server_with_fip.assert_called_once_with(
"foo_server", self.ip, force_delete=False) "foo_server", self.ip, force_delete=False)
self.assertFalse(self.scenario.add_output.called) self.assertFalse(scenario.add_output.called)
def test_boot_runcommand_delete_custom_image(self): @mock.patch("%s.BootRuncommandDelete.run" % BASE)
def test_boot_runcommand_delete_custom_image(self, mock_scenario):
context = { context = {
"user": { "user": {
"tenant_id": "tenant_id", "tenant_id": "tenant_id",
@ -179,26 +190,23 @@ class VMTasksTestCase(test.ScenarioTestCase):
"custom_image": {"id": "image_id"} "custom_image": {"id": "image_id"}
} }
} }
scenario = vmtasks.VMTasks(context) scenario = vmtasks.BootRuncommandDeleteCustomImage(context)
scenario.boot_runcommand_delete = mock.Mock() scenario.run(flavor="flavor_id",
command={
"script_file": "foo_script",
"interpreter": "bar_interpreter"},
username="username")
scenario.boot_runcommand_delete_custom_image( mock_scenario.assert_called_once_with(
flavor="flavor_id",
command={
"script_file": "foo_script",
"interpreter": "bar_interpreter"},
username="username")
scenario.boot_runcommand_delete.assert_called_once_with(
image="image_id", flavor="flavor_id", username="username", image="image_id", flavor="flavor_id", username="username",
command={ command={
"script_file": "foo_script", "script_file": "foo_script",
"interpreter": "bar_interpreter"} "interpreter": "bar_interpreter"}
) )
@mock.patch("rally.plugins.openstack.scenarios.vm.vmtasks.heat") @mock.patch("%s.heat" % BASE)
@mock.patch("rally.plugins.openstack.scenarios.vm.vmtasks.sshutils") @mock.patch("%s.sshutils" % BASE)
def test_runcommand_heat(self, mock_sshutils, mock_heat): def test_runcommand_heat(self, mock_sshutils, mock_heat):
fake_ssh = mock.Mock() fake_ssh = mock.Mock()
fake_ssh.execute.return_value = [0, "key:val", ""] fake_ssh.execute.return_value = [0, "key:val", ""]
@ -212,14 +220,14 @@ class VMTasksTestCase(test.ScenarioTestCase):
"credential": "ok"}, "credential": "ok"},
"tenant": {"networks": [{"router_id": "1"}]} "tenant": {"networks": [{"router_id": "1"}]}
} }
scenario = vmtasks.VMTasks(context) scenario = vmtasks.RuncommandHeat(context)
scenario.generate_random_name = mock.Mock(return_value="name") scenario.generate_random_name = mock.Mock(return_value="name")
scenario.add_output = mock.Mock() scenario.add_output = mock.Mock()
workload = {"username": "admin", workload = {"username": "admin",
"resource": ["foo", "bar"]} "resource": ["foo", "bar"]}
scenario.runcommand_heat(workload, "template", scenario.run(workload, "template",
{"file_key": "file_value"}, {"file_key": "file_value"},
{"param_key": "param_value"}) {"param_key": "param_value"})
expected = {"chart_plugin": "Table", expected = {"chart_plugin": "Table",
"data": {"rows": [["key", "val"]], "data": {"rows": [["key", "val"]],
"cols": ["key", "value"]}, "cols": ["key", "value"]},

View File

@ -22,12 +22,12 @@ from tests.unit import test
class WatcherTestCase(test.ScenarioTestCase): class WatcherTestCase(test.ScenarioTestCase):
def test_create_audit_template_and_delete(self): def test_create_audit_template_and_delete(self):
scenario = basic.Watcher(self.context) scenario = basic.CreateAuditTemplateAndDelete(self.context)
audit_template = mock.Mock() audit_template = mock.Mock()
scenario._create_audit_template = mock.MagicMock( scenario._create_audit_template = mock.MagicMock(
return_value=audit_template) return_value=audit_template)
scenario._delete_audit_template = mock.MagicMock() scenario._delete_audit_template = mock.MagicMock()
scenario.create_audit_template_and_delete("goal", "strategy", {}) scenario.run("goal", "strategy", {})
scenario._create_audit_template.assert_called_once_with("goal", scenario._create_audit_template.assert_called_once_with("goal",
"strategy", "strategy",
{}) {})
@ -35,20 +35,20 @@ class WatcherTestCase(test.ScenarioTestCase):
audit_template.uuid) audit_template.uuid)
def test_list_audit_template(self): def test_list_audit_template(self):
scenario = basic.Watcher(self.context) scenario = basic.ListAuditTemplates(self.context)
scenario._list_audit_templates = mock.MagicMock() scenario._list_audit_templates = mock.MagicMock()
scenario.list_audit_templates() scenario.run()
scenario._list_audit_templates.assert_called_once_with( scenario._list_audit_templates.assert_called_once_with(
detail=False, goal=None, limit=None, name=None, sort_dir=None, detail=False, goal=None, limit=None, name=None, sort_dir=None,
sort_key=None, strategy=None) sort_key=None, strategy=None)
def test_create_audit_and_delete(self): def test_create_audit_and_delete(self):
mock_audit = mock.MagicMock() mock_audit = mock.MagicMock()
scenario = basic.Watcher(self.context) scenario = basic.CreateAuditAndDelete(self.context)
scenario.context = mock.MagicMock() scenario.context = mock.MagicMock()
scenario._create_audit = mock.MagicMock(return_value=mock_audit) scenario._create_audit = mock.MagicMock(return_value=mock_audit)
scenario.sleep_between = mock.MagicMock() scenario.sleep_between = mock.MagicMock()
scenario._delete_audit = mock.MagicMock() scenario._delete_audit = mock.MagicMock()
scenario.create_audit_and_delete() scenario.run()
scenario._create_audit.assert_called_once_with(mock.ANY) scenario._create_audit.assert_called_once_with(mock.ANY)
scenario._delete_audit.assert_called_once_with(mock_audit) scenario._delete_audit.assert_called_once_with(mock_audit)

View File

@ -17,22 +17,23 @@ import mock
from rally.plugins.openstack.scenarios.zaqar import basic from rally.plugins.openstack.scenarios.zaqar import basic
from tests.unit import test from tests.unit import test
BASE = "rally.plugins.openstack.scenarios.zaqar." BASE = "rally.plugins.openstack.scenarios.zaqar.basic"
BASIC = BASE + "basic.ZaqarBasic."
class ZaqarBasicTestCase(test.ScenarioTestCase): class ZaqarBasicTestCase(test.ScenarioTestCase):
@mock.patch(BASIC + "generate_random_name", return_value="fizbit") @mock.patch("%s.CreateQueue.generate_random_name" % BASE,
def test_create_queue(self, mock_generate_random_name): return_value="fizbit")
scenario = basic.ZaqarBasic(self.context) def test_create_queue(self, mock_random_name):
scenario = basic.CreateQueue(self.context)
scenario._queue_create = mock.MagicMock() scenario._queue_create = mock.MagicMock()
scenario.create_queue(fakearg="fake") scenario.run(fakearg="fake")
scenario._queue_create.assert_called_once_with(fakearg="fake") scenario._queue_create.assert_called_once_with(fakearg="fake")
@mock.patch(BASIC + "generate_random_name", return_value="kitkat") @mock.patch("%s.CreateQueue.generate_random_name" % BASE,
def test_producer_consumer(self, mock_generate_random_name): return_value="kitkat")
scenario = basic.ZaqarBasic(self.context) def test_producer_consumer(self, mock_random_name):
scenario = basic.ProducerConsumer(self.context)
messages = [{"body": {"id": idx}, "ttl": 360} for idx messages = [{"body": {"id": idx}, "ttl": 360} for idx
in range(20)] in range(20)]
queue = mock.MagicMock() queue = mock.MagicMock()
@ -42,8 +43,7 @@ class ZaqarBasicTestCase(test.ScenarioTestCase):
scenario._messages_list = mock.MagicMock() scenario._messages_list = mock.MagicMock()
scenario._queue_delete = mock.MagicMock() scenario._queue_delete = mock.MagicMock()
scenario.producer_consumer(min_msg_count=20, max_msg_count=20, scenario.run(min_msg_count=20, max_msg_count=20, fakearg="fake")
fakearg="fake")
scenario._queue_create.assert_called_once_with(fakearg="fake") scenario._queue_create.assert_called_once_with(fakearg="fake")
scenario._messages_post.assert_called_once_with(queue, messages, scenario._messages_post.assert_called_once_with(queue, messages,

View File

@ -43,9 +43,20 @@ class DocstringsTestCase(test.TestCase):
def test_all_scenarios_have_docstrings(self): def test_all_scenarios_have_docstrings(self):
ignored_params = ["self", "scenario_obj"] ignored_params = ["self", "scenario_obj"]
for scenario_inst in scenario.Scenario.get_all(): for scenario_inst in scenario.Scenario.get_all():
self.assertIsNotNone(scenario_inst.__doc__, try:
"%s doensn't have a docstring." % self.assertIsNotNone(scenario_inst.__doc__,
scenario_inst.get_name()) "%s doensn't have a docstring." %
scenario_inst.get_name())
except Exception:
msg = ("'{}.run' doesn't have a docstring. "
"At least class '{}' or method '{}.run' "
"should contain a docstring")
inst_name = scenario_inst.__name__
if scenario_inst.is_classbased:
self.assertIsNotNone(scenario_inst.run.__doc__,
msg.format(inst_name,
inst_name,
inst_name))
doc = info.parse_docstring(scenario_inst.__doc__) doc = info.parse_docstring(scenario_inst.__doc__)
short_description = doc["short_description"] short_description = doc["short_description"]
self.assertIsNotNone(short_description, self.assertIsNotNone(short_description,