Home > Back-end >  How to set urls with port of StubRunner from spring-cloud-contract in spring-cloud-gateway contract
How to set urls with port of StubRunner from spring-cloud-contract in spring-cloud-gateway contract

Time:12-24

I have a spring cloud gateway application which routes requests to another service. Another service defines contracts which are imported as stubs by spring cloud gateway application in tests.

Now I would like to have contract tests in my gateway that will consume the stubs of another service. The problem is that I do not know how to inject the StubRunnerPort as property/environment so it can be picked by my configuration class and configure the routes accordingly :

Api gateway routes configuration

@Configuration
class GatewayConfig {

    
    @Value("${subscriptions.url}")
    private String subscriptionsUrl;

    @Autowired
    private TokenRelayGatewayFilterFactory tokenFilterFactory;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.csrf(ServerHttpSecurity.CsrfSpec::disable);
        return http.build();
    }

    @Bean
    RouteLocator routeLocator(final RouteLocatorBuilder routeLocatorBuilder) {
        return routeLocatorBuilder.routes()
                .route("subscriptions", subscriptionsRoute())
                .build();
    }

    private Function<PredicateSpec, Buildable<Route>> subscriptionsRoute() {
        return spec -> spec
                .path("/subscriptions/**")
                .filters(s -> s.filter(tokenFilterFactory.apply()).prefixPath("/v1"))
                .uri(subscriptionsUrl);
    }

}

And the test class :

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {PnApiGatewayApp.class})
@AutoConfigureStubRunner(ids = "io.mkrzywanski:subscription-app: :stubs", stubsMode = StubRunnerProperties.StubsMode.CLASSPATH)
@ActiveProfiles("test")
class SubscriptionSpec {

    private WebTestClient webClient;

    @LocalServerPort
    private int port;

    @StubRunnerPort("io.mkrzywanski:subscription-app")
    private int stubRunnerPort;

    @Autowired
    ConfigurableEnvironment environment;

    @BeforeEach
    void setup() {
        String baseUri = "http://localhost:"   port;
        this.webClient = WebTestClient.bindToServer()
                .responseTimeout(Duration.ofSeconds(10))
                .baseUrl(baseUri).build();
    }

    @Test
    void  test() {
        String body = "{\"userId\":\"22e90bbd-7399-468a-9b76-cf050ff16c63\",\"itemSet\":[{\"value\":\" Rainbow Six\"}]}";
        var response = webClient.post()
                .uri("/subscriptions")
                .header("Authorization", "Bearer xxx")
                .header("Content-type", MediaType.APPLICATION_JSON_VALUE)
                .bodyValue(body)
                .exchange()
                .expectStatus().isCreated()
                .expectBody(String.class)
                .value(Matchers.equalTo("{\"subscriptionId : \"6d692849-58fd-439b-bb2c-50a5d3669fa9\"\"}"));
    }

Ideally I would like to have subscriptions.url property set after stub runner is configured but before my gateway configuration is picked by Spring so that url redirects will work.

I have already tried to use ApplicationContextInitializer but it seems that StubRunnerPort is not configured yet, when instance of initializer is launched.

So the question is - how to get stub runner port and use it to inject it into other services url, so that gateway would route the requests to the stub runner in tests?

CodePudding user response:

I made it work by creating a test configuration which extends configuration that contains url properties and RouteLocator configuration and has a dependency on batchStubRunner bean :

@DependsOn("batchStubRunner")
@EnableAutoConfiguration
@Import(LoggingFilter.class)
class GatewayTestConfig extends GatewayConfig implements InitializingBean {

    @Autowired
    ConfigurableEnvironment environment;

    @Override
    public void afterPropertiesSet() {
        this.subscriptionsUrl = "http://localhost:"   environment.getProperty("stubrunner.runningstubs.io.mkrzywanski.subscription-app.port");
    }
}

The key points here are :

  • the configuration is run only after batchStubRunner bean is available so the port of StrubRunner can be found in the environment
  • The configuration implements InitializingBean so I am able to override the subscriptionsUrl which is now protected in parent configuration
  • After subscriptionsUrl is overriden - it can be used to configure RouteLocator bean from parent configuration.

The test looks like this now :

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {GatewayTestConfig.class})
@AutoConfigureStubRunner(ids = "io.mkrzywanski:subscription-app: :stubs", stubsMode = StubRunnerProperties.StubsMode.CLASSPATH)
@ActiveProfiles("test")
class SubscriptionSpec {

    private WebTestClient webClient;

    @LocalServerPort
    private int port;

    @BeforeEach
    void setup() {
        String baseUri = "http://localhost:"   port;
        this.webClient = WebTestClient.bindToServer()
                .responseTimeout(Duration.ofSeconds(10))
                .baseUrl(baseUri).build();
    }

    @Test
    void shouldRouteToSubscriptions() {

        String body = "{\"userId\":\"22e90bbd-7399-468a-9b76-cf050ff16c63\",\"itemSet\":[{\"value\":\"Rainbow Six\"}]}";
        webClient.post()
                .uri("/subscriptions")
                .header("Accept", MediaType.APPLICATION_JSON_VALUE)
                .header("Authorization", "Bearer xxx")
                .header("Content-type", MediaType.APPLICATION_JSON_VALUE)
                .bodyValue(body)
                .exchange()
                .expectStatus().isCreated()
                .expectBody()
                .jsonPath("$.subscriptionId").exists()
                .jsonPath("$.subscriptionId").value(IsUUID.UUID());
    }
}
  • Related