Split Scenario class to its own file
Change-Id: Ia029de7ecda4c8dc3d0b4c412e4c9c0a65cf0185
This commit is contained in:
parent
b1d8d30526
commit
4e6b5077d0
|
@ -3,7 +3,11 @@ import os
|
|||
import sys
|
||||
import _prep
|
||||
import shutil
|
||||
from osmo_gsm_tester.core import log, config, util, report
|
||||
from osmo_gsm_tester.core import log
|
||||
from osmo_gsm_tester.core import config
|
||||
from osmo_gsm_tester.core import util
|
||||
from osmo_gsm_tester.core import report
|
||||
from osmo_gsm_tester.core import scenario
|
||||
from osmo_gsm_tester.core import suite
|
||||
from osmo_gsm_tester.core.schema import generate_schemas, get_all_schema
|
||||
|
||||
|
@ -66,26 +70,26 @@ print(output)
|
|||
|
||||
print('- test with half empty scenario')
|
||||
trial = FakeTrial()
|
||||
scenario = config.Scenario('foo', 'bar')
|
||||
scenario['resources'] = { 'bts': [{'type': 'osmo-bts-trx'}] }
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])
|
||||
sc = scenario.Scenario('foo', 'bar')
|
||||
sc['resources'] = { 'bts': [{'type': 'osmo-bts-trx'}] }
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])
|
||||
results = s.run_tests('hello_world.py')
|
||||
print(report.suite_to_text(s))
|
||||
|
||||
print('- test with scenario')
|
||||
trial = FakeTrial()
|
||||
scenario = config.Scenario('foo', 'bar')
|
||||
scenario['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])
|
||||
sc = scenario.Scenario('foo', 'bar')
|
||||
sc['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])
|
||||
results = s.run_tests('hello_world.py')
|
||||
print(report.suite_to_text(s))
|
||||
|
||||
print('- test with scenario and modifiers')
|
||||
trial = FakeTrial()
|
||||
scenario = config.Scenario('foo', 'bar')
|
||||
scenario['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }
|
||||
scenario['modifiers'] = { 'bts': [{ 'times': '2', 'trx_list': [{'nominal_power': '20'}, {'nominal_power': '20'}]}, {'type': 'sysmo'}] }
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])
|
||||
sc = scenario.Scenario('foo', 'bar')
|
||||
sc['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }
|
||||
sc['modifiers'] = { 'bts': [{ 'times': '2', 'trx_list': [{'nominal_power': '20'}, {'nominal_power': '20'}]}, {'type': 'sysmo'}] }
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])
|
||||
s.reserve_resources()
|
||||
print(repr(s.reserved_resources))
|
||||
results = s.run_tests('hello_world.py')
|
||||
|
@ -93,9 +97,9 @@ print(report.suite_to_text(s))
|
|||
|
||||
print('- test with suite-specific config')
|
||||
trial = FakeTrial()
|
||||
scenario = config.Scenario('foo', 'bar')
|
||||
scenario['config'] = {'suite': {s.name(): { 'some_suite_global_param': 'heyho', 'test_suite_params': {'one_bool_parameter': 'true', 'second_list_parameter': ['23', '45']}}}}
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])
|
||||
sc = scenario.Scenario('foo', 'bar')
|
||||
sc['config'] = {'suite': {s.name(): { 'some_suite_global_param': 'heyho', 'test_suite_params': {'one_bool_parameter': 'true', 'second_list_parameter': ['23', '45']}}}}
|
||||
s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])
|
||||
s.reserve_resources()
|
||||
print(repr(s.reserved_resources))
|
||||
results = s.run_tests('test_suite_params.py')
|
||||
|
|
|
@ -165,6 +165,13 @@ def write(path, config):
|
|||
with open(path, 'w') as f:
|
||||
f.write(tostr(config))
|
||||
|
||||
def fromstr(config_str, validation_schema=None):
|
||||
config = yaml.safe_load(config_str)
|
||||
config = _standardize(config)
|
||||
if validation_schema is not None:
|
||||
schema.validate(config, validation_schema)
|
||||
return config
|
||||
|
||||
def tostr(config):
|
||||
return _tostr(_standardize(config))
|
||||
|
||||
|
@ -188,99 +195,6 @@ def get_defaults(for_kind):
|
|||
defaults = read_config_file(DEFAULTS_CONF, if_missing_return={})
|
||||
return defaults.get(for_kind, {})
|
||||
|
||||
class Scenario(log.Origin, dict):
|
||||
def __init__(self, name, path, param_list=[]):
|
||||
super().__init__(log.C_TST, name)
|
||||
self.path = path
|
||||
self.param_list = param_list
|
||||
|
||||
@classmethod
|
||||
def count_cont_char_backward(cls, str, before_pos, c):
|
||||
n = 0
|
||||
i = before_pos - 1
|
||||
while i >= 0:
|
||||
if str[i] != c:
|
||||
break
|
||||
n += 1
|
||||
i -= 1
|
||||
return n
|
||||
|
||||
@classmethod
|
||||
def split_scenario_parameters(cls, str):
|
||||
cur_pos = 0
|
||||
param_li = []
|
||||
saved = ''
|
||||
# Split into a list, but we want to escape '\,' to avoid splitting parameters containing commas.
|
||||
while True:
|
||||
prev_pos = cur_pos
|
||||
cur_pos = str.find(',', prev_pos)
|
||||
if cur_pos == -1:
|
||||
param_li.append(str[prev_pos:])
|
||||
break
|
||||
if cur_pos == 0:
|
||||
param_li.append('')
|
||||
elif cur_pos != 0 and str[cur_pos - 1] == '\\' and cls.count_cont_char_backward(str, cur_pos, '\\') % 2 == 1:
|
||||
saved += str[prev_pos:cur_pos - 1] + ','
|
||||
else:
|
||||
param_li.append(saved + str[prev_pos:cur_pos])
|
||||
saved = ''
|
||||
cur_pos += 1
|
||||
i = 0
|
||||
# Also escape '\\' -> '\'
|
||||
while i < len(param_li):
|
||||
param_li[i] = param_li[i].replace('\\\\', '\\')
|
||||
i += 1
|
||||
return param_li
|
||||
|
||||
@classmethod
|
||||
def from_param_list_str(cls, name, path, param_list_str):
|
||||
param_list = cls.split_scenario_parameters(param_list_str)
|
||||
return cls(name, path, param_list)
|
||||
|
||||
def read_from_file(self, validation_schema):
|
||||
with open(self.path, 'r') as f:
|
||||
config_str = f.read()
|
||||
if len(self.param_list) != 0:
|
||||
param_dict = {}
|
||||
i = 1
|
||||
for param in self.param_list:
|
||||
param_dict['param' + str(i)] = param
|
||||
i += 1
|
||||
self.dbg(param_dict=param_dict)
|
||||
config_str = template.render_strbuf_inline(config_str, param_dict)
|
||||
config = yaml.safe_load(config_str)
|
||||
config = _standardize(config)
|
||||
if validation_schema:
|
||||
schema.validate(config, validation_schema)
|
||||
self.update(config)
|
||||
|
||||
def get_scenario(name, validation_schema=None):
|
||||
scenarios_dir = get_scenarios_dir()
|
||||
if not name.endswith('.conf'):
|
||||
name = name + '.conf'
|
||||
is_parametrized_file = '@' in name
|
||||
param_list = []
|
||||
path = scenarios_dir.child(name)
|
||||
if not is_parametrized_file:
|
||||
if not os.path.isfile(path):
|
||||
raise RuntimeError('No such scenario file: %r' % path)
|
||||
sc = Scenario(name, path)
|
||||
else: # parametrized scenario:
|
||||
# Allow first matching complete matching names (eg: scenario@param1,param2.conf),
|
||||
# this allows setting specific content in different files for specific values.
|
||||
if not os.path.isfile(path):
|
||||
# get "scenario@.conf" from "scenario@param1,param2.conf":
|
||||
prefix_name = name[:name.index("@")+1] + '.conf'
|
||||
path = scenarios_dir.child(prefix_name)
|
||||
if not os.path.isfile(path):
|
||||
raise RuntimeError('No such scenario file: %r (nor %s)' % (path, name))
|
||||
# At this point, we have existing file path. Let's now scrap the parameter(s):
|
||||
# get param1,param2 str from scenario@param1,param2.conf
|
||||
param_list_str = name.split('@', 1)[1][:-len('.conf')]
|
||||
sc = Scenario.from_param_list_str(name, path, param_list_str)
|
||||
sc.read_from_file(validation_schema)
|
||||
return sc
|
||||
|
||||
def overlay(dest, src):
|
||||
if is_dict(dest):
|
||||
if not is_dict(src):
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
# osmo_gsm_tester: Suite scenario
|
||||
#
|
||||
# Copyright (C) 2016-2020 by sysmocom - s.f.m.c. GmbH
|
||||
#
|
||||
# Author: Neels Hofmeyr <neels@hofmeyr.de>
|
||||
# Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
|
||||
from . import log
|
||||
from . import template
|
||||
from . import config
|
||||
|
||||
class Scenario(log.Origin, dict):
|
||||
def __init__(self, name, path, param_list=[]):
|
||||
super().__init__(log.C_TST, name)
|
||||
self.path = path
|
||||
self.param_list = param_list
|
||||
|
||||
@classmethod
|
||||
def count_cont_char_backward(cls, str, before_pos, c):
|
||||
n = 0
|
||||
i = before_pos - 1
|
||||
while i >= 0:
|
||||
if str[i] != c:
|
||||
break
|
||||
n += 1
|
||||
i -= 1
|
||||
return n
|
||||
|
||||
@classmethod
|
||||
def split_scenario_parameters(cls, str):
|
||||
cur_pos = 0
|
||||
param_li = []
|
||||
saved = ''
|
||||
# Split into a list, but we want to escape '\,' to avoid splitting parameters containing commas.
|
||||
while True:
|
||||
prev_pos = cur_pos
|
||||
cur_pos = str.find(',', prev_pos)
|
||||
if cur_pos == -1:
|
||||
param_li.append(str[prev_pos:])
|
||||
break
|
||||
if cur_pos == 0:
|
||||
param_li.append('')
|
||||
elif cur_pos != 0 and str[cur_pos - 1] == '\\' and cls.count_cont_char_backward(str, cur_pos, '\\') % 2 == 1:
|
||||
saved += str[prev_pos:cur_pos - 1] + ','
|
||||
else:
|
||||
param_li.append(saved + str[prev_pos:cur_pos])
|
||||
saved = ''
|
||||
cur_pos += 1
|
||||
i = 0
|
||||
# Also escape '\\' -> '\'
|
||||
while i < len(param_li):
|
||||
param_li[i] = param_li[i].replace('\\\\', '\\')
|
||||
i += 1
|
||||
return param_li
|
||||
|
||||
@classmethod
|
||||
def from_param_list_str(cls, name, path, param_list_str):
|
||||
param_list = cls.split_scenario_parameters(param_list_str)
|
||||
return cls(name, path, param_list)
|
||||
|
||||
def read_from_file(self, validation_schema):
|
||||
with open(self.path, 'r') as f:
|
||||
config_str = f.read()
|
||||
if len(self.param_list) != 0:
|
||||
param_dict = {}
|
||||
i = 1
|
||||
for param in self.param_list:
|
||||
param_dict['param' + str(i)] = param
|
||||
i += 1
|
||||
self.dbg(param_dict=param_dict)
|
||||
config_str = template.render_strbuf_inline(config_str, param_dict)
|
||||
conf = config.fromstr(config_str, validation_schema)
|
||||
self.update(conf)
|
||||
|
||||
def get_scenario(name, validation_schema=None):
|
||||
scenarios_dir = config.get_scenarios_dir()
|
||||
if not name.endswith('.conf'):
|
||||
name = name + '.conf'
|
||||
is_parametrized_file = '@' in name
|
||||
param_list = []
|
||||
path = scenarios_dir.child(name)
|
||||
if not is_parametrized_file:
|
||||
if not os.path.isfile(path):
|
||||
raise RuntimeError('No such scenario file: %r' % path)
|
||||
sc = Scenario(name, path)
|
||||
else: # parametrized scenario:
|
||||
# Allow first matching complete matching names (eg: scenario@param1,param2.conf),
|
||||
# this allows setting specific content in different files for specific values.
|
||||
if not os.path.isfile(path):
|
||||
# get "scenario@.conf" from "scenario@param1,param2.conf":
|
||||
prefix_name = name[:name.index("@")+1] + '.conf'
|
||||
path = scenarios_dir.child(prefix_name)
|
||||
if not os.path.isfile(path):
|
||||
raise RuntimeError('No such scenario file: %r (nor %s)' % (path, name))
|
||||
# At this point, we have existing file path. Let's now scrap the parameter(s):
|
||||
# get param1,param2 str from scenario@param1,param2.conf
|
||||
param_list_str = name.split('@', 1)[1][:-len('.conf')]
|
||||
sc = Scenario.from_param_list_str(name, path, param_list_str)
|
||||
sc.read_from_file(validation_schema)
|
||||
return sc
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
|
@ -26,6 +26,7 @@ from . import log
|
|||
from . import util
|
||||
from . import schema
|
||||
from . import resource
|
||||
from . import scenario
|
||||
from . import test
|
||||
|
||||
class SuiteDefinition(log.Origin):
|
||||
|
@ -111,12 +112,12 @@ class SuiteRun(log.Origin):
|
|||
if replicate_times:
|
||||
combination = config.replicate_times(combination)
|
||||
log.dbg(definition_conf=combination)
|
||||
for scenario in self.scenarios:
|
||||
log.ctx(combining_scenarios=conf_name, scenario=scenario.name())
|
||||
c = scenario.get(conf_name, {})
|
||||
for sc in self.scenarios:
|
||||
log.ctx(combining_scenarios=conf_name, scenario=sc.name())
|
||||
c = sc.get(conf_name, {})
|
||||
if replicate_times:
|
||||
c = config.replicate_times(c)
|
||||
log.dbg(scenario=scenario.name(), conf=c)
|
||||
log.dbg(scenario=sc.name(), conf=c)
|
||||
if c is None:
|
||||
continue
|
||||
schema.combine(combination, c)
|
||||
|
@ -258,7 +259,7 @@ def parse_suite_scenario_str(suite_scenario_str):
|
|||
def load_suite_scenario_str(suite_scenario_str):
|
||||
suite_name, scenario_names = parse_suite_scenario_str(suite_scenario_str)
|
||||
suite = load(suite_name)
|
||||
scenarios = [config.get_scenario(scenario_name, schema.get_all_schema()) for scenario_name in scenario_names]
|
||||
scenarios = [scenario.get_scenario(scenario_name, schema.get_all_schema()) for scenario_name in scenario_names]
|
||||
return (suite_scenario_str, suite, scenarios)
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
||||
|
|
Loading…
Reference in New Issue