<p>pespin <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/18042">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Jenkins Builder: Verified
pespin: Looks good to me, approved
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Move all obj/ references in suite.py to testenv.py<br><br>Change-Id: If4ab39be7a97d33e82c5a34e2a10dfec38613a4e<br>---<br>M selftest/suite_test/test_suite/hello_world.py<br>M selftest/suite_test/test_suite/test_error.py<br>M selftest/suite_test/test_suite/test_fail.py<br>M src/osmo_gsm_tester/core/test.py<br>M src/osmo_gsm_tester/suite.py<br>M src/osmo_gsm_tester/testenv.py<br>M src/osmo_gsm_tester/trial.py<br>7 files changed, 315 insertions(+), 271 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/selftest/suite_test/test_suite/hello_world.py b/selftest/suite_test/test_suite/hello_world.py</span><br><span>index 073d07f..a69f95a 100644</span><br><span>--- a/selftest/suite_test/test_suite/hello_world.py</span><br><span>+++ b/selftest/suite_test/test_suite/hello_world.py</span><br><span>@@ -1,5 +1,5 @@</span><br><span> from osmo_gsm_tester.testenv import *</span><br><span> </span><br><span> print('hello world')</span><br><span style="color: hsl(0, 100%, 40%);">-print('I am %r / %r' % (suite.name(), test.name()))</span><br><span style="color: hsl(120, 100%, 40%);">+print('I am %r / %r' % (suite.suite().name(), test.name()))</span><br><span> print('one\ntwo\nthree')</span><br><span>diff --git a/selftest/suite_test/test_suite/test_error.py b/selftest/suite_test/test_suite/test_error.py</span><br><span>index c0583ff..70d14a1 100755</span><br><span>--- a/selftest/suite_test/test_suite/test_error.py</span><br><span>+++ b/selftest/suite_test/test_suite/test_error.py</span><br><span>@@ -1,5 +1,5 @@</span><br><span> from osmo_gsm_tester.testenv import *</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-print('I am %r / %r' % (suite.name(), test.name()))</span><br><span style="color: hsl(120, 100%, 40%);">+print('I am %r / %r' % (suite.suite().name(), test.name()))</span><br><span> </span><br><span> assert False</span><br><span>diff --git a/selftest/suite_test/test_suite/test_fail.py b/selftest/suite_test/test_suite/test_fail.py</span><br><span>index cbaeded..ffb7218 100755</span><br><span>--- a/selftest/suite_test/test_suite/test_fail.py</span><br><span>+++ b/selftest/suite_test/test_suite/test_fail.py</span><br><span>@@ -1,6 +1,6 @@</span><br><span> #!/usr/bin/env python3</span><br><span> from osmo_gsm_tester.testenv import *</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-print('I am %r / %r' % (suite.name(), test.name()))</span><br><span style="color: hsl(120, 100%, 40%);">+print('I am %r / %r' % (suite.suite().name(), test.name()))</span><br><span> </span><br><span> test.set_fail('EpicFail', 'This failure is expected')</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 93dbf6a..76c9ce9 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>@@ -21,9 +21,13 @@</span><br><span> import sys</span><br><span> import time</span><br><span> import traceback</span><br><span style="color: hsl(0, 100%, 40%);">-from .. import testenv</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-from . import log, util, resource</span><br><span style="color: hsl(120, 100%, 40%);">+from . import log</span><br><span style="color: hsl(120, 100%, 40%);">+from . import util</span><br><span style="color: hsl(120, 100%, 40%);">+from . import resource</span><br><span style="color: hsl(120, 100%, 40%);">+from .event_loop import MainLoop</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from .. import testenv</span><br><span> </span><br><span> class Test(log.Origin):</span><br><span> UNKNOWN = 'UNKNOWN' # matches junit 'error'</span><br><span>@@ -51,12 +55,13 @@</span><br><span> return self._run_dir</span><br><span> </span><br><span> def run(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ testenv_obj = None</span><br><span> try:</span><br><span> self.log_target = log.FileLogTarget(self.get_run_dir().new_child('log')).set_all_levels(log.L_DBG).style_change(trace=True)</span><br><span> log.large_separator(self.suite_run.trial.name(), self.suite_run.name(), self.name(), sublevel=3)</span><br><span> self.status = Test.UNKNOWN</span><br><span> self.start_timestamp = time.time()</span><br><span style="color: hsl(0, 100%, 40%);">- testenv.setup(self.suite_run, self)</span><br><span style="color: hsl(120, 100%, 40%);">+ testenv_obj = testenv.setup(self.suite_run, self)</span><br><span> with self.redirect_stdout():</span><br><span> util.run_python_file('%s.%s' % (self.suite_run.definition.name(), self.basename),</span><br><span> self.path)</span><br><span>@@ -83,6 +88,8 @@</span><br><span> self.err('TEST RUN ABORTED: %s' % type(e).__name__)</span><br><span> raise</span><br><span> finally:</span><br><span style="color: hsl(120, 100%, 40%);">+ if testenv_obj:</span><br><span style="color: hsl(120, 100%, 40%);">+ testenv_obj.stop()</span><br><span> if self.log_target:</span><br><span> self.log_target.remove()</span><br><span> </span><br><span>diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py</span><br><span>index 6952fd2..3416ff5 100644</span><br><span>--- a/src/osmo_gsm_tester/suite.py</span><br><span>+++ b/src/osmo_gsm_tester/suite.py</span><br><span>@@ -21,18 +21,12 @@</span><br><span> import sys</span><br><span> import time</span><br><span> import pprint</span><br><span style="color: hsl(0, 100%, 40%);">-from .core import config, log, util, process, schema, resource</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import config</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import log</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import util</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import schema</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import resource</span><br><span> from .core import test</span><br><span style="color: hsl(0, 100%, 40%);">-from .core.event_loop import MainLoop</span><br><span style="color: hsl(0, 100%, 40%);">-from .obj import nitb_osmo, hlr_osmo, mgcpgw_osmo, mgw_osmo, msc_osmo, bsc_osmo, stp_osmo, ggsn_osmo, sgsn_osmo, esme, osmocon, ms_driver, iperf3</span><br><span style="color: hsl(0, 100%, 40%);">-from .obj import run_node</span><br><span style="color: hsl(0, 100%, 40%);">-from .obj import epc</span><br><span style="color: hsl(0, 100%, 40%);">-from .obj import enb</span><br><span style="color: hsl(0, 100%, 40%);">-from .obj import bts</span><br><span style="color: hsl(0, 100%, 40%);">-from .obj import ms</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-class Timeout(Exception):</span><br><span style="color: hsl(0, 100%, 40%);">- pass</span><br><span> </span><br><span> class SuiteDefinition(log.Origin):</span><br><span> '''A test suite reserves resources for a number of tests.</span><br><span>@@ -74,12 +68,9 @@</span><br><span> self.start_timestamp = None</span><br><span> self.duration = None</span><br><span> self.reserved_resources = None</span><br><span style="color: hsl(0, 100%, 40%);">- self.objects_to_clean_up = None</span><br><span style="color: hsl(0, 100%, 40%);">- self.test_import_modules_to_clean_up = []</span><br><span> self._resource_requirements = None</span><br><span> self._resource_modifiers = None</span><br><span> self._config = None</span><br><span style="color: hsl(0, 100%, 40%);">- self._processes = []</span><br><span> self._run_dir = None</span><br><span> self.trial = trial</span><br><span> self.definition = suite_definition</span><br><span>@@ -93,40 +84,6 @@</span><br><span> for test_basename in self.definition.test_basenames:</span><br><span> self.tests.append(test.Test(self, test_basename))</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- def register_for_cleanup(self, *obj):</span><br><span style="color: hsl(0, 100%, 40%);">- assert all([hasattr(o, 'cleanup') for o in obj])</span><br><span style="color: hsl(0, 100%, 40%);">- self.objects_to_clean_up = self.objects_to_clean_up or []</span><br><span style="color: hsl(0, 100%, 40%);">- self.objects_to_clean_up.extend(obj)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def objects_cleanup(self):</span><br><span style="color: hsl(0, 100%, 40%);">- while self.objects_to_clean_up:</span><br><span style="color: hsl(0, 100%, 40%);">- obj = self.objects_to_clean_up.pop()</span><br><span style="color: hsl(0, 100%, 40%);">- try:</span><br><span style="color: hsl(0, 100%, 40%);">- obj.cleanup()</span><br><span style="color: hsl(0, 100%, 40%);">- except Exception:</span><br><span style="color: hsl(0, 100%, 40%);">- log.log_exn()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def test_import_modules_register_for_cleanup(self, mod):</span><br><span style="color: hsl(0, 100%, 40%);">- '''</span><br><span style="color: hsl(0, 100%, 40%);">- Tests are required to call this API for any module loaded from its own</span><br><span style="color: hsl(0, 100%, 40%);">- lib subdir, because they are loaded in the global namespace. Otherwise</span><br><span style="color: hsl(0, 100%, 40%);">- later tests importing modules with the same name will re-use an already</span><br><span style="color: hsl(0, 100%, 40%);">- loaded module.</span><br><span style="color: hsl(0, 100%, 40%);">- '''</span><br><span style="color: hsl(0, 100%, 40%);">- if mod not in self.test_import_modules_to_clean_up:</span><br><span style="color: hsl(0, 100%, 40%);">- self.dbg('registering module %r for cleanup' % mod)</span><br><span style="color: hsl(0, 100%, 40%);">- self.test_import_modules_to_clean_up.append(mod)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def test_import_modules_cleanup(self):</span><br><span style="color: hsl(0, 100%, 40%);">- while self.test_import_modules_to_clean_up:</span><br><span style="color: hsl(0, 100%, 40%);">- mod = self.test_import_modules_to_clean_up.pop()</span><br><span style="color: hsl(0, 100%, 40%);">- try:</span><br><span style="color: hsl(0, 100%, 40%);">- self.dbg('Cleaning up module %r' % mod)</span><br><span style="color: hsl(0, 100%, 40%);">- del sys.modules[mod.__name__]</span><br><span style="color: hsl(0, 100%, 40%);">- del mod</span><br><span style="color: hsl(0, 100%, 40%);">- except Exception:</span><br><span style="color: hsl(0, 100%, 40%);">- log.log_exn()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> def mark_start(self):</span><br><span> self.start_timestamp = time.time()</span><br><span> self.duration = 0</span><br><span>@@ -155,11 +112,6 @@</span><br><span> self._run_dir = util.Dir(self.trial.get_run_dir().new_dir(self.name()))</span><br><span> return self._run_dir</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- def get_test_run_dir(self):</span><br><span style="color: hsl(0, 100%, 40%);">- if self.current_test:</span><br><span style="color: hsl(0, 100%, 40%);">- return self.current_test.get_run_dir()</span><br><span style="color: hsl(0, 100%, 40%);">- return self.get_run_dir()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> def resource_requirements(self):</span><br><span> if self._resource_requirements is None:</span><br><span> self._resource_requirements = self.combined('resources')</span><br><span>@@ -175,19 +127,24 @@</span><br><span> self._config = self.combined('config', False)</span><br><span> return self._config</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ def resource_pool(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.resources_pool</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def reserve_resources(self):</span><br><span> if self.reserved_resources:</span><br><span> raise RuntimeError('Attempt to reserve resources twice for a SuiteRun')</span><br><span> self.log('reserving resources in', self.resources_pool.state_dir, '...')</span><br><span> self.reserved_resources = self.resources_pool.reserve(self, self.resource_requirements(), self.resource_modifiers())</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ def get_reserved_resource(self, resource_class_str, specifics):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.reserved_resources.get(resource_class_str, specifics=specifics)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def run_tests(self, names=None):</span><br><span> suite_libdir = os.path.join(self.definition.suite_dir, 'lib')</span><br><span> try:</span><br><span> log.large_separator(self.trial.name(), self.name(), sublevel=2)</span><br><span> self.mark_start()</span><br><span> util.import_path_prepend(suite_libdir)</span><br><span style="color: hsl(0, 100%, 40%);">- MainLoop.register_poll_func(self.poll)</span><br><span> if not self.reserved_resources:</span><br><span> self.reserve_resources()</span><br><span> for t in self.tests:</span><br><span>@@ -196,9 +153,6 @@</span><br><span> continue</span><br><span> self.current_test = t</span><br><span> t.run()</span><br><span style="color: hsl(0, 100%, 40%);">- self.stop_processes()</span><br><span style="color: hsl(0, 100%, 40%);">- self.objects_cleanup()</span><br><span style="color: hsl(0, 100%, 40%);">- self.reserved_resources.put_all()</span><br><span> except Exception:</span><br><span> log.log_exn()</span><br><span> except BaseException as e:</span><br><span>@@ -206,14 +160,7 @@</span><br><span> self.err('SUITE RUN ABORTED: %s' % type(e).__name__)</span><br><span> raise</span><br><span> finally:</span><br><span style="color: hsl(0, 100%, 40%);">- # if sys.exit() called from signal handler (e.g. SIGINT), SystemExit</span><br><span style="color: hsl(0, 100%, 40%);">- # base exception is raised. Make sure to stop processes in this</span><br><span style="color: hsl(0, 100%, 40%);">- # finally section. Resources are automatically freed with 'atexit'.</span><br><span style="color: hsl(0, 100%, 40%);">- self.stop_processes()</span><br><span style="color: hsl(0, 100%, 40%);">- self.objects_cleanup()</span><br><span> self.free_resources()</span><br><span style="color: hsl(0, 100%, 40%);">- MainLoop.unregister_poll_func(self.poll)</span><br><span style="color: hsl(0, 100%, 40%);">- self.test_import_modules_cleanup()</span><br><span> util.import_path_remove(suite_libdir)</span><br><span> self.duration = time.time() - self.start_timestamp</span><br><span> </span><br><span>@@ -245,203 +192,11 @@</span><br><span> errors += 1</span><br><span> return (passed, skipped, failed, errors)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- def remember_to_stop(self, process, respawn=False):</span><br><span style="color: hsl(0, 100%, 40%);">- '''Ask suite to monitor and manage lifecycle of the Process object. If a</span><br><span style="color: hsl(0, 100%, 40%);">- process managed by suite finishes before cleanup time, the current test</span><br><span style="color: hsl(0, 100%, 40%);">- will be marked as FAIL and end immediatelly. If respwan=True, then suite</span><br><span style="color: hsl(0, 100%, 40%);">- will respawn() the process instead.'''</span><br><span style="color: hsl(0, 100%, 40%);">- self._processes.insert(0, (process, respawn))</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def stop_processes(self):</span><br><span style="color: hsl(0, 100%, 40%);">- if len(self._processes) == 0:</span><br><span style="color: hsl(0, 100%, 40%);">- return</span><br><span style="color: hsl(0, 100%, 40%);">- strategy = process.ParallelTerminationStrategy()</span><br><span style="color: hsl(0, 100%, 40%);">- while self._processes:</span><br><span style="color: hsl(0, 100%, 40%);">- proc, _ = self._processes.pop()</span><br><span style="color: hsl(0, 100%, 40%);">- strategy.add_process(proc)</span><br><span style="color: hsl(0, 100%, 40%);">- strategy.terminate_all()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def stop_process(self, process):</span><br><span style="color: hsl(0, 100%, 40%);">- 'Remove process from monitored list and stop it'</span><br><span style="color: hsl(0, 100%, 40%);">- for proc_respawn in self._processes:</span><br><span style="color: hsl(0, 100%, 40%);">- proc, respawn = proc_respawn</span><br><span style="color: hsl(0, 100%, 40%);">- if proc == process:</span><br><span style="color: hsl(0, 100%, 40%);">- self._processes.remove(proc_respawn)</span><br><span style="color: hsl(0, 100%, 40%);">- proc.terminate()</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> def free_resources(self):</span><br><span> if self.reserved_resources is None:</span><br><span> return</span><br><span> self.reserved_resources.free()</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- def ip_address(self, specifics=None):</span><br><span style="color: hsl(0, 100%, 40%);">- return self.reserved_resources.get(resource.R_IP_ADDRESS, specifics=specifics)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def nitb(self, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return nitb_osmo.OsmoNitb(self, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def hlr(self, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return hlr_osmo.OsmoHlr(self, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def ggsn(self, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return ggsn_osmo.OsmoGgsn(self, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def sgsn(self, hlr, ggsn, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return sgsn_osmo.OsmoSgsn(self, hlr, ggsn, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def mgcpgw(self, ip_address=None, bts_ip=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return mgcpgw_osmo.OsmoMgcpgw(self, ip_address, bts_ip)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def mgw(self, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return mgw_osmo.OsmoMgw(self, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def msc(self, hlr, mgcpgw, stp, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return msc_osmo.OsmoMsc(self, hlr, mgcpgw, stp, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def bsc(self, msc, mgw, stp, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return bsc_osmo.OsmoBsc(self, msc, mgw, stp, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def stp(self, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- return stp_osmo.OsmoStp(self, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def ms_driver(self):</span><br><span style="color: hsl(0, 100%, 40%);">- ms = ms_driver.MsDriver(self)</span><br><span style="color: hsl(0, 100%, 40%);">- self.register_for_cleanup(ms)</span><br><span style="color: hsl(0, 100%, 40%);">- return ms</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def bts(self, specifics=None):</span><br><span style="color: hsl(0, 100%, 40%);">- bts_obj = bts.Bts.get_instance_by_type(self, self.reserved_resources.get(resource.R_BTS, specifics=specifics))</span><br><span style="color: hsl(0, 100%, 40%);">- bts_obj.set_lac(self.lac())</span><br><span style="color: hsl(0, 100%, 40%);">- bts_obj.set_rac(self.rac())</span><br><span style="color: hsl(0, 100%, 40%);">- bts_obj.set_cellid(self.cellid())</span><br><span style="color: hsl(0, 100%, 40%);">- bts_obj.set_bvci(self.bvci())</span><br><span style="color: hsl(0, 100%, 40%);">- self.register_for_cleanup(bts_obj)</span><br><span style="color: hsl(0, 100%, 40%);">- return bts_obj</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def modem(self, specifics=None):</span><br><span style="color: hsl(0, 100%, 40%);">- conf = self.reserved_resources.get(resource.R_MODEM, specifics=specifics)</span><br><span style="color: hsl(0, 100%, 40%);">- ms_obj = ms.MS.get_instance_by_type(self, conf)</span><br><span style="color: hsl(0, 100%, 40%);">- self.register_for_cleanup(ms_obj)</span><br><span style="color: hsl(0, 100%, 40%);">- return ms_obj</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def modems(self, count):</span><br><span style="color: hsl(0, 100%, 40%);">- l = []</span><br><span style="color: hsl(0, 100%, 40%);">- for i in range(count):</span><br><span style="color: hsl(0, 100%, 40%);">- l.append(self.modem())</span><br><span style="color: hsl(0, 100%, 40%);">- return l</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def all_resources(self, resource_func):</span><br><span style="color: hsl(0, 100%, 40%);">- """Returns all yielded resource."""</span><br><span style="color: hsl(0, 100%, 40%);">- l = []</span><br><span style="color: hsl(0, 100%, 40%);">- while True:</span><br><span style="color: hsl(0, 100%, 40%);">- try:</span><br><span style="color: hsl(0, 100%, 40%);">- l.append(resource_func())</span><br><span style="color: hsl(0, 100%, 40%);">- except resource.NoResourceExn:</span><br><span style="color: hsl(0, 100%, 40%);">- return l</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def esme(self):</span><br><span style="color: hsl(0, 100%, 40%);">- esme_obj = esme.Esme(self.msisdn())</span><br><span style="color: hsl(0, 100%, 40%);">- self.register_for_cleanup(esme_obj)</span><br><span style="color: hsl(0, 100%, 40%);">- return esme_obj</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def run_node(self, specifics=None):</span><br><span style="color: hsl(0, 100%, 40%);">- return run_node.RunNode.from_conf(self.reserved_resources.get(resource.R_RUN_NODE, specifics=specifics))</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def enb(self, specifics=None):</span><br><span style="color: hsl(0, 100%, 40%);">- enb_obj = enb.eNodeB.get_instance_by_type(self, self.reserved_resources.get(resource.R_ENB, specifics=specifics))</span><br><span style="color: hsl(0, 100%, 40%);">- self.register_for_cleanup(enb_obj)</span><br><span style="color: hsl(0, 100%, 40%);">- return enb_obj</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def epc(self, run_node=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if run_node is None:</span><br><span style="color: hsl(0, 100%, 40%);">- run_node = self.run_node()</span><br><span style="color: hsl(0, 100%, 40%);">- epc_obj = epc.EPC.get_instance_by_type(self, run_node)</span><br><span style="color: hsl(0, 100%, 40%);">- self.register_for_cleanup(epc_obj)</span><br><span style="color: hsl(0, 100%, 40%);">- return epc_obj</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def osmocon(self, specifics=None):</span><br><span style="color: hsl(0, 100%, 40%);">- conf = self.reserved_resources.get(resource.R_OSMOCON, specifics=specifics)</span><br><span style="color: hsl(0, 100%, 40%);">- osmocon_obj = osmocon.Osmocon(self, conf=conf)</span><br><span style="color: hsl(0, 100%, 40%);">- self.register_for_cleanup(osmocon_obj)</span><br><span style="color: hsl(0, 100%, 40%);">- return osmocon_obj</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def iperf3srv(self, ip_address=None):</span><br><span style="color: hsl(0, 100%, 40%);">- if ip_address is None:</span><br><span style="color: hsl(0, 100%, 40%);">- ip_address = self.ip_address()</span><br><span style="color: hsl(0, 100%, 40%);">- iperf3srv_obj = iperf3.IPerf3Server(self, ip_address)</span><br><span style="color: hsl(0, 100%, 40%);">- return iperf3srv_obj</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def msisdn(self):</span><br><span style="color: hsl(0, 100%, 40%);">- msisdn = self.resources_pool.next_msisdn(self)</span><br><span style="color: hsl(0, 100%, 40%);">- self.log('using MSISDN', msisdn)</span><br><span style="color: hsl(0, 100%, 40%);">- return msisdn</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def lac(self):</span><br><span style="color: hsl(0, 100%, 40%);">- lac = self.resources_pool.next_lac(self)</span><br><span style="color: hsl(0, 100%, 40%);">- self.log('using LAC', lac)</span><br><span style="color: hsl(0, 100%, 40%);">- return lac</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def rac(self):</span><br><span style="color: hsl(0, 100%, 40%);">- rac = self.resources_pool.next_rac(self)</span><br><span style="color: hsl(0, 100%, 40%);">- self.log('using RAC', rac)</span><br><span style="color: hsl(0, 100%, 40%);">- return rac</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def cellid(self):</span><br><span style="color: hsl(0, 100%, 40%);">- cellid = self.resources_pool.next_cellid(self)</span><br><span style="color: hsl(0, 100%, 40%);">- self.log('using CellId', cellid)</span><br><span style="color: hsl(0, 100%, 40%);">- return cellid</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def bvci(self):</span><br><span style="color: hsl(0, 100%, 40%);">- bvci = self.resources_pool.next_bvci(self)</span><br><span style="color: hsl(0, 100%, 40%);">- self.log('using BVCI', bvci)</span><br><span style="color: hsl(0, 100%, 40%);">- return bvci</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def poll(self):</span><br><span style="color: hsl(0, 100%, 40%);">- for proc, respawn in self._processes:</span><br><span style="color: hsl(0, 100%, 40%);">- if proc.terminated():</span><br><span style="color: hsl(0, 100%, 40%);">- if respawn == True:</span><br><span style="color: hsl(0, 100%, 40%);">- proc.respawn()</span><br><span style="color: hsl(0, 100%, 40%);">- else:</span><br><span style="color: hsl(0, 100%, 40%);">- proc.log_stdout_tail()</span><br><span style="color: hsl(0, 100%, 40%);">- proc.log_stderr_tail()</span><br><span style="color: hsl(0, 100%, 40%);">- log.ctx(proc)</span><br><span style="color: hsl(0, 100%, 40%);">- raise log.Error('Process ended prematurely: %s' % proc.name())</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- def prompt(self, *msgs, **msg_details):</span><br><span style="color: hsl(0, 100%, 40%);">- 'ask for user interaction. Do not use in tests that should run automatically!'</span><br><span style="color: hsl(0, 100%, 40%);">- if msg_details:</span><br><span style="color: hsl(0, 100%, 40%);">- msgs = list(msgs)</span><br><span style="color: hsl(0, 100%, 40%);">- msgs.append('{%s}' %</span><br><span style="color: hsl(0, 100%, 40%);">- (', '.join(['%s=%r' % (k,v)</span><br><span style="color: hsl(0, 100%, 40%);">- for k,v in sorted(msg_details.items())])))</span><br><span style="color: hsl(0, 100%, 40%);">- msg = ' '.join(msgs) or 'Hit Enter to continue'</span><br><span style="color: hsl(0, 100%, 40%);">- self.log('prompt:', msg)</span><br><span style="color: hsl(0, 100%, 40%);">- sys.__stdout__.write('\n\n--- PROMPT ---\n')</span><br><span style="color: hsl(0, 100%, 40%);">- sys.__stdout__.write(msg)</span><br><span style="color: hsl(0, 100%, 40%);">- sys.__stdout__.write('\n')</span><br><span style="color: hsl(0, 100%, 40%);">- sys.__stdout__.flush()</span><br><span style="color: hsl(0, 100%, 40%);">- entered = util.input_polling('> ', MainLoop.poll)</span><br><span style="color: hsl(0, 100%, 40%);">- self.log('prompt entered:', repr(entered))</span><br><span style="color: hsl(0, 100%, 40%);">- return entered</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> def resource_status_str(self):</span><br><span> return '\n'.join(('',</span><br><span> 'SUITE RUN: %s' % self.origin_id(),</span><br><span>diff --git a/src/osmo_gsm_tester/testenv.py b/src/osmo_gsm_tester/testenv.py</span><br><span>index 8c4743a..aa94f3c 100644</span><br><span>--- a/src/osmo_gsm_tester/testenv.py</span><br><span>+++ b/src/osmo_gsm_tester/testenv.py</span><br><span>@@ -20,6 +20,22 @@</span><br><span> # These will be initialized before each test run.</span><br><span> # A test script can thus establish its context by doing:</span><br><span> # from osmo_gsm_tester.testenv import *</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import sys</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import process</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import log as log_module</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import process as process_module</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import resource</span><br><span style="color: hsl(120, 100%, 40%);">+from .core.event_loop import MainLoop</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from .obj import nitb_osmo, hlr_osmo, mgcpgw_osmo, mgw_osmo, msc_osmo, bsc_osmo, stp_osmo, ggsn_osmo, sgsn_osmo, esme, osmocon, ms_driver, iperf3</span><br><span style="color: hsl(120, 100%, 40%);">+from .obj import run_node</span><br><span style="color: hsl(120, 100%, 40%);">+from .obj import epc</span><br><span style="color: hsl(120, 100%, 40%);">+from .obj import enb</span><br><span style="color: hsl(120, 100%, 40%);">+from .obj import bts</span><br><span style="color: hsl(120, 100%, 40%);">+from .obj import ms</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> trial = None</span><br><span> suite = None</span><br><span> test = None</span><br><span>@@ -32,22 +48,284 @@</span><br><span> sleep = None</span><br><span> poll = None</span><br><span> prompt = None</span><br><span style="color: hsl(0, 100%, 40%);">-Timeout = None</span><br><span> Sms = None</span><br><span> process = None</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+class Timeout(Exception):</span><br><span style="color: hsl(120, 100%, 40%);">+ pass</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class TestEnv(log_module.Origin):</span><br><span style="color: hsl(120, 100%, 40%);">+ def __init__(self, suite_run, test):</span><br><span style="color: hsl(120, 100%, 40%);">+ super().__init__(log_module.C_TST, test.name())</span><br><span style="color: hsl(120, 100%, 40%);">+ self.suite_run = suite_run</span><br><span style="color: hsl(120, 100%, 40%);">+ self._test = test</span><br><span style="color: hsl(120, 100%, 40%);">+ self.trial = suite_run.trial # backward compat with objects</span><br><span style="color: hsl(120, 100%, 40%);">+ self.resources_pool = suite_run.resource_pool() # backward compat with objects</span><br><span style="color: hsl(120, 100%, 40%);">+ self._processes = []</span><br><span style="color: hsl(120, 100%, 40%);">+ self.test_import_modules_to_clean_up = []</span><br><span style="color: hsl(120, 100%, 40%);">+ self.objects_to_clean_up = None</span><br><span style="color: hsl(120, 100%, 40%);">+ MainLoop.register_poll_func(self.poll)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def suite(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.suite_run</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # backward compat with objects</span><br><span style="color: hsl(120, 100%, 40%);">+ def get_test_run_dir(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self._test.get_run_dir()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # backward compat with objects</span><br><span style="color: hsl(120, 100%, 40%);">+ def config(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.suite_run.config()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def remember_to_stop(self, process, respawn=False):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Ask suite to monitor and manage lifecycle of the Process object. If a</span><br><span style="color: hsl(120, 100%, 40%);">+ process managed by suite finishes before cleanup time, the current test</span><br><span style="color: hsl(120, 100%, 40%);">+ will be marked as FAIL and end immediatelly. If respwan=True, then suite</span><br><span style="color: hsl(120, 100%, 40%);">+ will respawn() the process instead.'''</span><br><span style="color: hsl(120, 100%, 40%);">+ self._processes.insert(0, (process, respawn))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def stop_processes(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ if len(self._processes) == 0:</span><br><span style="color: hsl(120, 100%, 40%);">+ return</span><br><span style="color: hsl(120, 100%, 40%);">+ strategy = process_module.ParallelTerminationStrategy()</span><br><span style="color: hsl(120, 100%, 40%);">+ while self._processes:</span><br><span style="color: hsl(120, 100%, 40%);">+ proc, _ = self._processes.pop()</span><br><span style="color: hsl(120, 100%, 40%);">+ strategy.add_process(proc)</span><br><span style="color: hsl(120, 100%, 40%);">+ strategy.terminate_all()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def stop_process(self, process):</span><br><span style="color: hsl(120, 100%, 40%);">+ 'Remove process from monitored list and stop it'</span><br><span style="color: hsl(120, 100%, 40%);">+ for proc_respawn in self._processes:</span><br><span style="color: hsl(120, 100%, 40%);">+ proc, respawn = proc_respawn</span><br><span style="color: hsl(120, 100%, 40%);">+ if proc == process:</span><br><span style="color: hsl(120, 100%, 40%);">+ self._processes.remove(proc_respawn)</span><br><span style="color: hsl(120, 100%, 40%);">+ proc.terminate()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def register_for_cleanup(self, *obj):</span><br><span style="color: hsl(120, 100%, 40%);">+ assert all([hasattr(o, 'cleanup') for o in obj])</span><br><span style="color: hsl(120, 100%, 40%);">+ self.objects_to_clean_up = self.objects_to_clean_up or []</span><br><span style="color: hsl(120, 100%, 40%);">+ self.objects_to_clean_up.extend(obj)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def objects_cleanup(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ while self.objects_to_clean_up:</span><br><span style="color: hsl(120, 100%, 40%);">+ obj = self.objects_to_clean_up.pop()</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ obj.cleanup()</span><br><span style="color: hsl(120, 100%, 40%);">+ except Exception:</span><br><span style="color: hsl(120, 100%, 40%);">+ log_module.log_exn()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def test_import_modules_register_for_cleanup(self, mod):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+ Tests are required to call this API for any module loaded from its own</span><br><span style="color: hsl(120, 100%, 40%);">+ lib subdir, because they are loaded in the global namespace. Otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ later tests importing modules with the same name will re-use an already</span><br><span style="color: hsl(120, 100%, 40%);">+ loaded module.</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+ if mod not in self.test_import_modules_to_clean_up:</span><br><span style="color: hsl(120, 100%, 40%);">+ self.dbg('registering module %r for cleanup' % mod)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.test_import_modules_to_clean_up.append(mod)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def test_import_modules_cleanup(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ while self.test_import_modules_to_clean_up:</span><br><span style="color: hsl(120, 100%, 40%);">+ mod = self.test_import_modules_to_clean_up.pop()</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ self.dbg('Cleaning up module %r' % mod)</span><br><span style="color: hsl(120, 100%, 40%);">+ del sys.modules[mod.__name__]</span><br><span style="color: hsl(120, 100%, 40%);">+ del mod</span><br><span style="color: hsl(120, 100%, 40%);">+ except Exception:</span><br><span style="color: hsl(120, 100%, 40%);">+ log_module.log_exn()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def poll(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ for proc, respawn in self._processes:</span><br><span style="color: hsl(120, 100%, 40%);">+ if proc.terminated():</span><br><span style="color: hsl(120, 100%, 40%);">+ if respawn == True:</span><br><span style="color: hsl(120, 100%, 40%);">+ proc.respawn()</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ proc.log_stdout_tail()</span><br><span style="color: hsl(120, 100%, 40%);">+ proc.log_stderr_tail()</span><br><span style="color: hsl(120, 100%, 40%);">+ log_module.ctx(proc)</span><br><span style="color: hsl(120, 100%, 40%);">+ raise log_module.Error('Process ended prematurely: %s' % proc.name())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def stop(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ # if sys.exit() called from signal handler (e.g. SIGINT), SystemExit</span><br><span style="color: hsl(120, 100%, 40%);">+ # base exception is raised. Make sure to stop processes in this</span><br><span style="color: hsl(120, 100%, 40%);">+ # finally section. Resources are automatically freed with 'atexit'.</span><br><span style="color: hsl(120, 100%, 40%);">+ self.stop_processes()</span><br><span style="color: hsl(120, 100%, 40%);">+ self.objects_cleanup()</span><br><span style="color: hsl(120, 100%, 40%);">+ self.suite_run.reserved_resources.put_all()</span><br><span style="color: hsl(120, 100%, 40%);">+ MainLoop.unregister_poll_func(self.poll)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.test_import_modules_cleanup()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def prompt(self, *msgs, **msg_details):</span><br><span style="color: hsl(120, 100%, 40%);">+ 'ask for user interaction. Do not use in tests that should run automatically!'</span><br><span style="color: hsl(120, 100%, 40%);">+ if msg_details:</span><br><span style="color: hsl(120, 100%, 40%);">+ msgs = list(msgs)</span><br><span style="color: hsl(120, 100%, 40%);">+ msgs.append('{%s}' %</span><br><span style="color: hsl(120, 100%, 40%);">+ (', '.join(['%s=%r' % (k,v)</span><br><span style="color: hsl(120, 100%, 40%);">+ for k,v in sorted(msg_details.items())])))</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = ' '.join(msgs) or 'Hit Enter to continue'</span><br><span style="color: hsl(120, 100%, 40%);">+ self.log('prompt:', msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ sys.__stdout__.write('\n\n--- PROMPT ---\n')</span><br><span style="color: hsl(120, 100%, 40%);">+ sys.__stdout__.write(msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ sys.__stdout__.write('\n')</span><br><span style="color: hsl(120, 100%, 40%);">+ sys.__stdout__.flush()</span><br><span style="color: hsl(120, 100%, 40%);">+ entered = util.input_polling('> ', MainLoop.poll)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.log('prompt entered:', repr(entered))</span><br><span style="color: hsl(120, 100%, 40%);">+ return entered</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def get_reserved_resource(self, resource_class_str, specifics=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.suite_run.get_reserved_resource(resource_class_str, specifics)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def ip_address(self, specifics=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.get_reserved_resource(resource.R_IP_ADDRESS, specifics)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def nitb(self, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return nitb_osmo.OsmoNitb(self, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def hlr(self, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return hlr_osmo.OsmoHlr(self, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def ggsn(self, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return ggsn_osmo.OsmoGgsn(self, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def sgsn(self, hlr, ggsn, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return sgsn_osmo.OsmoSgsn(self, hlr, ggsn, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def mgcpgw(self, ip_address=None, bts_ip=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return mgcpgw_osmo.OsmoMgcpgw(self, ip_address, bts_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def mgw(self, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return mgw_osmo.OsmoMgw(self, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def msc(self, hlr, mgcpgw, stp, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return msc_osmo.OsmoMsc(self, hlr, mgcpgw, stp, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def bsc(self, msc, mgw, stp, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return bsc_osmo.OsmoBsc(self, msc, mgw, stp, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def stp(self, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ return stp_osmo.OsmoStp(self, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def ms_driver(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ ms = ms_driver.MsDriver(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.register_for_cleanup(ms)</span><br><span style="color: hsl(120, 100%, 40%);">+ return ms</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def bts(self, specifics=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ bts_obj = bts.Bts.get_instance_by_type(self, self.get_reserved_resource(resource.R_BTS, specifics=specifics))</span><br><span style="color: hsl(120, 100%, 40%);">+ bts_obj.set_lac(self.lac())</span><br><span style="color: hsl(120, 100%, 40%);">+ bts_obj.set_rac(self.rac())</span><br><span style="color: hsl(120, 100%, 40%);">+ bts_obj.set_cellid(self.cellid())</span><br><span style="color: hsl(120, 100%, 40%);">+ bts_obj.set_bvci(self.bvci())</span><br><span style="color: hsl(120, 100%, 40%);">+ self.register_for_cleanup(bts_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ return bts_obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def modem(self, specifics=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ conf = self.get_reserved_resource(resource.R_MODEM, specifics=specifics)</span><br><span style="color: hsl(120, 100%, 40%);">+ ms_obj = ms.MS.get_instance_by_type(self, conf)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.register_for_cleanup(ms_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ return ms_obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def modems(self, count):</span><br><span style="color: hsl(120, 100%, 40%);">+ l = []</span><br><span style="color: hsl(120, 100%, 40%);">+ for i in range(count):</span><br><span style="color: hsl(120, 100%, 40%);">+ l.append(self.modem())</span><br><span style="color: hsl(120, 100%, 40%);">+ return l</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def all_resources(self, resource_func):</span><br><span style="color: hsl(120, 100%, 40%);">+ """Returns all yielded resource."""</span><br><span style="color: hsl(120, 100%, 40%);">+ l = []</span><br><span style="color: hsl(120, 100%, 40%);">+ while True:</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ l.append(resource_func())</span><br><span style="color: hsl(120, 100%, 40%);">+ except resource.NoResourceExn:</span><br><span style="color: hsl(120, 100%, 40%);">+ return l</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def esme(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ esme_obj = esme.Esme(self.msisdn())</span><br><span style="color: hsl(120, 100%, 40%);">+ self.register_for_cleanup(esme_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ return esme_obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def run_node(self, specifics=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ return run_node.RunNode.from_conf(self.get_reserved_resource(resource.R_RUN_NODE, specifics=specifics))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def enb(self, specifics=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ enb_obj = enb.eNodeB.get_instance_by_type(self, self.get_reserved_resource(resource.R_ENB, specifics=specifics))</span><br><span style="color: hsl(120, 100%, 40%);">+ self.register_for_cleanup(enb_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ return enb_obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def epc(self, run_node=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if run_node is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ run_node = self.run_node()</span><br><span style="color: hsl(120, 100%, 40%);">+ epc_obj = epc.EPC.get_instance_by_type(self, run_node)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.register_for_cleanup(epc_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ return epc_obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def osmocon(self, specifics=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ conf = self.get_reserved_resource(resource.R_OSMOCON, specifics=specifics)</span><br><span style="color: hsl(120, 100%, 40%);">+ osmocon_obj = osmocon.Osmocon(self, conf=conf)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.register_for_cleanup(osmocon_obj)</span><br><span style="color: hsl(120, 100%, 40%);">+ return osmocon_obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def iperf3srv(self, ip_address=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ if ip_address is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ ip_address = self.ip_address()</span><br><span style="color: hsl(120, 100%, 40%);">+ iperf3srv_obj = iperf3.IPerf3Server(self, ip_address)</span><br><span style="color: hsl(120, 100%, 40%);">+ return iperf3srv_obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def msisdn(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ msisdn = self.suite_run.resource_pool().next_msisdn(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.log('using MSISDN', msisdn)</span><br><span style="color: hsl(120, 100%, 40%);">+ return msisdn</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def lac(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ lac = self.suite_run.resource_pool().next_lac(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.log('using LAC', lac)</span><br><span style="color: hsl(120, 100%, 40%);">+ return lac</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def rac(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ rac = self.suite_run.resource_pool().next_rac(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.log('using RAC', rac)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rac</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def cellid(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ cellid = self.suite_run.resource_pool().next_cellid(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.log('using CellId', cellid)</span><br><span style="color: hsl(120, 100%, 40%);">+ return cellid</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def bvci(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ bvci = self.suite_run.resource_pool().next_bvci(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.log('using BVCI', bvci)</span><br><span style="color: hsl(120, 100%, 40%);">+ return bvci</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> def setup(suite_run, _test):</span><br><span style="color: hsl(0, 100%, 40%);">- from .core import process as process_module</span><br><span> from .core.event_loop import MainLoop</span><br><span> from .obj.sms import Sms as Sms_class</span><br><span style="color: hsl(0, 100%, 40%);">- from . import suite as suite_module</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- global trial, suite, test, resources, log, dbg, err, wait, wait_no_raise, sleep, poll, prompt, Timeout, Sms, process</span><br><span style="color: hsl(120, 100%, 40%);">+ global trial, suite, test, resources, log, dbg, err, wait, wait_no_raise, sleep, poll, prompt, Sms, process</span><br><span> </span><br><span> trial = suite_run.trial</span><br><span style="color: hsl(0, 100%, 40%);">- suite = suite_run</span><br><span> test = _test</span><br><span style="color: hsl(0, 100%, 40%);">- resources = suite_run.reserved_resources</span><br><span style="color: hsl(120, 100%, 40%);">+ resources = suite_run.reserved_resources # TODO: remove this global, only used in selftest</span><br><span> log = test.log</span><br><span> dbg = test.dbg</span><br><span> err = test.err</span><br><span>@@ -55,9 +333,10 @@</span><br><span> wait_no_raise = lambda *args, **kwargs: MainLoop.wait_no_raise(suite_run, *args, **kwargs)</span><br><span> sleep = lambda *args, **kwargs: MainLoop.sleep(suite_run, *args, **kwargs)</span><br><span> poll = MainLoop.poll</span><br><span style="color: hsl(0, 100%, 40%);">- prompt = suite_run.prompt</span><br><span style="color: hsl(0, 100%, 40%);">- Timeout = suite_module.Timeout</span><br><span> Sms = Sms_class</span><br><span> process = process_module</span><br><span style="color: hsl(120, 100%, 40%);">+ suite = TestEnv(suite_run, _test) # stored in "suite" for backward compatibility</span><br><span style="color: hsl(120, 100%, 40%);">+ prompt = suite.prompt</span><br><span style="color: hsl(120, 100%, 40%);">+ return suite</span><br><span> </span><br><span> # vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/src/osmo_gsm_tester/trial.py b/src/osmo_gsm_tester/trial.py</span><br><span>index fb94a59..08b7d8f 100644</span><br><span>--- a/src/osmo_gsm_tester/trial.py</span><br><span>+++ b/src/osmo_gsm_tester/trial.py</span><br><span>@@ -22,7 +22,10 @@</span><br><span> import shutil</span><br><span> import tarfile</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-from .core import log, util, report</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import log</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import util</span><br><span style="color: hsl(120, 100%, 40%);">+from .core import report</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> from . import suite</span><br><span> </span><br><span> FILE_MARK_TAKEN = 'taken'</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/18042">change 18042</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/+/18042"/><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: If4ab39be7a97d33e82c5a34e2a10dfec38613a4e </div>
<div style="display:none"> Gerrit-Change-Number: 18042 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>