001: /*
002: * Conditions Of Use
003: *
004: * This software was developed by employees of the National Institute of
005: * Standards and Technology (NIST), and others.
006: * This software is has been contributed to the public domain.
007: * As a result, a formal license is not needed to use the software.
008: *
009: * This software is provided "AS IS."
010: * NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
011: * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
012: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
013: * AND DATA ACCURACY. NIST does not warrant or make any representations
014: * regarding the use of the software or the results thereof, including but
015: * not limited to the correctness, accuracy, reliability or usefulness of
016: * the software.
017: *
018: *
019: */
020: package test.tck.msgflow;
021:
022: import junit.framework.*;
023:
024: import javax.sip.*;
025: import javax.sip.message.*;
026: import java.util.*;
027: import test.tck.*;
028:
029: /**
030: *
031: * The test tries to verify that Non Invite Client Transactions correctly change
032: * states as specified by the rfc3261. The Tested Implementation is used
033: * to send requests and the ReferenceImplementation issues (or not) corresponding
034: * responses. ClientTransaction states are constantly queried
035: * and compared to those in the state machine described in
036: * section 17.1.2 of rfc3261
037: *<pre>
038: *
039: * | Request from TU
040: * | send request
041: * Timer E V
042: * send request +-----------+
043: * +---------| |-------------------+
044: * | | Trying | Timer F |
045: * +-------->| | or Transport Err.|
046: * +-----------+ inform TU |
047: * 200-699 | | |
048: * resp. to TU | |1xx |
049: * +---------------+ |resp. to TU |
050: * | | |
051: * | Timer E V Timer F |
052: * | send req +-----------+ or Transport Err. |
053: * | +---------| | inform TU |
054: * | | |Proceeding |------------------>|
055: * | +-------->| |-----+ |
056: * | +-----------+ |1xx |
057: * | | ^ |resp to TU |
058: * | 200-699 | +--------+ |
059: * | resp. to TU | |
060: * | | |
061: * | V |
062: * | +-----------+ |
063: * | | | |
064: * | | Completed | |
065: * | | | |
066: * | +-----------+ |
067: * | ^ | |
068: * | | | Timer K |
069: * +--------------+ | - |
070: * | |
071: * V |
072: * NOTE: +-----------+ |
073: * | | |
074: * transitions | Terminated|<------------------+
075: * labeled with | |
076: * the event +-----------+
077: * over the action
078: * to take
079: *
080: * Figure 6: non-INVITE client transaction
081: *
082: * TODO test timeout events
083: *</pre>
084: *
085: * @author Emil Ivov
086: * Network Research Team, Louis Pasteur University, Strasbourg, France.
087: * This code is in the public domain.
088: * @version 1.0
089: */
090:
091: public class NonInviteClientTransactionsStateMachineTest extends
092: MessageFlowHarness {
093:
094: public NonInviteClientTransactionsStateMachineTest(String name) {
095: super (name);
096: }
097:
098: //==================== tests ==============================
099:
100: /**
101: * Tries to walk a TI client transaction through the following scenario
102: * Trying-->Proceeding-->Completed-->Terminated. Apart from state
103: * transitions, we also test, retransmissions and proper hiding/passing
104: * of messages to the TU.
105: */
106: public void testTryingProceedingCompletedTerminatedScenario() {
107: try {
108: Request register = createTiRegisterRequest();
109: ClientTransaction tran = null;
110: try {
111: eventCollector.collectRequestEvent(riSipProvider);
112: tran = tiSipProvider.getNewClientTransaction(register);
113: tran.sendRequest();
114: } catch (SipException ex) {
115: throw new TiUnexpectedError(
116: "A SipExceptionOccurred while trying to send request!",
117: ex);
118: } catch (TooManyListenersException ex) {
119: throw new TckInternalError(
120: "Failed to regiest a SipListener with an RI SipProvider",
121: ex);
122: }
123: waitForMessage();
124: RequestEvent registerReceivedEvent = eventCollector
125: .extractCollectedRequestEvent();
126: if (registerReceivedEvent == null
127: || registerReceivedEvent.getRequest() == null)
128: throw new TiUnexpectedError(
129: "The REGISTER request was not received by the RI!");
130: //At this point the ClientTransaction should be TRYING!
131: assertEquals(TransactionState.TRYING, tran.getState());
132: //Check Request retransmission
133: try {
134: eventCollector.collectRequestEvent(riSipProvider);
135: } catch (TooManyListenersException ex) {
136: throw new TckInternalError(
137: "Failed to regiest a SipListener with an RI SipProvider",
138: ex);
139: }
140: //Wait for the retransmission timer to fire if it had not already done so.
141: if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
142: sleep((long) tran.getRetransmitTimer()
143: - MESSAGES_ARRIVE_FOR);
144: //subtract the time we waited for the REGISTER
145: //Wait for the retransmitted request to arrive
146: waitForMessage();
147: registerReceivedEvent = eventCollector
148: .extractCollectedRequestEvent();
149: assertNotNull(
150: "The REGISTER request was not retransmitted!",
151: registerReceivedEvent);
152: assertNotNull(
153: "The REGISTER request was not retransmitted!",
154: registerReceivedEvent.getRequest());
155: assertEquals(Request.REGISTER, registerReceivedEvent
156: .getRequest().getMethod());
157: //At this point the ClientTransaction should STILL be TRYING!
158: assertEquals(TransactionState.TRYING, tran.getState());
159: //Send a TRYING response
160: try {
161: eventCollector.collectResponseEvent(tiSipProvider);
162: } catch (TooManyListenersException ex) {
163: throw new TiUnexpectedError(
164: "Failed to register a SipListener with TI", ex);
165: }
166: try {
167: Response res = riMessageFactory.createResponse(
168: Response.TRYING, registerReceivedEvent
169: .getRequest());
170: addStatus(registerReceivedEvent.getRequest(), res);
171: riSipProvider.sendResponse(res);
172: } catch (Throwable ex) {
173: throw new TckInternalError(
174: "The TCK could not send a trying response back to the TI",
175: ex);
176: }
177: waitForMessage();
178: //Analyze the TRYING response and Tran state back at the TI
179: ResponseEvent responseEvent = eventCollector
180: .extractCollectedResponseEvent();
181: assertNotNull(
182: "The Tested Implementation did not pass a 1xx response to the TU!",
183: responseEvent);
184: assertNotNull(
185: "The Tested Implementation did not pass a 1xx response to the TU!",
186: responseEvent.getResponse());
187: assertTrue(
188: "A response different from TRYING was passed to the TU!",
189: responseEvent.getResponse().getStatusCode() == Response.TRYING);
190: assertSame(
191: "The TRYING response was not associated with the right transaction",
192: tran, responseEvent.getClientTransaction());
193: //verify the the tran state is now PROCEEDING
194: assertEquals(
195: "The ClientTransaction did not pass in the PROCEEDING state after "
196: + "receiving 1xx provisional response",
197: tran.getState(), TransactionState.PROCEEDING);
198: //Send a 200 OK (final) response from the RI
199: try {
200: eventCollector.collectResponseEvent(tiSipProvider);
201: } catch (TooManyListenersException ex) {
202: throw new TiUnexpectedError(
203: "Failed to register a SipListener with TI", ex);
204: }
205: //The OK response shouldn't trigger any ACKs so let's register
206: //a listener with the RI to verify whether that is the case
207: SipEventCollector ackCollector = new SipEventCollector();
208: try {
209: ackCollector.collectRequestEvent(riSipProvider);
210: } catch (TooManyListenersException ex) {
211: throw new TckInternalError(
212: "Failed to regiest a SipListener with an RI SipProvider",
213: ex);
214: }
215: Response ok = null;
216: try {
217: ok = riMessageFactory.createResponse(Response.OK,
218: registerReceivedEvent.getRequest());
219: addStatus(registerReceivedEvent.getRequest(), ok);
220:
221: riSipProvider.sendResponse((Response) ok.clone());
222: } catch (Throwable ex) {
223: throw new TckInternalError(
224: "The TCK could not send a OK response back to the TI",
225: ex);
226: }
227: waitForMessage();
228: //Analyze the OK response and Tran state back at the TI
229: responseEvent = eventCollector
230: .extractCollectedResponseEvent();
231: assertNotNull(
232: "The Tested Implementation did not pass a 200-699 response to the TU!",
233: responseEvent);
234: assertNotNull(
235: "The Tested Implementation did not pass a 200-699 response to the TU!",
236: responseEvent.getResponse());
237: assertSame(
238: "The OK response was not associated with the right transaction",
239: tran, responseEvent.getClientTransaction());
240: assertSame(
241: "A response different from OK was passed to the TU",
242: tran, responseEvent.getClientTransaction());
243: assertEquals(
244: "The ClientTransaction did not pass in the COMPLETED state after "
245: + "receiving 200-699 final response", tran
246: .getState(), TransactionState.COMPLETED);
247: //check whether the ackCollector has caught any fish
248: RequestEvent ackReceivedEvent = ackCollector
249: .extractCollectedRequestEvent();
250: assertNull(
251: "The TI sent an ACK request in a non INVITE transaction",
252: ackReceivedEvent);
253: //Now let's retransmit the final response. See again that no acks are sent
254: try {
255: eventCollector.collectResponseEvent(tiSipProvider);
256: } catch (TooManyListenersException ex) {
257: throw new TiUnexpectedError(
258: "Failed to register a SipListener with TI", ex);
259: }
260: //go fish the ack
261: try {
262: ackCollector.collectRequestEvent(riSipProvider);
263: } catch (TooManyListenersException ex) {
264: throw new TckInternalError(
265: "Failed to regiest a SipListener with an RI SipProvider",
266: ex);
267: }
268: try {
269: riSipProvider.sendResponse((Response) ok.clone());
270: } catch (Throwable ex) {
271: throw new TckInternalError(
272: "The TCK could not send a OK response back to the TI",
273: ex);
274: }
275: waitForMessage();
276: //The TU shouldn't see the retransmitted OK response
277: responseEvent = eventCollector
278: .extractCollectedResponseEvent();
279: assertNull(
280: "The Tested Implementation passed a retransmitted 200-699 response "
281: + "to the TU.", responseEvent);
282: //We must still be in the completed state.
283: assertTrue(
284: "The ClientTransaction did not stay long enough in the COMPLETED "
285: + "state.", tran.getState().equals(
286: TransactionState.COMPLETED)
287: || tran.getState().equals(
288: TransactionState.TERMINATED));
289: //check whether the ackCollector has caught any fish
290: ackReceivedEvent = ackCollector
291: .extractCollectedRequestEvent();
292: assertNull(
293: "The TI replied with an ACK to a nonINVITE request",
294: ackReceivedEvent);
295: } catch (Throwable exc) {
296: exc.printStackTrace();
297: fail(exc.getClass().getName() + ": " + exc.getMessage());
298: }
299: assertTrue(new Exception().getStackTrace()[0].toString(), true);
300:
301: }
302:
303: /**
304: * Tries to walk a TI client transaction through the following scenario
305: * Trying-->Completed-->Terminated. Apart from state
306: * transitions, we also test, retransmissions and proper hiding/passing
307: * of messages to the TU.
308: */
309: public void testTryingCompletedTerminatedScenario() {
310: try {
311: Request register = createTiRegisterRequest();
312: ClientTransaction tran = null;
313: try {
314: eventCollector.collectRequestEvent(riSipProvider);
315: tran = tiSipProvider.getNewClientTransaction(register);
316: tran.sendRequest();
317: } catch (SipException ex) {
318: throw new TiUnexpectedError(
319: "A SipExceptionOccurred while trying to send request!",
320: ex);
321: } catch (TooManyListenersException ex) {
322: throw new TckInternalError(
323: "Failed to regiest a SipListener with an RI SipProvider",
324: ex);
325: }
326: waitForMessage();
327: RequestEvent registerReceivedEvent = eventCollector
328: .extractCollectedRequestEvent();
329: if (registerReceivedEvent == null
330: || registerReceivedEvent.getRequest() == null)
331: throw new TiUnexpectedError(
332: "The REGISTER request was not received by the RI!");
333: //At this point the ClientTransaction should be TRYING!
334: assertEquals(TransactionState.TRYING, tran.getState());
335: //Check Request retransmission
336: try {
337: eventCollector.collectRequestEvent(riSipProvider);
338: } catch (TooManyListenersException ex) {
339: throw new TckInternalError(
340: "Failed to regiest a SipListener with an RI SipProvider",
341: ex);
342: }
343: //Wait for the retransmission timer to fire if it had not already done so.
344: if (tran.getRetransmitTimer() > MESSAGES_ARRIVE_FOR)
345: sleep((long) tran.getRetransmitTimer()
346: - MESSAGES_ARRIVE_FOR);
347: //subtract the time we waited for the REGISTER
348: //Wait for the retransmitted request to arrive
349: waitForMessage();
350: registerReceivedEvent = eventCollector
351: .extractCollectedRequestEvent();
352: assertNotNull(
353: "The REGISTER request was not retransmitted!",
354: registerReceivedEvent);
355: assertNotNull(
356: "The REGISTER request was not retransmitted!",
357: registerReceivedEvent.getRequest());
358: assertEquals(Request.REGISTER, registerReceivedEvent
359: .getRequest().getMethod());
360: //At this point the ClientTransaction should STILL be TRYING!
361: assertEquals(TransactionState.TRYING, tran.getState());
362: //Send a 200 OK (final) response from the RI
363: try {
364: eventCollector.collectResponseEvent(tiSipProvider);
365: } catch (TooManyListenersException ex) {
366: throw new TiUnexpectedError(
367: "Failed to register a SipListener with TI", ex);
368: }
369: //The OK response shouldn't trigger any ACKs so let's register
370: //a listener with the RI to verify whether that is the case
371: SipEventCollector ackCollector = new SipEventCollector();
372: try {
373: ackCollector.collectRequestEvent(riSipProvider);
374: } catch (TooManyListenersException ex) {
375: throw new TckInternalError(
376: "Failed to regiest a SipListener with an RI SipProvider",
377: ex);
378: }
379: Response ok = null;
380: try {
381: ok = riMessageFactory.createResponse(Response.OK,
382: registerReceivedEvent.getRequest());
383: addStatus(registerReceivedEvent.getRequest(), ok);
384: riSipProvider.sendResponse((Response) ok.clone());
385: } catch (Throwable ex) {
386: throw new TckInternalError(
387: "The TCK could not send a OK response back to the TI",
388: ex);
389: }
390: waitForMessage();
391: //Analyze the OK response and Tran state back at the TI
392: ResponseEvent responseEvent = eventCollector
393: .extractCollectedResponseEvent();
394: assertNotNull(
395: "The Tested Implementation did not pass a 200-699 response to the TU!",
396: responseEvent);
397: assertNotNull(
398: "The Tested Implementation did not pass a 200-699 response to the TU!",
399: responseEvent.getResponse());
400: assertSame(
401: "The OK response was not associated with the right transaction",
402: tran, responseEvent.getClientTransaction());
403: assertSame(
404: "A response different from OK was passed to the TU",
405: tran, responseEvent.getClientTransaction());
406: assertEquals(
407: "The ClientTransaction did not pass in the COMPLETED state after "
408: + "receiving 200-699 final response", tran
409: .getState(), TransactionState.COMPLETED);
410: //check whether the ackCollector has caught any fish
411: RequestEvent ackReceivedEvent = ackCollector
412: .extractCollectedRequestEvent();
413: assertNull(
414: "The TI sent an ACK request in a non INVITE transaction",
415: ackReceivedEvent);
416: //Now let's retransmit the final response. See again that no acks are sent
417: try {
418: eventCollector.collectResponseEvent(tiSipProvider);
419: } catch (TooManyListenersException ex) {
420: throw new TiUnexpectedError(
421: "Failed to register a SipListener with TI", ex);
422: }
423: //go fish the ack
424: try {
425: ackCollector.collectRequestEvent(riSipProvider);
426: } catch (TooManyListenersException ex) {
427: throw new TckInternalError(
428: "Failed to regiest a SipListener with an RI SipProvider",
429: ex);
430: }
431: try {
432: riSipProvider.sendResponse((Response) ok.clone());
433: } catch (Throwable ex) {
434: throw new TckInternalError(
435: "The TCK could not send a OK response back to the TI",
436: ex);
437: }
438: waitForMessage();
439: //The TU shouldn't see the retransmitted OK response
440: responseEvent = eventCollector
441: .extractCollectedResponseEvent();
442: assertNull(
443: "The Tested Implementation passed a retransmitted 200-699 response "
444: + "to the TU.", responseEvent);
445: //We must still be in the completed state.
446: assertTrue(
447: "The ClientTransaction did not stay long enough in the COMPLETED "
448: + "state.", tran.getState().equals(
449: TransactionState.COMPLETED)
450: || tran.getState().equals(
451: TransactionState.TERMINATED));
452: //check whether the ackCollector has caught any fish
453: ackReceivedEvent = ackCollector
454: .extractCollectedRequestEvent();
455: assertNull(
456: "The TI replied with an ACK to a nonINVITE request",
457: ackReceivedEvent);
458: } catch (Throwable exc) {
459: exc.printStackTrace();
460: fail(exc.getClass().getName() + ": " + exc.getMessage());
461: }
462: assertTrue(new Exception().getStackTrace()[0].toString(), true);
463:
464: }
465:
466: //==================== end of tests
467:
468: //====== STATIC JUNIT ==========
469: public static Test suite() {
470: return new TestSuite(
471: NonInviteClientTransactionsStateMachineTest.class);
472: }
473:
474: }
|