java-tutorials/play-framework/async-http/test/controllers/HomeControllerTest.java

233 lines
8.9 KiB
Java

package controllers;
import static java.time.temporal.ChronoUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static play.mvc.Http.Status.SERVICE_UNAVAILABLE;
import akka.Done;
import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Sink;
import akka.util.ByteString;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.OptionalInt;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import org.apache.http.HttpStatus;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.Application;
import play.inject.guice.GuiceApplicationBuilder;
import play.libs.concurrent.Futures;
import play.libs.ws.WSClient;
import play.libs.ws.WSResponse;
import play.libs.ws.ahc.AhcCurlRequestLogger;
import play.mvc.Result;
import play.mvc.Results;
import play.test.WithServer;
public class HomeControllerTest extends WithServer {
private final Logger log = LoggerFactory.getLogger(HomeControllerTest.class);
private String url;
private int port;
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().build();
}
@Before
public void setup() {
OptionalInt optHttpsPort = testServer.getRunningHttpsPort();
if (optHttpsPort.isPresent()) {
port = optHttpsPort.getAsInt();
url = "https://localhost:" + port;
} else {
port = testServer.getRunningHttpPort()
.getAsInt();
url = "http://localhost:" + port;
}
}
@Test
public void givenASingleGetRequestWhenResponseThenBlockWithCompletableAndLog()
throws Exception {
WSClient ws = play.test.WSTestClient.newClient(port);
WSResponse wsResponse = ws.url(url)
.setRequestFilter(new AhcCurlRequestLogger())
.addHeader("key", "value")
.addQueryParameter("num", "" + 1)
.get()
.toCompletableFuture()
.get();
log.debug("Thread#" + Thread.currentThread()
.getId() + " Request complete: Response code = "
+ wsResponse.getStatus()
+ " | Response: " + wsResponse.getBody() + " | Current Time:"
+ System.currentTimeMillis());
assert (HttpStatus.SC_OK == wsResponse.getStatus());
}
@Test
public void givenASingleGetRequestWhenResponseThenLog() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WSClient ws = play.test.WSTestClient.newClient(port);
ws.url(url)
.setRequestFilter(new AhcCurlRequestLogger())
.addHeader("key", "value")
.addQueryParameter("num", "" + 1)
.get()
.thenAccept(r -> {
log.debug("Thread#" + Thread.currentThread()
.getId() + " Request complete: Response code = "
+ r.getStatus()
+ " | Response: " + r.getBody() + " | Current Time:" + System.currentTimeMillis());
latch.countDown();
});
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenASinglePostRequestWhenResponseThenLog() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WSClient ws = play.test.WSTestClient.newClient(port);
ws.url(url)
.setContentType("application/x-www-form-urlencoded")
.post("key1=value1&key2=value2")
.thenAccept(r -> {
log.debug("Thread#" + Thread.currentThread()
.getId() + " Request complete: Response code = "
+ r.getStatus()
+ " | Response: " + r.getBody() + " | Current Time:" + System.currentTimeMillis());
latch.countDown();
});
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenMultipleRequestsWhenResponseThenLog() throws Exception {
CountDownLatch latch = new CountDownLatch(100);
WSClient ws = play.test.WSTestClient.newClient(port);
IntStream.range(0, 100)
.parallel()
.forEach(num ->
ws.url(url)
.setRequestFilter(new AhcCurlRequestLogger())
.addHeader("key", "value")
.addQueryParameter("num", "" + num)
.get()
.thenAccept(r -> {
log.debug(
"Thread#" + num + " Request complete: Response code = " + r.getStatus()
+ " | Response: " + r.getBody() + " | Current Time:"
+ System.currentTimeMillis());
latch.countDown();
})
);
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenLongResponseWhenTimeoutThenHandle() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WSClient ws = play.test.WSTestClient.newClient(port);
Futures futures = app.injector()
.instanceOf(Futures.class);
CompletionStage<Result> f = futures.timeout(
ws.url(url)
.setRequestTimeout(Duration.of(1, SECONDS))
.get()
.thenApply(result -> {
try {
Thread.sleep(2000L);
return Results.ok();
} catch (InterruptedException e) {
return Results.status(
SERVICE_UNAVAILABLE);
}
}), 1L, TimeUnit.SECONDS
);
CompletionStage<Object> res = f.handleAsync((result, e) -> {
if (e != null) {
log.error("Exception thrown", e);
latch.countDown();
return e.getCause();
} else {
return result;
}
});
res.thenAccept(result -> assertEquals(TimeoutException.class, result));
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenMultigigabyteResponseConsumeWithStreams() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
final ActorSystem system = ActorSystem.create();
final ActorMaterializer materializer = ActorMaterializer.create(system);
final Path path = Files.createTempFile("tmp_", ".out");
WSClient ws = play.test.WSTestClient.newClient(port);
log.info("Starting test server on url: " + url);
ws.url(url)
.stream()
.thenAccept(
response -> {
try {
OutputStream outputStream = java.nio.file.Files.newOutputStream(path);
Sink<ByteString, CompletionStage<Done>> outputWriter =
Sink.foreach(bytes -> {
log.info("Reponse: " + bytes.utf8String());
outputStream.write(bytes.toArray());
});
response.getBodyAsSource()
.runWith(outputWriter, materializer);
} catch (IOException e) {
log.error("An error happened while opening the output stream", e);
}
})
.whenComplete((value, error) -> latch.countDown());
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
}