koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 1 | import abc |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 2 | import time |
| 3 | import logging |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 4 | import os.path |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 5 | import datetime |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 6 | from typing import Dict, Any, List, Optional, Callable, cast |
koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 7 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 8 | from concurrent.futures import ThreadPoolExecutor, wait |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 9 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 10 | from ..utils import Barrier, StopTestError, sec_to_str |
| 11 | from ..node_interfaces import IRPCNode |
koder aka kdanilov | 3d2bc4f | 2016-11-12 18:31:18 +0200 | [diff] [blame] | 12 | from ..storage import Storage |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 13 | from ..result_classes import NodeTestResults, IStorable |
| 14 | from queue import Queue |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 15 | |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 16 | |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 17 | logger = logging.getLogger("wally") |
koder aka kdanilov | 88407ff | 2015-05-26 15:35:57 +0300 | [diff] [blame] | 18 | |
| 19 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 20 | __doc__ = "Contains base classes for performance tests" |
| 21 | |
| 22 | |
| 23 | class TestInputConfig: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 24 | """ |
| 25 | this class describe test input configuration |
koder aka kdanilov | 88407ff | 2015-05-26 15:35:57 +0300 | [diff] [blame] | 26 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 27 | test_type - test type name |
| 28 | params - parameters from yaml file for this test |
| 29 | test_uuid - UUID to be used to create file names & Co |
| 30 | log_directory - local directory to store results |
| 31 | nodes - nodes to run tests on |
| 32 | remote_dir - directory on nodes to be used for local files |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 33 | """ |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 34 | def __init__(self, |
| 35 | test_type: str, |
| 36 | params: Dict[str, Any], |
koder aka kdanilov | 3d2bc4f | 2016-11-12 18:31:18 +0200 | [diff] [blame] | 37 | run_uuid: str, |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 38 | nodes: List[IRPCNode], |
koder aka kdanilov | 3d2bc4f | 2016-11-12 18:31:18 +0200 | [diff] [blame] | 39 | storage: Storage, |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 40 | remote_dir: str) -> None: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 41 | self.test_type = test_type |
| 42 | self.params = params |
koder aka kdanilov | 3d2bc4f | 2016-11-12 18:31:18 +0200 | [diff] [blame] | 43 | self.run_uuid = run_uuid |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 44 | self.nodes = nodes |
koder aka kdanilov | 3d2bc4f | 2016-11-12 18:31:18 +0200 | [diff] [blame] | 45 | self.storage = storage |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 46 | self.remote_dir = remote_dir |
koder aka kdanilov | 88407ff | 2015-05-26 15:35:57 +0300 | [diff] [blame] | 47 | |
| 48 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 49 | class IterationConfig(IStorable): |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 50 | name = None # type: str |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 51 | summary = None # type: str |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 52 | |
| 53 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 54 | class PerfTest(metaclass=abc.ABCMeta): |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 55 | """Base class for all tests""" |
| 56 | name = None # type: str |
| 57 | max_retry = 3 |
| 58 | retry_time = 30 |
| 59 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 60 | def __init__(self, config: TestInputConfig, on_idle: Callable[[], None] = None) -> None: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 61 | self.config = config |
koder aka kdanilov | e2de58c | 2015-04-24 22:59:36 +0300 | [diff] [blame] | 62 | self.stop_requested = False |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 63 | self.nodes = self.config.nodes # type: List[IRPCNode] |
| 64 | self.sorted_nodes_ids = sorted(node.info.node_id() for node in self.nodes) |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 65 | self.on_idle = on_idle |
koder aka kdanilov | e2de58c | 2015-04-24 22:59:36 +0300 | [diff] [blame] | 66 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 67 | def request_stop(self) -> None: |
koder aka kdanilov | e2de58c | 2015-04-24 22:59:36 +0300 | [diff] [blame] | 68 | self.stop_requested = True |
koder aka kdanilov | 2066daf | 2015-04-23 21:05:41 +0300 | [diff] [blame] | 69 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 70 | def join_remote(self, path: str) -> str: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 71 | return os.path.join(self.config.remote_dir, path) |
koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 72 | |
koder aka kdanilov | 4af1c1d | 2015-05-18 15:48:58 +0300 | [diff] [blame] | 73 | @abc.abstractmethod |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 74 | def run(self) -> None: |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 75 | pass |
| 76 | |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 77 | @abc.abstractmethod |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 78 | def format_for_console(self, data: Any) -> str: |
koder aka kdanilov | ec1b973 | 2015-04-23 20:43:29 +0300 | [diff] [blame] | 79 | pass |
| 80 | |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 81 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 82 | class ThreadedTest(PerfTest, metaclass=abc.ABCMeta): |
| 83 | """Base class for tests, which spawn separated thread for each node""" |
| 84 | |
| 85 | # max allowed time difference between starts and stops of run of the same test on different test nodes |
| 86 | # used_max_diff = max((min_run_time * max_rel_time_diff), max_time_diff) |
| 87 | max_time_diff = 5 |
| 88 | max_rel_time_diff = 0.05 |
koder aka kdanilov | ffaf48d | 2016-12-27 02:25:29 +0200 | [diff] [blame^] | 89 | load_profile_name = None # type: str |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 90 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 91 | def __init__(self, *args, **kwargs) -> None: |
| 92 | PerfTest.__init__(self, *args, **kwargs) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 93 | self.iterations_configs = [None] # type: List[Optional[IterationConfig]] |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 94 | self.storage_q = Queue() # type: Any |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 95 | |
| 96 | @abc.abstractmethod |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 97 | def get_expected_runtime(self, iter_cfg: IterationConfig) -> Optional[int]: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 98 | pass |
| 99 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 100 | def get_not_done_stages(self, storage: Storage) -> Dict[int, IterationConfig]: |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 101 | not_done = {} # type: Dict[int, IterationConfig] |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 102 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 103 | for run_id, iteration_config in enumerate(self.iterations_configs): |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 104 | info_path = "result/{}/info".format(run_id) |
| 105 | if info_path in storage: |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 106 | info = cast(Dict[str, Any], storage.get(info_path)) # type: Dict[str, Any] |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 107 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 108 | assert isinstance(info, dict), \ |
| 109 | "Broken storage at path {}. Expect test info dict, obtain {!r}".format(info_path, info) |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 110 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 111 | info = info.copy() |
| 112 | del info['begin_time'] |
| 113 | del info['end_time'] |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 114 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 115 | iter_name = "Unnamed" if iteration_config is None else iteration_config.name |
| 116 | expected_config = { |
| 117 | 'name': self.name, |
| 118 | 'iteration_name': iter_name, |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 119 | 'iteration_config': iteration_config.raw(), |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 120 | 'params': self.config.params, |
| 121 | 'nodes': self.sorted_nodes_ids |
| 122 | } |
| 123 | |
| 124 | assert info == expected_config, \ |
koder aka kdanilov | 39e449e | 2016-12-17 15:15:26 +0200 | [diff] [blame] | 125 | ("Test info at path {} is not equal to expected config." + |
| 126 | "Maybe configuration was changed before test was restarted. " + |
| 127 | "Current cfg is {!r}, expected cfg is {!r}").format(info_path, info, expected_config) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 128 | |
| 129 | logger.info("Test iteration {} found in storage and will be skipped".format(iter_name)) |
| 130 | else: |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 131 | not_done[run_id] = iteration_config |
| 132 | |
| 133 | return not_done |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 134 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 135 | def run(self) -> None: |
| 136 | not_in_storage = self.get_not_done_stages(self.config.storage) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 137 | |
| 138 | if not not_in_storage: |
| 139 | logger.info("All test iteration in storage already. Skip test") |
| 140 | return |
| 141 | |
koder aka kdanilov | ffaf48d | 2016-12-27 02:25:29 +0200 | [diff] [blame^] | 142 | logger.debug("Run test io.{} with profile {!r} on nodes {}.".format(self.name, |
| 143 | self.load_profile_name, |
| 144 | ",".join(self.sorted_nodes_ids))) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 145 | logger.debug("Prepare nodes") |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 146 | |
| 147 | with ThreadPoolExecutor(len(self.nodes)) as pool: |
| 148 | list(pool.map(self.config_node, self.nodes)) |
| 149 | |
| 150 | # +5% - is a rough estimation for additional operations |
| 151 | run_times = [self.get_expected_runtime(iteration_config) for iteration_config in not_in_storage.values()] |
| 152 | if None not in run_times: |
| 153 | expected_run_time = int(sum(run_times) * 1.05) |
| 154 | exec_time_s = sec_to_str(expected_run_time) |
| 155 | now_dt = datetime.datetime.now() |
| 156 | end_dt = now_dt + datetime.timedelta(0, expected_run_time) |
| 157 | logger.info("Entire test should takes aroud: {} and finished at {:%H:%M:%S}" |
| 158 | .format(exec_time_s, end_dt)) |
| 159 | |
| 160 | for run_id, iteration_config in sorted(not_in_storage.items()): |
| 161 | iter_name = "Unnamed" if iteration_config is None else iteration_config.name |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 162 | logger.info("Run test iteration %s", iter_name) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 163 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 164 | current_result_path = "result/{}_{}".format(iteration_config.summary, run_id) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 165 | results = [] # type: List[NodeTestResults] |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 166 | for idx in range(self.max_retry): |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 167 | logger.debug("Prepare iteration %s", iter_name) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 168 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 169 | # prepare nodes for new iterations |
| 170 | futures = [pool.submit(self.prepare_iteration, node, iteration_config) for node in self.nodes] |
| 171 | wait(futures) |
| 172 | |
| 173 | # run iteration |
| 174 | logger.debug("Run iteration %s", iter_name) |
| 175 | try: |
| 176 | futures = [] |
| 177 | for node in self.nodes: |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 178 | path = "{}/measurement/{}".format(current_result_path, node.info.node_id()) |
| 179 | futures.append(pool.submit(self.run_iteration, node, iteration_config, path)) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 180 | |
| 181 | results = [fut.result() for fut in futures] |
| 182 | break |
| 183 | except EnvironmentError: |
| 184 | if self.max_retry - 1 == idx: |
| 185 | logger.exception("Fio failed") |
| 186 | raise StopTestError() |
| 187 | logger.exception("During fio run") |
| 188 | logger.info("Sleeping %ss and retrying", self.retry_time) |
| 189 | time.sleep(self.retry_time) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 190 | |
| 191 | start_times = [] # type: List[int] |
| 192 | stop_times = [] # type: List[int] |
| 193 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 194 | # TODO: FIX result processing - NodeTestResults |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 195 | for result in results: |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 196 | for name, serie in result.series.items(): |
| 197 | start_times.append(serie.start_at) |
| 198 | stop_times.append(serie.step * len(serie.data)) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 199 | |
| 200 | min_start_time = min(start_times) |
| 201 | max_start_time = max(start_times) |
| 202 | min_stop_time = min(stop_times) |
| 203 | max_stop_time = max(stop_times) |
| 204 | |
| 205 | max_allowed_time_diff = int((min_stop_time - max_start_time) * self.max_rel_time_diff) |
| 206 | max_allowed_time_diff = max(max_allowed_time_diff, self.max_time_diff) |
| 207 | |
| 208 | if min_start_time + self.max_time_diff < max_allowed_time_diff: |
| 209 | logger.warning("Too large difference in {}:{} start time - {}. Max recommended difference is {}" |
| 210 | .format(self.name, iter_name, max_start_time - min_start_time, self.max_time_diff)) |
| 211 | |
| 212 | if min_stop_time + self.max_time_diff < max_allowed_time_diff: |
| 213 | logger.warning("Too large difference in {}:{} stop time - {}. Max recommended difference is {}" |
| 214 | .format(self.name, iter_name, max_start_time - min_start_time, self.max_time_diff)) |
| 215 | |
| 216 | test_config = { |
koder aka kdanilov | ffaf48d | 2016-12-27 02:25:29 +0200 | [diff] [blame^] | 217 | 'suite': 'io', |
| 218 | 'test': self.name, |
| 219 | 'profile': self.load_profile_name, |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 220 | 'iteration_name': iter_name, |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 221 | 'iteration_config': iteration_config.raw(), |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 222 | 'params': self.config.params, |
| 223 | 'nodes': self.sorted_nodes_ids, |
| 224 | 'begin_time': min_start_time, |
| 225 | 'end_time': max_stop_time |
| 226 | } |
| 227 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 228 | self.process_storage_queue() |
koder aka kdanilov | ffaf48d | 2016-12-27 02:25:29 +0200 | [diff] [blame^] | 229 | self.config.storage.put(test_config, current_result_path, "info") |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 230 | self.config.storage.sync() |
| 231 | |
| 232 | if self.on_idle is not None: |
| 233 | self.on_idle() |
| 234 | |
| 235 | def store_data(self, val: Any, type: str, prefix: str, *path: str) -> None: |
| 236 | self.storage_q.put((val, type, prefix, path)) |
| 237 | |
| 238 | def process_storage_queue(self) -> None: |
| 239 | while not self.storage_q.empty(): |
| 240 | value, val_type, subpath, val_path = self.storage_q.get() |
| 241 | if val_type == 'raw': |
| 242 | self.config.storage.put_raw(value, subpath, *val_path) |
| 243 | elif val_type == 'yaml': |
| 244 | self.config.storage.put(value, subpath, *val_path) |
| 245 | elif val_type == 'array': |
| 246 | self.config.storage.put_array(value, subpath, *val_path) |
| 247 | else: |
| 248 | logger.error("Internal logic error - unknown data stop type {!r}".format(val_path)) |
| 249 | raise StopTestError() |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 250 | |
| 251 | @abc.abstractmethod |
| 252 | def config_node(self, node: IRPCNode) -> None: |
| 253 | pass |
| 254 | |
| 255 | @abc.abstractmethod |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 256 | def prepare_iteration(self, node: IRPCNode, iter_config: IterationConfig) -> None: |
| 257 | pass |
| 258 | |
| 259 | @abc.abstractmethod |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 260 | def run_iteration(self, node: IRPCNode, iter_config: IterationConfig, stor_prefix: str) -> NodeTestResults: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 261 | pass |
| 262 | |
| 263 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 264 | class TwoScriptTest(ThreadedTest, metaclass=abc.ABCMeta): |
| 265 | def __init__(self, *dt, **mp) -> None: |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 266 | ThreadedTest.__init__(self, *dt, **mp) |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 267 | self.prerun_script = self.config.params['prerun_script'] |
| 268 | self.run_script = self.config.params['run_script'] |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 269 | self.prerun_tout = self.config.params.get('prerun_tout', 3600) |
| 270 | self.run_tout = self.config.params.get('run_tout', 3600) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 271 | self.iterations_configs = [None] |
Yulia Portnova | 7ddfa73 | 2015-02-24 17:32:58 +0200 | [diff] [blame] | 272 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 273 | def get_expected_runtime(self, iter_cfg: IterationConfig) -> Optional[int]: |
| 274 | return None |
Yulia Portnova | 7ddfa73 | 2015-02-24 17:32:58 +0200 | [diff] [blame] | 275 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 276 | def config_node(self, node: IRPCNode) -> None: |
| 277 | node.copy_file(self.run_script, self.join_remote(self.run_script)) |
| 278 | node.copy_file(self.prerun_script, self.join_remote(self.prerun_script)) |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 279 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 280 | cmd = self.join_remote(self.prerun_script) |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 281 | cmd += ' ' + self.config.params.get('prerun_opts', '') |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 282 | node.run(cmd, timeout=self.prerun_tout) |
Yulia Portnova | 7ddfa73 | 2015-02-24 17:32:58 +0200 | [diff] [blame] | 283 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 284 | def prepare_iteration(self, node: IRPCNode, iter_config: IterationConfig) -> None: |
| 285 | pass |
| 286 | |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 287 | def run_iteration(self, node: IRPCNode, iter_config: IterationConfig, stor_prefix: str) -> NodeTestResults: |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 288 | # TODO: have to store logs |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 289 | cmd = self.join_remote(self.run_script) |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 290 | cmd += ' ' + self.config.params.get('run_opts', '') |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 291 | return self.parse_results(node.run(cmd, timeout=self.run_tout)) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 292 | |
| 293 | @abc.abstractmethod |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 294 | def parse_results(self, data: str) -> NodeTestResults: |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 295 | pass |
| 296 | |