Updated configuration to include the stubbing of the new load balancer; fixes gh-1391

This commit is contained in:
Marcin Grzejszczak
2020-05-21 14:59:29 +02:00
parent 0d58b6e954
commit a6bf27ddb4
8 changed files with 220 additions and 53 deletions

View File

@@ -62,9 +62,6 @@ public class StubRunnerConfiguration {
private StubDownloaderBuilderProvider provider = new StubDownloaderBuilderProvider();
@Autowired
private StubRunnerProperties props;
@Autowired
private ConfigurableEnvironment environment;
@@ -77,9 +74,10 @@ public class StubRunnerConfiguration {
*/
@Bean
public BatchStubRunner batchStubRunner(BeanFactory beanFactory) {
StubRunnerOptionsBuilder builder = builder();
if (this.props.getProxyHost() != null) {
builder.withProxy(this.props.getProxyHost(), this.props.getProxyPort());
StubRunnerProperties props = beanFactory.getBean(StubRunnerProperties.class);
StubRunnerOptionsBuilder builder = builder(props);
if (props.getProxyHost() != null) {
builder.withProxy(props.getProxyHost(), props.getProxyPort());
}
StubRunnerOptions stubRunnerOptions = stubRunnerOptions(builder);
BatchStubRunner batchStubRunner = new BatchStubRunnerFactory(stubRunnerOptions,
@@ -101,30 +99,30 @@ public class StubRunnerConfiguration {
};
}
private StubRunnerOptionsBuilder builder() {
private StubRunnerOptionsBuilder builder(StubRunnerProperties props) {
return new StubRunnerOptionsBuilder()
.withMinMaxPort(
Integer.valueOf(resolvePlaceholder(this.props.getMinPort(),
this.props.getMinPort())),
Integer.valueOf(resolvePlaceholder(this.props.getMaxPort(),
this.props.getMaxPort())))
.withStubRepositoryRoot(this.props.getRepositoryRoot())
.withStubsMode(resolvePlaceholder(this.props.getStubsMode()))
.withStubsClassifier(resolvePlaceholder(this.props.getClassifier()))
.withStubs(resolvePlaceholder(this.props.getIds()))
.withUsername(resolvePlaceholder(this.props.getUsername()))
.withPassword(resolvePlaceholder(this.props.getPassword()))
.withStubPerConsumer(Boolean.parseBoolean(
resolvePlaceholder(this.props.isStubsPerConsumer())))
.withConsumerName(consumerName())
Integer.valueOf(resolvePlaceholder(props.getMinPort(),
props.getMinPort())),
Integer.valueOf(resolvePlaceholder(props.getMaxPort(),
props.getMaxPort())))
.withStubRepositoryRoot(props.getRepositoryRoot())
.withStubsMode(resolvePlaceholder(props.getStubsMode()))
.withStubsClassifier(resolvePlaceholder(props.getClassifier()))
.withStubs(resolvePlaceholder(props.getIds()))
.withUsername(resolvePlaceholder(props.getUsername()))
.withPassword(resolvePlaceholder(props.getPassword()))
.withStubPerConsumer(Boolean
.parseBoolean(resolvePlaceholder(props.isStubsPerConsumer())))
.withConsumerName(consumerName(props))
.withMappingsOutputFolder(
resolvePlaceholder(this.props.getMappingsOutputFolder()))
.withDeleteStubsAfterTest(Boolean.parseBoolean(
resolvePlaceholder(this.props.isDeleteStubsAfterTest())))
.withGenerateStubs(Boolean
.parseBoolean(resolvePlaceholder(this.props.isGenerateStubs())))
.withProperties(this.props.getProperties())
.withHttpServerStubConfigurer(this.props.getHttpServerStubConfigurer());
resolvePlaceholder(props.getMappingsOutputFolder()))
.withDeleteStubsAfterTest(Boolean
.parseBoolean(resolvePlaceholder(props.isDeleteStubsAfterTest())))
.withGenerateStubs(
Boolean.parseBoolean(resolvePlaceholder(props.isGenerateStubs())))
.withProperties(props.getProperties())
.withHttpServerStubConfigurer(props.getHttpServerStubConfigurer());
}
private String[] resolvePlaceholder(String[] string) {
@@ -142,9 +140,9 @@ public class StubRunnerConfiguration {
return this.environment.resolvePlaceholders(string.toString());
}
private String consumerName() {
if (StringUtils.hasText(this.props.getConsumerName())) {
return resolvePlaceholder(this.props.getConsumerName());
private String consumerName(StubRunnerProperties props) {
if (StringUtils.hasText(props.getConsumerName())) {
return resolvePlaceholder(props.getConsumerName());
}
return this.environment.getProperty("spring.application.name");
}

View File

@@ -18,7 +18,6 @@ package org.springframework.cloud.contract.stubrunner.spring.cloud;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -44,12 +43,10 @@ import org.springframework.core.env.Environment;
@ConditionalOnProperty(value = "stubrunner.cloud.enabled", matchIfMissing = true)
public class StubRunnerSpringCloudAutoConfiguration {
@Autowired
BeanFactory beanFactory;
@Bean
public StubRunnerDiscoveryClientWrapper stubRunnerDiscoveryClientWrapper() {
return new StubRunnerDiscoveryClientWrapper(this.beanFactory);
public StubRunnerDiscoveryClientWrapper stubRunnerDiscoveryClientWrapper(
BeanFactory beanFactory) {
return new StubRunnerDiscoveryClientWrapper(beanFactory);
}
@Bean
@@ -70,8 +67,6 @@ class StubRunnerDiscoveryClientWrapper implements BeanPostProcessor {
private final BeanFactory beanFactory;
DiscoveryClient discoveryClient;
StubFinder stubFinder;
StubMapperProperties stubMapperProperties;

View File

@@ -18,11 +18,13 @@ package org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer;
import java.io.Closeable;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -37,18 +39,21 @@ import org.springframework.cloud.contract.stubrunner.StubConfiguration;
import org.springframework.cloud.contract.stubrunner.StubFinder;
import org.springframework.cloud.contract.stubrunner.spring.cloud.ConditionalOnStubbedDiscoveryEnabled;
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubMapperProperties;
import org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerSpringCloudAutoConfiguration;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration;
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.ResolvableType;
import org.springframework.util.StringUtils;
/**
* Provides autoconfiguraion for the Spring Cloud Load Balancer module.
*
* @since 3.0.0
* @since 2.2.3
* @author Marcin Grzejszczak
*/
@Configuration(proxyBeanMethods = false)
@@ -57,15 +62,16 @@ import org.springframework.util.StringUtils;
matchIfMissing = true)
@ConditionalOnBean(StubMapperProperties.class)
@AutoConfigureBefore(LoadBalancerAutoConfiguration.class)
@AutoConfigureAfter(LoadBalancerClientConfiguration.class)
@AutoConfigureAfter({ LoadBalancerClientConfiguration.class,
StubRunnerSpringCloudAutoConfiguration.class })
@ConditionalOnStubbedDiscoveryEnabled
public class SpringCloudLoadBalancerAutoConfiguration {
@Bean
@Primary
LoadBalancerClientFactory stubRunnerLoadBalancerClientFactory(StubFinder stubFinder,
StubMapperProperties stubMapperProperties) {
return new StubRunnerLoadBalancerClientFactory(stubFinder, stubMapperProperties);
LoadBalancerClientFactory stubRunnerLoadBalancerClientFactory(
BeanFactory beanFactory) {
return new StubRunnerLoadBalancerClientFactory(beanFactory);
}
}
@@ -73,20 +79,62 @@ public class SpringCloudLoadBalancerAutoConfiguration {
class StubRunnerLoadBalancerClientFactory extends LoadBalancerClientFactory
implements Closeable {
private final StubFinder stubFinder;
private StubFinder stubFinder;
private final StubMapperProperties stubMapperProperties;
private StubMapperProperties stubMapperProperties;
StubRunnerLoadBalancerClientFactory(StubFinder stubFinder,
StubMapperProperties stubMapperProperties) {
this.stubFinder = stubFinder;
this.stubMapperProperties = stubMapperProperties;
private final BeanFactory beanFactory;
StubRunnerLoadBalancerClientFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
private StubFinder stubFinder() {
if (this.stubFinder == null) {
this.stubFinder = this.beanFactory.getBean(StubFinder.class);
}
return this.stubFinder;
}
private StubMapperProperties stubMapperProperties() {
if (this.stubMapperProperties == null) {
this.stubMapperProperties = this.beanFactory
.getBean(StubMapperProperties.class);
}
return this.stubMapperProperties;
}
@Override
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
return request -> Mono.just(new DefaultResponse(
new StubbedServiceInstance(stubFinder, stubMapperProperties, serviceId)));
return (ReactorServiceInstanceLoadBalancer) request -> Mono
.just(new DefaultResponse(new StubbedServiceInstance(stubFinder(),
stubMapperProperties(), serviceId)));
}
@Override
@SuppressWarnings("unchecked")
public <T> T getInstance(String name, Class<T> type) {
return (T) getInstance(name);
}
@Override
@SuppressWarnings("unchecked")
public <T> T getInstance(String name, Class<?> clazz, Class<?>... generics) {
return (T) getInstance(name);
}
@Override
@SuppressWarnings("unchecked")
public <T> T getInstance(String name, ResolvableType type) {
return (T) getInstance(name);
}
@Override
@SuppressWarnings("unchecked")
public <T> Map<String, T> getInstances(String name, Class<T> type) {
Map<String, T> map = new HashMap<>();
map.put(name, (T) getInstance(name));
return map;
}
@Override

View File

@@ -2,6 +2,7 @@
org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner=\
org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration,\
org.springframework.cloud.contract.stubrunner.spring.cloud.StubRunnerSpringCloudAutoConfiguration,\
org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer.SpringCloudLoadBalancerAutoConfiguration,\
org.springframework.cloud.contract.stubrunner.spring.cloud.ribbon.StubRunnerRibbonAutoConfiguration,\
org.springframework.cloud.contract.stubrunner.messaging.integration.StubRunnerIntegrationConfiguration,\
org.springframework.cloud.contract.stubrunner.messaging.jms.StubRunnerJmsConfiguration,\

View File

@@ -28,12 +28,15 @@ import org.springframework.cloud.consul.ConsulAutoConfiguration
import org.springframework.cloud.contract.stubrunner.StubFinder
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
import org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer.StubRunnerLoadBalancerClientFactory
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.context.TestPropertySource
import org.springframework.web.client.RestTemplate
/**
* @author Marcin Grzejszczak
@@ -41,6 +44,7 @@ import org.springframework.web.client.RestTemplate
//TODO: Document that ribbon.eureka.enabled=false needs to be set or override it somehow
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
@ActiveProfiles("cloudtest")
@TestPropertySource(properties = "stubrunner.cloud.loadbalancer.enabled=false")
// tag::autoconfigure[]
@AutoConfigureStubRunner(
ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
@@ -56,6 +60,8 @@ class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
@Autowired
@LoadBalanced
RestTemplate restTemplate
@Autowired
LoadBalancerClientFactory loadBalancerClientFactory;
@BeforeClass
@AfterClass
@@ -64,6 +70,10 @@ class StubRunnerSpringCloudAutoConfigurationSpec extends Specification {
System.clearProperty("stubrunner.classifier")
}
def setup() {
assert !(loadBalancerClientFactory instanceof StubRunnerLoadBalancerClientFactory)
}
// tag::test[]
def 'should make service discovery work'() {
expect: 'WireMocks are running'

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2013-2020 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.spring.cloud
import org.junit.AfterClass
import org.junit.BeforeClass
import spock.lang.Specification
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.test.context.SpringBootContextLoader
import org.springframework.cloud.client.loadbalancer.LoadBalanced
import org.springframework.cloud.consul.ConsulAutoConfiguration
import org.springframework.cloud.contract.stubrunner.StubFinder
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
import org.springframework.cloud.contract.stubrunner.spring.cloud.loadbalancer.StubRunnerLoadBalancerClientFactory
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory
import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.test.context.ActiveProfiles
import org.springframework.test.context.ContextConfiguration
import org.springframework.web.client.RestTemplate
/**
* @author Marcin Grzejszczak
*/
@ContextConfiguration(classes = Config, loader = SpringBootContextLoader)
@ActiveProfiles("cloudtest-no-ribbon")
// tag::autoconfigure[]
@AutoConfigureStubRunner(
ids = ["org.springframework.cloud.contract.verifier.stubs:loanIssuance",
"org.springframework.cloud.contract.verifier.stubs:fraudDetectionServer",
"org.springframework.cloud.contract.verifier.stubs:bootService"],
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
repositoryRoot = "classpath:m2repo/repository/")
// end::autoconfigure[]
class StubRunnerSpringCloudNoRibbonAutoConfigurationSpec extends Specification {
@Autowired
StubFinder stubFinder
@Autowired
@LoadBalanced
RestTemplate restTemplate
@Autowired
LoadBalancerClientFactory loadBalancerClientFactory;
@BeforeClass
@AfterClass
static void setupProps() {
System.clearProperty("stubrunner.repository.root")
System.clearProperty("stubrunner.classifier")
}
def setup() {
assert loadBalancerClientFactory instanceof StubRunnerLoadBalancerClientFactory
}
// tag::test[]
def 'should make service discovery work'() {
expect: 'WireMocks are running'
"${stubFinder.findStubUrl('loanIssuance').toString()}/name".toURL().text == 'loanIssuance'
"${stubFinder.findStubUrl('fraudDetectionServer').toString()}/name".toURL().text == 'fraudDetectionServer'
and: 'Stubs can be reached via load service discovery'
restTemplate.getForObject('http://loanIssuance/name', String) == 'loanIssuance'
restTemplate.getForObject('http://someNameThatShouldMapFraudDetectionServer/name', String) == 'fraudDetectionServer'
}
// end::test[]
@Configuration
@EnableAutoConfiguration(exclude = [EurekaClientAutoConfiguration,
ConsulAutoConfiguration, ZookeeperAutoConfiguration])
static class Config {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate()
}
}
}

View File

@@ -0,0 +1,17 @@
stubrunner:
cloud.stubbed.discovery.enabled: true
spring.cloud:
zookeeper:
enabled: false
discovery.enabled: false
consul:
enabled: false
discovery.enabled: false
service-registry.enabled: false
eureka.client.enabled: false
ribbon.eureka.enabled: false
spring:
cloud:
loadbalancer:
ribbon:
enabled: false # Use Reactive Load Balancer

View File

@@ -45,8 +45,10 @@ class JaxRsRequestMethodWhen implements When, JaxRsBodyParser {
ContentType type = metadata.getInputTestContentType();
String method = request.getMethod().getServerValue().toString().toLowerCase();
if (request.getBody() != null) {
String contentType = StringUtils.hasText(metadata.getDefinedInputTestContentType())
? metadata.getDefinedInputTestContentType() : type.getMimeType();
String contentType = StringUtils
.hasText(metadata.getDefinedInputTestContentType())
? metadata.getDefinedInputTestContentType()
: type.getMimeType();
Object body = request.getBody().getServerValue();
String value;
if (body instanceof ExecutionProperty) {