test.tck.msgflow.NonInviteClientTransactionsStateMachineTest Maven / Gradle / Ivy
/*
* Conditions Of Use
*
* This software was developed by employees of the National Institute of
* Standards and Technology (NIST), and others.
* This software is has been contributed to the public domain.
* As a result, a formal license is not needed to use the software.
*
* This software is provided "AS IS."
* NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY. NIST does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
*
*/
package test.tck.msgflow;
import junit.framework.*;
import javax.sip.*;
import javax.sip.message.*;
import java.util.*;
import test.tck.*;
/**
*
* The test tries to verify that Non Invite Client Transactions correctly change
* states as specified by the rfc3261. The Tested Implementation is used
* to send requests and the ReferenceImplementation issues (or not) corresponding
* responses. ClientTransaction states are constantly queried
* and compared to those in the state machine described in
* section 17.1.2 of rfc3261
*
*
* | Request from TU
* | send request
* Timer E V
* send request +-----------+
* +---------| |-------------------+
* | | Trying | Timer F |
* +-------->| | or Transport Err.|
* +-----------+ inform TU |
* 200-699 | | |
* resp. to TU | |1xx |
* +---------------+ |resp. to TU |
* | | |
* | Timer E V Timer F |
* | send req +-----------+ or Transport Err. |
* | +---------| | inform TU |
* | | |Proceeding |------------------>|
* | +-------->| |-----+ |
* | +-----------+ |1xx |
* | | ^ |resp to TU |
* | 200-699 | +--------+ |
* | resp. to TU | |
* | | |
* | V |
* | +-----------+ |
* | | | |
* | | Completed | |
* | | | |
* | +-----------+ |
* | ^ | |
* | | | Timer K |
* +--------------+ | - |
* | |
* V |
* NOTE: +-----------+ |
* | | |
* transitions | Terminated|<------------------+
* labeled with | |
* the event +-----------+
* over the action
* to take
*
* Figure 6: non-INVITE client transaction
*
* TODO test timeout events
*
*
* @author Emil Ivov
* Network Research Team, Louis Pasteur University, Strasbourg, France.
* This code is in the public domain.
* @version 1.0
*/
public class NonInviteClientTransactionsStateMachineTest
extends MessageFlowHarness {
public NonInviteClientTransactionsStateMachineTest(String name) {
super(name);
}
//==================== tests ==============================
/**
* Tries to walk a TI client transaction through the following scenario
* Trying-->Proceeding-->Completed-->Terminated. Apart from state
* transitions, we also test, retransmissions and proper hiding/passing
* of messages to the TU.
*/
public void testTryingProceedingCompletedTerminatedScenario() {
try {
Request register = createTiRegisterRequest();
ClientTransaction tran = null;
try {
eventCollector.collectRequestEvent(riSipProvider);
tran = tiSipProvider.getNewClientTransaction(register);
tran.sendRequest();
} catch (SipException ex) {
throw new TiUnexpectedError(
"A SipExceptionOccurred while trying to send request!",
ex);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
waitForMessage();
RequestEvent registerReceivedEvent =
eventCollector.extractCollectedRequestEvent();
if (registerReceivedEvent == null
|| registerReceivedEvent.getRequest() == null)
throw new TiUnexpectedError("The REGISTER request was not received by the RI!");
//At this point the ClientTransaction should be TRYING!
assertEquals(TransactionState.TRYING, tran.getState());
//Check Request retransmission
try {
eventCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
//Wait for the retransmission timer to fire if it had not already done so.
if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
sleep((long) tran.getRetransmitTimer() - MESSAGES_ARRIVE_FOR);
//subtract the time we waited for the REGISTER
//Wait for the retransmitted request to arrive
waitForMessage();
registerReceivedEvent =
eventCollector.extractCollectedRequestEvent();
assertNotNull(
"The REGISTER request was not retransmitted!",
registerReceivedEvent);
assertNotNull(
"The REGISTER request was not retransmitted!",
registerReceivedEvent.getRequest());
assertEquals(
Request.REGISTER,
registerReceivedEvent.getRequest().getMethod());
//At this point the ClientTransaction should STILL be TRYING!
assertEquals(TransactionState.TRYING, tran.getState());
//Send a TRYING response
try {
eventCollector.collectResponseEvent(tiSipProvider);
} catch (TooManyListenersException ex) {
throw new TiUnexpectedError(
"Failed to register a SipListener with TI",
ex);
}
try {
Response res =
riMessageFactory.createResponse(
Response.TRYING,
registerReceivedEvent.getRequest());
addStatus(registerReceivedEvent.getRequest(), res);
riSipProvider.sendResponse(res);
} catch (Throwable ex) {
throw new TckInternalError(
"The TCK could not send a trying response back to the TI",
ex);
}
waitForMessage();
//Analyze the TRYING response and Tran state back at the TI
ResponseEvent responseEvent =
eventCollector.extractCollectedResponseEvent();
assertNotNull(
"The Tested Implementation did not pass a 1xx response to the TU!",
responseEvent);
assertNotNull(
"The Tested Implementation did not pass a 1xx response to the TU!",
responseEvent.getResponse());
assertTrue(
"A response different from TRYING was passed to the TU!",
responseEvent.getResponse().getStatusCode() == Response.TRYING);
assertSame(
"The TRYING response was not associated with the right transaction",
tran,
responseEvent.getClientTransaction());
//verify the the tran state is now PROCEEDING
assertEquals(
"The ClientTransaction did not pass in the PROCEEDING state after "
+ "receiving 1xx provisional response",
tran.getState(),
TransactionState.PROCEEDING);
//Send a 200 OK (final) response from the RI
try {
eventCollector.collectResponseEvent(tiSipProvider);
} catch (TooManyListenersException ex) {
throw new TiUnexpectedError(
"Failed to register a SipListener with TI",
ex);
}
//The OK response shouldn't trigger any ACKs so let's register
//a listener with the RI to verify whether that is the case
SipEventCollector ackCollector = new SipEventCollector();
try {
ackCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
Response ok = null;
try {
ok =
riMessageFactory.createResponse(
Response.OK,
registerReceivedEvent.getRequest());
addStatus(registerReceivedEvent.getRequest(), ok);
riSipProvider.sendResponse((Response) ok.clone());
} catch (Throwable ex) {
throw new TckInternalError(
"The TCK could not send a OK response back to the TI",
ex);
}
waitForMessage();
//Analyze the OK response and Tran state back at the TI
responseEvent = eventCollector.extractCollectedResponseEvent();
assertNotNull(
"The Tested Implementation did not pass a 200-699 response to the TU!",
responseEvent);
assertNotNull(
"The Tested Implementation did not pass a 200-699 response to the TU!",
responseEvent.getResponse());
assertSame(
"The OK response was not associated with the right transaction",
tran,
responseEvent.getClientTransaction());
assertSame(
"A response different from OK was passed to the TU",
tran,
responseEvent.getClientTransaction());
assertEquals(
"The ClientTransaction did not pass in the COMPLETED state after "
+ "receiving 200-699 final response",
tran.getState(),
TransactionState.COMPLETED);
//check whether the ackCollector has caught any fish
RequestEvent ackReceivedEvent =
ackCollector.extractCollectedRequestEvent();
assertNull(
"The TI sent an ACK request in a non INVITE transaction",
ackReceivedEvent);
//Now let's retransmit the final response. See again that no acks are sent
try {
eventCollector.collectResponseEvent(tiSipProvider);
} catch (TooManyListenersException ex) {
throw new TiUnexpectedError(
"Failed to register a SipListener with TI",
ex);
}
//go fish the ack
try {
ackCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
try {
riSipProvider.sendResponse((Response) ok.clone());
} catch (Throwable ex) {
throw new TckInternalError(
"The TCK could not send a OK response back to the TI",
ex);
}
waitForMessage();
//The TU shouldn't see the retransmitted OK response
responseEvent = eventCollector.extractCollectedResponseEvent();
assertNull(
"The Tested Implementation passed a retransmitted 200-699 response "
+ "to the TU.",
responseEvent);
//We must still be in the completed state.
assertTrue(
"The ClientTransaction did not stay long enough in the COMPLETED "
+ "state.",
tran.getState().equals(TransactionState.COMPLETED)
|| tran.getState().equals(TransactionState.TERMINATED));
//check whether the ackCollector has caught any fish
ackReceivedEvent = ackCollector.extractCollectedRequestEvent();
assertNull(
"The TI replied with an ACK to a nonINVITE request",
ackReceivedEvent);
} catch (Throwable exc) {
exc.printStackTrace();
fail(exc.getClass().getName() + ": " + exc.getMessage());
}
assertTrue(new Exception().getStackTrace()[0].toString(), true);
}
/**
* Tries to walk a TI client transaction through the following scenario
* Trying-->Completed-->Terminated. Apart from state
* transitions, we also test, retransmissions and proper hiding/passing
* of messages to the TU.
*/
public void testTryingCompletedTerminatedScenario() {
try {
Request register = createTiRegisterRequest();
ClientTransaction tran = null;
try {
eventCollector.collectRequestEvent(riSipProvider);
tran = tiSipProvider.getNewClientTransaction(register);
tran.sendRequest();
} catch (SipException ex) {
throw new TiUnexpectedError(
"A SipExceptionOccurred while trying to send request!",
ex);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
waitForMessage();
RequestEvent registerReceivedEvent =
eventCollector.extractCollectedRequestEvent();
if (registerReceivedEvent == null
|| registerReceivedEvent.getRequest() == null)
throw new TiUnexpectedError("The REGISTER request was not received by the RI!");
//At this point the ClientTransaction should be TRYING!
assertEquals(TransactionState.TRYING, tran.getState());
//Check Request retransmission
try {
eventCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
//Wait for the retransmission timer to fire if it had not already done so.
if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
sleep((long) tran.getRetransmitTimer() - MESSAGES_ARRIVE_FOR);
//subtract the time we waited for the REGISTER
//Wait for the retransmitted request to arrive
waitForMessage();
registerReceivedEvent =
eventCollector.extractCollectedRequestEvent();
assertNotNull(
"The REGISTER request was not retransmitted!",
registerReceivedEvent);
assertNotNull(
"The REGISTER request was not retransmitted!",
registerReceivedEvent.getRequest());
assertEquals(
Request.REGISTER,
registerReceivedEvent.getRequest().getMethod());
//At this point the ClientTransaction should STILL be TRYING!
assertEquals(TransactionState.TRYING, tran.getState());
//Send a 200 OK (final) response from the RI
try {
eventCollector.collectResponseEvent(tiSipProvider);
} catch (TooManyListenersException ex) {
throw new TiUnexpectedError(
"Failed to register a SipListener with TI",
ex);
}
//The OK response shouldn't trigger any ACKs so let's register
//a listener with the RI to verify whether that is the case
SipEventCollector ackCollector = new SipEventCollector();
try {
ackCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
Response ok = null;
try {
ok =
riMessageFactory.createResponse(
Response.OK,
registerReceivedEvent.getRequest());
addStatus(registerReceivedEvent.getRequest(), ok);
riSipProvider.sendResponse((Response) ok.clone());
} catch (Throwable ex) {
throw new TckInternalError(
"The TCK could not send a OK response back to the TI",
ex);
}
waitForMessage();
//Analyze the OK response and Tran state back at the TI
ResponseEvent responseEvent =
eventCollector.extractCollectedResponseEvent();
assertNotNull(
"The Tested Implementation did not pass a 200-699 response to the TU!",
responseEvent);
assertNotNull(
"The Tested Implementation did not pass a 200-699 response to the TU!",
responseEvent.getResponse());
assertSame(
"The OK response was not associated with the right transaction",
tran,
responseEvent.getClientTransaction());
assertSame(
"A response different from OK was passed to the TU",
tran,
responseEvent.getClientTransaction());
assertEquals(
"The ClientTransaction did not pass in the COMPLETED state after "
+ "receiving 200-699 final response",
tran.getState(),
TransactionState.COMPLETED);
//check whether the ackCollector has caught any fish
RequestEvent ackReceivedEvent =
ackCollector.extractCollectedRequestEvent();
assertNull(
"The TI sent an ACK request in a non INVITE transaction",
ackReceivedEvent);
//Now let's retransmit the final response. See again that no acks are sent
try {
eventCollector.collectResponseEvent(tiSipProvider);
} catch (TooManyListenersException ex) {
throw new TiUnexpectedError(
"Failed to register a SipListener with TI",
ex);
}
//go fish the ack
try {
ackCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to regiest a SipListener with an RI SipProvider",
ex);
}
try {
riSipProvider.sendResponse((Response) ok.clone());
} catch (Throwable ex) {
throw new TckInternalError(
"The TCK could not send a OK response back to the TI",
ex);
}
waitForMessage();
//The TU shouldn't see the retransmitted OK response
responseEvent = eventCollector.extractCollectedResponseEvent();
assertNull(
"The Tested Implementation passed a retransmitted 200-699 response "
+ "to the TU.",
responseEvent);
//We must still be in the completed state.
assertTrue(
"The ClientTransaction did not stay long enough in the COMPLETED "
+ "state.",
tran.getState().equals(TransactionState.COMPLETED)
|| tran.getState().equals(TransactionState.TERMINATED));
//check whether the ackCollector has caught any fish
ackReceivedEvent = ackCollector.extractCollectedRequestEvent();
assertNull(
"The TI replied with an ACK to a nonINVITE request",
ackReceivedEvent);
} catch (Throwable exc) {
exc.printStackTrace();
fail(exc.getClass().getName() + ": " + exc.getMessage());
}
assertTrue(new Exception().getStackTrace()[0].toString(), true);
}
//==================== end of tests
//====== STATIC JUNIT ==========
public static Test suite() {
return new TestSuite(NonInviteClientTransactionsStateMachineTest.class);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy