config: suites_dir and scenarios_dir are now a list of paths

This allows inheriting suites or scenarios from eg. sysmocom/ dir, while
still allowing to apply new suites and scenarios on top.

Change-Id: Icecdae32d400a6b6da2ebf167c1c795f7a74ae96
This commit is contained in:
Pau Espin 2020-05-25 13:26:41 +02:00
parent 3a0dea682e
commit 66ef9457cb
25 changed files with 96 additions and 55 deletions

View File

@ -1,6 +1,6 @@
state_dir: '/var/tmp/osmo-gsm-tester/state'
suites_dir: './suites'
scenarios_dir: './scenarios'
suites_dir: ['./suites']
scenarios_dir: ['./scenarios']
default_suites_conf_path: './default-suites.conf'
defaults_conf_path: './defaults.conf'
resource_conf_path: './resources.conf'

View File

@ -1,6 +1,6 @@
state_dir: '/var/tmp/osmo-gsm-tester/state'
suites_dir: './suites'
scenarios_dir: './scenarios'
suites_dir: ['./suites']
scenarios_dir: ['./scenarios']
default_suites_conf_path: './default-suites.conf'
defaults_conf_path: './defaults.conf'
resource_conf_path: './resources.conf'

View File

@ -26,13 +26,19 @@ then overrides the above locations.
{app-name} expects to find the following configuration settings in 'main.conf':
- 'state_dir': Path to <<state_dir,state_dir>> directory
- 'suites_dir': Path to <<suites_dir,suites_dir>> directory
- 'trial_dir': Path to <<trials,trial>> directory to test against (overridden by cmdline argument)
- 'scenarios_dir': Path to <<scenarios_dir,scenarios_dir>> directory (optional)
- 'suites_dir': List of paths to <<suites_dir,suites_dir>> directories.
- 'scenarios_dir': List of paths to <<scenarios_dir,scenarios_dir>> directories (optional)
- 'default_suites_conf_path': Path to <<default_suites_conf,default-suites.conf>> file (optional)
- 'defaults_conf_path': Path to <<defaults_conf,defaults.conf>> file (optional)
- 'resource_conf_path': Path to <<resource_conf,resources.conf>> file (optional)
Configuration settings holding a list of paths, such as 'suites_dir' or
'scenarios_dir', are used to look up for paths in regular list of order, meaning
first paths in list take preference over last ones. As a result, if a suite
named 'A' is found in several paths, the one on the first path in the list will
be used.
These are described in detail in the following sections. If no value is provided
for a given setting, sane default paths are used: For 'state_dir',
'/var/tmp/osmo-gsm-tester/state/' is used. All other files and directories are
@ -45,8 +51,8 @@ of the {app-name} process parsing it.
.Sample main.conf file:
----
state_dir: '/var/tmp/osmo-gsm-tester/state'
suites_dir: '/usr/local/src/osmo-gsm-tester/suites'
scenarios_dir: './scenarios'
suites_dir: [ '/usr/local/src/osmo-gsm-tester/suites' ]
scenarios_dir: [ './scenarios' ]
trial_dir: './trial'
default_suites_conf_path: './default-suites.conf'
defaults_conf_path: './defaults.conf'

View File

@ -1,2 +1,2 @@
state_dir: ./test_work/state_dir
suites_dir: ./suite_test
suites_dir: ['./suite_test']

View File

