Allow to automatically reserve an FSM test id
authorEduardo Ramos Testillano (ert) <eduardo.ramos.testillano@gmail.com>
Mon, 1 Nov 2021 18:06:30 +0000 (19:06 +0100)
committerEduardo Ramos Testillano (ert) <eduardo.ramos.testillano@gmail.com>
Mon, 1 Nov 2021 18:06:30 +0000 (19:06 +0100)
We will allow to provide '0' as special value for test
identifier on test manager in order to reserve the id
as the current pool size plus 1. This is valid if previous
reservations were done in the same way, or starting from
the id=1 and monotonically increased without holes in the
sequence.

REST API now will return the response body with the response field
as the affected test id in order to know the one reserved just in
case 0 was provided instead of specific value.

Component tests have been adapted to the new feature.

24 files changed:
example/diameter/launcher/EventOperation.cpp
example/diameter/launcher/resources/HELP.md
example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-finished_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-goto_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-initialized_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-interact_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-look_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-run_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/test-state_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-delay_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-description_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-ip-limit_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-sendmsg2c_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-sendmsg2e_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-sh-command_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-timeout_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfc-hex_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfc-msg_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfc_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfe-hex_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfe-msg_test.py
example/diameter/launcher/resources/rest_api/ct/fsm-testing/testid-waitfe_test.py
include/anna/testing/TestManager.hpp
source/testing/TestManager.cpp

