test.tck.msgflow.DialogTest 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 javax.sip.header.*;
import java.util.*;
import test.tck.*;
/**
* Title: TCK
* Description: JAIN SIP 1.2 Technology Compatibility Kit
* @author Emil Ivov
* Network Research Team, Louis Pasteur University, Strasbourg, France.
* This code is in the public domain.
* @version 1.0
*/
public class DialogTest extends MessageFlowHarness {
/** The Dialog to test.*/
private Dialog dialog = null;
/** The request that was sent by the TI*/
private Request tiInvite = null;
/** The initial invite request at the RI side.*/
private Request riInvite = null;
private ClientTransaction cliTran = null;
private Response ringing = null;
private String riToTag; // JvB: to-tag set by RI
public DialogTest(String name) {
super(name);
}
//==================== add a dialog to the fixture ========
/**
* Calls MessageFlowHarness.setUp() and creates a dialog afterwards.
* @throws Exception if anything goes wrong
*/
public void setUp() throws Exception {
try {
super.setUp();
tiInvite = createTiInviteRequest(null, null, null);
//Send an invite request
try {
eventCollector.collectRequestEvent(riSipProvider);
cliTran = tiSipProvider.getNewClientTransaction(tiInvite);
cliTran.sendRequest();
} catch (TooManyListenersException e) {
throw new TckInternalError(
"Failed to register a listener with the RI",
e);
} catch (SipException e) {
throw new TiUnexpectedError(
"Failed to send initial invite request",
e);
}
//Wait for the invite to arrive
waitForMessage();
RequestEvent inviteReqEvt =
eventCollector.extractCollectedRequestEvent();
if (inviteReqEvt == null || inviteReqEvt.getRequest() == null)
throw new TiUnexpectedError("The TI did not send the initial invite request");
riInvite = inviteReqEvt.getRequest();
//get the dialog
dialog = cliTran.getDialog();
//Send ringing to initialise dialog
//start listening for the response
try {
eventCollector.collectResponseEvent(tiSipProvider);
} catch (TooManyListenersException e) {
throw new TiUnexpectedError(
"Failed to register a SipListener with the TI.",
e);
}
try {
ringing =
riMessageFactory.createResponse(
Response.RINGING,
inviteReqEvt.getRequest());
((ToHeader) ringing.getHeader(ToHeader.NAME)).setTag(
riToTag = Integer.toString(hashCode()));
// BUG report from Ben Evans:
// set contact header on dialog-creating response
ringing.setHeader(createRiContact());
riSipProvider.sendResponse(ringing);
} catch (Exception e) {
throw new TckInternalError(
"Failed to create and send a RINGING response",
e);
}
waitForMessage();
ResponseEvent ringingRespEvt =
eventCollector.extractCollectedResponseEvent();
if (ringingRespEvt == null || ringingRespEvt.getResponse() == null)
throw new TiUnexpectedError("The TI did not dispatch a RINGING response.");
} catch (Throwable exc) {
exc.printStackTrace();
fail(exc.getClass().getName() + ": " + exc.getMessage());
}
assertTrue(new Exception().getStackTrace()[0].toString(), true);
}
//==================== tests ==============================
/**
* Test whether dialog fields are properly set
*/
public void testDialogProperties() {
try {
//CallId
assertEquals(
"The Dialog did not have the right Call ID.",
((CallIdHeader) riInvite.getHeader(CallIdHeader.NAME))
.getCallId(),
dialog.getCallId().getCallId());
//Tran
/* Deprecated
* assertSame(
"The Dialog.getTransaction did not return the right transaction.",
cliTran,
dialog.getFirstTransaction());
*/
//LocalParty
assertEquals(
"Dialog.getLocalParty() returned a bad address.",
((FromHeader) tiInvite.getHeader(FromHeader.NAME)).getAddress(),
dialog.getLocalParty());
//SeqNum
assertTrue(
"Dialog.getLocalSequenceNumber() returned a bad value.",
1 == dialog.getLocalSeqNumber());
//LocalTag
assertEquals(
"Dialog.getLocalTag() returned a bad tag",
((FromHeader) riInvite.getHeader(FromHeader.NAME)).getTag(),
dialog.getLocalTag());
//RemoteParty
assertEquals(
"Dialog.getRemoteParty() returned a bad address.",
((ToHeader) tiInvite.getHeader(ToHeader.NAME)).getAddress(),
dialog.getRemoteParty());
//RemoteTag
assertEquals(
"Dialog.getRemoteTag() returned a bad tag",
((ToHeader) ringing.getHeader(ToHeader.NAME)).getTag(),
dialog.getRemoteTag());
//is server
assertFalse(
"Dialog.isServer returned true for a client side dialog",
dialog.isServer());
} catch (Throwable exc) {
exc.printStackTrace();
fail(exc.getClass().getName() + ": " + exc.getMessage());
}
assertTrue(new Exception().getStackTrace()[0].toString(), true);
}
/**
* Create a BYE request and check whether major fields are properly set
*/
public void testCreateRequest() {
try {
// JvB: First abort the INVITE, this should trigger a TransactionTerminatedEvent
cliTran.terminate();
Request bye = null;
try {
bye = dialog.createRequest(Request.BYE);
} catch (SipException ex) {
ex.printStackTrace();
fail("A dialog failed to create a BYE request.");
}
//check method
assertEquals(
"Dialog.createRequest() returned a request with a bad method.",
Request.BYE,
bye.getMethod());
//check CSeq number
assertEquals(
"Dialog.createRequest() returned a request with a bad sequence number.",
dialog.getLocalSeqNumber() + 1,
((CSeqHeader) bye.getHeader(CSeqHeader.NAME))
.getSeqNumber());
//Check From
FromHeader byeFrom = (FromHeader) bye.getHeader(FromHeader.NAME);
assertEquals(
"Dialog.createRequest() returned a request with a bad From header.",
dialog.getLocalParty(),
byeFrom.getAddress());
//Check From tags
assertEquals(
"Dialog.createRequest() returned a request with a bad From tag.",
dialog.getLocalTag(),
byeFrom.getTag());
//Check To
ToHeader byeTo = (ToHeader) bye.getHeader(ToHeader.NAME);
assertEquals(
"Dialog.createRequest() returned a request with a bad To header.",
dialog.getRemoteParty(),
byeTo.getAddress());
//Check To tags
assertEquals(
"Dialog.createRequest() returned a request with a bad To tag.",
dialog.getRemoteTag(),
byeTo.getTag());
ClientTransaction ct = super.tiSipProvider.getNewClientTransaction(bye);
// JvB: set the SipListener before sending the BYE
try {
eventCollector.collectDialogTermiatedEvent(tiSipProvider);
} catch( TooManyListenersException ex) {
throw new TckInternalError("failed to regiser a listener iwth the TI", ex);
}
dialog.sendRequest(ct);
assertEquals("Dialog mismatch ", ct.getDialog(),dialog );
waitForMessage();
waitForTimeout();
DialogTerminatedEvent dte = eventCollector.extractCollectedDialogTerminatedEvent();
// Should see a DTE here also for early Dialog
assertNotNull("No DTE received for early Dialog terminated via BYE", dte);
} catch (Throwable exc) {
exc.printStackTrace();
fail(exc.getClass().getName() + ": " + exc.getMessage());
}
assertTrue(new Exception().getStackTrace()[0].toString(), true);
}
/**
* Steer the dialog to a CONFIRMED state and try sending an ack
* An invite has been sent by the TI in the setUp method so we take it from
* that point on.
*/
public void testSendAck() {
this.doTestSendAck(false);
}
/**
* Regression test for broken clients that send ACK to 2xx with same branch as INVITE
public void testSendAckWithSameBranch() {
this.doTestSendAck(true);
}
*/
private void doTestSendAck( boolean sameBranch ) {
System.out.println("doTestSendAck " + sameBranch);
try {
//We will now send an OK response
//start listening for the response
try {
eventCollector.collectResponseEvent(tiSipProvider);
} catch (TooManyListenersException e) {
throw new TckInternalError(
"Failed to register a SipListener with the RI.",
e);
}
Response ok = null;
try {
ok = riMessageFactory.createResponse(Response.OK, riInvite);
ok.addHeader(
createRiInviteRequest(null, null, null).getHeader(
ContactHeader.NAME));
ToHeader okToHeader = (ToHeader)ok.getHeader(ToHeader.NAME);
okToHeader.setTag( riToTag );// needs same tag as 180 ringing!
// riSipProvider.sendResponse(ok);
// Need to explicitly create the dialog on RI side
ServerTransaction riST = riSipProvider.getNewServerTransaction( riInvite );
riST.getDialog();
riST.sendResponse( ok );
} catch (Exception e) {
throw new TckInternalError(
"Failed to create and send an OK response",
e);
}
waitForMessage();
ResponseEvent okRespEvt =
eventCollector.extractCollectedResponseEvent();
if (okRespEvt == null || okRespEvt.getResponse() == null)
throw new TiUnexpectedError("The TI did not dispatch an OK response.");
String okBranch =
((ViaHeader) okRespEvt.getResponse().getHeader(ViaHeader.NAME)).getBranch();
// After 2xx, dialog should be in CONFIRMED state. Needed to send ACK
assertEquals( DialogState.CONFIRMED, dialog.getState() );
//Send the ack
//Setup the ack listener
try {
eventCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to register a SipListener with the RI",
ex);
}
Request ack = null;
try {
CSeqHeader cseq = (CSeqHeader) okRespEvt.getResponse().getHeader(CSeqHeader.NAME);
ack = dialog.createAck(cseq.getSeqNumber());
//System.out.println( "Created ACK:" + ack );
//System.out.println( "original INVITE:" + riInvite );
// This is wrong according to RFC3261, but some clients do this...
if (sameBranch) {
ViaHeader via = (ViaHeader) ack.getHeader("Via");
via.setBranch( ((ViaHeader)riInvite.getHeader("Via")).getBranch() );
}
} catch (SipException ex) {
throw new TiUnexpectedError(
"Failed to create an ACK request.",
ex);
}
try {
dialog.sendAck(ack);
} catch (Throwable ex) {
ex.printStackTrace();
fail("SipException; Failed to send an ACK request using Dialog.sendAck()");
}
waitForMessage();
// Did the RI get the ACK? If the dialog is not found, the ACK is filtered!
RequestEvent ackEvt = eventCollector.extractCollectedRequestEvent();
assertNotNull(
"No requestEvent sent by Dialog.sendAck() was received by the RI",
ackEvt);
assertNotNull(
"The request sent by Dialog.sendAck() was not received by the RI",
ackEvt.getRequest());
if ( !sameBranch ) {
String ackBranchId = ((ViaHeader) ackEvt.getRequest().getHeader(ViaHeader.NAME)).getBranch();
super.assertNotSame("ACK branch ID must differ from INVITE OK branch ID", ackBranchId,
okBranch);
}
} catch (Throwable exc) {
exc.printStackTrace();
fail(exc.getClass().getName() + ": " + exc.getMessage());
}
assertTrue(new Exception().getStackTrace()[0].toString(), true);
}
public void testSendRequest() {
try {
Request reInvite = null;
ClientTransaction reInviteTran = null;
//Create
try {
reInvite = dialog.createRequest(Request.INVITE);
reInviteTran = tiSipProvider.getNewClientTransaction(reInvite);
} catch (Exception ex) {
throw new TiUnexpectedError(
"Failed to create a CANCEL request with Dialog.createRequest()",
ex);
}
//Listen
try {
eventCollector.collectRequestEvent(riSipProvider);
} catch (TooManyListenersException ex) {
throw new TckInternalError(
"Failed to register a SipListener with the RI",
ex);
}
//Send
try {
dialog.sendRequest(reInviteTran);
} catch (SipException ex) {
ex.printStackTrace();
fail("Failed to send a cancel request using Dialog.sendRequest()");
}
waitForMessage();
//Did they get it?
RequestEvent cancelEvt =
eventCollector.extractCollectedRequestEvent();
assertNotNull("The RI did not receive the sent request", cancelEvt);
assertNotNull(
"The RI did not receive the sent request",
cancelEvt.getRequest());
} 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(DialogTest.class);
}
}