@ -14,9 +14,9 @@ cnf -: DBG: MAIN CONFIG:
{'default_suites_conf_path': '[PATH]/selftest/resource_test/conf/default-suites.conf',
'defaults_conf_path': '[PATH]/selftest/resource_test/conf/defaults.conf',
'resource_conf_path': '[PATH]/selftest/resource_test/conf/resources.conf',
'scenarios_dir': '[PATH]/selftest/resource_test/conf/scenarios',
'scenarios_dir': ['[PATH]/selftest/resource_test/conf/scenarios'],
'state_dir': '[PATH]/selftest/resource_test/conf/test_work/state_dir',
'suites_dir': '[PATH]/selftest/resource_test/conf/suite_test',
'suites_dir': ['[PATH]/selftest/resource_test/conf/suite_test'],
'trial_dir': '[PATH]/selftest/resource_test/conf/trial'}
*** all resources:
{'arfcn': [{'_hash': 'e620569450f8259b3f0212ec19c285dd07df063c',

View File

@ -1,3 +1,3 @@
state_dir: ./test_work/state_dir
suites_dir: .
scenarios_dir: .
suites_dir: ['.']
scenarios_dir: ['.']

View File

@ -3,9 +3,9 @@ cnf -: DBG: MAIN CONFIG:
{'default_suites_conf_path': '[PATH]/selftest/scenario_test/default-suites.conf',
'defaults_conf_path': '[PATH]/selftest/scenario_test/defaults.conf',
'resource_conf_path': '[PATH]/selftest/scenario_test/resources.conf',
'scenarios_dir': '[PATH]/selftest/scenario_test',
'scenarios_dir': ['[PATH]/selftest/scenario_test'],
'state_dir': '[PATH]/selftest/scenario_test/test_work/state_dir',
'suites_dir': '[PATH]/selftest/scenario_test',
'suites_dir': ['[PATH]/selftest/scenario_test'],
'trial_dir': '[PATH]/selftest/scenario_test/trial'}
scenario_case_01.conf
{'anotherlist': ['4', '0'],
@ -19,11 +19,11 @@ scenario_case_01.conf
'somelist': [{'somelistitem': 'firststring'},
{'somelistitem': 'secondstring'},
{'somelistitem': 'thirdstring'}]}
OK: expected RuntimeError: No such scenario file: '[PATH]/selftest/scenario_test/scenario_case_01@.conf' (nor scenario_case_01@.conf)
OK: expected RuntimeError: No such scenario file 'scenario_case_01@.conf' (nor scenario_case_01@.conf) in [[PATH]/selftest/scenario_test]
OK: expected ValueError
OK: expected ValueError
OK: expected RuntimeError: No such scenario file: '[PATH]/selftest/scenario_test/scenario_case_03.conf'
OK: expected RuntimeError: No such scenario file: '[PATH]/selftest/scenario_test/scenario_case_03.conf'
OK: expected RuntimeError: No such scenario file scenario_case_03.conf in [[PATH]/selftest/scenario_test]
OK: expected RuntimeError: No such scenario file scenario_case_03.conf in [[PATH]/selftest/scenario_test]
tst scenario_case_03@heyho,1,yes.conf: DBG: {param_dict={param1='heyho', param2='1', param3='yes'}}
scenario_case_03@heyho,1,yes.conf
{'anotherlist': ['1', '0'],

View File

@ -1,2 +1,2 @@
state_dir: ./test_work/state_dir
suites_dir: .
suites_dir: ['suitedirA', 'suitedirB']

View File

@ -4,14 +4,15 @@ cnf -: DBG: MAIN CONFIG:
{'default_suites_conf_path': '[PATH]/selftest/suite_test/default-suites.conf',
'defaults_conf_path': '[PATH]/selftest/suite_test/defaults.conf',
'resource_conf_path': '[PATH]/selftest/suite_test/resources.conf',
'scenarios_dir': '[PATH]/selftest/suite_test/scenarios',
'scenarios_dir': ['[PATH]/selftest/suite_test/scenarios'],
'state_dir': '[PATH]/selftest/suite_test/test_work/state_dir',
'suites_dir': '[PATH]/selftest/suite_test',
'suites_dir': ['[PATH]/selftest/suite_test/suitedirA',
'[PATH]/selftest/suite_test/suitedirB'],
'trial_dir': '[PATH]/selftest/suite_test/trial'}
--- -: ERR: RuntimeError: Suite not found: 'does_not_exist' in [PATH]/selftest/suite_test
--- -: ERR: RuntimeError: Suite not found: 'does_not_exist' in [[PATH]/selftest/suite_test/suitedirA, [PATH]/selftest/suite_test/suitedirB]
- no suite.conf
cnf empty_dir: DBG: reading suite.conf
cnf [PATH]/selftest/suite_test/empty_dir/suite.conf: ERR: FileNotFoundError: [Errno 2] No such file or directory: '[PATH]/selftest/suite_test/empty_dir/suite.conf' [empty_dir↪[PATH]/selftest/suite_test/empty_dir/suite.conf]
cnf [PATH]/selftest/suite_test/suitedirA/empty_dir/suite.conf: ERR: FileNotFoundError: [Errno 2] No such file or directory: '[PATH]/selftest/suite_test/suitedirA/empty_dir/suite.conf' [empty_dir↪[PATH]/selftest/suite_test/suitedirA/empty_dir/suite.conf]
- valid suite dir
cnf test_suite: DBG: reading suite.conf
defaults:

View File

@ -0,0 +1,4 @@
resources:
defaults:
timeout: 60s

View File

@ -0,0 +1,5 @@
#!/usr/bin/env python3
from osmo_gsm_tester.testenv import *
print('I am %r / %r' % (tenv.suite().name(), test.name()))

View File

@ -71,8 +71,8 @@ CFG_DEFAULTS_CONF = 'defaults_conf_path'
CFG_RESOURCES_CONF = 'resource_conf_path'
MAIN_CONFIG_SCHEMA = {
CFG_STATE_DIR: schema.STR,
CFG_SUITES_DIR: schema.STR,
CFG_SCENARIOS_DIR: schema.STR,
CFG_SUITES_DIR + '[]': schema.STR,
CFG_SCENARIOS_DIR + '[]': schema.STR,
CFG_TRIAL_DIR: schema.STR,
CFG_DEFAULT_SUITES_CONF: schema.STR,
CFG_DEFAULTS_CONF: schema.STR,
@ -80,8 +80,8 @@ MAIN_CONFIG_SCHEMA = {
}
DF_CFG_STATE_DIR = '/var/tmp/osmo-gsm-tester/state/'
DF_CFG_SUITES_DIR = './suites'
DF_CFG_SCENARIOS_DIR = './scenarios'
DF_CFG_SUITES_DIR = ['./suites']
DF_CFG_SCENARIOS_DIR = ['./scenarios']
DF_CFG_TRIAL_DIR = './trial'
DF_CFG_DEFAULT_SUITES_CONF = './default-suites.conf'
DF_CFG_DEFAULTS_CONF = './defaults.conf'
@ -122,11 +122,16 @@ def _get_main_config_path():
MAIN_CONFIG_PATH = _find_main_config_path()
return MAIN_CONFIG_PATH
def main_config_path_to_abspath(path):
def main_config_path_to_abspath(val):
'Relative files in main config are relative towards the config file, not towards $CWD'
if not path.startswith(os.pathsep):
return os.path.realpath(os.path.join(os.path.dirname(_get_main_config_path()), path))
return path
# If val is a list of paths, recurse to translate its paths.
if isinstance(val, list):
for i in range(len(val)):
val[i] = main_config_path_to_abspath(val[i])
return val
if not val.startswith(os.pathsep):
return os.path.realpath(os.path.join(os.path.dirname(_get_main_config_path()), val))
return val
def _get_main_config():
global MAIN_CONFIG
@ -169,11 +174,11 @@ def read_config_file(cfg_name, validation_schema=None, if_missing_return=False):
def get_state_dir():
return Dir(get_main_config_value(CFG_STATE_DIR))
def get_suites_dir():
return Dir(get_main_config_value(CFG_SUITES_DIR))
def get_suites_dirs():
return [Dir(d) for d in get_main_config_value(CFG_SUITES_DIR)]
def get_scenarios_dir():
return Dir(get_main_config_value(CFG_SCENARIOS_DIR))
def get_scenarios_dirs():
return [Dir(d) for d in get_main_config_value(CFG_SCENARIOS_DIR)]
DEFAULTS_CONF = None
def get_defaults(for_kind):

View File

@ -88,25 +88,41 @@ class Scenario(log.Origin, dict):
self.update(conf)
def get_scenario(name, validation_schema=None):
scenarios_dir = config.get_scenarios_dir()
found = False
path = None
param_list = []
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)
scenarios_dirs = config.get_scenarios_dirs()
for d in scenarios_dirs:
path = d.child(name)
if os.path.isfile(path):
found = True
break
if not found:
raise RuntimeError('No such scenario file %s in %r' % (name, scenarios_dirs))
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):
scenarios_dirs = config.get_scenarios_dirs()
for d in scenarios_dirs:
path = d.child(name)
if os.path.isfile(path):
found = True
break
if not found:
# get "scenario@.conf" from "scenario@param1,param2.conf":
for d in scenarios_dirs:
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))
path = d.child(prefix_name)
if os.path.isfile(path):
found = True
break
if not found:
raise RuntimeError('No such scenario file %r (nor %s) in %r' % (name, prefix_name, scenarios_dirs))
# 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')]

View File

@ -232,12 +232,16 @@ def load(suite_name):
if suite is not None:
return suite
suites_dir = config.get_suites_dir()
suite_dir = suites_dir.child(suite_name)
if not suites_dir.exists(suite_name):
raise RuntimeError('Suite not found: %r in %r' % (suite_name, suites_dir))
if not suites_dir.isdir(suite_name):
raise RuntimeError('Suite name found, but not a directory: %r' % (suite_dir))
suites_dirs = config.get_suites_dirs()
suite_dir = None
found = False
for d in suites_dirs:
suite_dir = d.child(suite_name)
if d.exists(suite_name) and d.isdir(suite_name):
found = True
break
if not found:
raise RuntimeError('Suite not found: %r in %r' % (suite_name, suites_dirs))
suite_def = SuiteDefinition(suite_dir)
loaded_suite_definitions[suite_name] = suite_def

View File

@ -1,6 +1,6 @@
state_dir: '/var/tmp/osmo-gsm-tester/state'
suites_dir: './suites'
scenarios_dir: './scenarios'
suites_dir: ['./suites']
scenarios_dir: ['./scenarios']
default_suites_conf_path: './default-suites.conf'
defaults_conf_path: './defaults.conf'
resource_conf_path: './resources.conf'

View File

@ -1,6 +1,6 @@
state_dir: '/var/tmp/osmo-gsm-tester/state'
suites_dir: './suites'
scenarios_dir: './scenarios'
suites_dir: ['./suites']
scenarios_dir: ['./scenarios']
default_suites_conf_path: './default-suites.conf'
defaults_conf_path: '../defaults.conf'
resource_conf_path: './resources.conf'