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 javax.sip.header.*;
027: import java.util.*;
028: import test.tck.*;
029:
030: /**
031: * <p>Title: TCK</p>
032: * <p>Description: JAIN SIP 1.2 Technology Compatibility Kit</p>
033: * @author Emil Ivov
034: * Network Research Team, Louis Pasteur University, Strasbourg, France.
035: * This code is in the public domain.
036: * @version 1.0
037: */
038:
039: public class DialogTest extends MessageFlowHarness {
040: /** The Dialog to test.*/
041: private Dialog dialog = null;
042: /** The request that was sent by the TI*/
043: private Request tiInvite = null;
044: /** The initial invite request at the RI side.*/
045: private Request riInvite = null;
046: private ClientTransaction cliTran = null;
047: private Response ringing = null;
048:
049: private String riToTag; // JvB: to-tag set by RI
050:
051: public DialogTest(String name) {
052: super (name);
053: }
054:
055: //==================== add a dialog to the fixture ========
056: /**
057: * Calls MessageFlowHarness.setUp() and creates a dialog afterwards.
058: * @throws Exception if anything goes wrong
059: */
060: public void setUp() throws Exception {
061: try {
062: super .setUp();
063: tiInvite = createTiInviteRequest(null, null, null);
064: //Send an invite request
065: try {
066: eventCollector.collectRequestEvent(riSipProvider);
067: cliTran = tiSipProvider
068: .getNewClientTransaction(tiInvite);
069: cliTran.sendRequest();
070: } catch (TooManyListenersException e) {
071: throw new TckInternalError(
072: "Failed to register a listener with the RI", e);
073: } catch (SipException e) {
074: throw new TiUnexpectedError(
075: "Failed to send initial invite request", e);
076: }
077: //Wait for the invite to arrive
078: waitForMessage();
079: RequestEvent inviteReqEvt = eventCollector
080: .extractCollectedRequestEvent();
081: if (inviteReqEvt == null
082: || inviteReqEvt.getRequest() == null)
083: throw new TiUnexpectedError(
084: "The TI did not send the initial invite request");
085: riInvite = inviteReqEvt.getRequest();
086: //get the dialog
087: dialog = cliTran.getDialog();
088: //Send ringing to initialise dialog
089: //start listening for the response
090: try {
091: eventCollector.collectResponseEvent(tiSipProvider);
092: } catch (TooManyListenersException e) {
093: throw new TiUnexpectedError(
094: "Failed to register a SipListener with the TI.",
095: e);
096: }
097: try {
098: ringing = riMessageFactory.createResponse(
099: Response.RINGING, inviteReqEvt.getRequest());
100: ((ToHeader) ringing.getHeader(ToHeader.NAME))
101: .setTag(riToTag = Integer.toString(hashCode()));
102: // BUG report from Ben Evans:
103: // set contact header on dialog-creating response
104: ringing.setHeader(createRiContact());
105: riSipProvider.sendResponse(ringing);
106: } catch (Exception e) {
107: throw new TckInternalError(
108: "Failed to create and send a RINGING response",
109: e);
110: }
111: waitForMessage();
112: ResponseEvent ringingRespEvt = eventCollector
113: .extractCollectedResponseEvent();
114: if (ringingRespEvt == null
115: || ringingRespEvt.getResponse() == null)
116: throw new TiUnexpectedError(
117: "The TI did not dispatch a RINGING response.");
118: } catch (Throwable exc) {
119: exc.printStackTrace();
120: fail(exc.getClass().getName() + ": " + exc.getMessage());
121: }
122:
123: assertTrue(new Exception().getStackTrace()[0].toString(), true);
124:
125: }
126:
127: //==================== tests ==============================
128: /**
129: * Test whether dialog fields are properly set
130: */
131: public void testDialogProperties() {
132: try {
133: //CallId
134: assertEquals("The Dialog did not have the right Call ID.",
135: ((CallIdHeader) riInvite
136: .getHeader(CallIdHeader.NAME)).getCallId(),
137: dialog.getCallId().getCallId());
138: //Tran
139: /* Deprecated
140: * assertSame(
141: "The Dialog.getTransaction did not return the right transaction.",
142: cliTran,
143: dialog.getFirstTransaction());
144: */
145: //LocalParty
146: assertEquals(
147: "Dialog.getLocalParty() returned a bad address.",
148: ((FromHeader) tiInvite.getHeader(FromHeader.NAME))
149: .getAddress(), dialog.getLocalParty());
150: //SeqNum
151: assertTrue(
152: "Dialog.getLocalSequenceNumber() returned a bad value.",
153: 1 == dialog.getLocalSeqNumber());
154: //LocalTag
155: assertEquals("Dialog.getLocalTag() returned a bad tag",
156: ((FromHeader) riInvite.getHeader(FromHeader.NAME))
157: .getTag(), dialog.getLocalTag());
158: //RemoteParty
159: assertEquals(
160: "Dialog.getRemoteParty() returned a bad address.",
161: ((ToHeader) tiInvite.getHeader(ToHeader.NAME))
162: .getAddress(), dialog.getRemoteParty());
163: //RemoteTag
164: assertEquals("Dialog.getRemoteTag() returned a bad tag",
165: ((ToHeader) ringing.getHeader(ToHeader.NAME))
166: .getTag(), dialog.getRemoteTag());
167: //is server
168: assertFalse(
169: "Dialog.isServer returned true for a client side dialog",
170: dialog.isServer());
171: } catch (Throwable exc) {
172: exc.printStackTrace();
173: fail(exc.getClass().getName() + ": " + exc.getMessage());
174: }
175:
176: assertTrue(new Exception().getStackTrace()[0].toString(), true);
177:
178: }
179:
180: /**
181: * Create a BYE request and check whether major fields are properly set
182: */
183: public void testCreateRequest() {
184: try {
185: Request bye = null;
186: try {
187: bye = dialog.createRequest(Request.BYE);
188: } catch (SipException ex) {
189: ex.printStackTrace();
190: fail("A dialog failed to create a BYE request.");
191: }
192: //check method
193: assertEquals(
194: "Dialog.createRequest() returned a request with a bad method.",
195: Request.BYE, bye.getMethod());
196: //check CSeq number
197: assertEquals(
198: "Dialog.createRequest() returned a request with a bad sequence number.",
199: dialog.getLocalSeqNumber() + 1, ((CSeqHeader) bye
200: .getHeader(CSeqHeader.NAME)).getSeqNumber());
201: //Check From
202: FromHeader byeFrom = (FromHeader) bye
203: .getHeader(FromHeader.NAME);
204: assertEquals(
205: "Dialog.createRequest() returned a request with a bad From header.",
206: dialog.getLocalParty(), byeFrom.getAddress());
207: //Check From tags
208: assertEquals(
209: "Dialog.createRequest() returned a request with a bad From tag.",
210: dialog.getLocalTag(), byeFrom.getTag());
211: //Check To
212: ToHeader byeTo = (ToHeader) bye.getHeader(ToHeader.NAME);
213: assertEquals(
214: "Dialog.createRequest() returned a request with a bad To header.",
215: dialog.getRemoteParty(), byeTo.getAddress());
216: //Check To tags
217: assertEquals(
218: "Dialog.createRequest() returned a request with a bad To tag.",
219: dialog.getRemoteTag(), byeTo.getTag());
220: ClientTransaction ct = super .tiSipProvider
221: .getNewClientTransaction(bye);
222: dialog.sendRequest(ct);
223: assertEquals("Dialog mismatch ", ct.getDialog(), dialog);
224: waitForMessage();
225:
226: try {
227: eventCollector
228: .collectDialogTermiatedEvent(tiSipProvider);
229: } catch (TooManyListenersException ex) {
230: throw new TckInternalError(
231: "failed to regiser a listener iwth the TI", ex);
232: }
233: waitForTimeout();
234: DialogTerminatedEvent dte = eventCollector
235: .extractCollectedDialogTerminatedEvent();
236: // Should not see a DTE here because the Dialog is not established.
237: assertNull("DTE is not null", dte);
238:
239: } catch (Throwable exc) {
240: exc.printStackTrace();
241: fail(exc.getClass().getName() + ": " + exc.getMessage());
242: }
243: assertTrue(new Exception().getStackTrace()[0].toString(), true);
244:
245: }
246:
247: /**
248: * Steer the dialog to a CONFIRMED state and try sending an ack
249: * An invite has been sent by the TI in the setUp method so we take it from
250: * that point on.
251: */
252: public void testSendAck() {
253: this .doTestSendAck(false);
254: }
255:
256: /**
257: * Regression test for broken clients that send ACK to 2xx with same branch as INVITE
258: */
259: public void testSendAckWithSameBranch() {
260: this .doTestSendAck(true);
261: }
262:
263: private void doTestSendAck(boolean sameBranch) {
264: try {
265: //We will now send an OK response
266: //start listening for the response
267: try {
268: eventCollector.collectResponseEvent(tiSipProvider);
269: } catch (TooManyListenersException e) {
270: throw new TckInternalError(
271: "Failed to register a SipListener with the RI.",
272: e);
273: }
274: Response ok = null;
275: try {
276: ok = riMessageFactory.createResponse(Response.OK,
277: riInvite);
278: ok.addHeader(createRiInviteRequest(null, null, null)
279: .getHeader(ContactHeader.NAME));
280: ToHeader okToHeader = (ToHeader) ok
281: .getHeader(ToHeader.NAME);
282: okToHeader.setTag(riToTag); // needs same tag as 180 ringing!
283: // riSipProvider.sendResponse(ok);
284:
285: // Need to explicitly create the dialog on RI side
286: ServerTransaction riST = riSipProvider
287: .getNewServerTransaction(riInvite);
288: riST.getDialog();
289: riST.sendResponse(ok);
290: } catch (Exception e) {
291: throw new TckInternalError(
292: "Failed to create and send an OK response", e);
293: }
294: waitForMessage();
295: ResponseEvent okRespEvt = eventCollector
296: .extractCollectedResponseEvent();
297: if (okRespEvt == null || okRespEvt.getResponse() == null)
298: throw new TiUnexpectedError(
299: "The TI did not dispatch an OK response.");
300:
301: // After 2xx, dialog should be in CONFIRMED state. Needed to send ACK
302: assertEquals(DialogState.CONFIRMED, dialog.getState());
303:
304: //Send the ack
305: //Setup the ack listener
306: try {
307: eventCollector.collectRequestEvent(riSipProvider);
308: } catch (TooManyListenersException ex) {
309: throw new TckInternalError(
310: "Failed to register a SipListener with the RI",
311: ex);
312: }
313: Request ack = null;
314: try {
315: CSeqHeader cseq = (CSeqHeader) okRespEvt.getResponse()
316: .getHeader(CSeqHeader.NAME);
317: ack = dialog.createAck(cseq.getSeqNumber());
318: //System.out.println( "Created ACK:" + ack );
319: //System.out.println( "original INVITE:" + riInvite );
320:
321: // This is wrong according to RFC3261, but some clients do this...
322: if (sameBranch) {
323: ViaHeader via = (ViaHeader) ack.getHeader("Via");
324: via.setBranch(((ViaHeader) riInvite
325: .getHeader("Via")).getBranch());
326: }
327:
328: } catch (SipException ex) {
329: throw new TiUnexpectedError(
330: "Failed to create an ACK request.", ex);
331: }
332: try {
333: dialog.sendAck(ack);
334: } catch (Throwable ex) {
335: ex.printStackTrace();
336: fail("SipException; Failed to send an ACK request using Dialog.sendAck()");
337: }
338: waitForMessage();
339:
340: // Did the RI get the ACK? If the dialog is not found, the ACK is filtered!
341: RequestEvent ackEvt = eventCollector
342: .extractCollectedRequestEvent();
343: assertNotNull(
344: "No requestEvent sent by Dialog.sendAck() was received by the RI",
345: ackEvt);
346: assertNotNull(
347: "The request sent by Dialog.sendAck() was not received by the RI",
348: ackEvt.getRequest());
349: } catch (Throwable exc) {
350: exc.printStackTrace();
351: fail(exc.getClass().getName() + ": " + exc.getMessage());
352: }
353: assertTrue(new Exception().getStackTrace()[0].toString(), true);
354:
355: }
356:
357: public void testSendRequest() {
358: try {
359: Request reInvite = null;
360: ClientTransaction reInviteTran = null;
361: //Create
362: try {
363: reInvite = dialog.createRequest(Request.INVITE);
364: reInviteTran = tiSipProvider
365: .getNewClientTransaction(reInvite);
366: } catch (Exception ex) {
367: throw new TiUnexpectedError(
368: "Failed to create a CANCEL request with Dialog.createRequest()",
369: ex);
370: }
371: //Listen
372: try {
373: eventCollector.collectRequestEvent(riSipProvider);
374: } catch (TooManyListenersException ex) {
375: throw new TckInternalError(
376: "Failed to register a SipListener with the RI",
377: ex);
378: }
379: //Send
380: try {
381: dialog.sendRequest(reInviteTran);
382: } catch (SipException ex) {
383: ex.printStackTrace();
384: fail("Failed to send a cancel request using Dialog.sendRequest()");
385: }
386: waitForMessage();
387: //Did they get it?
388: RequestEvent cancelEvt = eventCollector
389: .extractCollectedRequestEvent();
390: assertNotNull("The RI did not receive the sent request",
391: cancelEvt);
392: assertNotNull("The RI did not receive the sent request",
393: cancelEvt.getRequest());
394: } catch (Throwable exc) {
395: exc.printStackTrace();
396: fail(exc.getClass().getName() + ": " + exc.getMessage());
397: }
398: assertTrue(new Exception().getStackTrace()[0].toString(), true);
399:
400: }
401:
402: //==================== end of tests
403:
404: //====== STATIC JUNIT ==========
405: public static Test suite() {
406: return new TestSuite(DialogTest.class);
407: }
408:
409: }
|