繁体   English   中英

如何在 spring-cloud-gateway 合约测试中从 spring-cloud-contract 中设置带有 StubRunner 端口的 url

[英]How to set urls with port of StubRunner from spring-cloud-contract in spring-cloud-gateway contract tests

我有一个 spring 云网关应用程序,它将请求路由到另一个服务。 另一个服务定义了在测试中由 spring 云网关应用程序作为存根导入的合约。

现在我想在我的网关中进行合同测试,这将消耗另一个服务的存根。 问题是我不知道如何将StubRunnerPort作为属性/环境注入,因此可以通过我的配置 class 选择它并相应地配置路由:

Api网关路由配置

@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);
    }

}

以及测试 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\"\"}"));
    }

理想情况下,我想要subscriptions.url 。url 属性设置配置存根运行器之后但Spring 选择我的网关配置之前,这样 url 将工作。

我已经尝试过使用ApplicationContextInitializer但在启动初始化程序实例时似乎尚未配置 StubRunnerPort 。

所以问题是 - 如何获取存根运行器端口并使用它将其注入其他服务 url,以便网关将请求路由到测试中的存根运行器?

我通过创建一个测试配置使其工作,该配置扩展了包含 url 属性和RouteLocator配置的配置,并且依赖于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");
    }
}

这里的关键点是:

  • 只有在batchStubRunner bean 可用后才运行配置,因此可以在environment中找到 StrubRunner 的端口
  • 该配置实现了InitializingBean ,因此我能够覆盖现在在父配置中protectedsubscriptionsUrl
  • subscriptionsUrl被覆盖之后——它可以用来从父配置中配置RouteLocator bean。

测试现在看起来像这样:

@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());
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM