0001: /*
0002: * Conditions Of Use
0003: *
0004: * This software was developed by employees of the National Institute of
0005: * Standards and Technology (NIST), and others.
0006: * This software is has been contributed to the public domain.
0007: * As a result, a formal license is not needed to use the software.
0008: *
0009: * This software is provided "AS IS."
0010: * NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
0011: * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
0012: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
0013: * AND DATA ACCURACY. NIST does not warrant or make any representations
0014: * regarding the use of the software or the results thereof, including but
0015: * not limited to the correctness, accuracy, reliability or usefulness of
0016: * the software.
0017: *
0018: *
0019: */
0020: package test.tck.msgflow;
0021:
0022: import java.util.TooManyListenersException;
0023:
0024: import javax.sip.*;
0025: import javax.sip.header.ContactHeader;
0026: import javax.sip.header.ToHeader;
0027: import javax.sip.message.Request;
0028: import javax.sip.message.Response;
0029:
0030: import org.apache.log4j.Logger;
0031:
0032: import junit.framework.Test;
0033: import junit.framework.TestSuite;
0034: import test.tck.TckInternalError;
0035: import test.tck.TiUnexpectedError;
0036:
0037: /**
0038: * The test tries to verify that Invite Client Transactions correctly change
0039: * states as specified by the rfc3261. The Tested Implementation is used to send
0040: * requests and the ReferenceImplementation issues (or not) corresponding
0041: * responses. ClientTransaction states are constantly queried and compared to
0042: * those in the state machine described in section 17.1.1 of rfc3261
0043: *
0044: * <pre>
0045: *
0046: * |INVITE from TU
0047: * Timer A fires |INVITE sent
0048: * Reset A, V Timer B fires
0049: * INVITE sent +-----------+ or Transport Err.
0050: * +---------| |---------------+inform TU
0051: * | | Calling | |
0052: * +-------->| |-------------->|
0053: * +-----------+ 2xx |
0054: * | | 2xx to TU |
0055: * | |1xx |
0056: * 300-699 +---------------+ |1xx to TU |
0057: * ACK sent | | |
0058: * esp. to TU | 1xx V |
0059: * | 1xx to TU -----------+ |
0060: * | +---------| | |
0061: * | | |Proceeding |-------------->|
0062: * | +-------->| | 2xx |
0063: * | +-----------+ 2xx to TU |
0064: * | 300-699 | |
0065: * | ACK sent, | |
0066: * | resp. to TU| |
0067: * | | | NOTE:
0068: * | 300-699 V |
0069: * | ACK sent +-----------+Transport Err. | transitions
0070: * | +---------| |Inform TU | labeled with
0071: * | | | Completed |-------------->| the event
0072: * | +-------->| | | over the action
0073: * | +-----------+ | to take
0074: * | ˆ | |
0075: * | | | Timer D fires |
0076: * +--------------+ | - |
0077: * | |
0078: * V |
0079: * +-----------+ |
0080: * | | |
0081: * | Terminated|<--------------+
0082: * | |
0083: * +-----------+
0084: *
0085: * Figure 5: INVITE client transaction
0086: *
0087: *
0088: * </pre>
0089: *
0090: * TODO Currently, transactions' behaviour is not tested for misappropriation of
0091: * incoming messages.
0092: *
0093: * TODO Currently, invite transactions are not tested for proper termination
0094: * upon respective timeouts.
0095: *
0096: * @author Emil Ivov Network Research Team, Louis Pasteur University,
0097: * Strasbourg, France. This code is in the public domain.
0098: * @version 1.0
0099: */
0100: public class InviteClientTransactionsStateMachineTest extends
0101: MessageFlowHarness {
0102:
0103: private static Logger logger = Logger
0104: .getLogger(InviteClientTransactionsStateMachineTest.class);
0105:
0106: public InviteClientTransactionsStateMachineTest(String name) {
0107: super (name, false); // disable auto-dialog for the RI, else ACKs get
0108: // filtered out
0109: }
0110:
0111: // ==================== tests ==============================
0112:
0113: /**
0114: * Tries to steer a TI client transaction through the following scenario
0115: * Calling-->Proceeding-->Completed-->Terminated. Apart from state
0116: * transitions, we also test, retransmissions and proper hiding/passing of
0117: * messages to the TU.
0118: */
0119: public void testCallingProceedingCompletedTerminatedScenario() {
0120: try {
0121: Request invite = createTiInviteRequest(null, null, null);
0122: ClientTransaction tran = null;
0123: try {
0124: eventCollector.collectRequestEvent(riSipProvider);
0125: tran = tiSipProvider.getNewClientTransaction(invite);
0126: tran.sendRequest();
0127: } catch (SipException ex) {
0128: throw new TiUnexpectedError(
0129: "A SipExceptionOccurred while trying to send request!",
0130: ex);
0131: } catch (TooManyListenersException ex) {
0132: throw new TckInternalError(
0133: "Failed to regiest a SipListener with an RI SipProvider",
0134: ex);
0135: }
0136: waitForMessage();
0137: RequestEvent inviteReceivedEvent = eventCollector
0138: .extractCollectedRequestEvent();
0139: if (inviteReceivedEvent == null
0140: || inviteReceivedEvent.getRequest() == null)
0141: throw new TiUnexpectedError(
0142: "The invite request was not received by the RI!");
0143: // At this point the ClientTransaction should be CALLING!
0144: assertEquals(TransactionState.CALLING, tran.getState());
0145: // Check Request retransmission
0146: try {
0147: eventCollector.collectRequestEvent(riSipProvider);
0148: } catch (TooManyListenersException ex) {
0149: throw new TckInternalError(
0150: "Failed to regiest a SipListener with an RI SipProvider",
0151: ex);
0152: }
0153: // Wait for the retransmission timer to fire if it had not already
0154: // done so.
0155: if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
0156: sleep((long) tran.getRetransmitTimer()
0157: - MESSAGES_ARRIVE_FOR); // subtract
0158: // the
0159: // time
0160: // we
0161: // waited
0162: // for
0163: // the
0164: // invite
0165: // Wait for the retransmitted request to arrive
0166: waitForMessage();
0167: inviteReceivedEvent = eventCollector
0168: .extractCollectedRequestEvent();
0169: assertNotNull("The invite request was not retransmitted!",
0170: inviteReceivedEvent);
0171: assertNotNull("The invite request was not retransmitted!",
0172: inviteReceivedEvent.getRequest());
0173: assertEquals(Request.INVITE, inviteReceivedEvent
0174: .getRequest().getMethod());
0175: // At this point the ClientTransaction should STILL be CALLING!
0176: assertEquals(TransactionState.CALLING, tran.getState());
0177: // Send a TRYING response
0178: try {
0179: eventCollector.collectResponseEvent(tiSipProvider);
0180: } catch (TooManyListenersException ex) {
0181: throw new TiUnexpectedError(
0182: "Failed to register a SipListener with TI", ex);
0183: }
0184: try {
0185: Response resp = riMessageFactory.createResponse(
0186: Response.TRYING, inviteReceivedEvent
0187: .getRequest());
0188: addStatus(inviteReceivedEvent.getRequest(), resp);
0189: riSipProvider.sendResponse(resp);
0190: } catch (Throwable ex) {
0191: throw new TckInternalError(
0192: "The TCK could not send a trying response back to the TI",
0193: ex);
0194: }
0195:
0196: waitForMessage();
0197: // Analyze the TRYING response and Tran state back at the TI
0198: ResponseEvent responseEvent = eventCollector
0199: .extractCollectedResponseEvent();
0200: assertNotNull(
0201: "The Tested Implementation did not pass a 1xx response to the TU!",
0202: responseEvent);
0203: assertNotNull(
0204: "The Tested Implementation did not pass a 1xx response to the TU!",
0205: responseEvent.getResponse());
0206: assertTrue(
0207: "A response different from TYING was passed to the TU!",
0208: responseEvent.getResponse().getStatusCode() == Response.TRYING);
0209: assertSame(
0210: "The TRYING response was not associated with the right transaction.",
0211: tran, responseEvent.getClientTransaction());
0212: // verify the the tran state is now PROCEEDING
0213: assertEquals(
0214: "The ClientTransaction did not pass in the PROCEEDING state after "
0215: + "receiving 1xx provisional response",
0216: tran.getState(), TransactionState.PROCEEDING);
0217: // Send a 486 BUSY HERE (final) response from the RI
0218: try {
0219: eventCollector.collectResponseEvent(tiSipProvider);
0220: } catch (TooManyListenersException ex) {
0221: throw new TiUnexpectedError(
0222: "Failed to register a SipListener with TI", ex);
0223: }
0224: // The BUSY_HERE response should trigger some ACKs so let's register
0225: // a listener with the RI
0226: SipEventCollector ackCollector = new SipEventCollector();
0227: try {
0228: ackCollector.collectRequestEvent(riSipProvider);
0229: } catch (TooManyListenersException ex) {
0230: throw new TckInternalError(
0231: "Failed to regiest a SipListener with an RI SipProvider",
0232: ex);
0233: }
0234: Response busyHere = null;
0235: try {
0236: busyHere = riMessageFactory.createResponse(
0237: Response.BUSY_HERE, inviteReceivedEvent
0238: .getRequest());
0239: addStatus(inviteReceivedEvent.getRequest(), busyHere);
0240:
0241: // JvB: set to-tag too, mandatory and tests that ACK is properly
0242: // formatted
0243: ((ToHeader) busyHere.getHeader("to"))
0244: .setTag("busy-here");
0245:
0246: riSipProvider.sendResponse(busyHere);
0247: } catch (Throwable ex) {
0248: throw new TckInternalError(
0249: "The TCK could not send a BUSY HERE response back to the TI",
0250: ex);
0251: }
0252: waitForMessage();
0253:
0254: // Analyze the BUSY_HERE response and Tran state back at the TI
0255: responseEvent = eventCollector
0256: .extractCollectedResponseEvent();
0257: assertNotNull(
0258: "The Tested Implementation did not pass a 300-699 response to the TU!",
0259: responseEvent);
0260: assertNotNull(
0261: "The Tested Implementation did not pass a 300-699 response to the TU!",
0262: responseEvent.getResponse());
0263: assertSame(
0264: "The BUSY_HERE response was not associated with the right transaction",
0265: tran, responseEvent.getClientTransaction());
0266: assertEquals(
0267: "A response different from BUSY_HERE was passed to the TU",
0268: Response.BUSY_HERE, responseEvent.getResponse()
0269: .getStatusCode());
0270: assertEquals(
0271: "The ClientTransaction did not pass in the COMPLETED state after "
0272: + "receiving 300-699 final response", tran
0273: .getState(), TransactionState.COMPLETED);
0274: // check whether the ackCollector has caught any fish
0275: RequestEvent ackReceivedEvent = ackCollector
0276: .extractCollectedRequestEvent();
0277:
0278: // JvB: With auto-dialog-support enabled, the ACK should be filtered
0279: // by the RI
0280: assertNotNull("The TI did not send an ACK request",
0281: ackReceivedEvent);
0282: assertNotNull("The TI did not send an ACK request",
0283: ackReceivedEvent.getRequest());
0284: assertEquals(Request.ACK, ackReceivedEvent.getRequest()
0285: .getMethod());
0286:
0287: // Try to kill remaining ACK retransmissions
0288: // TODO this may not always work .. should give it a specific
0289: // timeout value
0290: waitForMessage();
0291: // Now let's retransmit the final response. This time it shouldn't
0292: // be
0293: // passed to the TU but an ACK should still be sent
0294: try {
0295: eventCollector.collectResponseEvent(tiSipProvider);
0296: } catch (TooManyListenersException ex) {
0297: throw new TiUnexpectedError(
0298: "Failed to register a SipListener with TI", ex);
0299: }
0300: // go fish the ack
0301: try {
0302: ackCollector.collectRequestEvent(riSipProvider);
0303: } catch (TooManyListenersException ex) {
0304: throw new TckInternalError(
0305: "Failed to regiest a SipListener with an RI SipProvider",
0306: ex);
0307: }
0308: try {
0309: riSipProvider.sendResponse((Response) busyHere.clone());
0310: } catch (Throwable ex) {
0311: throw new TckInternalError(
0312: "The TCK could not send a BUSY HERE response back to the TI",
0313: ex);
0314: }
0315: waitForMessage();
0316: // The TU shouldn't see the retransmitted BUSY_HERE response
0317: responseEvent = eventCollector
0318: .extractCollectedResponseEvent();
0319: assertNull(
0320: "The Tested Implementation passed a retransmitted 300-699 response "
0321: + "to the TU instead of just silently acknowledging it!",
0322: responseEvent);
0323: // We must still be in the completed state.
0324: assertEquals(
0325: "The ClientTransaction did not stay long enough in the COMPLETED "
0326: + "state.", tran.getState(),
0327: TransactionState.COMPLETED);
0328: // check whether the ackCollector has caught any fish
0329: ackReceivedEvent = ackCollector
0330: .extractCollectedRequestEvent();
0331: assertNotNull(
0332: "The TI did not send an ACK request to the second response",
0333: ackReceivedEvent);
0334: assertNotNull(
0335: "The TI did not send an ACK request to the second response",
0336: ackReceivedEvent.getRequest());
0337: assertEquals(Request.ACK, ackReceivedEvent.getRequest()
0338: .getMethod());
0339: } catch (Throwable exc) {
0340: exc.printStackTrace();
0341: fail(exc.getClass().getName() + ": " + exc.getMessage());
0342: }
0343: assertTrue(new Exception().getStackTrace()[0].toString(), true);
0344:
0345: // Unfortunately we can't assert the TERMINATED state as TIMER_K TIMER_D
0346: // is not exported by JAIN SIP
0347:
0348: }
0349:
0350: /**
0351: * JvB: Tests transmission of an INVITE followed by CANCELlation of that
0352: * request
0353: * -> INVITE <- 100 -> CANCEL <- OK <- 487 -> ACK
0354: */
0355: public void testInviteCancel() {
0356: doCancelTest(true);
0357: }
0358:
0359: /**
0360: * Same as above, but for non-RFC3261 client (i.e. no Via branch, no from/to
0361: * tags
0362: *
0363: * Cannot do this on 1.2 stack
0364: *
0365: * public void testInviteCancelNonRFC3261() { doCancelTest(false); }
0366: */
0367:
0368: /**
0369: * JvB: Tests transmission of an INVITE followed by CANCELlation of that
0370: * request
0371: * -> INVITE <- 100 -> CANCEL <- OK <- 487 -> ACK
0372: *
0373: * Note: for 1.2 it is impossible to manually set the top via branch to
0374: * something not RFC3261-compliant
0375: */
0376: private void doCancelTest(boolean rfc3261Compliant) {
0377: try {
0378: Request invite = createTiInviteRequest(null, null, null);
0379: ClientTransaction tran = null;
0380: try {
0381: eventCollector.collectRequestEvent(riSipProvider);
0382:
0383: // This call overwrites any branch we set
0384: tran = tiSipProvider.getNewClientTransaction(invite);
0385:
0386: // And this call too
0387: tran.sendRequest();
0388: } catch (SipException ex) {
0389: throw new TiUnexpectedError(
0390: "A SipExceptionOccurred while trying to send request!",
0391: ex);
0392: } catch (TooManyListenersException ex) {
0393: throw new TckInternalError(
0394: "Failed to regiest a SipListener with an RI SipProvider",
0395: ex);
0396: }
0397: waitForMessage();
0398: RequestEvent inviteReceivedEvent = eventCollector
0399: .extractCollectedRequestEvent();
0400:
0401: if (inviteReceivedEvent == null
0402: || inviteReceivedEvent.getRequest() == null)
0403: throw new TiUnexpectedError(
0404: "The invite request was not received by the RI!");
0405:
0406: // At this point the ClientTransaction should be CALLING!
0407: assertEquals(TransactionState.CALLING, tran.getState());
0408:
0409: // Send a TRYING response
0410: try {
0411: eventCollector.collectResponseEvent(tiSipProvider);
0412: } catch (TooManyListenersException ex) {
0413: throw new TiUnexpectedError(
0414: "Failed to register a SipListener with TI", ex);
0415: }
0416: try {
0417: Response resp = riMessageFactory.createResponse(
0418: Response.TRYING, inviteReceivedEvent
0419: .getRequest());
0420: addStatus(inviteReceivedEvent.getRequest(), resp);
0421: riSipProvider.sendResponse(resp);
0422: } catch (Throwable ex) {
0423: throw new TckInternalError(
0424: "The TCK could not send a trying response back to the TI",
0425: ex);
0426: }
0427:
0428: waitForMessage();
0429: // Analyze the TRYING response and Tran state back at the TI
0430: ResponseEvent responseEvent = eventCollector
0431: .extractCollectedResponseEvent();
0432: assertNotNull(
0433: "The Tested Implementation did not pass a 1xx response to the TU!",
0434: responseEvent);
0435: assertNotNull(
0436: "The Tested Implementation did not pass a 1xx response to the TU!",
0437: responseEvent.getResponse());
0438: assertTrue(
0439: "A response different from TYING was passed to the TU!",
0440: responseEvent.getResponse().getStatusCode() == Response.TRYING);
0441: assertSame(
0442: "The TRYING response was not associated with the right transaction.",
0443: tran, responseEvent.getClientTransaction());
0444: // verify the the tran state is now PROCEEDING
0445: assertEquals(
0446: "The ClientTransaction did not pass in the PROCEEDING state after "
0447: + "receiving 1xx provisional response",
0448: tran.getState(), TransactionState.PROCEEDING);
0449:
0450: // Send a CANCEL from the TI
0451: Request tiCancel = tran.createCancel();
0452:
0453: /*
0454: * this works, but since we cannot patch the INVITE the test fails
0455: * if (!rfc3261Compliant) { ((ViaHeader)
0456: * tiCancel.getHeader("Via")).setBranch( "xxx" ); // Not allowed by
0457: * RI // ((FromHeader) tiCancel.getHeader("From")).setTag( "" ); }
0458: */
0459:
0460: ClientTransaction tiCancelTrans;
0461: try {
0462: eventCollector.collectRequestEvent(riSipProvider);
0463: tiCancelTrans = tiSipProvider
0464: .getNewClientTransaction(tiCancel);
0465: tiCancelTrans.sendRequest();
0466: } catch (SipException ex) {
0467: throw new TiUnexpectedError(
0468: "A SipExceptionOccurred while trying to send CANCEL!",
0469: ex);
0470: }
0471: waitForMessage();
0472: RequestEvent cancelReceivedEvent = eventCollector
0473: .extractCollectedRequestEvent();
0474: if (cancelReceivedEvent == null
0475: || cancelReceivedEvent.getRequest() == null)
0476: throw new TiUnexpectedError(
0477: "The CANCEL request was not received by the RI!");
0478:
0479: // Send 200 OK to the CANCEL
0480: try {
0481: eventCollector.collectResponseEvent(tiSipProvider);
0482: } catch (TooManyListenersException ex) {
0483: throw new TiUnexpectedError(
0484: "Failed to register a SipListener with TI", ex);
0485: }
0486: Response riCancelOk = null;
0487: try {
0488: riCancelOk = riMessageFactory.createResponse(
0489: Response.OK, cancelReceivedEvent.getRequest());
0490: addStatus(cancelReceivedEvent.getRequest(), riCancelOk);
0491: riSipProvider.sendResponse(riCancelOk);
0492: } catch (Throwable ex) {
0493: throw new TckInternalError(
0494: "The TCK could not send a CANCEL OK response back to the TI",
0495: ex);
0496: }
0497: waitForMessage();
0498:
0499: // Analyze the OK response and Tran state back at the TI
0500: responseEvent = eventCollector
0501: .extractCollectedResponseEvent();
0502: if (responseEvent == null
0503: || responseEvent.getResponse() == null) {
0504: throw new TiUnexpectedError(
0505: "The CANCEL OK response was not received by the TI!");
0506: }
0507:
0508: // Send 487 to the INVITE, expect ACK
0509: try {
0510: eventCollector.collectResponseEvent(tiSipProvider);
0511: } catch (TooManyListenersException ex) {
0512: throw new TiUnexpectedError(
0513: "Failed to register a SipListener with TI", ex);
0514: }
0515: SipEventCollector ackCollector = new SipEventCollector();
0516: try {
0517: ackCollector.collectRequestEvent(riSipProvider);
0518: } catch (TooManyListenersException ex) {
0519: throw new TckInternalError(
0520: "Failed to regiest a SipListener with an RI SipProvider",
0521: ex);
0522: }
0523:
0524: Response riInviteTerminated = null;
0525: try {
0526: riInviteTerminated = riMessageFactory.createResponse(
0527: Response.REQUEST_TERMINATED,
0528: inviteReceivedEvent.getRequest());
0529: addStatus(inviteReceivedEvent.getRequest(),
0530: riInviteTerminated);
0531: riSipProvider.sendResponse(riInviteTerminated);
0532: } catch (Throwable ex) {
0533: throw new TckInternalError(
0534: "The TCK could not send a INVITE 487 response back to the TI",
0535: ex);
0536: }
0537: waitForMessage();
0538:
0539: // Analyze the REQUEST_TERMINATED response and Tran state back at
0540: // the TI
0541: responseEvent = eventCollector
0542: .extractCollectedResponseEvent();
0543: assertNotNull(
0544: "The Tested Implementation did not pass a 300-699 response to the TU!",
0545: responseEvent);
0546: assertNotNull(
0547: "The Tested Implementation did not pass a 300-699 response to the TU!",
0548: responseEvent.getResponse());
0549: assertSame(
0550: "The 487 response was not associated with the right transaction",
0551: tran, responseEvent.getClientTransaction());
0552: assertEquals(
0553: "A response different from 487 was passed to the TU",
0554: Response.REQUEST_TERMINATED, responseEvent
0555: .getResponse().getStatusCode());
0556: assertEquals(
0557: "The ClientTransaction did not pass in the COMPLETED state after "
0558: + "receiving 300-699 final response", tran
0559: .getState(), TransactionState.COMPLETED);
0560: // check whether the ackCollector has caught any fish
0561: RequestEvent ackReceivedEvent = ackCollector
0562: .extractCollectedRequestEvent();
0563: assertNotNull("The TI did not send an ACK request event",
0564: ackReceivedEvent);
0565: assertNotNull("The TI did not send an ACK request",
0566: ackReceivedEvent.getRequest());
0567: assertEquals(Request.ACK, ackReceivedEvent.getRequest()
0568: .getMethod());
0569:
0570: // Try to kill remaining ACK retransmissions?
0571: } catch (Throwable exc) {
0572: exc.printStackTrace();
0573: fail(exc.getClass().getName() + ": " + exc.getMessage());
0574: }
0575: assertTrue(new Exception().getStackTrace()[0].toString(), true);
0576:
0577: // Unfortunately we can't assert the TERMINATED state as TIMER_K TIMER_D
0578: // is not exported by JAIN SIP
0579: }
0580:
0581: /**
0582: * Tries to steer a TI client transaction through the following scenario
0583: * Calling-->Completed-->Terminated. Apart from state transitions, we also
0584: * test, retransmissions and proper hiding/passing of messages to the TU.
0585: */
0586: public void testCallingCompletedTerminatedScenario() {
0587: try {
0588: Request invite = createTiInviteRequest(null, null, null);
0589:
0590: // JvB: test
0591: // ((MessageExt) invite).getFirstViaHeader().setParameter( "rport",
0592: // null );
0593:
0594: ClientTransaction tran = null;
0595: try {
0596: eventCollector.collectRequestEvent(riSipProvider);
0597: tran = tiSipProvider.getNewClientTransaction(invite);
0598: tran.sendRequest();
0599: } catch (SipException ex) {
0600: throw new TiUnexpectedError(
0601: "A SipExceptionOccurred while trying to send request!",
0602: ex);
0603: } catch (TooManyListenersException ex) {
0604: throw new TckInternalError(
0605: "Failed to regiest a SipListener with an RI SipProvider",
0606: ex);
0607: }
0608: waitForMessage();
0609: RequestEvent inviteReceivedEvent = eventCollector
0610: .extractCollectedRequestEvent();
0611: if (inviteReceivedEvent == null
0612: || inviteReceivedEvent.getRequest() == null)
0613: throw new TiUnexpectedError(
0614: "The invite request was not received by the RI!");
0615: // At this point the ClientTransaction should be CALLING!
0616: assertEquals(TransactionState.CALLING, tran.getState());
0617: // Check Request retransmission
0618: try {
0619: eventCollector.collectRequestEvent(riSipProvider);
0620: } catch (TooManyListenersException ex) {
0621: throw new TckInternalError(
0622: "Failed to regiest a SipListener with an RI SipProvider",
0623: ex);
0624: }
0625: // Wait for the retransmission timer to fire if it had not already
0626: // done so.
0627: if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
0628: sleep((long) tran.getRetransmitTimer()
0629: - MESSAGES_ARRIVE_FOR); // subtract
0630: // the
0631: // time
0632: // we
0633: // waited
0634: // for
0635: // the
0636: // invite
0637: // Wait for the retransmitted request to arrive
0638: waitForMessage();
0639: inviteReceivedEvent = eventCollector
0640: .extractCollectedRequestEvent();
0641: assertNotNull("The invite request was not retransmitted!",
0642: inviteReceivedEvent);
0643: assertNotNull("The invite request was not retransmitted!",
0644: inviteReceivedEvent.getRequest());
0645: assertEquals(Request.INVITE, inviteReceivedEvent
0646: .getRequest().getMethod());
0647: // At this point the ClientTransaction should STILL be CALLING!
0648: assertEquals(TransactionState.CALLING, tran.getState());
0649: // Send a 486 BUSY HERE (final) response from the RI
0650: try {
0651: eventCollector.collectResponseEvent(tiSipProvider);
0652: } catch (TooManyListenersException ex) {
0653: throw new TiUnexpectedError(
0654: "Failed to register a SipListener with TI", ex);
0655: }
0656: // The BUSY_HERE response should trigger some ACKs so let's register
0657: // a listener with the RI
0658: SipEventCollector ackCollector = new SipEventCollector();
0659: try {
0660: ackCollector.collectRequestEvent(riSipProvider);
0661: } catch (TooManyListenersException ex) {
0662: throw new TckInternalError(
0663: "Failed to regiest a SipListener with an RI SipProvider",
0664: ex);
0665: }
0666: Response busyHere = null;
0667: try {
0668: busyHere = riMessageFactory.createResponse(
0669: Response.BUSY_HERE, inviteReceivedEvent
0670: .getRequest());
0671: addStatus(inviteReceivedEvent.getRequest(), busyHere);
0672:
0673: // JvB: set to-tag, check it against the ACK generated
0674: ((ToHeader) busyHere.getHeader("to"))
0675: .setTag("ack-to-test");
0676:
0677: riSipProvider.sendResponse((Response) busyHere.clone());
0678: } catch (Throwable ex) {
0679: throw new TckInternalError(
0680: "The TCK could not send a BUSY HERE response back to the TI",
0681: ex);
0682: }
0683: waitForMessage();
0684: // Analyze the BUSY_HERE response and Tran state back at the TI
0685: ResponseEvent responseEvent = eventCollector
0686: .extractCollectedResponseEvent();
0687: assertNotNull(
0688: "The Tested Implementation did not pass a 300-699 response to the TU!",
0689: responseEvent);
0690: assertNotNull(
0691: "The Tested Implementation did not pass a 300-699 response to the TU!",
0692: responseEvent.getResponse());
0693: assertSame(
0694: "The BUSY_HERE response was not associated with the right transaction",
0695: tran, responseEvent.getClientTransaction());
0696: assertSame(
0697: "A response different from BUSY_HERE was passed to the TU",
0698: tran, responseEvent.getClientTransaction());
0699: assertEquals(
0700: "The ClientTransaction did not pass in the COMPLETED state after "
0701: + "receiving 300-699 final response", tran
0702: .getState(), TransactionState.COMPLETED);
0703: // check whether the ackCollector has caught any fish
0704: RequestEvent ackReceivedEvent = ackCollector
0705: .extractCollectedRequestEvent();
0706: assertNotNull("The TI did not send an ACK request",
0707: ackReceivedEvent);
0708: assertNotNull("The TI did not send an ACK request",
0709: ackReceivedEvent.getRequest());
0710: assertEquals(Request.ACK, ackReceivedEvent.getRequest()
0711: .getMethod());
0712: // Try to kill remaining ACK retransmissions
0713: // TODO this may not always work .. should give it a specific
0714: // timeout value
0715: waitForMessage();
0716: // Now let's retransmit the final response. This time it shouldn't
0717: // be
0718: // passed to the TU but an ACK should still be sent
0719: try {
0720: eventCollector.collectResponseEvent(tiSipProvider);
0721: } catch (TooManyListenersException ex) {
0722: throw new TiUnexpectedError(
0723: "Failed to register a SipListener with TI", ex);
0724: }
0725: // go fish the ack
0726: try {
0727: ackCollector.collectRequestEvent(riSipProvider);
0728: } catch (TooManyListenersException ex) {
0729: throw new TckInternalError(
0730: "Failed to regiest a SipListener with an RI SipProvider",
0731: ex);
0732: }
0733: try {
0734: riSipProvider.sendResponse((Response) busyHere.clone());
0735: } catch (Throwable ex) {
0736: throw new TckInternalError(
0737: "The TCK could not send a BUSY HERE response back to the TI",
0738: ex);
0739: }
0740: waitForMessage();
0741: // The TU shouldn't see the retransmitted BUSY_HERE response
0742: responseEvent = eventCollector
0743: .extractCollectedResponseEvent();
0744: assertNull(
0745: "The Tested Implementation passed a retransmitted 300-699 response "
0746: + "to the TU instead of just silently acknowledging it!",
0747: responseEvent);
0748: // We must still be in the completed state.
0749: assertEquals(
0750: "The ClientTransaction did not stay long enough in the COMPLETED "
0751: + "state.", tran.getState(),
0752: TransactionState.COMPLETED);
0753: // check whether the ackCollector has caught any fish
0754: ackReceivedEvent = ackCollector
0755: .extractCollectedRequestEvent();
0756: assertNotNull(
0757: "The TI did not send an ACK request to the second response",
0758: ackReceivedEvent);
0759: assertNotNull(
0760: "The TI did not send an ACK request to the second response",
0761: ackReceivedEvent.getRequest());
0762:
0763: assertEquals(Request.ACK, ackReceivedEvent.getRequest()
0764: .getMethod());
0765:
0766: // JvB: verify to tag
0767: assertEquals(
0768: "The To header field in the ACK MUST equal the To header field "
0769: + " in the response being acknowledged",
0770: "ack-to-test", ((ToHeader) ackReceivedEvent
0771: .getRequest().getHeader("to")).getTag());
0772: } catch (Throwable exc) {
0773: exc.printStackTrace();
0774: fail(exc.getClass().getName() + ": " + exc.getMessage());
0775: }
0776: assertTrue(new Exception().getStackTrace()[0].toString(), true);
0777:
0778: // Unfortunately we can't assert the TERMINATED state as TIMER_D
0779: // is not exported by JAIN SIP
0780:
0781: }
0782:
0783: /**
0784: * Tries to steer a TI client transaction through the following scenario
0785: * Calling-->Proceeding-->Terminated. Apart from state transitions, we also
0786: * test, retransmissions and proper hiding/passing of messages to the TU.
0787: */
0788: public void testCallingProceedingTerminatedScenario() {
0789: try {
0790: Request invite = createTiInviteRequest(null, null, null);
0791: ClientTransaction tran = null;
0792: try {
0793: eventCollector.collectRequestEvent(riSipProvider);
0794: tran = tiSipProvider.getNewClientTransaction(invite);
0795: tran.sendRequest();
0796: } catch (SipException ex) {
0797: throw new TiUnexpectedError(
0798: "A SipExceptionOccurred while trying to send request!",
0799: ex);
0800: } catch (TooManyListenersException ex) {
0801: throw new TckInternalError(
0802: "Failed to regiest a SipListener with an RI SipProvider",
0803: ex);
0804: }
0805: waitForMessage();
0806: RequestEvent inviteReceivedEvent = eventCollector
0807: .extractCollectedRequestEvent();
0808: if (inviteReceivedEvent == null
0809: || inviteReceivedEvent.getRequest() == null)
0810: throw new TiUnexpectedError(
0811: "The invite request was not received by the RI!");
0812: // At this point the ClientTransaction should be CALLING!
0813: assertEquals(TransactionState.CALLING, tran.getState());
0814: // Check Request retransmission
0815: try {
0816: eventCollector.collectRequestEvent(riSipProvider);
0817: } catch (TooManyListenersException ex) {
0818: throw new TckInternalError(
0819: "Failed to regiest a SipListener with an RI SipProvider",
0820: ex);
0821: }
0822: // Wait for the retransmission timer to fire if it had not already
0823: // done so.
0824: if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
0825: sleep((long) tran.getRetransmitTimer()
0826: - MESSAGES_ARRIVE_FOR); // subtract
0827: // the
0828: // time
0829: // we
0830: // waited
0831: // for
0832: // the
0833: // invite
0834: // Wait for the retransmitted request to arrive
0835: waitForMessage();
0836: inviteReceivedEvent = eventCollector
0837: .extractCollectedRequestEvent();
0838: assertNotNull("The invite request was not retransmitted!",
0839: inviteReceivedEvent);
0840: assertNotNull("The invite request was not retransmitted!",
0841: inviteReceivedEvent.getRequest());
0842: assertEquals(Request.INVITE, inviteReceivedEvent
0843: .getRequest().getMethod());
0844: // At this point the ClientTransaction should STILL be CALLING!
0845: assertEquals(TransactionState.CALLING, tran.getState());
0846: // Send a TRYING response
0847: try {
0848: eventCollector.collectResponseEvent(tiSipProvider);
0849: } catch (TooManyListenersException ex) {
0850: throw new TiUnexpectedError(
0851: "Failed to register a SipListener with TI", ex);
0852: }
0853: try {
0854: Response resp = riMessageFactory.createResponse(
0855: Response.TRYING, inviteReceivedEvent
0856: .getRequest());
0857: addStatus(inviteReceivedEvent.getRequest(), resp);
0858: riSipProvider.sendResponse(resp);
0859: } catch (Throwable ex) {
0860: throw new TckInternalError(
0861: "The TCK could not send a trying response back to the TI",
0862: ex);
0863: }
0864: waitForMessage();
0865: // Analyze the TRYING response and Tran state back at the TI
0866: ResponseEvent responseEvent = eventCollector
0867: .extractCollectedResponseEvent();
0868: assertNotNull(
0869: "The Tested Implementation did not pass a 1xx response to the TU!",
0870: responseEvent);
0871: assertNotNull(
0872: "The Tested Implementation did not pass a 1xx response to the TU!",
0873: responseEvent.getResponse());
0874: assertTrue(
0875: "A response different from TYING was passed to the TU!",
0876: responseEvent.getResponse().getStatusCode() == Response.TRYING);
0877: assertSame(
0878: "The TRYING response was not associated with the right transaction",
0879: tran, responseEvent.getClientTransaction());
0880: // verify the the tran state is now PROCEEDING
0881: assertEquals(
0882: "The ClientTransaction did not pass in the PROCEEDING state after "
0883: + "receiving 1xx provisional response",
0884: tran.getState(), TransactionState.PROCEEDING);
0885: // Send a 200 OK (final) response from the RI
0886: try {
0887: eventCollector.collectResponseEvent(tiSipProvider);
0888: } catch (TooManyListenersException ex) {
0889: throw new TiUnexpectedError(
0890: "Failed to register a SipListener with TI", ex);
0891: }
0892: // The OK response shouldn't trigger any ACKs so let's register
0893: // a listener with the RI to verify whether that is the case
0894: SipEventCollector ackCollector = new SipEventCollector();
0895: try {
0896: ackCollector.collectRequestEvent(riSipProvider);
0897: } catch (TooManyListenersException ex) {
0898: throw new TckInternalError(
0899: "Failed to regiest a SipListener with an RI SipProvider",
0900: ex);
0901: }
0902: Response ok = null;
0903: try {
0904: ok = riMessageFactory.createResponse(Response.OK,
0905: inviteReceivedEvent.getRequest());
0906:
0907: // JvB: MUST add Contact too!
0908: ContactHeader contact = riHeaderFactory
0909: .createContactHeader(((ToHeader) ok
0910: .getHeader("To")).getAddress());
0911: ok.addHeader(contact);
0912: // end JvB
0913:
0914: addStatus(inviteReceivedEvent.getRequest(), ok);
0915: riSipProvider.sendResponse((Response) ok.clone());
0916: } catch (Throwable ex) {
0917: throw new TckInternalError(
0918: "The TCK could not send an OK response back to the TI",
0919: ex);
0920: }
0921: waitForMessage();
0922: // Analyze the OK response and Tran state back at the TI
0923: responseEvent = eventCollector
0924: .extractCollectedResponseEvent();
0925: assertNotNull(
0926: "The Tested Implementation did not pass a 200 OK response to the TU!",
0927: responseEvent);
0928: assertNotNull(
0929: "The Tested Implementation did not pass a 200 OK response to the TU!",
0930: responseEvent.getResponse());
0931: assertSame(
0932: "The OK response was not associated with the right transaction",
0933: tran, responseEvent.getClientTransaction());
0934: assertSame(
0935: "A response different from OK was passed to the TU",
0936: tran, responseEvent.getClientTransaction());
0937: assertEquals(
0938: "The ClientTransaction did not pass in the TERMINATED state after "
0939: + "receiving 200 final response", tran
0940: .getState(), TransactionState.TERMINATED);
0941: // check whether the ackCollector has caught any fish
0942: RequestEvent ackReceivedEvent = ackCollector
0943: .extractCollectedRequestEvent();
0944: if (ackReceivedEvent != null)
0945: logger.error("Shouldn't have received that="
0946: + ackReceivedEvent.getRequest());
0947: assertNull(
0948: "The TI sent an ACK to an OK (this is TU's job)!",
0949: ackReceivedEvent);
0950: // Now let's retransmit the final response and see it is
0951: // passed to the TU (again no ACKs)
0952: try {
0953: eventCollector.collectResponseEvent(tiSipProvider);
0954: } catch (TooManyListenersException ex) {
0955: throw new TiUnexpectedError(
0956: "Failed to register a SipListener with TI", ex);
0957: }
0958: // go fish the ack
0959: try {
0960: ackCollector.collectRequestEvent(riSipProvider);
0961: } catch (TooManyListenersException ex) {
0962: throw new TckInternalError(
0963: "Failed to regiest a SipListener with an RI SipProvider",
0964: ex);
0965: }
0966: try {
0967: riSipProvider.sendResponse((Response) ok.clone());
0968: } catch (Throwable ex) {
0969: throw new TckInternalError(
0970: "The TCK could not send an OK response back to the TI",
0971: ex);
0972: }
0973: waitForMessage();
0974: // Did we get the 2nd OK?
0975: responseEvent = eventCollector
0976: .extractCollectedResponseEvent();
0977:
0978: /*
0979: * JvB: the stack should in fact ~not~ pass the retransmitted
0980: * response, but filter it out
0981: *
0982: * assertNotNull( "The TI did not pass to the TU a retransmitted OK
0983: * response!", responseEvent); assertNotNull( "The TI did not pass
0984: * to the TU a retransmitted OK response!",
0985: * responseEvent.getResponse()); assertTrue( "The TI passed to the
0986: * TU a bad response!",
0987: * responseEvent.getResponse().getStatusCode()==Response.OK);
0988: */
0989: // TBD
0990: // assertNull( "The TI should filter the retransmitted OK response",
0991: // responseEvent );
0992: // We must still be in the terminated state.
0993: assertEquals(
0994: "The ClientTransaction mysteriously left the TERMINATED state!",
0995: tran.getState(), TransactionState.TERMINATED);
0996: // check whether the ackCollector has caught any fish
0997: ackReceivedEvent = ackCollector
0998: .extractCollectedRequestEvent();
0999: assertNull(
1000: "The TI sent an ACK request to the second OK response "
1001: + "(OK acks are TU's responsibility)!",
1002: ackReceivedEvent);
1003: } catch (Throwable exc) {
1004: exc.printStackTrace();
1005: fail(exc.getClass().getName() + ": " + exc.getMessage());
1006: }
1007: assertTrue(new Exception().getStackTrace()[0].toString(), true);
1008: }
1009:
1010: /**
1011: * Tries to steer a TI client transaction through the following scenario
1012: * Calling-->Terminated. Apart from state transitions, we also test,
1013: * retransmissions and proper hiding/passing of messages to the TU.
1014: */
1015: public void testCallingTerminatedScenario() {
1016: try {
1017: Request invite = createTiInviteRequest(null, null, null);
1018: ClientTransaction tran = null;
1019: try {
1020: eventCollector.collectRequestEvent(riSipProvider);
1021: tran = tiSipProvider.getNewClientTransaction(invite);
1022: tran.sendRequest();
1023: } catch (SipException ex) {
1024: throw new TiUnexpectedError(
1025: "A SipExceptionOccurred while trying to send request!",
1026: ex);
1027: } catch (TooManyListenersException ex) {
1028: throw new TckInternalError(
1029: "Failed to regiest a SipListener with an RI SipProvider",
1030: ex);
1031: }
1032: waitForMessage();
1033: RequestEvent inviteReceivedEvent = eventCollector
1034: .extractCollectedRequestEvent();
1035: if (inviteReceivedEvent == null
1036: || inviteReceivedEvent.getRequest() == null)
1037: throw new TiUnexpectedError(
1038: "The invite request was not received by the RI!");
1039: // At this point the ClientTransaction should be CALLING!
1040: assertEquals(TransactionState.CALLING, tran.getState());
1041: // Check Request retransmission
1042: try {
1043: eventCollector.collectRequestEvent(riSipProvider);
1044: } catch (TooManyListenersException ex) {
1045: throw new TckInternalError(
1046: "Failed to regiest a SipListener with an RI SipProvider",
1047: ex);
1048: }
1049: // Wait for the retransmission timer to fire if it had not already
1050: // done so.
1051: if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
1052: sleep((long) tran.getRetransmitTimer()
1053: - MESSAGES_ARRIVE_FOR); // subtract
1054: // the
1055: // time
1056: // we
1057: // waited
1058: // for
1059: // the
1060: // invite
1061: // Wait for the retransmitted request to arrive
1062: waitForMessage();
1063: inviteReceivedEvent = eventCollector
1064: .extractCollectedRequestEvent();
1065: assertNotNull("The invite request was not retransmitted!",
1066: inviteReceivedEvent);
1067: assertNotNull("The invite request was not retransmitted!",
1068: inviteReceivedEvent.getRequest());
1069: assertEquals(Request.INVITE, inviteReceivedEvent
1070: .getRequest().getMethod());
1071: // At this point the ClientTransaction should STILL be CALLING!
1072: assertEquals(TransactionState.CALLING, tran.getState());
1073: // Send a 200 OK (final) response from the RI
1074: try {
1075: eventCollector.collectResponseEvent(tiSipProvider);
1076: } catch (TooManyListenersException ex) {
1077: throw new TiUnexpectedError(
1078: "Failed to register a SipListener with TI", ex);
1079: }
1080: // The OK response shouldn't trigger any ACKs so let's register
1081: // a listener with the RI to verify whether that is the case
1082: SipEventCollector ackCollector = new SipEventCollector();
1083: try {
1084: ackCollector.collectRequestEvent(riSipProvider);
1085: } catch (TooManyListenersException ex) {
1086: throw new TckInternalError(
1087: "Failed to regiest a SipListener with an RI SipProvider",
1088: ex);
1089: }
1090: Response ok = null;
1091: try {
1092: ok = riMessageFactory.createResponse(Response.OK,
1093: inviteReceivedEvent.getRequest());
1094: addStatus(inviteReceivedEvent.getRequest(), ok);
1095:
1096: // JvB: MUST add Contact too!
1097: ContactHeader contact = riHeaderFactory
1098: .createContactHeader(((ToHeader) ok
1099: .getHeader("To")).getAddress());
1100: ok.addHeader(contact);
1101: // end JvB
1102:
1103: riSipProvider.sendResponse(ok);
1104: } catch (Throwable ex) {
1105: throw new TckInternalError(
1106: "The TCK could not send an OK response back to the TI",
1107: ex);
1108: }
1109: waitForMessage();
1110: // Analyze the OK response and Tran state back at the TI
1111: ResponseEvent responseEvent = eventCollector
1112: .extractCollectedResponseEvent();
1113: assertNotNull(
1114: "The Tested Implementation did not pass a 200 OK response to the TU!",
1115: responseEvent);
1116: assertNotNull(
1117: "The Tested Implementation did not pass a 200 OK response to the TU!",
1118: responseEvent.getResponse());
1119: assertSame(
1120: "The OK response was not associated with the right transaction",
1121: tran, responseEvent.getClientTransaction());
1122: assertSame(
1123: "A response different from OK was passed to the TU",
1124: tran, responseEvent.getClientTransaction());
1125: assertEquals(
1126: "The ClientTransaction did not pass in the TERMINATED state after "
1127: + "receiving 200 final response", tran
1128: .getState(), TransactionState.TERMINATED);
1129: // check whether the ackCollector has caught any fish
1130: RequestEvent ackReceivedEvent = ackCollector
1131: .extractCollectedRequestEvent();
1132: assertNull(
1133: "The TI sent an ACK to an OK (this is TU's job)!",
1134: ackReceivedEvent);
1135: // Now let's retransmit the final response and see that it is
1136: // passed to the TU (again no ACKs should be sent by the TI)
1137: try {
1138: eventCollector.collectResponseEvent(tiSipProvider);
1139: } catch (TooManyListenersException ex) {
1140: throw new TiUnexpectedError(
1141: "Failed to register a SipListener with TI", ex);
1142: }
1143: // go fish the ack
1144: try {
1145: ackCollector.collectRequestEvent(riSipProvider);
1146: } catch (TooManyListenersException ex) {
1147: throw new TckInternalError(
1148: "Failed to regiest a SipListener with an RI SipProvider",
1149: ex);
1150: }
1151: try {
1152: riSipProvider.sendResponse((Response) ok.clone());
1153: } catch (Throwable ex) {
1154: throw new TckInternalError(
1155: "The TCK could not send an OK response back to the TI",
1156: ex);
1157: }
1158: waitForMessage();
1159: // Did we get the 2nd OK?
1160: responseEvent = eventCollector
1161: .extractCollectedResponseEvent();
1162: /*
1163: * JvB: see previous comment
1164: *
1165: * assertNotNull( "The TI did not pass to the TU a retransmitted OK
1166: * response!", responseEvent); assertNotNull( "The TI did not pass
1167: * to the TU a retransmitted OK response!",
1168: * responseEvent.getResponse()); assertTrue( "The TI passed to the
1169: * TU a bad response!",
1170: * responseEvent.getResponse().getStatusCode()==Response.OK);
1171: */
1172: // JvB: TBD
1173: // assertNull( "The TI should filter the retransmitted OK response",
1174: // responseEvent );
1175: // We must still be in the terminated state.
1176: assertEquals(
1177: "The ClientTransaction mysteriously left the TERMINATED state!",
1178: tran.getState(), TransactionState.TERMINATED);
1179: // check whether the ackCollector has caught any fish
1180: ackReceivedEvent = ackCollector
1181: .extractCollectedRequestEvent();
1182: assertNull(
1183: "The TI sent an ACK request to the second OK response "
1184: + "(OK acks are TU's responsibility)!",
1185: ackReceivedEvent);
1186: } catch (Throwable exc) {
1187: exc.printStackTrace();
1188: fail(exc.getClass().getName() + ": " + exc.getMessage());
1189: }
1190: assertTrue(new Exception().getStackTrace()[0].toString(), true);
1191: }
1192:
1193: // ==================== end of tests
1194:
1195: // ====== STATIC JUNIT ==========
1196: public static Test suite() {
1197: return new TestSuite(
1198: InviteClientTransactionsStateMachineTest.class);
1199: }
1200:
1201: }
|