Skip to content

Commit

Permalink
Add further integration tests for InstrumentedEE10Handler metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
zUniQueX committed Jan 30, 2024
1 parent 6939798 commit c134f96
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 39 deletions.
6 changes: 6 additions & 0 deletions metrics-jetty12-ee10/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,11 @@
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${awaitility.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.dropwizard.metrics.jetty12.ee10;

import com.codahale.metrics.MetricRegistry;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.junit.After;
import org.junit.Before;

import static com.codahale.metrics.annotation.ResponseMeteredLevel.ALL;

abstract class AbstractIntegrationTest {

protected final HttpClient client = new HttpClient();
protected final MetricRegistry registry = new MetricRegistry();
protected final Server server = new Server();
protected final ServerConnector connector = new ServerConnector(server);
protected final InstrumentedEE10Handler handler = new InstrumentedEE10Handler(registry, null, ALL);
protected final ServletContextHandler servletContextHandler = new ServletContextHandler();

@Before
public void setUp() throws Exception {
handler.setName("handler");

// builds the following handler chain:
// ServletContextHandler -> InstrumentedHandler -> TestHandler
// the ServletContextHandler is needed to utilize servlet related classes
servletContextHandler.setHandler(getHandler());
servletContextHandler.insertHandler(handler);
server.setHandler(servletContextHandler);

server.addConnector(connector);
server.start();
client.start();
}

@After
public void tearDown() throws Exception {
server.stop();
client.stop();
}

protected String uri(String path) {
return "http://localhost:" + connector.getLocalPort() + path;
}

protected abstract Handler getHandler();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package io.dropwizard.metrics.jetty12.ee10;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.CompletableResponseListener;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.ee10.servlet.ServletHandler;
import org.eclipse.jetty.server.Handler;
import org.junit.Test;

import java.util.EnumSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.awaitility.Awaitility.await;

public class AsyncTest extends AbstractIntegrationTest {

@Override
protected Handler getHandler() {
return new ServletHandler();
}

@Test
public void testAsyncTimeout() throws Exception {
servletContextHandler.addFilter((request, response, chain) -> {
AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(1);
}, "/*", EnumSet.allOf(DispatcherType.class));

client.GET(uri("/"));
Meter asyncTimeouts = registry.meter(MetricRegistry.name(ServletHandler.class, "handler.async-timeouts"));
assertThat(asyncTimeouts.getCount()).isEqualTo(1L);

client.GET(uri("/"));
assertThat(asyncTimeouts.getCount()).isEqualTo(2L);
}

@Test
public void testActiveSuspended() {
servletContextHandler.addFilter((request, response, chain) -> {
AsyncContext asyncContext = request.startAsync();
asyncContext.start(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException interruptedException) {
Thread.currentThread().interrupt();
}
asyncContext.complete();
});
}, "/*", EnumSet.allOf(DispatcherType.class));

Counter activeSuspended = registry.counter(MetricRegistry.name(ServletHandler.class, "handler.active-suspended"));
Request request = client.POST(uri("/"));
CompletableResponseListener completableResponseListener = new CompletableResponseListener(request);
CompletableFuture<ContentResponse> asyncResponse = completableResponseListener.send();
assertThatNoException().isThrownBy(() -> {
await()
.atMost(750, TimeUnit.MILLISECONDS)
.until(() -> activeSuspended.getCount() == 1L);
asyncResponse.get();
});
assertThat(activeSuspended.getCount()).isEqualTo(0L);
}

@Test
public void testAsyncDispatches() throws Exception {
servletContextHandler.addFilter((request, response, chain) -> {
if (!(request instanceof HttpServletRequest)) {
throw new IllegalStateException("Expecting ServletRequest to be an instance of HttpServletRequest");
}
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
if ("/".equals(httpServletRequest.getRequestURI())) {
AsyncContext asyncContext = request.startAsync();
asyncContext.dispatch("/dispatch");
return;
}
if ("/dispatch".equals(httpServletRequest.getRequestURI())) {
AsyncContext asyncContext = request.startAsync();
if (!(response instanceof HttpServletResponse)) {
throw new IllegalStateException("Expecting ServletResponse to be an instance of HttpServletResponse");
}
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(204);
asyncContext.complete();
return;
}
throw new UnsupportedOperationException("Only '/' and '/dispatch' are valid paths");
}, "/*", EnumSet.allOf(DispatcherType.class));

ContentResponse contentResponse = client.GET(uri("/"));
assertThat(contentResponse).isNotNull().extracting(Response::getStatus).isEqualTo(204);
Meter asyncDispatches = registry.meter(MetricRegistry.name(ServletHandler.class, "handler.async-dispatches"));
assertThat(asyncDispatches.getCount()).isEqualTo(1L);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@

import com.codahale.metrics.MetricRegistry;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.ee10.servlet.DefaultServlet;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
import org.eclipse.jetty.ee10.servlet.ServletHandler;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.Callback;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

Expand All @@ -32,39 +27,15 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;

public class InstrumentedEE10HandlerTest {
private final HttpClient client = new HttpClient();
private final MetricRegistry registry = new MetricRegistry();
private final Server server = new Server();
private final ServerConnector connector = new ServerConnector(server);
private final InstrumentedEE10Handler handler = new InstrumentedEE10Handler(registry, null, ALL);
public class InstrumentedEE10HandlerTest extends AbstractIntegrationTest {

@Before
public void setUp() throws Exception {
handler.setName("handler");

TestHandler testHandler = new TestHandler();
@Override
protected Handler getHandler() {
InstrumentedEE10HandlerTest.TestHandler testHandler = new InstrumentedEE10HandlerTest.TestHandler();
// a servlet handler needs a servlet mapping, else the request will be short-circuited
// so use the DefaultServlet here
testHandler.addServletWithMapping(DefaultServlet.class, "/");

// builds the following handler chain:
// ServletContextHandler -> InstrumentedHandler -> TestHandler
// the ServletContextHandler is needed to utilize servlet related classes
ServletContextHandler servletContextHandler = new ServletContextHandler();
servletContextHandler.setHandler(testHandler);
servletContextHandler.insertHandler(handler);
server.setHandler(servletContextHandler);

server.addConnector(connector);
server.start();
client.start();
}

@After
public void tearDown() throws Exception {
server.stop();
client.stop();
return testHandler;
}

@Test
Expand Down Expand Up @@ -183,10 +154,6 @@ private void assertResponseTimesValid() {
.getSnapshot().getMedian()).isGreaterThan(0.0).isLessThan(TimeUnit.SECONDS.toNanos(1));
}

private String uri(String path) {
return "http://localhost:" + connector.getLocalPort() + path;
}

private String metricName() {
return MetricRegistry.name(TestHandler.class.getName(), "handler");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.dropwizard.metrics.jetty12.ee10;

import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.StringRequestContent;
import org.eclipse.jetty.ee10.servlet.DefaultServlet;
import org.eclipse.jetty.ee10.servlet.ServletHandler;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import static org.assertj.core.api.Assertions.assertThat;

public class ResponseStatusTest extends AbstractIntegrationTest {

@Override
protected Handler getHandler() {
ServletHandler servletHandler = new ResponseStatusHandler();
servletHandler.addServletWithMapping(DefaultServlet.class, "/");
return servletHandler;
}

@Test
public void testResponseCodes() throws Exception {

for (int i = 2; i <= 5; i++) {
String status = String.format("%d00", i);
ContentResponse contentResponse = client.POST(uri("/"))
.body(new StringRequestContent(status))
.headers(headers -> headers.add("Content-Type", "text/plain"))
.send();
assertThat(contentResponse).isNotNull().satisfies(response ->
assertThat(response.getStatus()).hasToString(status));

Meter meter = registry.meter(MetricRegistry.name(ResponseStatusHandler.class, String.format("handler.%dxx-responses", i)));
assertThat(meter.getCount()).isEqualTo(1L);
}
}

private static class ResponseStatusHandler extends ServletHandler {
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception {
try (InputStream inputStream = Request.asInputStream(request);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
String status = bufferedReader.readLine();
int statusCode = Integer.parseInt(status);
response.setStatus(statusCode);
callback.succeeded();
return true;
}
}
}
}
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<errorprone.version>2.24.1</errorprone.version>
<errorprone.javac.version>9+181-r4173-1</errorprone.javac.version>
<servlet6.version>6.0.0</servlet6.version>
<awaitility.version>4.2.0</awaitility.version>

<sonar.projectKey>dropwizard_metrics</sonar.projectKey>
<sonar.organization>dropwizard</sonar.organization>
Expand Down

0 comments on commit c134f96

Please sign in to comment.