Remove operation help.
authorEduardo Ramos Testillano (eramedu) <eduardo.ramos.testillano@ericsson.com>
Tue, 28 Apr 2020 14:20:15 +0000 (16:20 +0200)
committerEduardo Ramos Testillano (eramedu) <eduardo.ramos.testillano@ericsson.com>
Tue, 28 Apr 2020 14:20:15 +0000 (16:20 +0200)
Created a new version in file: HELP.md

22 files changed:
example/diameter/launcher/Launcher.cpp
example/diameter/launcher/Launcher.hpp
example/diameter/launcher/MyHandler.cpp
example/diameter/launcher/deploy-adml-http.sh
example/diameter/launcher/deploy-aots.sh
example/diameter/launcher/deploy.sh
example/diameter/launcher/deployments/advanced/README
example/diameter/launcher/deployments/advanced/help.sh [deleted file]
example/diameter/launcher/deployments/basic/README
example/diameter/launcher/deployments/basic/configure.sh
example/diameter/launcher/deployments/ft-client/README
example/diameter/launcher/deployments/st-client/README
example/diameter/launcher/deployments/st-client/operation_all.sh
example/diameter/launcher/deployments/st-client/program.sh
example/diameter/launcher/deployments/st-client/services_example/dictionaryBase.xml
example/diameter/launcher/deployments/st-client/services_example/dictionaryGx.xml
example/diameter/launcher/deployments/st-client/services_example/dictionaryRx.xml
example/diameter/launcher/main.cpp
example/diameter/launcher/resources/HELP.md [new file with mode: 0644]
example/diameter/launcher/resources/scripts/operation_curl.sh
example/diameter/launcher/resources/scripts/operation_signal.sh
example/diameter/launcher/resources/services_examples/services.dtd

