From 27acfd8cc3a6cdfedd03bac717704f81fe403122 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Mon, 22 Feb 2021 11:41:06 +0100 Subject: [PATCH] GH-653 Add documentation and additional test to validate function definition order for RSocket Resolves #653 --- spring-cloud-function-rsocket/README.md | 22 ++++++- .../RSocketAutoConfigurationRoutingTests.java | 64 +++++++++++++++---- 2 files changed, 72 insertions(+), 14 deletions(-) diff --git a/spring-cloud-function-rsocket/README.md b/spring-cloud-function-rsocket/README.md index 109e4e849..d32b98df1 100644 --- a/spring-cloud-function-rsocket/README.md +++ b/spring-cloud-function-rsocket/README.md @@ -13,9 +13,8 @@ adjustment needed to apply proper invocation model to the framework. To use RSocket integration all you need is to add `spring-cloud-function-rsocket` dependency to your classpath ``` - org.springframework.cloud - spring-cloud-function-rsocket - 3.1.0 + org.springframework.cloud + spring-cloud-function-rsocket ``` @@ -56,4 +55,21 @@ rsocketRequesterBuilder.tcp("localhost", port) .subscribe(System.out::println); ``` +### Function Definitions + +As you can see from the preceding example, we provide function definition as a value to `route(..)` operator of `RSocketRequester.Builder`. +However that is not the only way. You can also use standard `spring.cloud.function.definition` property as well as `spring.cloud.function.routing-expression` property. +This raises a question of _order_ and _priorities_ when it comes to reconsiling a conflict in the event several ways of providing definition are used. So it is a mater of clearly stating the rule whcih is: + +***1 - spring.cloud.function.routing-expression*** +The `spring.cloud.function.routing-expression` property takes precedence over all other ways of providing definition. So, in the event you may have also use `route(..)` operator or `spring.cloud.function.definition` property, they will be ignored if `spring.cloud.function.routing-expression` property is provided. + +***2 - route(..)*** +The next in line is `route(..)` operator. So in the event there are no `spring.cloud.function.routing-expression` property but you defined `spring.cloud.function.definition` property, it will be ignored in favor of definition provided by the `route(..)` operator. + +***3 - spring.cloud.function.definition*** +The `spring.cloud.function.definition` property is the last in the list allowing you to simply `route("")` to empty string. + + + You can also look at one of the [RSocket samples](https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-samples/function-sample-cloudevent-rsocket) that is also introduces you to Cloud Events \ No newline at end of file diff --git a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java index 82a9a290d..bfc5f5b6e 100644 --- a/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java +++ b/spring-cloud-function-rsocket/src/test/java/org/springframework/cloud/function/rsocket/RSocketAutoConfigurationRoutingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2020 the original author or authors. + * Copyright 2021-2021 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. @@ -43,7 +43,7 @@ import org.springframework.util.SocketUtils; */ public class RSocketAutoConfigurationRoutingTests { @Test - public void testImperativeFunctionAsRequestReplyWithDefinition() { + public void testRoutingWithRoute() { int port = SocketUtils.findAvailableTcpPort(); try ( ConfigurableApplicationContext applicationContext = @@ -87,18 +87,60 @@ public class RSocketAutoConfigurationRoutingTests { .expectComplete() .verify(); -// rsocketRequesterBuilder.tcp("localhost", port) -// .route(RoutingFunction.FUNCTION_NAME) -// .metadata("{\"func_name\":\"uppercase\"}", MimeTypeUtils.APPLICATION_JSON) -// .data("hello") -// .retrieveMono(String.class) -// .as(StepVerifier::create) -// .expectNext("HELLO") -// .expectComplete() -// .verify(); } } + @Test + public void testRoutingWithDefinition() { + int port = SocketUtils.findAvailableTcpPort(); + try ( + ConfigurableApplicationContext applicationContext = + new SpringApplicationBuilder(SampleFunctionConfiguration.class) + .web(WebApplicationType.NONE) + .run("--logging.level.org.springframework.cloud.function=DEBUG", + "--spring.cloud.function.definition=uppercase", + "--spring.cloud.function.routing-expression=headers.func_name", + "--spring.cloud.function.expected-content-type=text/plain", + "--spring.rsocket.server.port=" + port); + ) { + RSocketRequester.Builder rsocketRequesterBuilder = + applicationContext.getBean(RSocketRequester.Builder.class); + + rsocketRequesterBuilder.tcp("localhost", port) + .route("uppercase") + .metadata("{\"func_name\":\"echo\"}", MimeTypeUtils.APPLICATION_JSON) + .data("hello") + .retrieveMono(String.class) + .as(StepVerifier::create) + .expectNext("hello") + .expectComplete() + .verify(); + + rsocketRequesterBuilder.tcp("localhost", port) + .route("") + .metadata("{\"func_name\":\"echo\"}", MimeTypeUtils.APPLICATION_JSON) + .data("hello") + .retrieveMono(String.class) + .as(StepVerifier::create) + .expectNext("hello") + .expectComplete() + .verify(); + + rsocketRequesterBuilder.tcp("localhost", port) + .route(RoutingFunction.FUNCTION_NAME) + .metadata("{\"func_name\":\"echo\"}", MimeTypeUtils.APPLICATION_JSON) + .data("hello") + .retrieveMono(String.class) + .as(StepVerifier::create) + .expectNext("hello") + .expectComplete() + .verify(); + + } + } + + + @EnableAutoConfiguration @Configuration