blob: 83ce490fc4e4bc02dd5742a16a5d766d2ddf1095 [file] [log] [blame]
Pau Espin Pedrol4e6b5072020-05-11 15:12:07 +02001# osmo_gsm_tester: Suite scenario
2#
3# Copyright (C) 2016-2020 by sysmocom - s.f.m.c. GmbH
4#
5# Author: Neels Hofmeyr <neels@hofmeyr.de>
6# Author: Pau Espin Pedrol <pespin@sysmocom.de>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21import os
22
23from . import log
24from . import template
25from . import config
26
27class Scenario(log.Origin, dict):
28 def __init__(self, name, path, param_list=[]):
29 super().__init__(log.C_TST, name)
30 self.path = path
31 self.param_list = param_list
32
33 @classmethod
34 def count_cont_char_backward(cls, str, before_pos, c):
35 n = 0
36 i = before_pos - 1
37 while i >= 0:
38 if str[i] != c:
39 break
40 n += 1
41 i -= 1
42 return n
43
44 @classmethod
45 def split_scenario_parameters(cls, str):
46 cur_pos = 0
47 param_li = []
48 saved = ''
49 # Split into a list, but we want to escape '\,' to avoid splitting parameters containing commas.
50 while True:
51 prev_pos = cur_pos
52 cur_pos = str.find(',', prev_pos)
53 if cur_pos == -1:
54 param_li.append(str[prev_pos:])
55 break
56 if cur_pos == 0:
57 param_li.append('')
58 elif cur_pos != 0 and str[cur_pos - 1] == '\\' and cls.count_cont_char_backward(str, cur_pos, '\\') % 2 == 1:
59 saved += str[prev_pos:cur_pos - 1] + ','
60 else:
61 param_li.append(saved + str[prev_pos:cur_pos])
62 saved = ''
63 cur_pos += 1
64 i = 0
65 # Also escape '\\' -> '\'
66 while i < len(param_li):
67 param_li[i] = param_li[i].replace('\\\\', '\\')
68 i += 1
69 return param_li
70
71 @classmethod
72 def from_param_list_str(cls, name, path, param_list_str):
73 param_list = cls.split_scenario_parameters(param_list_str)
74 return cls(name, path, param_list)
75
76 def read_from_file(self, validation_schema):
77 with open(self.path, 'r') as f:
78 config_str = f.read()
79 if len(self.param_list) != 0:
80 param_dict = {}
81 i = 1
82 for param in self.param_list:
83 param_dict['param' + str(i)] = param
84 i += 1
85 self.dbg(param_dict=param_dict)
86 config_str = template.render_strbuf_inline(config_str, param_dict)
87 conf = config.fromstr(config_str, validation_schema)
88 self.update(conf)
89
90def get_scenario(name, validation_schema=None):
Pau Espin Pedrol66ef9452020-05-25 13:26:41 +020091 found = False
92 path = None
93 param_list = []
Pau Espin Pedrol4e6b5072020-05-11 15:12:07 +020094 if not name.endswith('.conf'):
95 name = name + '.conf'
96 is_parametrized_file = '@' in name
Pau Espin Pedrol4e6b5072020-05-11 15:12:07 +020097 if not is_parametrized_file:
Pau Espin Pedrol66ef9452020-05-25 13:26:41 +020098 scenarios_dirs = config.get_scenarios_dirs()
99 for d in scenarios_dirs:
100 path = d.child(name)
101 if os.path.isfile(path):
102 found = True
103 break
104 if not found:
105 raise RuntimeError('No such scenario file %s in %r' % (name, scenarios_dirs))
Pau Espin Pedrol4e6b5072020-05-11 15:12:07 +0200106 sc = Scenario(name, path)
107 else: # parametrized scenario:
108 # Allow first matching complete matching names (eg: scenario@param1,param2.conf),
109 # this allows setting specific content in different files for specific values.
Pau Espin Pedrol66ef9452020-05-25 13:26:41 +0200110 scenarios_dirs = config.get_scenarios_dirs()
111 for d in scenarios_dirs:
112 path = d.child(name)
113 if os.path.isfile(path):
114 found = True
115 break
116 if not found:
Pau Espin Pedrol4e6b5072020-05-11 15:12:07 +0200117 # get "scenario@.conf" from "scenario@param1,param2.conf":
Pau Espin Pedrol66ef9452020-05-25 13:26:41 +0200118 for d in scenarios_dirs:
119 prefix_name = name[:name.index("@")+1] + '.conf'
120 path = d.child(prefix_name)
121 if os.path.isfile(path):
122 found = True
123 break
124 if not found:
125 raise RuntimeError('No such scenario file %r (nor %s) in %r' % (name, prefix_name, scenarios_dirs))
Pau Espin Pedrol4e6b5072020-05-11 15:12:07 +0200126 # At this point, we have existing file path. Let's now scrap the parameter(s):
127 # get param1,param2 str from scenario@param1,param2.conf
128 param_list_str = name.split('@', 1)[1][:-len('.conf')]
129 sc = Scenario.from_param_list_str(name, path, param_list_str)
130 sc.read_from_file(validation_schema)
131 return sc
132
133# vim: expandtab tabstop=4 shiftwidth=4