/*
* Copyright (c) 2011-2013 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.test.core;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Context;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Handler;
import io.vertx.core.Verticle;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.datagram.DatagramSocket;
import io.vertx.core.datagram.DatagramSocketOptions;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.http.ServerWebSocket;
import io.vertx.core.http.WebSocket;
import io.vertx.core.metrics.MetricsOptions;
import io.vertx.core.metrics.impl.DummyVertxMetrics;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetClientOptions;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.NetServerOptions;
import io.vertx.core.net.SocketAddress;
import io.vertx.core.spi.VertxMetricsFactory;
import io.vertx.core.spi.metrics.DatagramSocketMetrics;
import io.vertx.core.spi.metrics.EventBusMetrics;
import io.vertx.core.spi.metrics.HttpClientMetrics;
import io.vertx.core.spi.metrics.HttpServerMetrics;
import io.vertx.core.spi.metrics.TCPMetrics;
import org.junit.Ignore;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Function;
/**
* @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
*/
public class MetricsContextTest extends VertxTestBase {
@Test
public void testFactory() throws Exception {
AtomicReference<Thread> metricsThread = new AtomicReference<>();
AtomicReference<Context> metricsContext = new AtomicReference<>();
VertxMetricsFactory factory = (vertx, options) -> {
metricsThread.set(Thread.currentThread());
metricsContext.set(Vertx.currentContext());
return DummyVertxMetrics.INSTANCE;
};
vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
assertSame(Thread.currentThread(), metricsThread.get());
assertNull(metricsContext.get());
}
@Test
public void testFactoryInCluster() throws Exception {
AtomicReference<Thread> metricsThread = new AtomicReference<>();
AtomicReference<Context> metricsContext = new AtomicReference<>();
Thread testThread = Thread.currentThread();
VertxMetricsFactory factory = (vertx, options) -> {
metricsThread.set(Thread.currentThread());
metricsContext.set(Vertx.currentContext());
return DummyVertxMetrics.INSTANCE;
};
clusteredVertx(new VertxOptions().setClustered(true).setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)), onSuccess(vertx -> {
assertSame(testThread, metricsThread.get());
assertNull(metricsContext.get());
testComplete();
}));
await();
}
@Test
public void testHttpServerRequestEventLoop() throws Exception {
testHttpServerRequest(eventLoopContextFactory, eventLoopChecker);
}
@Test
public void testHttpServerRequestWorker() throws Exception {
testHttpServerRequest(workerContextFactory, workerChecker);
}
private void testHttpServerRequest(Function<Vertx, Context> contextFactory, BiConsumer<Thread, Context> checker) throws Exception {
AtomicReference<Thread> expectedThread = new AtomicReference<>();
AtomicReference<Context> expectedContext = new AtomicReference<>();
AtomicBoolean requestBeginCalled = new AtomicBoolean();
AtomicBoolean responseEndCalled = new AtomicBoolean();
AtomicBoolean socketConnectedCalled = new AtomicBoolean();
AtomicBoolean socketDisconnectedCalled = new AtomicBoolean();
AtomicBoolean bytesReadCalled = new AtomicBoolean();
AtomicBoolean bytesWrittenCalled = new AtomicBoolean();
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public HttpServerMetrics createMetrics(HttpServer server, SocketAddress localAddress, HttpServerOptions options) {
return new DummyHttpServerMetrics() {
@Override
public Void requestBegin(Void socketMetric, HttpServerRequest request) {
requestBeginCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void responseEnd(Void requestMetric, HttpServerResponse response) {
responseEndCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public Void connected(SocketAddress remoteAddress, String remoteName) {
socketConnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void socketMetric, SocketAddress remoteAddress) {
socketDisconnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesRead(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesReadCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesWritten(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesWrittenCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public void close() {
closeCalled.set(true);
}
};
}
};
CountDownLatch latch = new CountDownLatch(1);
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
Context ctx = contextFactory.apply(vertx);
ctx.runOnContext(v1 -> {
HttpServer server = vertx.createHttpServer().requestHandler(req -> {
HttpServerResponse response = req.response();
response.setStatusCode(200).setChunked(true).write("bye").end();
response.close();
});
server.listen(8080, "localhost", onSuccess(s -> {
expectedThread.set(Thread.currentThread());
expectedContext.set(Vertx.currentContext());
latch.countDown();
}));
});
awaitLatch(latch);
HttpClient client = vertx.createHttpClient();
client.put(8080, "localhost", "/", resp -> {
resp.netSocket().closeHandler(v -> {
vertx.close(v4 -> {
assertTrue(requestBeginCalled.get());
assertTrue(responseEndCalled.get());
assertTrue(bytesReadCalled.get());
assertTrue(bytesWrittenCalled.get());
assertTrue(socketConnectedCalled.get());
assertTrue(socketDisconnectedCalled.get());
assertTrue(closeCalled.get());
testComplete();
});
});
}).exceptionHandler(err -> {
fail(err.getMessage());
}).setChunked(true).write(Buffer.buffer("hello")).end();
await();
}
@Test
public void testHttpServerWebsocketEventLoop() throws Exception {
testHttpServerWebsocket(eventLoopContextFactory, eventLoopChecker);
}
@Test
public void testHttpServerWebsocketWorker() throws Exception {
testHttpServerWebsocket(workerContextFactory, workerChecker);
}
private void testHttpServerWebsocket(Function<Vertx, Context> contextFactory, BiConsumer<Thread, Context> checker) throws Exception {
AtomicReference<Thread> expectedThread = new AtomicReference<>();
AtomicReference<Context> expectedContext = new AtomicReference<>();
AtomicBoolean websocketConnected = new AtomicBoolean();
AtomicBoolean websocketDisconnected = new AtomicBoolean();
AtomicBoolean socketConnectedCalled = new AtomicBoolean();
AtomicBoolean socketDisconnectedCalled = new AtomicBoolean();
AtomicBoolean bytesReadCalled = new AtomicBoolean();
AtomicBoolean bytesWrittenCalled = new AtomicBoolean();
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public HttpServerMetrics createMetrics(HttpServer server, SocketAddress localAddress, HttpServerOptions options) {
return new DummyHttpServerMetrics() {
@Override
public Void connected(Void socketMetric, ServerWebSocket serverWebSocket) {
websocketConnected.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void serverWebSocketMetric) {
websocketDisconnected.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public Void connected(SocketAddress remoteAddress, String remoteName) {
socketConnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void socketMetric, SocketAddress remoteAddress) {
socketDisconnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesRead(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesReadCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesWritten(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesWrittenCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public void close() {
closeCalled.set(true);
}
};
}
};
CountDownLatch latch = new CountDownLatch(1);
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
Context ctx = contextFactory.apply(vertx);
ctx.runOnContext(v1 -> {
HttpServer server = vertx.createHttpServer().websocketHandler(ws -> {
ws.handler(buf -> {
ws.write(Buffer.buffer("bye"));
});
});
server.listen(8080, "localhost", onSuccess(s -> {
expectedThread.set(Thread.currentThread());
expectedContext.set(Vertx.currentContext());
latch.countDown();
}));
});
awaitLatch(latch);
HttpClient client = vertx.createHttpClient();
client.websocket(8080, "localhost", "/", ws -> {
ws.handler(buf -> {
ws.closeHandler(v -> {
vertx.close(v4 -> {
assertTrue(websocketConnected.get());
assertTrue(websocketDisconnected.get());
assertTrue(bytesReadCalled.get());
assertTrue(bytesWrittenCalled.get());
assertTrue(socketConnectedCalled.get());
assertTrue(socketDisconnectedCalled.get());
assertTrue(closeCalled.get());
testComplete();
});
});
ws.close();
});
ws.write(Buffer.buffer("hello"));
});
await();
}
@Test
public void testHttpClientRequestEventLoop() throws Exception {
testHttpClientRequest(eventLoopContextFactory, eventLoopChecker);
}
@Test
public void testHttpClientRequestWorker() throws Exception {
testHttpClientRequest(workerContextFactory, workerChecker);
}
private void testHttpClientRequest(Function<Vertx, Context> contextFactory, BiConsumer<Thread, Context> checker) throws Exception {
AtomicReference<Thread> expectedThread = new AtomicReference<>();
AtomicReference<Context> expectedContext = new AtomicReference<>();
AtomicBoolean requestBeginCalled = new AtomicBoolean();
AtomicBoolean responseEndCalled = new AtomicBoolean();
AtomicBoolean socketConnectedCalled = new AtomicBoolean();
AtomicBoolean socketDisconnectedCalled = new AtomicBoolean();
AtomicBoolean bytesReadCalled = new AtomicBoolean();
AtomicBoolean bytesWrittenCalled = new AtomicBoolean();
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public HttpClientMetrics createMetrics(HttpClient client, HttpClientOptions options) {
return new DummyHttpClientMetrics() {
@Override
public Void requestBegin(Void endpointMetric, Void socketMetric, SocketAddress localAddress, SocketAddress remoteAddress, HttpClientRequest request) {
requestBeginCalled.set(true);
return null;
}
@Override
public void responseEnd(Void requestMetric, HttpClientResponse response) {
responseEndCalled.set(true);
}
@Override
public Void connected(SocketAddress remoteAddress, String remoteName) {
socketConnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void socketMetric, SocketAddress remoteAddress) {
socketDisconnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesRead(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesReadCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesWritten(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesWrittenCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void close() {
closeCalled.set(true);
}
@Override
public boolean isEnabled() {
return true;
}
};
}
};
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
HttpServer server = vertx.createHttpServer();
server.requestHandler(req -> {
req.endHandler(buf -> {
HttpServerResponse resp = req.response();
resp.setChunked(true).write(Buffer.buffer("bye")).end();
resp.close();
});
});
CountDownLatch latch = new CountDownLatch(1);
server.listen(8080, "localhost", onSuccess(s -> {
latch.countDown();
}));
awaitLatch(latch);
Context ctx = contextFactory.apply(vertx);
ctx.runOnContext(v1 -> {
expectedThread.set(Thread.currentThread());
expectedContext.set(Vertx.currentContext());
HttpClient client = vertx.createHttpClient();
checker.accept(expectedThread.get(), expectedContext.get());
HttpClientRequest req = client.put(8080, "localhost", "/");
req.handler(resp -> {
executeInVanillaThread(() -> {
client.close();
vertx.close(v2 -> {
assertTrue(requestBeginCalled.get());
assertTrue(responseEndCalled.get());
assertTrue(socketConnectedCalled.get());
assertTrue(socketDisconnectedCalled.get());
assertTrue(bytesReadCalled.get());
assertTrue(bytesWrittenCalled.get());
assertTrue(closeCalled.get());
testComplete();
});
});
});
req.setChunked(true).write("hello");
req.end();
});
await();
}
@Test
public void testHttpClientWebsocketEventLoop() throws Exception {
testHttpClientWebsocket(eventLoopContextFactory, eventLoopChecker);
}
// FIXME!! This test intermittently fails
@Test
@Ignore
public void testHttpClientWebsocketWorker() throws Exception {
testHttpClientWebsocket(workerContextFactory, workerChecker);
}
private void testHttpClientWebsocket(Function<Vertx, Context> contextFactory, BiConsumer<Thread, Context> checker) throws Exception {
AtomicReference<Thread> expectedThread = new AtomicReference<>();
AtomicReference<Context> expectedContext = new AtomicReference<>();
AtomicBoolean websocketConnected = new AtomicBoolean();
AtomicBoolean websocketDisconnected = new AtomicBoolean();
AtomicBoolean socketConnectedCalled = new AtomicBoolean();
AtomicBoolean socketDisconnectedCalled = new AtomicBoolean();
AtomicBoolean bytesReadCalled = new AtomicBoolean();
AtomicBoolean bytesWrittenCalled = new AtomicBoolean();
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public HttpClientMetrics createMetrics(HttpClient client, HttpClientOptions options) {
return new DummyHttpClientMetrics() {
@Override
public Void connected(Void endpointMetric, Void socketMetric, WebSocket webSocket) {
websocketConnected.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void webSocketMetric) {
websocketDisconnected.set(true);
}
@Override
public Void connected(SocketAddress remoteAddress, String remoteName) {
socketConnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void socketMetric, SocketAddress remoteAddress) {
socketDisconnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesRead(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesReadCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesWritten(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesWrittenCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void close() {
closeCalled.set(true);
}
@Override
public boolean isEnabled() {
return true;
}
};
}
};
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
HttpServer server = vertx.createHttpServer();
server.websocketHandler(ws -> {
ws.handler(buf -> {
ws.write(Buffer.buffer("bye"));
});
});
CountDownLatch latch = new CountDownLatch(1);
server.listen(8080, "localhost", onSuccess(s -> {
latch.countDown();
}));
awaitLatch(latch);
Context ctx = contextFactory.apply(vertx);
ctx.runOnContext(v1 -> {
expectedThread.set(Thread.currentThread());
expectedContext.set(Vertx.currentContext());
HttpClient client = vertx.createHttpClient();
checker.accept(expectedThread.get(), expectedContext.get());
client.websocket(8080, "localhost", "/", ws -> {
ws.handler(buf -> {
ws.closeHandler(v2 -> {
executeInVanillaThread(() -> {
client.close();
vertx.close(v3 -> {
assertTrue(websocketConnected.get());
assertTrue(websocketDisconnected.get());
assertTrue(socketConnectedCalled.get());
assertTrue(socketDisconnectedCalled.get());
assertTrue(bytesReadCalled.get());
assertTrue(bytesWrittenCalled.get());
assertTrue(closeCalled.get());
testComplete();
});
});
});
ws.close();
});
ws.write(Buffer.buffer("hello"));
});
});
await();
}
@Test
public void testNetServerEventLoop() throws Exception {
testNetServer(eventLoopContextFactory, eventLoopChecker);
}
@Test
public void testNetServerWorker() throws Exception {
testNetServer(workerContextFactory, workerChecker);
}
private void testNetServer(Function<Vertx, Context> contextFactory, BiConsumer<Thread, Context> checker) throws Exception {
AtomicReference<Thread> expectedThread = new AtomicReference<>();
AtomicReference<Context> expectedContext = new AtomicReference<>();
AtomicBoolean socketConnectedCalled = new AtomicBoolean();
AtomicBoolean socketDisconnectedCalled = new AtomicBoolean();
AtomicBoolean bytesReadCalled = new AtomicBoolean();
AtomicBoolean bytesWrittenCalled = new AtomicBoolean();
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public TCPMetrics createMetrics(SocketAddress localAddress, NetServerOptions options) {
return new DummyTCPMetrics() {
@Override
public Void connected(SocketAddress remoteAddress, String remoteName) {
socketConnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void socketMetric, SocketAddress remoteAddress) {
socketDisconnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesRead(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesReadCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesWritten(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesWrittenCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public void close() {
closeCalled.set(true);
}
};
}
};
CountDownLatch latch = new CountDownLatch(1);
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
Context ctx = contextFactory.apply(vertx);
ctx.runOnContext(v1 -> {
NetServer server = vertx.createNetServer().connectHandler(so -> {
so.handler(buf -> {
so.write("bye");
});
});
server.listen(1234, "localhost", onSuccess(s -> {
expectedThread.set(Thread.currentThread());
expectedContext.set(Vertx.currentContext());
checker.accept(expectedThread.get(), expectedContext.get());
latch.countDown();
}));
});
awaitLatch(latch);
NetClient client = vertx.createNetClient();
client.connect(1234, "localhost", onSuccess(so -> {
so.handler(buf -> {
so.closeHandler(v -> {
executeInVanillaThread(() -> {
vertx.close(v4 -> {
assertTrue(bytesReadCalled.get());
assertTrue(bytesWrittenCalled.get());
assertTrue(socketConnectedCalled.get());
assertTrue(socketDisconnectedCalled.get());
assertTrue(closeCalled.get());
testComplete();
});
});
});
so.close();
});
so.write("hello");
}));
await();
}
@Test
public void testNetClientEventLoop() throws Exception {
testNetClient(eventLoopContextFactory, eventLoopChecker);
}
@Test
public void testNetClientWorker() throws Exception {
testNetClient(workerContextFactory, workerChecker);
}
private void testNetClient(Function<Vertx, Context> contextFactory, BiConsumer<Thread, Context> checker) throws Exception {
AtomicReference<Thread> expectedThread = new AtomicReference<>();
AtomicReference<Context> expectedContext = new AtomicReference<>();
AtomicBoolean socketConnectedCalled = new AtomicBoolean();
AtomicBoolean socketDisconnectedCalled = new AtomicBoolean();
AtomicBoolean bytesReadCalled = new AtomicBoolean();
AtomicBoolean bytesWrittenCalled = new AtomicBoolean();
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public TCPMetrics createMetrics(NetClientOptions options) {
return new DummyTCPMetrics() {
@Override
public Void connected(SocketAddress remoteAddress, String remoteName) {
socketConnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
return null;
}
@Override
public void disconnected(Void socketMetric, SocketAddress remoteAddress) {
socketDisconnectedCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesRead(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesReadCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesWritten(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesWrittenCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public void close() {
closeCalled.set(true);
}
};
}
};
CountDownLatch latch = new CountDownLatch(1);
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
Context ctx = contextFactory.apply(vertx);
NetServer server = vertx.createNetServer().connectHandler(so -> {
so.handler(buf -> {
so.write("bye");
});
});
server.listen(1234, "localhost", onSuccess(s -> {
latch.countDown();
}));
awaitLatch(latch);
ctx.runOnContext(v1 -> {
NetClient client = vertx.createNetClient();
expectedThread.set(Thread.currentThread());
expectedContext.set(Vertx.currentContext());
client.connect(1234, "localhost", onSuccess(so -> {
so.handler(buf -> {
so.closeHandler(v -> {
assertTrue(bytesReadCalled.get());
assertTrue(bytesWrittenCalled.get());
assertTrue(socketConnectedCalled.get());
assertTrue(socketDisconnectedCalled.get());
executeInVanillaThread(() -> {
client.close();
vertx.close(v4 -> {
assertTrue(closeCalled.get());
testComplete();
});
});
});
so.close();
});
so.write("hello");
}));
});
await();
}
@Test
public void testDatagramEventLoop() throws Exception {
testDatagram(eventLoopContextFactory, eventLoopChecker);
}
@Test
public void testDatagramWorker() throws Exception {
testDatagram(workerContextFactory, workerChecker);
}
private void testDatagram(Function<Vertx, Context> contextFactory, BiConsumer<Thread, Context> checker) {
AtomicReference<Thread> expectedThread = new AtomicReference<>();
AtomicReference<Context> expectedContext = new AtomicReference<>();
AtomicBoolean listening = new AtomicBoolean();
AtomicBoolean bytesReadCalled = new AtomicBoolean();
AtomicBoolean bytesWrittenCalled = new AtomicBoolean();
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public DatagramSocketMetrics createMetrics(DatagramSocket socket, DatagramSocketOptions options) {
return new DummyDatagramMetrics() {
@Override
public void listening(String localName, SocketAddress localAddress) {
listening.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesRead(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesReadCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void bytesWritten(Void socketMetric, SocketAddress remoteAddress, long numberOfBytes) {
bytesWrittenCalled.set(true);
checker.accept(expectedThread.get(), expectedContext.get());
}
@Override
public void close() {
closeCalled.set(true);
}
@Override
public boolean isEnabled() {
return true;
}
};
}
};
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
Context ctx = contextFactory.apply(vertx);
ctx.runOnContext(v1 -> {
expectedThread.set(Thread.currentThread());
expectedContext.set(Vertx.currentContext());
DatagramSocket socket = vertx.createDatagramSocket();
socket.listen(1234, "localhost", ar1 -> {
assertTrue(ar1.succeeded());
checker.accept(expectedThread.get(), expectedContext.get());
socket.handler(packet -> {
assertTrue(listening.get());
assertTrue(bytesReadCalled.get());
assertTrue(bytesWrittenCalled.get());
executeInVanillaThread(() -> {
socket.close(ar2 -> {
assertTrue(closeCalled.get());
assertTrue(ar2.succeeded());
testComplete();
});
});
});
socket.send(Buffer.buffer("msg"), 1234, "localhost", ar2 -> {
assertTrue(ar2.succeeded());
});
});
});
await();
}
@Test
public void testEventBusLifecycle() {
AtomicBoolean closeCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public EventBusMetrics createMetrics(EventBus eventBus) {
return new DummyEventBusMetrics() {
@Override
public boolean isEnabled() {
return true;
}
@Override
public void close() {
closeCalled.set(true);
}
};
}
};
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
vertx.eventBus();
executeInVanillaThread(() -> {
vertx.close(onSuccess(v -> {
assertTrue(closeCalled.get());
testComplete();
}));
});
await();
}
@Test
public void testMessageHandler() {
testMessageHandler((vertx, handler) -> handler.handle(null), eventLoopChecker);
}
@Test
public void testMessageHandlerEventLoop() {
testMessageHandler((vertx, handler) -> eventLoopContextFactory.apply(vertx).runOnContext(handler), eventLoopChecker);
}
private void testMessageHandler(BiConsumer<Vertx, Handler<Void>> runOnContext, BiConsumer<Thread, Context> checker) {
AtomicReference<Thread> consumerThread = new AtomicReference<>();
AtomicReference<Context> consumerContext = new AtomicReference<>();
AtomicBoolean registeredCalled = new AtomicBoolean();
AtomicBoolean unregisteredCalled = new AtomicBoolean();
AtomicBoolean beginHandleCalled = new AtomicBoolean();
AtomicBoolean endHandleCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public EventBusMetrics createMetrics(EventBus eventBus) {
return new DummyEventBusMetrics() {
@Override
public boolean isEnabled() {
return true;
}
@Override
public Void handlerRegistered(String address, String repliedAddress) {
registeredCalled.set(true);
return null;
}
@Override
public void handlerUnregistered(Void handler) {
unregisteredCalled.set(true);
}
@Override
public void beginHandleMessage(Void handler, boolean local) {
consumerThread.set(Thread.currentThread());
consumerContext.set(Vertx.currentContext());
beginHandleCalled.set(true);
}
@Override
public void endHandleMessage(Void handler, Throwable failure) {
endHandleCalled.set(true);
checker.accept(consumerThread.get(), consumerContext.get());
}
};
}
};
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
EventBus eb = vertx.eventBus();
runOnContext.accept(vertx, v -> {
MessageConsumer<Object> consumer = eb.consumer("the_address");
consumer.handler(msg -> {
checker.accept(consumerThread.get(), consumerContext.get());
executeInVanillaThread(() -> {
vertx.getOrCreateContext().runOnContext(v2 -> {
consumer.unregister(onSuccess(v3 -> {
assertTrue(registeredCalled.get());
assertTrue(beginHandleCalled.get());
assertTrue(endHandleCalled.get());
assertWaitUntil(() -> unregisteredCalled.get());
testComplete();
}));
});
});
}).completionHandler(onSuccess(v2 -> {
eb.send("the_address", "the_msg");
}));
});
await();
}
@Test
public void testDeployEventLoop() {
testDeploy(false, false, eventLoopChecker);
}
@Test
public void testDeployWorker() {
testDeploy(true, false, workerChecker);
}
@Test
public void testDeployMultiThreadedWorker() {
testDeploy(true, true, workerChecker);
}
private void testDeploy(boolean worker, boolean multiThreaded, BiConsumer<Thread, Context> checker) {
AtomicReference<Thread> verticleThread = new AtomicReference<>();
AtomicReference<Context> verticleContext = new AtomicReference<>();
AtomicBoolean deployedCalled = new AtomicBoolean();
AtomicBoolean undeployedCalled = new AtomicBoolean();
VertxMetricsFactory factory = (vertx, options) -> new DummyVertxMetrics() {
@Override
public void verticleDeployed(Verticle verticle) {
deployedCalled.set(true);
checker.accept(verticleThread.get(), verticleContext.get());
}
@Override
public void verticleUndeployed(Verticle verticle) {
undeployedCalled.set(true);
checker.accept(verticleThread.get(), verticleContext.get());
}
};
Vertx vertx = vertx(new VertxOptions().setMetricsOptions(new MetricsOptions().setEnabled(true).setFactory(factory)));
vertx.deployVerticle(new AbstractVerticle() {
@Override
public void start() throws Exception {
verticleThread.set(Thread.currentThread());
verticleContext.set(Vertx.currentContext());
}
}, new DeploymentOptions().setWorker(worker).setMultiThreaded(multiThreaded), ar1 -> {
assertTrue(ar1.succeeded());
vertx.undeploy(ar1.result(), ar2 -> {
assertTrue(ar1.succeeded());
assertTrue(deployedCalled.get());
assertTrue(undeployedCalled.get());
testComplete();
});
});
await();
}
private void executeInVanillaThread(Runnable task) {
new Thread(task).start();
}
private Function<Vertx, Context> eventLoopContextFactory = Vertx::getOrCreateContext;
private BiConsumer<Thread, Context> eventLoopChecker = (thread, ctx) -> {
assertSame(Vertx.currentContext(), ctx);
assertSame(Thread.currentThread(), thread);
};
private Function<Vertx, Context> workerContextFactory = vertx -> {
AtomicReference<Context> ctx = new AtomicReference<>();
vertx.deployVerticle(new AbstractVerticle() {
@Override
public void start() throws Exception {
ctx.set(context);
super.start();
}
}, new DeploymentOptions().setWorker(true));
assertWaitUntil(() -> ctx.get() != null);
return ctx.get();
};
private BiConsumer<Thread, Context> workerChecker = (thread, ctx) -> {
assertSame(Vertx.currentContext(), ctx);
assertTrue(Context.isOnWorkerThread());
};
}