Add new feature to initialize a Supplier from a remote HTTP endpoint
Kind of like the SupplierExporter but to create the Supplier itself. With this in place you can define the templateUrl (destination) and the originaUrl (source) and use the app as a pipeline for events from/to HTTP. Provide functional bean support for HTTP export Add autoconfig to AWS adapter for custom runtime Fix HttpSupplier to always supply Message if headers are included Fix registration of origin supplier in functional beans Add docs on new AWS features Add custom runtime sample
This commit is contained in:
committed by
Oleg Zhurakousky
parent
cdca44f714
commit
428243ce48
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2012-2019 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.test;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
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.SpringBootConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.FunctionType;
|
||||
import org.springframework.cloud.function.context.test.FunctionalSpringBootTest;
|
||||
import org.springframework.cloud.function.test.FunctionalExporterTests.ApplicationConfiguration;
|
||||
import org.springframework.cloud.function.web.source.SupplierExporter;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.SocketUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@FunctionalSpringBootTest(classes = ApplicationConfiguration.class, webEnvironment = WebEnvironment.NONE, properties = {
|
||||
"spring.main.web-application-type=none",
|
||||
"spring.cloud.function.web.export.sink.url=http://localhost:${my.port}",
|
||||
"spring.cloud.function.web.export.source.url=http://localhost:${my.port}",
|
||||
"spring.cloud.function.web.export.sink.name=origin|uppercase",
|
||||
"spring.cloud.function.web.export.debug=true",
|
||||
"spring.cloud.function.web.export.enabled=true" })
|
||||
public class FunctionalExporterTests {
|
||||
|
||||
@Autowired
|
||||
private SupplierExporter forwarder;
|
||||
|
||||
private static RestConfiguration app;
|
||||
|
||||
private static ConfigurableApplicationContext context;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws Exception {
|
||||
String port = "" + SocketUtils.findAvailableTcpPort();
|
||||
System.setProperty("server.port", port);
|
||||
System.setProperty("my.port", port);
|
||||
context = SpringApplication.run(RestConfiguration.class,
|
||||
"--spring.main.web-application-type=reactive");
|
||||
app = context.getBean(RestConfiguration.class);
|
||||
// Sometimes the server doesn't start quick enough
|
||||
Thread.sleep(500L);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void close() {
|
||||
System.clearProperty("server.port");
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void words() throws Exception {
|
||||
int count = 0;
|
||||
while (this.forwarder.isRunning() && count++ < 1000) {
|
||||
Thread.sleep(20);
|
||||
}
|
||||
// It completed
|
||||
assertThat(this.forwarder.isRunning()).isFalse();
|
||||
assertThat(FunctionalExporterTests.app.inputs).contains("HELLO");
|
||||
assertThat(this.forwarder.isOk()).isTrue();
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
protected static class ApplicationConfiguration
|
||||
implements ApplicationContextInitializer<GenericApplicationContext> {
|
||||
|
||||
Function<Message<String>, Message<String>> uppercase() {
|
||||
return value -> MessageBuilder.withPayload(value.getPayload().toUpperCase())
|
||||
.copyHeaders(value.getHeaders()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(GenericApplicationContext context) {
|
||||
context.registerBean("uppercase", FunctionRegistration.class,
|
||||
() -> new FunctionRegistration<>(uppercase()).type(
|
||||
FunctionType.from(String.class).to(String.class).message()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
public class RestConfiguration {
|
||||
|
||||
private static Log logger = LogFactory.getLog(RestConfiguration.class);
|
||||
|
||||
List<String> inputs = new ArrayList<>();
|
||||
|
||||
private Iterator<String> outputs = Arrays.asList("hello", "world").iterator();
|
||||
|
||||
@GetMapping("/")
|
||||
ResponseEntity<String> home() {
|
||||
logger.info("HOME");
|
||||
if (this.outputs.hasNext()) {
|
||||
return ResponseEntity.ok(this.outputs.next());
|
||||
}
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
ResponseEntity<String> accept(@RequestBody String body) {
|
||||
logger.info("ACCEPT");
|
||||
this.inputs.add(body);
|
||||
return ResponseEntity.accepted().body(body);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(RestConfiguration.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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.source;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
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.context.TestConfiguration;
|
||||
import org.springframework.cloud.function.web.source.FunctionAutoConfigurationIntegrationTests.ApplicationConfiguration;
|
||||
import org.springframework.cloud.function.web.source.FunctionAutoConfigurationIntegrationTests.RestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, properties = {
|
||||
"spring.cloud.function.web.export.sink.url=http://localhost:${server.port}",
|
||||
"spring.cloud.function.web.export.source.url=http://localhost:${server.port}",
|
||||
"spring.cloud.function.web.export.sink.name=origin|uppercase",
|
||||
"spring.cloud.function.web.export.debug=true",
|
||||
"spring.cloud.function.web.export.enabled=true" })
|
||||
@ContextConfiguration(classes = { RestConfiguration.class,
|
||||
ApplicationConfiguration.class })
|
||||
public class FunctionAutoConfigurationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private SupplierExporter forwarder;
|
||||
|
||||
@Autowired
|
||||
private RestConfiguration app;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
System.setProperty("server.port", "" + SocketUtils.findAvailableTcpPort());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void close() {
|
||||
System.clearProperty("server.port");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copiesMessages() throws Exception {
|
||||
int count = 0;
|
||||
while (this.forwarder.isRunning() && count++ < 100) {
|
||||
Thread.sleep(20);
|
||||
}
|
||||
// It completed
|
||||
assertThat(this.forwarder.isRunning()).isFalse();
|
||||
assertThat(this.forwarder.isOk()).isTrue();
|
||||
assertThat(this.app.inputs).contains("HELLO");
|
||||
assertThat(this.app.inputs).contains("WORLD");
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@TestConfiguration
|
||||
public static class ApplicationConfiguration {
|
||||
|
||||
@Bean
|
||||
public Function<String, String> uppercase() {
|
||||
return value -> value.toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
@RestController
|
||||
public static class RestConfiguration {
|
||||
|
||||
private static Log logger = LogFactory.getLog(RestConfiguration.class);
|
||||
|
||||
private List<String> inputs = new ArrayList<>();
|
||||
|
||||
private Iterator<String> outputs = Arrays.asList("hello", "world").iterator();
|
||||
|
||||
@GetMapping("/")
|
||||
ResponseEntity<String> home() {
|
||||
logger.info("HOME");
|
||||
if (this.outputs.hasNext()) {
|
||||
return ResponseEntity.ok(this.outputs.next());
|
||||
}
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
void accept(@RequestBody String body) {
|
||||
logger.info("ACCEPT");
|
||||
this.inputs.add(body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,7 +26,6 @@ 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.cloud.function.web.RestApplication;
|
||||
import org.springframework.cloud.function.web.source.SourceAutoConfigurationIntegrationTests.ApplicationConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -39,9 +38,11 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE, //
|
||||
properties = "spring.cloud.function.web.supplier.templateUrl=http://localhost:9999/notthere")
|
||||
@ContextConfiguration(classes = { RestApplication.class, ApplicationConfiguration.class })
|
||||
// @formatter:off
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE,
|
||||
properties = "spring.cloud.function.web.export.sink.url=http://nosuchhost")
|
||||
// @formatter:on
|
||||
@ContextConfiguration(classes = { ApplicationConfiguration.class })
|
||||
public class SourceAutoConfigurationIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -24,6 +24,8 @@ import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -37,6 +39,7 @@ import org.springframework.cloud.function.web.source.WebAppIntegrationTests.Appl
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -48,13 +51,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, properties = {
|
||||
"spring.main.web-application-type=reactive",
|
||||
"spring.cloud.function.web.supplier.templateUrl=http://localhost:${local.server.port}/values",
|
||||
"spring.cloud.function.web.export.sink.url=http://localhost:${server.port}/values",
|
||||
// in a webapp we have to explicitly enable the export
|
||||
"spring.cloud.function.web.supplier.enabled=true",
|
||||
"spring.cloud.function.web.export.enabled=true",
|
||||
// manually so we know the webapp is listening when we start
|
||||
"spring.cloud.function.web.supplier.autoStartup=false" })
|
||||
"spring.cloud.function.web.export.autoStartup=false" })
|
||||
@ContextConfiguration(classes = { RestApplication.class, ApplicationConfiguration.class })
|
||||
public class WebAppIntegrationTests {
|
||||
|
||||
@@ -66,6 +69,16 @@ public class WebAppIntegrationTests {
|
||||
@Autowired
|
||||
private ApplicationConfiguration app;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
System.setProperty("server.port", "" + SocketUtils.findAvailableTcpPort());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void close() {
|
||||
System.clearProperty("server.port");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void posts() throws Exception {
|
||||
this.forwarder.start();
|
||||
|
||||
Reference in New Issue
Block a user