diff options
Diffstat (limited to 'backend')
-rw-r--r-- | backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java | 58 | ||||
-rw-r--r-- | backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java | 66 |
2 files changed, 123 insertions, 1 deletions
diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java index 3388e002..43c8edeb 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java +++ b/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompClient.java @@ -6,6 +6,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.springframework.context.Lifecycle; import org.springframework.messaging.converter.MappingJackson2MessageConverter; import org.springframework.messaging.simp.stomp.StompSession; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @@ -16,16 +17,28 @@ import org.springframework.web.socket.sockjs.client.SockJsClient; import org.springframework.web.socket.sockjs.client.Transport; import org.springframework.web.socket.sockjs.client.WebSocketTransport; -public class JackstompClient { +/** + * A simple wrapper around a {@link WebSocketStompClient} which preconfigures websocket transports, a Jackson + * converter for messages, and allows for the creation of {@link JackstompSession}s. + */ +public class JackstompClient implements Lifecycle { private static final long DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS = 15; private final WebSocketStompClient client; + /** + * Creates a {@code JackstompClient} with convenient defaults. It creates a pre-configured + * {@link WebSocketStompClient} using Spring {@link SockJsClient} and a Jackson message converter. + */ public JackstompClient() { this(createDefaultStompClient()); } + /** + * Creates a {@code JackstompClient} based on the given {@link WebSocketStompClient}. This allows you to + * configure as you please the actual client used by Jackstomp. + */ public JackstompClient(WebSocketStompClient client) { this.client = client; } @@ -51,10 +64,42 @@ public class JackstompClient { return taskScheduler; } + /** + * Connects to the given URL. Uses a default timeout of {@value #DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS} seconds. + * + * @param url + * the URL to connect to + * + * @return a new {@link JackstompSession} for the created connection + * @throws InterruptedException + * if the current thread was interrupted while waiting for the connection + * @throws ExecutionException + * if an exception was thrown while connecting + * @throws TimeoutException + * if the connection took too long to establish + */ public JackstompSession connect(String url) throws InterruptedException, ExecutionException, TimeoutException { return connect(url, DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); } + /** + * Connects to the given URL. Uses a default timeout of {@value #DEFAULT_CONNECTION_TIMEOUT_IN_SECONDS} seconds. + * + * @param url + * the URL to connect to + * @param timeout + * the maximum time to wait for the connection + * @param unit + * the time unit of the timeout argument + * + * @return a new {@link JackstompSession} for the created connection + * @throws InterruptedException + * if the current thread was interrupted while waiting for the connection + * @throws ExecutionException + * if an exception was thrown while connecting + * @throws TimeoutException + * if the connection took too long to establish + */ public JackstompSession connect(String url, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { StompSession session = client.connect(url, new LoggingStompSessionHandler()).get(timeout, unit); @@ -62,7 +107,18 @@ public class JackstompClient { return new JackstompSession(session); } + @Override + public void start() { + client.start(); + } + + @Override public void stop() { client.stop(); } + + @Override + public boolean isRunning() { + return client.isRunning(); + } } diff --git a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java b/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java index 12ab0adc..db361fca 100644 --- a/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java +++ b/backend/src/test/java/org/luxons/sevenwonders/test/client/JackstompSession.java @@ -7,10 +7,21 @@ import org.springframework.messaging.simp.stomp.StompFrameHandler; import org.springframework.messaging.simp.stomp.StompHeaders; import org.springframework.messaging.simp.stomp.StompSession; +/** + * Wrapper a {@link StompSession} that provides additional subscription features. It can return a {@link Channel} + * upon subscription for a given payload type, which can then be queried actively. This is particularly useful for + * unit tests. + */ public class JackstompSession implements StompSession { private final StompSession stompSession; + /** + * Creates a new {@code JackstompSession} wrapping the given {@link StompSession}. + * + * @param stompSession + * the session to wrap + */ public JackstompSession(StompSession stompSession) { this.stompSession = stompSession; } @@ -35,6 +46,17 @@ public class JackstompSession implements StompSession { return stompSession.subscribe(headers, handler); } + /** + * Subscribe to the given destination by sending a SUBSCRIBE frame and queue received messages in the returned + * {@link Channel}. + * + * @param destination + * the destination to subscribe to + * @param payloadType + * the expected type for received messages + * + * @return a new channel to use to actively check for received values, unsubscribe, or track receipts + */ public <T> Channel<T> subscribe(String destination, Class<T> payloadType) { BlockingQueue<T> blockingQueue = new LinkedBlockingDeque<>(); StompFrameHandler frameHandler = new QueuedStompFrameHandler<>(blockingQueue, payloadType); @@ -42,6 +64,16 @@ public class JackstompSession implements StompSession { return new Channel<>(sub, blockingQueue); } + /** + * Subscribe to the given destination by sending a SUBSCRIBE frame and queue received messages in the returned + * {@link Channel}. The messages are expected to have no body, and empty {@link Object}s are queued to be able to + * track reception events. + * + * @param destination + * the destination to subscribe to + * + * @return a new channel to use to actively check for received events, unsubscribe, or track receipts + */ public Channel<Object> subscribeEmptyMsgs(String destination) { BlockingQueue<Object> blockingQueue = new LinkedBlockingDeque<>(); StompFrameHandler frameHandler = new EmptyMsgStompFrameHandler(blockingQueue); @@ -74,6 +106,25 @@ public class JackstompSession implements StompSession { stompSession.disconnect(); } + /** + * Makes a synchronous request/response call via a send and a subscription. + * + * @param payload + * the payload to send on the given requestDestination + * @param responseType + * the type of the response to expect on the responseDestination + * @param requestDestination + * the destination to send payload to + * @param responseDestination + * the destination to expect a response on + * @param <T> + * the type of object to receive as a response + * + * @return the response object, deserialized from the JSON received on the responseDestination, or null if no + * response was received before timeout. + * @throws InterruptedException + * if the current thread was interrupted while waiting for the response + */ public <T> T request(Object payload, Class<T> responseType, String requestDestination, String responseDestination) throws InterruptedException { Channel<T> channel = subscribe(responseDestination, responseType); @@ -83,6 +134,21 @@ public class JackstompSession implements StompSession { return msg; } + /** + * Makes a synchronous request/response call via a send and a subscription, but does not expect any value as + * response, just an event message with no body. + * + * @param payload + * the payload to send on the given requestDestination + * @param requestDestination + * the destination to send payload to + * @param responseDestination + * the destination to expect a response on + * + * @return true if the event message was received before timeout, false otherwise + * @throws InterruptedException + * if the current thread was interrupted while waiting for the response + */ public boolean request(Object payload, String requestDestination, String responseDestination) throws InterruptedException { Channel<Object> channel = subscribeEmptyMsgs(responseDestination); |