osmo_ctrl.py: add RateCounters

First user will be the upcoming handover_2G/handover.py test in
I0b2671304165a1aaae2b386af46fbd8b098e3bd8.

Change-Id: Id799b3bb81eb9c04d13c26ff611e40363920300e
diff --git a/selftest/rate_ctrs_test/_prep.py b/selftest/rate_ctrs_test/_prep.py
new file mode 100644
index 0000000..773f190
--- /dev/null
+++ b/selftest/rate_ctrs_test/_prep.py
@@ -0,0 +1,16 @@
+import sys, os
+
+script_dir = sys.path[0]
+top_dir = os.path.join(script_dir, '..', '..')
+src_dir = os.path.join(top_dir, 'src')
+
+# to find the osmo_gsm_tester py module
+sys.path.append(src_dir)
+
+from osmo_gsm_tester.core import log
+
+log.TestsTarget()
+log.set_all_levels(log.L_DBG)
+
+if '-v' in sys.argv:
+    log.style_change(trace=True)
diff --git a/selftest/rate_ctrs_test/rate_ctrs_test.err b/selftest/rate_ctrs_test/rate_ctrs_test.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selftest/rate_ctrs_test/rate_ctrs_test.err
diff --git a/selftest/rate_ctrs_test/rate_ctrs_test.ok b/selftest/rate_ctrs_test/rate_ctrs_test.ok
new file mode 100644
index 0000000..489f58f
--- /dev/null
+++ b/selftest/rate_ctrs_test/rate_ctrs_test.ok
@@ -0,0 +1,155 @@
+- empty RateCounters()
+| 
+- initialized RateCounters, single var
+| rate_ctr.abs.inst.0.var = 0
+- incremented inst.var
+| rate_ctr.abs.inst.0.var = 1
+- incremented inst.var again
+| rate_ctr.abs.inst.0.var = 2
+- incremented inst.var by 5
+| rate_ctr.abs.inst.0.var = 7
+- initialized RateCounters, two vars
+| rate_ctr.abs.inst.0.foo = 0
+| rate_ctr.abs.inst.0.var = 0
+- incremented foo and var
+| rate_ctr.abs.inst.0.foo = 1
+| rate_ctr.abs.inst.0.var = 1
+- incremented var again
+| rate_ctr.abs.inst.0.foo = 1
+| rate_ctr.abs.inst.0.var = 2
+- incremented foo by 5
+| rate_ctr.abs.inst.0.foo = 6
+| rate_ctr.abs.inst.0.var = 2
+- initialized RateCounters, two vars, three instances
+| rate_ctr.abs.inst.0.foo = 0
+| rate_ctr.abs.inst.0.var = 0
+| rate_ctr.abs.inst.1.foo = 0
+| rate_ctr.abs.inst.1.var = 0
+| rate_ctr.abs.inst.2.foo = 0
+| rate_ctr.abs.inst.2.var = 0
+- incremented foo and var on separate instances
+| rate_ctr.abs.inst.0.foo = 1
+| rate_ctr.abs.inst.0.var = 0
+| rate_ctr.abs.inst.1.foo = 0
+| rate_ctr.abs.inst.1.var = 1
+| rate_ctr.abs.inst.2.foo = 0
+| rate_ctr.abs.inst.2.var = 0
+- incremented var on instance 2
+| rate_ctr.abs.inst.0.foo = 1
+| rate_ctr.abs.inst.0.var = 0
+| rate_ctr.abs.inst.1.foo = 0
+| rate_ctr.abs.inst.1.var = 1
+| rate_ctr.abs.inst.2.foo = 0
+| rate_ctr.abs.inst.2.var = 1
+- incremented foo by 5 on instances 1,2
+| rate_ctr.abs.inst.0.foo = 1
+| rate_ctr.abs.inst.0.var = 0
+| rate_ctr.abs.inst.1.foo = 5
+| rate_ctr.abs.inst.1.var = 1
+| rate_ctr.abs.inst.2.foo = 5
+| rate_ctr.abs.inst.2.var = 1
+- copy
+| rate_ctr.abs.inst.0.foo = 1
+| rate_ctr.abs.inst.0.var = 0
+| rate_ctr.abs.inst.1.foo = 5
+| rate_ctr.abs.inst.1.var = 1
+| rate_ctr.abs.inst.2.foo = 5
+| rate_ctr.abs.inst.2.var = 1
+- increment two vars by 100 on all three instances
+| rate_ctr.abs.inst.0.foo = 101
+| rate_ctr.abs.inst.0.var = 100
+| rate_ctr.abs.inst.1.foo = 105
+| rate_ctr.abs.inst.1.var = 101
+| rate_ctr.abs.inst.2.foo = 105
+| rate_ctr.abs.inst.2.var = 101
+- subtract original copy
+| rate_ctr.abs.inst.0.foo = 100
+| rate_ctr.abs.inst.0.var = 100
+| rate_ctr.abs.inst.1.foo = 100
+| rate_ctr.abs.inst.1.var = 100
+| rate_ctr.abs.inst.2.foo = 100
+| rate_ctr.abs.inst.2.var = 100
+- add original copy
+| rate_ctr.abs.inst.0.foo = 101
+| rate_ctr.abs.inst.0.var = 100
+| rate_ctr.abs.inst.1.foo = 105
+| rate_ctr.abs.inst.1.var = 101
+| rate_ctr.abs.inst.2.foo = 105
+| rate_ctr.abs.inst.2.var = 101
+- increment types per_hour, per_day by 23
+| rate_ctr.abs.inst.0.foo = 101
+| rate_ctr.abs.inst.0.var = 100
+| rate_ctr.abs.inst.1.foo = 105
+| rate_ctr.abs.inst.1.var = 101
+| rate_ctr.abs.inst.2.foo = 105
+| rate_ctr.abs.inst.2.var = 101
+| rate_ctr.per_day.inst.0.foo = 23
+| rate_ctr.per_day.inst.0.moo = 23
+| rate_ctr.per_day.inst.0.var = 23
+| rate_ctr.per_day.inst.1.foo = 23
+| rate_ctr.per_day.inst.1.moo = 23
+| rate_ctr.per_day.inst.1.var = 23
+| rate_ctr.per_day.inst.2.foo = 23
+| rate_ctr.per_day.inst.2.moo = 23
+| rate_ctr.per_day.inst.2.var = 23
+| rate_ctr.per_hour.inst.0.foo = 23
+| rate_ctr.per_hour.inst.0.moo = 23
+| rate_ctr.per_hour.inst.0.var = 23
+| rate_ctr.per_hour.inst.1.foo = 23
+| rate_ctr.per_hour.inst.1.moo = 23
+| rate_ctr.per_hour.inst.1.var = 23
+| rate_ctr.per_hour.inst.2.foo = 23
+| rate_ctr.per_hour.inst.2.moo = 23
+| rate_ctr.per_hour.inst.2.var = 23
+- copy
+| rate_ctr.abs.inst.0.foo = 101
+| rate_ctr.abs.inst.0.var = 100
+| rate_ctr.abs.inst.1.foo = 105
+| rate_ctr.abs.inst.1.var = 101
+| rate_ctr.abs.inst.2.foo = 105
+| rate_ctr.abs.inst.2.var = 101
+| rate_ctr.per_day.inst.0.foo = 23
+| rate_ctr.per_day.inst.0.moo = 23
+| rate_ctr.per_day.inst.0.var = 23
+| rate_ctr.per_day.inst.1.foo = 23
+| rate_ctr.per_day.inst.1.moo = 23
+| rate_ctr.per_day.inst.1.var = 23
+| rate_ctr.per_day.inst.2.foo = 23
+| rate_ctr.per_day.inst.2.moo = 23
+| rate_ctr.per_day.inst.2.var = 23
+| rate_ctr.per_hour.inst.0.foo = 23
+| rate_ctr.per_hour.inst.0.moo = 23
+| rate_ctr.per_hour.inst.0.var = 23
+| rate_ctr.per_hour.inst.1.foo = 23
+| rate_ctr.per_hour.inst.1.moo = 23
+| rate_ctr.per_hour.inst.1.var = 23
+| rate_ctr.per_hour.inst.2.foo = 23
+| rate_ctr.per_hour.inst.2.moo = 23
+| rate_ctr.per_hour.inst.2.var = 23
+- match?  True
+- increment foo
+| rate_ctr.abs.inst.0.foo = 102
+| rate_ctr.abs.inst.0.var = 100
+| rate_ctr.abs.inst.1.foo = 105
+| rate_ctr.abs.inst.1.var = 101
+| rate_ctr.abs.inst.2.foo = 105
+| rate_ctr.abs.inst.2.var = 101
+| rate_ctr.per_day.inst.0.foo = 23
+| rate_ctr.per_day.inst.0.moo = 23
+| rate_ctr.per_day.inst.0.var = 23
+| rate_ctr.per_day.inst.1.foo = 23
+| rate_ctr.per_day.inst.1.moo = 23
+| rate_ctr.per_day.inst.1.var = 23
+| rate_ctr.per_day.inst.2.foo = 23
+| rate_ctr.per_day.inst.2.moo = 23
+| rate_ctr.per_day.inst.2.var = 23
+| rate_ctr.per_hour.inst.0.foo = 23
+| rate_ctr.per_hour.inst.0.moo = 23
+| rate_ctr.per_hour.inst.0.var = 23
+| rate_ctr.per_hour.inst.1.foo = 23
+| rate_ctr.per_hour.inst.1.moo = 23
+| rate_ctr.per_hour.inst.1.var = 23
+| rate_ctr.per_hour.inst.2.foo = 23
+| rate_ctr.per_hour.inst.2.moo = 23
+| rate_ctr.per_hour.inst.2.var = 23
+- match?  False
diff --git a/selftest/rate_ctrs_test/rate_ctrs_test.py b/selftest/rate_ctrs_test/rate_ctrs_test.py
new file mode 100755
index 0000000..935bd9d
--- /dev/null
+++ b/selftest/rate_ctrs_test/rate_ctrs_test.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+import _prep
+
+from osmo_gsm_tester.obj.osmo_ctrl import *
+
+rc = RateCounters()
+print('- empty RateCounters()' + rc.str())
+
+rc = RateCounters('inst', 'var')
+print('- initialized RateCounters, single var' + rc.str())
+rc.inc('inst', 'var')
+print('- incremented inst.var' + rc.str())
+rc.inc('inst', 'var')
+print('- incremented inst.var again' + rc.str())
+rc.inc('inst', 'var', 5)
+print('- incremented inst.var by 5' + rc.str())
+
+rc = RateCounters('inst', ('foo', 'var'))
+print('- initialized RateCounters, two vars' + rc.str())
+rc.inc('inst', ('foo', 'var'))
+print('- incremented foo and var' + rc.str())
+rc.inc('inst', 'var')
+print('- incremented var again' + rc.str())
+rc.inc('inst', 'foo', 5)
+print('- incremented foo by 5' + rc.str())
+
+rc = RateCounters('inst', ('foo', 'var'), instances=range(3))
+print('- initialized RateCounters, two vars, three instances' + rc.str())
+rc.inc('inst', 'foo', instances=0)
+rc.inc('inst', 'var', instances=1)
+print('- incremented foo and var on separate instances' + rc.str())
+rc.inc('inst', 'var', instances=2)
+print('- incremented var on instance 2' + rc.str())
+rc.inc('inst', 'foo', 5, instances=(1,2))
+print('- incremented foo by 5 on instances 1,2' + rc.str())
+
+rc_rel = rc.copy()
+print('- copy' + rc_rel.str())
+rc.inc('inst', ('foo', 'var'), 100, instances=range(3))
+print('- increment two vars by 100 on all three instances' + rc.str())
+rc.subtract(rc_rel)
+print('- subtract original copy' + rc.str())
+rc.add(rc_rel)
+print('- add original copy' + rc.str())
+
+rc.inc('inst', ('foo', 'var', 'moo'), 23, instances=range(3), kinds=('per_hour', 'per_day'))
+print('- increment types per_hour, per_day by 23' + rc.str())
+
+rc2 = rc.copy()
+print('- copy' + rc2.str())
+print('- match? ', (rc == rc2))
+rc2.inc('inst', 'foo')
+print('- increment foo' + rc2.str())
+print('- match? ', (rc == rc2))
+
+# vim: expandtab tabstop=4 shiftwidth=4