Interface Simulator


public interface Simulator
Simulates server behavior of accepting a request and returning a response without touching the network, useful for writing integration tests.

Server-Sent Event simulation is also supported.

Instances of Simulator are made available via Soklet.runSimulator(SokletConfig, Consumer).

Usage example:

@Test
public void basicIntegrationTest () {
  // Just use your app's existing configuration
  SokletConfig config = obtainMySokletConfig();

  // With the Simulator, you can issue requests
  // and receive responses just like you would with real servers.
  Soklet.runSimulator(config, (simulator) -> {
    // Construct a request
    Request request = Request.withPath(HttpMethod.GET, "/hello")
      .queryParameters(Map.of("name", Set.of("Mark")))
      .build();

    // Perform the request and get a handle to the result
    RequestResult result = simulator.performRequest(request);

    // Verify status code
    Integer expectedCode = 200;
    Integer actualCode = result.getMarshaledResponse().getStatusCode();
    assertEquals(expectedCode, actualCode, "Bad status code");

    // Now, create a request for an SSE Event Source...
    Request eventSourceRequest = Request.withPath(HttpMethod.GET, "/sse-test")
        .queryParameters(Map.of("signingToken", Set.of("xxx")))
        .build();

    // ...and perform it and get a handle to the result.
    ServerSentEventRequestResult eventSourceResult =
      simulator.performServerSentEventRequest(eventSourceRequest);

    // Single-shot latch; we'll wait until a Server-Sent Event comes through
    CountDownLatch eventReceivedLatch = new CountDownLatch(1);

    // The Simulator provides 3 logical outcomes for SSE connections:
    // * Accepted Handshake (connection stays open)
    // * Rejected Handshake (explicit rejection, connection closed)
    // * Request Failed (implicit rejection, e.g. uncaught exception, connection closed)
    switch (eventSourceResult) {
      // Explicit handshake acceptance
      case HandshakeAccepted handshakeAccepted -> {
        handshakeAccepted.registerEventConsumer((event) -> {
          // Server-Sent Event received: open the latch to end the test
          eventReceivedLatch.countDown();
        });

        // On a separate thread, broadcast a Server-Sent Event
        new Thread(() -> {
          // ... not shown
        }).start();
      }

      // Explicit handshake rejection
      case HandshakeRejected handshakeRejected ->
        Assertions.fail("SSE Handshake Rejected: " + handshakeRejected);

      // Uncaught exception
      case RequestFailed requestFailed ->
        Assertions.fail("SSE Request Failed: " + requestFailed);
    }

    // Finally, wait a bit for the latch to open
    try {
      eventReceivedLatch.await(5, SECONDS);
    } catch (InterruptedException e) {
      Assertions.fail("Didn't receive a Server-Sent Event in time");
    }
  });
}

Full documentation is available at https://www.soklet.com/docs/testing.

Author:
Mark Allen