001/*
002 * Copyright 2022-2025 Revetware LLC.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.soklet.core;
018
019import com.soklet.SokletConfiguration;
020
021import javax.annotation.Nonnull;
022import java.util.function.Consumer;
023
024/**
025 * Simulates server behavior of accepting a request and returning a response, useful for writing integration tests.
026 * <p>
027 * <a href="https://www.soklet.com/docs/server-sent-events">Server-Sent Event</a> simulation is also supported.
028 * <p>
029 * Instances of {@link Simulator} are made available via {@link com.soklet.Soklet#runSimulator(SokletConfiguration, Consumer)}.
030 * <p>
031 * Usage example:
032 * <pre>{@code  @Test
033 * public void basicIntegrationTest() {
034 *   // Build your configuration however you like
035 *   SokletConfiguration config = obtainMySokletConfig();
036 *
037 *   // Instead of running on a real HTTP server that listens on a port,
038 *   // a simulator is provided against which you can issue requests
039 *   // and receive responses.
040 *   Soklet.runSimulator(config, (simulator -> {
041 *     // Construct a request.
042 *     // You may alternatively specify query parameters directly in the URI
043 *     // as a query string, e.g. "/hello?name=Mark"
044 *     Request request = Request.with(HttpMethod.GET, "/hello")
045 *       .queryParameters(Map.of("name", Set.of("Mark")))
046 *       .build();
047 *
048 *     // Perform the request and get a handle to the result
049 *     RequestResult result = simulator.performRequest(request);
050 *
051 *     // Verify status code
052 *     Integer expectedCode = 200;
053 *     Integer actualCode = result.getMarshaledResponse().getStatusCode();
054 *     Assert.assertEquals("Bad status code", expectedCode, actualCode);
055 *   }));
056 * }}</pre>
057 * <p>
058 * Full documentation is available at <a href="https://www.soklet.com/docs/automated-testing">https://www.soklet.com/docs/automated-testing</a>.
059 *
060 * @author <a href="https://www.revetkn.com">Mark Allen</a>
061 */
062public interface Simulator {
063        /**
064         * Given a request, process it and return response data (both logical {@link Response}, if present, and the {@link MarshaledResponse} bytes to be sent over the wire) as well as the matching <em>Resource Method</em>, if available.
065         *
066         * @param request the request to process
067         * @return the result (logical response, marshaled response, etc.) that corresponds to the request
068         */
069        @Nonnull
070        RequestResult performRequest(@Nonnull Request request);
071
072        /**
073         * Registers a {@link ServerSentEvent} "consumer" for the given {@link ResourcePath} - similar to how a real client would listen for Server-Sent Events.
074         * <p>
075         * See documentation at <a href="https://www.soklet.com/docs/server-sent-events#testing">https://www.soklet.com/docs/server-sent-events#testing</a>.
076         *
077         * @param resourcePath            the Resource Path on which to listen for Server-Sent Events
078         * @param serverSentEventConsumer function to be invoked when a Server-Sent Event has been broadcast on the Resource Path
079         */
080        void registerServerSentEventConsumer(@Nonnull ResourcePath resourcePath,
081                                                                                                                                                         @Nonnull Consumer<ServerSentEvent> serverSentEventConsumer);
082
083        /**
084         * Acquires a Server-Sent Event broadcaster for the given {@link ResourcePath}.
085         * <p>
086         * See documentation at <a href="https://www.soklet.com/docs/server-sent-events#testing">https://www.soklet.com/docs/server-sent-events#testing</a>.
087         *
088         * @param resourcePath the Resource Path on which to broadcast Server-Sent Events
089         * @return a Server-Sent Event broadcaster
090         */
091        @Nonnull
092        ServerSentEventBroadcaster acquireServerSentEventBroadcaster(@Nonnull ResourcePath resourcePath);
093}