@After
  public void after() throws Exception {
    if (bobPhone != null) {
      bobPhone.dispose();
    }
    if (bobSipStack != null) {
      bobSipStack.dispose();
    }

    if (aliceSipStack != null) {
      aliceSipStack.dispose();
    }
    if (alicePhone != null) {
      alicePhone.dispose();
    }
    Thread.sleep(3000);
    wireMockRule.resetRequests();
    Thread.sleep(2000);
  }
 /** Release the sipStack 1 & 2 and a user agent for the test. */
 @After
 public void tearDown() throws Exception {
   ua.dispose();
   awaitStackDispose(sipStack1);
   awaitStackDispose(sipStack2);
 }
  @Test
  public void testBothSides() throws Exception {
    assertTrue(ua.register("amit", "a1b2c3d4", null, 600, 5000));

    SipPhone ub =
        sipStack2.createSipPhone(PROXY_HOST, PROXY_PROTO, PROXY_PORT, "sip:[email protected]");
    assertTrue(ub.register("becky", "a1b2c3d4", null, 600, 5000));

    SipCall callA = ua.createSipCall();
    SipCall callB = ub.createSipCall();

    callB.listenForIncomingCall();
    Thread.sleep(100);

    callA.initiateOutgoingCall("sip:[email protected]", null); // "127.0.0.1:4000/UDP"
    assertLastOperationSuccess("a initiate call - " + callA.format(), callA);

    callB.waitForIncomingCall(3000);
    assertLastOperationSuccess("b wait incoming call - " + callB.format(), callB);

    callB.sendIncomingCallResponse(Response.RINGING, null, -1);
    assertLastOperationSuccess("b send RINGING - " + callB.format(), callB);

    Thread.sleep(1000);

    callB.sendIncomingCallResponse(Response.OK, "Answer - Hello world", 0);
    assertLastOperationSuccess("b send OK - " + callB.format(), callB);

    callA.waitOutgoingCallResponse(10000);
    assertLastOperationSuccess("a wait 1st response - " + callA.format(), callA);
    assertTrue(
        "Unexpected 1st response received",
        (callA.getReturnCode() == Response.RINGING || callA.getReturnCode() == Response.TRYING));
    if (callA.getLastReceivedResponse().getStatusCode() == Response.RINGING) {
      assertNotNull(
          "Default response reason not sent", callA.getLastReceivedResponse().getReasonPhrase());
      assertEquals(
          "Unexpected default reason",
          "Ringing",
          callA.getLastReceivedResponse().getReasonPhrase());
    }

    callA.waitOutgoingCallResponse(5000);
    assertLastOperationSuccess("a wait 2nd response - " + callA.format(), callA);
    callA.waitOutgoingCallResponse(2000);

    assertEquals(
        "Unexpected final response received",
        Response.OK,
        callA.getLastReceivedResponse().getStatusCode());

    callA.sendInviteOkAck();
    assertLastOperationSuccess("Failure sending ACK - " + callA.format(), callA);

    Thread.sleep(1000);

    callA.listenForDisconnect();
    assertLastOperationSuccess("a listen disc - " + callA.format(), callA);

    callB.disconnect();
    assertLastOperationSuccess("b disc - " + callB.format(), callB);

    callA.waitForDisconnect(5000);
    assertLastOperationSuccess("a wait disc - " + callA.format(), callA);

    callA.respondToDisconnect();
    assertLastOperationSuccess("a respond to disc - " + callA.format(), callA);

    Thread.sleep(1000);
    ub.dispose();
  }