/** * @author ETSI * @version $URL: svn+ssh://vcs.etsi.org/TTCN3/LIB/Ttcn3LibCommon/trunk/ttcn/LibCommon_Sync.ttcn $ * $Id: LibCommon_Sync.ttcn 34 2009-05-25 13:12:29Z deshpande $ * @desc This module implements _one_ generic synchronization mechanism * for TTCN-3 test cases with one or more test components. * Key concept is here that one test component acts as a * synchronization server which listens and triggers one or more * synchronization clients. It is recomended to use the MTC always as * the synchronization server but in theory also a PTC can act as such * a server.

* This synchronization is used by calling a function on * the server test component to wait for a desired amount of clients * to notify the server that they have reached a specific synchronization * point. Each client test component must call another * function to perform this notification.

* In the event that a client is not able to reach a synchronization * point the server sends out a signal to all clients to abort the * test case. This signal is a STOP message which can be caught by * a test component default which in turn can then run a proper * shut down behavior based on the current state of the test * component.

* Note that this synchronization mechanism can also be used * in a special mode called "self synchronization" when a test case * only has one test component. Here, the test component in essence * acts as a server and client at the same time. The main benefit of * using self synchoronization is that the same shutdown mechanisms * can also be reused fomr the multi component test cases.

* This module contains a lot of TTCN-3 definitions. It has been * structured into tree main groups to help the user to identify * quickly relevant TTCN-3 definitions. For rookie users of this * module basicUserRelevantDefinitions should offer all the needed * definitions. Advanced users can consider use of definitions in * advancedUserRelevantDefinitions. Finally, internalDefinitions * are definitions which are required for the module to work * properly but do not need to be used in your code. Remember that * the main motiviation of this sychronization module is to offer * are _simple_ user interface. Practice has shown that when writing * actual test component behavior _only a handful_ of functions * usually wind up being used! Also check the synchronization examples * module for example uses of this synchronization mechanism.

* The invocation of the sync functions is also closely tied * to the verdict control functions which should also be reviewed * prior to using this module.

* This module has been derived from EtsiCommon_Synchronization * which was created in ETSIs STF256/276. It has been kept * intentionally separate to avoid conflicts with future ETSI * test suite releases. * @see LibCommon_Sync.basicUserRelevantDefinitions * @see LibCommon_Sync.advancedUserRelevantDefinitions * @remark End users should be aware that any changes made to the in * definitions this module may be overwritten in future releases. * End users are encouraged to contact the distributers of this * module regarding their modifications or additions so that future * updates will include your changes. */ module LibCommon_Sync { //Common import from LibCommon_BasicTypesAndValues { type UInt } ; import from LibCommon_AbstractData all; import from LibCommon_VerdictControl all; group stringStack { type record StringStack { UInt stackSize, StringItems stringItems } type record of charstring StringItems; /** * @desc Constant which can be used to initialize a * string stack. A string stack can be intialized by * assigning this value in the variable declariation. * An alternative is to call the initlialization function. * @see LibCommon_AbstractData.f_initStringStack * @remark Note that an initlialized stack stack is not * necessarily the same as an empty string stack. * An empty tring stack as 0 zero elements but may * have a non empty list of (empty) items. */ const StringStack c_initStringStack := { 0, {} } /** * @desc The invocation of this function will initialize * a string stack to an empty string stack. * An alternative is to initlialize a stack using a * constant value. * @see LibCommon_AbstractData.c_initStringStack * @param p_stack String stack to be initialized. */ function f_initStringStack ( inout StringStack p_stack ) { p_stack := c_initStringStack } /** * @desc This function checks if a string stack is empty. * @param p_stack String stack to be checked. * @return true if empty, false if not empty */ function f_isStringStackEmpty ( inout StringStack p_stack ) return boolean { if ( p_stack.stackSize == 0 ) {return true} else {return false} } /** * @desc This function checks if a given string is on the * string stack. * @param p_stack String stack where the string item * is to be looked for. * @param p_item String to be checked for. * @return true if found, false if not found */ function f_isItemOnStringStack ( inout StringStack p_stack, in charstring p_item ) return boolean { var integer i; for (i := 0; i < p_stack.stackSize; i := i+1 ) { if ( p_stack.stringItems[i] == p_item ) { return true; } } return false; } /** * @desc This function checks if a given string is on the * string stack. * @param p_stack String stack where the string item * is to be looked for. * @param p_item String item on top of the stack. * @return false if stack is empty, true otherwise */ function f_peekStringStackTop ( inout StringStack p_stack, out charstring p_item) return boolean { if (p_stack.stackSize == 0) { p_item := "f_peekTopStringStack: String stack is empty!"; return false; } p_item := p_stack.stringItems[p_stack.stackSize-1]; return true; } /** * @desc This function puts a string to the top of a * string stack. * @param p_stack String stack to which the string item * is to be added. * @param p_item String to be added. */ function f_pushStringStack ( inout StringStack p_stack, in charstring p_item ) { p_stack.stringItems[p_stack.stackSize] := p_item; p_stack.stackSize := p_stack.stackSize + 1; } /** * @desc This function removes the string from the top of a * string stack. If the stack is empty nothing is done * @param p_stack String stack from which the top string item * is to be removed. */ function f_popStringStack ( inout StringStack p_stack ) { if ( p_stack.stackSize > 0 ) { p_stack.stackSize := p_stack.stackSize-1; // "delete" top stack item to be safe // Note: due to record of index the "old top" is size-1! p_stack.stringItems[p_stack.stackSize] := ""; } } } // end group stringStack group basicUserRelevantDefinitions { group importantSyncTypeDefinitions { group compTypeRelated { /** * @desc This type is used to be the base of any synchronization * behavior which is to be executed on a sync server * component. The test component which acts as a * sync server in a test case must NOT directly use * this component type in its runs on clause! * Note that server synchronization functions may be * invoked by a test component as long as its * component type is type compatible to this component * type definition! */ type component BaseSyncComp { port SyncPort syncPort; timer tc_sync := PX_TSYNC_TIME_LIMIT; } /** * @desc This type is used to define any synchronization * behavior which is to be executed on a sync server * component. The test component which acts as a * sync server in a test case may - but does * not have to - directly use this component type its * runs on clause. * Note that server synchronization functions may be * invoked by a test component as long as its * component type is type compatible to this component * type definition! */ type component ServerSyncComp { timer tc_shutDown := PX_TSHUT_DOWN_TIME_LIMIT; // definitions for BaseSyncComp port SyncPort syncPort; timer tc_sync := PX_TSYNC_TIME_LIMIT; } with { extension "extends BaseSyncComp" } /** * @desc This type is used to define any synchronization * behavior which is to be executed on a sync client * component. The test component(s) which act as a * sync client in a test case may - but do not have * to - directly use this component type their runs * on clause. * Note that server synchronization functions may be * invoked by a test component as long as its * component type is type compatible to this component * type definition! */ type component ClientSyncComp { var StringStack v_stateStack:= c_initStringStack; // definitions for BaseSyncComp port SyncPort syncPort; timer tc_sync := PX_TSYNC_TIME_LIMIT; } with { extension "extends BaseSyncComp" } /** * @desc This type is used to define any synchronization * behavior which is relevant to non-concurrent test * cases. * Note that self synchronization functions may be * invoked by a test component as long as its * component type is type compatible to this component * type definition! * Note also that this type is type compatible to the * ClientSyncComp type so that shutdown altsteps from * concurrent test cases can also be reused in single * component test cases! * @see LibCommon_Sync.ClientSyncComp */ type component SelfSyncComp { port SyncPort syncSendPort; // definitions for ClientSyncComp var StringStack v_stateStack:= c_initStringStack; port SyncPort syncPort; timer tc_sync := PX_TSYNC_TIME_LIMIT; } with { extension "extends ClientSyncComp" } /** * @desc This port type must be imported into test suites * when defining test component types which are * type compatible to a synchronization component * type * @see LibCommon_Sync.SelfSyncComp * @see LibCommon_Sync.ServerSyncComp * @see LibCommon_Sync.ClientSyncComp */ type port SyncPort message { inout SyncCmd } } // end compTypeRelated group standardSyncPointNames { const charstring c_prDone := "preambleDone"; const charstring c_poDone := "postambleDone"; const charstring c_tbDone := "testBodyDone"; const charstring c_initDone := "initDone"; } } // end group importantSyncTypeDefinitions group syncCompTestConfiguration { /** * @desc Calls self connect function if invoking * component is the MTC or otherwise connects the client * the server. This function allows to implement preambles * in a way that they can be used by test components * in both non-concurrent as well as concurrent test * cases! * @remark This function should _not_ be called if the MTC * acts as a client (and not a server) in a concurrent * test case. In this case f_connect4ClientSync * should be used instead. * @see LibCommon_Sync.f_connect4SelfSync * @see LibCommon_Sync.f_connect4ClientSync */ function f_connect4SelfOrClientSync() runs on SelfSyncComp { if ( self == mtc ) { f_connect4SelfSync(); } else { f_connect4ClientSync(); } } /** * @desc Calls self connect function if the invoking * component is the MTC or otherwise disconnects the client * from the server. This function allows to implement * postambles in a way that they can be used in both * non-concurrent as well as concurrent test cases. * @remark This function should _not_ be called if the MTC * acts as a client (and not a server) in a concurrent * test case. In this case f_disconnect4ClientSync * should be used instead. * @see LibCommon_Sync.f_disconnect4SelfSync * @see LibCommon_Sync.f_disconnect4ClientSync */ function f_disconnect4SelfOrClientSync() runs on SelfSyncComp { if ( self == mtc ) { f_disconnect4SelfSync(); } else { f_disconnect4ClientSync(); } } } // end group syncCompTestConfiguration group syncFunctions { /** * @desc Implements synchronization of 2 clients from server side * on one or more synchronization points. * If problem occurs, then server sends STOP to all clients. * Waits for PX_TSYNC_TIME_LIMIT to let clients * finish executing their behavior until this * synchronization point. After passing all synchronization * points successfuly the server waits for all clients * to stop. * See f_serverSyncClientsTimed for overwriting this * the timing constraint! * This function sets the server component verdict. * @remark The use of this function requires prior connection of * the server sync ports! * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.f_serverSyncClientsTimed * @see LibCommon_Sync.f_serverWaitForAllClientsToStop * @param p_syncPointIds list of synchronization point name/ids */ function f_serverSync2ClientsAndStop( in SyncPointList p_syncPointIds ) runs on ServerSyncComp { var integer i, v_noOfSyncIds := sizeof(p_syncPointIds); for ( i := 0; i < v_noOfSyncIds; i := i+1 ) { f_serverSyncClientsTimed(2,p_syncPointIds[i], PX_TSYNC_TIME_LIMIT); } f_serverWaitForAllClientsToStop(); } /** * @desc Implements synchronization of 3 clients from server side * on one or more synchronization points. * If problem occurs, then server sends STOP to all clients. * Waits for PX_TSYNC_TIME_LIMIT to let clients * finish executing their behavior until this * synchronization point. After passing all synchronization * points successfuly the server waits for all clients * to stop. * See f_serverSyncClientsTimed for overwriting this * the timing constraint! * This function sets the server component verdict. * @remark The use of this function requires prior connection of * the server sync ports! * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.f_serverSyncClientsTimed * @see LibCommon_Sync.f_serverWaitForAllClientsToStop * @param p_syncPointIds list of synchronization point name/ids */ function f_serverSync3ClientsAndStop( in SyncPointList p_syncPointIds ) runs on ServerSyncComp { var integer i, v_noOfSyncIds := sizeof(p_syncPointIds); for ( i := 0; i < v_noOfSyncIds; i := i+1 ) { f_serverSyncClientsTimed(3,p_syncPointIds[i], PX_TSYNC_TIME_LIMIT); } f_serverWaitForAllClientsToStop(); } /** * @desc Implements synchronization of 4 clients from server side * on one or more synchronization points. * If problem occurs, then server sends STOP to all clients. * Waits for PX_TSYNC_TIME_LIMIT to let clients * finish executing their behavior until this * synchronization point. After passing all synchronization * points successfuly the server waits for all clients * to stop. * See f_serverSyncClientsTimed for overwriting this * the timing constraint! * This function sets the server component verdict. * @remark The use of this function requires prior connection of * the server sync ports! * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.f_serverSyncClientsTimed * @see LibCommon_Sync.f_serverWaitForAllClientsToStop * @param p_syncPointIds list of synchronization point name/ids */ function f_serverSync4ClientsAndStop( in SyncPointList p_syncPointIds ) runs on ServerSyncComp { var integer i, v_noOfSyncIds := sizeof(p_syncPointIds); for ( i := 0; i < v_noOfSyncIds; i := i+1 ) { f_serverSyncClientsTimed(4,p_syncPointIds[i], PX_TSYNC_TIME_LIMIT); } f_serverWaitForAllClientsToStop(); } /** * @desc Implements synchronization of N clients from server side * on one or more synchronization points. * If problem occurs, then server sends STOP to all clients. * Waits for PX_TSYNC_TIME_LIMIT to let clients * finish executing their behavior until this * synchronization point. After passing all synchronization * points successfuly the server waits for all clients * to stop. * See f_serverSyncClientsTimed for overwriting this * the timing constraint! * This function sets the server component verdict. * @remark The use of this function requires prior connection of * the server sync ports! * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.f_serverSyncClientsTimed * @see LibCommon_Sync.f_serverWaitForAllClientsToStop * @param p_numClients number of synchronization clients * @param p_syncPointIds list of synchronization point name/ids */ function f_serverSyncNClientsAndStop ( in integer p_numClients, in SyncPointList p_syncPointIds ) runs on ServerSyncComp { var integer i, v_noOfSyncIds := sizeof(p_syncPointIds); for ( i := 0; i < v_noOfSyncIds; i := i+1 ) { f_serverSyncClientsTimed ( p_numClients, p_syncPointIds[i], PX_TSYNC_TIME_LIMIT ); } f_serverWaitForAllClientsToStop(); } /** * @desc Implements synchronization of 2 clients and 1 UT from server side * on one or more synchronization points. * If problem occurs, then server sends STOP to all clients. * Waits for PX_TSYNC_TIME_LIMIT to let clients * finish executing their behavior until this * synchronization point. After passing all synchronization * points successfuly the server waits for all clients * to stop. * See f_serverSyncClientsTimed for overwriting this * the timing constraint! * This function sets the server component verdict. * @remark The use of this function requires prior connection of * the server sync ports! * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.f_serverSyncClientsTimed * @see LibCommon_Sync.f_serverWaitForAllClientsToStop * @param p_syncPointIds list of synchronization point name/ids */ function f_serverSync2ClientsUtAndStop( in SyncPointList p_syncPointIds ) runs on ServerSyncComp { var integer i, v_noOfSyncIds := sizeof(p_syncPointIds); for ( i := 0; i < v_noOfSyncIds; i := i+1 ) { f_serverSyncClientsTimed(3,p_syncPointIds[i], PX_TSYNC_TIME_LIMIT); } f_serverWaitForAllClientsToStop(); } /** * @desc Calls either self synchronization function if * invoking component is the MTC, otherwise * calls client synchronization. After that it * sets the verdict based on the specified return code. * This function allows to implement TTCN-3 functions * in a way that they can be used in both non-concurrent * as well as concurrent test cases. * @remark This function should _not_ be called if the MTC * acts as a client (and not a server) in a concurrent * test case. In this case f_clientSyncAndVerdict * should be used instead. * @param p_syncPoint Synchronization point name/id * @param p_ret Current behavior execution status * @see LibCommon_Sync.f_clientSyncAndVerdict * @see LibCommon_VerdictControl.f_setVerdict */ function f_selfOrClientSyncAndVerdict( in charstring p_syncPoint, in FncRetCode p_ret) runs on SelfSyncComp { if ( self == mtc ) { // then assume we are running non-conurrent test case f_selfSyncAndVerdict(p_syncPoint, p_ret); } else { f_clientSyncAndVerdict(p_syncPoint, p_ret); } } /** * @desc Calls either self synchronization function if * invoking component is the MTC, otherwise * calls client synchronization. After that it * sets a preamble specific verdict based on the * specified return code. * This function allows to implement TTCN-3 functions * in a way that they can be used in both non-concurrent * as well as concurrent test cases. * @remark This function should _not_ be called if the MTC * acts as a client (and not a server) in a concurrent * test case. In this case f_clientSyncAndVerdict * should be used instead. * @param p_syncPoint Synchronization point name/id * @param p_ret Current behavior execution status * @see LibCommon_Sync.f_clientSyncAndVerdict * @see LibCommon_VerdictControl.f_setVerdictPreamble */ function f_selfOrClientSyncAndVerdictPR( in charstring p_syncPoint, in FncRetCode p_ret) runs on SelfSyncComp { if ( self == mtc ) { // then assume we are running non-conurrent test case f_selfSyncAndVerdictPreamble(p_syncPoint, p_ret); } else { f_clientSyncAndVerdictPreamble(p_syncPoint, p_ret); } } } // end group syncFunctions group syncCompStateHandling { /** * * @desc This function updates the state (stack) of a * sync client or self sync component. This stack is * key in the shutdown handling of test components. * It adds the new state name to the top of the * sync component stack of states. * The state will only be added in case of a current * execution status of e_success. * @param p_newSyncCompState Name of state which was attempted to be reached. * @param p_ret Current behavior execution status * @remark If the state of component changes this function must be * _at least_ called from your test suite prior to f_selfSync * or f_clientSync which is the only definite place for the * shutdown default invocation! * @see LibCommon_Sync.a_dummyShutDown * @see LibCommon_Sync.f_selfSync * @see LibCommon_Sync.f_clientSync */ function f_addSyncCompState(in charstring p_newSyncCompState, in FncRetCode p_ret) runs on ClientSyncComp { if ( p_ret == e_success ) { if ( f_isItemOnStringStack(v_stateStack,p_newSyncCompState) ) { log("**** f_addSyncCompState: WARNING: Attempt to add state which is already on sync state stack! No additition done.****"); } else { f_pushStringStack(v_stateStack,p_newSyncCompState); } } } // end function f_addSyncCompState /** * * @desc This function returns the top state on the sync * state stack of a sync client or self sync * component and removes it from the stack * This function cna be used, e.g., in a while * statement within a postamble or shutdown * implementation * @param p_state State on top of the state stack. * @return false if state stack is empty, true otherwise * @see LibCommon_Sync.a_dummyShutDown */ function f_getTopSyncCompState( out charstring p_state ) runs on ClientSyncComp return boolean { if ( not f_peekStringStackTop(v_stateStack,p_state) ) { p_state := "IDLE"; return false; } f_popStringStack(v_stateStack); return true; } // end function f_getTopSyncCompState /* * @desc This function removes the last state on the state stack * of a sync client or self sync component. * This stack is key in the shutdown handling of test * components. * @see LibCommon_Sync.a_dummyShutDown */ function f_popSyncCompState() runs on ClientSyncComp { f_popStringStack(v_stateStack); } // end function f_popSyncCompState /** * * @desc This function returns the top state on the sync state * stack of a sync client or self sync component. It * does not remove it from the stack * This stack is key in the shutdown handling of test * components. * @param p_state State on top of the state stack. * @return false if state stack is empty, true otherwise * @see LibCommon_Sync.a_dummyShutDown */ function f_peekTopSyncCompState(out charstring p_state) runs on ClientSyncComp return boolean { return f_peekStringStackTop(v_stateStack,p_state); } // end function f_peekTopSyncCompState /** * @desc This function checks if the sync state stack * of a sync client or self sync component is empty. * This stack is key in the shutdown handling of test * components. * @see LibCommon_Sync.a_dummyShutDown */ function f_isSyncCompStateStackEmpty() runs on ClientSyncComp return boolean { return f_isStringStackEmpty(v_stateStack); } // end function f_isSyncCompStateStackEmpty } // end group syncCompStateHandling group exampleShutDownAltstep { /** * @desc This is an example of a shutdown altstep which can be * used as a "template" for a interface specific shutdown * altstep or possily as a first temporary solution in * test case development.

* This altstep shall be activated as a default as the * first statement in each test case function which drives * an interface, i.e., in MTC behavior of single component * and in each client behavior of multi component test * cases.
* The required behavior from this altstep is to:

* 1) expect the STOP either via the test component * syncPort