index f21f729..2b42486 100644 (file)
@@ -558,8 +558,9 @@ bool EventOperation::test_id__description(std::string &response, unsigned int id
   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
 
   try {
-    testManager.getTestCase(id)->setDescription(description); // creates / reuses
-    response = "Done";
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
+    tc->setDescription(description);
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -576,8 +577,9 @@ bool EventOperation::test_id__ip_limit(std::string &response, unsigned int id, i
   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
 
   try {
-    testManager.getTestCase(id)->addIpLimit(amount); // creates / reuses
-    response = "Done";
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
+    tc->addIpLimit(amount);
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -595,8 +597,9 @@ bool EventOperation::test_id__timeout(std::string &response, unsigned int id, in
 
   try {
     anna::Millisecond timeout = my_app.checkTimeMeasure("Test case timeout", anna::functions::asString(msecs));
-    testManager.getTestCase(id)->addTimeout(timeout); // creates / reuses
-    response = "Done";
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
+    tc->addTimeout(timeout);
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -627,13 +630,14 @@ bool EventOperation::test_id__sendmsg2e_2c(std::string &response, unsigned int i
   );
 
   try {
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
     my_app.updateOperatedOriginHostWithMessage(codecMsg);
     if (_2e_or_2c)
-      testManager.getTestCase(id)->addSendDiameterXml2e(codecMsg.code(), my_app.getOperatedHost(), stepNumber); // creates / reuses
+      tc->addSendDiameterXml2e(codecMsg.code(), my_app.getOperatedHost(), stepNumber);
     else
-      testManager.getTestCase(id)->addSendDiameterXml2c(codecMsg.code(), my_app.getOperatedHost(), stepNumber); // creates / reuses
+      tc->addSendDiameterXml2c(codecMsg.code(), my_app.getOperatedHost(), stepNumber);
 
-    response = "Done";
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -650,9 +654,10 @@ bool EventOperation::test_id__delay(std::string &response, unsigned int id, int
   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
 
   try {
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
     anna::Millisecond delay = ((msecs == 0 /* special case */) ? (anna::Millisecond)0 : my_app.checkTimeMeasure("Test case delay step", anna::functions::asString(msecs)));
-    testManager.getTestCase(id)->addDelay(delay); // creates / reuses
-    response = "Done";
+    tc->addDelay(delay); // creates / reuses
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -669,8 +674,9 @@ bool EventOperation::test_id__sh_command(std::string &response, unsigned int id,
   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
 
   try {
-    testManager.getTestCase(id)->addCommand(script); // creates / reuses
-    response = "Done";
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
+    tc->addCommand(script); // creates / reuses
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -718,8 +724,9 @@ bool EventOperation::test_id__waitfefc_hex(std::string &response, unsigned int i
   }
 
   try {
-    testManager.getTestCase(id)->addWaitDiameterRegexpHex(fe_or_fc, regexp);
-    response = "Done";
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
+    tc->addWaitDiameterRegexpHex(fe_or_fc, regexp);
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -795,8 +802,9 @@ bool EventOperation::test_id__waitfefc_msg(std::string &response, unsigned int i
       //regexp += "$";
     }
 
-    testManager.getTestCase(id)->addWaitDiameterRegexpXml(fe_or_fc, regexp);
-    response = "Done";
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
+    tc->addWaitDiameterRegexpXml(fe_or_fc, regexp);
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
@@ -822,8 +830,9 @@ bool EventOperation::test_id__waitfefc(std::string &response, unsigned int id, b
   anna::testing::TestManager &testManager = anna::testing::TestManager::instantiate();
 
   try { // [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]
-    testManager.getTestCase(id)->addWaitDiameter(fe_or_fc, code, bitR, hopByHop, applicationId, sessionId, resultCode, msisdn, imsi, serviceContextId);
-    response = "Done";
+    anna::testing::TestCase *tc = testManager.getTestCase(id); // creates / reuses
+    tc->addWaitDiameter(fe_or_fc, code, bitR, hopByHop, applicationId, sessionId, resultCode, msisdn, imsi, serviceContextId);
+    response = std::to_string(tc->getId());
   }
   catch(anna::RuntimeException &ex) {
     ex.trace();
index c7a15a7..8429ef4 100644 (file)
@@ -278,7 +278,7 @@ Burst mode only allows single interface interaction. For multiple interface (ori
 
 Adds a new step to the test case with provided identifier. If provided identifier is not registered yet, a new test case will be created with that value and the step will be added as the first. For a specific 'id', the steps are stored in order as they are programmed. Check possible runtime exceptions when adding a new step because those which fail, will be ignored/skipped during test case programming giving an incomplete sequence invalid for the testing purpose.
 
-<id>: integer number, normally monotonically increased for each test case. Some external script/procedure shall clone a test case template in order to build a collection of independent and coherent test cases (normally same type) with different context values (Session-Id, Subscriber-Id, etc.).
+<id>: integer number, normally monotonically increased for each test case. Some external script/procedure shall clone a test case template in order to build a collection of independent and coherent test cases (normally same type) with different context values (Session-Id, Subscriber-Id, etc.). If 0 provided, `id` will be calculated as the current number of test cases plus 1 (normally valid when identification started on value of 1 and no holes were created).
 
 <command>: commands to be executed for the test id provided. Each command programmed constitutes a test case 'step', numbered from 1 to N, with an exception for 'description' which is used to describe the test case:
 
@@ -1242,6 +1242,25 @@ Sends diameter expressed in hexadecimal string (no spaces, no colons, i.e.: `010
 ### FSM testing
 
 ADML implements a bulting *Finite State Machine* to plan testing flows with a great flexibility.
+Every operation will receive a response which  `json` content is as follows:
+
+```json
+{
+    "result":"true",
+    "response":"<test id>"
+}
+```
+
+or
+
+```json
+{
+    "result":"false",
+    "response":"<error hint>"
+}
+```
+
+In case of success operation, the value of the affected test identifier carried in `response` field is useful when zero value was provided to automatically reserve the next test case. In case of error, a brief error description will be carried in that field.
 
 #### POST /testid-description/{id}
 
index 73e9534..ffc57fe 100644 (file)
@@ -8,7 +8,7 @@ def test_001_i_want_check_the_number_of_finished_test_cases_in_the_pool(admlc, a
   response = admlc.postDict("/testid-description/{}".format(flow), { "description":"My test" })
 
   # Verify response
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Send POST
index 5adea9a..029a44f 100644 (file)
@@ -10,7 +10,7 @@ def test_001_i_want_to_move_to_specific_test_and_check_it(admlc, admlf):
   response = admlc.postDict("/testid-description/{}".format(flow), { "description":"testid-description.test_001.flow{}".format(flow) })
 
   # Verify response
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Go to the second test:
@@ -34,7 +34,7 @@ def test_002_i_want_to_move_to_a_test_out_of_range_and_check_it(admlc, admlf):
   response = admlc.postDict("/testid-description/{}".format(flow), { "description":"testid-description.test_001.flow{}".format(flow) })
 
   # Verify response
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Go to the second test:
index dde5330..0a7beb4 100644 (file)
@@ -8,7 +8,7 @@ def test_001_i_want_check_the_number_of_initialized_test_cases_in_the_pool(admlc
   response = admlc.postDict("/testid-description/{}".format(flow), { "description":"My test" })
 
   # Verify response
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Send POST
index d11086b..310c1e1 100644 (file)
@@ -8,7 +8,7 @@ def test_001_i_want_to_make_one_test_non_interactive(admlc, admlf):
   response = admlc.postDict("/testid-ip-limit/{}".format(flow), { "amount":15 })
 
   # Verify response (test & step programmed)
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Send POST (execute the former test)
@@ -29,7 +29,7 @@ def test_002_i_want_to_freeze_a_test(admlc, admlf):
   response = admlc.postDict("/testid-ip-limit/{}".format(flow), { "amount":15 })
 
   # Verify response (test & step programmed)
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Send POST (execute the former test)
index 0d2fb9a..27a3c2b 100644 (file)
@@ -8,7 +8,7 @@ def test_001_i_want_to_look_an_specific_test(b64_encode, resources, admlc, admlf
   response = admlc.postDict("/testid-description/{}".format(flow), { "description":"Look test" })
 
   # Verify response
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Send POST
index 9db4edd..7185cd5 100644 (file)
@@ -8,7 +8,7 @@ def test_001_i_want_to_run_specific_test(admlc, admlf):
   response = admlc.postDict("/testid-ip-limit/{}".format(flow), { "amount":15 })
 
   # Verify response (test & step programmed)
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Send POST (execute the former test)
index f2332f2..5e10cf6 100644 (file)
@@ -8,7 +8,7 @@ def test_001_i_want_to_get_the_state_for_specific_test(admlc, admlf):
   response = admlc.postDict("/testid-description/{}".format(flow), { "description":"Look test" })
 
   # Verify response
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
   admlc.assert_response__status_body_headers(response, 200, responseBodyRef)
 
   # Send POST
index 8978c7e..063bb71 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_i_want_to_set_test_id_delay(admlc, admlf):
   flow = admlf.getId()
 
   requestBody = { "msecs":500 }
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.postDict("/testid-delay/{}".format(flow), requestBody)
index d44cb83..ad98e0e 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_i_want_to_set_test_id_description(admlc, adm
   flow = admlf.getId()
 
   requestBody = { "description":"testid-description.test_001.flow{}".format(flow) }
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.postDict("/testid-description/{}".format(flow), requestBody)
index ed4e330..f7c8a97 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_i_want_to_set_test_id_ip_limit(admlc, admlf)
   flow = admlf.getId()
 
   requestBody = { "amount":5 }
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.postDict("/testid-ip-limit/{}".format(flow), requestBody)
index 19affa3..72cea9c 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_diameter_json_representation_i_want_to_a
   flow = admlf.getId()
 
   requestBody = resources("aar-diameterJsonFromOwnToAF-request.json")
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.post("/testid-sendmsg2c/{}".format(flow), requestBody)
index e25c2ea..c8a55d0 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_diameter_json_representation_i_want_to_a
   flow = admlf.getId()
 
   requestBody = resources("aar-diameterJsonFromOwnToAF-request.json")
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.post("/testid-sendmsg2e/{}".format(flow), requestBody)
index 15c811d..34a4734 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_i_want_to_set_test_id_sh_command(admlc, adml
   flow = admlf.getId()
 
   requestBody = { "script":"date" }
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.postDict("/testid-sh-command/{}".format(flow), requestBody)
index 025b236..03ed32a 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_i_want_to_set_test_id_timeout(admlc, admlf):
   flow = admlf.getId()
 
   requestBody = { "msecs":3000 }
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.postDict("/testid-timeout/{}".format(flow), requestBody)
index ad0e052..bed1543 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_hex_representation_i_want_to_add_test_id
   flow = admlf.getId()
 
   requestBody = { "hex":"01000150c000010901000014" }
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.postDict("/testid-waitfc-hex/{}".format(flow), requestBody)
index 611cb0e..928a0aa 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_diameter_json_representation_i_want_to_a
   flow = admlf.getId()
 
   requestBody = resources("aar-diameterJsonFromOwnToAF-request.json")
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.post("/testid-waitfc-msg/{}".format(flow), requestBody)
index 53d8861..6fd73ca 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_diameter_json_condition_i_want_to_add_te
   flow = admlf.getId()
 
   requestBody = resources("condition-request.json")
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.post("/testid-waitfc/{}".format(flow), requestBody)
index fb579b3..f5dbbc3 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_hex_representation_i_want_to_add_test_id
   flow = admlf.getId()
 
   requestBody = { "hex":"01000150c000010901000014" }
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.postDict("/testid-waitfe-hex/{}".format(flow), requestBody)
index 18d3b4f..dc81d69 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_diameter_json_representation_i_want_to_a
   flow = admlf.getId()
 
   requestBody = resources("aar-diameterJsonFromOwnToAF-request.json")
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.post("/testid-waitfe-msg/{}".format(flow), requestBody)
index e5628de..1fbbaa0 100644 (file)
@@ -6,7 +6,7 @@ def test_001_given_test_indentifier_and_diameter_json_condition_i_want_to_add_te
   flow = admlf.getId()
 
   requestBody = resources("condition-request.json")
-  responseBodyRef = { "success":"true", "response":"Done" }
+  responseBodyRef = { "success":"true", "response":str(flow) }
 
   # Send POST
   response = admlc.post("/testid-waitfe/{}".format(flow), requestBody)
index 916177a..a6b0c21 100644 (file)
@@ -178,7 +178,7 @@ class TestManager : public anna::timex::TimeEventObserver, public anna::Singleto
     bool runTestCase(unsigned int id) ;
     TestCase *findTestCase(unsigned int id) const ; // id = -1 provides current test case triggered
     TestCase *getTestCase(unsigned int id, const std::string &description = "") ; // creates/reuses a test case
-
+                                                                                  // provide 0 to reserve the id = tests() + 1
     // Diameter-specific
     TestCase *getDiameterTestCaseFromSessionId(const anna::DataBlock &message, std::string &sessionId) ;
     TestCase *getDiameterTestCaseFromSubscriberId(const anna::DataBlock &message, std::string &subscriberId) ;
index 87278f1..e90d20d 100644 (file)
@@ -287,6 +287,10 @@ TestCase *TestManager::findTestCase(unsigned int id) const { // id = -1 provides
 
 TestCase *TestManager::getTestCase(unsigned int id, const std::string &description) {
 
+  if (id == 0) { // 0 is used to sequence automatically and get the value of 'tests() + 1'
+    id = tests() + 1;
+  }
+
   test_pool_nc_it it = a_testPool.find(id);
   if (it != a_testPool.end()) return it->second;