<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/18799">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Implement per-test timeout guard<br><br>Timeout value can be specified by test in suite.conf:<br><br>config:<br>  suite:<br>    <suite_name>:<br>      <test_name>:<br>        timeout: 2 # 2 seconds timeout<br><br>Change-Id: I522f51f77f8be64ebfdb5d5e07ba92baf82d7706<br>---<br>M selftest/suite_test/suite_test.py<br>M selftest/suite_test/suitedirA/test_suite/suite.conf<br>A selftest/suite_test/suitedirA/test_suite/test_timeout.py<br>M src/osmo_gsm_tester/core/suite.py<br>M src/osmo_gsm_tester/core/test.py<br>M src/osmo_gsm_tester/testenv.py<br>6 files changed, 30 insertions(+), 5 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/99/18799/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 260b9c4..9708037 100755</span><br><span>--- a/selftest/suite_test/suite_test.py</span><br><span>+++ b/selftest/suite_test/suite_test.py</span><br><span>@@ -102,7 +102,7 @@</span><br><span> 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 style="color: hsl(0, 100%, 40%);">-results = s.run_tests('test_suite_params.py')</span><br><span style="color: hsl(120, 100%, 40%);">+results = s.run_tests(['test_suite_params.py', 'test_timeout.py'])</span><br><span> print(report.suite_to_text(s))</span><br><span> </span><br><span> print('- test with template overlay')</span><br><span>diff --git a/selftest/suite_test/suitedirA/test_suite/suite.conf b/selftest/suite_test/suitedirA/test_suite/suite.conf</span><br><span>index ff4899a..0426ea7 100644</span><br><span>--- a/selftest/suite_test/suitedirA/test_suite/suite.conf</span><br><span>+++ b/selftest/suite_test/suitedirA/test_suite/suite.conf</span><br><span>@@ -15,3 +15,9 @@</span><br><span>       one_bool_parameter: 'bool_str'</span><br><span>       second_list_parameter: ['uint']</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+config:</span><br><span style="color: hsl(120, 100%, 40%);">+  suite:</span><br><span style="color: hsl(120, 100%, 40%);">+    test_suite:</span><br><span style="color: hsl(120, 100%, 40%);">+      test_timeout:</span><br><span style="color: hsl(120, 100%, 40%);">+        timeout: 1 # timeout in 1 second</span><br><span>diff --git a/selftest/suite_test/suitedirA/test_suite/test_timeout.py b/selftest/suite_test/suitedirA/test_suite/test_timeout.py</span><br><span>new file mode 100644</span><br><span>index 0000000..eeddb70</span><br><span>--- /dev/null</span><br><span>+++ b/selftest/suite_test/suitedirA/test_suite/test_timeout.py</span><br><span>@@ -0,0 +1,6 @@</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.testenv import *</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+timeout = int(tenv.config_test_specific()['timeout'])</span><br><span style="color: hsl(120, 100%, 40%);">+print('starting test and waiting to receive Timeout after %d seconds' % timeout)</span><br><span style="color: hsl(120, 100%, 40%);">+sleep(10)</span><br><span style="color: hsl(120, 100%, 40%);">+print('test failed, we expected timeout after %d seconds' % timeout)</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 9b9062d..aa09cd6 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>@@ -44,6 +44,8 @@</span><br><span>         self.suite_dir = suite_dir</span><br><span>         self.conf = None</span><br><span>         self._schema = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.test_basenames = []</span><br><span style="color: hsl(120, 100%, 40%);">+        self.load_test_basenames()</span><br><span>         self.read_conf()</span><br><span> </span><br><span>     def read_conf(self):</span><br><span>@@ -54,13 +56,17 @@</span><br><span>                                              SuiteDefinition.CONF_FILENAME))</span><br><span>         # Drop schema part since it's dynamically defining content, makes no sense to validate it.</span><br><span>         self._schema = self.conf.pop('schema', {})</span><br><span style="color: hsl(120, 100%, 40%);">+        # Add per-test 'timeout' attribute:</span><br><span style="color: hsl(120, 100%, 40%);">+        d = {t.rstrip('.py'):{'timeout': schema.DURATION} for t in self.test_basenames}</span><br><span style="color: hsl(120, 100%, 40%);">+        #self.log('dictionary is: %r' % repr(d))</span><br><span style="color: hsl(120, 100%, 40%);">+        schema.combine(self._schema, d)</span><br><span style="color: hsl(120, 100%, 40%);">+        # Convert config file format to proper schema format and register it:</span><br><span>         sdef = schema.config_to_schema_def(self._schema, "%s." % self._suite_name)</span><br><span>         schema.register_config_schema('suite', sdef)</span><br><span style="color: hsl(120, 100%, 40%);">+        # Finally validate the file:</span><br><span>         schema.validate(self.conf, schema.get_all_schema())</span><br><span style="color: hsl(0, 100%, 40%);">-        self.load_test_basenames()</span><br><span> </span><br><span>     def load_test_basenames(self):</span><br><span style="color: hsl(0, 100%, 40%);">-        self.test_basenames = []</span><br><span>         for basename in sorted(os.listdir(self.suite_dir)):</span><br><span>             if not basename.endswith('.py'):</span><br><span>                 continue</span><br><span>diff --git a/src/osmo_gsm_tester/core/test.py b/src/osmo_gsm_tester/core/test.py</span><br><span>index 45dfd41..2fa4fe9 100644</span><br><span>--- a/src/osmo_gsm_tester/core/test.py</span><br><span>+++ b/src/osmo_gsm_tester/core/test.py</span><br><span>@@ -35,12 +35,12 @@</span><br><span>     PASS = 'pass'</span><br><span>     FAIL = 'FAIL'</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def __init__(self, suite_run, test_basename, test_specific_config):</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, suite_run, test_basename, config_test_specific):</span><br><span>         self.basename = test_basename</span><br><span>         super().__init__(log.C_TST, self.basename)</span><br><span>         self._run_dir = None</span><br><span>         self.suite_run = suite_run</span><br><span style="color: hsl(0, 100%, 40%);">-        self._config_test_specific = test_specific_config</span><br><span style="color: hsl(120, 100%, 40%);">+        self._config_test_specific = config_test_specific</span><br><span>         self.path = os.path.join(self.suite_run.definition.suite_dir, self.basename)</span><br><span>         self.status = Test.UNKNOWN</span><br><span>         self.start_timestamp = 0</span><br><span>@@ -49,6 +49,7 @@</span><br><span>         self.fail_message = None</span><br><span>         self.log_targets = []</span><br><span>         self._report_stdout = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self.timeout = int(config_test_specific['timeout']) if 'timeout' in config_test_specific else None</span><br><span> </span><br><span>     def module_name(self):</span><br><span>         'Return test name without trailing .py'</span><br><span>@@ -110,6 +111,10 @@</span><br><span>         'time elapsed since test was started'</span><br><span>         return time.time() - self.start_timestamp</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    def verify_timeout(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.timeout is not None and self.elapsed_time() > self.timeout:</span><br><span style="color: hsl(120, 100%, 40%);">+            raise log.Error('Test Timeout triggered: %d seconds elapsed' % self.timeout)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def set_fail(self, fail_type, fail_message, tb_str=None, src=4):</span><br><span>         self.status = Test.FAIL</span><br><span>         self.duration = self.elapsed_time()</span><br><span>diff --git a/src/osmo_gsm_tester/testenv.py b/src/osmo_gsm_tester/testenv.py</span><br><span>index 11199c2..e2e8ce9 100644</span><br><span>--- a/src/osmo_gsm_tester/testenv.py</span><br><span>+++ b/src/osmo_gsm_tester/testenv.py</span><br><span>@@ -130,6 +130,8 @@</span><br><span>                     proc.log_stderr_tail()</span><br><span>                     log_module.ctx(proc)</span><br><span>                     raise log_module.Error('Process ended prematurely: %s' % proc.name())</span><br><span style="color: hsl(120, 100%, 40%);">+        # TODO: do it better, use a GLib timer and make sure to remove in testenv.stop()</span><br><span style="color: hsl(120, 100%, 40%);">+        self._test.verify_timeout()</span><br><span> </span><br><span>     def stop(self):</span><br><span>         # if sys.exit() called from signal handler (e.g. SIGINT), SystemExit</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/18799">change 18799</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/+/18799"/><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: I522f51f77f8be64ebfdb5d5e07ba92baf82d7706 </div>
<div style="display:none"> Gerrit-Change-Number: 18799 </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>