* 2) upon its arrival it should shut down the SUT * gracefully based on the current component state

* The current component state should have been * previously kept uptodate from a test suite via the * f_addSyncCompState function. This default will then be * (automatically) invoked either from within f_selfSync * or f_clientSync.
* Note that shutdown defaults can be written as * _interface specific_ - they do not need to be test case * or test component specific! See another example of a * shutdown altstep in the sync module. * @see LibCommon_Sync.f_addSyncCompState * @see LibCommon_Sync.f_selfSync * @see LibCommon_Sync.f_clientSync * @see LibCommon_SyncExamples.a_exampleShutDown * @remark Your application specific shutdown altstep * implementation(s) should _not_ be defined in this * module but as part of your test suite or application specific * modules. */ altstep a_dummyShutDown() runs on SelfSyncComp { [] syncPort.receive(m_syncServerStop){ var charstring v_state := ""; tc_sync.stop; log("**** a_dummyShutDown: Test component received STOP signal from sync server - going to IDLE state ****"); while ( f_getTopSyncCompState(v_state) ) { if ( v_state == "x" ) { // then do something } else if ( v_state == "y" ) { // then do something else } } // end while f_disconnect4SelfOrClientSync(); // unmap/disconnect more if needed log("**** a_dummyShutDown: -> Test component stopping itself now! ****") ; stop ; } } // end altstep a_dummyShutDown } // end group exampleShutDownAltstep } // end group basicUserRelevantDefinitions group advancedUserRelevantDefinitions { group serverRelated { /** * @desc Implements synchronization of "n" clients from server * side. If a problem occurs, then server sends STOP to * all clients. Waits for PX_TSYNC_TIME_LIMIT to let * clients finish executing their behavior until this * synchronization point. See f_serverSyncClientsTimed for * overwriting this later timing constraint! * This function sets the server component verdict. * @remark The use of this function requires prior connection of * the server sync port! * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.f_serverSyncClientsTimed * @param p_noOfClients number of clients to be synchronized * @param p_syncId synchronization point name/id */ function f_serverSyncClients( in UInt p_noOfClients, in charstring p_syncId ) runs on ServerSyncComp { f_serverSyncClientsTimed(p_noOfClients,p_syncId, PX_TSYNC_TIME_LIMIT); } /** * @desc Handles synchronization of clients from server side. * If problem occurs, then server sends STOP to all clients. * This function sets the server verdict. * @remark The use of this function requires prior connection of * the server sync ports! * @param p_NoOfClients number of clients to be synchronized * @param p_syncId synchronization point name/id * @param p_execTimeLimit time limit given to all clients to finish the execution * of their behavior up to this synchronization point * @see LibCommon_Sync.f_connect4SelfOrClientSync */ function f_serverSyncClientsTimed( in UInt p_NoOfClients, in charstring p_syncId, float p_execTimeLimit ) runs on ServerSyncComp { var integer v_noOfRecvdSyncMsgs := 0; var boolean v_stopClients := false; var ClientSyncCompList v_clientRefs := {}; var ClientSyncComp v_clientRef; if ( p_syncId == c_prDone ) { log("**** f_serverSyncClientsTimed: Sync server now starting PREAMBLE synchronization ... ****") ; } else if ( p_syncId == c_tbDone ) { log("**** f_serverSyncClientsTimed: Sync server now starting TEST BODY synchronization ... ****") ; } else if ( p_syncId == c_initDone ) { log("**** f_serverSyncClientsTimed: Sync server now starting UPPER TESTER synchronization ... ****") ; } else { log("**** f_serverSyncClientsTimed: Sync server now starting handling of next synchronization point ... ****") ; } tc_sync.start(p_execTimeLimit) ; alt{ [] syncPort.receive(m_syncClientReady(p_syncId)) -> sender v_clientRef { v_clientRefs[v_noOfRecvdSyncMsgs] := v_clientRef; v_noOfRecvdSyncMsgs := v_noOfRecvdSyncMsgs + 1; if ( v_noOfRecvdSyncMsgs != p_NoOfClients ) { repeat; } } [] syncPort.receive(m_syncClientStop) -> sender v_clientRef { log("**** f_serverSyncClientsTimed: Sync server received STOP signal from a client - server will wait for all clients to reach their next synchronization point and then stop them! ****") ; v_stopClients := true; v_clientRefs[v_noOfRecvdSyncMsgs] := v_clientRef; v_noOfRecvdSyncMsgs := v_noOfRecvdSyncMsgs + 1; if ( v_noOfRecvdSyncMsgs != p_NoOfClients ) { repeat; } } [] syncPort.receive(m_syncClientReady(?)) -> sender v_clientRef { log("**** f_serverSyncClientsTimed: Sync server received client sync message with incorrect synchronization point id which is currently not handled - server will stop all clients! ****") ; v_stopClients := true; v_clientRefs[v_noOfRecvdSyncMsgs] := v_clientRef; } [] syncPort.receive(SyncCmd :? ) { log("**** f_serverSyncClientsTimed: Sync server received (invalid) sync message from other sync server - server will stop all clients! ****") ; v_stopClients := true; } [] any port.receive { // leave it to be ok to receive anything else // in case that the user has added any non-sync ports to // his/her server component type definition! } [] tc_sync.timeout{ log("**** f_serverSyncClientsTimed: A client is not responding within specified time limit - sync server is sending stop to all clients! ****"); v_stopClients := true; } } //end alt tc_sync.stop ; if ( v_stopClients ) { setverdict(inconc); // then send out STOP sync msg f_serverSendToAllClients(v_clientRefs, m_syncServerStop); f_serverWaitForAllClientsToShutDown(); // function will never return! } else { setverdict(pass); // then send out READY sync msg f_serverSendToAllClients(v_clientRefs, m_syncServerReady(p_syncId)); if ( p_syncId == c_prDone ) { log("**** f_serverSyncClientsTimed: Sync server successfully passed PREAMBLE synchronization point. ****") ; } else if ( p_syncId == c_tbDone ) { log("**** f_serverSyncClientsTimed: Sync server successfully passed TEST BODY synchronization point. ****") ; } else { log("**** f_serverSyncClientsTimed: Sync server successfully passed synchronization point. ****") ; } } } // end function f_serverSyncClientsTimed /** * @desc This function is intended only for use on the sync * server component in concurrent TTCN-3 test cases. * It waits for all components to finish execution within * the PX_TSYNC_TIME_LIMIT. If a timeout occurs * the server will stop all clients. * This function sets the server component verdict. */ function f_serverWaitForAllClientsToStop() runs on ServerSyncComp { tc_sync.start; alt { [] all component.done { tc_sync.stop; log("**** f_serverWaitForAllClientsToStop: All sync clients have finished their execution. Sync server now terminating test case. ****") ; } [] tc_sync.timeout { log("**** f_serverWaitForAllClientsToStop: Not all sync clients have finshed execution within the sync time limit. Sync server will stop test case! ****") ; } } // end alt setverdict(pass); stop; } // end function f_serverWaitForAllClientsToStop } // end group serverRelated group clientRelated { /** * @desc This function creates the connection needed to * execute client synchronization functions * @see LibCommon_Sync.f_clientSync * @see LibCommon_Sync.f_clientSendStop */ function f_connect4ClientSync() runs on ClientSyncComp { connect(self:syncPort, mtc:syncPort); }// end function f_connect4ClientSync /** * @desc This function removes the connection needed * to execute client synchronization functions * @see LibCommon_Sync.f_clientSync * @see LibCommon_Sync.f_clientSendStop */ function f_disconnect4ClientSync() runs on ClientSyncComp { disconnect(self:syncPort, mtc:syncPort); }// end function f_disconnect4ClientSync /** * @desc This function combines client verdict setting with its * synchronization for use after or within a preamble * implementation. * Note that such preambles can _not_ be reused in non- * concurrent test cases. * This function sets the client component verdict. * @remark The use of this function requires prior connection * of the client sync port! * @see LibCommon_Sync.f_connect4ClientSync * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_VerdictControl.f_setVerdictPreamble * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status */ function f_clientSyncAndVerdictPreamble(in charstring p_syncId , FncRetCode p_ret ) runs on ClientSyncComp { f_setVerdictPreamble(p_ret); f_clientSync(p_syncId,p_ret); } /** * @desc This function combines client verdict setting with its * synchronization for use,e.g, after or within a * test body implementation. * Note that such premables can _not_ be reused in non- * concurrent test cases. This can be achieved by using * the f_selfOrClientSyncAndVerdict function instead. * This function sets the client component verdict. * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status * @remark The use of this function requires prior connection * of the client sync port! * @see LibCommon_Sync.f_connect4ClientSync * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_VerdictControl.f_setVerdict * @see LibCommon_Sync.f_selfOrClientSyncAndVerdict */ function f_clientSyncAndVerdict(in charstring p_syncId, in FncRetCode p_ret ) runs on ClientSyncComp { f_setVerdict(p_ret); f_clientSync(p_syncId,p_ret); } /** * @desc This function combines client verdict setting with its * synchronization for use after or within a * postamble implementation. * Note that such prostambles can _not_ be reused in non- * concurrent test cases. * This function sets the client component verdict. * @remark The use of this function requires prior connection * of the client sync port! * @see LibCommon_Sync.f_connect4ClientSync * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_VerdictControl.f_setVerdictPostamble * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status */ function f_clientSyncAndVerdictPostamble(in charstring p_syncId , in FncRetCode p_ret ) runs on ClientSyncComp { f_setVerdictPostamble(p_ret); f_clientSync(p_syncId,p_ret); } /** * @desc This function handles synchronization of a sync client * with the server. In case of successful execution it sends * a READY message to the server and waits the READY back. * The time used for waiting is defined by PX_TSYNC_TIME_LIMIT. * In case of a non successful execution status it * sends a STOP message to the server. * In both cases the receipt of a STOP message or no * response from the server it will trigger the shutdown * default (if activated). * This function will set only the client verdict to INCONC * (and stop its execution) if no STOP response is received * from the server within the PX_TSYNC_TIME_LIMIT * or if no shutdown default is activated. In all other * cases the client verdict is NOT set. * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status * @remark The use of this function requires prior connection * of the client sync port! * @see LibCommon_Sync.f_connect4ClientSync * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.a_dummyShutDown * @see LibCommon_Sync.f_clientSendStop * @return Updated execution status */ function f_clientSync( in charstring p_syncId , in FncRetCode p_ret ) runs on ClientSyncComp return FncRetCode{ if (p_ret == e_success){ syncPort.send(m_syncClientReady(p_syncId)); tc_sync.start; alt{ [] syncPort.receive(m_syncServerReady(p_syncId)){ tc_sync.stop ; } [] tc_sync.timeout{ log("**** f_clientSync: Sync client did not receive message from sync server within the specified time limit - sync client will ask sync server to stop test case! ****") ; f_clientSendStop(); } // function will not return! } //end alt } //end if else { log("**** f_clientSync: Execution status indicates that execution of test component behavior was not successful - sync client will ask sync server to stop test case! ****") ; f_clientSendStop(); // function will not return! } if ( p_syncId == c_prDone ) { log("**** f_clientSync: Sync client successfully passed PREAMBLE synchronization point. ****") ; } else if ( p_syncId == c_tbDone ) { log("**** f_clientSync: Sync client successfully passed TEST BODY synchronization point. ****") ; } else { log("**** f_clientSync: Sync client successfully passed synchronization point. ****") ; } return e_success ; } // end function f_clientSync /** * @desc This function can be used to request the shutdown a * multi component test case _prior_ to reaching a * synchronization point. It sends a STOP message to * the sync server and awaits then the STOP from the server * which will trigger the shutdown default (if activated). * This function will set the server verdict to INCONC (and * stop the test case) if no shutdown default is activated. * This function will set only the client verdict to INCONC * (and stop its execution) if no STOP response is received * from the server within the PX_TSYNC_TIME_LIMIT * or if no shutdown default is activated. In all other * cases the client verdict is NOT set. * @remark The use of this function requires prior connection * of the client sync port! * @see LibCommon_Sync.f_connect4ClientSync * @see LibCommon_Sync.f_connect4SelfOrClientSync * @see LibCommon_Sync.PX_TSYNC_TIME_LIMIT * @see LibCommon_Sync.a_dummyShutDown */ function f_clientSendStop() runs on ClientSyncComp { log("**** f_clientSendStop: Sync client requesting from server to stop test case (including itself). ****") ; syncPort.send(m_syncClientStop) ; tc_sync.start; alt{ [] tc_sync.timeout{ log("**** f_clientSendStop: Stopping sync client without shutdown - either no shutdown default active or no stop received from server. ****") ; setverdict(inconc); stop ; } }//end alt tc_sync.stop; stop; // stop here if shutdown default does not stop } } // end group clientRelated } // end group advancedUserRelevantDefinitions group otherSyncModuleDefinitions { group syncModuleparams { /** * * @desc Default time limit for a sync client to reach a * synchronization point */ modulepar {float PX_TSYNC_TIME_LIMIT := 120.0} /* * @desc Default time limit for a sync client to finish * its execution of the shutdown default */ modulepar {float PX_TSHUT_DOWN_TIME_LIMIT := 120.0} } group otherSyncTypes { type record of charstring SyncPointList; type record of ClientSyncComp ClientSyncCompList; } // end group otherSyncTypes group otherSelfSyncRelatedDefinitions { /** * @desc This function creates the connection needed to * execute self sync functions * @see LibCommon_Sync.f_selfSync * @see LibCommon_Sync.f_selfSyncStop */ function f_connect4SelfSync() runs on SelfSyncComp { connect(self:syncSendPort, self:syncPort); }// end function f_connect4SelfSync /** * @desc This function removes the connection needed * to execute self sync functions * @see LibCommon_Sync.f_selfSync * @see LibCommon_Sync.f_selfSyncStop */ function f_disconnect4SelfSync() runs on SelfSyncComp { disconnect(self:syncSendPort, self:syncPort); }// end function f_disconnect4SelfSync /** * @desc This function combines MTC verdict setting with self * synchronization for use after and possibly in the test body * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status * @see LibCommon_VerdictControl.f_setVerdict * @see LibCommon_Sync.f_selfSync * @see LibCommon_Sync.a_dummyShutDown */ function f_selfSyncAndVerdict( in charstring p_syncId, in FncRetCode p_ret ) runs on SelfSyncComp { f_setVerdict(p_ret); f_selfSync(p_syncId,p_ret); } /** * @desc This function combines MTC verdict setting with self * synchronization for use after the preamble. * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status * @see LibCommon_VerdictControl.f_setVerdictPreamble * @see LibCommon_Sync.f_selfSync */ function f_selfSyncAndVerdictPreamble( in charstring p_syncId, in FncRetCode p_ret ) runs on SelfSyncComp { f_setVerdictPreamble(p_ret); f_selfSync(p_syncId,p_ret); } /** * @desc This function combines MTC verdict setting with self * synchronization for use after the postamble. * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status * @see LibCommon_VerdictControl.f_setVerdictPostamble * @see LibCommon_Sync.f_selfSync */ function f_selfSyncAndVerdictPostamble( in charstring p_syncId , in FncRetCode p_ret ) runs on SelfSyncComp { f_setVerdictPostamble(p_ret); f_selfSync(p_syncId,p_ret); } /** * @desc This function synchronizes a MTC with itself. In case * of a non successful execution status it sends a STOP * message to itself and invokes that way the * shutdown default (if activated). * This function will set the server verdict to INCONC (and * stop the test case) if no shutdown default is activated. * Otherwise no verdict is set. * @remark Sync ports should be connected prior to the invocation * of this function! * @param p_syncId Synchronization point name/id * @param p_ret Current behavior execution status * @return Updated execution status * @see LibCommon_Sync.f_connect4SelfSync * @see LibCommon_Sync.a_dummyShutDown */ function f_selfSync( in charstring p_syncId , in FncRetCode p_ret ) runs on SelfSyncComp return FncRetCode{ if (p_ret != e_success){ f_selfSyncStop() ; // function will not return! } if ( p_syncId == c_prDone ) { log("**** f_selfSync: Successfully passed PREAMBLE synchronization point. ****") ; } else if ( p_syncId == c_tbDone ) { log("**** f_selfSync: Successfully passed TEST BODY synchronization point. ****") ; } else { log("**** f_selfSync: Successfully passed synchronization point. ****") ; } return e_success ; }// end function f_selfSync /** * @desc This function can be used to shut down a test case _prior_ * to reaching a synchronization point. it sends a STOP * message to itself and invokes that way the * shutdown default (if activated). * This function will set the server verdict to INCONC (and * stop the test case) if no shutdown default is activated. * Otherwise no verdict is set. * @remark Sync ports should be connected prior to the invocation * of this function! * @see LibCommon_Sync.f_connect4SelfSync */ function f_selfSyncStop() runs on SelfSyncComp { log("**** f_selfSyncStop: MTC requests to stop test case (itself). ****") ; syncSendPort.send(m_syncServerStop) ; // this MUST be _server_ for the default to catch! tc_sync.start(PX_TSYNC_TIME_LIMIT); alt{ [] tc_sync.timeout{ log("**** f_selfSyncStop: Stopping MTC without shutdown - either no shutdown default active or missing syncPort connection ****") ; setverdict(inconc); stop ; } }//end alt tc_sync.stop; stop; // if shutdown default is not activated or if it does not stop } // end function f_selfSyncStop } // end group otherSelfSyncRelatedDefinitions /** * * @desc The sychronization protocol is conceptually based on * named synchronization. Each synchronization point * has it own specific synchronization message. This * makes each synchronization unique, and allows, e.g., to * ensure that a server synchronizes only clients which have * reached the same synchronization point. */ group syncProtocolDefinition { type union SyncCmd { ClientReady clientReady, ServerReady serverReady, ClientStop clientStop, ServerStop serverStop } type record ClientReady { charstring syncPointId } type record ServerReady { charstring syncPointId } type record ClientStop {} type record ServerStop {} } // end group syncProtocolDefinition group syncMessages { template SyncCmd m_syncClientReady( template charstring p_syncId ) := { clientReady := { p_syncId } } template SyncCmd m_syncServerReady( template charstring p_syncId ) := { serverReady := { p_syncId } } template SyncCmd m_syncClientStop := { clientStop := {} } template SyncCmd m_syncServerStop := { serverStop := {} } } // end group syncMessages group otherSyncFunctions { /** * @desc Makes server send a sync message to all known clients * @param p_clientRefs List of client references to which the message is to be send * @param p_syncCmd The actual synchronization message to be sent out */ function f_serverSendToAllClients( in ClientSyncCompList p_clientRefs, in template SyncCmd p_syncCmd) runs on ServerSyncComp { var integer i:=0; for (i:=0; i< sizeof(p_clientRefs); i:=i+1 ){ syncPort.send(p_syncCmd) to p_clientRefs[i]; } } // end function f_serverSendToAllClients /** * @desc This function is intended only for use on server in concurrent * TTCN-3 test cases. It waits for all components to shut down * within the PX_TSHUT_DOWN_TIME_LIMIT. If a timeout occurs * it aborts the test case (no matter how far clients got with their * shutdown). * This function sets the server verdict. */ function f_serverWaitForAllClientsToShutDown() runs on ServerSyncComp { tc_shutDown.start(PX_TSHUT_DOWN_TIME_LIMIT); alt { [] all component.done { tc_shutDown.stop; log("**** f_serverWaitForAllClientsToShutDown: All components have properly shut down. Sync server will now terminate the test case. ****") ; } [] tc_shutDown.timeout { log("**** f_serverWaitForAllClientsToShutDown: Not all clients have properly shutdown within the shut down time limit. Sync server will now terminate test case! ****") ; } } // end alt // cover case that shut down default is NOT activated setverdict(inconc); mtc.stop; } // end function f_serverWaitForAllClientsToShutDown } // end group otherSyncFunctions } // end group otherSyncDefinitions } // end module LibCommon_Sync