From 3158e6fe8611106334911ee032b10c57dbb533f5 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 26 Sep 2019 17:48:51 +0200 Subject: [PATCH] Makes the BatchStubRunner bean initialized as early as possible without this change beans that require the property with stub port might have already been initialized before BatchStubRunner was setup with this change we're initilizing that bean as early as possible fixes gh-1225 --- .../spring/StubRunnerConfiguration.java | 62 ++++++++++++-- .../stubrunner/issue1225/Issue1225Tests.java | 80 +++++++++++++++++++ .../FailFastLoanApplicationServiceTests.java | 6 +- 3 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java index f97628ff88..54a4e33abb 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerConfiguration.java @@ -18,8 +18,12 @@ package org.springframework.cloud.contract.stubrunner.spring; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.contract.stubrunner.BatchStubRunner; @@ -54,9 +58,6 @@ public class StubRunnerConfiguration { static final String STUBRUNNER_PREFIX = "stubrunner.runningstubs"; - @Autowired(required = false) - private MessageVerifier contractVerifierMessaging; - private StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider(); @Autowired @@ -72,7 +73,7 @@ public class StubRunnerConfiguration { * @return the batch stub runner bean */ @Bean - public BatchStubRunner batchStubRunner() { + public BatchStubRunner batchStubRunner(BeanFactory beanFactory) { StubRunnerOptionsBuilder builder = builder(); if (this.props.getProxyHost() != null) { builder.withProxy(this.props.getProxyHost(), this.props.getProxyPort()); @@ -80,14 +81,19 @@ public class StubRunnerConfiguration { StubRunnerOptions stubRunnerOptions = builder.build(); BatchStubRunner batchStubRunner = new BatchStubRunnerFactory(stubRunnerOptions, this.provider.get(stubRunnerOptions), - this.contractVerifierMessaging != null ? this.contractVerifierMessaging - : new NoOpStubMessages()).buildBatchStubRunner(); + new LazyMessageVerifier(beanFactory)).buildBatchStubRunner(); // TODO: Consider running it in a separate thread RunningStubs runningStubs = batchStubRunner.runStubs(); registerPort(runningStubs); return batchStubRunner; } + @Bean + public BeanPostProcessor batchStubRunnerBeanPostProcessor(BatchStubRunner runner) { + return new BeanPostProcessor() { + }; + } + private StubRunnerOptionsBuilder builder() { return new StubRunnerOptionsBuilder() .withMinMaxPort(this.props.getMinPort(), this.props.getMaxPort()) @@ -131,3 +137,47 @@ public class StubRunnerConfiguration { } } + +class LazyMessageVerifier implements MessageVerifier { + + private MessageVerifier messageVerifier; + + private final BeanFactory beanFactory; + + LazyMessageVerifier(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + private MessageVerifier messageVerifier() { + if (this.messageVerifier == null) { + try { + this.messageVerifier = this.beanFactory.getBean(MessageVerifier.class); + } + catch (BeansException ex) { + this.messageVerifier = new NoOpStubMessages(); + } + } + return this.messageVerifier; + } + + @Override + public void send(Object message, String destination) { + messageVerifier().send(message, destination); + } + + @Override + public Object receive(String destination, long timeout, TimeUnit timeUnit) { + return messageVerifier().receive(destination, timeout, timeUnit); + } + + @Override + public Object receive(String destination) { + return messageVerifier().receive(destination); + } + + @Override + public void send(Object payload, Map headers, String destination) { + messageVerifier().send(payload, headers, destination); + } + +} \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java new file mode 100644 index 0000000000..0168b647c4 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/issue1225/Issue1225Tests.java @@ -0,0 +1,80 @@ +/* + * Copyright 2013-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 + * + * https://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.contract.stubrunner.issue1225; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; +import org.springframework.cloud.contract.stubrunner.spring.StubRunnerPort; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.bind.annotation.RestController; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests that stub runner specific auto-configuration can be loaded up in combination with + * other slice tests + * + * @author Biju Kunjummen + */ +@RunWith(SpringRunner.class) +@SpringBootTest(properties = { + "ping.url=http://localhost:${stubrunner.runningstubs.loanIssuance.port}" }) +@AutoConfigureStubRunner(ids = { + "org.springframework.cloud.contract.verifier.stubs:loanIssuance:+:stubs", + "org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer:+:stubs" }) +@ActiveProfiles("test") +public class Issue1225Tests { + + @StubRunnerPort("loanIssuance") + private int stubRunnerLoanIssuancePort; + + @Autowired + private PingProxyController pingProxyController; + + @Test + public void shouldInjectTheStubPortsAsEarlyAsPossible() { + assertThat(this.stubRunnerLoanIssuancePort).isPositive(); + assertThat(this.pingProxyController.pingUrl) + .contains(":" + this.stubRunnerLoanIssuancePort); + } + + @ComponentScan + @SpringBootConfiguration + static class Config { + + } + +} + +@RestController +class PingProxyController { + + String pingUrl; + + public PingProxyController(@Value("${ping.url}") String pingUrl) { + this.pingUrl = pingUrl; + } + +} \ No newline at end of file diff --git a/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java b/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java index 98da40bca1..de31af7ca2 100644 --- a/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java +++ b/tests/spring-cloud-contract-stub-runner-context-path/src/test/java/com/example/loan/FailFastLoanApplicationServiceTests.java @@ -46,9 +46,8 @@ public class FailFastLoanApplicationServiceTests { // Then assertThat(throwable).isInstanceOf(BeanCreationException.class); - assertThat(throwable.getCause()).isInstanceOf(BeanInstantiationException.class); assertThat(throwable.getCause().getCause()) - .isInstanceOf(IllegalArgumentException.class).hasMessageContaining( + .isInstanceOf(BeanInstantiationException.class).hasMessageContaining( "For groupId [org.springframework.cloud.contract.verifier.stubs] artifactId [should-not-be-found] " + "and classifier [stubs] the version was not resolved! The following exceptions took place"); } @@ -66,9 +65,8 @@ public class FailFastLoanApplicationServiceTests { // Then assertThat(throwable).isInstanceOf(BeanCreationException.class); - assertThat(throwable.getCause()).isInstanceOf(BeanInstantiationException.class); assertThat(throwable.getCause().getCause()) - .isInstanceOf(IllegalStateException.class) + .isInstanceOf(BeanInstantiationException.class) .hasMessageContaining("No stubs were found on classpath "); }