Various test improvements

This commit is contained in:
Arjen Poutsma
2016-03-17 15:42:30 +01:00
parent 5519428d43
commit 2c52731417
7 changed files with 205 additions and 252 deletions

View File

@@ -1,30 +0,0 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.server.reactive;
import reactor.core.publisher.Mono;
/**
* @author Arjen Poutsma
*/
public class EchoHandler implements HttpHandler {
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
return response.setBody(request.getBody());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,13 +20,13 @@ import java.net.URI;
import java.util.Random;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class EchoHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTests {
@@ -43,7 +43,7 @@ public class EchoHandlerIntegrationTests extends AbstractHttpHandlerIntegrationT
@Test
public void echoBytes() throws Exception {
public void echo() throws Exception {
RestTemplate restTemplate = new RestTemplate();
byte[] body = randomBytes();
@@ -53,36 +53,6 @@ public class EchoHandlerIntegrationTests extends AbstractHttpHandlerIntegrationT
assertArrayEquals(body, response.getBody());
}
@Test
public void echoString() throws Exception {
RestTemplate restTemplate = new RestTemplate();
String body = randomString();
RequestEntity<String> request = RequestEntity.post(new URI("http://localhost:" + port)).body(body);
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
assertEquals(body, response.getBody());
}
private String randomString() {
StringBuilder builder = new StringBuilder();
int i = 1;
while (builder.length() < REQUEST_SIZE) {
builder.append(randomChar());
if (i % 5 == 0) {
builder.append(' ');
}
if (i % 80 == 0) {
builder.append('\n');
}
i++;
}
return builder.toString();
}
private char randomChar() {
return (char) (rnd.nextInt(26) + 'a');
}
private byte[] randomBytes() {
byte[] buffer = new byte[REQUEST_SIZE];
@@ -90,4 +60,14 @@ public class EchoHandlerIntegrationTests extends AbstractHttpHandlerIntegrationT
return buffer;
}
/**
* @author Arjen Poutsma
*/
public static class EchoHandler implements HttpHandler {
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
return response.setBody(request.getBody());
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.server.reactive;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferAllocator;
import static org.junit.Assert.assertEquals;
/**
* @author Arjen Poutsma
*/
public class RandomHandler implements HttpHandler {
private static final Log logger = LogFactory.getLog(RandomHandler.class);
public static final int RESPONSE_SIZE = 4096 * 3;
private final Random rnd = new Random();
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
request.getBody().subscribe(new Subscriber<DataBuffer>() {
private Subscription s;
private int requestSize = 0;
@Override
public void onSubscribe(Subscription s) {
this.s = s;
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(DataBuffer bytes) {
requestSize += bytes.readableByteCount();
}
@Override
public void onError(Throwable t) {
logger.error(t);
}
@Override
public void onComplete() {
logger.debug("Complete");
assertEquals(RandomHandlerIntegrationTests.REQUEST_SIZE, requestSize);
}
});
response.getHeaders().setContentLength(RESPONSE_SIZE);
byte[] randomBytes = randomBytes();
DataBuffer buffer =
new DefaultDataBufferAllocator().allocateBuffer(randomBytes.length);
buffer.write(randomBytes);
return response.setBody(Mono.just(buffer));
}
private byte[] randomBytes() {
byte[] buffer = new byte[RESPONSE_SIZE];
rnd.nextBytes(buffer);
return buffer;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,29 +20,48 @@ import java.net.URI;
import java.util.Random;
import org.junit.Test;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferAllocator;
import org.springframework.core.io.buffer.DefaultDataBufferAllocator;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.boot.ReactorHttpServer;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeFalse;
public class RandomHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTests {
public static final int REQUEST_SIZE = 4096 * 3;
private Random rnd = new Random();
public static final int RESPONSE_SIZE = 1024 * 4;
private final Random rnd = new Random();
private final RandomHandler handler = new RandomHandler();
private final DataBufferAllocator allocator = new DefaultDataBufferAllocator();
@Override
protected RandomHandler createHttpHandler() {
return new RandomHandler();
return handler;
}
@Test
public void random() throws Exception {
public void random() throws Throwable {
// TODO: fix Reactor support
assumeFalse(server instanceof ReactorHttpServer);
RestTemplate restTemplate = new RestTemplate();
byte[] body = randomBytes();
@@ -50,9 +69,17 @@ public class RandomHandlerIntegrationTests extends AbstractHttpHandlerIntegratio
ResponseEntity<byte[]> response = restTemplate.exchange(request, byte[].class);
assertNotNull(response.getBody());
assertEquals(RandomHandler.RESPONSE_SIZE,
assertEquals(RESPONSE_SIZE,
response.getHeaders().getContentLength());
assertEquals(RandomHandler.RESPONSE_SIZE, response.getBody().length);
assertEquals(RESPONSE_SIZE, response.getBody().length);
while (!handler.requestComplete) {
Thread.sleep(100);
}
if (handler.requestError != null) {
throw handler.requestError;
}
assertEquals(REQUEST_SIZE, handler.requestSize);
}
@@ -62,4 +89,67 @@ public class RandomHandlerIntegrationTests extends AbstractHttpHandlerIntegratio
return buffer;
}
private class RandomHandler implements HttpHandler {
public static final int CHUNKS = 16;
private volatile boolean requestComplete;
private int requestSize;
private Throwable requestError;
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
requestError = null;
request.getBody().subscribe(new Subscriber<DataBuffer>() {
@Override
public void onSubscribe(Subscription s) {
requestComplete = false;
requestSize = 0;
requestError = null;
s.request(Long.MAX_VALUE);
}
@Override
public void onNext(DataBuffer bytes) {
requestSize += bytes.readableByteCount();
}
@Override
public void onError(Throwable t) {
requestComplete = true;
requestError = t;
}
@Override
public void onComplete() {
requestComplete = true;
}
});
response.getHeaders().setContentLength(RESPONSE_SIZE);
return response.setBody(multipleChunks());
}
private Publisher<DataBuffer> singleChunk() {
return Mono.just(randomBuffer(RESPONSE_SIZE));
}
private Publisher<DataBuffer> multipleChunks() {
int chunkSize = RESPONSE_SIZE / CHUNKS;
return Flux.range(1, CHUNKS).map(integer -> randomBuffer(chunkSize));
}
private DataBuffer randomBuffer(int size) {
byte[] bytes = new byte[size];
rnd.nextBytes(bytes);
DataBuffer buffer = allocator.allocateBuffer(size);
buffer.write(bytes);
return buffer;
}
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.http.server.reactive;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferAllocator;
import org.springframework.core.io.buffer.support.DataBufferUtils;
import org.springframework.http.MediaType;
import static org.junit.Assert.fail;
/**
* @author Arjen Poutsma
*/
public class XmlHandler implements HttpHandler {
private static final Log logger = LogFactory.getLog(XmlHandler.class);
@Override
public Mono<Void> handle(ServerHttpRequest request,
ServerHttpResponse response) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(XmlHandlerIntegrationTests.Person.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Marshaller marshaller = jaxbContext.createMarshaller();
Runnable r = () -> {
try {
InputStream bis = DataBufferUtils.toInputStream(request.getBody());
XmlHandlerIntegrationTests.Person johnDoe =
(XmlHandlerIntegrationTests.Person) unmarshaller.unmarshal(bis);
logger.info("Read: " + johnDoe);
}
catch (Exception e) {
logger.error(e, e);
}
};
Thread t = new Thread(r);
t.start();
response.getHeaders().setContentType(MediaType.APPLICATION_XML);
XmlHandlerIntegrationTests.Person janeDoe = new XmlHandlerIntegrationTests.Person("Jane Doe");
DataBuffer buffer = new DefaultDataBufferAllocator().allocateBuffer();
OutputStream bos = buffer.asOutputStream();
marshaller.marshal(janeDoe, bos);
bos.close();
return response.setBody(Flux.just(buffer));
}
catch (Exception ex) {
logger.error(ex, ex);
fail(ex.getMessage());
return null;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,39 +16,123 @@
package org.springframework.http.server.reactive;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferAllocator;
import org.springframework.core.io.buffer.support.DataBufferUtils;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.boot.ReactorHttpServer;
import org.springframework.http.server.reactive.boot.RxNettyHttpServer;
import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeFalse;
/**
* @author Arjen Poutsma
*/
public class XmlHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTests {
private final XmlHandler handler = new XmlHandler();
@Override
protected HttpHandler createHttpHandler() {
return new XmlHandler();
return handler;
}
@Test
public void xml() throws Exception {
// TODO: fix Reactor and RxNetty support
assumeFalse(server instanceof ReactorHttpServer ||
server instanceof RxNettyHttpServer);
RestTemplate restTemplate = new RestTemplate();
Person johnDoe = new Person("John Doe");
Person janeDoe = new Person("Jane Doe");
RequestEntity<Person> request = RequestEntity.post(new URI("http://localhost:" + port)).body(
johnDoe);
ResponseEntity<Person> response = restTemplate.exchange(request, Person.class);
System.out.println(response.getBody());
assertEquals(janeDoe, response.getBody());
while (!handler.requestComplete) {
Thread.sleep(100);
}
if (handler.requestError != null) {
throw handler.requestError;
}
assertEquals(johnDoe, handler.requestPerson);
}
private static class XmlHandler implements HttpHandler {
private volatile boolean requestComplete = false;
private Person requestPerson;
private Exception requestError;
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
requestError = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Marshaller marshaller = jaxbContext.createMarshaller();
Runnable r = () -> {
try {
InputStream bis =
DataBufferUtils.toInputStream(request.getBody());
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
requestPerson = (Person) unmarshaller.unmarshal(bis);
}
catch (Exception ex) {
requestError = ex;
}
finally {
requestComplete = true;
}
};
Thread t = new Thread(r);
t.start();
response.getHeaders().setContentType(MediaType.APPLICATION_XML);
Person janeDoe = new Person("Jane Doe");
DataBuffer buffer = new DefaultDataBufferAllocator().allocateBuffer();
OutputStream bos = buffer.asOutputStream();
marshaller.marshal(janeDoe, bos);
bos.close();
return response.setBody(Flux.just(buffer));
}
catch (Exception ex) {
return Mono.error(ex);
}
}
}
@XmlRootElement
static class Person {
private static class Person {
private String name;
@@ -82,4 +166,5 @@ public class XmlHandlerIntegrationTests extends AbstractHttpHandlerIntegrationTe
return name;
}
}
}

View File

@@ -25,7 +25,6 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.junit.Ignore;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -170,8 +169,6 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
}
@Test
@Ignore
//FIXME Fail with Jetty and Tomcat
public void streamResult() throws Exception {
RestTemplate restTemplate = new RestTemplate();
@@ -468,7 +465,13 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
@RequestMapping("/stream-result")
public Publisher<Long> stringStreamResponseBody() {
return Flux.interval(Duration.ofMillis(100)).take(5);
/*
TODO: replace the following line with:
return Flux.interval(Duration.ofMillis(100)).take(5);
to make the build last shorter. Unfortunately, this hangs the build as of
20160317.
*/
return Flux.interval(Duration.ofSeconds(1)).take(5);
}
@RequestMapping("/raw-flux")