blob: 44aabbdee8b077846c551bd3d13737bca7ac1957 [file] [log] [blame]
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +02001# osmo_gsm_tester: test suite
2#
3# Copyright (C) 2016-2017 by sysmocom - s.f.m.c. GmbH
4#
5# Author: Neels Hofmeyr <neels@hofmeyr.de>
6#
7# This program is free software: you can redistribute it and/or modify
Harald Welte27205342017-06-03 09:51:45 +02008# it under the terms of the GNU General Public License as
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +02009# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte27205342017-06-03 09:51:45 +020015# GNU General Public License for more details.
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +020016#
Harald Welte27205342017-06-03 09:51:45 +020017# You should have received a copy of the GNU General Public License
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +020018# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20import os
Neels Hofmeyr3531a192017-03-28 14:30:28 +020021import sys
22import time
Neels Hofmeyr2d1d5612017-05-22 20:02:41 +020023import pprint
Pau Espin Pedrol9a4631c2018-03-28 19:17:34 +020024from . import config, log, template, util, resource, schema, test
25from .event_loop import MainLoop
Pau Espin Pedrol4796b352017-11-23 11:07:42 +010026from . import osmo_nitb, osmo_hlr, osmo_mgcpgw, osmo_mgw, osmo_msc, osmo_bsc, osmo_stp, osmo_ggsn, osmo_sgsn, modem, esme
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +020027
Neels Hofmeyr1ffc3fe2017-05-07 02:15:21 +020028class Timeout(Exception):
29 pass
30
Neels Hofmeyr3531a192017-03-28 14:30:28 +020031class SuiteDefinition(log.Origin):
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +020032 '''A test suite reserves resources for a number of tests.
33 Each test requires a specific number of modems, BTSs etc., which are
34 reserved beforehand by a test suite. This way several test suites can be
35 scheduled dynamically without resource conflicts arising halfway through
36 the tests.'''
37
38 CONF_FILENAME = 'suite.conf'
39
Neels Hofmeyr3531a192017-03-28 14:30:28 +020040 def __init__(self, suite_dir):
Neels Hofmeyr3531a192017-03-28 14:30:28 +020041 self.suite_dir = suite_dir
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +020042 super().__init__(log.C_CNF, os.path.basename(self.suite_dir))
Neels Hofmeyr3531a192017-03-28 14:30:28 +020043 self.read_conf()
44
45 def read_conf(self):
Neels Hofmeyr6ccda112017-06-06 19:41:17 +020046 self.dbg('reading %s' % SuiteDefinition.CONF_FILENAME)
47 if not os.path.isdir(self.suite_dir):
48 raise RuntimeError('No such directory: %r' % self.suite_dir)
49 self.conf = config.read(os.path.join(self.suite_dir,
50 SuiteDefinition.CONF_FILENAME),
Pau Espin Pedrol0b302792017-09-10 16:33:10 +020051 resource.CONF_SCHEMA)
Neels Hofmeyr6ccda112017-06-06 19:41:17 +020052 self.load_test_basenames()
Neels Hofmeyr3531a192017-03-28 14:30:28 +020053
Neels Hofmeyr6ccda112017-06-06 19:41:17 +020054 def load_test_basenames(self):
55 self.test_basenames = []
56 for basename in sorted(os.listdir(self.suite_dir)):
57 if not basename.endswith('.py'):
58 continue
59 self.test_basenames.append(basename)
Neels Hofmeyr3531a192017-03-28 14:30:28 +020060
Neels Hofmeyr3531a192017-03-28 14:30:28 +020061class SuiteRun(log.Origin):
Pau Espin Pedrol0ffb4142017-05-15 18:24:35 +020062 UNKNOWN = 'UNKNOWN'
63 PASS = 'PASS'
64 FAIL = 'FAIL'
Neels Hofmeyr3531a192017-03-28 14:30:28 +020065
66 trial = None
Neels Hofmeyr6ccda112017-06-06 19:41:17 +020067 status = None
Neels Hofmeyrf8e61862017-06-06 23:08:07 +020068 start_timestamp = None
69 duration = None
Neels Hofmeyr3531a192017-03-28 14:30:28 +020070 resources_pool = None
71 reserved_resources = None
Neels Hofmeyr4d688c22017-05-29 04:13:58 +020072 objects_to_clean_up = None
Neels Hofmeyr3531a192017-03-28 14:30:28 +020073 _resource_requirements = None
74 _config = None
75 _processes = None
Pau Espin Pedrold0912332017-06-14 13:27:08 +020076 _run_dir = None
Neels Hofmeyr3531a192017-03-28 14:30:28 +020077
Neels Hofmeyr6ccda112017-06-06 19:41:17 +020078 def __init__(self, trial, suite_scenario_str, suite_definition, scenarios=[]):
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +020079 super().__init__(log.C_TST, suite_scenario_str)
Neels Hofmeyr6ccda112017-06-06 19:41:17 +020080 self.trial = trial
Neels Hofmeyr3531a192017-03-28 14:30:28 +020081 self.definition = suite_definition
82 self.scenarios = scenarios
Neels Hofmeyr3531a192017-03-28 14:30:28 +020083 self.resources_pool = resource.ResourcesPool()
Neels Hofmeyr6ccda112017-06-06 19:41:17 +020084 self.status = SuiteRun.UNKNOWN
85 self.load_tests()
86
87 def load_tests(self):
88 self.tests = []
89 for test_basename in self.definition.test_basenames:
Pau Espin Pedrolfd5de3d2017-11-09 14:26:35 +010090 self.tests.append(test.Test(self, test_basename))
Neels Hofmeyr3531a192017-03-28 14:30:28 +020091
Neels Hofmeyr4d688c22017-05-29 04:13:58 +020092 def register_for_cleanup(self, *obj):
93 assert all([hasattr(o, 'cleanup') for o in obj])
94 self.objects_to_clean_up = self.objects_to_clean_up or []
95 self.objects_to_clean_up.extend(obj)
96
97 def objects_cleanup(self):
98 while self.objects_to_clean_up:
99 obj = self.objects_to_clean_up.pop()
Pau Espin Pedrol6100b622017-07-31 18:19:06 +0200100 try:
101 obj.cleanup()
102 except Exception:
103 log.log_exn()
Neels Hofmeyr4d688c22017-05-29 04:13:58 +0200104
Pau Espin Pedrol0ffb4142017-05-15 18:24:35 +0200105 def mark_start(self):
Pau Espin Pedrol0ffb4142017-05-15 18:24:35 +0200106 self.start_timestamp = time.time()
107 self.duration = 0
Pau Espin Pedrol0ffb4142017-05-15 18:24:35 +0200108 self.status = SuiteRun.UNKNOWN
109
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200110 def combined(self, conf_name):
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200111 log.dbg(combining=conf_name)
112 log.ctx(combining_scenarios=conf_name)
Pau Espin Pedrol0b302792017-09-10 16:33:10 +0200113 combination = config.replicate_times(self.definition.conf.get(conf_name, {}))
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200114 log.dbg(definition_conf=combination)
115 for scenario in self.scenarios:
116 log.ctx(combining_scenarios=conf_name, scenario=scenario.name())
Pau Espin Pedrol0b302792017-09-10 16:33:10 +0200117 c = config.replicate_times(scenario.get(conf_name, {}))
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200118 log.dbg(scenario=scenario.name(), conf=c)
119 if c is None:
120 continue
121 config.combine(combination, c)
122 return combination
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200123
Pau Espin Pedrold0912332017-06-14 13:27:08 +0200124 def get_run_dir(self):
125 if self._run_dir is None:
126 self._run_dir = util.Dir(self.trial.get_run_dir().new_dir(self.name()))
127 return self._run_dir
128
129 def get_test_run_dir(self):
130 if self.current_test:
131 return self.current_test.get_run_dir()
132 return self.get_run_dir()
133
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200134 def resource_requirements(self):
135 if self._resource_requirements is None:
136 self._resource_requirements = self.combined('resources')
137 return self._resource_requirements
138
139 def config(self):
140 if self._config is None:
141 self._config = self.combined('config')
142 return self._config
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200143
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200144 def reserve_resources(self):
145 if self.reserved_resources:
146 raise RuntimeError('Attempt to reserve resources twice for a SuiteRun')
Neels Hofmeyr7e2e8f12017-05-14 03:37:13 +0200147 self.log('reserving resources in', self.resources_pool.state_dir, '...')
Neels Hofmeyr6ccda112017-06-06 19:41:17 +0200148 self.reserved_resources = self.resources_pool.reserve(self, self.resource_requirements())
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200149
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200150 def run_tests(self, names=None):
Pau Espin Pedrol7e02d202018-05-08 15:28:48 +0200151 suite_libdir = os.path.join(self.definition.suite_dir, 'lib')
Pau Espin Pedrol469316f2017-05-17 14:51:31 +0200152 try:
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200153 log.large_separator(self.trial.name(), self.name(), sublevel=2)
154 self.mark_start()
Pau Espin Pedrol7e02d202018-05-08 15:28:48 +0200155 util.import_path_prepend(suite_libdir)
Pau Espin Pedrol9a4631c2018-03-28 19:17:34 +0200156 MainLoop.register_poll_func(self.poll)
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200157 if not self.reserved_resources:
158 self.reserve_resources()
Pau Espin Pedrolfd5de3d2017-11-09 14:26:35 +0100159 for t in self.tests:
160 if names and not t.name() in names:
161 t.set_skip()
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200162 continue
Pau Espin Pedrolfd5de3d2017-11-09 14:26:35 +0100163 self.current_test = t
164 t.run()
Pau Espin Pedrol1dd29552017-06-13 18:07:57 +0200165 self.stop_processes()
166 self.objects_cleanup()
167 self.reserved_resources.put_all()
Neels Hofmeyr6ccda112017-06-06 19:41:17 +0200168 except Exception:
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200169 log.log_exn()
Neels Hofmeyr6ccda112017-06-06 19:41:17 +0200170 except BaseException as e:
171 # when the program is aborted by a signal (like Ctrl-C), escalate to abort all.
172 self.err('SUITE RUN ABORTED: %s' % type(e).__name__)
173 raise
Pau Espin Pedrol469316f2017-05-17 14:51:31 +0200174 finally:
175 # if sys.exit() called from signal handler (e.g. SIGINT), SystemExit
176 # base exception is raised. Make sure to stop processes in this
177 # finally section. Resources are automatically freed with 'atexit'.
178 self.stop_processes()
Neels Hofmeyr4d688c22017-05-29 04:13:58 +0200179 self.objects_cleanup()
Neels Hofmeyred4e5282017-05-29 02:53:54 +0200180 self.free_resources()
Pau Espin Pedrol9a4631c2018-03-28 19:17:34 +0200181 MainLoop.unregister_poll_func(self.poll)
Pau Espin Pedrol7e02d202018-05-08 15:28:48 +0200182 util.import_path_remove(suite_libdir)
Neels Hofmeyr6ccda112017-06-06 19:41:17 +0200183 self.duration = time.time() - self.start_timestamp
184
185 passed, skipped, failed = self.count_test_results()
186 # if no tests ran, count it as failure
187 if passed and not failed:
188 self.status = SuiteRun.PASS
189 else:
190 self.status = SuiteRun.FAIL
191
192 log.large_separator(self.trial.name(), self.name(), self.status, sublevel=2, space_above=False)
193
194 def passed(self):
195 return self.status == SuiteRun.PASS
196
197 def count_test_results(self):
198 passed = 0
199 skipped = 0
200 failed = 0
Pau Espin Pedrolfd5de3d2017-11-09 14:26:35 +0100201 for t in self.tests:
202 if t.status == test.Test.PASS:
Neels Hofmeyr6ccda112017-06-06 19:41:17 +0200203 passed += 1
Pau Espin Pedrolfd5de3d2017-11-09 14:26:35 +0100204 elif t.status == test.Test.FAIL:
Neels Hofmeyr6ccda112017-06-06 19:41:17 +0200205 failed += 1
206 else:
207 skipped += 1
208 return (passed, skipped, failed)
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200209
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200210 def remember_to_stop(self, process):
211 if self._processes is None:
212 self._processes = []
Pau Espin Pedrolecf10792017-05-08 16:56:38 +0200213 self._processes.insert(0, process)
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200214
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200215 def stop_processes(self):
Pau Espin Pedrol1dd29552017-06-13 18:07:57 +0200216 while self._processes:
217 self._processes.pop().terminate()
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200218
Pau Espin Pedrol1b28a582018-03-08 21:01:26 +0100219 def stop_process(self, process):
220 'Remove process from monitored list and stop it'
221 self._processes.remove(process)
222 process.terminate()
223
Neels Hofmeyred4e5282017-05-29 02:53:54 +0200224 def free_resources(self):
225 if self.reserved_resources is None:
226 return
227 self.reserved_resources.free()
228
Neels Hofmeyrb902b292017-06-06 21:52:03 +0200229 def ip_address(self, specifics=None):
230 return self.reserved_resources.get(resource.R_IP_ADDRESS, specifics=specifics)
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200231
Neels Hofmeyr76d81032017-05-18 18:35:32 +0200232 def nitb(self, ip_address=None):
233 if ip_address is None:
234 ip_address = self.ip_address()
235 return osmo_nitb.OsmoNitb(self, ip_address)
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200236
Neels Hofmeyr798e5922017-05-18 15:24:02 +0200237 def hlr(self, ip_address=None):
238 if ip_address is None:
239 ip_address = self.ip_address()
240 return osmo_hlr.OsmoHlr(self, ip_address)
241
Pau Espin Pedrol30ceb5c2017-08-31 18:30:11 +0200242 def ggsn(self, ip_address=None):
243 if ip_address is None:
244 ip_address = self.ip_address()
245 return osmo_ggsn.OsmoGgsn(self, ip_address)
246
Pau Espin Pedrol4796b352017-11-23 11:07:42 +0100247 def sgsn(self, hlr, ggsn, ip_address=None):
248 if ip_address is None:
249 ip_address = self.ip_address()
250 return osmo_sgsn.OsmoSgsn(self, hlr, ggsn, ip_address)
251
Neels Hofmeyr798e5922017-05-18 15:24:02 +0200252 def mgcpgw(self, ip_address=None, bts_ip=None):
253 if ip_address is None:
254 ip_address = self.ip_address()
255 return osmo_mgcpgw.OsmoMgcpgw(self, ip_address, bts_ip)
256
Pau Espin Pedrol386b78d2017-11-09 13:02:09 +0100257 def mgw(self, ip_address=None):
258 if ip_address is None:
259 ip_address = self.ip_address()
260 return osmo_mgw.OsmoMgw(self, ip_address)
261
Pau Espin Pedrol1e1d3812017-11-16 18:06:37 +0100262 def msc(self, hlr, mgcpgw, stp, ip_address=None):
Neels Hofmeyr798e5922017-05-18 15:24:02 +0200263 if ip_address is None:
264 ip_address = self.ip_address()
Pau Espin Pedrol1e1d3812017-11-16 18:06:37 +0100265 return osmo_msc.OsmoMsc(self, hlr, mgcpgw, stp, ip_address)
Neels Hofmeyr798e5922017-05-18 15:24:02 +0200266
Pau Espin Pedrol1e1d3812017-11-16 18:06:37 +0100267 def bsc(self, msc, mgw, stp, ip_address=None):
Neels Hofmeyr798e5922017-05-18 15:24:02 +0200268 if ip_address is None:
269 ip_address = self.ip_address()
Pau Espin Pedrol1e1d3812017-11-16 18:06:37 +0100270 return osmo_bsc.OsmoBsc(self, msc, mgw, stp, ip_address)
Neels Hofmeyr798e5922017-05-18 15:24:02 +0200271
Neels Hofmeyr38b051c2017-06-13 16:26:06 +0200272 def stp(self, ip_address=None):
273 if ip_address is None:
274 ip_address = self.ip_address()
275 return osmo_stp.OsmoStp(self, ip_address)
276
Neels Hofmeyrb902b292017-06-06 21:52:03 +0200277 def bts(self, specifics=None):
Pau Espin Pedrol15aae982017-09-08 13:55:54 +0200278 bts = bts_obj(self, self.reserved_resources.get(resource.R_BTS, specifics=specifics))
Pau Espin Pedrol5e0c2512017-11-06 18:40:23 +0100279 bts.set_lac(self.lac())
Pau Espin Pedrol8a3a7b52017-11-28 15:50:02 +0100280 bts.set_rac(self.rac())
Pau Espin Pedrol4ccce7c2017-11-07 11:13:20 +0100281 bts.set_cellid(self.cellid())
Pau Espin Pedrol8a3a7b52017-11-28 15:50:02 +0100282 bts.set_bvci(self.bvci())
Pau Espin Pedrol15aae982017-09-08 13:55:54 +0200283 self.register_for_cleanup(bts)
284 return bts
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200285
Neels Hofmeyrb902b292017-06-06 21:52:03 +0200286 def modem(self, specifics=None):
287 conf = self.reserved_resources.get(resource.R_MODEM, specifics=specifics)
Neels Hofmeyr4d688c22017-05-29 04:13:58 +0200288 self.dbg('create Modem object', conf=conf)
Pau Espin Pedrol6cdd2fd2017-11-07 11:57:42 +0100289 ms = modem.Modem(conf)
290 self.register_for_cleanup(ms)
291 return ms
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200292
Neels Hofmeyrf2d279c2017-05-06 15:05:02 +0200293 def modems(self, count):
294 l = []
295 for i in range(count):
296 l.append(self.modem())
297 return l
298
Pau Espin Pedrol2d16f6f2017-05-30 15:33:57 +0200299 def esme(self):
300 esme_obj = esme.Esme(self.msisdn())
Pau Espin Pedrolac9c1bb2017-08-10 10:59:40 +0200301 self.register_for_cleanup(esme_obj)
Pau Espin Pedrol2d16f6f2017-05-30 15:33:57 +0200302 return esme_obj
303
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200304 def msisdn(self):
Pau Espin Pedrol2d16f6f2017-05-30 15:33:57 +0200305 msisdn = self.resources_pool.next_msisdn(self)
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200306 self.log('using MSISDN', msisdn)
307 return msisdn
308
Pau Espin Pedrol5e0c2512017-11-06 18:40:23 +0100309 def lac(self):
310 lac = self.resources_pool.next_lac(self)
311 self.log('using LAC', lac)
312 return lac
313
Pau Espin Pedrol8a3a7b52017-11-28 15:50:02 +0100314 def rac(self):
315 rac = self.resources_pool.next_rac(self)
316 self.log('using RAC', rac)
317 return rac
318
Pau Espin Pedrol4ccce7c2017-11-07 11:13:20 +0100319 def cellid(self):
320 cellid = self.resources_pool.next_cellid(self)
321 self.log('using CellId', cellid)
322 return cellid
323
Pau Espin Pedrol8a3a7b52017-11-28 15:50:02 +0100324 def bvci(self):
325 bvci = self.resources_pool.next_bvci(self)
326 self.log('using BVCI', bvci)
327 return bvci
328
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200329 def poll(self):
330 if self._processes:
331 for process in self._processes:
Neels Hofmeyr5356d0a2017-04-10 03:45:30 +0200332 if process.terminated():
Neels Hofmeyr85eb3242017-04-09 22:01:16 +0200333 process.log_stdout_tail()
334 process.log_stderr_tail()
Neels Hofmeyr1a7a3f02017-06-10 01:18:27 +0200335 log.ctx(process)
Pau Espin Pedrol800a6972017-07-03 18:34:09 +0200336 raise log.Error('Process ended prematurely: %s' % process.name())
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200337
338 def prompt(self, *msgs, **msg_details):
339 'ask for user interaction. Do not use in tests that should run automatically!'
340 if msg_details:
341 msgs = list(msgs)
342 msgs.append('{%s}' %
343 (', '.join(['%s=%r' % (k,v)
344 for k,v in sorted(msg_details.items())])))
345 msg = ' '.join(msgs) or 'Hit Enter to continue'
346 self.log('prompt:', msg)
Neels Hofmeyracf0c932017-05-06 16:05:33 +0200347 sys.__stdout__.write('\n\n--- PROMPT ---\n')
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200348 sys.__stdout__.write(msg)
Neels Hofmeyracf0c932017-05-06 16:05:33 +0200349 sys.__stdout__.write('\n')
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200350 sys.__stdout__.flush()
Pau Espin Pedrol9a4631c2018-03-28 19:17:34 +0200351 entered = util.input_polling('> ', MainLoop.poll)
Neels Hofmeyracf0c932017-05-06 16:05:33 +0200352 self.log('prompt entered:', repr(entered))
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200353 return entered
354
Neels Hofmeyr2d1d5612017-05-22 20:02:41 +0200355 def resource_status_str(self):
356 return '\n'.join(('',
357 'SUITE RUN: %s' % self.origin_id(),
358 'ASKED FOR:', pprint.pformat(self._resource_requirements),
359 'RESERVED COUNT:', pprint.pformat(self.reserved_resources.counts()),
360 'RESOURCES STATE:', repr(self.reserved_resources)))
361
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200362loaded_suite_definitions = {}
363
364def load(suite_name):
365 global loaded_suite_definitions
366
367 suite = loaded_suite_definitions.get(suite_name)
368 if suite is not None:
369 return suite
370
371 suites_dir = config.get_suites_dir()
372 suite_dir = suites_dir.child(suite_name)
373 if not suites_dir.exists(suite_name):
374 raise RuntimeError('Suite not found: %r in %r' % (suite_name, suites_dir))
375 if not suites_dir.isdir(suite_name):
376 raise RuntimeError('Suite name found, but not a directory: %r' % (suite_dir))
377
378 suite_def = SuiteDefinition(suite_dir)
379 loaded_suite_definitions[suite_name] = suite_def
380 return suite_def
381
382def parse_suite_scenario_str(suite_scenario_str):
383 tokens = suite_scenario_str.split(':')
384 if len(tokens) > 2:
385 raise RuntimeError('invalid combination string: %r' % suite_scenario_str)
386
387 suite_name = tokens[0]
388 if len(tokens) <= 1:
389 scenario_names = []
390 else:
391 scenario_names = tokens[1].split('+')
392
393 return suite_name, scenario_names
394
395def load_suite_scenario_str(suite_scenario_str):
396 suite_name, scenario_names = parse_suite_scenario_str(suite_scenario_str)
397 suite = load(suite_name)
Pau Espin Pedrol0b302792017-09-10 16:33:10 +0200398 scenarios = [config.get_scenario(scenario_name, resource.CONF_SCHEMA) for scenario_name in scenario_names]
Your Name44af3412017-04-13 03:11:59 +0200399 return (suite_scenario_str, suite, scenarios)
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200400
401def bts_obj(suite_run, conf):
402 bts_type = conf.get('type')
Neels Hofmeyrd28d1a72017-06-14 02:59:55 +0200403 log.dbg('create BTS object', type=bts_type)
Neels Hofmeyr3531a192017-03-28 14:30:28 +0200404 bts_class = resource.KNOWN_BTS_TYPES.get(bts_type)
405 if bts_class is None:
406 raise RuntimeError('No such BTS type is defined: %r' % bts_type)
407 return bts_class(suite_run, conf)
408
Neels Hofmeyrdae3d3c2017-03-28 12:16:58 +0200409# vim: expandtab tabstop=4 shiftwidth=4