Merge "[docs] Resolve "nested numbering in toctree?" warning"
[yardstick.git] / yardstick / benchmark / scenarios / base.py
1 # Copyright 2013: Mirantis Inc.
2 # All Rights Reserved.
3 #
4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
5 #    not use this file except in compliance with the License. You may obtain
6 #    a copy of the License at
7 #
8 #         http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #    Unless required by applicable law or agreed to in writing, software
11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 #    License for the specific language governing permissions and limitations
14 #    under the License.
15
16 import abc
17 import time
18
19 import six
20 from stevedore import extension
21
22 import yardstick.common.utils as utils
23 from yardstick.common import exceptions as y_exc
24
25
26 def _iter_scenario_classes(scenario_type=None):
27     """Generator over all 'Scenario' subclasses
28
29     This function will iterate over all 'Scenario' subclasses defined in this
30     project and will load any class introduced by any installed plugin project,
31     defined in 'entry_points' section, under 'yardstick.scenarios' subsection.
32     """
33     extension.ExtensionManager(namespace='yardstick.scenarios',
34                                invoke_on_load=False)
35     for scenario in utils.itersubclasses(Scenario):
36         if not scenario_type:
37             yield scenario
38         elif getattr(scenario, '__scenario_type__', None) == scenario_type:
39             yield scenario
40
41
42 @six.add_metaclass(abc.ABCMeta)
43 class Scenario(object):
44
45     def setup(self):
46         """Default setup implementation for Scenario classes"""
47         pass
48
49     @abc.abstractmethod
50     def run(self, *args):
51         """Entry point for scenario classes, called from runner worker"""
52
53     def is_ended(self):
54         return False
55
56     def teardown(self):
57         """Default teardown implementation for Scenario classes"""
58         pass
59
60     def pre_run_wait_time(self, time_seconds):
61         """Time waited before executing the run method"""
62         pass
63
64     def post_run_wait_time(self, time_seconds):
65         """Time waited after executing the run method"""
66         time.sleep(time_seconds)
67
68     def verify_SLA(self, condition, error_msg):
69         if not condition:
70             raise y_exc.SLAValidationError(
71                 case_name=self.__scenario_type__, error_msg=error_msg)
72
73     @staticmethod
74     def get_types():
75         """return a list of known runner type (class) names"""
76         scenarios = []
77         for scenario in _iter_scenario_classes():
78             scenarios.append(scenario)
79         return scenarios
80
81     @staticmethod
82     def get_cls(scenario_type):
83         """return class of specified type"""
84         for scenario in _iter_scenario_classes(scenario_type):
85             return scenario
86
87         raise RuntimeError("No such scenario type %s" % scenario_type)
88
89     @staticmethod
90     def get(scenario_type):
91         """Returns instance of a scenario runner for execution type.
92         """
93         scenario = Scenario.get_cls(scenario_type)
94         return scenario.__module__ + "." + scenario.__name__
95
96     @classmethod
97     def get_scenario_type(cls):
98         """Return a string with the scenario type, if defined"""
99         return str(getattr(cls, '__scenario_type__', None))
100
101     @classmethod
102     def get_description(cls):
103         """Return a single line string with the class description
104
105         This function will retrieve the class docstring and return the first
106         line, or 'None' if it's empty.
107         """
108         return cls.__doc__.splitlines()[0] if cls.__doc__ else str(None)
109
110     @staticmethod
111     def _push_to_outputs(keys, values):
112         """Return a dictionary given the keys and the values"""
113         return dict(zip(keys, values))
114
115     @staticmethod
116     def _change_obj_to_dict(obj):
117         """Return a dictionary from the __dict__ attribute of an object"""
118         dic = {}
119         for k, v in vars(obj).items():
120             try:
121                 vars(v)
122             except TypeError:
123                 dic[k] = v
124         return dic
125
126     def get_mq_ids(self):  # pragma: no cover
127         """Return stored MQ producer IDs, if defined"""
128         pass