/**
   * Creates an invite request using the Tested Implementation and then tests creating a cancel for
   * the same invite request.
   */
  public void testCreateCancel() {
    try {
      Request invite = createTiInviteRequest(null, null, null);
      ClientTransaction tran = null;
      try {
        tran = tiSipProvider.getNewClientTransaction(invite);
      } catch (TransactionUnavailableException exc) {
        throw new TiUnexpectedError(
            "A TransactionUnavailableException was thrown while trying to "
                + "create a new client transaction",
            exc);
      }
      Request cancel = null;
      try {
        cancel = tran.createCancel();
      } catch (SipException ex) {
        ex.printStackTrace();
        fail("Failed to create cancel request!");
      }
      assertEquals(
          "The created request did not have a CANCEL method.", cancel.getMethod(), Request.CANCEL);
      assertEquals(
          "Request-URIs of the original and the cancel request do not match",
          cancel.getRequestURI(),
          invite.getRequestURI());
      assertEquals(
          "Call-IDs of the original and the cancel request do not match",
          cancel.getHeader(CallIdHeader.NAME),
          invite.getHeader(CallIdHeader.NAME));
      assertEquals(
          "ToHeaders of the original and the cancel request do not match",
          cancel.getHeader(ToHeader.NAME),
          invite.getHeader(ToHeader.NAME));
      assertTrue(
          "The CSeqHeader's sequence number of the original and "
              + "the cancel request do not match",
          ((CSeqHeader) cancel.getHeader(CSeqHeader.NAME)).getSequenceNumber()
              == ((CSeqHeader) invite.getHeader(CSeqHeader.NAME)).getSequenceNumber());
      assertEquals(
          "The CSeqHeader's method of the cancel request was not CANCEL",
          ((CSeqHeader) cancel.getHeader(CSeqHeader.NAME)).getMethod(),
          Request.CANCEL);
      assertTrue(
          "There was no ViaHeader in the cancel request",
          cancel.getHeaders(ViaHeader.NAME).hasNext());
      Iterator cancelVias = cancel.getHeaders(ViaHeader.NAME);
      ViaHeader cancelVia = ((ViaHeader) cancelVias.next());
      ViaHeader inviteVia = ((ViaHeader) invite.getHeaders(ViaHeader.NAME).next());
      assertEquals(
          "ViaHeaders of the original and the cancel request do not match!", cancelVia, inviteVia);
      assertFalse("Cancel request had more than one ViaHeader.", cancelVias.hasNext());
    } catch (Throwable exc) {
      exc.printStackTrace();
      fail(exc.getClass().getName() + ": " + exc.getMessage());
    }

    assertTrue(new Exception().getStackTrace()[0].toString(), true);
  }
  /**
   * JvB: Tests transmission of an INVITE followed by CANCELlation of that request -> INVITE <- 100
   * -> CANCEL <- OK <- 487 -> ACK
   *
   * <p>Note: for 1.2 it is impossible to manually set the top via branch to something not
   * RFC3261-compliant
   */
  private void doCancelTest(boolean rfc3261Compliant) {
    try {
      Request invite = createTiInviteRequest(null, null, null);
      ClientTransaction tran = null;
      try {
        eventCollector.collectRequestEvent(riSipProvider);

        // This call overwrites any branch we set
        tran = tiSipProvider.getNewClientTransaction(invite);

        // And this call too
        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 inviteReceivedEvent = eventCollector.extractCollectedRequestEvent();

      if (inviteReceivedEvent == null || inviteReceivedEvent.getRequest() == null)
        throw new TiUnexpectedError("The invite request was not received by the RI!");

      // At this point the ClientTransaction should be CALLING!
      assertEquals(TransactionState.CALLING, 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 resp =
            riMessageFactory.createResponse(Response.TRYING, inviteReceivedEvent.getRequest());
        addStatus(inviteReceivedEvent.getRequest(), resp);
        riSipProvider.sendResponse(resp);
      } 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 TYING 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 CANCEL from the TI
      Request tiCancel = tran.createCancel();

      /*
       * this works, but since we cannot patch the INVITE the test fails
       * if (!rfc3261Compliant) { ((ViaHeader)
       * tiCancel.getHeader("Via")).setBranch( "xxx" ); // Not allowed by
       * RI // ((FromHeader) tiCancel.getHeader("From")).setTag( "" ); }
       */

      ClientTransaction tiCancelTrans;
      try {
        eventCollector.collectRequestEvent(riSipProvider);
        tiCancelTrans = tiSipProvider.getNewClientTransaction(tiCancel);
        tiCancelTrans.sendRequest();
      } catch (SipException ex) {
        throw new TiUnexpectedError("A SipExceptionOccurred while trying to send CANCEL!", ex);
      }
      waitForMessage();
      RequestEvent cancelReceivedEvent = eventCollector.extractCollectedRequestEvent();
      if (cancelReceivedEvent == null || cancelReceivedEvent.getRequest() == null)
        throw new TiUnexpectedError("The CANCEL request was not received by the RI!");

      // Send 200 OK to the CANCEL
      try {
        eventCollector.collectResponseEvent(tiSipProvider);
      } catch (TooManyListenersException ex) {
        throw new TiUnexpectedError("Failed to register a SipListener with TI", ex);
      }
      Response riCancelOk = null;
      try {
        riCancelOk = riMessageFactory.createResponse(Response.OK, cancelReceivedEvent.getRequest());
        addStatus(cancelReceivedEvent.getRequest(), riCancelOk);
        riSipProvider.sendResponse(riCancelOk);
      } catch (Throwable ex) {
        throw new TckInternalError(
            "The TCK could not send a CANCEL OK response back to the TI", ex);
      }
      waitForMessage();

      // Analyze the OK response and Tran state back at the TI
      responseEvent = eventCollector.extractCollectedResponseEvent();
      if (responseEvent == null || responseEvent.getResponse() == null) {
        throw new TiUnexpectedError("The CANCEL OK response was not received by the TI!");
      }

      // Send 487 to the INVITE, expect ACK
      try {
        eventCollector.collectResponseEvent(tiSipProvider);
      } catch (TooManyListenersException ex) {
        throw new TiUnexpectedError("Failed to register a SipListener with TI", ex);
      }
      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 riInviteTerminated = null;
      try {
        riInviteTerminated =
            riMessageFactory.createResponse(
                Response.REQUEST_TERMINATED, inviteReceivedEvent.getRequest());
        addStatus(inviteReceivedEvent.getRequest(), riInviteTerminated);
        riSipProvider.sendResponse(riInviteTerminated);
      } catch (Throwable ex) {
        throw new TckInternalError(
            "The TCK could not send a INVITE 487 response back to the TI", ex);
      }
      waitForMessage();

      // Analyze the REQUEST_TERMINATED response and Tran state back at
      // the TI
      responseEvent = eventCollector.extractCollectedResponseEvent();
      assertNotNull(
          "The Tested Implementation did not pass a 300-699 response to the TU!", responseEvent);
      assertNotNull(
          "The Tested Implementation did not pass a 300-699 response to the TU!",
          responseEvent.getResponse());
      assertSame(
          "The 487 response was not associated with the right transaction",
          tran,
          responseEvent.getClientTransaction());
      assertEquals(
          "A response different from 487 was passed to the TU",
          Response.REQUEST_TERMINATED,
          responseEvent.getResponse().getStatusCode());
      assertEquals(
          "The ClientTransaction did not pass in the COMPLETED state after "
              + "receiving 300-699 final response",
          tran.getState(),
          TransactionState.COMPLETED);
      // check whether the ackCollector has caught any fish
      RequestEvent ackReceivedEvent = ackCollector.extractCollectedRequestEvent();
      assertNotNull("The TI did not send an ACK request event", ackReceivedEvent);
      assertNotNull("The TI did not send an ACK request", ackReceivedEvent.getRequest());
      assertEquals(Request.ACK, ackReceivedEvent.getRequest().getMethod());

      // Try to kill remaining ACK retransmissions?
    } catch (Throwable exc) {
      exc.printStackTrace();
      fail(exc.getClass().getName() + ": " + exc.getMessage());
    }
    assertTrue(new Exception().getStackTrace()[0].toString(), true);

    // Unfortunately we can't assert the TERMINATED state as timerK timerD
    // is not exported by JAIN SIP
  }