Add support for webflux
MVC and Webflux share some common business logic so it makes sense to put them in the same module. Also simplifies the MVC code, removing the custom argument and return value handlers. Weed out unecessary method param Unignore some tests
This commit is contained in:
committed by
Oleg Zhurakousky
parent
ed14474b9f
commit
7dd38edf84
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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.cloud.function.flux;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.flux.FluxRestApplicationTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Tests for vanilla MVC handling (no function layer). Validates the MVC customizations
|
||||
* that are added in this project independently of the specific concerns of function.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = TestConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive")
|
||||
public class FluxRestApplicationTests {
|
||||
|
||||
private static final MediaType EVENT_STREAM = MediaType.valueOf("text/event-stream");
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
@Autowired
|
||||
private TestConfiguration test;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
test.list.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsSSE() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(),
|
||||
String.class).getBody()).isEqualTo(sse("foo", "bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/words"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Fix error handling")
|
||||
public void errorJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/bang"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void words() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/words")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foos() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/foos")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMore() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/get/more")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Should this even work? Or do we need to be explicit about the JSON?")
|
||||
public void updates() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.post(new URI("/updates")).body("one\ntwo"), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isEqualTo("onetwo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatesJson() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"one\",\"two\"]"), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isEqualTo("[\"one\",\"two\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addFoos() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/addFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeout() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/timeout")).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/empty"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentences() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/sentences")).build(), String.class)
|
||||
.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptAny() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(),
|
||||
String.class).getBody())
|
||||
.isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptJson() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(
|
||||
RequestEntity.get(new URI("/sentences"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
assertThat(result.getHeaders().getContentType())
|
||||
.isGreaterThanOrEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercase() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/uppercase")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseFoos() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transform() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/transform")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postMore() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/post/more")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseGet() throws Exception {
|
||||
assertThat(rest.exchange(RequestEntity.get(new URI("/uppercase/foo"))
|
||||
.accept(MediaType.TEXT_PLAIN).build(), String.class).getBody())
|
||||
.isEqualTo("[FOO]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGet() throws Exception {
|
||||
assertThat(rest.exchange(RequestEntity.get(new URI("/wrap/123"))
|
||||
.accept(MediaType.TEXT_PLAIN).build(), String.class).getBody())
|
||||
.isEqualTo("..123..");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGetJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/entity/321"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("{\"value\":321}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseJsonStream() throws Exception {
|
||||
assertThat(
|
||||
rest.exchange(
|
||||
RequestEntity.post(new URI("/maps"))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"),
|
||||
String.class).getBody())
|
||||
.isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseSSE() throws Exception {
|
||||
assertThat(rest.exchange(RequestEntity.post(new URI("/uppercase"))
|
||||
.accept(EVENT_STREAM).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class).getBody())
|
||||
.isEqualTo(sse("[FOO]", "[BAR]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void altSSE() throws Exception {
|
||||
assertThat(rest.exchange(RequestEntity.post(new URI("/alt")).accept(EVENT_STREAM)
|
||||
.contentType(MediaType.APPLICATION_JSON).body("[\"foo\",\"bar\"]"),
|
||||
String.class).getBody()).isEqualTo(sse("[FOO]", "[BAR]"));
|
||||
}
|
||||
|
||||
private String sse(String... values) {
|
||||
return "data:" + StringUtils.arrayToDelimitedString(values, "\n\ndata:") + "\n\n";
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
@Configuration
|
||||
public static class TestConfiguration {
|
||||
|
||||
private List<String> list = new ArrayList<>();
|
||||
|
||||
@PostMapping({ "/uppercase", "/transform", "/post/more" })
|
||||
public Flux<?> uppercase(@RequestBody List<String> flux) {
|
||||
return Flux.fromIterable(flux).log()
|
||||
.map(value -> "[" + value.trim().toUpperCase() + "]");
|
||||
}
|
||||
|
||||
@PostMapping({ "/alt" })
|
||||
public Mono<ResponseEntity<?>> alt(@RequestBody List<String> flux) {
|
||||
Publisher<?> result = Flux.fromIterable(flux)
|
||||
.map(value -> "[" + value.trim().toUpperCase() + "]");
|
||||
return Flux.from(result).log()
|
||||
.then(Mono.fromSupplier(() -> ResponseEntity.ok(result)));
|
||||
}
|
||||
|
||||
@PostMapping("/upFoos")
|
||||
public Flux<Foo> upFoos(@RequestBody List<Foo> list) {
|
||||
return Flux.fromIterable(list).log()
|
||||
.map(value -> new Foo(value.getValue().trim().toUpperCase()));
|
||||
}
|
||||
|
||||
@GetMapping("/uppercase/{id}")
|
||||
public Mono<ResponseEntity<?>> uppercaseGet(@PathVariable String id) {
|
||||
return Mono.just(id).map(value -> "[" + value.trim().toUpperCase() + "]")
|
||||
.flatMap(body -> Mono.just(ResponseEntity.ok(body)));
|
||||
}
|
||||
|
||||
@GetMapping("/wrap/{id}")
|
||||
public Mono<ResponseEntity<?>> wrapGet(@PathVariable int id) {
|
||||
return Mono.just(id).log().map(value -> ".." + value + "..")
|
||||
.flatMap(body -> Mono.just(ResponseEntity.ok(body)));
|
||||
}
|
||||
|
||||
@GetMapping("/entity/{id}")
|
||||
public Mono<Map<String, Object>> entity(@PathVariable Integer id) {
|
||||
return Mono.just(id).log()
|
||||
.map(value -> Collections.singletonMap("value", value));
|
||||
}
|
||||
|
||||
@PostMapping("/maps")
|
||||
public Flux<Map<String, String>> maps(
|
||||
@RequestBody List<Map<String, String>> flux) {
|
||||
return Flux.fromIterable(flux).map(value -> {
|
||||
value.put("value", value.get("value").trim().toUpperCase());
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@GetMapping({ "/words", "/get/more" })
|
||||
public Flux<Object> words() {
|
||||
return Flux.fromArray(new String[] { "foo", "bar" });
|
||||
}
|
||||
|
||||
@GetMapping("/foos")
|
||||
public Flux<Foo> foos() {
|
||||
return Flux.just(new Foo("foo"), new Foo("bar"));
|
||||
}
|
||||
|
||||
@PostMapping("/updates")
|
||||
@ResponseStatus(HttpStatus.ACCEPTED)
|
||||
public Flux<?> updates(@RequestBody List<String> list) {
|
||||
Flux<String> flux = Flux.fromIterable(list).cache();
|
||||
flux.subscribe(value -> this.list.add(value));
|
||||
return flux;
|
||||
}
|
||||
|
||||
@PostMapping("/addFoos")
|
||||
@ResponseStatus(HttpStatus.ACCEPTED)
|
||||
public Flux<Foo> addFoos(@RequestBody List<Foo> list) {
|
||||
Flux<Foo> flux = Flux.fromIterable(list).cache();
|
||||
flux.subscribe(value -> this.list.add(value.getValue()));
|
||||
return flux;
|
||||
}
|
||||
|
||||
@GetMapping("/bang")
|
||||
public Flux<?> bang() {
|
||||
return Flux.fromArray(new String[] { "foo", "bar" }).map(value -> {
|
||||
if (value.equals("bar")) {
|
||||
throw new RuntimeException("Bar");
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@GetMapping("/empty")
|
||||
public Flux<?> empty() {
|
||||
return Flux.fromIterable(Collections.emptyList());
|
||||
}
|
||||
|
||||
@GetMapping("/timeout")
|
||||
public Flux<?> timeout() {
|
||||
return Flux.defer(() -> Flux.<String>create(emitter -> {
|
||||
emitter.next("foo");
|
||||
}).timeout(Duration.ofMillis(100L), Flux.empty()));
|
||||
}
|
||||
|
||||
@GetMapping("/sentences")
|
||||
public Flux<List<String>> sentences() {
|
||||
return Flux.just(Arrays.asList("go", "home"), Arrays.asList("come", "back"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
private String value;
|
||||
|
||||
public Foo(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
Foo() {
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,8 +61,8 @@ import reactor.core.publisher.Mono;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@SpringBootTest(classes = TestConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=servlet")
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = TestConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class MvcRestApplicationTests {
|
||||
|
||||
private static final MediaType EVENT_STREAM = MediaType.valueOf("text/event-stream");
|
||||
@@ -253,11 +253,13 @@ public class MvcRestApplicationTests {
|
||||
|
||||
@Test
|
||||
public void uppercaseJsonStream() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.post(new URI("/maps"))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class)
|
||||
.getBody()).isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||
assertThat(
|
||||
rest.exchange(
|
||||
RequestEntity.post(new URI("/maps"))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"),
|
||||
String.class).getBody())
|
||||
.isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -13,34 +13,41 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.function.web;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
package org.springframework.cloud.function.web.flux;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.flux.HeadersToMessageTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"spring.cloud.function.web.path=/functions" })
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"spring.cloud.function.web.path=/functions",
|
||||
"spring.main.web-application-type=reactive" })
|
||||
@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class})
|
||||
public class HeadersToMessageTests {
|
||||
|
||||
@Autowired
|
||||
@@ -48,26 +55,27 @@ public class HeadersToMessageTests {
|
||||
|
||||
@Test
|
||||
public void testBodyAndCustomHeaderFromMessagePropagation() throws Exception {
|
||||
ResponseEntity<String> postForEntity = rest.postForEntity(new URI("/functions/employee"), "{\"name\":\"Bob\",\"age\":25}", String.class);
|
||||
ResponseEntity<String> postForEntity = rest.postForEntity(
|
||||
new URI("/functions/employee"), "{\"name\":\"Bob\",\"age\":25}",
|
||||
String.class);
|
||||
assertEquals("{\"name\":\"Bob\",\"age\":25}", postForEntity.getBody());
|
||||
assertTrue(postForEntity.getHeaders().containsKey("x-content-type"));
|
||||
assertEquals("application/xml", postForEntity.getHeaders().get("x-content-type").get(0));
|
||||
assertEquals("application/xml",
|
||||
postForEntity.getHeaders().get("x-content-type").get(0));
|
||||
assertEquals("bar", postForEntity.getHeaders().get("foo").get(0));
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@org.springframework.boot.test.context.TestConfiguration
|
||||
protected static class TestConfiguration {
|
||||
@Bean({ "employee"})
|
||||
public Function<Message<String>, Message<String>> function() {
|
||||
@Bean({ "employee" })
|
||||
public Function<Message<String>, Message<String>> function() {
|
||||
return request -> {
|
||||
Message<String> message = MessageBuilder.withPayload(request.getPayload())
|
||||
.setHeader("X-Content-Type", "application/xml")
|
||||
.setHeader("foo", "bar")
|
||||
.build();
|
||||
.setHeader("foo", "bar").build();
|
||||
return message;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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.cloud.function.web.flux;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.flux.HttpGetIntegrationTests.ApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive")
|
||||
@ContextConfiguration(classes= {RestApplication.class, ApplicationConfiguration.class})
|
||||
public class HttpGetIntegrationTests {
|
||||
|
||||
private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM;
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
@Autowired
|
||||
private ApplicationConfiguration test;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
test.list.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staticResource() {
|
||||
assertThat(rest.getForObject("/test.html", String.class)).contains("<body>Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsSSE() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(),
|
||||
String.class).getBody()).isEqualTo(sse("foo", "bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/words"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Fix error handling")
|
||||
public void errorJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/bang"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void words() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/words")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void word() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.get(new URI("/word")).accept(MediaType.TEXT_PLAIN).build(),
|
||||
String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foos() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/foos")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMore() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/get/more")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareWords() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/bareWords")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeoutJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/timeout"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/empty"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentences() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/sentences")).build(), String.class)
|
||||
.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptAny() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(),
|
||||
String.class).getBody())
|
||||
.isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptJson() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(
|
||||
RequestEntity.get(new URI("/sentences"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
assertThat(result.getHeaders().getContentType())
|
||||
.isGreaterThanOrEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptSse() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.get(new URI("/sentences")).accept(EVENT_STREAM).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo(sse("[\"go\",\"home\"]", "[\"come\",\"back\"]"));
|
||||
assertThat(result.getHeaders().getContentType().isCompatibleWith(EVENT_STREAM))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postMoreFoo() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.get(new URI("/post/more/foo")).accept(MediaType.TEXT_PLAIN).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("(FOO)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseGet() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.get(new URI("/uppercase/foo")).accept(MediaType.TEXT_PLAIN).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("(FOO)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGet() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.get(new URI("/wrap/123")).accept(MediaType.TEXT_PLAIN).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("..123..");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supplierFirst() {
|
||||
assertThat(rest.getForObject("/not/a/function", String.class))
|
||||
.isEqualTo("[\"hello\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGetJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/entity/321"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("{\"value\":321}");
|
||||
}
|
||||
|
||||
private String sse(String... values) {
|
||||
return "data:" + StringUtils.arrayToDelimitedString(values, "\n\ndata:") + "\n\n";
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@TestConfiguration
|
||||
public static class ApplicationConfiguration {
|
||||
|
||||
private List<String> list = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(HttpGetIntegrationTests.ApplicationConfiguration.class,
|
||||
args);
|
||||
}
|
||||
|
||||
@Bean({ "uppercase", "post/more" })
|
||||
public Function<Flux<String>, Flux<String>> uppercase() {
|
||||
return flux -> flux.log()
|
||||
.map(value -> "(" + value.trim().toUpperCase() + ")");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Integer>, Flux<String>> wrap() {
|
||||
return flux -> flux.log().map(value -> ".." + value + "..");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Integer>, Flux<Map<String, Object>>> entity() {
|
||||
return flux -> flux.log()
|
||||
.map(value -> Collections.singletonMap("value", value));
|
||||
}
|
||||
|
||||
@Bean({ "words", "get/more" })
|
||||
public Supplier<Flux<String>> words() {
|
||||
return () -> Flux.just("foo", "bar");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<String> word() {
|
||||
return () -> "foo";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<Foo>> foos() {
|
||||
return () -> Flux.just(new Foo("foo"), new Foo("bar"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<List<String>> bareWords() {
|
||||
return () -> Arrays.asList("foo", "bar");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> bang() {
|
||||
return () -> Flux.fromArray(new String[] { "foo", "bar" }).map(value -> {
|
||||
if (value.equals("bar")) {
|
||||
throw new RuntimeException("Bar");
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> empty() {
|
||||
return () -> Flux.fromIterable(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Bean("not/a/function")
|
||||
public Supplier<Flux<String>> supplier() {
|
||||
return () -> Flux.just("hello");
|
||||
}
|
||||
|
||||
@Bean("not/a")
|
||||
public Function<Flux<String>, Flux<String>> function() {
|
||||
return input -> Flux.just("bye");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> timeout() {
|
||||
return () -> Flux.defer(() -> Flux.<String>create(emitter -> {
|
||||
emitter.next("foo");
|
||||
}).timeout(Duration.ofMillis(100L), Flux.empty()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<List<String>>> sentences() {
|
||||
return () -> Flux.just(Arrays.asList("go", "home"),
|
||||
Arrays.asList("come", "back"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<MultiValueMap<String, String>, Map<String, Integer>> sum() {
|
||||
return valueMap -> valueMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, values -> values
|
||||
.getValue().stream().mapToInt(Integer::parseInt).sum()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
private String value;
|
||||
|
||||
public Foo(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
Foo() {
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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.cloud.function.web.flux;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.flux.HttpPostIntegrationTests.ApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive")
|
||||
@ContextConfiguration(classes = { RestApplication.class, ApplicationConfiguration.class })
|
||||
public class HttpPostIntegrationTests {
|
||||
|
||||
private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM;
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
@Autowired
|
||||
private ApplicationConfiguration test;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
test.list.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifierFoos() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity.post(new URI("/foos"))
|
||||
.contentType(MediaType.APPLICATION_JSON).body("[\"foo\",\"bar\"]"),
|
||||
String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"[FOO]\"},{\"value\":\"[BAR]\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updates() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.post(new URI("/updates")).body("[\"one\", \"two\"]"),
|
||||
String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatesJson() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"one\",\"two\"]"), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addFoos() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/addFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareUpdates() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/bareUpdates")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"one\",\"two\"]"), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercase() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/uppercase")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messages() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/messages")).contentType(MediaType.APPLICATION_JSON)
|
||||
.header("x-foo", "bar").body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getHeaders().getFirst("x-foo")).isEqualTo("bar");
|
||||
assertThat(result.getHeaders()).doesNotContainKey("id");
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headers() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/headers")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getHeaders().getFirst("foo")).isEqualTo("bar");
|
||||
assertThat(result.getHeaders()).doesNotContainKey("id");
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseSingleValue() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(
|
||||
RequestEntity.post(new URI("/uppercase"))
|
||||
.contentType(MediaType.TEXT_PLAIN).body("foo"),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("WebFlux would split the request body into lines: TODO make this work the same")
|
||||
public void uppercasePlainText() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.post(new URI("/uppercase"))
|
||||
.contentType(MediaType.TEXT_PLAIN).body("foo\nbar"),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("(FOO\nBAR)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseFoos() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseFoo() throws Exception {
|
||||
// Single Foo can be parsed
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("{\"value\":\"foo\"}"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[{\"value\":\"FOO\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareUppercaseFoos() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareUppercaseFoo() throws Exception {
|
||||
// Single Foo can be parsed and returns a single value if the function is defined
|
||||
// that way
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("{\"value\":\"foo\"}"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("{\"value\":\"FOO\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareUppercase() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/bareUppercase")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleValuedText() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.post(new URI("/bareUppercase")).accept(MediaType.TEXT_PLAIN)
|
||||
.contentType(MediaType.TEXT_PLAIN).body("foo"),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("(FOO)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transform() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/transform")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postMore() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/post/more")).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertPost() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity.post(new URI("/wrap"))
|
||||
.contentType(MediaType.TEXT_PLAIN).body("123"), String.class);
|
||||
// Result is multi-valued so it has to come out as an array
|
||||
assertThat(result.getBody()).isEqualTo("[\"..123..\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertPostJson() throws Exception {
|
||||
// If you POST a single value to a Function<Flux<Integer>,Flux<Integer>> it can't
|
||||
// determine if the output is single valued, so it has to send an array back
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(
|
||||
RequestEntity.post(new URI("/doubler"))
|
||||
.contentType(MediaType.TEXT_PLAIN).body("123"),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[246]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseJsonArray() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.post(new URI("/maps"))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
// The new line in the middle is optional
|
||||
.body("[{\"value\":\"foo\"},\n{\"value\":\"bar\"}]"),
|
||||
String.class).getBody())
|
||||
.isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseSSE() throws Exception {
|
||||
assertThat(rest.exchange(RequestEntity.post(new URI("/uppercase"))
|
||||
.accept(EVENT_STREAM).contentType(MediaType.APPLICATION_JSON)
|
||||
.body("[\"foo\",\"bar\"]"), String.class).getBody())
|
||||
.isEqualTo(sse("(FOO)", "(BAR)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sum() throws Exception {
|
||||
|
||||
LinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
|
||||
map.put("A", Arrays.asList("1", "2", "3"));
|
||||
map.put("B", Arrays.asList("5", "6"));
|
||||
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.post(new URI("/sum")).accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED).body(map),
|
||||
String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void count() throws Exception {
|
||||
List<String> list = Arrays.asList("A", "B", "A");
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.post(new URI("/count")).accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON).body(list),
|
||||
String.class).getBody()).isEqualTo("{\"A\":2,\"B\":1}");
|
||||
}
|
||||
|
||||
private String sse(String... values) {
|
||||
return "data:" + StringUtils.arrayToDelimitedString(values, "\n\ndata:") + "\n\n";
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@TestConfiguration
|
||||
public static class ApplicationConfiguration {
|
||||
|
||||
private List<String> list = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(HttpPostIntegrationTests.ApplicationConfiguration.class,
|
||||
args);
|
||||
}
|
||||
|
||||
@Bean({ "uppercase", "transform", "post/more" })
|
||||
public Function<Flux<String>, Flux<String>> uppercase() {
|
||||
return flux -> flux.log()
|
||||
.map(value -> "(" + value.trim().toUpperCase() + ")");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<String, String> bareUppercase() {
|
||||
return value -> "(" + value.trim().toUpperCase() + ")";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Message<String>, Message<String>> messages() {
|
||||
return value -> MessageBuilder
|
||||
.withPayload("(" + value.getPayload().trim().toUpperCase() + ")")
|
||||
.copyHeaders(value.getHeaders()).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Message<String>>, Flux<Message<String>>> headers() {
|
||||
return flux -> flux.map(value -> MessageBuilder
|
||||
.withPayload("(" + value.getPayload().trim().toUpperCase() + ")")
|
||||
.setHeader("foo", "bar").build());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Foo>, Flux<Foo>> upFoos() {
|
||||
return flux -> flux.log()
|
||||
.map(value -> new Foo(value.getValue().trim().toUpperCase()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Foo, Foo> bareUpFoos() {
|
||||
return value -> new Foo(value.getValue().trim().toUpperCase());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Integer>, Flux<String>> wrap() {
|
||||
return flux -> flux.log().map(value -> ".." + value + "..");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Integer>, Flux<Integer>> doubler() {
|
||||
return flux -> flux.log().map(value -> 2 * value);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<HashMap<String, String>>, Flux<Map<String, String>>> maps() {
|
||||
return flux -> flux.map(value -> {
|
||||
value.put("value", value.get("value").trim().toUpperCase());
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Qualifier("foos")
|
||||
public Function<String, Foo> qualifier() {
|
||||
return value -> new Foo("[" + value.trim().toUpperCase() + "]");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Consumer<Flux<String>> updates() {
|
||||
return flux -> flux.subscribe(value -> list.add(value));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Consumer<Flux<Foo>> addFoos() {
|
||||
return flux -> flux.subscribe(value -> list.add(value.getValue()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Consumer<String> bareUpdates() {
|
||||
return value -> list.add(value);
|
||||
}
|
||||
|
||||
@Bean("not/a")
|
||||
public Function<Flux<String>, Flux<String>> function() {
|
||||
return input -> Flux.just("bye");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<MultiValueMap<String, String>, Map<String, Integer>> sum() {
|
||||
return valueMap -> valueMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, values -> values
|
||||
.getValue().stream().mapToInt(Integer::parseInt).sum()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<String>, Mono<Map<String, Integer>>> count() {
|
||||
return flux -> flux.collect(HashMap::new,
|
||||
(map, word) -> map.merge(word, 1, Integer::sum));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
private String value;
|
||||
|
||||
public Foo(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
Foo() {
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.web;
|
||||
package org.springframework.cloud.function.web.flux;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.function.Supplier;
|
||||
@@ -28,10 +28,13 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.flux.PrefixTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -44,7 +47,9 @@ import reactor.core.publisher.Flux;
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"spring.main.web-application-type=reactive",
|
||||
"spring.cloud.function.web.path=/functions", "debug" })
|
||||
@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class})
|
||||
public class PrefixTests {
|
||||
|
||||
@LocalServerPort
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2012-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.cloud.function.web.flux;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.flux.SingletonTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive")
|
||||
@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class})
|
||||
public class SingletonTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
|
||||
@Test
|
||||
public void words() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/words")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@org.springframework.boot.test.context.TestConfiguration
|
||||
protected static class TestConfiguration {
|
||||
@Bean
|
||||
public static BeanDefinitionRegistryPostProcessor processor() {
|
||||
return new BeanDefinitionRegistryPostProcessor() {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(
|
||||
ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(
|
||||
BeanDefinitionRegistry registry) throws BeansException {
|
||||
// Simulates what happens when you add a compiled function
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
MySupplier.class);
|
||||
registry.registerBeanDefinition("words", beanDefinition);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static class MySupplier implements Supplier<Flux<String>> {
|
||||
@Override
|
||||
public Flux<String> get() {
|
||||
return Flux.just("foo", "bar");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.web;
|
||||
package org.springframework.cloud.function.web.mvc;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.function.Function;
|
||||
@@ -29,10 +29,13 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.mvc.DefaultRouteTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -45,6 +48,7 @@ import reactor.core.publisher.Flux;
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "")
|
||||
@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class})
|
||||
public class DefaultRouteTests {
|
||||
|
||||
@LocalServerPort
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.cloud.function.web.mvc;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.mvc.HeadersToMessageTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"spring.main.web-application-type=servlet", "spring.cloud.function.web.path=/functions" })
|
||||
@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class})
|
||||
public class HeadersToMessageTests {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
|
||||
@Test
|
||||
public void testBodyAndCustomHeaderFromMessagePropagation() throws Exception {
|
||||
ResponseEntity<String> postForEntity = rest.postForEntity(
|
||||
new URI("/functions/employee"), "{\"name\":\"Bob\",\"age\":25}",
|
||||
String.class);
|
||||
assertEquals("{\"name\":\"Bob\",\"age\":25}", postForEntity.getBody());
|
||||
assertTrue(postForEntity.getHeaders().containsKey("x-content-type"));
|
||||
assertEquals("application/xml",
|
||||
postForEntity.getHeaders().get("x-content-type").get(0));
|
||||
assertEquals("bar", postForEntity.getHeaders().get("foo").get(0));
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@org.springframework.boot.test.context.TestConfiguration
|
||||
protected static class TestConfiguration {
|
||||
@Bean({ "employee" })
|
||||
public Function<Message<Map<String, Object>>, Message<Map<String, Object>>> function() {
|
||||
return request -> {
|
||||
Message<Map<String, Object>> message = MessageBuilder
|
||||
.withPayload(request.getPayload())
|
||||
.setHeader("X-Content-Type", "application/xml")
|
||||
.setHeader("foo", "bar").build();
|
||||
return message;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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.cloud.function.web.mvc;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.mvc.HttpGetIntegrationTests.ApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties="spring.main.web-application-type=servlet")
|
||||
@ContextConfiguration(classes= {RestApplication.class, ApplicationConfiguration.class})
|
||||
public class HttpGetIntegrationTests {
|
||||
|
||||
private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM;
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
@Autowired
|
||||
private ApplicationConfiguration test;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
test.list.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staticResource() {
|
||||
assertThat(rest.getForObject("/test.html", String.class)).contains("<body>Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsSSE() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(),
|
||||
String.class).getBody()).isEqualTo(sse("foo", "bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/words"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Fix error handling")
|
||||
public void errorJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/bang"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void words() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/words")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void word() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/word")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foos() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/foos")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMore() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/get/more")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareWords() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/bareWords")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeoutJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/timeout"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/empty"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentences() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/sentences")).build(), String.class)
|
||||
.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptAny() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(),
|
||||
String.class).getBody())
|
||||
.isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptJson() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(
|
||||
RequestEntity.get(new URI("/sentences"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
assertThat(result.getHeaders().getContentType())
|
||||
.isGreaterThanOrEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptSse() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.get(new URI("/sentences")).accept(EVENT_STREAM).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo(sse("[\"go\",\"home\"]", "[\"come\",\"back\"]"));
|
||||
assertThat(result.getHeaders().getContentType().isCompatibleWith(EVENT_STREAM))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postMoreFoo() {
|
||||
assertThat(rest.getForObject("/post/more/foo", String.class)).isEqualTo("(FOO)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseGet() {
|
||||
assertThat(rest.getForObject("/uppercase/foo", String.class)).isEqualTo("(FOO)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGet() {
|
||||
assertThat(rest.getForObject("/wrap/123", String.class)).isEqualTo("..123..");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supplierFirst() {
|
||||
assertThat(rest.getForObject("/not/a/function", String.class))
|
||||
.isEqualTo("[\"hello\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGetJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/entity/321"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("{\"value\":321}");
|
||||
}
|
||||
|
||||
private String sse(String... values) {
|
||||
return "data:" + StringUtils.arrayToDelimitedString(values, "\n\ndata:") + "\n\n";
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@TestConfiguration
|
||||
public static class ApplicationConfiguration {
|
||||
|
||||
private List<String> list = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(HttpGetIntegrationTests.ApplicationConfiguration.class,
|
||||
args);
|
||||
}
|
||||
|
||||
@Bean({ "uppercase", "post/more" })
|
||||
public Function<Flux<String>, Flux<String>> uppercase() {
|
||||
return flux -> flux.log()
|
||||
.map(value -> "(" + value.trim().toUpperCase() + ")");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Integer>, Flux<String>> wrap() {
|
||||
return flux -> flux.log().map(value -> ".." + value + "..");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Integer>, Flux<Map<String, Object>>> entity() {
|
||||
return flux -> flux.log()
|
||||
.map(value -> Collections.singletonMap("value", value));
|
||||
}
|
||||
|
||||
@Bean({ "words", "get/more" })
|
||||
public Supplier<Flux<String>> words() {
|
||||
return () -> Flux.just("foo", "bar");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<String> word() {
|
||||
return () -> "foo";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<Foo>> foos() {
|
||||
return () -> Flux.just(new Foo("foo"), new Foo("bar"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<List<String>> bareWords() {
|
||||
return () -> Arrays.asList("foo", "bar");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> bang() {
|
||||
return () -> Flux.fromArray(new String[] { "foo", "bar" }).map(value -> {
|
||||
if (value.equals("bar")) {
|
||||
throw new RuntimeException("Bar");
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> empty() {
|
||||
return () -> Flux.fromIterable(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Bean("not/a/function")
|
||||
public Supplier<Flux<String>> supplier() {
|
||||
return () -> Flux.just("hello");
|
||||
}
|
||||
|
||||
@Bean("not/a")
|
||||
public Function<Flux<String>, Flux<String>> function() {
|
||||
return input -> Flux.just("bye");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> timeout() {
|
||||
return () -> Flux.defer(() -> Flux.<String>create(emitter -> {
|
||||
emitter.next("foo");
|
||||
}).timeout(Duration.ofMillis(100L), Flux.empty()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<List<String>>> sentences() {
|
||||
return () -> Flux.just(Arrays.asList("go", "home"),
|
||||
Arrays.asList("come", "back"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<MultiValueMap<String, String>, Map<String, Integer>> sum() {
|
||||
return valueMap -> valueMap.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, values -> values
|
||||
.getValue().stream().mapToInt(Integer::parseInt).sum()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
private String value;
|
||||
|
||||
public Foo(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
Foo() {
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,19 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.function.web;
|
||||
package org.springframework.cloud.function.web.mvc;
|
||||
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -42,6 +39,8 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.mvc.HttpPostIntegrationTests.ApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -49,6 +48,7 @@ import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -63,8 +63,9 @@ import reactor.core.publisher.Mono;
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class RestApplicationTests {
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties="spring.main.web-application-type=servlet")
|
||||
@ContextConfiguration(classes= {RestApplication.class, ApplicationConfiguration.class})
|
||||
public class HttpPostIntegrationTests {
|
||||
|
||||
private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM;
|
||||
@LocalServerPort
|
||||
@@ -78,61 +79,6 @@ public class RestApplicationTests {
|
||||
public void init() {
|
||||
test.list.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void staticResource() {
|
||||
assertThat(rest.getForObject("/test.html", String.class)).contains("<body>Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsSSE() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(),
|
||||
String.class).getBody()).isEqualTo(sse("foo", "bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wordsJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/words"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Fix error handling")
|
||||
public void errorJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/bang"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void words() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/words")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void word() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/word")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foos() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/foos")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifierFoos() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity.post(new URI("/foos"))
|
||||
@@ -144,29 +90,13 @@ public class RestApplicationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMore() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/get/more")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareWords() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/bareWords")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Should this even work? Or do we need to be explicit about the JSON?")
|
||||
public void updates() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.post(new URI("/updates")).body("one\ntwo"), String.class);
|
||||
RequestEntity.post(new URI("/updates")).body("[\"one\", \"two\"]"),
|
||||
String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isEqualTo("onetwo");
|
||||
assertThat(result.getBody()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -176,7 +106,7 @@ public class RestApplicationTests {
|
||||
.body("[\"one\",\"two\"]"), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody()).isEqualTo("[\"one\",\"two\"]");
|
||||
assertThat(result.getBody()).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -187,7 +117,7 @@ public class RestApplicationTests {
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
|
||||
assertThat(test.list).hasSize(2);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]");
|
||||
.isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,60 +130,6 @@ public class RestApplicationTests {
|
||||
assertThat(result.getBody()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeoutJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/timeout"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[\"foo\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/empty"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentences() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/sentences")).build(), String.class)
|
||||
.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptAny() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(),
|
||||
String.class).getBody())
|
||||
.isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptJson() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(
|
||||
RequestEntity.get(new URI("/sentences"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]");
|
||||
assertThat(result.getHeaders().getContentType())
|
||||
.isGreaterThanOrEqualTo(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sentencesAcceptSse() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.get(new URI("/sentences")).accept(EVENT_STREAM).build(),
|
||||
String.class);
|
||||
assertThat(result.getBody())
|
||||
.isEqualTo(sse("[\"go\",\"home\"]", "[\"come\",\"back\"]"));
|
||||
assertThat(result.getHeaders().getContentType().isCompatibleWith(EVENT_STREAM))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercase() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
@@ -263,10 +139,11 @@ public class RestApplicationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Ignore("FIXME")
|
||||
public void messages() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/messages")).contentType(MediaType.APPLICATION_JSON)
|
||||
// Remove this when Spring 5.0.8 is used
|
||||
.accept(MediaType.valueOf("application/stream+json"))
|
||||
.header("x-foo", "bar").body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getHeaders().getFirst("x-foo")).isEqualTo("bar");
|
||||
assertThat(result.getHeaders()).doesNotContainKey("id");
|
||||
@@ -277,10 +154,12 @@ public class RestApplicationTests {
|
||||
public void headers() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity
|
||||
.post(new URI("/headers")).contentType(MediaType.APPLICATION_JSON)
|
||||
// Remove this when Spring 5.0.8 is used
|
||||
.accept(MediaType.valueOf("application/stream+json"))
|
||||
.body("[\"foo\",\"bar\"]"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
assertThat(result.getHeaders().getFirst("foo")).isEqualTo("bar");
|
||||
assertThat(result.getHeaders()).doesNotContainKey("id");
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -290,7 +169,8 @@ public class RestApplicationTests {
|
||||
RequestEntity.post(new URI("/uppercase"))
|
||||
.contentType(MediaType.TEXT_PLAIN).body("foo"),
|
||||
String.class);
|
||||
assertThat(result.getBody()).isEqualTo("(FOO)");
|
||||
// Result is multi-valued so it has to come out as an array
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -374,26 +254,12 @@ public class RestApplicationTests {
|
||||
assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postMoreFoo() {
|
||||
assertThat(rest.getForObject("/post/more/foo", String.class)).isEqualTo("(FOO)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseGet() {
|
||||
assertThat(rest.getForObject("/uppercase/foo", String.class)).isEqualTo("(FOO)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGet() {
|
||||
assertThat(rest.getForObject("/wrap/123", String.class)).isEqualTo("..123..");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertPost() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(RequestEntity.post(new URI("/wrap"))
|
||||
.contentType(MediaType.TEXT_PLAIN).body("123"), String.class);
|
||||
assertThat(result.getBody()).isEqualTo("..123..");
|
||||
// Result is multi-valued so it has to come out as an array
|
||||
assertThat(result.getBody()).isEqualTo("[\"..123..\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -408,20 +274,6 @@ public class RestApplicationTests {
|
||||
assertThat(result.getBody()).isEqualTo("[246]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supplierFirst() {
|
||||
assertThat(rest.getForObject("/not/a/function", String.class))
|
||||
.isEqualTo("[\"hello\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertGetJson() throws Exception {
|
||||
assertThat(rest
|
||||
.exchange(RequestEntity.get(new URI("/entity/321"))
|
||||
.accept(MediaType.APPLICATION_JSON).build(), String.class)
|
||||
.getBody()).isEqualTo("{\"value\":321}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uppercaseJsonArray() throws Exception {
|
||||
assertThat(rest.exchange(
|
||||
@@ -475,7 +327,7 @@ public class RestApplicationTests {
|
||||
private List<String> list = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(RestApplicationTests.ApplicationConfiguration.class,
|
||||
SpringApplication.run(HttpPostIntegrationTests.ApplicationConfiguration.class,
|
||||
args);
|
||||
}
|
||||
|
||||
@@ -525,12 +377,6 @@ public class RestApplicationTests {
|
||||
return flux -> flux.log().map(value -> 2 * value);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<Integer>, Flux<Map<String, Object>>> entity() {
|
||||
return flux -> flux.log()
|
||||
.map(value -> Collections.singletonMap("value", value));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Flux<HashMap<String, String>>, Flux<Map<String, String>>> maps() {
|
||||
return flux -> flux.map(value -> {
|
||||
@@ -539,32 +385,12 @@ public class RestApplicationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Bean({ "words", "get/more" })
|
||||
public Supplier<Flux<String>> words() {
|
||||
return () -> Flux.just("foo", "bar");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<String> word() {
|
||||
return () -> "foo";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<Foo>> foos() {
|
||||
return () -> Flux.just(new Foo("foo"), new Foo("bar"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Qualifier("foos")
|
||||
public Function<String, Foo> qualifier() {
|
||||
return value -> new Foo("[" + value.trim().toUpperCase() + "]");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<List<String>> bareWords() {
|
||||
return () -> Arrays.asList("foo", "bar");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Consumer<Flux<String>> updates() {
|
||||
return flux -> flux.subscribe(value -> list.add(value));
|
||||
@@ -580,44 +406,11 @@ public class RestApplicationTests {
|
||||
return value -> list.add(value);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> bang() {
|
||||
return () -> Flux.fromArray(new String[] { "foo", "bar" }).map(value -> {
|
||||
if (value.equals("bar")) {
|
||||
throw new RuntimeException("Bar");
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> empty() {
|
||||
return () -> Flux.fromIterable(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Bean("not/a/function")
|
||||
public Supplier<Flux<String>> supplier() {
|
||||
return () -> Flux.just("hello");
|
||||
}
|
||||
|
||||
@Bean("not/a")
|
||||
public Function<Flux<String>, Flux<String>> function() {
|
||||
return input -> Flux.just("bye");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<String>> timeout() {
|
||||
return () -> Flux.defer(() -> Flux.<String>create(emitter -> {
|
||||
emitter.next("foo");
|
||||
}).timeout(Duration.ofMillis(100L), Flux.empty()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Supplier<Flux<List<String>>> sentences() {
|
||||
return () -> Flux.just(Arrays.asList("go", "home"),
|
||||
Arrays.asList("come", "back"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<MultiValueMap<String, String>, Map<String, Integer>> sum() {
|
||||
return valueMap -> valueMap.entrySet().stream()
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2012-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.cloud.function.web.mvc;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.mvc.PrefixTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"spring.main.web-application-type=servlet",
|
||||
"spring.cloud.function.web.path=/functions" })
|
||||
@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class})
|
||||
public class PrefixTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
|
||||
@Test
|
||||
public void words() throws Exception {
|
||||
ResponseEntity<String> result = rest.exchange(
|
||||
RequestEntity.get(new URI("/functions/words")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missing() throws Exception {
|
||||
ResponseEntity<String> result = rest
|
||||
.exchange(RequestEntity.get(new URI("/words")).build(), String.class);
|
||||
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@org.springframework.boot.test.context.TestConfiguration
|
||||
protected static class TestConfiguration {
|
||||
@Bean({ "words", "get/more" })
|
||||
public Supplier<Flux<String>> words() {
|
||||
return () -> Flux.fromArray(new String[] { "foo", "bar" });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.web;
|
||||
package org.springframework.cloud.function.web.mvc;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.function.Supplier;
|
||||
@@ -33,10 +33,13 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.mvc.SingletonTests.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -49,6 +52,7 @@ import reactor.core.publisher.Flux;
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class})
|
||||
public class SingletonTests {
|
||||
|
||||
@LocalServerPort
|
||||
Reference in New Issue
Block a user