* Fix typos in docs

* Add `spring-cloud-function-integration` into `spring-cloud-function-dependencies`
* Fix "memoize" logic in the `FunctionLookupHelper` and cover it in the `FunctionFlowTests`
against `@SpyBean FunctionCatalog`
This commit is contained in:
abilan
2023-05-17 13:59:52 -04:00
committed by Oleg Zhurakousky
parent e0629b5080
commit 42a5319c99
4 changed files with 46 additions and 25 deletions

View File

@@ -40,24 +40,22 @@ public class FunctionLookupHelper {
}
<P> Supplier<P> lookupSupplier(String functionDefinition) {
return () ->
memoize(() -> this.functionCatalog.<Supplier<P>>lookup(Supplier.class, functionDefinition))
.get()
.get();
Supplier<Supplier<P>> memoizedSupplier = lazyLookup(Supplier.class, functionDefinition);
return () -> memoizedSupplier.get().get();
}
<P> Function<P, ?> lookupFunction(String functionDefinition) {
return (p) ->
memoize(() -> this.functionCatalog.<Function<P, ?>>lookup(Function.class, functionDefinition))
.get()
.apply(p);
Supplier<Function<P, ?>> memoizedFunction = lazyLookup(Function.class, functionDefinition);
return (p) -> memoizedFunction.get().apply(p);
}
<P> Consumer<P> lookupConsumer(String consumerDefinition) {
return (p) ->
memoize(() -> this.functionCatalog.<Consumer<P>>lookup(Consumer.class, consumerDefinition))
.get()
.accept(p);
Supplier<Consumer<P>> memoizedConsumer = lazyLookup(Consumer.class, consumerDefinition);
return (p) -> memoizedConsumer.get().accept(p);
}
private <T> Supplier<T> lazyLookup(Class<?> functionType, String functionDefinition) {
return memoize(() -> this.functionCatalog.lookup(functionType, functionDefinition));
}
/**

View File

@@ -28,12 +28,15 @@ import org.junit.jupiter.api.Test;
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.mock.mockito.SpyBean;
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.PollerSpec;
import org.springframework.integration.dsl.Pollers;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.handler.LoggingHandler;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.integration.test.util.OnlyOnceTrigger;
@@ -43,6 +46,7 @@ import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
/**
* @author Artem Bilan
@@ -53,31 +57,45 @@ import static org.assertj.core.api.Assertions.assertThat;
@DirtiesContext
public class FunctionFlowTests {
@Autowired
QueueChannel wireTapChannel;
// To verify cached lookups
@SpyBean
FunctionCatalog functionCatalog;
@Autowired
BlockingQueue<String> results;
@Test
void fromSupplierOverFunctionToConsumer() throws InterruptedException {
String result = results.poll(10, TimeUnit.SECONDS);
void fromSupplierOverFunctionToConsumer(@Autowired SourcePollingChannelAdapter supplierEndpoint,
@Autowired QueueChannel wireTapChannel) throws InterruptedException {
supplierEndpoint.start();
String result = this.results.poll(10, TimeUnit.SECONDS);
assertThat(result).isEqualTo("SIMPLE TEST DATA");
Message<?> receive = wireTapChannel.receive(10_000);
assertThat(receive).isNotNull()
assertThat(receive)
.extracting(Message::getPayload)
.isEqualTo("simple test data".getBytes());
supplierEndpoint.stop();
}
@Autowired
MessageChannel functionCompositionInput;
@Test
void fromChannelToFunctionComposition() throws InterruptedException {
this.functionCompositionInput.send(new GenericMessage<>("compose this"));
void fromChannelToFunctionComposition(@Autowired MessageChannel functionCompositionInput)
throws InterruptedException {
String result = results.poll(10, TimeUnit.SECONDS);
functionCompositionInput.send(new GenericMessage<>("compose this"));
String result = this.results.poll(10, TimeUnit.SECONDS);
assertThat(result).isEqualTo("COMPOSE THIS");
functionCompositionInput.send(new GenericMessage<>("compose again"));
result = this.results.poll(10, TimeUnit.SECONDS);
assertThat(result).isEqualTo("COMPOSE AGAIN");
// Ensure that FunctionLookupHelper.memoize() does its trick calling FunctionCatalog.lookup() only once
verify(this.functionCatalog).lookup(Consumer.class, "upperCaseFunction|simpleStringConsumer");
}
@EnableAutoConfiguration
@@ -117,7 +135,7 @@ public class FunctionFlowTests {
@Bean
IntegrationFlow someFunctionFlow(FunctionFlowBuilder functionFlowBuilder) {
return functionFlowBuilder
.fromSupplier("simpleByteArraySupplier")
.fromSupplier("simpleByteArraySupplier", e -> e.id("supplierEndpoint").autoStartup(false))
.wireTap("wireTapChannel")
.apply("upperCaseFunction")
.log(LoggingHandler.Level.WARN, FunctionFlowTests.class.getName())