<p>neels <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-gsm-tester/+/21522">View Change</a></p><div style="white-space:pre-wrap"></div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">osmo_ctrl.py: add RateCounters<br><br>First user will be the upcoming handover_2G/handover.py test in<br>I0b2671304165a1aaae2b386af46fbd8b098e3bd8.<br><br>Change-Id: Id799b3bb81eb9c04d13c26ff611e40363920300e<br>---<br>A selftest/rate_ctrs_test/_prep.py<br>A selftest/rate_ctrs_test/rate_ctrs_test.err<br>A selftest/rate_ctrs_test/rate_ctrs_test.ok<br>A selftest/rate_ctrs_test/rate_ctrs_test.py<br>M src/osmo_gsm_tester/obj/osmo_ctrl.py<br>5 files changed, 453 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/selftest/rate_ctrs_test/_prep.py b/selftest/rate_ctrs_test/_prep.py</span><br><span>new file mode 100644</span><br><span>index 0000000..773f190</span><br><span>--- /dev/null</span><br><span>+++ b/selftest/rate_ctrs_test/_prep.py</span><br><span>@@ -0,0 +1,16 @@</span><br><span style="color: hsl(120, 100%, 40%);">+import sys, os</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+script_dir = sys.path[0]</span><br><span style="color: hsl(120, 100%, 40%);">+top_dir = os.path.join(script_dir, '..', '..')</span><br><span style="color: hsl(120, 100%, 40%);">+src_dir = os.path.join(top_dir, 'src')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# to find the osmo_gsm_tester py module</span><br><span style="color: hsl(120, 100%, 40%);">+sys.path.append(src_dir)</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+log.TestsTarget()</span><br><span style="color: hsl(120, 100%, 40%);">+log.set_all_levels(log.L_DBG)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if '-v' in sys.argv:</span><br><span style="color: hsl(120, 100%, 40%);">+ log.style_change(trace=True)</span><br><span>diff --git a/selftest/rate_ctrs_test/rate_ctrs_test.err b/selftest/rate_ctrs_test/rate_ctrs_test.err</span><br><span>new file mode 100644</span><br><span>index 0000000..e69de29</span><br><span>--- /dev/null</span><br><span>+++ b/selftest/rate_ctrs_test/rate_ctrs_test.err</span><br><span>diff --git a/selftest/rate_ctrs_test/rate_ctrs_test.ok b/selftest/rate_ctrs_test/rate_ctrs_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..489f58f</span><br><span>--- /dev/null</span><br><span>+++ b/selftest/rate_ctrs_test/rate_ctrs_test.ok</span><br><span>@@ -0,0 +1,155 @@</span><br><span style="color: hsl(120, 100%, 40%);">+- empty RateCounters()</span><br><span style="color: hsl(120, 100%, 40%);">+| </span><br><span style="color: hsl(120, 100%, 40%);">+- initialized RateCounters, single var</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented inst.var</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented inst.var again</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 2</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented inst.var by 5</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 7</span><br><span style="color: hsl(120, 100%, 40%);">+- initialized RateCounters, two vars</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented foo and var</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented var again</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 2</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented foo by 5</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 6</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 2</span><br><span style="color: hsl(120, 100%, 40%);">+- initialized RateCounters, two vars, three instances</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented foo and var on separate instances</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented var on instance 2</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+- incremented foo by 5 on instances 1,2</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 5</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 5</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+- copy</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 0</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 5</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 5</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 1</span><br><span style="color: hsl(120, 100%, 40%);">+- increment two vars by 100 on all three instances</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+- subtract original copy</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+- add original copy</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+- increment types per_hour, per_day by 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+- copy</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+- match? True</span><br><span style="color: hsl(120, 100%, 40%);">+- increment foo</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.foo = 102</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.0.var = 100</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.1.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.foo = 105</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.abs.inst.2.var = 101</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.0.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.1.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_day.inst.2.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.0.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.1.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.foo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.moo = 23</span><br><span style="color: hsl(120, 100%, 40%);">+| rate_ctr.per_hour.inst.2.var = 23</span><br><span style="color: hsl(120, 100%, 40%);">+- match? False</span><br><span>diff --git a/selftest/rate_ctrs_test/rate_ctrs_test.py b/selftest/rate_ctrs_test/rate_ctrs_test.py</span><br><span>new file mode 100755</span><br><span>index 0000000..935bd9d</span><br><span>--- /dev/null</span><br><span>+++ b/selftest/rate_ctrs_test/rate_ctrs_test.py</span><br><span>@@ -0,0 +1,56 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python3</span><br><span style="color: hsl(120, 100%, 40%);">+import _prep</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from osmo_gsm_tester.obj.osmo_ctrl import *</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rc = RateCounters()</span><br><span style="color: hsl(120, 100%, 40%);">+print('- empty RateCounters()' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rc = RateCounters('inst', 'var')</span><br><span style="color: hsl(120, 100%, 40%);">+print('- initialized RateCounters, single var' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'var')</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented inst.var' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'var')</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented inst.var again' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'var', 5)</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented inst.var by 5' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rc = RateCounters('inst', ('foo', 'var'))</span><br><span style="color: hsl(120, 100%, 40%);">+print('- initialized RateCounters, two vars' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', ('foo', 'var'))</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented foo and var' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'var')</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented var again' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'foo', 5)</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented foo by 5' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rc = RateCounters('inst', ('foo', 'var'), instances=range(3))</span><br><span style="color: hsl(120, 100%, 40%);">+print('- initialized RateCounters, two vars, three instances' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'foo', instances=0)</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'var', instances=1)</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented foo and var on separate instances' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'var', instances=2)</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented var on instance 2' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', 'foo', 5, instances=(1,2))</span><br><span style="color: hsl(120, 100%, 40%);">+print('- incremented foo by 5 on instances 1,2' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rc_rel = rc.copy()</span><br><span style="color: hsl(120, 100%, 40%);">+print('- copy' + rc_rel.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', ('foo', 'var'), 100, instances=range(3))</span><br><span style="color: hsl(120, 100%, 40%);">+print('- increment two vars by 100 on all three instances' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.subtract(rc_rel)</span><br><span style="color: hsl(120, 100%, 40%);">+print('- subtract original copy' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+rc.add(rc_rel)</span><br><span style="color: hsl(120, 100%, 40%);">+print('- add original copy' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rc.inc('inst', ('foo', 'var', 'moo'), 23, instances=range(3), kinds=('per_hour', 'per_day'))</span><br><span style="color: hsl(120, 100%, 40%);">+print('- increment types per_hour, per_day by 23' + rc.str())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+rc2 = rc.copy()</span><br><span style="color: hsl(120, 100%, 40%);">+print('- copy' + rc2.str())</span><br><span style="color: hsl(120, 100%, 40%);">+print('- match? ', (rc == rc2))</span><br><span style="color: hsl(120, 100%, 40%);">+rc2.inc('inst', 'foo')</span><br><span style="color: hsl(120, 100%, 40%);">+print('- increment foo' + rc2.str())</span><br><span style="color: hsl(120, 100%, 40%);">+print('- match? ', (rc == rc2))</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/obj/osmo_ctrl.py b/src/osmo_gsm_tester/obj/osmo_ctrl.py</span><br><span>index 644025f..6c4ac87 100644</span><br><span>--- a/src/osmo_gsm_tester/obj/osmo_ctrl.py</span><br><span>+++ b/src/osmo_gsm_tester/obj/osmo_ctrl.py</span><br><span>@@ -238,4 +238,230 @@</span><br><span> def __exit__(self, *exc_info):</span><br><span> self.disconnect()</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+class RateCountersExn(log.Error):</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 RateCounters(dict):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Usage example:</span><br><span style="color: hsl(120, 100%, 40%);">+ counter_names = (</span><br><span style="color: hsl(120, 100%, 40%);">+ 'handover:completed',</span><br><span style="color: hsl(120, 100%, 40%);">+ 'handover:stopped',</span><br><span style="color: hsl(120, 100%, 40%);">+ 'handover:no_channel',</span><br><span style="color: hsl(120, 100%, 40%);">+ 'handover:timeout',</span><br><span style="color: hsl(120, 100%, 40%);">+ 'handover:failed',</span><br><span style="color: hsl(120, 100%, 40%);">+ 'handover:error',</span><br><span style="color: hsl(120, 100%, 40%);">+ )</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # initialize the listing of CTRL vars of the counters to watch.</span><br><span style="color: hsl(120, 100%, 40%);">+ # First on the 'bsc' node:</span><br><span style="color: hsl(120, 100%, 40%);">+ # rate_ctr.abs.bsc.0.handover:completed</span><br><span style="color: hsl(120, 100%, 40%);">+ # rate_ctr.abs.bsc.0.handover:stopped</span><br><span style="color: hsl(120, 100%, 40%);">+ # ...</span><br><span style="color: hsl(120, 100%, 40%);">+ counters = RateCounters('bsc', counter_names, from_ctrl=bsc.ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # And also add counters for two 'bts' instances:</span><br><span style="color: hsl(120, 100%, 40%);">+ # rate_ctr.abs.bts.0.handover:completed</span><br><span style="color: hsl(120, 100%, 40%);">+ # rate_ctr.abs.bts.0.handover:stopped</span><br><span style="color: hsl(120, 100%, 40%);">+ # ...</span><br><span style="color: hsl(120, 100%, 40%);">+ # rate_ctr.abs.bts.1.handover:completed</span><br><span style="color: hsl(120, 100%, 40%);">+ # ...</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.add(RateCounters('bts', counter_names, instances=(0, 1)))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # read initial counter values, from the bsc_ctrl, as set in</span><br><span style="color: hsl(120, 100%, 40%);">+ # counters.from_ctrl in the RateCounters() constructor above.</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.read()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # Do some actions that should increment counters in the SUT</span><br><span style="color: hsl(120, 100%, 40%);">+ do_a_handover()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if approach_without_wait:</span><br><span style="color: hsl(120, 100%, 40%);">+ # increment the counters as expected</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.inc('bts', 'handover:completed')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # read counters from CTRL again, and fail if they differ</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.verify()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if approach_with_wait:</span><br><span style="color: hsl(120, 100%, 40%);">+ # you can wait for counters to change. counters.changed() does not</span><br><span style="color: hsl(120, 100%, 40%);">+ # modify counters' values, just reads values from CTRL and stores</span><br><span style="color: hsl(120, 100%, 40%);">+ # the changes in counters.diff.</span><br><span style="color: hsl(120, 100%, 40%);">+ wait(counters.changed, timeout=20)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # log which counters changed by how much, found in counters.diff</span><br><span style="color: hsl(120, 100%, 40%);">+ # after each counters.changed() call:</span><br><span style="color: hsl(120, 100%, 40%);">+ print(counters.diff.str(skip_zero_vals=True))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if check_all_vals:</span><br><span style="color: hsl(120, 100%, 40%);">+ # Assert all values:</span><br><span style="color: hsl(120, 100%, 40%);">+ expected_diff = counters.copy().clear()</span><br><span style="color: hsl(120, 100%, 40%);">+ expected_diff.inc('bts', 'handover:completed', instances=(0, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.diff.expect(expected_diff)</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ # Assert only some specific counters:</span><br><span style="color: hsl(120, 100%, 40%);">+ expected_diff = RateCounters()</span><br><span style="color: hsl(120, 100%, 40%);">+ expected_diff.inc('bts', 'handover:completed', instances=(0, 1))</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.diff.expect(expected_diff)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ # update counters to the last read values if desired</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.add(counters.diff)</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def __init__(self, instance_names=(), counter_names=(), instances=0, kinds='abs', init_val=0, from_ctrl=None):</span><br><span style="color: hsl(120, 100%, 40%);">+ def init_cb(var):</span><br><span style="color: hsl(120, 100%, 40%);">+ self[var] = init_val</span><br><span style="color: hsl(120, 100%, 40%);">+ RateCounters.for_each(init_cb, instance_names, counter_names, instances, kinds, results=False)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.from_ctrl = from_ctrl</span><br><span style="color: hsl(120, 100%, 40%);">+ self.diff = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ @staticmethod</span><br><span style="color: hsl(120, 100%, 40%);">+ def for_each(callback_func, instance_names, counter_names, instances=0, kinds='abs', results=True):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Call callback_func for a set of rate counter var names, mostly</span><br><span style="color: hsl(120, 100%, 40%);">+ called by more convenient functions. See inc() for a comprehensive</span><br><span style="color: hsl(120, 100%, 40%);">+ explanation.</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+ if type(instance_names) is str:</span><br><span style="color: hsl(120, 100%, 40%);">+ instance_names = (instance_names, )</span><br><span style="color: hsl(120, 100%, 40%);">+ if type(counter_names) is str:</span><br><span style="color: hsl(120, 100%, 40%);">+ counter_names = (counter_names, )</span><br><span style="color: hsl(120, 100%, 40%);">+ if type(kinds) is str:</span><br><span style="color: hsl(120, 100%, 40%);">+ kinds = (kinds, )</span><br><span style="color: hsl(120, 100%, 40%);">+ if type(instances) is int:</span><br><span style="color: hsl(120, 100%, 40%);">+ instances = (instances, )</span><br><span style="color: hsl(120, 100%, 40%);">+ if results is True:</span><br><span style="color: hsl(120, 100%, 40%);">+ results = RateCounters()</span><br><span style="color: hsl(120, 100%, 40%);">+ elif results is False:</span><br><span style="color: hsl(120, 100%, 40%);">+ results = None</span><br><span style="color: hsl(120, 100%, 40%);">+ for instance_name in instance_names:</span><br><span style="color: hsl(120, 100%, 40%);">+ for instance_nr in instances:</span><br><span style="color: hsl(120, 100%, 40%);">+ for counter_name in counter_names:</span><br><span style="color: hsl(120, 100%, 40%);">+ for kind in kinds:</span><br><span style="color: hsl(120, 100%, 40%);">+ var = 'rate_ctr.{kind}.{instance_name}.{instance_nr}.{counter_name}'.format(**locals())</span><br><span style="color: hsl(120, 100%, 40%);">+ result = callback_func(var)</span><br><span style="color: hsl(120, 100%, 40%);">+ if results is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+ results[var] = result</span><br><span style="color: hsl(120, 100%, 40%);">+ return results</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def __str__(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ return self.str(', ', '')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def str(self, sep='\n| ', prefix='\n| ', vals=None, skip_zero_vals=False):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''The 'vals' arg is useful to print a plain dict() of counter values like a RateCounters class.</span><br><span style="color: hsl(120, 100%, 40%);">+ By default print self.'''</span><br><span style="color: hsl(120, 100%, 40%);">+ if vals is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ vals = self</span><br><span style="color: hsl(120, 100%, 40%);">+ return prefix + sep.join('%s = %d' % (var, val) for var, val in sorted(vals.items())</span><br><span style="color: hsl(120, 100%, 40%);">+ if (not skip_zero_vals) or (val != 0))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def inc(self, instance_names, counter_names, inc=1, instances=0, kinds='abs'):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Increment a set of counters.</span><br><span style="color: hsl(120, 100%, 40%);">+ inc('xyz', 'val') --> rate_ctr.abs.xyz.0.val += 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ inc('xyz', ('foo', 'bar')) --> rate_ctr.abs.xyz.0.foo += 1</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr.abs.xyz.0.bar += 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ inc(('xyz', 'pqr'), 'val') --> rate_ctr.abs.xyz.0.val += 1</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr.abs.pqr.0.val += 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ inc('xyz', 'val', instances=range(3))</span><br><span style="color: hsl(120, 100%, 40%);">+ --> rate_ctr.abs.xyz.0.val += 1</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr.abs.xyz.1.val += 1</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_ctr.abs.xyz.2.val += 1</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+ def inc_cb(var):</span><br><span style="color: hsl(120, 100%, 40%);">+ val = self.get(var, 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ val += inc</span><br><span style="color: hsl(120, 100%, 40%);">+ self[var] = val</span><br><span style="color: hsl(120, 100%, 40%);">+ return val</span><br><span style="color: hsl(120, 100%, 40%);">+ RateCounters.for_each(inc_cb, instance_names, counter_names, instances, kinds, results=False)</span><br><span style="color: hsl(120, 100%, 40%);">+ return self</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def add(self, rate_counters):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Add the given values up to the values in self.</span><br><span style="color: hsl(120, 100%, 40%);">+ rate_counters can be a RateCounters instance or a plain dict of CTRL</span><br><span style="color: hsl(120, 100%, 40%);">+ var as key and counter integer as value.</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+ for var, add_val in rate_counters.items():</span><br><span style="color: hsl(120, 100%, 40%);">+ val = self.get(var, 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ val += add_val</span><br><span style="color: hsl(120, 100%, 40%);">+ self[var] = val</span><br><span style="color: hsl(120, 100%, 40%);">+ return self</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def subtract(self, rate_counters):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Same as add(), but subtract values from self instead.</span><br><span style="color: hsl(120, 100%, 40%);">+ Useful to verify counters relative to an arbitrary reference.'''</span><br><span style="color: hsl(120, 100%, 40%);">+ for var, subtract_val in rate_counters.items():</span><br><span style="color: hsl(120, 100%, 40%);">+ val = self.get(var, 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ val -= subtract_val</span><br><span style="color: hsl(120, 100%, 40%);">+ self[var] = val</span><br><span style="color: hsl(120, 100%, 40%);">+ return self</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def clear(self, val=0):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Set all counts to 0 (or a specific value)'''</span><br><span style="color: hsl(120, 100%, 40%);">+ for var in self.keys():</span><br><span style="color: hsl(120, 100%, 40%);">+ self[var] = val</span><br><span style="color: hsl(120, 100%, 40%);">+ return self</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def copy(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Return a copy of all keys and values stored in self.'''</span><br><span style="color: hsl(120, 100%, 40%);">+ cpy = RateCounters(from_ctrl = self.from_ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+ cpy.update(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ return cpy</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def read(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Read all counters from the CTRL connection passed to RateCounters(from_ctrl=x).</span><br><span style="color: hsl(120, 100%, 40%);">+ The CTRL must be connected, e.g.</span><br><span style="color: hsl(120, 100%, 40%);">+ with bsc.ctrl() as ctrl:</span><br><span style="color: hsl(120, 100%, 40%);">+ counters = RateCounters(ctrl)</span><br><span style="color: hsl(120, 100%, 40%);">+ counters.read()</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+ for var in self.keys():</span><br><span style="color: hsl(120, 100%, 40%);">+ self[var] = self.from_ctrl.get_int_var(var)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.from_ctrl.dbg('Read counters:', self.str())</span><br><span style="color: hsl(120, 100%, 40%);">+ return self</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def verify(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Read counters from CTRL and assert that they match the current counts'''</span><br><span style="color: hsl(120, 100%, 40%);">+ got_vals = self.copy()</span><br><span style="color: hsl(120, 100%, 40%);">+ got_vals.read()</span><br><span style="color: hsl(120, 100%, 40%);">+ got_vals.expect(self)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def changed(self):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Read counters from CTRL, and return True if anyone is different now.</span><br><span style="color: hsl(120, 100%, 40%);">+ Store the difference in counts in self.diff (replace self.diff for</span><br><span style="color: hsl(120, 100%, 40%);">+ each changed() call). The counts in self are never modified.'''</span><br><span style="color: hsl(120, 100%, 40%);">+ self.diff = None</span><br><span style="color: hsl(120, 100%, 40%);">+ got_vals = self.copy()</span><br><span style="color: hsl(120, 100%, 40%);">+ got_vals.read()</span><br><span style="color: hsl(120, 100%, 40%);">+ if self != got_vals:</span><br><span style="color: hsl(120, 100%, 40%);">+ self.diff = got_vals</span><br><span style="color: hsl(120, 100%, 40%);">+ self.diff.subtract(self)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.from_ctrl.dbg('Changed counters:', self.diff.str(skip_zero_vals=True))</span><br><span style="color: hsl(120, 100%, 40%);">+ return True</span><br><span style="color: hsl(120, 100%, 40%);">+ return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def expect(self, expect_vals):</span><br><span style="color: hsl(120, 100%, 40%);">+ '''Iterate expect_vals and fail if any counter value differs from self.</span><br><span style="color: hsl(120, 100%, 40%);">+ expect_vals can be a RateCounters instance or a plain dict of CTRL</span><br><span style="color: hsl(120, 100%, 40%);">+ var as key and counter integer as value.</span><br><span style="color: hsl(120, 100%, 40%);">+ '''</span><br><span style="color: hsl(120, 100%, 40%);">+ ok = 0</span><br><span style="color: hsl(120, 100%, 40%);">+ errs = []</span><br><span style="color: hsl(120, 100%, 40%);">+ for var, expect_val in expect_vals.items():</span><br><span style="color: hsl(120, 100%, 40%);">+ got_val = self.get(var)</span><br><span style="color: hsl(120, 100%, 40%);">+ if got_val is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ errs.append('expected {var} == {expect_val}, but no such value found'.format(**locals()))</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ if got_val != expect_val:</span><br><span style="color: hsl(120, 100%, 40%);">+ errs.append('expected {var} == {expect_val}, but is {got_val}'.format(**locals()))</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ ok += 1</span><br><span style="color: hsl(120, 100%, 40%);">+ if errs:</span><br><span style="color: hsl(120, 100%, 40%);">+ self.from_ctrl.dbg('Expected rate counters:', self.str(vals=expect_vals))</span><br><span style="color: hsl(120, 100%, 40%);">+ self.from_ctrl.dbg('Got rate counters:', self.str())</span><br><span style="color: hsl(120, 100%, 40%);">+ raise RateCountersExn('%d of %d rate counters mismatch:' % (len(errs), len(errs) + ok), '\n| ' + '\n| '.join(errs))</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ self.from_ctrl.log('Verified %d rate counters' % ok)</span><br><span style="color: hsl(120, 100%, 40%);">+ self.from_ctrl.dbg('Verified %d rate counters:' % ok, expect_vals)</span><br><span style="color: hsl(120, 100%, 40%);">+</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/+/21522">change 21522</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/+/21522"/><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: Id799b3bb81eb9c04d13c26ff611e40363920300e </div>
<div style="display:none"> Gerrit-Change-Number: 21522 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@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>