/*
* Copyright (c) 2011-2015 The original author or authors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.vertx.ext.stomp.impl;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;
import io.vertx.ext.stomp.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static com.jayway.awaitility.Awaitility.await;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test the received and writing frame handler
* @author <a href="http://escoffier.me">Clement Escoffier</a>
*/
public class FrameHandlerTest {
private Vertx vertx;
private StompServer server;
private StompClient client;
private Buffer UNKNOWN_FRAME = Buffer.buffer("YEAH\nfoo:val\n\nMy body...")
.appendString(FrameParser.NULL);
// The last connection received by the server.
private StompServerConnection connection;
private List<Frame> receivedByServer = new ArrayList<>();
private List<Frame> receivedByClient = new ArrayList<>();
private List<Frame> writtenByServer = new ArrayList<>();
@Before
public void setUp() {
AsyncLock<StompServer> lock = new AsyncLock<>();
vertx = Vertx.vertx();
server = StompServer.create(vertx)
.handler(StompServerHandler.create(vertx)
.receivedFrameHandler(frame -> {
frame.frame().addHeader("mark", "true");
receivedByServer.add(frame.frame());
connection = frame.connection();
}))
.writingFrameHandler(frame -> {
frame.frame().addHeader("mark", "true");
writtenByServer.add(frame.frame());
})
.listen(lock.handler());
lock.waitForSuccess();
client = StompClient.create(vertx);
client.receivedFrameHandler(frame -> {
frame.addHeader("c-mark", "true");
receivedByClient.add(frame);
});
}
@After
public void tearDown() {
AsyncLock<Void> lock = new AsyncLock<>();
server.close(lock.handler());
lock.waitForSuccess();
lock = new AsyncLock<>();
vertx.close(lock.handler());
lock.waitForSuccess();
client.close();
receivedByClient.clear();
receivedByServer.clear();
}
@Test
public void testFrameHandler() {
AtomicReference<StompClientConnection> reference = new AtomicReference<>();
client.connect(connection -> {
reference.set(connection.result());
});
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByServer, Frame.Command.CONNECT));
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByClient, Frame.Command.CONNECTED));
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(writtenByServer, Frame.Command.CONNECTED));
reference.get().send("foo", Buffer.buffer("hello"), f -> {
// just there to receive a reply.
});
await().atMost(10, TimeUnit.SECONDS).until(() -> containsFrameWithCommandAndIsMarked(receivedByServer,
Frame.Command.SEND));
await().atMost(10, TimeUnit.SECONDS).until(() -> containsFrameWithCommandAndIsMarked(receivedByClient,
Frame.Command.RECEIPT));
await().atMost(10, TimeUnit.SECONDS).until(() -> containsFrameWithCommandAndIsMarked(writtenByServer,
Frame.Command.RECEIPT));
}
@Test
public void testFrameHandlerWithPingFrames() {
AtomicReference<StompClientConnection> reference = new AtomicReference<>();
client.connect(connection -> {
reference.set(connection.result());
});
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByServer, Frame.Command.CONNECT));
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByClient, Frame.Command.CONNECTED));
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(writtenByServer, Frame.Command.CONNECTED));
await().atMost(10, TimeUnit.SECONDS).until(() -> containsFrameWithCommand(receivedByServer,
Frame.Command.PING));
await().atMost(10, TimeUnit.SECONDS).until(() -> containsFrameWithCommand(receivedByClient,
Frame.Command.PING));
await().atMost(10, TimeUnit.SECONDS).until(() -> containsFrameWithCommand(writtenByServer,
Frame.Command.PING));
}
@Test
public void testFrameHandlerWithInvalidFramesReceivedByServer() throws InterruptedException {
AtomicReference<StompClientConnection> reference = new AtomicReference<>();
client.connect(connection -> {
reference.set(connection.result());
});
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByServer, Frame.Command.CONNECT));
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByClient, Frame.Command.CONNECTED));
StompClientConnectionImpl impl = (StompClientConnectionImpl) reference.get();
NetSocket socket = impl.socket();
socket.write(UNKNOWN_FRAME);
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByServer, Frame.Command.UNKNOWN));
Frame frame = getFrameWithCommand(receivedByServer, Frame.Command.UNKNOWN);
assertThat(frame).isNotNull();
assertThat(frame.getHeader(Frame.STOMP_FRAME_COMMAND)).isEqualToIgnoringCase("YEAH");
}
@Test
public void testFrameHandlerWithInvalidFramesReceivedByClient() throws InterruptedException {
client.connect(v -> { });
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByServer, Frame.Command.CONNECT));
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByClient, Frame.Command.CONNECTED));
assertThat(connection).isNotNull();
connection.write(UNKNOWN_FRAME);
await().atMost(10, TimeUnit.SECONDS).until(() ->
containsFrameWithCommand(receivedByClient, Frame.Command.UNKNOWN));
Frame frame = getFrameWithCommand(receivedByClient, Frame.Command.UNKNOWN);
assertThat(frame).isNotNull();
assertThat(frame.getHeader(Frame.STOMP_FRAME_COMMAND)).isEqualToIgnoringCase("YEAH");
}
private boolean containsFrameWithCommand(List<Frame> frames, Frame.Command command) {
for (Frame frame : frames) {
if (frame.getCommand() == command) {
return true;
}
}
return false;
}
private boolean containsFrameWithCommandAndIsMarked(List<Frame> frames, Frame.Command command) {
for (Frame frame : frames) {
if (frame.getCommand() == command && frame.getHeader("mark") != null) {
return true;
}
}
return false;
}
private Frame getFrameWithCommand(List<Frame> frames, Frame.Command command) {
for (Frame frame : frames) {
if (frame.getCommand() == command) {
return frame;
}
}
return null;
}
@Test
public void testThatWeReceiveConnectAndDisconnectFrames() throws InterruptedException {
List<Frame> received = new ArrayList<>();
List<Frame> sent = new ArrayList<>();
StompClient stompClient = StompClient.create(vertx);
AtomicReference<StompClientConnection> ref = new AtomicReference<>();
stompClient
.receivedFrameHandler(frame -> {
if (frame.getCommand() != Frame.Command.PING) {
received.add(frame);
}
})
.writingFrameHandler(frame -> {
if (frame.getCommand() != Frame.Command.PING) {
sent.add(frame);
}
})
.connect(ar -> {
ref.set(ar.result());
if (ar.succeeded()) {
ref.set(ar.result());
} else {
ar.cause().printStackTrace();
}
});
await().until(() -> sent.stream().anyMatch(f -> f.getCommand() == Frame.Command.CONNECT));
await().until(() -> received.stream().anyMatch(f -> f.getCommand() == Frame.Command.CONNECTED));
ref.get().disconnect();
await().until(() -> sent.stream().anyMatch(f -> f.getCommand() == Frame.Command.DISCONNECT));
}
}