index 07c2e1b..0c4a5bd 100644 (file)
@@ -118,8 +118,8 @@ const char *ServicesDTD = "\
    log:                                     Process log file (operations result, traffic log, etc.). By default '<originHost>.launcher.log'.\n\
                                             Empty string or \"null\" name, to disable. Warning: there is no rotation for log files\n\
                                             (use logrotate or whatever you consider).\n\
-   splitLog:                                Splits log file (appends to log filename, extensions with the type of event: see help on\n\
-                                            startup information-level traces). No log files for code/decode and load operations are created.\n\
+   splitLog:                                Splits log file (appends to log filename, extensions with the type of event.\n\
+                                            (Check 'HELP.md' for more information). No log files for code/decode and load operations are created.\n\
                                             Default value 'no'.\n\
    detailedLog:                             Insert detailed information at log files (timestamps, communication resources, etc.). Useful\n\
                                             to analyze the messages flow along the sockets (specially on 'balance' mode). Default 'no'.\n\
@@ -644,8 +644,6 @@ throw(anna::RuntimeException) {
   anna::statistics::Engine::instantiate().enable();
 
   LOGINFORMATION(
-      // Help on startup traces:
-      anna::Logger::information(help(), ANNA_FILE_LOCATION);
   // Test messages dtd:
   std::string msg = "\n                     ------------- TESTMESSAGES DTD -------------\n";
   msg += anna::diameter::codec::MessageDTD;
@@ -926,670 +924,6 @@ void Launcher::signalUSR2() throw(anna::RuntimeException) {
   out_file.close();
 }
 
-std::string Launcher::help() const throw() {
-  std::string result = "\n";
-  result += "\n                     ------------- HELP -------------\n";
-  result += "\n";
-  result += "\nOVERVIEW";
-  result += "\n--------";
-  result += "\n";
-  result += "\nThe ADML (ANNA Diameter MultiHost Launcher) process is a multi-host node with client and server";
-  result += "\n capabilities as well as balancer (proxy) features. It could be used as diameter server (i.e. to";
-  result += "\n simulate PCRF nodes, OCS systems, etc.), as diameter client (GGSNs, DPIs, etc.), and balancer";
-  result += "\n systems to provide failover to external round-robin launchers. Also, auxiliary encoder/decoder/loader";
-  result += "\n function could be deployed to reinterpret certain external flow and send it to another process.";
-  result += "\n ";
-  result += "\nThe ANNA::diameter_comm built-in module provides a great set of characteristics as multiple connections";
-  result += "\n on both server and client side, definition for multiple-server entities (and not only two as standard";
-  result += "\n establish as minimum), separate statistics analyzer per each resource, automatic CER/CEA and DWR/DWA";
-  result += "\n generation, expiration control and many more features.";
-  result += "\n";
-  result += "\nThe ADML process can easily configure a many origin-host nodes as needed, which will have own endpoints.";
-  result += "\nYou should avoid loop configurations (client and server for that client) because automatic forwarding,";
-  result += "\n is implemented and this would get in a never ending cycle when a request is sent.";
-  result += "\n";
-  result += "\nProcess traces are dump on \"launcher.trace\" and could have any trace level (POSIX levels), usually";
-  result += "\n 'debug' or 'warning'. See ANNA documentation for more details.";
-  result += "\n";
-  result += "\nAs any other ANNA process, context dump could be retrieved sending SIGUSR1 signal:";
-  result += "\n   kill -10 <pid>";
-  result += "\n    or";
-  result += "\n   kill -s SIGUSR1 <pid>";
-  result += "\n    and then";
-  result += "\n   vi /var/tmp/anna.context.<pid>";
-  result += "\n";
-  result += "\nA complete xml report will show all the context information (counters, alarms, statistics,";
-  result += "\n handlers, diameter stacks, etc.), and a powerful log module could dump all the events";
-  result += "\n processed and flow information. Statistics could be analized at context dump and optionally";
-  result += "\n written to disk as sample files (useful for graphs and spreadsheet reports) with all the";
-  result += "\n measurements.";
-  result += "\n";
-  result += "\nAlso SIGUSR2 is handled for management purposes. We will talk later about this.";
-  result += "\n";
-  result += "\n";
-  result += "\nCOMMAND LINE";
-  result += "\n------------";
-  result += "\n";
-  result += "\nStart the launcher process without arguments in order to see all the startup configuration";
-  result += "\n posibilities, many of which could be modified on the air through the management interface";
-  result += "\n (we will talk later about this great feature). There is only one mandatory parameter which";
-  result += "\n is the services definition: --services <services xml file>. You must follow the dtd schema";
-  result += "\n to build a valid services xml file. Some basic examples are:";
-  result += "\n";
-  result += "\nClient configuration:";
-  result += "\n";
-  result += "\n<services>";
-  result += "\n  <!-- Stacks -->";
-  result += "\n  <stack id=\"0\" dictionary=\"dictionary.xml\"/>";
-  result += "\n";
-  result += "\n  <!-- Nodes -->";
-  result += "\n  <node originHost=\"ADML-client\" applicationId=\"0\" entity=\"localhost:3868\"/>";
-  result += "\n</services>";
-  result += "\n";
-  result += "\nServer configuration:";
-  result += "\n";
-  result += "\n<services>";
-  result += "\n  <!-- Stacks -->";
-  result += "\n  <stack id=\"0\" dictionary=\"dictionary.xml\"/>";
-  result += "\n";
-  result += "\n  <!-- Nodes -->";
-  result += "\n  <node originHost=\"ADML-server\" applicationId=\"0\" diameterServer=\"localhost:3868\"/>";
-  result += "\n</services>";
-  result += "\n";
-  result += "\nIf you act as a proxy or a translation agent, you need to combine both former setups, and probably";
-  result += "\n will need to program the answers to be replied through the operations interface. To balance the";
-  result += "\n traffic at your client side you shall use '--balance' and '--sessionBasedModelsClientSocketSelection'";
-  result += "\n arguments in order to define the balancing behaviour. To make hybrid setups you only must mix the nodes:";
-  result += "\n";
-  result += "\nClient and server configuration:";
-  result += "\n";
-  result += "\n<services>";
-  result += "\n  <!-- Stacks -->";
-  result += "\n  <stack id=\"16777236\" dictionary=\"dictionary_Rx.xml\"/>";
-  result += "\n  <stack id=\"16777238\" dictionary=\"dictionary_Gx.xml\"/>";
-  result += "\n  <stack id=\"0\" dictionary=\"dictionary_base.xml\"/>";
-  result += "\n";
-  result += "\n  <!-- Nodes -->";
-  result += "\n  <node originHost=\"ADML-Rx-client\" applicationId=\"16777236\" entity=\"localhost:3868\" cer=\"cer_Rx.xml\"/>";
-  result += "\n  <node originHost=\"ADML-Gx-client\" applicationId=\"16777238\" entity=\"localhost:3868\" cer=\"cer_Gx.xml\"/>";
-  result += "\n</services>";
-  result += "\n";
-  result += "\n";
-  result += "\nThe process builds automatically CER and DWR messages as a client, but you could specify your own";
-  result += "\n as shown in the hybrid former example. Note that the base protocol stack must be registered because";
-  result += "\n the configuration corresponds to a multistack process which change the stack using the application-id";
-  result += "\n processed (0 in the case of base protocol messages: CER, CEA, DWR, DWA, DPR, DPA).";
-  result += "\n";
-  result += "\nDYNAMIC OPERATIONS";
-  result += "\n------------------";
-  result += "\n";
-  result += "\nADML supports several operations which could be reconized via HTTP interface or SIGUSR2 caugh.";
-  result += "\nAn operation is specified by mean a string containing the operation name and needed arguments";
-  result += "\n separated by pipes. These are the available commands:";
-  result += "\n";
-  result += "\n--------------------------------------------------------------------------------------- General purpose";
-  result += "\n";
-  result += "\nhelp                                 This help.";
-  result += "\n";
-  result += "\n--------------------------------------------------------------------------------------- Node management";
-  result += "\n";
-  result += "\nnode[|<name>]                         Selects a context working node by mean a registered name (origin-host).";
-  result += "\n                                      All the subsequent operations will be forced to work with";
-  result += "\n                                      this node, which makes possible some rare scenarios like";
-  result += "\n                                      sending unexpected messages on remote peers. This is also";
-  result += "\n                                      useful for some operations in order to restrict the scope";
-  result += "\n                                      of action (statistics, communication visibility, etc.).";
-  result += "\n                                      Empty parameter will show the current configuration.";
-  result += "\n";
-  result += "\nnode_auto                             Returns to the default behaviour (smart node selection).";
-  result += "\n                                      Depending on the operation, this could imply a global";
-  result += "\n                                      action scope, affecting to all the registered hosts.";
-  result += "\n                                      This should be the normal configuration. Take into";
-  result += "\n                                      account that if you fix the working node, this could";
-  result += "\n                                      affect to things like test programming: communication";
-  result += "\n                                      resources will override those which would be inferred";
-  result += "\n                                      from programmed messages Origin-Host avps.";
-  result += "\n";
-  result += "\n------------------------------------------------------------------------------------ Parsing operations";
-  result += "\n";
-  result += "\ncode|<source_file>|<target_file>     Encodes source file (pathfile) into target file (pathfile).";
-  result += "\ndecode|<source_file>|<target_file>   Decodes source file (pathfile) into target file (pathfile).";
-  result += "\nloadxml|<source_file>                Reinterpret xml source file (pathfile).";
-  result += "\n";
-  result += "\n------------------------------------------------------------------------------------------- Hot changes";
-  result += "\n";
-  result += "\nservices[|source file]               Adds and starts the services specified in the xml file provided.";
-  result += "\n                                      (if missing, the file 'services.xml' will be used). This is used";
-  result += "\n                                      to load new nodes once the ADML is started, regardless if command";
-  result += "\n                                      line '--services' parameter was used or not. Those services which";
-  result += "\n                                      are not correctly loaded will be ignored to keep the process alive.";
-  result += "\n                                     If you need to load services as deltas, you must firstly load the";
-  result += "\n                                      diameter base dictionary with stack id 0, because all the nodes";
-  result += "\n                                      will use this dictionary to encode/decode base protocol messages";
-  result += "\n                                      managed by the communication engine.";
-  result += "\n";
-  result += "\ndiameterServerSessions|<integer>     Updates the maximum number of accepted connections to diameter";
-  result += "\n                                      server socket.";
-  result += "\ncontext[|target file]                Application context could also be written by mean this operation,";
-  result += "\n                                      and not only through SIGUSR1. If optional path file is missing,";
-  result += "\n                                      default '/var/tmp/anna.context.<pid>' will be used.";
-  result += "\ncollect                              Reset statistics and counters to start a new test stage of";
-  result += "\n                                      performance measurement. Context data can be written at";
-  result += "\n                                      '/var/tmp/anna.context.<pid>' by mean 'kill -10 <pid>'.";
-  result += "\n                                      or sending operation 'context|[target file]'.";
-  result += "\n                                     This operation applies over all the registered host nodes";
-  result += "\n                                      except if one specific working node has been set.";
-  result += "\nforceCountersRecord                  Forces dump to file the current counters of the process.";
-  result += "\nlog-statistics-samples|<list>        Log statistics samples for the provided comma-separated concept id";
-  result += "\n                                      list, over './sample.<concept id>.csv' files. For example: \"1,2\"";
-  result += "\n                                      will log concepts 1 and 2. Reserved words \"all\"/\"none\" activates/";
-  result += "\n                                      deactivates all registered statistics concept identifiers. That ids";
-  result += "\n                                      are shown at context dump.";
-  result += "\nchange-dir[|directory]               Changes the execution point which could be fine to ease some";
-  result += "\n                                     file system interaction tasks. Be care about some requirements";
-  result += "\n                                     (for example if you have a user defined counters directory as";
-  result += "\n                                     relative path this must exists from the new execution directory).";
-  result += "\n                                     If nothing provided, initial working directory will be restored.";
-  result += "\nshow-oam                             Dumps current counters of the process. This is also done at";
-  result += "\n                                      process context dump.";
-  result += "\nshow-stats                           Dumps statistics of the process. This is also done at process";
-  result += "\n                                      context dump.";
-  result += "\n";
-  result += "\n<visibility action>[|<address>:<port>][|socket id]";
-  result += "\n";
-  result += "\n       Actions: hide, show (update state) and hidden, shown (query state).";
-  result += "\n       Acts over a client session for messages delivery (except CER/A, DWR/A, DPR/A).";
-  result += "\n       If missing server (first parameter) all applications sockets will be affected.";
-  result += "\n       If missing socket (second parameter) for specific server, all its sockets will be affected.";
-  result += "\n";
-  result += "\n       All application client sessions are shown on startup, but standard delivery only use primary";
-  result += "\n        server ones except if fails. Balance configuration use all the allowed sockets. You could also";
-  result += "\n        use command line 'sessionBasedModelsClientSocketSelection' to force traffic flow over certain";
-  result += "\n        client sessions, but for this, hide/show feature seems easier.";
-  result += "\n";
-  result += "\n--------------------------------------------------------------------------------------- Flow operations";
-  result += "\n";
-  result += "\nsendxml2e|<source_file>    Sends xml source file (pathfile) through configured entity.";
-  result += "\nsendxml2c|<source_file>    Sends xml source file (pathfile) to client.";
-  result += "\nanswerxml2e[|source_file]  Answer xml source file (pathfile) for incoming request with same code from entity.";
-  result += "\n                           The answer is stored in a FIFO queue for a specific message code, then there are";
-  result += "\n                           as many queues as different message codes have been programmed.";
-  result += "\nanswerxml2c[|source_file]  Answer xml source file (pathfile) for incoming request with same code from client.";
-  result += "\n                           The answer is stored in a FIFO queue for a specific message code, then there are";
-  result += "\n                           as many queues as different message codes have been programmed.";
-  result += "\nanswerxml<2e/2c>           List programmed answers (to entity/client) if no parameter provided.";
-  result += "\nanswerxml<2e/2c>|dump      Write programmed answers (to entity/client) to file 'programmed_answer.<message code>.<sequence>',";
-  result += "\n                           where 'sequence' is the order of the answer in each FIFO code-queue of programmed answers.";
-  result += "\nanswerxml<2e/2c>|clear     Clear programmed answers (to entity/client).";
-  result += "\nanswerxml<2e/2c>|exhaust   Disable the corresponding queue rotation, which is the default behaviour.";
-  result += "\nanswerxml<2e/2c>|rotate    Enable the corresponding queue rotation, useful in performance tests.";
-  result += "\n                           Rotation consists in add again to the queue, each element retrieved for answering.";
-  result += "\n";
-  result += "\nSend operations are available using hexadecimal content (hex formatted files) which also allow to test";
-  result += "\nspecial scenarios (protocol errors):";
-  result += "\n";
-  result += "\nsendhex2e|<source_file>    Sends hex source file (pathfile) through configured entity.";
-  result += "\nsendhex2c|<source_file>    Sends hex source file (pathfile) to client.";
-  result += "\n";
-  result += "\nAnswer programming in hexadecimal is not really neccessary (you could use send primitives) and also";
-  result += "\n is intended to be used with decoded messages in order to replace things like hop by hop, end to end,";
-  result += "\n subscriber id, session id, etc. Anyway you could use 'decode' operation and then program the xml created.";
-  result += "\n";
-  result += "\nIf a request is received, answer map (built with 'answerxml<2e/2c>' operations) will be";
-  result += "\n checked to find a corresponding programmed answer to be replied(*). If no ocurrence is found,";
-  result += "\n or answer message was received, the message is forwarded to the other side (entity or client),";
-  result += "\n or nothing but trace when no peer at that side is configured. Answer to client have sense when";
-  result += "\n diameter server socket is configured, answer to entity have sense when entity does.";
-  result += "\n";
-  result += "\nIn the most complete situation (process with both client and server side) there are internally";
-  result += "\n two maps with N FIFO queues, one for each different message code within programmed answers.";
-  result += "\nOne map is for answers towards the client, and the other is to react entity requests. Then in";
-  result += "\n each one we could program different answers corresponding to different request codes received.";
-  result += "\n";
-  result += "\n(*) sequence values (hop-by-hop and end-to-end), Session-Id and Subscription-Id avps, are mirrored";
-  result += "\n    to the peer which sent the request. If user wants to test a specific answer without changing it,";
-  result += "\n    use sendxml<2e/2c>/sendhex<2e/2c> operations better than programming.";
-  result += "\n";
-  result += "\nBalance ('--balance' command line parameter) could be used to forward server socket receptions through";
-  result += "\n entity servers by mean a round-robin algorithm. Both diameter server socket and entity targets should";
-  result += "\n have been configured, that is to say: launcher acts as client and server. If no balance is used, an";
-  result += "\n standard delivery is performed: first primary entity server, secondary when fails, etc.";
-  result += "\n";
-  result += "\n--------------------------------------------------------------------------- Processing types (log tags)";
-  result += "\n";
-  result += "\nUsed as log file extensions (when '--splitLog' is provided on command line) and context preffixes on log";
-  result += "\n details when unique log file is dumped:";
-  result += "\n";
-  result += "\n   [sent2e/send2eError]   Send to entity (success/error)";
-  result += "\n   [sent2c/send2cError]   Send to client (success/error)";
-  result += "\n   [fwd2e/fwd2eError]     Forward to entity a reception from client (success/error)";
-  result += "\n   [fwd2c/fwd2cError]     Forward to client a reception from entity (success/error)";
-  result += "\n   [recvfc]               Reception from client";
-  result += "\n   [recvfe]               Reception from entity";
-  result += "\n   [req2c-expired]        A request sent to client has been expired";
-  result += "\n   [req2e-expired]        A request sent to entity has been expired";
-  result += "\n   [recvfc-ans-unknown]   Reception from client of an unknown answer (probably former [req2c-expired]";
-  result += "\n                           has been logged)";
-  result += "\n   [recvfe-ans-unknown]   Reception from entity of an unknown answer (probably former [req2e-expired]";
-  result += "\n                           has been logged)";
-  result += "\n   [retry]                Request retransmission";
-  result += "\n";
-  result += "\n------------------------------------------------------------------------------------------- Burst tests";
-  result += "\n";
-  result += "\nIn order to simplify user experience, burst category operations are only allowed in single host node";
-  result += "\n configuration. Indeed, you could send messages with unmatched Origin-Host, and no warning is shown.";
-  result += "\nAll the operations are performed through the unique host: if you need to use more interfaces, you may";
-  result += "\n launch different ADML instances. Is nonsense to allow burst in a multi-host configured ADML, because";
-  result += "\n this feature is not able to coordinate the messages.";
-  result += "\n";
-  result += "\nburst|<action>[|parameter]     Used for performance testing, we first program diameter requests";
-  result += "\n                                messages in order to launch them from client side to the configured";
-  result += "\n                                diameter entity. We could start the burst with an initial load";
-  result += "\n                                (non-asynchronous sending), after this, a new request will be sent";
-  result += "\n                                per answer received or expired context. There are 10 actions: clear,";
-  result += "\n                                load, start, push, pop, stop, repeat, send, goto and look.";
-  result += "\n";
-  result += "\n   burst|clear                 Clears all loaded burst messages.";
-  result += "\n   burst|load|<source_file>    Loads the next diameter message into launcher burst.";
-  result += "\n   burst|start|<initial load>  Starts (or restarts if already in progress) the message sending with";
-  result += "\n                                a certain initial load.";
-  result += "\n   burst|push|<load amount>    Sends specific non-aynchronous load.";
-  result += "\n   burst|pop|<release amount>  Skip send burst messages in order to reduce over-the-air requests.";
-  result += "\n                               Popping all OTA requests implies burst stop because no more answer";
-  result += "\n                                will arrive to the process. Burst output file (--burstLog command";
-  result += "\n                                line parameter) shows popped messages with crosses (x). Each cross";
-  result += "\n                                represents one received answer for which no new request is sent.";
-  result += "\n   burst|stop                  Stops the burst cycle. You can resume pushing 1 load amount.";
-  result += "\n   burst|repeat[|[yes]|no]     Restarts the burst launch when finish. If initial load or push load";
-  result += "\n                                amount is greater than burst list size, they will be limited when";
-  result += "\n                                the list is processed except when repeat mode is enabled.";
-  result += "\n   burst|send|<amount>         Sends messages from burst list. The main difference with start/push";
-  result += "\n                                operations is that burst won't be awaken. Externally we could control";
-  result += "\n                                sending time (no request will be sent for answers).";
-  result += "\n   burst|goto|<order>          Updates current burst pointer position.";
-  result += "\n   burst|look[|order]          Show programmed burst message for order provided, current when missing.";
-  result += "\n";
-  result += "\n-------------------------------------------------------------------------------------- Advanced testing";
-  result += "\n";
-  result += "\n                           Burst mode only allows single interface interaction. For multiple interface";
-  result += "\n                            (origin-host) coordination, you could use the advanced test cases programming:";
-  result += "\n";
-  result += "\n";
-  result += "\n   test|<id>|<command>[|parameters]";
-  result += "\n";
-  result += "\n                           Adds a new step to the test case with provided identifier. If provided identifier";
-  result += "\n                            is not registered yet, a new test case will be created with that value and the";
-  result += "\n                            step will be added as the first. For a specific 'id', the steps are stored in";
-  result += "\n                            order as they are programmed. Check possible runtime exceptions when adding a";
-  result += "\n                            new step because those which fail, will be ignored/skipped during test case";
-  result += "\n                            programming giving an incomplete sequence invalid for the testing purpose.";
-  result += "\n";
-  result += "\n                           <id>: integer number, normally monotonically increased for each test case. Some external";
-  result += "\n                                 script/procedure shall clone a test case template in order to build a collection";
-  result += "\n                                 of independent and coherent test cases (normally same type) with different context";
-  result += "\n                                 values (Session-Id, Subscriber-Id, etc.).";
-  result += "\n";
-  result += "\n                           <command>: commands to be executed for the test id provided. Each command programmed";
-  result += "\n                                      constitutes a test case 'step', numbered from 1 to N, with an exception for";
-  result += "\n                                      'description' which is used to describe the test case:";
-  result += "\n";
-  result += "\n                              description|<description>  Sets a test case description. Test cases by default are";
-  result += "\n                                                          constructed with description 'Testcase_<id>'.";
-  result += "\n";
-  result += "\n                              ip-limit[|amount]          In-progress limit of test cases controlled from this test.";
-  result += "\n                                                         No new test cases will be launched over this value (test";
-  result += "\n                                                         manager tick work will be ignored). Zero-value is equivalent";
-  result += "\n                                                         to stop the clock tick, -1 is used to specify 'no limit' which";
-  result += "\n                                                         is the default. For missing amount, value of 1 is applied.";
-  result += "\n";
-  result += "\n                              timeout|<msecs>            Sets an asynchronous timer to restrict the maximum timeout";
-  result += "\n                                                          until last test step. Normally, this command is invoked";
-  result += "\n                                                          in the first step, anyway it measures the time from the";
-  result += "\n                                                          execution point whatever it is. The expiration will abort";
-  result += "\n                                                          the test if still running. One or more timeouts could be";
-  result += "\n                                                          programmed (not usual), but the more restrict will apply.";
-  result += "\n                                                         It is highly recommended to program a initial timeout step,";
-  result += "\n                                                          or the test case could be eternally in-progress.";
-  result += "\n";
-  result += "\n                              sendxml2e|<source_file>[|<step number>]";
-  result += "\n                                                         Sends xml source file (pathfile) to entity (it would be a";
-  result += "\n                                                          'forward' event if it came through local server endpoint).";
-  result += "\n                                                         Take into account that the xml message is encoded just on";
-  result += "\n                                                          call. The xml file is not longer needed neither interpreted";
-  result += "\n                                                          in case of modification, after calling this command.";
-  result += "\n                                                         The step number should be provided for answers to indicate";
-  result += "\n                                                          the 'wait for request' corresponding step. If you miss this";
-  result += "\n                                                          reference, the sequence information (hop-by-hop, end-to-end)";
-  result += "\n                                                          will be sent as they are in the answer xml message (realize";
-  result += "\n                                                          the difficulty of predicting these information). Be sure to";
-  result += "\n                                                          refer to a 'wait for request' step. Conditions like 'regexp'";
-  result += "\n                                                          (as we will see later) are not verified.";
-  result += "\n                                                         In the case of requests, the step number is used to force the";
-  result += "\n                                                          copy of Session-Id value from the referred step.";
-  result += "\n";
-  result += "\n                              sendxml2c|<source_file>[|<step number>]";
-  result += "\n                                                         Sends xml source file (pathfile) to client (it would be a";
-  result += "\n                                                          'forward' event if it came through remote server endpoint).";
-  result += "\n                                                         Same commented for 'sendxml2e' regarding the step number.";
-  result += "\n";
-  result += "\n                              delay|<msecs>              Blocking step until the time lapse expires. Useful to give ";
-  result += "\n                                                          some cadence control and time schedule for a specific case.";
-  result += "\n                                                         A value of 0 could be used as a dummy step.";
-  result += "\n";
-  result += "\n                              sh-command|<script>        External execution for script/executable via shell through a dedicated";
-  result += "\n                                                          thread, providing the command and parameters. You could use dynamic";
-  result += "\n                                                          variables ##<tag> to have more flexibility:";
-  result += "\n                                                             Test pool cycle id: "; result += SH_COMMAND_TAG_FOR_REPLACE__CYCLE_ID;
-  result += "\n                                                             Test case id:       "; result += SH_COMMAND_TAG_FOR_REPLACE__TESTCASE_ID;
-  result += "\n                                                             Test step id:       "; result += SH_COMMAND_TAG_FOR_REPLACE__TESTSTEP_ID;
-  result += "\n";
-  result += "\n                                                         For example, your command could be something like this:";
-  result += "\n                                                          insert_sql_"; result += SH_COMMAND_TAG_FOR_REPLACE__TESTCASE_ID; result += ".sh -db dbname --verbose";
-  result += "\n                                                             > /tmp/cycle-"; result += SH_COMMAND_TAG_FOR_REPLACE__CYCLE_ID;
-  result += ".testcase-"; result += SH_COMMAND_TAG_FOR_REPLACE__TESTCASE_ID;
-  result += ".teststep-"; result += SH_COMMAND_TAG_FOR_REPLACE__TESTSTEP_ID;
-  result += ".out";
-  result += "\n                                                         Try to redirect stdout and stderr to avoid ADML output contamination";
-  result += "\n                                                          with the possible outputs from the scripts. You could also put your";
-  result += "\n                                                          job in background although sh-command will return 0-value immediately.";
-  result += "\n";
-  result += "\n                              wait<fe/fc>-hex|<source_file>[|strict]";
-  result += "\n                                                         Wait condition, from entity (waitfe-hex) or client (waitfc-hex) to";
-  result += "\n                                                          match the hexadecimal representation for received messages against";
-  result += "\n                                                          source file (hex format). Fix mode must be enabled to avoid unexpected";
-  result += "\n                                                          matching behaviour. Specify 'strict' to use the hex content 'as is'.";
-  result += "\n                                                          If not, the hex content will be understood as whole message and then,";
-  result += "\n                                                          borders will be added (^<content>$) and sequence information bypassed";
-  result += "\n                                                          even for diameter answers.";
-  result += "\n";
-  result += "\n                              wait<fe/fc>-xml|<source_file>[|strict]";
-  result += "\n                                                         Wait condition from entity (waitfe-xml) or client (waitfc-xml) to";
-  result += "\n                                                          match the serialized xml content for received messages against";
-  result += "\n                                                          source file (xml representation). Fix mode must be enabled to avoid";
-  result += "\n                                                          unexpected matching behaviour. If you need a strict matching you";
-  result += "\n                                                          must add parameter 'strict', if not, regexp is built ignoring sequence";
-  result += "\n                                                          information (hop-by-hop-id=\"[0-9]+\" end-to-end-id=\"[0-9]+\") and";
-  result += "\n                                                          Origin-State-Id value.";
-  result += "\n                                                          All LF codes will be internally removed when comparison is executed";
-  result += "\n                                                          in order to ease xml content configuration.";
-  result += "\n";
-  result += "\n                              wait<fe/fc>|<condition>    Blocking step until condition is fulfilled. The message could";
-  result += "\n                                                          received from entity (waitfe) or from client (waitfc).";
-  result += "\n                                                         CPU cost is lower than former 'wait<fe/fc>-<xml|hex>' variants.";
-  result += "\n";
-  result += "\n                                          <condition>: Optional parameters which must be fulfilled to continue through the next step.";
-  result += "\n                                                       Any received message over diameter interfaces will be evaluated against the";
-  result += "\n                                                        corresponding test case starting from the current step until the first one";
-  result += "\n                                                        whose condition is fulfilled. If no condition is fulfilled the event will be";
-  result += "\n                                                        classified as 'uncovered' (normally a test case bad configuration, or perhaps";
-  result += "\n                                                        a real unexpected message).";
-
-  // TODO(***)
-  //  result += "\n                                        The way to identify the test case, is through registered Session-Id values for";
-  //  result += "\n                                         programmed requests. But this depends on the type of node. Acting as clients,";
-  //  result += "\n                                         requests received have Session-Id values which are already registered with";
-  //  result += "\n                                         one test case, causing an error if not found. Acting as servers, requests are";
-  //  result += "\n                                         received over a diameter local server from a client which are generating that";
-  //  result += "\n                                         Session-Id values. Then we know nothing about such values. The procedure in";
-  //  result += "\n                                         this case is find out a test case not-started containing a condition which";
-  //  result += "\n                                         comply with the incoming message, and reactivates it.";
-  // The other solution: register Session-Id values for answers send to client from a local diameter server.
-
-  result += "\n                                                       How to answer: a wait condition for a request will store the incoming message";
-  result += "\n                                                        which fulfills that condition. This message is useful together with the peer";
-  result += "\n                                                        connection source in a further send step configured with the corresponding";
-  result += "\n                                                        response. You could also insert a delay between wait and send steps to be";
-  result += "\n                                                        more realistic (processing time simulation in a specific ADML host node).";
-  result += "\n                                                        Always, a response send step will get the needed information from the most";
-  result += "\n                                                        recent wait step finding in reverse order (note that some race conditions";
-  result += "\n                                                        could happen if your condition is not specific enough).";
-
-  result += "\n";
-  result += "\n                                                       Condition format:";
-  result += "\n";
-  result += "\n                                                          [code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]";
-  result += "\n";
-  result += "\n                                                            code: integer number";
-  result += "\n                                                            bitR: 1 (request), 0 (answer)";
-  result += "\n                                                            hopByHop: integer number or request send step reference: #<step number>";
-  result += "\n";
-  result += "\n                                                                      Using the hash reference, you would indicate a specific wait condition";
-  result += "\n                                                                       for answers. The step number provided must correspond to any of the";
-  result += "\n                                                                       previous send commands (sendxml2e/sendxml2c) configured for a request.";
-  result += "\n                                                                      This 'hop-by-hop' variant eases the wait condition for answers in the";
-  result += "\n                                                                       safest way.";
-  result += "\n";
-  result += "\n                                                            applicationId: integer number";
-  result += "\n                                                            sessionId: string";
-  result += "\n                                                            resultCode: integer number";
-  result += "\n                                                            msisdn: string";
-  result += "\n                                                            imsi: string";
-  result += "\n                                                            serviceContextId: string";
-  result += "\n";
-  result += "\n                                                       Take into account these rules, useful in general:";
-  result += "\n";
-  result += "\n                                                          - Be as much specific as possible defining conditions to avoid ambiguity sending";
-  result += "\n                                                            messages out of context due to race conditions. Although you could program several";
-  result += "\n                                                            times similar conditions, some risky practices will throw a warning trace (if you";
-  result += "\n                                                            repeat the same condition within the same test case).";
-  result += "\n                                                          - Adding a ResultCode and/or HopByHop to the condition are only valid waiting answers.";
-  result += "\n                                                          - Requests hop-by-hop values must be different for all the test case requests.";
-  result += "\n                                                            RFC says that a hop by hop must be unique for a specific connection, something that";
-  result += "\n                                                            could be difficult to manage if we have multiple available connections from client";
-  result += "\n                                                            side endpoint (entity or local server), even if we would have only one connection but";
-  result += "\n                                                            several host interfaces. It is enough to configure different hop-by-hop values within";
-  result += "\n                                                            each test case, because on reception, the Session-Id is used to identify that test case.";
-  result += "\n";
-  result += "\n";
-  result += "\n";
-  result += "\n";
-  result += "\n                           Programming example:";
-  result += "\n";
-  result += "\n                              Basic Rx/Gx scenary: PCEF (Gx) - PCRF - AF (Rx)";
-  result += "\n";
-  result += "\n                              test|1|timeout|5000                  (step 1: whole time requirement is 5 seconds)";
-  result += "\n                              test|1|sendxml2e|CCR-I.xml           (step 2: imagine this xml uses the Session-Id 'SGx')";
-  result += "\n                              test|1|waitfe|272|0|||SGx|2001       (step 3: waits the CCA for the CCR-I with Result-Code = DIAMETER_SUCCESS)";
-  result += "\n                              test|1|sendxml2e|AAR-flows.xml       (step 4: imagine this xml uses the Session-Id 'SRx')";
-  result += "\n                              test|1|waitfe|265|0|||SRx|2001       (step 5: waits the AAA for the AAR-flows with Result-Code = DIAMETER_SUCCESS)";
-  result += "\n                              test|1|waitfe|258|1|||SGx            (step 6: waits the RAR (install policies) from the PCRF server)";
-  result += "\n                              test|1|sendxml2e|RAA-install.xml|6   (step 7: sends the response for the RAR)";
-  result += "\n                              test|1|sendxml2e|CCR-T.xml           (step 8: termination of the Gx session, imagine this xml puts hop-by-hop 'H1')";
-  result += "\n                              test|1|waitfe|272|0|H1||SGx|2001     (step 9: waits the CCA for the CCR-T with Result-Code = DIAMETER_SUCCESS and hop-by-hop 'H1')";
-  result += "\n                              test|1|waitfe|258|1|||SGx            (step 10: waits the RAR (remove policies) from the PCRF server)";
-  result += "\n                              test|1|sendxml2e|RAA-remove.xml|10   (step 11: sends the response for the RAR)";
-  result += "\n";
-  result += "\n                              Notes: We added an additional condition in step 9: the hop-by-hop. When we program the corresponding";
-  result += "\n                                      source request (CCR-T), we configured the value 'H1' for the hop-by-hop. This is an 'application";
-  result += "\n                                      value' because the real hop-by-hop transported through the client connection is managed by the";
-  result += "\n                                      diameter stack. But when returned, the transaction pool resolve the original value. This feature";
-  result += "\n                                      is necessary to ease the implementation of certain diameter agents (proxies for example). In our";
-  result += "\n                                      case, we could format the hop-by-hop values within the request templates with total freedom to";
-  result += "\n                                      improve the programmed conditions.";
-  result += "\n";
-  result += "\n                                     In the case of 'waiting for requests' is not such easy. Indeed, steps 6 and 10 will write a warning";
-  result += "\n                                      because they are the same condition. We know that we are not going to have any problem because";
-  result += "\n                                      such events are blocking-protected regarding logic-dependent messages (CCR-T), and race condition";
-  result += "\n                                      is absolutely strange in this case.";
-  result += "\n";
-  result += "\n                                     You could speed up the test case moving forward steps like 3 & 5, understood as non-strict requirements";
-  result += "\n                                      to continue testing. Anyway, remember that test cases should be as real as possible, and that there";
-  result += "\n                                      are many ways to increase the load rate as we will see in next section (test cases execution).";
-  result += "\n";
-  result += "\n                                     Other simplifications: the steps 3, 5 and 9 can be replaced by";
-  result += "\n";
-  result += "\n                                        test|1|waitfe||0|#2";
-  result += "\n                                        test|1|waitfe||0|#4";
-  result += "\n                                        test|1|waitfe||0|#8";
-  result += "\n";
-  result += "\n                                        which means that hop-by-hop must be retrieved from steps 2, 4 and 8 respectively,";
-  result += "\n                                        and the expected message shall be an answer. Normally you will add other conditions,";
-  result += "\n                                        for example a DIAMETER_SUCCESS result (adding 2001 as Result-Code).";
-  result += "\n";
-  result += "\nTest cases execution:";
-  result += "\n";
-  result += "\n";
-  result += "\n   test|ttps|<amount>            Starts/resume the provided number of test ticks per second (ttps). The ADML starts";
-  result += "\n                                 with the event trigger system suspended, and this operation is neccessary to begin";
-  result += "\n                                 those cases which need this time event (internal triggering). Some other test cases";
-  result += "\n                                 could be started through external events (first test case event could be programmed";
-  result += "\n                                 to wait specific message), but is not usual this external mode and neither usual to";
-  result += "\n                                 mix triggering types. Normally, you will pause/stop new test launchs providing 0 as";
-  result += "\n                                 ttps value, and also you could dynamically modify the load rate updating that value.";
-  result += "\n                                 If a test case has N messages then 'ttps * N' will be the virtual number of messages";
-  result += "\n                                 managed per second when no bottleneck exists.";
-  result += "\n";
-  result += "\n                                 Provide 0 in order to stop the timer triggering.";
-  result += "\n";
-  result += "\n                                 The timer manager resolution currently harcoded allows a maximum  of ";
-  result += anna::functions::asString(1000/a_admlMinResolution); result += " events";
-  result += "\n                                 per second. To reach greater rates ADML will join synchronously the needed number of";
-  result += "\n                                 new time-triggered test cases per a single event, writting a warning-level trace to";
-  result += "\n                                 advice about the risk of burst sendings and recommend launching multiple instances";
-  result += "\n                                 to achieve such load with a lower rate per instance.";
-  result += "\n";
-  result += "\n   test|next[|<sync-amount>]     Forces the execution of the next test case(s) without waiting for test manager tick.";
-  result += "\n                                 Provide an integer value for 'sync-amount' to send a burst synchronous amount of the";
-  result += "\n                                 next programmed test cases (1 by default). This event works regardless the timer tick";
-  result += "\n                                 function, but it is normally used with the test manager tick stopped.";
-  result += "\n";
-  result += "\n   test|ip-limit[|amount]        In-progress limit of test cases established from global context. This value will be";
-  result += "\n                                 overwritten if used at test case level when the corresponding test step is executed.";
-  result += "\n                                 Anyway, the meaning is the same in both contexts. But now, when the amount is missing,";
-  result += "\n                                 the limit and current amount of in-progress test cases will be shown.";
-  result += "\n";
-  result += "\n   test|goto|<id>                Updates current test pointer position.";
-  result += "\n";
-  result += "\n   test|look[|id]                Show programmed test case for id provided, current 'in-process' test case when missing.";
-  result += "\n                                 Test cases reports are not dumped on process context (too many information in general).";
-  result += "\n                                 The report contains context information in every moment: this operation acts as a snapshot.";
-  result += "\n";
-  result += "\n   test|state[|id]               Get test case state for id provided, current 'in-process' test case when missing.";
-  result += "\n";
-  result += "\n   test|interact|amount[|id]     Makes interactive a specific test case id. The amount is the margin of execution steps";
-  result += "\n                                 to be done. Normally, we will execute 'test|interact|0[|<test case id>]', which means that";
-  result += "\n                                 the test case is selected to be interactive, but no step is executed. Then you have to";
-  result += "\n                                 interact with positive amounts (usually 1), executing the provided number of steps if";
-  result += "\n                                 they are ready and fulfill the needed conditions. The value of 0, implies no execution";
-  result += "\n                                 steps margin, which could be useful to 'freeze' a test in the middle of its execution.";
-  result += "\n                                 You could also provide -1 to make it non-interactive resuming it from the current step.";
-  result += "\n                                 By default, current test case id is selected for interaction.";
-  result += "\n";
-  result += "\n   test|reset|<[soft]/hard>[|id] Reset the test case for id provided, all the tests when missing. It could be hard/soft:";
-  result += "\n                                 - hard: you probably may need to stop the load rate before. This operation initializes";
-  result += "\n                                         all test cases regardless their states.";
-  result += "\n                                 - soft: only for finished cases (those with 'Success' or 'Failed' states). It does not";
-  result += "\n                                         affect to test cases with 'InProgress' state.";
-  result += "\n";
-  result += "\n   test|repeats|<amount>         Restarts the whole programmed test list when finished the amount number of times (repeats";
-  result += "\n                                 forever if value -1 is provided). This is disabled by default (amount = 0): testing trigger";
-  result += "\n                                 system will enter suspended state until new ttps operation is received and a soft reset has";
-  result += "\n                                 been done before. Test cases state & data will be reset (when achieved again), but general";
-  result += "\n                                 statistics and counters will continue measuring until reset with 'collect' operation.";
-  result += "\n";
-  result += "\n   test|auto-reset|<soft|hard>   When cycling, current test cases can be soft (default) or hard reset. If no timeout has";
-  result += "\n                                 been configured for the test case, hard reset could prevent stuck on the next cycle for";
-  result += "\n                                 those test cases still in progress.";
-  result += "\n";
-  result += "\n   test|initialized              Shows the number of initialized test cases. Zero-value means that everything was processed";
-  result += "                                   or not initiated yet.\n";
-  result += "\n";
-  result += "\n   test|finished                 Shows the number of finished (successful or failed) test cases.";
-  result += "\n";
-  result += "\n   test|clear                    Clears all the programmed test cases and stop testing (if in progress).";
-  result += "\n";
-  result += "\n   test|junit                    Shows the junit report in the moment of execution.";
-  result += "\n";
-  result += "\n   test|summary-counts           Test manager counts report. Counts by state and prints total verdict.";
-  result += "\n";
-  result += "\n   test|summary-states           Test manager states report.";
-  result += "\n";
-  result += "\n   test|summary                  Test manager general report (number of test cases, counts by state, global configuration,";
-  result += "\n                                 forced in-progress limitation, reports visibility, etc.). Be careful when you have reports";
-  result += "\n                                 enabled because the programmed test cases dumps could be heavy (anyway you could enable the";
-  result += "\n                                 dumps separately, for any of the possible states: Initialized, InProgress, Failed, Success).";
-  result += "\n";
-  result += "\n   test|report|<initialized/in-progress/failed/success/[all]/none>[|[yes]|no]";
-  result += "\n";
-  result += "\n                                 Enables/disables report generation for a certain test case state: initialized, in-progress,";
-  result += "\n                                 failed or success (also 'all' and 'none' reserved words could be used). This applies to report";
-  result += "\n                                 summary (former described operation) and automatic dumps during testing where only failed or";
-  result += "\n                                 successful states will appear: every time a test case is finished its xml representation will";
-  result += "\n                                 be dump on a file under the execution directory (or the one configured in process command-line";
-  result += "\n                                 'tmDir') with the name:";
-  result += "\n";
-  result += "\n                                    'cycle-<cycle id>.testcase-<test case id>.xml'.";
-  result += "\n";
-  result += "\n                                 By default, all the states are disabled to avoid IO overload. In most of cases not all the";
-  result += "\n                                 tests are going to fail then you could enable only such failed dumps. Anyway you could set";
-  result += "\n                                 the reports visibility to fit your needs in a given situation.";
-  result += "\n";
-  result += "\n   test|report-hex[|[yes]|no]    Reports could include the diameter messages in hexadecimal format. Disabled by default.";
-  result += "\n";
-  result += "\n   test|dump-stdout[|[yes]|no]   Test manager information is dumped into stdout.";
-  result += "\n";
-  result += "\n";
-  result += "\n------------------------------------------------------------------------------------- Dynamic procedure";
-  result += "\n";
-  result += "\ndynamic[|args]                   This launch an internal operation implemented in 'Procedure' class.";
-  result += "\n                                 Its default implementation does nothing, but you could create a dynamic";
-  result += "\n                                 library 'libanna_launcherDynamic.so' and replace the one in this project.";
-  result += "\n                                 One interesting application consists in the use of the diameter API and";
-  result += "\n                                 event operation to create a set of libraries as the testing framework.";
-  result += "\n                                 To execute each test case, the ADML process would be executed with a";
-  result += "\n                                 specific library path. But the main use would be the stress programming";
-  result += "\n                                 to achieve a great amount of cloned (even mixed) tests without using";
-  result += "\n                                 the management operation interface by mean http or signals: a single";
-  result += "\n                                 call to 'dynamic' would be enough to start a cascade of internally";
-  result += "\n                                 implemented operations.";
-  result += "\n                                 This operation accepts a generic string argument (piped or not, as you";
-  result += "\n                                 desire and depending on your procedure implementation).";
-  result += "\n";
-  result += "\n                                 This operation requires advanced programming and knowlegde of ANNA Diameter";
-  result += "\n                                 stack and testing framework, to take advantage of all the possibilities.";
-  result += "\n";
-  result += "\n";
-  result += "\n";
-  result += "\nUSING OPERATIONS INTERFACE";
-  result += "\n--------------------------";
-  result += "\n";
-  result += "\n------------------------------------------------------------------------- Operations via HTTP interface";
-  result += "\n";
-  result += "\nAll the operations described above can be used through the optional HTTP interface. You only have";
-  result += "\n to define the http server at the command line with something like: '--httpServer localhost:9000'.";
-  result += "\nTo send the task, we shall build the http request body with the operation string. Some examples";
-  result += "\n using curl client could be:";
-  result += "\n";
-  result += "\n   curl -m 1 --data \"diameterServerSessions|4\" localhost:9000";
-  result += "\n   curl -m 1 --data \"code|ccr.xml\" localhost:9000";
-  result += "\n   curl -m 1 --data \"decode|ccr.hex\" localhost:9000";
-  result += "\n   curl -m 1 --data \"sendxml2e|ccr.xml\" localhost:9000";
-  result += "\n   etc.";
-  result += "\n";
-  result += "\n------------------------------------------------------------------------- Operations via SIGUSR2 signal";
-  result += "\n";
-  result += "\nThe alternative using SIGUSR2 signal requires the creation of the task(s) file which will be read at";
-  result += "\n signal event:";
-  result += "\n   echo \"<operation>\" > "; result += getSignalUSR2InputFile();
-  result += "\n    then";
-  result += "\n   kill -12 <pid>";
-  result += "\n    or";
-  result += "\n   kill -s SIGUSR2 <pid>";
-  result += "\n    and then see the results:";
-  result += "\n   cat "; result += getSignalUSR2OutputFile();
-  result += "\n";
-  result += "\n   (this file is ended with EOF final line, useful managing huge batch files to ensure the job completion)";
-  result += "\n";
-  result += "\nYou could place more than one line (task) in the input file. Output reports will be appended in that";
-  result += "\n case over the output file. Take into account that all the content of the task file will be executed";
-  result += "\n sinchronously by the process. If you are planning traffic load, better use the asynchronous http";
-  result += "\n interface.";
-  result += "\n";
-  result += "\n";
-
-  return result;
-}
-
 
 void Launcher::logStatisticsSamples(const std::string &conceptsList) throw() {
   anna::statistics::Engine &statEngine = anna::statistics::Engine::instantiate();
@@ -1650,7 +984,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     int op_size = operation.size();
     std::string args = ((operation.find("dynamic|") == 0) && (op_size > 8)) ? operation.substr(8) : "";
     if (args == "" && op_size != 7)
-      throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+      throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
     try {
       p.execute(args, response_content);
     }
@@ -1662,12 +996,6 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     return true; // OK
   }
 
-  // Help:
-  if(operation == "help") {
-    response_content = help();
-    return true; // OK
-  }
-
   // Reset performance data:
   if(operation == "collect") {
     resetCounters();
@@ -1732,7 +1060,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
 
   // No operation has more than 2 arguments except 'test' ...
   if(opType != "test" && numParams > 2)
-    throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+    throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
 
   // Check the number of parameters:
@@ -1758,7 +1086,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     // Launch exception
     std::string msg = "Wrong body content format on HTTP Request for '";
     msg += opType;
-    msg += "' operation (missing parameter/s). Use 'help' management command to see more information.";
+    msg += "' operation (missing parameter/s). Check 'HELP.md' for more information.";
     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
   }
 
@@ -2014,7 +1342,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
       opt_response_content = "\n\n";
       opt_response_content += getOperatedHost()->lookBurst(order);
     } else {
-      throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). See help", ANNA_FILE_LOCATION);
+      throw anna::RuntimeException("Wrong body content format on HTTP Request for 'burst' operation (unexpected action parameter). Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
     }
 
   } else if((opType == "test")) {
@@ -2028,6 +1356,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     // test|report-hex[|[yes]|no]               Reports could include the diameter messages in hexadecimal format. Disabled by default.
     // test|goto|<id>                           Updates current test pointer position.
     // test|look[|id]                           Show programmed test case for id provided, current when missing ...
+    // test|state[|id]                          Show test case state for id provided, current when missing ...
     // test|interact|amount|id                  Makes interactive a specific test case id. The amount is the margin of execution steps ...
     // test|reset|<[soft]/hard>[|id]            Reset the test case for id provided, all the tests when missing ...
     // test|auto-reset|<soft|hard>              When cycling, current test cases can be soft (default) or hard reset ...
@@ -2037,7 +1366,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
 
     if(param1 == "ttps") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       bool success = ((param2 != "") ? testManager.configureTTPS(atoi(param2.c_str())) : false);
       if (success) {
@@ -2051,7 +1380,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if (param1 == "next") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       int sync_amount = ((param2 != "") ? atoi(param2.c_str()) : 1);
 
@@ -2067,7 +1396,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "ip-limit") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       unsigned int limit;
       if (param2 != "") {
@@ -2087,7 +1416,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "repeats") {
       if (numParams != 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
       int repeats = atoi(param2.c_str());
       if (repeats < 0) repeats = -1;
       testManager.setPoolRepeats(repeats);
@@ -2096,7 +1425,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "report") {
       if (numParams > 3)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       if(param2 == "") param2 = "all";
       if(param3 == "") param3 = "yes";
@@ -2120,7 +1449,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
         testManager.setDumpAllReports(enable);
       }
       else
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       opt_response_content += (enable ? "report enabled " : "report disabled ");
       opt_response_content += "for tests in '";
@@ -2129,7 +1458,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "report-hex") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       if(param2 == "") param2 = "yes";
       testManager.setDumpHex((param2 == "yes"));
@@ -2137,7 +1466,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "dump-stdout") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       if(param2 == "") param2 = "yes";
       testManager.setDumpStdout((param2 == "yes"));
