3 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.
5 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.
7 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.
9 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.
11 As any other ANNA process, context dump could be retrieved sending SIGUSR1 signal:
16 vi /var/tmp/anna.context.<pid>
18 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.
20 Also SIGUSR2 is handled for management purposes. We will talk later about this.
26 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:
32 > <stack id=\"0\" dictionary=\"dictionary.xml\"/>
35 > <node originHost=\"ADML-client\" applicationId=\"0\" entity=\"localhost:3868\"/>
42 > <stack id=\"0\" dictionary=\"dictionary.xml\"/>
45 > <node originHost=\"ADML-server\" applicationId=\"0\" diameterServer=\"localhost:3868\"/>
48 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:
50 Client and server configuration:
54 > <stack id=\"16777236\" dictionary=\"dictionary_Rx.xml\"/>
55 > <stack id=\"16777238\" dictionary=\"dictionary_Gx.xml\"/>
56 > <stack id=\"0\" dictionary=\"dictionary_base.xml\"/>
59 > <node originHost=\"ADML-Rx-client\" applicationId=\"16777236\" entity=\"localhost:3868\" cer=\"cer_Rx.xml\"/>
60 > <node originHost=\"ADML-Gx-client\" applicationId=\"16777238\" entity=\"localhost:3868\" cer=\"cer_Gx.xml\"/>
63 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).
68 ADML supports several operations which could be recognized via SIGUSR2 caugh or HTTP interface:
72 Requires the creation of the task(s) file which will be read at signal event:
74 > echo \"<operation>\" > "; result += getSignalUSR2InputFile();
78 > kill -s SIGUSR2 <pid>
79 > and then see the results:
80 > cat "; result += getSignalUSR2OutputFile();
82 (this file is ended with EOF final line, useful managing huge batch files to ensure the job completion)
84 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.
86 An operation is specified by mean a string containing the operation name and needed arguments separated by pipes. These are the available commands:
92 Selects a context working node by mean a registered name (origin-host).
93 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.).
95 Empty parameter will show the current configuration.
99 Returns to the default behaviour (smart node selection).
100 Depending on the operation, this could imply a global action scope, affecting to all the registered hosts.
101 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.
103 ### Parsing operations
105 **code|<source_file>|<target_file>**
107 Encodes source file (pathfile) into target file (pathfile).
109 **decode|<source_file>|<target_file>**
111 Decodes source file (pathfile) into target file (pathfile).
113 **loadxml|<source_file>**
115 Reinterpret xml source file (pathfile).
119 **services[|<source file>]**
121 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.
122 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.
124 **diameterServerSessions|<integer>**
126 Updates the maximum number of accepted connections to diameter server socket.
128 **change-dir[|directory]**
130 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.
132 ### Client sessions visibility
134 <action: **hide**, **show**, **hidden**, **shown**>|<address>:<port>|<socket>
136 *Actions*: hide, show (update state) and hidden, shown (query state).
137 Acts over a client session for messages delivery (except CER/A, DWR/A, DPR/A).
138 If missing server (first parameter) all applications sockets will be affected.
139 If missing socket (second parameter) for specific server, all its sockets will be affected.
141 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.
147 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.
149 **context[|<target file>]**
151 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.
153 **forceCountersRecord**
155 Forces dump to file the current counters of the process.
157 **log-statistics-samples|<list>**
159 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.
163 Dumps current counters of the process. This is also done at process context dump.
167 Dumps statistics of the process. This is also done at process context dump.
171 **sendxml2e|<source_file>**
173 Sends xml source file (pathfile) through configured entity.
175 **sendxml2c|<source_file>**
177 Sends xml source file (pathfile) to client.
179 **answerxml2e[|source_file]**
181 Answer xml source file (pathfile) for incoming request with same code from entity.
182 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.
184 **answerxml2c[|source_file]**
186 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.
190 List programmed answers (to entity/client) if no parameter provided.
192 **answerxml<2e/2c>|dump**
194 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.
196 **answerxml<2e/2c>|clear**
198 Clear programmed answers (to entity/client).
200 **answerxml<2e/2c>|exhaust**
202 Disable the corresponding queue rotation, which is the default behaviour.
204 **answerxml<2e/2c>|rotate**
206 Enable the corresponding queue rotation, useful in performance tests. Rotation consists in add again to the queue, each element retrieved for answering.
208 Send operations are available using hexadecimal content (hex formatted files) which also allow to test
209 special scenarios (protocol errors):
211 **sendhex2e|<source_file>**
213 Sends hex source file (pathfile) through configured entity.
215 **sendhex2c|<source_file>**
217 Sends hex source file (pathfile) to client.
219 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.
221 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.
223 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.
225 (*) 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.
227 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.
229 ### Processing types (log tags)
231 Used as log file extensions (when '--splitLog' is provided on command line) and context preffixes on log
232 details when unique log file is dumped:
234 | MULTIPLEXOR IDENTIFIER | Description |
235 | ---------------------- | ------------------------------------------------------------ |
236 | [sent2e/send2eError] | Send to entity (success/error) |
237 | [sent2c/send2cError] | Send to client (success/error) |
238 | [fwd2e/fwd2eError] | Forward to entity a reception from client (success/error) |
239 | [fwd2c/fwd2cError] | Forward to client a reception from entity (success/error) |
240 | [recvfc] | Reception from client |
241 | [recvfe] | Reception from entity |
242 | [req2c-expired] | A request sent to client has been expired |
243 | [req2e-expired] | A request sent to entity has been expired |
244 | [recvfc-ans-unknown] | Reception from client of an unknown answer (probably former [req2c-expired] has been logged) |
245 | [recvfe-ans-unknown] | Reception from entity of an unknown answer (probably former [req2e-expired] has been logged) |
246 | [retry] | Request retransmission |
250 In order to simplify user experience, burst category operations are only allowed in single host node
251 configuration. Indeed, you could send messages with unmatched Origin-Host, and no warning is shown.
252 All the operations are performed through the unique host: if you need to use more interfaces, you may
253 launch different ADML instances. Is nonsense to allow burst in a multi-host configured ADML, because
254 this feature is not able to coordinate the messages.
256 **burst|<action>[|parameter]**
258 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.
260 | OPERATION | DESCRIPTION |
261 | ---------------------------- | ------------------------------------------------------------ |
262 | burst\|clear | Clears all loaded burst messages. |
263 | burst\|load\|<source_file> | Loads the next diameter message into launcher burst. |
264 | burst\|start\|<initial load> | Starts (or restarts if already in progress) the message sending with a certain initial load. |
265 | burst\|push\|<load amount> | Sends specific non-aynchronous load. |
266 | 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. |
267 | burst\|stop\| | Stops the burst cycle. You can resume pushing 1 load amount. |
268 | 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. |
269 | 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). |
270 | burst\|goto\|<order> | Updates current burst pointer position. |
271 | burst\|look[\|order] | Show programmed burst message for order provided, current when missing. |
273 ### Advanced testing (FSM, finite state machine)
275 Burst mode only allows single interface interaction. For multiple interface (origin-host) coordination, you could use the advanced test cases programming:
277 **test|<id>|<command>[|parameters]**
279 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.
281 <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.).
283 <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:
287 > **description|<description>**
289 > Sets a test case description. Test cases by default are constructed with description 'Testcase_<id>'.
291 > **ip-limit[|amount]**
293 > 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.
295 > **timeout|<msecs>**
297 > 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.
298 > It is highly recommended to program a initial timeout step, or the test case could be eternally in-progress.
300 > **sendxml2e|<source_file>[|<step number>]**
301 > Sends xml source file (pathfile) to entity (it would be a 'forward' event if it came through local server endpoint).
302 > 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.
303 > In the case of requests, the step number is used to force the copy of Session-Id value from the referred step.
305 > **sendxml2c|<source_file>[|<step number>]**
306 > 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.
310 > 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.
312 > **sh-command|<script>**
314 > 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:
315 > Test pool cycle id: ##cycleid##
316 > Test case id: ##testcaseid##
317 > Test step id: ##teststepid##
319 > For example, your command could be something like this:
321 > > insert_sql_##testcaseid##.sh -db dbname --verbose > /tmp/cycle-##cycleid##.testcase-##testcaseid##.teststep-##teststepid##.out
325 > 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.
327 > **wait<fe/fc>-hex|<source_file>[|strict]**
328 > 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'.
329 > 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.
331 > **wait<fe/fc>-xml|<source_file>[|strict]**
332 > 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.
334 > **wait<fe/fc>|<condition>**
336 > 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.
340 > > 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).
342 > > 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).
343 > > 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).
345 > > Condition format is: **[code]|[bitR]|[hopByHop]|[applicationId]|[sessionId]|[resultCode]|[msisdn]|[imsi]|[serviceContextId]**
347 > > *code*: integer number
348 > > *bitR*: 1 (request), 0 (answer)
349 > > *hopByHop*: integer number or request send step reference: #<step number>
351 > > 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.
352 > > This 'hop-by-hop' variant eases the wait condition for answers in the safest way.
354 > > *applicationId*: integer number
355 > > *sessionId*: string
356 > > *resultCode*: integer number
359 > > *serviceContextId*: string
361 > > Take into account these rules, useful in general:
363 > > - 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).
364 > > - Adding a ResultCode and/or HopByHop to the condition are only valid waiting answers.
365 > > - Requests hop-by-hop values must be different for all the test case requests.
366 > > 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.
368 #### Programming example:
370 *Basic Rx/Gx scenary: PCEF (Gx) - PCRF - AF (Rx)*
373 test|1|sendxml2e|CCR-I.xml
374 test|1|waitfe|272|0|||SGx|2001
375 test|1|sendxml2e|AAR-flows.xml
376 test|1|waitfe|265|0|||SRx|2001
377 test|1|waitfe|258|1|||SGx
378 test|1|sendxml2e|RAA-install.xml|6
379 test|1|sendxml2e|CCR-T.xml
380 test|1|waitfe|272|0|H1||SGx|2001
381 test|1|waitfe|258|1|||SGx
382 test|1|sendxml2e|RAA-remove.xml|10
386 - Step 1: whole time requirement is 5 seconds
387 - Step 2: imagine this xml uses the Session-Id 'SGx'
388 - Step 3: waits the CCA for the CCR-I with Result-Code = DIAMETER_SUCCESS
389 - Step 4: imagine this xml uses the Session-Id 'SRx'
390 - Step 5: waits the AAA for the AAR-flows with Result-Code = DIAMETER_SUCCESS
391 - Step 6: waits the RAR (install policies) from the PCRF server
392 - Step 7: sends the response for the RAR
393 - Step 8: termination of the Gx session, imagine this xml puts hop-by-hop 'H1'
394 - Step 9: waits the CCA for the CCR-T with Result-Code = DIAMETER_SUCCESS and hop-by-hop 'H1'
395 - Step 10: waits the RAR (remove policies) from the PCRF server
396 - Step 11: sends the response for the RAR
402 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.
404 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.
406 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).
408 Other simplifications: the steps 3, 5 and 9 can be replaced by
414 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).
416 #### Test cases execution:
418 **test|ttps|<amount>**
420 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.
422 Provide 0 in order to stop the timer triggering.
424 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.
426 **test|next[|<sync-amount>]**
428 Forces the execution of the next test case(s) without waiting for test manager tick.
429 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.
431 **test|ip-limit[|amount]**
433 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.
434 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.
438 Updates current test pointer position. Take into account, that 'test|next' will execute the next test case, not the one pointed with *goto*.
442 Run the test case selected.
446 Show programmed test case for id provided, current 'in-process' test case when missing.
447 Test cases reports are not dumped on process context (too many information in general).
448 The report contains context information in every moment: this operation acts as a snapshot.
452 Get test case state for id provided, current 'in-process' test case when missing.
454 **test|interact|amount[|id]**
456 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.
457 You could also provide -1 to make it non-interactive resuming it from the current step.
458 By default, current test case id is selected for interaction.
460 **test|reset|<[soft]/hard>[|id]**
462 Reset the test case for id provided, all the tests when missing. It could be hard/soft:
464 - hard: you probably may need to stop the load rate before. This operation initializes all test cases regardless their states.
465 - soft: only for finished cases (those with 'Success' or 'Failed' states). It does not affect to test cases with 'InProgress' state.
467 **test|repeats|<amount>**
469 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.
471 **test|auto-reset|<soft|hard>**
473 When cycling, current test cases can be soft 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.
477 Shows the number of initialized test cases. Zero-value means that everything was processed or not initiated yet.
481 Shows the number of finished (successful or failed) test cases.
485 Clears all the programmed test cases and stop testing (if in progress).
489 Shows the junit report in the moment of execution.
491 **test|summary-counts**
493 Test manager counts report. Counts by state and prints total verdict.
495 **test|summary-states**
497 Test manager states report.
501 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).
503 **test|report|<initialized/in-progress/failed/success/[all]/none>[|[yes]|no]**
505 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'.
507 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
509 **test|report-hex[|[yes]|no]**
511 Reports could include the diameter messages in hexadecimal format. Disabled by default.
513 **test|dump-stdout[|[yes]|no]**
515 Test manager information is dumped into stdout.
517 ### Dynamic procedure
521 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.
522 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.
523 This operation accepts a generic string argument (piped or not, as you desire and depending on your procedure implementation).
525 This operation requires advanced programming and knowlegde of ANNA Diameter stack and testing framework, to take advantage of all the possibilities.
530 Most of the operations described above can be used through the optional HTTP1.1 interface. You only have
531 to define the http server at the command line with something like: '--httpServer localhost:8000'.
532 REST API specification.
534 **We will describe briefly the supported *GET* & *POST* operations, but you could extend the explanation from SIGUSR2 interface description above**.
536 Implemented status codes: *200* (ok), *400* (bad request) and *405* (method not allowed).
540 > curl -v --request GET localhost:8000<uri>
542 You could also expose the service as HTTP2 server through *nginx* working as reverse proxy (*anna-adml-http* image is built in this way although internally provides HTTP operations script only for 1.1). Then you could use HTTP2 clients like *nghttp*:
544 > nghttp -v -H ":method: GET" "<uri>"
552 Retrieve oam xml report (will be *base64-encoded* at response).
558 "result":"<true or false>",
559 "response":"<error description or base64-encoded xml report>"
565 Retrieve statistics xml report (will be *base64-encoded* at response).
571 "result":"<true or false>",
572 "response":"<error description or base64-encoded xml report>"
580 > curl -v --request POST -H "Content-Type: application/json" localhost:8000<uri> -d@test.json
582 You could also expose the service as HTTP2 server through *nginx* working as reverse proxy (*anna-adml-http* image is built in this way although internally provides HTTP operations script only for 1.1). Then you could use HTTP2 clients like *nghttp*:
584 > nghttp -v -H ":method: POST" -d test.json "<uri>"
588 **Important note:** Anna Suite work natively with xml. Although REST API supports diameter messages (*diameterJson* fields) and services configuration (*servicesJson* fields) in *json* format, these messages are not validated directly with a *json schema*. Instead, the *json* object are converted to *xml* at ADML and the resulting xml representations are validates against *dtd* schemas:
590 Schema for diameter messages: [here](../../../../include/anna/diameter/codec/message.dtd).
592 Schema for configuration services: [here](./services_examples/services.dtd).
594 There are lots of examples for *xml diameter messages and xml services* (normally deployed with *ADML* at `./xml_examples` and `./services_examples`), then you could transform them to the *json format* accepted by the REST API easily, for example using *xmltodict* python module:
605 print("Usage: " + sys.argv[0] + " <diameter xml file>")
609 with open(file, 'r') as myfile:
612 print("ERROR reading '" + file + "'")
615 # although default attribute prefix is '@', anyway we will
616 # force the value just in case xmltodict implementation
617 # changes. The anna::core::functions::json2xml helper,
618 # assumes this prefix in order to work properly.
619 my_dict=xmltodict.parse(xml, attr_prefix='@')
620 json_data=json.dumps(my_dict, indent=3, sort_keys=True)
624 **Former script is packaged** together with REST API component tests under `./diameterJsonHelper/xml2json.py`.
626 Native example for *AA-Request* diameter message:
629 <message version="1" name="AA-Request" p-bit="yes" application-id="16777236" hop-by-hop-id="0" end-to-end-id="0">
630 <avp name="Session-Id" data="test1;afNodeHostname.nodeHostRealm.com;1;8033450"/>
631 <avp name="Auth-Application-Id" data="16777236"/>
632 <avp name="Origin-Host" data="afHost.afRealm.com"/>
633 <avp name="Origin-Realm" data="afRealm.com"/>
634 <avp name="Destination-Realm" data="operatorRealm.com"/>
635 <avp name="Destination-Host" data="ownHostId.operatorRealm.com"/>
636 <avp name="AF-Application-Identifier" hex-data="313232"/>
637 <avp name="Media-Component-Description">
638 <avp name="Media-Component-Number" data="0"/>
639 <avp name="AF-Application-Identifier" hex-data="313232"/>
640 <avp name="Max-Requested-Bandwidth-UL" data="127"/>
641 <avp name="Max-Requested-Bandwidth-DL" data="133"/>
642 <avp name="Flow-Status" data="2" alias="ENABLED"/>
643 <avp name="Reservation-Priority" data="0" alias="DEFAULT"/>
645 <avp name="Service-Info-Status" data="0" alias="FINAL_SERVICE_INFORMATION"/>
646 <avp name="Subscription-Id">
647 <avp name="Subscription-Id-Type" data="0" alias="END_USER_E164"/>
648 <avp name="Subscription-Id-Data" data="626037099"/>
650 <avp name="Framed-IP-Address" hex-data="3139322e3136382e302e31"/>
651 <avp name="Called-Station-Id" hex-data="5741502e4d4f564953544152"/>
656 Corresponding content in *json* format:
661 "@application-id": "16777236",
662 "@end-to-end-id": "0",
663 "@hop-by-hop-id": "0",
664 "@name": "AA-Request",
669 "@data": "test1;afNodeHostname.nodeHostRealm.com;1;8033450",
670 "@name": "Session-Id"
674 "@name": "Auth-Application-Id"
677 "@data": "afHost.afRealm.com",
678 "@name": "Origin-Host"
681 "@data": "afRealm.com",
682 "@name": "Origin-Realm"
685 "@data": "operatorRealm.com",
686 "@name": "Destination-Realm"
689 "@data": "ownHostId.operatorRealm.com",
690 "@name": "Destination-Host"
693 "@hex-data": "313232",
694 "@name": "AF-Application-Identifier"
697 "@name": "Media-Component-Description",
701 "@name": "Media-Component-Number"
704 "@hex-data": "313232",
705 "@name": "AF-Application-Identifier"
709 "@name": "Max-Requested-Bandwidth-UL"
713 "@name": "Max-Requested-Bandwidth-DL"
718 "@name": "Flow-Status"
723 "@name": "Reservation-Priority"
728 "@alias": "FINAL_SERVICE_INFORMATION",
730 "@name": "Service-Info-Status"
733 "@name": "Subscription-Id",
736 "@alias": "END_USER_E164",
738 "@name": "Subscription-Id-Type"
741 "@data": "626037099",
742 "@name": "Subscription-Id-Data"
747 "@hex-data": "3139322e3136382e302e31",
748 "@name": "Framed-IP-Address"
751 "@hex-data": "5741502e4d4f564953544152",
752 "@name": "Called-Station-Id"
759 Native example for a services configuration example:
766 * Monostack: you could select any id value, normally 0.
767 * Multistack: use the application id for the id value.
768 This eases codec engine selection for
771 <stack id="0" dictionary="dictionary.xml" fixMode="Always" ignoreFlagsOnValidation="yes"/>
778 <node originHost="<origin host>" applicationId="<application id>"
779 entity="<addr1:port1[,addr2:port2]...[,addrN:portN]>"
780 cer="<cer xml file>" answersTimeout="300000" dumpLog="yes"/>
784 <node originHost="<origin host>" applicationId="<application id>"
785 diameterServer="<addr:port>" diameterServerSessions="10"
786 cea="<cea xml file>" answersTimeout="300000" dumpLog="yes"/>
788 <node originHost="afHost.afRealm.com" applicationId="0" entity="localhost:3868"/>
789 <node originHost="ownHostId.operatorRealm.com" applicationId="0"
790 diameterServer="localhost:3868" diameterServerSessions="1"/>
795 And the converted *json* equivalent:
802 "@applicationId": "0",
803 "@entity": "localhost:3868",
804 "@originHost": "afHost.afRealm.com"
807 "@applicationId": "0",
808 "@diameterServer": "localhost:3868",
809 "@diameterServerSessions": "1",
810 "@originHost": "ownHostId.operatorRealm.com"
814 "@dictionary": "dictionary.xml",
815 "@fixMode": "Always",
817 "@ignoreFlagsOnValidation": "yes"
825 **Note that the '@' character is mandatory to indicate attribute keys, and it is necessary to complete the *"json to xml"* conversion successfully at ADML REST Server endpoint.**
833 Selects a context working node by mean a registered name (origin-host). If empty, current node information is retrieved.
847 "result":"<true or false>",
848 "response":"<error description or base64-encoded xml information>"
854 Smart node selection.
856 **Request body**: none
862 "result":"<true or false>",
863 "response":"<response>"
867 ### Parsing operations
871 Encodes a diameter json into hexadecimal representation.
877 "diameterJson":<diameter message json object>
885 "result":"<true or false>",
886 "response":"<error description or diameter hex>"
892 Decodes an hexadecimal string (no spaces, no colons, i.e.: `01000150c0...`), into diameter xml (*base64-encoded*).
898 "diameterHex":"<hex string>"
906 "result":"<true or false>",
907 "response":"<error description or base64-encoded xml diameter message>"
913 Reinterprets diameter json into xml (*base64-encoded*).
919 "diameterJson":<diameter message json object>
927 "result":"<true or false>",
928 "response":"<error description or base64-encoded xml diameter message>"
936 Referred files (*dictionaries, cer, cea, etc.*) shall be accesible for ADML and are not provided in this operation.
942 "servicesJson":<services json object>
950 "result":"<true or false>",
951 "response":"<response>"
955 #### POST /diameterServerSessions
957 Updates diameter server sessions to be accepted.
963 "sessions":<sessions (integer)>
971 "result":"<true or false>",
972 "response":"<response>"
976 #### POST /change-dir
978 Updates ADML working directory.
984 "directory":"<directory path or empty to restore initial working directory>"
992 "result":"<true or false>",
993 "response":"<response>"
997 ### Client sessions visibility
999 #### POST /visibility
1005 "action":"<hide|show|hidden|shown>"
1006 [, "addressPort":"<address:port>"]
1007 [, "socket":<socket id (integer)>]
1015 "result":"<true or false>",
1016 "response":"<response>"
1024 Reset statistics and counters.
1026 **Request body**: none
1032 "result":"<true or false>",
1033 "response":"<response>"
1039 Dump ADML context at file path provided. If empty (or field missing), default path is selected. Context information is not retrieved in the response, so, file is related to ADML execution context.
1045 ["targetFile":"[file path]"]
1053 "result":"<true or false>",
1054 "response":"<response>"
1058 #### POST /forceCountersRecord
1060 Forces dump to file the current counters of the process.
1062 **Request body**: none
1068 "result":"<true or false>",
1069 "response":"<response>"
1073 #### POST /log-statistics-samples
1075 Set the statistics concepts to be logged. To know the concept indentifiers registered, get the ADML context information.
1081 ["list":"<comma-separated list|[all]|none>"]
1089 "result":"<true or false>",
1090 "response":"<response>"
1096 #### POST /sendmsg2e
1098 Sends diameter json message **to**(2) the connected **entity**(e).
1104 "diameterJson":<diameter message json object>
1112 "result":"<true or false>",
1113 "response":"<response>"
1117 #### POST /sendmsg2c
1119 Sends diameter json message **to**(2) the connected **client**(c).
1125 "diameterJson":<diameter message json object>
1133 "result":"<true or false>",
1134 "response":"<response>"
1138 #### POST /answermsg2e
1140 Answers diameter json message **to**(2) the connected **entity**(e).
1142 Mocking FIFO queue based in message code.
1148 "diameterJson":<diameter message json object>
1156 "action":"[action: <[list]|dump|clear|exhaust|rotate>]"
1164 "result":"<true or false>",
1165 "response":"<response or base64-encoded output for 'list' action>"
1169 #### POST /answermsg2c
1171 Answers diameter json message **to**(2) the connected **client**(c).
1173 Mocking FIFO queue based in message code.
1179 "diameterJson":<diameter message json object>
1187 "action":"[action: <[list]|dump|clear|exhaust|rotate>]"
1195 "result":"<true or false>",
1196 "response":"<response or base64-encoded output for 'list' action>"
1200 #### POST /sendhex2e
1202 Sends diameter expressed in hexadecimal string (no spaces, no colons, i.e.: `01000150c0...`), **to**(2) the connected **entity**(e).
1208 "diameterHex":"<hex string>"
1216 "result":"<true or false>",
1217 "response":"<response>"
1221 #### POST /sendhex2c
1223 Sends diameter expressed in hexadecimal string (no spaces, no colons, i.e.: `01000150c0...`), **to**(2) the connected **client**(c).
1229 "diameterHex":"<hex string>"
1237 "result":"<true or false>",
1238 "response":"<response>"
1244 ADML implements a bulting *Finite State Machine* to plan testing flows with a great flexibility.
1246 #### POST /testid-description/{id}
1252 "description":"<description (string)>"
1260 "result":"<true or false>",
1261 "response":"<response>"
1265 #### POST /testid-ip-limit/{id}
1267 In-Progress limit is the maximum number of tests which can be executed in parallel.
1268 This operation allows a specific test to set this global pool behaviour.
1270 Zero-value is equivalent to stop the clock (no tests will be executed).
1272 Value '-1' means 'no limit' (full parallel). Be careful with resources consumption.
1278 "amount":[amount (integer, 1 by default: execution in sequence)]
1286 "result":"<true or false>",
1287 "response":"<response>"
1291 #### POST /testid-timeout/{id}
1297 "msecs":<milliseconds (integer)>
1305 "result":"<true or false>",
1306 "response":"<response>"
1310 #### POST /testid-sendmsg2e/{id}
1316 "diameterJson":<diameter message json object>
1317 [,"stepNumber":[amount (integer, -1 no step associated)]]
1325 "result":"<true or false>",
1326 "response":"<response>"
1330 #### POST /testid-sendmsg2c/{id}
1336 "diameterJson":<diameter message json object>
1337 [,"stepNumber":[amount (integer, -1 no step associated)]]
1345 "result":"<true or false>",
1346 "response":"<response>"
1350 #### POST /testid-delay/{id}
1356 "msecs":<milliseconds (integer)>
1364 "result":"<true or false>",
1365 "response":"<response>"
1369 #### POST /testid-sh-command/{id}
1383 "result":"<true or false>",
1384 "response":"<response>"
1388 #### POST /testid-waitfe-hex/{id}
1394 "hex":"<hex string>"
1395 [,"strict":"[<true|[false]>]"]]
1403 "result":"<true or false>",
1404 "response":"<response>"
1408 #### POST /testid-waitfc-hex/{id}
1414 "hex":"<hex string>"
1415 [,"strict":"[<true|[false]>]"]]
1423 "result":"<true or false>",
1424 "response":"<response>"
1428 #### POST /testid-waitfe-msg/{id}
1434 "diameterJson":<diameter message json object>
1435 [,"strict":"[<true|[false]>]"]]
1443 "result":"<true or false>",
1444 "response":"<response>"
1448 #### POST /testid-waitfc-msg/{id}
1454 "diameterJson":<diameter message json object>
1455 [,"strict":"[<true|[false]>]"]]
1463 "result":"<true or false>",
1464 "response":"<response>"
1468 #### POST /testid-waitfe/{id}
1475 "code":"[(integer)]",
1477 "hopByHop":"[(integer)]",
1478 "applicationId":"[(integer)]",
1479 "sessionId":"[session id]",
1480 "resultCode":"[(integer)]",
1481 "msisdn":"[msisdn]",
1483 "serviceContextId":"[service context id]"
1492 "result":"<true or false>",
1493 "response":"<response>"
1497 #### POST /testid-waitfc/{id}
1504 "code":"[(integer)]",
1506 "hopByHop":"[(integer)]",
1507 "applicationId":"[(integer)]",
1508 "sessionId":"[session id]",
1509 "resultCode":"[(integer)]",
1510 "msisdn":"[msisdn]",
1512 "serviceContextId":"[service context id]"
1521 "result":"<true or false>",
1522 "response":"<response>"
1526 ### FSM TESTING EXECUTION ACTIONS
1528 #### POST /test-ttps
1534 "amount":<amount (integer)>
1542 "result":"<true or false>",
1543 "response":"<response>"
1547 #### POST /test-next
1553 ["syncAmount":[amount (integer: 1 by default)]]
1561 "result":"<true or false>",
1562 "response":"<response>"
1566 #### POST /test-ip-limit
1568 Global operation (also at test identifier level is accessible).
1570 Zero-value is equivalent to stop the clock (no tests will be executed).
1572 Value '-1' means 'no limit' (full parallel). Be careful with resources consumption.
1574 Defaults to '-2' (no '-1' which is default for *testid-ip-limit* version), which wil show the current pool *ip-limit* and also the number of test cases which are *in progress*.
1580 ["amount":[amount (integer, shows current ip-limit and in-progress test cases amount, by default (-2))]]
1588 "result":"<true or false>",
1589 "response":"<response>"
1593 #### POST /test-goto
1599 "id":<test identifier>
1607 "result":"<true or false>",
1608 "response":"<response>"
1618 "id":<test identifier>
1626 "result":"<true or false>",
1627 "response":"<response>"
1631 #### POST /test-look
1637 ["id":[test identifier (integer: current by default (-1))]]
1645 "result":"<true or false>",
1646 "response":"<base64-encoded output>"
1650 #### POST /test-state
1656 ["id":[test identifier (integer: current by default (-1))]]
1664 "result":"<true: if state is 'Success' or false>",
1665 "response":"<response>"
1669 #### POST /test-interact
1671 Makes interactive a specific test case id. The amount of 0, implies no execution steps margin, which could be useful to 'freeze' a test in the middle of its execution. Value -1 makes it non-interactive resuming it from the current step.
1677 "amount":<amount (integer)>
1678 [,"id":[test identifier (integer: current by default (-1))]]
1686 "result":"<true or false>",
1687 "response":"<response>"
1691 #### POST /test-reset
1697 ["type":"<[soft]|hard>"]
1698 [,"id":[test identifier (integer: apply to all the tests (-1))]]
1706 "result":"<true or false>",
1707 "response":"<response>"
1711 #### POST /test-repeats
1717 "amount":<amount (integer)>
1725 "result":"<true or false>",
1726 "response":"<response>"
1730 #### POST /test-auto-reset
1736 "type":"<soft|hard>"
1744 "result":"<true or false>",
1745 "response":"<response>"
1749 #### POST /test-initialized
1751 **Request body**: none
1757 "result":"<true or false>",
1758 "response":"<response>"
1762 #### POST /test-finished
1764 **Request body**: none
1770 "result":"<true or false>",
1771 "response":"<response>"
1775 #### POST /test-clear
1777 **Request body**: none
1783 "result":"<true or false>",
1784 "response":"<response>"
1788 #### POST /test-junit
1790 As it could be very large, it will be dumped on provided target directory, '*/tmp/junit.xml*' by default.
1796 ["targetFile":"<file path>"]
1804 "result":"<true or false>",
1805 "response":"<response>"
1809 #### POST /test-summary-counts
1811 **Request body**: none
1817 "result":"<true or false>",
1818 "response":"<base64-encoded output>"
1822 #### POST /test-summary-states
1824 **Request body**: none
1830 "result":"<true or false>",
1831 "response":"<base64-encoded output>"
1835 #### POST /test-summary
1837 **Request body**: none
1843 "result":"<true or false>",
1844 "response":"<base64-encoded output>"
1848 #### POST /test-report
1854 ["state":"[<initialized|in-progress|failed|success|[all]|none>]"]
1855 [,"action":"[<[enable]|disable>]"]
1863 "result":"<true or false>",
1864 "response":"<response>"
1868 #### POST /test-report-hex
1874 ["action":"[<[enable]|disable>]"]
1882 "result":"<true or false>",
1883 "response":"<response>"
1887 #### POST /test-dump_stdout
1893 ["action":"[<[enable]|disable>]"]
1901 "result":"<true or false>",
1902 "response":"<response>"
1906 ### DYNAMIC PROCEDURE
1908 Used for system test. Arguments are determined by the way in a specific dynamic library is designed/documented.
1916 "arguments": <diameter arguments json object>
1924 "result":"<true or false>",
1925 "response":"<response>"