<p>Pau Espin Pedrol <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/10562">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Neels Hofmeyr: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Introduce scenario modifiers<br><br>Before this patch, scenarios were only used to select resources with<br>specific attributes. This commit introduces "modifiers" in scenarios,<br>which allows setting or modifing config attributes of resources once<br>they have been reserved. This way same test can be run selecting same<br>resources but modifying its configuration, allowing for instance running<br>different number of TRX, different timeslot configuration, etc.<br><br>Modifiers are described by placing a "modifiers" dictionary in any<br>scenario file, similar to the current "resources" one used to select<br>requird resources. The "modifiers" dictionary is overlaid on top of the<br>"resources" one resulting from combining all the "resources" dictionary<br>of all scenario files.<br><br>Change-Id: If8c422c67d9a971d9ce2c72594f55cde2db7550d<br>---<br>A example/scenarios/mod-bts0-numtrx2.conf<br>M selftest/resource_test.ok<br>M selftest/resource_test.py<br>M selftest/suite_test.ok<br>M selftest/suite_test.ok.ign<br>M selftest/suite_test.py<br>M src/osmo_gsm_tester/resource.py<br>M src/osmo_gsm_tester/suite.py<br>8 files changed, 226 insertions(+), 12 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/example/scenarios/mod-bts0-numtrx2.conf b/example/scenarios/mod-bts0-numtrx2.conf</span><br><span>new file mode 100644</span><br><span>index 0000000..eb24fd3</span><br><span>--- /dev/null</span><br><span>+++ b/example/scenarios/mod-bts0-numtrx2.conf</span><br><span>@@ -0,0 +1,3 @@</span><br><span style="color: hsl(120, 100%, 40%);">+modifiers:</span><br><span style="color: hsl(120, 100%, 40%);">+  bts:</span><br><span style="color: hsl(120, 100%, 40%);">+  - num_trx: 2</span><br><span>diff --git a/selftest/resource_test.ok b/selftest/resource_test.ok</span><br><span>index 884c6b3..3ec922b 100644</span><br><span>--- a/selftest/resource_test.ok</span><br><span>+++ b/selftest/resource_test.ok</span><br><span>@@ -222,6 +222,54 @@</span><br><span> </span><br><span> ~~~ end: currently reserved</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+~~~ with modifiers:</span><br><span style="color: hsl(120, 100%, 40%);">+resources(testowner)={'arfcn': [{'_hash': 'e620569450f8259b3f0212ec19c285dd07df063c',</span><br><span style="color: hsl(120, 100%, 40%);">+            '_reserved_by': 'testowner-123-1490837279',</span><br><span style="color: hsl(120, 100%, 40%);">+            'arfcn': '512',</span><br><span style="color: hsl(120, 100%, 40%);">+            'band': 'GSM-1800'},</span><br><span style="color: hsl(120, 100%, 40%);">+           {'_hash': '022621e513c5a5bf33b77430a1e9c886be676fa1',</span><br><span style="color: hsl(120, 100%, 40%);">+            '_reserved_by': 'testowner-123-1490837279',</span><br><span style="color: hsl(120, 100%, 40%);">+            'arfcn': '514',</span><br><span style="color: hsl(120, 100%, 40%);">+            'band': 'GSM-1800'}],</span><br><span style="color: hsl(120, 100%, 40%);">+ 'bts': [{'_hash': 'd2aa7c1124943de352351b650ca0c751784da6b6',</span><br><span style="color: hsl(120, 100%, 40%);">+          '_reserved_by': 'testowner-123-1490837279',</span><br><span style="color: hsl(120, 100%, 40%);">+          'addr': '10.42.42.114',</span><br><span style="color: hsl(120, 100%, 40%);">+          'band': 'GSM-1800',</span><br><span style="color: hsl(120, 100%, 40%);">+          'ciphers': ['a5_0', 'a5_1'],</span><br><span style="color: hsl(120, 100%, 40%);">+          'direct_pcu': 'True',</span><br><span style="color: hsl(120, 100%, 40%);">+          'ipa_unit_id': '1',</span><br><span style="color: hsl(120, 100%, 40%);">+          'label': 'sysmoBTS 1002',</span><br><span style="color: hsl(120, 100%, 40%);">+          'type': 'osmo-bts-sysmo'},</span><br><span style="color: hsl(120, 100%, 40%);">+         {'_hash': '6a9c9fbd364e1563a5b9f0826030a7888fd19575',</span><br><span style="color: hsl(120, 100%, 40%);">+          '_reserved_by': 'testowner-123-1490837279',</span><br><span style="color: hsl(120, 100%, 40%);">+          'addr': '10.42.42.50',</span><br><span style="color: hsl(120, 100%, 40%);">+          'band': 'GSM-1800',</span><br><span style="color: hsl(120, 100%, 40%);">+          'ciphers': ['a5_0', 'a5_1'],</span><br><span style="color: hsl(120, 100%, 40%);">+          'ipa_unit_id': '6',</span><br><span style="color: hsl(120, 100%, 40%);">+          'label': 'Ettus B200',</span><br><span style="color: hsl(120, 100%, 40%);">+          'launch_trx': 'True',</span><br><span style="color: hsl(120, 100%, 40%);">+          'num_trx': 2,</span><br><span style="color: hsl(120, 100%, 40%);">+          'type': 'osmo-bts-trx'}],</span><br><span style="color: hsl(120, 100%, 40%);">+ 'ip_address': [{'_hash': 'fd103b22c7cf2480d609150e06f4bbd92ac78d8c',</span><br><span style="color: hsl(120, 100%, 40%);">+                 '_reserved_by': 'testowner-123-1490837279',</span><br><span style="color: hsl(120, 100%, 40%);">+                 'addr': '10.42.42.2'}],</span><br><span style="color: hsl(120, 100%, 40%);">+ 'modem': [{'_hash': '0b538cb6ad799fbd7c2953fd3b4463a76c7cc9c0',</span><br><span style="color: hsl(120, 100%, 40%);">+            '_reserved_by': 'testowner-123-1490837279',</span><br><span style="color: hsl(120, 100%, 40%);">+            'auth_algo': 'comp128v1',</span><br><span style="color: hsl(120, 100%, 40%);">+            'ciphers': ['a5_0', 'a5_1'],</span><br><span style="color: hsl(120, 100%, 40%);">+            'imsi': '901700000009031',</span><br><span style="color: hsl(120, 100%, 40%);">+            'ki': '80A37E6FDEA931EAC92FFA5F671EFEAD',</span><br><span style="color: hsl(120, 100%, 40%);">+            'label': 'sierra_1',</span><br><span style="color: hsl(120, 100%, 40%);">+            'path': '/sierra_1'},</span><br><span style="color: hsl(120, 100%, 40%);">+           {'_hash': '3a6e7747dfe7dfdf817bd3351031bd08051605c3',</span><br><span style="color: hsl(120, 100%, 40%);">+            '_reserved_by': 'testowner-123-1490837279',</span><br><span style="color: hsl(120, 100%, 40%);">+            'auth_algo': 'comp128v1',</span><br><span style="color: hsl(120, 100%, 40%);">+            'ciphers': ['a5_0', 'a5_1'],</span><br><span style="color: hsl(120, 100%, 40%);">+            'imsi': '901700000009029',</span><br><span style="color: hsl(120, 100%, 40%);">+            'ki': '00969E283349D354A8239E877F2E0866',</span><br><span style="color: hsl(120, 100%, 40%);">+            'label': 'sierra_2',</span><br><span style="color: hsl(120, 100%, 40%);">+            'path': '/sierra_2'}]}</span><br><span style="color: hsl(120, 100%, 40%);">+~~~ end: with modifiers:</span><br><span> ~~~ currently reserved:</span><br><span> {}</span><br><span> </span><br><span>diff --git a/selftest/resource_test.py b/selftest/resource_test.py</span><br><span>index 52d8e47..cdfe021 100755</span><br><span>--- a/selftest/resource_test.py</span><br><span>+++ b/selftest/resource_test.py</span><br><span>@@ -77,16 +77,22 @@</span><br><span>        'arfcn': [ { 'band': 'GSM-1800', 'times': 2 } ],</span><br><span>        'modem': [ { 'times': 2 , 'ciphers': ['a5_0', 'a5_1']} ],</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+modifiers = {</span><br><span style="color: hsl(120, 100%, 40%);">+    'bts': [ {}, {'num_trx': 2 }],</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> origin = log.Origin(None, 'testowner')</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-resources = pool.reserve(origin, config.replicate_times(want))</span><br><span style="color: hsl(120, 100%, 40%);">+resources = pool.reserve(origin, config.replicate_times(want), config.replicate_times(modifiers))</span><br><span> </span><br><span> print('~~~ currently reserved:')</span><br><span> with open(rrfile, 'r') as f:</span><br><span>     print(f.read())</span><br><span> print('~~~ end: currently reserved\n')</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+print('~~~ with modifiers:')</span><br><span style="color: hsl(120, 100%, 40%);">+print(repr(resources))</span><br><span style="color: hsl(120, 100%, 40%);">+print('~~~ end: with modifiers:')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> resources.free()</span><br><span> </span><br><span> print('~~~ currently reserved:')</span><br><span>diff --git a/selftest/suite_test.ok b/selftest/suite_test.ok</span><br><span>index 79c37cc..b792b57 100644</span><br><span>--- a/selftest/suite_test.ok</span><br><span>+++ b/selftest/suite_test.ok</span><br><span>@@ -34,6 +34,8 @@</span><br><span> tst test_suite: reserving resources in [PATH]/selftest/suite_test/test_work/state_dir ...</span><br><span> tst test_suite: DBG: {combining='resources'}</span><br><span> tst {combining_scenarios='resources'}: DBG: {definition_conf={bts=[{'label': 'sysmoCell 5000'}, {'label': 'sysmoCell 5000'}, {'type': 'sysmo'}], ip_address=[{}], modem=[{}, {}]}}  [test_suite↪{combining_scenarios='resources'}]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: {combining='modifiers'}</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='modifiers'}: DBG: {definition_conf={}}  [test_suite↪{combining_scenarios='modifiers'}]</span><br><span> tst test_suite: Reserving 3 x bts (candidates: 6)</span><br><span> tst test_suite: DBG: Picked - _hash: 076ff06a4b719e61779492d3fb99f42a6635bb72</span><br><span>   addr: 10.42.42.53</span><br><span>@@ -177,6 +179,9 @@</span><br><span> tst test_suite: DBG: {combining='resources'}  [suite.py:[LINENR]]</span><br><span> tst {combining_scenarios='resources'}: DBG: {definition_conf={bts=[{'label': 'sysmoCell 5000'}, {'label': 'sysmoCell 5000'}, {'type': 'sysmo'}], ip_address=[{}], modem=[{}, {}]}}  [test_suite↪{combining_scenarios='resources'}]  [suite.py:[LINENR]]</span><br><span> tst {combining_scenarios='resources', scenario='foo'}: [RESOURCE_DICT]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: {combining='modifiers'}  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='modifiers'}: DBG: {definition_conf={}}  [test_suite↪{combining_scenarios='modifiers'}]  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='modifiers', scenario='foo'}: DBG: {conf={}, scenario='foo'}  [test_suite↪{combining_scenarios='modifiers', scenario='foo'}]  [suite.py:[LINENR]]</span><br><span> tst test_suite: Reserving 3 x bts (candidates: 6)  [resource.py:[LINENR]]</span><br><span> tst test_suite: DBG: Picked - _hash: 076ff06a4b719e61779492d3fb99f42a6635bb72</span><br><span>   addr: 10.42.42.53</span><br><span>@@ -255,6 +260,9 @@</span><br><span> tst test_suite: DBG: {combining='resources'}  [suite.py:[LINENR]]</span><br><span> tst {combining_scenarios='resources'}: DBG: {definition_conf={bts=[{'label': 'sysmoCell 5000'}, {'label': 'sysmoCell 5000'}, {'type': 'sysmo'}], ip_address=[{}], modem=[{}, {}]}}  [test_suite↪{combining_scenarios='resources'}]  [suite.py:[LINENR]]</span><br><span> tst {combining_scenarios='resources', scenario='foo'}: [RESOURCE_DICT]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: {combining='modifiers'}  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='modifiers'}: DBG: {definition_conf={}}  [test_suite↪{combining_scenarios='modifiers'}]  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='modifiers', scenario='foo'}: DBG: {conf={}, scenario='foo'}  [test_suite↪{combining_scenarios='modifiers', scenario='foo'}]  [suite.py:[LINENR]]</span><br><span> tst test_suite: Reserving 3 x bts (candidates: 6)  [resource.py:[LINENR]]</span><br><span> tst test_suite: DBG: Picked - _hash: 076ff06a4b719e61779492d3fb99f42a6635bb72</span><br><span>   addr: 10.42.42.53</span><br><span>@@ -322,5 +330,128 @@</span><br><span>     skip: test_error.py</span><br><span>     skip: test_fail.py</span><br><span>     skip: test_fail_raise.py</span><br><span style="color: hsl(120, 100%, 40%);">+- test with scenario and modifiers</span><br><span style="color: hsl(120, 100%, 40%);">+cnf ResourcesPool: DBG: Found config file resources.conf as [PATH]/selftest/suite_test/resources.conf in ./suite_test which is [PATH]/selftest/suite_test  [config.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+cnf ResourcesPool: DBG: Found path state_dir as [PATH]/selftest/suite_test/test_work/state_dir  [config.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: reserving resources in [PATH]/selftest/suite_test/test_work/state_dir ...  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: {combining='resources'}  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='resources'}: DBG: {definition_conf={bts=[{'label': 'sysmoCell 5000'}, {'label': 'sysmoCell 5000'}, {'type': 'sysmo'}], ip_address=[{}], modem=[{}, {}]}}  [test_suite↪{combining_scenarios='resources'}]  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='resources', scenario='foo'}: [RESOURCE_DICT]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: {combining='modifiers'}  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='modifiers'}: DBG: {definition_conf={}}  [test_suite↪{combining_scenarios='modifiers'}]  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst {combining_scenarios='modifiers', scenario='foo'}: DBG: {conf={bts=[{'trx_list': [{'nominal_power': '20'}, {'nominal_power': '20'}]}, {'trx_list': [{'nominal_power': '20'}, {'nominal_power': '20'}]}, {'type': 'sysmo'}]}, scenario='foo'}  [test_suite↪{combining_scenarios='modifiers', scenario='foo'}]  [suite.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: Reserving 3 x bts (candidates: 6)  [resource.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: Picked - _hash: 076ff06a4b719e61779492d3fb99f42a6635bb72</span><br><span style="color: hsl(120, 100%, 40%);">+  addr: 10.42.42.53</span><br><span style="color: hsl(120, 100%, 40%);">+  band: GSM-1800</span><br><span style="color: hsl(120, 100%, 40%);">+  ipa_unit_id: '7'</span><br><span style="color: hsl(120, 100%, 40%);">+  label: sysmoCell 5000</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+  - max_power_red: '3'</span><br><span style="color: hsl(120, 100%, 40%);">+    nominal_power: '10'</span><br><span style="color: hsl(120, 100%, 40%);">+  - max_power_red: '0'</span><br><span style="color: hsl(120, 100%, 40%);">+    nominal_power: '12'</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_remote_ip: 10.42.42.112</span><br><span style="color: hsl(120, 100%, 40%);">+  type: osmo-bts-trx</span><br><span style="color: hsl(120, 100%, 40%);">+- _hash: 9eaa928b04ce04b19dbae972f9bfc3eea6f5e249</span><br><span style="color: hsl(120, 100%, 40%);">+  addr: 10.42.42.53</span><br><span style="color: hsl(120, 100%, 40%);">+  band: GSM-1800</span><br><span style="color: hsl(120, 100%, 40%);">+  ipa_unit_id: '7'</span><br><span style="color: hsl(120, 100%, 40%);">+  label: sysmoCell 5000</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_list:</span><br><span style="color: hsl(120, 100%, 40%);">+  - nominal_power: '10'</span><br><span style="color: hsl(120, 100%, 40%);">+  - max_power_red: '1'</span><br><span style="color: hsl(120, 100%, 40%);">+    nominal_power: '12'</span><br><span style="color: hsl(120, 100%, 40%);">+  trx_remote_ip: 10.42.42.112</span><br><span style="color: hsl(120, 100%, 40%);">+  type: osmo-bts-trx</span><br><span style="color: hsl(120, 100%, 40%);">+- _hash: 07d9c8aaa940b674efcbbabdd69f58a6ce4e94f9</span><br><span style="color: hsl(120, 100%, 40%);">+  addr: 10.42.42.114</span><br><span style="color: hsl(120, 100%, 40%);">+  band: GSM-1800</span><br><span style="color: hsl(120, 100%, 40%);">+  ipa_unit_id: '1'</span><br><span style="color: hsl(120, 100%, 40%);">+  label: sysmoBTS 1002</span><br><span style="color: hsl(120, 100%, 40%);">+  type: sysmo</span><br><span style="color: hsl(120, 100%, 40%);">+  [resource.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: Reserving 1 x ip_address (candidates: 3)  [resource.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: Picked - _hash: cde1debf28f07f94f92c761b4b7c6bf35785ced4</span><br><span style="color: hsl(120, 100%, 40%);">+  addr: 10.42.42.1</span><br><span style="color: hsl(120, 100%, 40%);">+  [resource.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: Reserving 2 x modem (candidates: 16)  [resource.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst test_suite: DBG: Picked - _hash: 19c69e45aa090fb511446bd00797690aa82ff52f</span><br><span style="color: hsl(120, 100%, 40%);">+  imsi: '901700000007801'</span><br><span style="color: hsl(120, 100%, 40%);">+  ki: D620F48487B1B782DA55DF6717F08FF9</span><br><span style="color: hsl(120, 100%, 40%);">+  label: m7801</span><br><span style="color: hsl(120, 100%, 40%);">+  path: /wavecom_0</span><br><span style="color: hsl(120, 100%, 40%);">+- _hash: e1a46516a1fb493b2617ab14fc1693a9a45ec254</span><br><span style="color: hsl(120, 100%, 40%);">+  imsi: '901700000007802'</span><br><span style="color: hsl(120, 100%, 40%);">+  ki: 47FDB2D55CE6A10A85ABDAD034A5B7B3</span><br><span style="color: hsl(120, 100%, 40%);">+  label: m7802</span><br><span style="color: hsl(120, 100%, 40%);">+  path: /wavecom_1</span><br><span style="color: hsl(120, 100%, 40%);">+  [resource.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+resources(test_suite)={'bts': [{'_hash': '076ff06a4b719e61779492d3fb99f42a6635bb72',</span><br><span style="color: hsl(120, 100%, 40%);">+          '_reserved_by': 'test_suite-[ID_NUM]-[ID_NUM]',</span><br><span style="color: hsl(120, 100%, 40%);">+          'addr': '10.42.42.53',</span><br><span style="color: hsl(120, 100%, 40%);">+          'band': 'GSM-1800',</span><br><span style="color: hsl(120, 100%, 40%);">+          'ipa_unit_id': '7',</span><br><span style="color: hsl(120, 100%, 40%);">+          'label': 'sysmoCell 5000',</span><br><span style="color: hsl(120, 100%, 40%);">+          'trx_list': [{'max_power_red': '3', 'nominal_power': '20'},</span><br><span style="color: hsl(120, 100%, 40%);">+                       {'max_power_red': '0', 'nominal_power': '20'}],</span><br><span style="color: hsl(120, 100%, 40%);">+          'trx_remote_ip': '10.42.42.112',</span><br><span style="color: hsl(120, 100%, 40%);">+          'type': 'osmo-bts-trx'},</span><br><span style="color: hsl(120, 100%, 40%);">+         {'_hash': '9eaa928b04ce04b19dbae972f9bfc3eea6f5e249',</span><br><span style="color: hsl(120, 100%, 40%);">+          '_reserved_by': 'test_suite-[ID_NUM]-[ID_NUM]',</span><br><span style="color: hsl(120, 100%, 40%);">+          'addr': '10.42.42.53',</span><br><span style="color: hsl(120, 100%, 40%);">+          'band': 'GSM-1800',</span><br><span style="color: hsl(120, 100%, 40%);">+          'ipa_unit_id': '7',</span><br><span style="color: hsl(120, 100%, 40%);">+          'label': 'sysmoCell 5000',</span><br><span style="color: hsl(120, 100%, 40%);">+          'trx_list': [{'nominal_power': '20'},</span><br><span style="color: hsl(120, 100%, 40%);">+                       {'max_power_red': '1', 'nominal_power': '20'}],</span><br><span style="color: hsl(120, 100%, 40%);">+          'trx_remote_ip': '10.42.42.112',</span><br><span style="color: hsl(120, 100%, 40%);">+          'type': 'osmo-bts-trx'},</span><br><span style="color: hsl(120, 100%, 40%);">+         {'_hash': '07d9c8aaa940b674efcbbabdd69f58a6ce4e94f9',</span><br><span style="color: hsl(120, 100%, 40%);">+          '_reserved_by': 'test_suite-[ID_NUM]-[ID_NUM]',</span><br><span style="color: hsl(120, 100%, 40%);">+          'addr': '10.42.42.114',</span><br><span style="color: hsl(120, 100%, 40%);">+          'band': 'GSM-1800',</span><br><span style="color: hsl(120, 100%, 40%);">+          'ipa_unit_id': '1',</span><br><span style="color: hsl(120, 100%, 40%);">+          'label': 'sysmoBTS 1002',</span><br><span style="color: hsl(120, 100%, 40%);">+          'type': 'sysmo'}],</span><br><span style="color: hsl(120, 100%, 40%);">+ 'ip_address': [{'_hash': 'cde1debf28f07f94f92c761b4b7c6bf35785ced4',</span><br><span style="color: hsl(120, 100%, 40%);">+                 '_reserved_by': 'test_suite-[ID_NUM]-[ID_NUM]',</span><br><span style="color: hsl(120, 100%, 40%);">+                 'addr': '10.42.42.1'}],</span><br><span style="color: hsl(120, 100%, 40%);">+ 'modem': [{'_hash': '19c69e45aa090fb511446bd00797690aa82ff52f',</span><br><span style="color: hsl(120, 100%, 40%);">+            '_reserved_by': 'test_suite-[ID_NUM]-[ID_NUM]',</span><br><span style="color: hsl(120, 100%, 40%);">+            'imsi': '901700000007801',</span><br><span style="color: hsl(120, 100%, 40%);">+            'ki': 'D620F48487B1B782DA55DF6717F08FF9',</span><br><span style="color: hsl(120, 100%, 40%);">+            'label': 'm7801',</span><br><span style="color: hsl(120, 100%, 40%);">+            'path': '/wavecom_0'},</span><br><span style="color: hsl(120, 100%, 40%);">+           {'_hash': 'e1a46516a1fb493b2617ab14fc1693a9a45ec254',</span><br><span style="color: hsl(120, 100%, 40%);">+            '_reserved_by': 'test_suite-[ID_NUM]-[ID_NUM]',</span><br><span style="color: hsl(120, 100%, 40%);">+            'imsi': '901700000007802',</span><br><span style="color: hsl(120, 100%, 40%);">+            'ki': '47FDB2D55CE6A10A85ABDAD034A5B7B3',</span><br><span style="color: hsl(120, 100%, 40%);">+            'label': 'm7802',</span><br><span style="color: hsl(120, 100%, 40%);">+            'path': '/wavecom_1'}]}</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%);">+trial test_suite</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%);">+----------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+trial test_suite hello_world.py</span><br><span style="color: hsl(120, 100%, 40%);">+----------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+tst hello_world.py:[LINENR]: hello world  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst hello_world.py:[LINENR]: I am 'test_suite' / 'hello_world.py:[LINENR]'  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst hello_world.py:[LINENR]: one  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst hello_world.py:[LINENR]: two  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst hello_world.py:[LINENR]: three  [test_suite↪hello_world.py:[LINENR]]  [hello_world.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+tst hello_world.py:[LINENR] Test passed (N.N sec)  [test_suite↪hello_world.py]  [test.py:[LINENR]]</span><br><span style="color: hsl(120, 100%, 40%);">+---------------------------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+trial test_suite PASS</span><br><span style="color: hsl(120, 100%, 40%);">+---------------------------------------------------------------------</span><br><span style="color: hsl(120, 100%, 40%);">+PASS: test_suite (pass: 1, skip: 5)</span><br><span style="color: hsl(120, 100%, 40%);">+    pass: hello_world.py (N.N sec)</span><br><span style="color: hsl(120, 100%, 40%);">+    skip: mo_mt_sms.py</span><br><span style="color: hsl(120, 100%, 40%);">+    skip: mo_sms.py</span><br><span style="color: hsl(120, 100%, 40%);">+    skip: test_error.py</span><br><span style="color: hsl(120, 100%, 40%);">+    skip: test_fail.py</span><br><span style="color: hsl(120, 100%, 40%);">+    skip: test_fail_raise.py</span><br><span> </span><br><span> - graceful exit.</span><br><span>diff --git a/selftest/suite_test.ok.ign b/selftest/suite_test.ok.ign</span><br><span>index 49bd9eb..9bd168f 100644</span><br><span>--- a/selftest/suite_test.ok.ign</span><br><span>+++ b/selftest/suite_test.ok.ign</span><br><span>@@ -2,3 +2,4 @@</span><br><span> \.py:[0-9]*  .py:[LINENR]</span><br><span> \([0-9.]+ sec\) (N.N sec)</span><br><span> {combining_scenarios='resources', scenario='foo'}:.*       {combining_scenarios='resources', scenario='foo'}: [RESOURCE_DICT]</span><br><span style="color: hsl(120, 100%, 40%);">+test_suite-[0-9]*-[0-9]*    test_suite-[ID_NUM]-[ID_NUM]</span><br><span>diff --git a/selftest/suite_test.py b/selftest/suite_test.py</span><br><span>index a8b0f37..db19ccc 100755</span><br><span>--- a/selftest/suite_test.py</span><br><span>+++ b/selftest/suite_test.py</span><br><span>@@ -58,5 +58,16 @@</span><br><span> results = s.run_tests('hello_world.py')</span><br><span> print(report.suite_to_text(s))</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+print('- test with scenario and modifiers')</span><br><span style="color: hsl(120, 100%, 40%);">+trial = log.Origin(log.C_TST, 'trial')</span><br><span style="color: hsl(120, 100%, 40%);">+scenario = config.Scenario('foo', 'bar')</span><br><span style="color: hsl(120, 100%, 40%);">+scenario['resources'] = { 'bts': [{ 'times': '2', 'type': 'osmo-bts-trx', 'trx_list': [{'nominal_power': '10'}, {'nominal_power': '12'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(120, 100%, 40%);">+scenario['modifiers'] = { 'bts': [{ 'times': '2', 'trx_list': [{'nominal_power': '20'}, {'nominal_power': '20'}]}, {'type': 'sysmo'}] }</span><br><span style="color: hsl(120, 100%, 40%);">+s = suite.SuiteRun(trial, 'test_suite', s_def, [scenario])</span><br><span style="color: hsl(120, 100%, 40%);">+s.reserve_resources()</span><br><span style="color: hsl(120, 100%, 40%);">+print(repr(s.reserved_resources))</span><br><span style="color: hsl(120, 100%, 40%);">+results = s.run_tests('hello_world.py')</span><br><span style="color: hsl(120, 100%, 40%);">+print(report.suite_to_text(s))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> print('\n- graceful exit.')</span><br><span> # vim: expandtab tabstop=4 shiftwidth=4</span><br><span>diff --git a/src/osmo_gsm_tester/resource.py b/src/osmo_gsm_tester/resource.py</span><br><span>index dca8090..5204b61 100644</span><br><span>--- a/src/osmo_gsm_tester/resource.py</span><br><span>+++ b/src/osmo_gsm_tester/resource.py</span><br><span>@@ -87,7 +87,8 @@</span><br><span> </span><br><span> CONF_SCHEMA = util.dict_add(</span><br><span>     { 'defaults.timeout': schema.STR },</span><br><span style="color: hsl(0, 100%, 40%);">-    dict([('resources.%s' % key, val) for key, val in WANT_SCHEMA.items()]))</span><br><span style="color: hsl(120, 100%, 40%);">+    dict([('resources.%s' % key, val) for key, val in WANT_SCHEMA.items()]),</span><br><span style="color: hsl(120, 100%, 40%);">+    dict([('modifiers.%s' % key, val) for key, val in WANT_SCHEMA.items()]))</span><br><span> </span><br><span> KNOWN_BTS_TYPES = {</span><br><span>         'osmo-bts-sysmo': bts_sysmo.SysmoBts,</span><br><span>@@ -113,7 +114,7 @@</span><br><span>         self.all_resources = Resources(config.read(self.config_path, RESOURCES_SCHEMA))</span><br><span>         self.all_resources.set_hashes()</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def reserve(self, origin, want):</span><br><span style="color: hsl(120, 100%, 40%);">+    def reserve(self, origin, want, modifiers):</span><br><span>         '''</span><br><span>         attempt to reserve the resources specified in the dict 'want' for</span><br><span>         'origin'. Obtain a lock on the resources lock dir, verify that all</span><br><span>@@ -125,7 +126,11 @@</span><br><span> </span><br><span>         'origin' should be an Origin() instance.</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        'want' is a dict matching RESOURCES_SCHEMA.</span><br><span style="color: hsl(120, 100%, 40%);">+        'want' is a dict matching RESOURCES_SCHEMA, used to specify what to</span><br><span style="color: hsl(120, 100%, 40%);">+        reserve.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        'modifiers' is a dict matching RESOURCES_SCHEMA, it is overlaid on top</span><br><span style="color: hsl(120, 100%, 40%);">+        of 'want'.</span><br><span> </span><br><span>         If an entry has no attribute set, any of the resources may be</span><br><span>         reserved without further limitations.</span><br><span>@@ -142,6 +147,7 @@</span><br><span>          }</span><br><span>         '''</span><br><span>         schema.validate(want, RESOURCES_SCHEMA)</span><br><span style="color: hsl(120, 100%, 40%);">+        schema.validate(modifiers, RESOURCES_SCHEMA)</span><br><span> </span><br><span>         origin_id = origin.origin_id()</span><br><span> </span><br><span>@@ -156,7 +162,7 @@</span><br><span>             config.write(rrfile_path, reserved)</span><br><span> </span><br><span>             self.remember_to_free(to_be_reserved)</span><br><span style="color: hsl(0, 100%, 40%);">-            return ReservedResources(self, origin, to_be_reserved)</span><br><span style="color: hsl(120, 100%, 40%);">+            return ReservedResources(self, origin, to_be_reserved, modifiers)</span><br><span> </span><br><span>     def free(self, origin, to_be_freed):</span><br><span>         log.ctx(origin)</span><br><span>@@ -491,10 +497,12 @@</span><br><span>     dependencies from so far unused (but reserved) resource.</span><br><span>     '''</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    def __init__(self, resources_pool, origin, reserved):</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(self, resources_pool, origin, reserved, modifiers):</span><br><span>         self.resources_pool = resources_pool</span><br><span>         self.origin = origin</span><br><span style="color: hsl(0, 100%, 40%);">-        self.reserved = reserved</span><br><span style="color: hsl(120, 100%, 40%);">+        self.reserved_original = reserved</span><br><span style="color: hsl(120, 100%, 40%);">+        self.reserved = copy.deepcopy(self.reserved_original)</span><br><span style="color: hsl(120, 100%, 40%);">+        config.overlay(self.reserved, modifiers)</span><br><span> </span><br><span>     def __repr__(self):</span><br><span>         return 'resources(%s)=%s' % (self.origin.name(), pprint.pformat(self.reserved))</span><br><span>@@ -551,9 +559,9 @@</span><br><span>                 item.pop(USED_KEY, None)</span><br><span> </span><br><span>     def free(self):</span><br><span style="color: hsl(0, 100%, 40%);">-        if self.reserved:</span><br><span style="color: hsl(0, 100%, 40%);">-            self.resources_pool.free(self.origin, self.reserved)</span><br><span style="color: hsl(0, 100%, 40%);">-        self.reserved = None</span><br><span style="color: hsl(120, 100%, 40%);">+        if self.reserved_original:</span><br><span style="color: hsl(120, 100%, 40%);">+            self.resources_pool.free(self.origin, self.reserved_original)</span><br><span style="color: hsl(120, 100%, 40%);">+        self.reserved_original = None</span><br><span> </span><br><span>     def counts(self):</span><br><span>         counts = {}</span><br><span>diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py</span><br><span>index c712a75..fa86f96 100644</span><br><span>--- a/src/osmo_gsm_tester/suite.py</span><br><span>+++ b/src/osmo_gsm_tester/suite.py</span><br><span>@@ -71,6 +71,7 @@</span><br><span>         self.objects_to_clean_up = None</span><br><span>         self.test_import_modules_to_clean_up = []</span><br><span>         self._resource_requirements = None</span><br><span style="color: hsl(120, 100%, 40%);">+        self._resource_modifiers = None</span><br><span>         self._config = None</span><br><span>         self._processes = None</span><br><span>         self._run_dir = None</span><br><span>@@ -154,6 +155,11 @@</span><br><span>             self._resource_requirements = self.combined('resources')</span><br><span>         return self._resource_requirements</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    def resource_modifiers(self):</span><br><span style="color: hsl(120, 100%, 40%);">+        if self._resource_modifiers is None:</span><br><span style="color: hsl(120, 100%, 40%);">+            self._resource_modifiers = self.combined('modifiers')</span><br><span style="color: hsl(120, 100%, 40%);">+        return self._resource_modifiers</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     def config(self):</span><br><span>         if self._config is None:</span><br><span>             self._config = self.combined('config')</span><br><span>@@ -163,7 +169,7 @@</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 style="color: hsl(0, 100%, 40%);">-        self.reserved_resources = self.resources_pool.reserve(self, self.resource_requirements())</span><br><span style="color: hsl(120, 100%, 40%);">+        self.reserved_resources = self.resources_pool.reserve(self, self.resource_requirements(), self.resource_modifiers())</span><br><span> </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></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/10562">change 10562</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/10562"/><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-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: If8c422c67d9a971d9ce2c72594f55cde2db7550d </div>
<div style="display:none"> Gerrit-Change-Number: 10562 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Pau Espin Pedrol <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>
<div style="display:none"> Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Pau Espin Pedrol <pespin@sysmocom.de> </div>