Description
State machine primitives are small functions with common prototype, which are being used as state actions in finite state machine based tests.
The common interface is as follows:
FSM_STATUS FUNC_NAME( FSM_TEST * pTestObject, FSM_EVENT nEventMask )
where FSM_STATUS is one of the FSM_OK (=0), FSM_ERROR (error code > then 0), FSM_WAIT ( negative number ), pTestObject is pointer to test object containing params, times, surrent state etc. and nEventMask is mask of events which caused the primitive to be called ( bitwise "or" of FSMEVENT_Read, FSMEVENT_Write, FSMEVENT_Exception ).
The primitive is expected to return FSM_OK in case it finished its job successfully and the state machine should pass in successful state. FSM_ERROR type value will make the machine assume the failure state of the current state. A FSM_WAIT value means that the job was not finished due to some reason ( for example, not all of the expected data could be received ) and the machine will stay in current state waiting for new events.
Primitives
Primitive: InitSock
Description: Initializes the underlying test object ( resolve host if not yet resolved, creates socket, etc. )
PROCEDURE InitSock( pTestObject, eventMask )
rc := DO_SOME_INIT_STUFF_ON_SOCKET( pTestObject->socket )
IF SUCCESSFUL( rc ) THEN
RETURN FSM_OK
ELSE
RETURN FSM_ERROR
END IF
END PROCEDURE
Primitive: Connect
Description: Connects the underlying test socket to host
PROCEDURE Connect( pTestObject, eventMask )
IF pTestObject->CurrentSubState = 0 THEN
pTestObject->connect( pTestObject->socket )
pTestObject->CurrentSubState = 1
ELSE
IF eventMask & WRITE_EVENT THEN
IF ERROR( pTestObject->socket ) THEN
SET_SOME_ERROR_VALUE_AND_DETAILS( pTestObject )
RETURN FSM_ERROR
ELSE
RETURN FSM_OK
END IF
END IF
END IF
RETURN FSM_WAIT
END PROCEDURE
Primitive: WriteSock
Description: Writes some data to the socket
PROCEDURE WriteSock( pTestObject, eventMask )
IF pTestObject->CurrentSubState = 0 THEN
pTestObject->Buffer := PREPARE_REQUEST( pTestObject )
pTestObject->LeftToSend := LENGTH( pTestObject->Buffer )
REGISTER_SOCKET( pTestObject->socket, FSMEVENT_Write | FSMEVENT_Exception )
pTestObject->CurrentSubState = 1
END IF
IF eventMask & FSMEVENT_Exception THEN
RETURN FSM_ERROR
END IF
sentBytes := send( pTestObject->socket, pTestObject->Buffer, pTestObject->LeftToSend )
IF SOME_ERROR_OCCURRED() THEN
SET_SOME_ERROR_VALUE_AND_DETAILS( pTestObject )
RETURN FSM_ERROR
END IF
pTestObject->LeftToSend -= sentBytes
IF pTestObject->LeftToSend = 0 THEN
RETURN FSM_OK
END IF
RETURN FSM_WAIT
END PROCEDURE
Primitive: ReadSock
Description: Reads some data from the socket
PROCEDURE ReadSock( pTestObject, eventMask )
IF pTestObject->CurrentSubState = 0 THEN
REGISTER_SOCKET( pTestObject->socket, FSMEVENT_Read | FSMEVENT_Exception )
pTestObject->CurrentSubState = 1
END IF
IF eventMask & FSMEVENT_Exception THEN
RETURN FSM_ERROR
END IF
rcvdBytes := read( pTestObject->socket, pTestObject->Buffer )
IF SOME_ERROR_OCCURRED() THEN
SET_SOME_ERROR_VALUE_AND_DETAILS( pTestObject )
RETURN FSM_ERROR
END IF
IF rcvdBytes = 0 THEN
# Ready for reading event was received but nothing was read
# which means that the sent data was received
IF MATCH_PATTERN( pTestObject->Buffer ) THEN
RETURN FSM_OK
ELSE
RETURN FSM_ERROR
END IF
END IF
RETURN FSM_WAIT
END PROCEDURE
Primitive: Close
Description: Shuts down the socket (this causes the TCP to close connection streams in both directions) and then closes sockets (this is very important since if the socket is not closed, it will remain as an entry in file descriptor table of the process, which has a limit of descriptors and when this limit is reached error will be issued on every socket() syscall)
PROCEDURE Close( pTestObject, eventMask )
SHUTDOWN(pTestObject->Socket, SHUT_RDWR)
CLOSE(pTestObject->Socket)
RETURN FSM_OK
END PROCEDURE