@@ -2145,7 +1474,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "goto") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       if(param2 == "") throw anna::RuntimeException("Missing id for test goto operation", ANNA_FILE_LOCATION);
       int id = atoi(param2.c_str());
@@ -2160,7 +1489,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "look") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       int id = ((param2 != "") ? atoi(param2.c_str()) : -1);
       anna::testing::TestCase *testCase = testManager.findTestCase(id);
@@ -2183,7 +1512,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "state") {
       if (numParams > 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       int id = ((param2 != "") ? atoi(param2.c_str()) : -1);
       anna::testing::TestCase *testCase = testManager.findTestCase(id);
@@ -2206,7 +1535,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if (param1 == "interact") {
       if (numParams != 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       int amount = atoi(param2.c_str());
       if (amount < -1)
@@ -2238,11 +1567,11 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "reset") {
       if (numParams > 3)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       if(param2 == "") param2 = "soft";
      if (param2 != "soft" && param2 != "hard")
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       int id = ((param3 != "") ? atoi(param3.c_str()) : -1);
       anna::testing::TestCase *testCase = ((id != -1) ? testManager.findTestCase(id) : NULL);
@@ -2270,29 +1599,29 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
     }
     else if(param1 == "auto-reset") {
       if (numParams != 2)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       if (param2 != "soft" && param2 != "hard")
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       testManager.setAutoResetHard(param2 == "hard");
       opt_response_content += anna::functions::asString("Auto-reset configured to '%s'", param2.c_str());
     }
     else if(param1 == "initialized") {
       if (numParams > 1)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       opt_response_content = anna::functions::asString("%lu", testManager.getInitializedCount());
     }
     else if(param1 == "finished") {
       if (numParams > 1)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       opt_response_content = anna::functions::asString("%lu", testManager.getFinishedCount());
     }
     else if(param1 == "clear") {
       if (numParams > 1)
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
 
       if (testManager.clearPool()) {
         opt_response_content = "all the programmed test cases have been dropped";
@@ -2339,26 +1668,26 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
       // Commands:
       if (param2 == "description") {
         if (numParams > 3)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException("Missing description for test case", ANNA_FILE_LOCATION);
         testManager.getTestCase(id)->setDescription(param3); // creates / reuses
       }
       else if (param2 == "ip-limit") {
         if (numParams > 3)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         unsigned int limit = (param3 == "") ? 1 : atoi(param3.c_str());
         testManager.getTestCase(id)->addIpLimit(limit); // creates / reuses
       }
       else if (param2 == "timeout") {
         if (numParams > 3)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException("Missing milliseconds for 'timeout' command in test id operation", ANNA_FILE_LOCATION);
         anna::Millisecond timeout = checkTimeMeasure("Test case timeout", param3);
         testManager.getTestCase(id)->addTimeout(timeout); // creates / reuses
       }
       else if ((param2 == "sendxml2e")||(param2 == "sendxml2c")) {
         if (numParams > 4)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing xml file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
         codecMsg.loadXMLFile(param3);
         LOGWARNING(
@@ -2376,14 +1705,25 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
       }
       else if (param2 == "delay") {
         if (numParams > 3)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException("Missing milliseconds for 'delay' command in test id operation", ANNA_FILE_LOCATION);
         anna::Millisecond delay = ((param3 == "0" /* special case */) ? (anna::Millisecond)0 : checkTimeMeasure("Test case delay step", param3));
         testManager.getTestCase(id)->addDelay(delay); // creates / reuses
       }
+
+// TODO(***)
+//                                        The way to identify the test case, is through registered Session-Id values for
+//                                         programmed requests. But this depends on the type of node. Acting as clients,
+//                                         requests received have Session-Id values which are already registered with
+//                                         one test case, causing an error if not found. Acting as servers, requests are
+//                                         received over a diameter local server from a client which are generating that
+//                                         Session-Id values. Then we know nothing about such values. The procedure in
+//                                         this case is find out a test case not-started containing a condition which
+//                                         comply with the incoming message, and reactivates it.
+// The other solution: register Session-Id values for answers send to client from a local diameter server.
       else if ((param2 == "waitfe")||(param2 == "waitfc")) {
         if (numParams > 11)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if (param3 != "" || param4 != "" || param5 != "" || param6 != "" || param7 != "" || param8 != "" || param9 != "" || param10 != "" || param11 != "") {
           bool fromEntity = (param2.substr(4,2) == "fe");
           testManager.getTestCase(id)->addWaitDiameter(fromEntity, param3, param4, param5, param6, param7, param8, param9, param10, param11);
@@ -2394,7 +1734,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
       }
       else if ((param2 == "waitfe-hex")||(param2 == "waitfc-hex")) {
         if (numParams > 4)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing hex file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
 
         // Get DataBlock from file with hex content:
@@ -2419,7 +1759,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
       }
       else if ((param2 == "waitfe-xml")||(param2 == "waitfc-xml")) {
         if (numParams > 4)
-          throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+          throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException(anna::functions::asString("Missing xml file for '%s' command in test id operation", param2.c_str()), ANNA_FILE_LOCATION);
 
         // Get xml content from file:
@@ -2480,14 +1820,14 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
       else if (param2 == "sh-command") {
         // Allow pipes in command:
         //if (numParams > 4)
-        //  throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        //  throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
         if(param3 == "") throw anna::RuntimeException("Missing script/executable command-line for 'sh-command' in test id operation", ANNA_FILE_LOCATION);
         std::string token = "|sh-command|";
         std::string command = operation.substr(operation.find(token) + token.size());
         testManager.getTestCase(id)->addCommand(command); // creates / reuses
       }
       else {
-        throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+        throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
       }
     }
 
@@ -2579,7 +1919,7 @@ bool Launcher::eventOperation(const std::string &operation, std::string &respons
       getOperatedEntity()->getReactingAnswers()->addMessage(code, message);
     }
   } else {
-    throw anna::RuntimeException("Wrong body content format on HTTP Request. Use 'help' management command to see more information.", ANNA_FILE_LOCATION);
+    throw anna::RuntimeException("Wrong body content format on HTTP Request. Check 'HELP.md' for more information.", ANNA_FILE_LOCATION);
   }
 
   // HTTP response
index a74ef39..8a68888 100644 (file)
@@ -114,7 +114,6 @@ public:
   void resetCounters() throw();
   void signalUSR2() throw(anna::RuntimeException);
   void signalTerminate() throw(anna::RuntimeException);
-  std::string help() const throw();
   anna::xml::Node* oamAsXML(anna::xml::Node* parent) const throw();
   anna::xml::Node* statsAsXML(anna::xml::Node* parent) const throw();
 
index bfbda6f..6638fc3 100644 (file)
@@ -17,6 +17,7 @@
 // Process
 #include <MyHandler.hpp>
 #include <Launcher.hpp>
+#include <EventOperation.hpp>
 
 
 void MyHandler::evRequest(anna::comm::ClientSocket& clientSocket, const anna::http::Request& request)
@@ -33,6 +34,7 @@ throw(anna::RuntimeException) {
   );
   std::string body_content;
   body_content.assign(body.getData(), body.getSize());
+  auto json_body = nlohmann::json::parse(body_content);
 
   // Operation:
   std::string response_content;
@@ -41,7 +43,7 @@ throw(anna::RuntimeException) {
 
   try {
     Launcher& my_app = static_cast <Launcher&>(anna::app::functions::getApp());
-    opOk = my_app.eventOperation(body_content, response_content);
+    opOk = my_app.eventOperation(EventOperation::json2piped(json_body), response_content);
   } catch(RuntimeException &ex) {
     ex.trace();
     opOk = false;
index 3ee0e58..3b8e6e3 100755 (executable)
@@ -112,6 +112,9 @@ echo "${httpOpt}" >> ${ADML}/args.ft
 echo "${httpOpt}" >> ${ADML}/args.st
 echo "localhost:8000" > ${ADML}/.httpServer
 
+# Help
+cp ${PROJECT_ROOT}/example/diameter/launcher/resources/HELP.md ${ADML}
+
 # Remove AOTS actions:
 rm ${ADML}/ACTIONS.md
 
index 1e7f471..3319dc5 100755 (executable)
@@ -106,5 +106,8 @@ cd ${DYNLIBS}
 ln -sf default/libanna_launcher_procedure_default_shared.so
 cd - >/dev/null
 
+# Help
+cp ${PROJECT_ROOT}/example/diameter/launcher/resources/HELP.md ${ADML}
+
 _exit "Done!" 0
 
index fdd17e7..f685bf0 100755 (executable)
@@ -41,10 +41,10 @@ usage () {
   echo
   exit 0
 }
+
 # $1: deployment type
 createRunScript () {
-  # Basic launcher 'run.sh' will be created at deployment configuration: 
+  # Basic launcher 'run.sh' will be created at deployment configuration:
   [ "$1" = "b" ] && return
 
   local other=
@@ -209,6 +209,7 @@ cp $SRVDTD $DPATH/DTDs
 [ "$option" = "b" ] && cp $SERVICES/* $DPATH/services
 cp $SCRIPTS/clone.sh $DPATH
 cp $SCRIPTS/tinyTestcase.sh $DPATH
+cp $SCR_DIR/resources/HELP.md $DPATH
 
 # Copy executables:
 cp $ADML_EXEC $DPATH/ADML
index 404524b..553eb3a 100644 (file)
@@ -14,8 +14,4 @@ get complete 'launcher.trace'. Execute 'ADML' without arguments to see a complet
 
 DEPLOYED SCRIPTS
 ----------------
-You could get help about installed resources by mean 'help.sh', which launch a help request to
-the started ADML process http interface. All the implemented http operations could be launched
-through a script to make easy use. The http client 'curl' is used by default due to its presence
-on common linux distributions.
-
+Check 'HELP.md' for more information.
diff --git a/example/diameter/launcher/deployments/advanced/help.sh b/example/diameter/launcher/deployments/advanced/help.sh
deleted file mode 100755 (executable)
index ebeafff..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-> curl_log.txt
-TRACE="--trace-ascii curl_log.txt"
-SERVER=`cat .httpServer`
-curl -m 1 --data "help" $TRACE ${SERVER}
-
index 6a51e4a..e3a5616 100644 (file)
@@ -28,6 +28,4 @@ have been prepared for the type of launcher you wanted.
 OPERATION
 ---------
 Management interface for lite version is based on SIGUSR2 signal caugh. Use './operation.sh'
-script to send any operation to the process. Ask for help with that script to see all the
-operations supported.
-
+script to send any operation to the process. Check 'HELP.md' for more information.
index af8b5fc..092adfc 100755 (executable)
@@ -81,7 +81,6 @@ if [ "$option" = "s" ]
 then
   echo
   echo "Ignore errors ? (y/n) [n]:"
-  echo " (ignoring errors, the process won't answer Failed-AVP automatically; execute './$EXE_BN | grep -A1 ignoreErrors:' for more help)"
   read i_errors
   [ "$i_errors" = "" ] && i_errors=n
   [ "$i_errors" = "y" ] && KINDNESS="$KINDNESS --ignoreErrors"
index ff22c92..296822f 100644 (file)
@@ -22,6 +22,4 @@ have been prepared for the type of launcher you wanted.
 OPERATION
 ---------
 Management interface for this version is based on SIGUSR2 signal caugh. Use './operation.sh'
-script to send any operation to the process. Ask for help with that script to see all the
-operations supported.
-
+script to send any operation to the process. Check 'HELP.md' for more information.
index fd3860a..30a176e 100644 (file)
@@ -48,8 +48,7 @@ OPERATION
 ---------
 Management interface for lite version is based on SIGUSR2 signal caugh.
 Use './operation.sh' script within a specific instance directory to send
-any operation to the process. Ask for help with that script to see all
-the operations supported.
+any operation to the process. Check 'HELP.md' for more information.
 
 Operation script acts over ADMLS symlink. You must update it if want to
 operate another ADMLS instances directory.
index 2dcb900..1d0628f 100755 (executable)
@@ -8,13 +8,6 @@ then
   exit 1
 fi
 
-if [ "$1" = "-h" -o "$1" = "--help" ]
-then
-  first_adml=$(ls -d ADMLS/* | head -n +1)
-  $first_adml/operation.sh help
-  exit 0
-fi
-
 for op in `ls ADMLS/*/operation.sh`
 do
   dn_op=`dirname $op`
index 5714785..cf44977 100755 (executable)
@@ -135,7 +135,7 @@ then
   #CLONE_GROUPS=1
   specific=
   [ -f $TESTCASE_DIR/specific ] && specific=specific
-  
+
   count=0
   while read -r line
   do
@@ -152,12 +152,12 @@ then
       wait $(jobs -p)
       count=0
     fi
-  
+
   done < $PROGRAM_LAYOUT_FILE
 
   # Advice for idle cpu:
   advice_to_squeeze_idle_cpu
-  
+
   # Wait background jobs to finish:
   sleep 5
   echo "Waiting for clone completion ..."
@@ -165,11 +165,11 @@ then
   echo
   echo "Background Jobs: $(jobs -p | wc -l)"
   wait $(jobs -p)
-  
+
   echo
   echo "Programming has finished !"
   echo
-  
+
   if [ -n "$specific" ]
   then
     echo "A new file '$TESTCASE_DIR/specific.all' has been created."
@@ -252,18 +252,18 @@ else
     ini_seq=$(echo $line | awk '{ print $2 }')
     fin_seq=$(echo $line | awk '{ print $3 }')
     ADML_DIR=`readlink -f ADMLS/ADML-$instance`
-  
-    cd $ADML_DIR                                                      
+
+    cd $ADML_DIR
     ./operation.sh -t 60 "dynamic|$ini_seq|$fin_seq|$dynamic_suffix" &
     sleep 0.1
-    count=$((count+1))                                                
+    count=$((count+1))
     if [ $count -eq $ADML_CONCURRENT_PROVISION_JOBS ]
     then
       wait $(jobs -p)
       count=1
     fi
-    cd - >/dev/null                                                   
-  
+    cd - >/dev/null
+
   done < $PROGRAM_LAYOUT_FILE
 
   # Advice for idle cpu:
@@ -278,7 +278,7 @@ echo "Configuring repeat cycles ..."
 echo
 echo "Done !"
 echo
-  
+
 start_testing=
 if [ "$AUTOSTART" = "-s" ]
 then
@@ -314,7 +314,7 @@ Remember that './operation.sh' broadcasts the operation scripts inside
  - Interactive-step execution: ADMLS/ADML-001/operation.sh "test|interact|<steps to execute>|<test id>"
  - Summary: ADMLS/ADML-001/operation.sh "test|summary"
 
-For a complete and detailed information, execute: ./operation.sh --help | less
+Check 'HELP.md' for more information.
 
 You could also use './launchCPS.sh' script.
 
index 4221ca3..32e9ebf 120000 (symlink)
@@ -1 +1 @@
-../../../resources/stack_examples/16777238.xml
\ No newline at end of file
+../../../resources/stack_examples/DictionaryGx.16777238.xml
\ No newline at end of file
index 0706e2b..97b8373 120000 (symlink)
@@ -1 +1 @@
-../../../resources/stack_examples/16777236.xml
\ No newline at end of file
+../../../resources/stack_examples/DictionaryRx.16777236.xml
\ No newline at end of file
index ca439a6..a827759 100644 (file)
@@ -45,12 +45,12 @@ int main(int argc, const char** argv) {
   try {
     anna::CommandLine& commandLine(anna::CommandLine::instantiate());
     // General
-    commandLine.add("services", anna::CommandLine::Argument::Mandatory, "Services xml path file. Shall be validated against dtd schema written on warning traces: 'Services DTD schema'. Empty string or \"null\" name, to start without services (see help for management operation 'services').");
+    commandLine.add("services", anna::CommandLine::Argument::Mandatory, "Services xml path file. Shall be validated against dtd schema written on warning traces: 'Services DTD schema'. Empty string or \"null\" name, to start without services (check 'HELP.md' for more 'services').");
     commandLine.add("trace", anna::CommandLine::Argument::Optional, "Trace level (emergency, alert, critical, error, warning, notice, information, debug, local0..local7)");
     commandLine.add("cntDir", anna::CommandLine::Argument::Optional, "Counters directory. By default is the current execution directory. Warning: a counter file will be dump per record period; take care about the possible accumulation of files");
-    commandLine.add("tmDir", anna::CommandLine::Argument::Optional, "Test manager directory. By default is the current execution directory. Warning: report files could be dump during system testing (see help for management operation 'test|report|result'); take care about the possible accumulation of files");
+    commandLine.add("tmDir", anna::CommandLine::Argument::Optional, "Test manager directory. By default is the current execution directory. Warning: report files could be dump during system testing (check 'HELP.md' for 'test|report|result'); take care about the possible accumulation of files");
     commandLine.add("cntRecordPeriod", anna::CommandLine::Argument::Optional, "Counters record procedure period in milliseconds. If missing, default value of 300000 (5 minutes) will be assigned. Value of 0 disables the record procedure.");
-    commandLine.add("logStatisticSamples", anna::CommandLine::Argument::Optional, "Log statistics samples for the provided comma-separated concept id list, over './sample.<concept id>.csv' files. For example: \"1,2\" will log concepts 1 and 2. Reserved words \"all\"/\"none\" activates/deactivates all registered statistics concept identifiers. That ids are shown at context dump (see help to get it).");
+    commandLine.add("logStatisticSamples", anna::CommandLine::Argument::Optional, "Log statistics samples for the provided comma-separated concept id list, over './sample.<concept id>.csv' files. For example: \"1,2\" will log concepts 1 and 2. Reserved words \"all\"/\"none\" activates/deactivates all registered statistics concept identifiers. That ids are shown at context dump (check 'HELP.md' to get it).");
     commandLine.add("disableLogs", anna::CommandLine::Argument::Optional, "Overrides every node configuration regarding traffic log in order to disable it and ease production or system test startup.", false);
 
     // Communications
diff --git a/example/diameter/launcher/resources/HELP.md b/example/diameter/launcher/resources/HELP.md
new file mode 100644 (file)
index 0000000..5dbf7b5
--- /dev/null
@@ -0,0 +1,527 @@
+# OVERVIEW
+
+The ADML (*ANNA Diameter MultiHost Launcher*) process is a multi-host node with client and server capabilities as well as balancer (proxy) features. It could be used as diameter server (i.e. to simulate PCRF nodes, OCS systems, etc.), as diameter client (GGSNs, DPIs, etc.), and balancer systems to provide failover to external round-robin launchers. Also, auxiliary encoder/decoder/loader function could be deployed to reinterpret certain external flow and send it to another process.
+
+The *ANNA::diameter_comm* built-in module provides a great set of characteristics as multiple connections on both server and client side, definition for multiple-server entities (and not only two as standard establish as minimum), separate statistics analyzer per each resource, automatic CER/CEA and DWR/DWA generation, expiration control and many more features.
+
+The ADML process can easily configure a many origin-host nodes as needed, which will have own endpoints. You should avoid loop configurations (client and server for that client) because automatic forwarding, is implemented and this would get in a never ending cycle when a request is sent.
+
+Process traces are dump on \"launcher.trace\" and could have any trace level (POSIX levels), usually 'debug' or 'warning'. See ANNA documentation for more details.
+
+As any other ANNA process, context dump could be retrieved sending SIGUSR1 signal:
+   kill -10 <pid>
+    or
+   kill -s SIGUSR1 <pid>
+    and then
+   vi /var/tmp/anna.context.<pid>
+
+A complete xml report will show all the context information (counters, alarms, statistics, handlers, diameter stacks, etc.), and a powerful log module could dump all the events processed and flow information. Statistics could be analized at context dump and optionally written to disk as sample files (useful for graphs and spreadsheet reports) with all the measurements.
+
+Also SIGUSR2 is handled for management purposes. We will talk later about this.
+
+
+COMMAND LINE
+============
+
+Start the launcher process without arguments in order to see all the startup configuration posibilities, many of which could be modified on the air through the management interface (we will talk later about this great feature). There is only one mandatory parameter which is the services definition: --services <services xml file>. You must follow the dtd schema to build a valid services xml file. Some basic examples are:
+
+Client configuration:
+
+> <services>
+>   <!-- Stacks -->
+>   <stack id=\"0\" dictionary=\"dictionary.xml\"/>
+>
+>   <!-- Nodes -->
+>   <node originHost=\"ADML-client\" applicationId=\"0\" entity=\"localhost:3868\"/>
+> </services>
+
+Server configuration:
+
+> <services>
+>   <!-- Stacks -->
+>   <stack id=\"0\" dictionary=\"dictionary.xml\"/>
+>
+>   <!-- Nodes -->
+>   <node originHost=\"ADML-server\" applicationId=\"0\" diameterServer=\"localhost:3868\"/>
+> </services>
+
+If you act as a proxy or a translation agent, you need to combine both former setups, and probably will need to program the answers to be replied through the operations interface. To balance the traffic at your client side you shall use '--balance' and '--sessionBasedModelsClientSocketSelection' arguments in order to define the balancing behaviour. To make hybrid setups you only must mix the nodes:
+
+Client and server configuration:
+
+> <services>
+>   <!-- Stacks -->
+>   <stack id=\"16777236\" dictionary=\"dictionary_Rx.xml\"/>
+>   <stack id=\"16777238\" dictionary=\"dictionary_Gx.xml\"/>
+>   <stack id=\"0\" dictionary=\"dictionary_base.xml\"/>
+>
+>   <!-- Nodes -->
+>   <node originHost=\"ADML-Rx-client\" applicationId=\"16777236\" entity=\"localhost:3868\" cer=\"cer_Rx.xml\"/>
+>   <node originHost=\"ADML-Gx-client\" applicationId=\"16777238\" entity=\"localhost:3868\" cer=\"cer_Gx.xml\"/>
+> </services>
+
+The process builds automatically CER and DWR messages as a client, but you could specify your own as shown in the hybrid former example. Note that the base protocol stack must be registered because the configuration corresponds to a multistack process which change the stack using the application-id processed (0 in the case of base protocol messages: CER, CEA, DWR, DWA, DPR, DPA).
+
+DYNAMIC OPERATIONS
+==================
+
+ADML supports several operations which could be recognized via SIGUSR2 caugh or HTTP interface:
+
+## SIGUSR2 caugh
+
+Requires the creation of the task(s) file which will be read at signal event:
+
+>    echo \"<operation>\" > "; result += getSignalUSR2InputFile();
+>     then
+>    kill -12 <pid>
+>     or
+>    kill -s SIGUSR2 <pid>
+>     and then see the results:
+>    cat "; result += getSignalUSR2OutputFile();
+
+   (this file is ended with EOF final line, useful managing huge batch files to ensure the job completion)
+
+You could place more than one line (task) in the input file. Output reports will be appended in that case over the output file. Take into account that all the content of the task file will be executed sinchronously by the process. If you are planning traffic load, better use the asynchronous http interface.
+
+An operation is specified by mean a string containing the operation name and needed arguments separated by pipes. These are the available commands:
+
+### Node management
+
+**node[|<name>]**
+
+Selects a context working node by mean a registered name (origin-host).
+All the subsequent operations will be forced to work with this node, which makes possible some rare scenarios like sending unexpected messages on remote peers. This is also useful for some operations in order to restrict the scope of action (statistics, communication visibility, etc.).
+
+Empty parameter will show the current configuration.
+
+**node_auto**
+
+Returns to the default behaviour (smart node selection).
+Depending on the operation, this could imply a global action scope, affecting to all the registered hosts.
+This should be the normal configuration. Take into account that if you fix the working node, this could affect to things like test programming: communication resources will override those which would be inferred from programmed messages Origin-Host avps.
+
+### Parsing operations
+
+**code|<source_file>|<target_file>**
+
+Encodes source file (pathfile) into target file (pathfile).
+
+**decode|<source_file>|<target_file>**
+
+Decodes source file (pathfile) into target file (pathfile).
+
+**loadxml|<source_file>**
+
+Reinterpret xml source file (pathfile).
+
+### Hot changes
+
+**services[|<source file>]**
+
+Adds and starts the services specified in the xml file provided. If missing, the file 'services.xml' will be used. This is used to load new nodes once the ADML is started, regardless if command line '--services' parameter was used or not. Those services which are not correctly loaded will be ignored to keep the process alive.
+If you need to load services as deltas, you must firstly load the diameter base dictionary with stack id 0, because all the nodes will use this dictionary to encode/decode base protocol messages managed by the communication engine.
+
+**diameterServerSessions|<integer>**
+
+Updates the maximum number of accepted connections to diameter server socket.
+
+**context[|<target file>]**
+
+Application context could also be written by mean this operation (not only through SIGUSR1). If optional path file is missing, default '/var/tmp/anna.context.<pid>' will be used.
+
+**collect**
+
+Reset statistics and counters to start a new test stage of performance measurement. Context data can be written at '/var/tmp/anna.context.<pid>' by mean 'kill -10 <pid>' or sending operation 'context|[target file]'. This operation applies over all the registered host nodes except if one specific working node has been set.
+
+**forceCountersRecord**
+
+Forces dump to file the current counters of the process.
+
+**log-statistics-samples|<list>**
+
+Log statistics samples for the provided comma-separated concept id list, over './sample.<concept id>.csv' files. For example: "1,2" will log concepts 1 and 2. Reserved words "all"/"none" activates/deactivates all registered statistics concept identifiers. That ids are shown at context dump.
+
+**change-dir[|directory]**
+
+Changes the execution point which could be fine to ease some file system interaction tasks. Be care about some requirements (for example if you have a user defined counters directory as relative path this must exists from the new execution directory). If nothing provided, initial working directory will be restored.
+
+**show-oam**
+
+Dumps current counters of the process. This is also done at process context dump.
+
+**show-stats**
+
+Dumps statistics of the process. This is also done at process context dump.
+
+**visibility|<action>|<address>:<port>**
+
+*Actions*: hide, show (update state) and hidden, shown (query state).
+Acts over a client session for messages delivery (except CER/A, DWR/A, DPR/A).
+If missing server (first parameter) all applications sockets will be affected.
+If missing socket (second parameter) for specific server, all its sockets will be affected.
+
+All application client sessions are shown on startup, but standard delivery only use primary server ones except if fails. Balance configuration use all the allowed sockets. You could also use command line 'sessionBasedModelsClientSocketSelection' to force traffic flow over certain client sessions, but for this, hide/show feature seems easier.
+
+### Flow operations
+
+**sendxml2e|<source_file>**
+
+Sends xml source file (pathfile) through configured entity.
+
+**sendxml2c|<source_file>**
+
+Sends xml source file (pathfile) to client.
+
+**answerxml2e[|source_file]**
+
+Answer xml source file (pathfile) for incoming request with same code from entity.
+The answer is stored in a FIFO queue for a specific message code, then there are as many queues as different message codes have been programmed.
+
+**answerxml2c[|source_file]**
+
+Answer xml source file (pathfile) for incoming request with same code from client. The answer is stored in a FIFO queue for a specific message code, then there are as many queues as different message codes have been programmed.
+
+**answerxml<2e/2c>**
+
+List programmed answers (to entity/client) if no parameter provided.
+
+**answerxml<2e/2c>|dump**
+
+Write programmed answers (to entity/client) to file 'programmed_answer.<message code>.<sequence>', where 'sequence' is the order of the answer in each FIFO code-queue of programmed answers.
+
+**answerxml<2e/2c>|clear**
+
+Clear programmed answers (to entity/client).
+
+**answerxml<2e/2c>|exhaust**
+
+Disable the corresponding queue rotation, which is the default behaviour.
+
+**answerxml<2e/2c>|rotate**
+
+Enable the corresponding queue rotation, useful in performance tests. Rotation consists in add again to the queue, each element retrieved for answering.
+
+Send operations are available using hexadecimal content (hex formatted files) which also allow to test
+special scenarios (protocol errors):
+
+**sendhex2e|<source_file>**
+
+Sends hex source file (pathfile) through configured entity.
+
+**sendhex2c|<source_file>**
+
+Sends hex source file (pathfile) to client.
+
+Answer programming in hexadecimal is not really neccessary (you could use send primitives) and also is intended to be used with decoded messages in order to replace things like hop by hop, end to end, subscriber id, session id, etc. Anyway you could use 'decode' operation and then program the xml created.
+
+If a request is received, answer map (built with 'answerxml<2e/2c>' operations) will be checked to find a corresponding programmed answer to be replied(*). If no ocurrence is found, or answer message was received, the message is forwarded to the other side (entity or client), or nothing but trace when no peer at that side is configured. Answer to client have sense when diameter server socket is configured, answer to entity have sense when entity does.
+
+In the most complete situation (process with both client and server side) there are internally two maps with N FIFO queues, one for each different message code within programmed answers. One map is for answers towards the client, and the other is to react entity requests. Then in each one we could program different answers corresponding to different request codes received.
+
+(*) sequence values (hop-by-hop and end-to-end), Session-Id and Subscription-Id avps, are mirrored to the peer which sent the request. If user wants to test a specific answer without changing it, use 'sendxml<2e/2c>/sendhex<2e/2c>' operations better than programming.
+
+Balance ('--balance' command line parameter) could be used to forward server socket receptions through entity servers by mean a round-robin algorithm. Both diameter server socket and entity targets should have been configured, that is to say: launcher acts as client and server. If no balance is used, an standard delivery is performed: first primary entity server, secondary when fails, etc.
+
+### Processing types (log tags)
+
+Used as log file extensions (when '--splitLog' is provided on command line) and context preffixes on log
+ details when unique log file is dumped:
+
+| MULTIPLEXOR IDENTIFIER | Description                                                  |
+| ---------------------- | ------------------------------------------------------------ |
+| [sent2e/send2eError]   | Send to entity (success/error)                               |
+| [sent2c/send2cError]   | Send to client (success/error)                               |
+| [fwd2e/fwd2eError]     | Forward to entity a reception from client (success/error)    |
+| [fwd2c/fwd2cError]     | Forward to client a reception from entity (success/error)    |
+| [recvfc]               | Reception from client                                        |
+| [recvfe]               | Reception from entity                                        |
+| [req2c-expired]        | A request sent to client has been expired                    |
+| [req2e-expired]        | A request sent to entity has been expired                    |
+| [recvfc-ans-unknown]   | Reception from client of an unknown answer (probably former [req2c-expired] has been logged) |
+| [recvfe-ans-unknown]   | Reception from entity of an unknown answer (probably former [req2e-expired] has been logged) |
+| [retry]                | Request retransmission                                       |
+
+### Burst test
+
+In order to simplify user experience, burst category operations are only allowed in single host node
+ configuration. Indeed, you could send messages with unmatched Origin-Host, and no warning is shown.
+All the operations are performed through the unique host: if you need to use more interfaces, you may
+ launch different ADML instances. Is nonsense to allow burst in a multi-host configured ADML, because
+ this feature is not able to coordinate the messages.
+
+**burst|<action>[|parameter]**
+
+Used for performance testing, we first program diameter requests messages in order to launch them from client side to the configured diameter entity. We could start the burst with an initial load (non-asynchronous sending), after this, a new request will be sent per answer received or expired context. There are 10 actions: clear, load, start, push, pop, stop, repeat, send, goto and look.
+
+| OPERATION                    | DESCRIPTION                                                  |
+| ---------------------------- | ------------------------------------------------------------ |
+| burst\|clear                 | Clears all loaded burst messages.                            |
+| burst\|load\|<source_file>   | Loads the next diameter message into launcher burst.         |
+| burst\|start\|<initial load> | Starts (or restarts if already in progress) the message sending with a certain initial load. |
+| burst\|push\|<load amount>   | Sends specific non-aynchronous load.                         |
+| burst\|pop\|<release amount> | Skip send burst messages in order to reduce over-the-air requests. Popping all OTA requests implies burst stop because no more answer will arrive to the process. Burst output file (--burstLog command line parameter) shows popped messages with crosses (x). Each cross represents one received answer for which no new request is sent. |
+| burst\|stop\|                | Stops the burst cycle. You can resume pushing 1 load amount. |
+| burst\|repeat[\|[yes]\|no]   | Restarts the burst launch when finish. If initial load or push load amount is greater than burst list size, they will be limited when the list is processed except when repeat mode is enabled. |
+| burst\|send\|<amount>        | Sends messages from burst list. The main difference with start/push operations is that burst won't be awaken. Externally we could control sending time (no request will be sent for answers). |
+| burst\|goto\|<order>         | Updates current burst pointer position.                      |
+| burst\|look[\|order]         | Show programmed burst message for order provided, current when missing. |
+
+### Advanced testing (FSM, finite state machine)
+
+Burst mode only allows single interface interaction. For multiple interface (origin-host) coordination, you could use the advanced test cases programming:
+
+   **test|<id>|<command>[|parameters]**
+
+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.).
+
+<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:
+
+
+
+> **description|<description>**
+>
+> Sets a test case description. Test cases by default are constructed with description 'Testcase_<id>'.
+>
+> **ip-limit[|amount]**
+>
+> In-progress limit of test cases controlled from this test. No new test cases will be launched over this value (test manager tick work will be ignored). Zero-value is equivalent to stop the clock tick, -1 is used to specify 'no limit' which is the default. For missing amount, value of 1 is applied.
+>
+> **timeout|<msecs>**
+>
+> Sets an asynchronous timer to restrict the maximum timeout until last test step. Normally, this command is invoked in the first step, anyway it measures the time from the execution point whatever it is. The expiration will abort the test if still running. One or more timeouts could be programmed (not usual), but the more restrict will apply.
+> It is highly recommended to program a initial timeout step, or the test case could be eternally in-progress.
+>
+> **sendxml2e|<source_file>[|<step number>]**
+> Sends xml source file (pathfile) to entity (it would be a 'forward' event if it came through local server endpoint).
+> Take into account that the xml message is encoded just on call. The xml file is not longer needed neither interpreted in case of modification, after calling this command. The step number should be provided for answers to indicate the 'wait for request' corresponding step. If you miss this reference, the sequence information (hop-by-hop, end-to-end) will be sent as they are in the answer xml message (realize the difficulty of predicting these information). Be sure to refer to a 'wait for request' step. Conditions like 'regexp' (as we will see later) are not verified.
+> In the case of requests, the step number is used to force the copy of Session-Id value from the referred step.
+>
+> **sendxml2c|<source_file>[|<step number>]**
+> Sends xml source file (pathfile) to client (it would be a 'forward' event if it came through remote server endpoint). Same commented for 'sendxml2e' regarding the step number.
+>
+> **delay|<msecs>**
+>
+> Blocking step until the time lapse expires. Useful to give some cadence control and time schedule for a specific case. A value of 0 could be used as a dummy step.
+>
+> **sh-command|<script>**
+>
+> External execution for script/executable via shell through a dedicated thread, providing the command and parameters. You could use dynamic variables ##<tag> to have more flexibility:
+> Test pool cycle id: ##cycleid##
+> Test case id: ##testcaseid##
+> Test step id: ##teststepid##
+>
+> For example, your command could be something like this:
+>
+> > insert_sql_##testcaseid##.sh -db dbname --verbose > /tmp/cycle-##cycleid##.testcase-##testcaseid##.teststep-##teststepid##.out
+>
+>
+>
+> Try to redirect stdout and stderr to avoid ADML output contamination with the possible outputs from the scripts. You could also put your job in background although sh-command will return 0-value immediately.
+>
+> **wait<fe/fc>-hex|<source_file>[|strict]**
+> Wait condition, from entity (waitfe-hex) or client (waitfc-hex) to match the hexadecimal representation for received messages against source file (hex format). Fix mode must be enabled to avoid unexpected matching behaviour. Specify 'strict' to use the hex content 'as is'.
+> If not, the hex content will be understood as whole message and then, borders will be added (^<content>$) and sequence information bypassed even for diameter answers.
+>
+> **wait<fe/fc>-xml|<source_file>[|strict]**
+> Wait condition from entity (waitfe-xml) or client (waitfc-xml) to match the serialized xml content for received messages against source file (xml representation). Fix mode must be enabled to avoid unexpected matching behaviour. If you need a strict matching you must add parameter 'strict', if not, regexp is built ignoring sequence information (hop-by-hop-id=\"[0-9]+\" end-to-end-id=\"[0-9]+\") and Origin-State-Id value. All LF codes will be internally removed when comparison is executed in order to ease xml content configuration.
+>
+> **wait<fe/fc>|<condition>**
+>
+> Blocking step until condition is fulfilled. The message could received from entity (waitfe) or from client (waitfc). CPU cost is lower than former 'wait<fe/fc>-<xml|hex>' variants.
+>
+> > <condition>:
+> >
+> > Optional parameters which must be fulfilled to continue through the next step. Any received message over diameter interfaces will be evaluated against the corresponding test case starting from the current step until the first one whose condition is fulfilled. If no condition is fulfilled the event will be classified as 'uncovered' (normally a test case bad configuration, or perhaps a real unexpected message).
+> >
+> > How to answer: a wait condition for a request will store the incoming message which fulfills that condition. This message is useful together with the peer connection source in a further send step configured with the corresponding response. You could also insert a delay between wait and send steps to be more realistic (processing time simulation in a specific ADML host node).
+> > Always, a response send step will get the needed information from the most recent wait step finding in reverse order (note that some race conditions could happen if your condition is not specific enough).
+> >
+> > Condition format is: **[code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]**
+> >
+> > *code*: integer number
+> > *bitR*: 1 (request), 0 (answer)
+> > *hopByHop*: integer number or request send step reference: #<step number>
+> >
+> > Using the hash reference, you would indicate a specific wait condition for answers. The step number provided must correspond to any of the previous send commands (sendxml2e/sendxml2c) configured for a request.
+> > This 'hop-by-hop' variant eases the wait condition for answers in the safest way.
+> >
+> > *applicationId*: integer number
+> > *sessionId*: string
+> > *resultCode*: integer number
+> > *msisdn*: string
+> > *imsi*: string
+> > *serviceContextId*: string
+> >
+> > Take into account these rules, useful in general:
+> >
+> > - Be as much specific as possible defining conditions to avoid ambiguity sending messages out of context due to race conditions. Although you could program several times similar conditions, some risky practices will throw a warning trace (if you repeat the same condition within the same test case).
+> > - Adding a ResultCode and/or HopByHop to the condition are only valid waiting answers.
+> > - Requests hop-by-hop values must be different for all the test case requests.
+> > RFC says that a hop by hop must be unique for a specific connection, something that could be difficult to manage if we have multiple available connections from client side endpoint (entity or local server), even if we would have only one connection but several host interfaces. It is enough to configure different hop-by-hop values within each test case, because on reception, the Session-Id is used to identify that test case.
+
+####  Programming example:
+
+*Basic Rx/Gx scenary: PCEF (Gx) - PCRF - AF (Rx)*
+
+test|1|timeout|5000
+test|1|sendxml2e|CCR-I.xml
+test|1|waitfe|272|0|||SGx|2001
+test|1|sendxml2e|AAR-flows.xml
+test|1|waitfe|265|0|||SRx|2001
+test|1|waitfe|258|1|||SGx
+test|1|sendxml2e|RAA-install.xml|6
+test|1|sendxml2e|CCR-T.xml
+test|1|waitfe|272|0|H1||SGx|2001
+test|1|waitfe|258|1|||SGx
+test|1|sendxml2e|RAA-remove.xml|10
+
+
+
+- Step 1: whole time requirement is 5 seconds
+- Step 2: imagine this xml uses the Session-Id 'SGx'
+- Step 3: waits the CCA for the CCR-I with Result-Code = DIAMETER_SUCCESS
+- Step 4: imagine this xml uses the Session-Id 'SRx'
+- Step 5: waits the AAA for the AAR-flows with Result-Code = DIAMETER_SUCCESS
+- Step 6: waits the RAR (install policies) from the PCRF server
+- Step 7: sends the response for the RAR
+- Step 8: termination of the Gx session, imagine this xml puts hop-by-hop 'H1'
+- Step 9: waits the CCA for the CCR-T with Result-Code = DIAMETER_SUCCESS and hop-by-hop 'H1'
+- Step 10: waits the RAR (remove policies) from the PCRF server
+- Step 11: sends the response for the RAR
+
+
+
+**Notes**:
+
+We added an additional condition in step 9: the hop-by-hop. When we program the corresponding source request (CCR-T), we configured the value 'H1' for the hop-by-hop. This is an 'application value' because the real hop-by-hop transported through the client connection is managed by the diameter stack. But when returned, the transaction pool resolve the original value. This feature is necessary to ease the implementation of certain diameter agents (proxies for example). In our case, we could format the hop-by-hop values within the request templates with total freedom to improve the programmed conditions.
+
+In the case of 'waiting for requests' is not such easy. Indeed, steps 6 and 10 will write a warning because they are the same condition. We know that we are not going to have any problem because such events are blocking-protected regarding logic-dependent messages (CCR-T), and race condition is absolutely strange in this case.
+
+You could speed up the test case moving forward steps like 3 & 5, understood as non-strict requirements to continue testing. Anyway, remember that test cases should be as real as possible, and that there are many ways to increase the load rate as we will see in next section (test cases execution).
+
+Other simplifications: the steps 3, 5 and 9 can be replaced by
+
+test|1|waitfe||0|#2
+test|1|waitfe||0|#4
+test|1|waitfe||0|#8
+
+which means that hop-by-hop must be retrieved from steps 2, 4 and 8 respectively, and the expected message shall be an answer. Normally you will add other conditions, for example a DIAMETER_SUCCESS result (adding 2001 as Result-Code).
+
+#### Test cases execution:
+
+**test|ttps|<amount>**
+
+Starts/resume the provided number of test ticks per second (ttps). The ADML starts with the event trigger system suspended, and this operation is neccessary to begin those cases which need this time event (internal triggering). Some other test cases could be started through external events (first test case event could be programmed to wait specific message), but is not usual this external mode and neither usual to mix triggering types. Normally, you will pause/stop new test launchs providing 0 as ttps value, and also you could dynamically modify the load rate updating that value. If a test case has N messages then 'ttps * N' will be the virtual number of messages managed per second when no bottleneck exists.
+
+Provide 0 in order to stop the timer triggering.
+
+The timer manager resolution currently harcoded allows a maximum  of 50 events per second. To reach greater rates ADML will join synchronously the needed number of new time-triggered test cases per a single event, writting a warning-level trace to advice about the risk of burst sendings and recommend launching multiple instances to achieve such load with a lower rate per instance.
+
+**test|next[|<sync-amount>]**
+
+Forces the execution of the next test case(s) without waiting for test manager tick.
+Provide an integer value for 'sync-amount' to send a burst synchronous amount of the next programmed test cases (1 by default). This event works regardless the timer tick function, but it is normally used with the test manager tick stopped.
+
+**test|ip-limit[|amount]**
+
+In-progress limit of test cases established from global context. This value will be overwritten if used at test case level when the corresponding test step is executed.
+Anyway, the meaning is the same in both contexts. But now, when the amount is missing, the limit and current amount of in-progress test cases will be shown.
+
+**test|goto|<id>**
+
+Updates current test pointer position.
+
+**test|look[|id]**
+
+Show programmed test case for id provided, current 'in-process' test case when missing.
+Test cases reports are not dumped on process context (too many information in general).
+The report contains context information in every moment: this operation acts as a snapshot.
+
+**test|state[|id]**
+
+Get test case state for id provided, current 'in-process' test case when missing.
+
+**test|interact|amount[|id]**
+
+Makes interactive a specific test case id. The amount is the margin of execution steps to be done. Normally, we will execute 'test|interact|0[|<test case id>]', which means that the test case is selected to be interactive, but no step is executed. Then you have to interact with positive amounts (usually 1), executing the provided number of steps if they are ready and fulfill the needed conditions. The value of 0, implies no execution steps margin, which could be useful to 'freeze' a test in the middle of its execution.
+You could also provide -1 to make it non-interactive resuming it from the current step.
+By default, current test case id is selected for interaction.
+
+**test|reset|<[soft]/hard>[|id]**
+
+Reset the test case for id provided, all the tests when missing. It could be hard/soft:
+
+- hard: you probably may need to stop the load rate before. This operation initializes all test cases regardless their states.
+- soft: only for finished cases (those with 'Success' or 'Failed' states). It does not affect to test cases with 'InProgress' state.
+
+**test|repeats|<amount>**
+
+Restarts the whole programmed test list when finished the amount number of times (repeats forever if value -1 is provided). This is disabled by default (amount = 0): testing trigger system will enter suspended state until new ttps operation is received and a soft reset has been done before. Test cases state & data will be reset (when achieved again), but general statistics and counters will continue measuring until reset with 'collect' operation.
+
+**test|auto-reset|<soft|hard>**
+
+When cycling, current test cases can be soft (default) or hard reset. If no timeout has been configured for the test case, hard reset could prevent stuck on the next cycle for those test cases still in progress.
+
+**test|initialized**
+
+Shows the number of initialized test cases. Zero-value means that everything was processed or not initiated yet.
+
+**test|finished**
+
+Shows the number of finished (successful or failed) test cases.
+
+**test|clear**
+
+Clears all the programmed test cases and stop testing (if in progress).
+
+**test|junit**
+
+Shows the junit report in the moment of execution.
+
+**test|summary-counts**
+
+Test manager counts report. Counts by state and prints total verdict.
+
+**test|summary-states**
+
+Test manager states report.
+
+**test|summary**
+
+Test manager general report (number of test cases, counts by state, global configuration, forced in-progress limitation, reports visibility, etc.). Be careful when you have reports enabled because the programmed test cases dumps could be heavy (anyway you could enable the dumps separately, for any of the possible states: Initialized, InProgress, Failed, Success).
+
+**test|report|<initialized/in-progress/failed/success/[all]/none>[|[yes]|no]**
+
+Enables/disables report generation for a certain test case state: initialized, in-progress, failed or success (also 'all' and 'none' reserved words could be used). This applies to report summary (former described operation) and automatic dumps during testing where only failed or successful states will appear: every time a test case is finished its xml representation will be dump on a file under the execution directory (or the one configured in process command-line 'tmDir') with the name: 'cycle-<cycle id>.testcase-<test case id>.xml'.
+
+By default, all the states are disabled to avoid IO overload. In most of cases not all the tests are going to fail then you could enable only such failed dumps. Anyway you could set the reports visibility to fit your needs in a given situation
+
+**test|report-hex[|[yes]|no]**
+
+Reports could include the diameter messages in hexadecimal format. Disabled by default.
+
+**test|dump-stdout[|[yes]|no]**
+
+Test manager information is dumped into stdout.
+
+### Dynamic procedure
+
+**dynamic[|args]**
+
+This launch an internal operation implemented in 'Procedure' class. Its default implementation does nothing, but you could create a dynamic library 'libanna_launcherDynamic.so' and replace the one in this project. One interesting application consists in the use of the diameter API and event operation to create a set of libraries as the testing framework.
+To execute each test case, the ADML process would be executed with a specific library path. But the main use would be the stress programming to achieve a great amount of cloned (even mixed) tests without using the management operation interface by mean http or signals: a single call to 'dynamic' would be enough to start a cascade of internally implemented operations.
+This operation accepts a generic string argument (piped or not, as you desire and depending on your procedure implementation).
+
+This operation requires advanced programming and knowlegde of ANNA Diameter stack and testing framework, to take advantage of all the possibilities.
+
+
+# HTTP Interface
+
+All the operations described above can be used through the optional HTTP interface. You only have
+ to define the http server at the command line with something like: '--httpServer localhost:9000'.
+To send the task, we shall build the http POST request json body with the operation string.
+
+ Json specification covers a subset for previous:
+
index 5cff3c7..18211fe 100755 (executable)
@@ -18,7 +18,7 @@ echo
 SERVER=`cat .httpServer`
 
 # Send operation:
-[ "$1" = "" ] && _exit "Usage: $0 <operation string>; i.e.: $0 help"
+[ "$1" = "" ] && _exit "Usage: $0 <operation string>; i.e.: $0 node"
 #> curl_log.txt
 #TRACE="--trace-ascii curl_log.txt"
 curl -m 1 --data "$1" $SERVER
index 4a9d0a7..87e4ce5 100755 (executable)
@@ -116,17 +116,17 @@ check_pid $PID
 kill -s SIGUSR2 $PID
 
 # Detect EOF and print all except that last line:
-count=$((10*timeout))                                                      
+count=$((10*timeout))
 expired=yes
-while [ $count -gt 0 ]                                           
-do                                                                               
-  sleep 0.1                                                                      
-  count=$((count-1))                                                             
+while [ $count -gt 0 ]
+do
+  sleep 0.1
+  count=$((count-1))
   if tail -1 sigusr2.out | grep "^EOF" >/dev/null; then
     expired=
     break;
   fi
-done                                                                             
+done
 
 if [ -z "$expired" ]
 then
index 27cd9ea..3413e1f 100755 (executable)
@@ -71,9 +71,8 @@
    log:                                     Process log file (operations result, traffic log, etc.). By default '<originHost>.launcher.log'.
                                             Empty string or \"null\" name, to disable. Warning: there is no rotation for log files
                                             (use logrotate or whatever you consider).
-   splitLog:                                Splits log file (appends to log filename, extensions with the type of event: see help on
-                                            startup information-level traces). No log files for code/decode and load operations are created.
-                                            Default value 'no'.
+   splitLog:                                Splits log file (appends to log filename, extensions with the type of event: check 'HELP.md' for
+                                            more information. No log files for code/decode and load operations are created. Default value 'no'.
    detailedLog:                             Insert detailed information at log files (timestamps, communication resources, etc.). Useful
                                             to analyze the messages flow along the sockets (specially on 'balance' mode). Default 'no'.
    dumpLog:                                 Write to disk every incoming/outcoming message named as: