From 259b2ca5f4de3fd97ae8a06ab6c5b4b49fb69c99 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 5 Sep 2018 11:03:55 +0200 Subject: [PATCH] Added tests for errors in the source stream This commit adds decoder/message-reader tests for errors in the source data buffer publisher. Because the tests extend AbstractDataBufferAllocatingTestCase, they also check whether the buffers that precede the error in the stream are properly released. Issue: SPR-17025 --- .../core/codec/ByteArrayDecoderTests.java | 19 ++++++-- .../core/codec/ByteBufferDecoderTests.java | 20 +++++++-- .../core/codec/ResourceDecoderTests.java | 17 ++++++- .../core/codec/StringDecoderTests.java | 16 +++++++ .../codec/FormHttpMessageReaderTests.java | 27 ++++++++++- ...ServerSentEventHttpMessageReaderTests.java | 45 +++++++++++++++---- 6 files changed, 126 insertions(+), 18 deletions(-) diff --git a/spring-core/src/test/java/org/springframework/core/codec/ByteArrayDecoderTests.java b/spring-core/src/test/java/org/springframework/core/codec/ByteArrayDecoderTests.java index 3ad1c094acd..b350958ba9f 100644 --- a/spring-core/src/test/java/org/springframework/core/codec/ByteArrayDecoderTests.java +++ b/spring-core/src/test/java/org/springframework/core/codec/ByteArrayDecoderTests.java @@ -29,9 +29,7 @@ import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.util.MimeTypeUtils; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * @author Arjen Poutsma @@ -67,6 +65,21 @@ public class ByteArrayDecoderTests extends AbstractDataBufferAllocatingTestCase .verify(); } + @Test + public void decodeError() { + DataBuffer fooBuffer = stringBuffer("foo"); + Flux source = + Flux.just(fooBuffer).mergeWith(Flux.error(new RuntimeException())); + Flux output = this.decoder.decode(source, + ResolvableType.forClassWithGenerics(Publisher.class, byte[].class), + null, Collections.emptyMap()); + + StepVerifier.create(output) + .consumeNextWith(bytes -> assertArrayEquals("foo".getBytes(), bytes)) + .expectError() + .verify(); + } + @Test public void decodeToMono() { DataBuffer fooBuffer = stringBuffer("foo"); diff --git a/spring-core/src/test/java/org/springframework/core/codec/ByteBufferDecoderTests.java b/spring-core/src/test/java/org/springframework/core/codec/ByteBufferDecoderTests.java index 4068822e6af..a40de1a44ad 100644 --- a/spring-core/src/test/java/org/springframework/core/codec/ByteBufferDecoderTests.java +++ b/spring-core/src/test/java/org/springframework/core/codec/ByteBufferDecoderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 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. @@ -30,8 +30,7 @@ import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.util.MimeTypeUtils; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * @author Sebastien Deleuze @@ -65,6 +64,21 @@ public class ByteBufferDecoderTests extends AbstractDataBufferAllocatingTestCase .verify(); } + @Test + public void decodeError() { + DataBuffer fooBuffer = stringBuffer("foo"); + Flux source = + Flux.just(fooBuffer).mergeWith(Flux.error(new RuntimeException())); + Flux output = this.decoder.decode(source, + ResolvableType.forClassWithGenerics(Publisher.class, ByteBuffer.class), + null, Collections.emptyMap()); + + StepVerifier.create(output) + .expectNext(ByteBuffer.wrap("foo".getBytes())) + .expectError() + .verify(); + } + @Test public void decodeToMono() { DataBuffer fooBuffer = stringBuffer("foo"); diff --git a/spring-core/src/test/java/org/springframework/core/codec/ResourceDecoderTests.java b/spring-core/src/test/java/org/springframework/core/codec/ResourceDecoderTests.java index 80c602e26a7..2b79e2a767f 100644 --- a/spring-core/src/test/java/org/springframework/core/codec/ResourceDecoderTests.java +++ b/spring-core/src/test/java/org/springframework/core/codec/ResourceDecoderTests.java @@ -32,7 +32,7 @@ import org.springframework.util.MimeTypeUtils; import org.springframework.util.StreamUtils; import static org.junit.Assert.*; -import static org.springframework.core.ResolvableType.*; +import static org.springframework.core.ResolvableType.forClass; /** * @author Arjen Poutsma @@ -73,4 +73,19 @@ public class ResourceDecoderTests extends AbstractDataBufferAllocatingTestCase { .verify(); } + @Test + public void decodeError() { + DataBuffer fooBuffer = stringBuffer("foo"); + Flux source = + Flux.just(fooBuffer).mergeWith(Flux.error(new RuntimeException())); + + + Flux result = this.decoder + .decode(source, forClass(Resource.class), null, Collections.emptyMap()); + + StepVerifier.create(result) + .expectError() + .verify(); + } + } diff --git a/spring-core/src/test/java/org/springframework/core/codec/StringDecoderTests.java b/spring-core/src/test/java/org/springframework/core/codec/StringDecoderTests.java index 19784605e12..f40bf243422 100644 --- a/spring-core/src/test/java/org/springframework/core/codec/StringDecoderTests.java +++ b/spring-core/src/test/java/org/springframework/core/codec/StringDecoderTests.java @@ -173,6 +173,22 @@ public class StringDecoderTests extends AbstractDataBufferAllocatingTestCase { } + @Test + public void decodeError() { + DataBuffer fooBuffer = stringBuffer("foo\n"); + Flux source = + Flux.just(fooBuffer).mergeWith(Flux.error(new RuntimeException())); + + Flux output = this.decoder.decode(source, + ResolvableType.forClass(String.class), null, Collections.emptyMap()); + + StepVerifier.create(output) + .expectNext("foo") + .expectError() + .verify(); + + } + @Test public void decodeToMono() { Flux source = Flux.just(stringBuffer("foo"), stringBuffer("bar"), stringBuffer("baz")); diff --git a/spring-web/src/test/java/org/springframework/http/codec/FormHttpMessageReaderTests.java b/spring-web/src/test/java/org/springframework/http/codec/FormHttpMessageReaderTests.java index 58c1ef5d349..8b2f151532d 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/FormHttpMessageReaderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/FormHttpMessageReaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,8 +20,14 @@ import java.util.List; import java.util.Map; import org.junit.Test; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase; +import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -34,7 +40,7 @@ import static org.junit.Assert.*; /** * @author Sebastien Deleuze */ -public class FormHttpMessageReaderTests { +public class FormHttpMessageReaderTests extends AbstractDataBufferAllocatingTestCase { private final FormHttpMessageReader reader = new FormHttpMessageReader(); @@ -96,8 +102,25 @@ public class FormHttpMessageReaderTests { assertNull("Invalid result", result.getFirst("name 3")); } + @Test + public void readFormError() { + DataBuffer fooBuffer = stringBuffer("name=value"); + Flux body = + Flux.just(fooBuffer).mergeWith(Flux.error(new RuntimeException())); + MockServerHttpRequest request = request(body); + + Flux> result = this.reader.read(null, request, null); + StepVerifier.create(result) + .expectError() + .verify(); + } + private MockServerHttpRequest request(String body) { + return request(Mono.just(stringBuffer(body))); + } + + private MockServerHttpRequest request(Publisher body) { return MockServerHttpRequest .method(HttpMethod.GET, "/") .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) diff --git a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java index 64b94b28d4f..f8a6d902b79 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageReaderTests.java @@ -21,10 +21,12 @@ import java.util.Collections; import org.junit.Test; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import org.springframework.core.ResolvableType; import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase; +import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.MediaType; import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; @@ -57,9 +59,10 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll @Test public void readServerSentEvents() { - MockServerHttpRequest request = MockServerHttpRequest.post("/").body( - "id:c42\nevent:foo\nretry:123\n:bla\n:bla bla\n:bla bla bla\ndata:bar\n\n" + - "id:c43\nevent:bar\nretry:456\ndata:baz\n\n"); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .body(Mono.just(stringBuffer( + "id:c42\nevent:foo\nretry:123\n:bla\n:bla bla\n:bla bla bla\ndata:bar\n\n" + + "id:c43\nevent:bar\nretry:456\ndata:baz\n\n"))); Flux events = this.messageReader .read(ResolvableType.forClassWithGenerics(ServerSentEvent.class, String.class), @@ -117,8 +120,9 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll @Test public void readString() { - String body = "data:foo\ndata:bar\n\ndata:baz\n\n"; - MockServerHttpRequest request = MockServerHttpRequest.post("/").body(body); + + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .body(Mono.just(stringBuffer("data:foo\ndata:bar\n\ndata:baz\n\n"))); Flux data = messageReader.read(ResolvableType.forClass(String.class), request, Collections.emptyMap()).cast(String.class); @@ -132,9 +136,10 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll @Test public void readPojo() { - MockServerHttpRequest request = MockServerHttpRequest.post("/").body( - "data:{\"foo\": \"foofoo\", \"bar\": \"barbar\"}\n\n" + - "data:{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}\n\n"); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .body(Mono.just(stringBuffer( + "data:{\"foo\": \"foofoo\", \"bar\": \"barbar\"}\n\n" + + "data:{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}\n\n"))); Flux data = messageReader.read(ResolvableType.forClass(Pojo.class), request, Collections.emptyMap()).cast(Pojo.class); @@ -155,7 +160,8 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll @Test // SPR-15331 public void decodeFullContentAsString() { String body = "data:foo\ndata:bar\n\ndata:baz\n\n"; - MockServerHttpRequest request = MockServerHttpRequest.post("/").body(body); + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .body(Mono.just(stringBuffer(body))); String actual = messageReader .readMono(ResolvableType.forClass(String.class), request, Collections.emptyMap()) @@ -165,4 +171,25 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractDataBufferAll assertEquals(body, actual); } + @Test + public void readError() { + + Flux body = + Flux.just(stringBuffer("data:foo\ndata:bar\n\ndata:baz\n\n")) + .mergeWith(Flux.error(new RuntimeException())); + + MockServerHttpRequest request = MockServerHttpRequest.post("/") + .body(body); + + Flux data = messageReader.read(ResolvableType.forClass(String.class), + request, Collections.emptyMap()).cast(String.class); + + StepVerifier.create(data) + .expectNextMatches(elem -> elem.equals("foo\nbar")) + .expectNextMatches(elem -> elem.equals("baz")) + .expectError() + .verify(); + } + + }