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
This commit is contained in:
Marcin Grzejszczak
2019-09-26 17:48:51 +02:00
parent 0a67fcbab3
commit 3158e6fe86
3 changed files with 138 additions and 10 deletions

View File

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

View File

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

View File

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