<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/18200">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Split Scenario class to its own file<br><br>Change-Id: Ia029de7ecda4c8dc3d0b4c412e4c9c0a65cf0185<br>---<br>M selftest/suite_test/suite_test.py<br>M src/osmo_gsm_tester/core/config.py<br>A src/osmo_gsm_tester/core/scenario.py<br>M src/osmo_gsm_tester/core/suite.py<br>4 files changed, 148 insertions(+), 112 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-gsm-tester refs/changes/00/18200/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/selftest/suite_test/suite_test.py b/selftest/suite_test/suite_test.py</span><br><span>index fc5f9df..a096027 100755</span><br><span>--- a/selftest/suite_test/suite_test.py</span><br><span>+++ b/selftest/suite_test/suite_test.py</span><br><span>@@ -3,7 +3,11 @@</span><br><span> import sys</span><br><span> import _prep</span><br><span> import shutil</span><br><span style="color: hsl(0, 100%, 40%);">-from osmo_gsm_tester.core import log, config, util, report</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.core import log</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.core import config</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.core import util</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.core import report</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.core import scenario</span><br><span> from osmo_gsm_tester.core import suite</span><br><span> from osmo_gsm_tester.core.schema import generate_schemas, get_all_schema</span><br><span> </span><br><span>@@ -66,26 +70,26 @@</span><br><span> </span><br><span> print('- test with half empty scenario')</span><br><span> trial = FakeTrial()</span><br><span style="color: hsl(0, 100%, 40%);">-scenario = config.Scenario('foo', 'bar')</span><br><span style="color: hsl(0, 100%, 40%);">-scenario['resources'] = { 'bts': [{'type': 'osmo-bts-trx'}] }</span><br><span style="color: hsl(0, 100%, 40%);">-s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])</span><br><span style="color: hsl(120, 100%, 40%);">+sc = scenario.Scenario('foo', 'bar')</span><br><span style="color: hsl(120, 100%, 40%);">+sc['resources'] = { 'bts': [{'type': 'osmo-bts-trx'}] }</span><br><span style="color: hsl(120, 100%, 40%);">+s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])</span><br><span> results = s.run_tests('hello_world.py')</span><br><span> print(report.suite_to_text(s))</span><br><span> </span><br><span> print('- test with scenario')</span><br><span> trial = FakeTrial()</span><br><span style="color: hsl(0, 100%, 40%);">-scenario = config.Scenario('foo', 'bar')</span><br><span style="color: hsl(0, 100%, 40%);">-scenario['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(0, 100%, 40%);">-s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])</span><br><span style="color: hsl(120, 100%, 40%);">+sc = scenario.Scenario('foo', 'bar')</span><br><span style="color: hsl(120, 100%, 40%);">+sc['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(120, 100%, 40%);">+s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])</span><br><span> results = s.run_tests('hello_world.py')</span><br><span> print(report.suite_to_text(s))</span><br><span> </span><br><span> print('- test with scenario and modifiers')</span><br><span> trial = FakeTrial()</span><br><span style="color: hsl(0, 100%, 40%);">-scenario = config.Scenario('foo', 'bar')</span><br><span style="color: hsl(0, 100%, 40%);">-scenario['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(0, 100%, 40%);">-scenario['modifiers'] = { 'bts': [{ 'times': '2', 'trx_list': [{'nominal_power': '20'}, {'nominal_power': '20'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(0, 100%, 40%);">-s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])</span><br><span style="color: hsl(120, 100%, 40%);">+sc = scenario.Scenario('foo', 'bar')</span><br><span style="color: hsl(120, 100%, 40%);">+sc['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(120, 100%, 40%);">+sc['modifiers'] = { 'bts': [{ 'times': '2', 'trx_list': [{'nominal_power': '20'}, {'nominal_power': '20'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(120, 100%, 40%);">+s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])</span><br><span> s.reserve_resources()</span><br><span> print(repr(s.reserved_resources))</span><br><span> results = s.run_tests('hello_world.py')</span><br><span>@@ -93,9 +97,9 @@</span><br><span> </span><br><span> print('- test with suite-specific config')</span><br><span> trial = FakeTrial()</span><br><span style="color: hsl(0, 100%, 40%);">-scenario = config.Scenario('foo', 'bar')</span><br><span style="color: hsl(0, 100%, 40%);">-scenario['config'] = {'suite': {s.name(): { 'some_suite_global_param': 'heyho', 'test_suite_params': {'one_bool_parameter': 'true', 'second_list_parameter': ['23', '45']}}}}</span><br><span style="color: hsl(0, 100%, 40%);">-s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])</span><br><span style="color: hsl(120, 100%, 40%);">+sc = scenario.Scenario('foo', 'bar')</span><br><span style="color: hsl(120, 100%, 40%);">+sc['config'] = {'suite': {s.name(): { 'some_suite_global_param': 'heyho', 'test_suite_params': {'one_bool_parameter': 'true', 'second_list_parameter': ['23', '45']}}}}</span><br><span style="color: hsl(120, 100%, 40%);">+s = suite.SuiteRun(trial, 'test_suite', s_def, [sc])</span><br><span> s.reserve_resources()</span><br><span> print(repr(s.reserved_resources))</span><br><span> results = s.run_tests('test_suite_params.py')</span><br><span>diff --git a/src/osmo_gsm_tester/core/config.py b/src/osmo_gsm_tester/core/config.py</span><br><span>index 98d422f..88e522d 100644</span><br><span>--- a/src/osmo_gsm_tester/core/config.py</span><br><span>+++ b/src/osmo_gsm_tester/core/config.py</span><br><span>@@ -165,6 +165,13 @@</span><br><span>     with open(path, 'w') as f:</span><br><span>         f.write(tostr(config))</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+def fromstr(config_str, validation_schema=None):</span><br><span style="color: hsl(120, 100%, 40%);">+    config = yaml.safe_load(config_str)</span><br><span style="color: hsl(120, 100%, 40%);">+    config = _standardize(config)</span><br><span style="color: hsl(120, 100%, 40%);">+    if validation_schema is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+        schema.validate(config, validation_schema)</span><br><span style="color: hsl(120, 100%, 40%);">+    return config</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def tostr(config):</span><br><span>     return _tostr(_standardize(config))</span><br><span> </span><br><span>@@ -188,99 +195,6 @@</span><br><span>     defaults = read_config_file(DEFAULTS_CONF, if_missing_return={})</span><br><span>     return defaults.get(for_kind, {})</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-class Scenario(log.Origin, dict):</span><br><span style="color: hsl(0, 100%, 40%);">-    def __init__(self, name, path, param_list=[]):</span><br><span style="color: hsl(0, 100%, 40%);">-        super().__init__(log.C_TST, name)</span><br><span style="color: hsl(0, 100%, 40%);">-        self.path = path</span><br><span style="color: hsl(0, 100%, 40%);">-        self.param_list = param_list</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    @classmethod</span><br><span style="color: hsl(0, 100%, 40%);">-    def count_cont_char_backward(cls, str, before_pos, c):</span><br><span style="color: hsl(0, 100%, 40%);">-        n = 0</span><br><span style="color: hsl(0, 100%, 40%);">-        i = before_pos - 1</span><br><span style="color: hsl(0, 100%, 40%);">-        while i >= 0:</span><br><span style="color: hsl(0, 100%, 40%);">-            if str[i] != c:</span><br><span style="color: hsl(0, 100%, 40%);">-                break</span><br><span style="color: hsl(0, 100%, 40%);">-            n += 1</span><br><span style="color: hsl(0, 100%, 40%);">-            i -= 1</span><br><span style="color: hsl(0, 100%, 40%);">-        return n</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    @classmethod</span><br><span style="color: hsl(0, 100%, 40%);">-    def split_scenario_parameters(cls, str):</span><br><span style="color: hsl(0, 100%, 40%);">-        cur_pos = 0</span><br><span style="color: hsl(0, 100%, 40%);">-        param_li = []</span><br><span style="color: hsl(0, 100%, 40%);">-        saved = ''</span><br><span style="color: hsl(0, 100%, 40%);">-        # Split into a list, but we want to escape '\,' to avoid splitting parameters containing commas.</span><br><span style="color: hsl(0, 100%, 40%);">-        while True:</span><br><span style="color: hsl(0, 100%, 40%);">-            prev_pos = cur_pos</span><br><span style="color: hsl(0, 100%, 40%);">-            cur_pos = str.find(',', prev_pos)</span><br><span style="color: hsl(0, 100%, 40%);">-            if cur_pos == -1:</span><br><span style="color: hsl(0, 100%, 40%);">-                param_li.append(str[prev_pos:])</span><br><span style="color: hsl(0, 100%, 40%);">-                break</span><br><span style="color: hsl(0, 100%, 40%);">-            if cur_pos == 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                param_li.append('')</span><br><span style="color: hsl(0, 100%, 40%);">-            elif cur_pos != 0 and str[cur_pos - 1] == '\\' and cls.count_cont_char_backward(str, cur_pos, '\\') % 2 == 1:</span><br><span style="color: hsl(0, 100%, 40%);">-                saved += str[prev_pos:cur_pos - 1] + ','</span><br><span style="color: hsl(0, 100%, 40%);">-            else:</span><br><span style="color: hsl(0, 100%, 40%);">-                param_li.append(saved + str[prev_pos:cur_pos])</span><br><span style="color: hsl(0, 100%, 40%);">-                saved = ''</span><br><span style="color: hsl(0, 100%, 40%);">-            cur_pos += 1</span><br><span style="color: hsl(0, 100%, 40%);">-        i = 0</span><br><span style="color: hsl(0, 100%, 40%);">-        # Also escape '\\' -> '\'</span><br><span style="color: hsl(0, 100%, 40%);">-        while i < len(param_li):</span><br><span style="color: hsl(0, 100%, 40%);">-            param_li[i] = param_li[i].replace('\\\\', '\\')</span><br><span style="color: hsl(0, 100%, 40%);">-            i += 1</span><br><span style="color: hsl(0, 100%, 40%);">-        return param_li</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    @classmethod</span><br><span style="color: hsl(0, 100%, 40%);">-    def from_param_list_str(cls, name, path, param_list_str):</span><br><span style="color: hsl(0, 100%, 40%);">-        param_list = cls.split_scenario_parameters(param_list_str)</span><br><span style="color: hsl(0, 100%, 40%);">-        return cls(name, path, param_list)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    def read_from_file(self, validation_schema):</span><br><span style="color: hsl(0, 100%, 40%);">-        with open(self.path, 'r') as f:</span><br><span style="color: hsl(0, 100%, 40%);">-            config_str = f.read()</span><br><span style="color: hsl(0, 100%, 40%);">-        if len(self.param_list) != 0:</span><br><span style="color: hsl(0, 100%, 40%);">-            param_dict = {}</span><br><span style="color: hsl(0, 100%, 40%);">-            i = 1</span><br><span style="color: hsl(0, 100%, 40%);">-            for param in self.param_list:</span><br><span style="color: hsl(0, 100%, 40%);">-                param_dict['param' + str(i)] = param</span><br><span style="color: hsl(0, 100%, 40%);">-                i += 1</span><br><span style="color: hsl(0, 100%, 40%);">-            self.dbg(param_dict=param_dict)</span><br><span style="color: hsl(0, 100%, 40%);">-            config_str = template.render_strbuf_inline(config_str, param_dict)</span><br><span style="color: hsl(0, 100%, 40%);">-        config = yaml.safe_load(config_str)</span><br><span style="color: hsl(0, 100%, 40%);">-        config = _standardize(config)</span><br><span style="color: hsl(0, 100%, 40%);">-        if validation_schema:</span><br><span style="color: hsl(0, 100%, 40%);">-            schema.validate(config, validation_schema)</span><br><span style="color: hsl(0, 100%, 40%);">-        self.update(config)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-def get_scenario(name, validation_schema=None):</span><br><span style="color: hsl(0, 100%, 40%);">-    scenarios_dir = get_scenarios_dir()</span><br><span style="color: hsl(0, 100%, 40%);">-    if not name.endswith('.conf'):</span><br><span style="color: hsl(0, 100%, 40%);">-        name = name + '.conf'</span><br><span style="color: hsl(0, 100%, 40%);">-    is_parametrized_file = '@' in name</span><br><span style="color: hsl(0, 100%, 40%);">-    param_list = []</span><br><span style="color: hsl(0, 100%, 40%);">-    path = scenarios_dir.child(name)</span><br><span style="color: hsl(0, 100%, 40%);">-    if not is_parametrized_file:</span><br><span style="color: hsl(0, 100%, 40%);">-        if not os.path.isfile(path):</span><br><span style="color: hsl(0, 100%, 40%);">-            raise RuntimeError('No such scenario file: %r' % path)</span><br><span style="color: hsl(0, 100%, 40%);">-        sc = Scenario(name, path)</span><br><span style="color: hsl(0, 100%, 40%);">-    else: # parametrized scenario:</span><br><span style="color: hsl(0, 100%, 40%);">-        # Allow first matching complete matching names (eg: scenario@param1,param2.conf),</span><br><span style="color: hsl(0, 100%, 40%);">-        # this allows setting specific content in different files for specific values.</span><br><span style="color: hsl(0, 100%, 40%);">-        if not os.path.isfile(path):</span><br><span style="color: hsl(0, 100%, 40%);">-            # get "scenario@.conf" from "scenario@param1,param2.conf":</span><br><span style="color: hsl(0, 100%, 40%);">-            prefix_name = name[:name.index("@")+1] + '.conf'</span><br><span style="color: hsl(0, 100%, 40%);">-            path = scenarios_dir.child(prefix_name)</span><br><span style="color: hsl(0, 100%, 40%);">-            if not os.path.isfile(path):</span><br><span style="color: hsl(0, 100%, 40%);">-                raise RuntimeError('No such scenario file: %r (nor %s)' % (path, name))</span><br><span style="color: hsl(0, 100%, 40%);">-        # At this point, we have existing file path. Let's now scrap the parameter(s):</span><br><span style="color: hsl(0, 100%, 40%);">-        # get param1,param2 str from scenario@param1,param2.conf</span><br><span style="color: hsl(0, 100%, 40%);">-        param_list_str = name.split('@', 1)[1][:-len('.conf')]</span><br><span style="color: hsl(0, 100%, 40%);">-        sc = Scenario.from_param_list_str(name, path, param_list_str)</span><br><span style="color: hsl(0, 100%, 40%);">-    sc.read_from_file(validation_schema)</span><br><span style="color: hsl(0, 100%, 40%);">-    return sc</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> def overlay(dest, src):</span><br><span>     if is_dict(dest):</span><br><span>         if not is_dict(src):</span><br><span>diff --git a/src/osmo_gsm_tester/core/scenario.py b/src/osmo_gsm_tester/core/scenario.py</span><br><span>new file mode 100644</span><br><span>index 0000000..efa045b</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo_gsm_tester/core/scenario.py</span><br><span>@@ -0,0 +1,117 @@</span><br><span style="color: hsl(120, 100%, 40%);">+# osmo_gsm_tester: Suite scenario</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Copyright (C) 2016-2020 by sysmocom - s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Neels Hofmeyr <neels@hofmeyr.de></span><br><span style="color: hsl(120, 100%, 40%);">+# Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is free software: you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+# it under the terms of the GNU General Public License as</span><br><span style="color: hsl(120, 100%, 40%);">+# published by the Free Software Foundation, either version 3 of the</span><br><span style="color: hsl(120, 100%, 40%);">+# License, or (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+# but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+# GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+#</span><br><span style="color: hsl(120, 100%, 40%);">+# You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+# along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import os</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from . import log</span><br><span style="color: hsl(120, 100%, 40%);">+from . import template</span><br><span style="color: hsl(120, 100%, 40%);">+from . import config</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class Scenario(log.Origin, dict):</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, name, path, param_list=[]):</span><br><span style="color: hsl(120, 100%, 40%);">+        super().__init__(log.C_TST, name)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.path = path</span><br><span style="color: hsl(120, 100%, 40%);">+        self.param_list = param_list</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    @classmethod</span><br><span style="color: hsl(120, 100%, 40%);">+    def count_cont_char_backward(cls, str, before_pos, c):</span><br><span style="color: hsl(120, 100%, 40%);">+        n = 0</span><br><span style="color: hsl(120, 100%, 40%);">+        i = before_pos - 1</span><br><span style="color: hsl(120, 100%, 40%);">+        while i >= 0:</span><br><span style="color: hsl(120, 100%, 40%);">+            if str[i] != c:</span><br><span style="color: hsl(120, 100%, 40%);">+                break</span><br><span style="color: hsl(120, 100%, 40%);">+            n += 1</span><br><span style="color: hsl(120, 100%, 40%);">+            i -= 1</span><br><span style="color: hsl(120, 100%, 40%);">+        return n</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    @classmethod</span><br><span style="color: hsl(120, 100%, 40%);">+    def split_scenario_parameters(cls, str):</span><br><span style="color: hsl(120, 100%, 40%);">+        cur_pos = 0</span><br><span style="color: hsl(120, 100%, 40%);">+        param_li = []</span><br><span style="color: hsl(120, 100%, 40%);">+        saved = ''</span><br><span style="color: hsl(120, 100%, 40%);">+        # Split into a list, but we want to escape '\,' to avoid splitting parameters containing commas.</span><br><span style="color: hsl(120, 100%, 40%);">+        while True:</span><br><span style="color: hsl(120, 100%, 40%);">+            prev_pos = cur_pos</span><br><span style="color: hsl(120, 100%, 40%);">+            cur_pos = str.find(',', prev_pos)</span><br><span style="color: hsl(120, 100%, 40%);">+            if cur_pos == -1:</span><br><span style="color: hsl(120, 100%, 40%);">+                param_li.append(str[prev_pos:])</span><br><span style="color: hsl(120, 100%, 40%);">+                break</span><br><span style="color: hsl(120, 100%, 40%);">+            if cur_pos == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                param_li.append('')</span><br><span style="color: hsl(120, 100%, 40%);">+            elif cur_pos != 0 and str[cur_pos - 1] == '\\' and cls.count_cont_char_backward(str, cur_pos, '\\') % 2 == 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                saved += str[prev_pos:cur_pos - 1] + ','</span><br><span style="color: hsl(120, 100%, 40%);">+            else:</span><br><span style="color: hsl(120, 100%, 40%);">+                param_li.append(saved + str[prev_pos:cur_pos])</span><br><span style="color: hsl(120, 100%, 40%);">+                saved = ''</span><br><span style="color: hsl(120, 100%, 40%);">+            cur_pos += 1</span><br><span style="color: hsl(120, 100%, 40%);">+        i = 0</span><br><span style="color: hsl(120, 100%, 40%);">+        # Also escape '\\' -> '\'</span><br><span style="color: hsl(120, 100%, 40%);">+        while i < len(param_li):</span><br><span style="color: hsl(120, 100%, 40%);">+            param_li[i] = param_li[i].replace('\\\\', '\\')</span><br><span style="color: hsl(120, 100%, 40%);">+            i += 1</span><br><span style="color: hsl(120, 100%, 40%);">+        return param_li</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    @classmethod</span><br><span style="color: hsl(120, 100%, 40%);">+    def from_param_list_str(cls, name, path, param_list_str):</span><br><span style="color: hsl(120, 100%, 40%);">+        param_list = cls.split_scenario_parameters(param_list_str)</span><br><span style="color: hsl(120, 100%, 40%);">+        return cls(name, path, param_list)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def read_from_file(self, validation_schema):</span><br><span style="color: hsl(120, 100%, 40%);">+        with open(self.path, 'r') as f:</span><br><span style="color: hsl(120, 100%, 40%);">+            config_str = f.read()</span><br><span style="color: hsl(120, 100%, 40%);">+        if len(self.param_list) != 0:</span><br><span style="color: hsl(120, 100%, 40%);">+            param_dict = {}</span><br><span style="color: hsl(120, 100%, 40%);">+            i = 1</span><br><span style="color: hsl(120, 100%, 40%);">+            for param in self.param_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                param_dict['param' + str(i)] = param</span><br><span style="color: hsl(120, 100%, 40%);">+                i += 1</span><br><span style="color: hsl(120, 100%, 40%);">+            self.dbg(param_dict=param_dict)</span><br><span style="color: hsl(120, 100%, 40%);">+            config_str = template.render_strbuf_inline(config_str, param_dict)</span><br><span style="color: hsl(120, 100%, 40%);">+        conf = config.fromstr(config_str, validation_schema)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.update(conf)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def get_scenario(name, validation_schema=None):</span><br><span style="color: hsl(120, 100%, 40%);">+    scenarios_dir = config.get_scenarios_dir()</span><br><span style="color: hsl(120, 100%, 40%);">+    if not name.endswith('.conf'):</span><br><span style="color: hsl(120, 100%, 40%);">+        name = name + '.conf'</span><br><span style="color: hsl(120, 100%, 40%);">+    is_parametrized_file = '@' in name</span><br><span style="color: hsl(120, 100%, 40%);">+    param_list = []</span><br><span style="color: hsl(120, 100%, 40%);">+    path = scenarios_dir.child(name)</span><br><span style="color: hsl(120, 100%, 40%);">+    if not is_parametrized_file:</span><br><span style="color: hsl(120, 100%, 40%);">+        if not os.path.isfile(path):</span><br><span style="color: hsl(120, 100%, 40%);">+            raise RuntimeError('No such scenario file: %r' % path)</span><br><span style="color: hsl(120, 100%, 40%);">+        sc = Scenario(name, path)</span><br><span style="color: hsl(120, 100%, 40%);">+    else: # parametrized scenario:</span><br><span style="color: hsl(120, 100%, 40%);">+        # Allow first matching complete matching names (eg: scenario@param1,param2.conf),</span><br><span style="color: hsl(120, 100%, 40%);">+        # this allows setting specific content in different files for specific values.</span><br><span style="color: hsl(120, 100%, 40%);">+        if not os.path.isfile(path):</span><br><span style="color: hsl(120, 100%, 40%);">+            # get "scenario@.conf" from "scenario@param1,param2.conf":</span><br><span style="color: hsl(120, 100%, 40%);">+            prefix_name = name[:name.index("@")+1] + '.conf'</span><br><span style="color: hsl(120, 100%, 40%);">+            path = scenarios_dir.child(prefix_name)</span><br><span style="color: hsl(120, 100%, 40%);">+            if not os.path.isfile(path):</span><br><span style="color: hsl(120, 100%, 40%);">+                raise RuntimeError('No such scenario file: %r (nor %s)' % (path, name))</span><br><span style="color: hsl(120, 100%, 40%);">+        # At this point, we have existing file path. Let's now scrap the parameter(s):</span><br><span style="color: hsl(120, 100%, 40%);">+        # get param1,param2 str from scenario@param1,param2.conf</span><br><span style="color: hsl(120, 100%, 40%);">+        param_list_str = name.split('@', 1)[1][:-len('.conf')]</span><br><span style="color: hsl(120, 100%, 40%);">+        sc = Scenario.from_param_list_str(name, path, param_list_str)</span><br><span style="color: hsl(120, 100%, 40%);">+    sc.read_from_file(validation_schema)</span><br><span style="color: hsl(120, 100%, 40%);">+    return sc</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/src/osmo_gsm_tester/core/suite.py b/src/osmo_gsm_tester/core/suite.py</span><br><span>index 81aab3e..a6eaca2 100644</span><br><span>--- a/src/osmo_gsm_tester/core/suite.py</span><br><span>+++ b/src/osmo_gsm_tester/core/suite.py</span><br><span>@@ -26,6 +26,7 @@</span><br><span> from . import util</span><br><span> from . import schema</span><br><span> from . import resource</span><br><span style="color: hsl(120, 100%, 40%);">+from . import scenario</span><br><span> from . import test</span><br><span> </span><br><span> class SuiteDefinition(log.Origin):</span><br><span>@@ -111,12 +112,12 @@</span><br><span>         if replicate_times:</span><br><span>             combination = config.replicate_times(combination)</span><br><span>         log.dbg(definition_conf=combination)</span><br><span style="color: hsl(0, 100%, 40%);">-        for scenario in self.scenarios:</span><br><span style="color: hsl(0, 100%, 40%);">-            log.ctx(combining_scenarios=conf_name, scenario=scenario.name())</span><br><span style="color: hsl(0, 100%, 40%);">-            c = scenario.get(conf_name, {})</span><br><span style="color: hsl(120, 100%, 40%);">+        for sc in self.scenarios:</span><br><span style="color: hsl(120, 100%, 40%);">+            log.ctx(combining_scenarios=conf_name, scenario=sc.name())</span><br><span style="color: hsl(120, 100%, 40%);">+            c = sc.get(conf_name, {})</span><br><span>             if replicate_times:</span><br><span>                 c = config.replicate_times(c)</span><br><span style="color: hsl(0, 100%, 40%);">-            log.dbg(scenario=scenario.name(), conf=c)</span><br><span style="color: hsl(120, 100%, 40%);">+            log.dbg(scenario=sc.name(), conf=c)</span><br><span>             if c is None:</span><br><span>                 continue</span><br><span>             schema.combine(combination, c)</span><br><span>@@ -258,7 +259,7 @@</span><br><span> def load_suite_scenario_str(suite_scenario_str):</span><br><span>     suite_name, scenario_names = parse_suite_scenario_str(suite_scenario_str)</span><br><span>     suite = load(suite_name)</span><br><span style="color: hsl(0, 100%, 40%);">-    scenarios = [config.get_scenario(scenario_name, schema.get_all_schema()) for scenario_name in scenario_names]</span><br><span style="color: hsl(120, 100%, 40%);">+    scenarios = [scenario.get_scenario(scenario_name, schema.get_all_schema()) for scenario_name in scenario_names]</span><br><span>     return (suite_scenario_str, suite, scenarios)</span><br><span> </span><br><span> # vim: expandtab tabstop=4 shiftwidth=4</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/18200">change 18200</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/18200"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-gsm-tester </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ia029de7ecda4c8dc3d0b4c412e4c9c0a65cf0185 </div>
<div style="display:none"> Gerrit-Change-Number: 18200 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>