Fails on no stubs for stubs Per Consumer
without this change the JAR gets downloaded, it contains mappings but there are no mappings that are actually matching the given consumer. Regardless, the WireMock server starts with no mappings with this change an exception is being thrown in that case fixes gh-2114
This commit is contained in:
@@ -29,6 +29,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.micrometer.common.lang.Nullable;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -57,7 +58,8 @@ class StubRepository {
|
||||
|
||||
private final StubRunnerOptions options;
|
||||
|
||||
StubRepository(File repository, List<HttpServerStub> httpServerStubs, StubRunnerOptions options) {
|
||||
StubRepository(File repository, List<HttpServerStub> httpServerStubs, StubRunnerOptions options,
|
||||
@Nullable StubConfiguration stubConfiguration) {
|
||||
if (!repository.isDirectory()) {
|
||||
throw new IllegalArgumentException("Missing descriptor repository under path [" + repository + "]");
|
||||
}
|
||||
@@ -70,13 +72,18 @@ class StubRepository {
|
||||
this.options = options;
|
||||
this.stubs = stubs();
|
||||
this.contracts = contracts();
|
||||
if (options.isFailOnNoStubs() && this.stubs.isEmpty() && this.contracts.isEmpty()) {
|
||||
throw new IllegalStateException("No stubs or contracts were found for ["
|
||||
+ (stubConfiguration != null ? stubConfiguration.toColonSeparatedDependencyNotation() : null)
|
||||
+ "] and the switch to fail on no stubs was set.");
|
||||
}
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Found the following contracts " + this.contracts);
|
||||
}
|
||||
}
|
||||
|
||||
StubRepository(File repository) {
|
||||
this(repository, new ArrayList<>(), new StubRunnerOptionsBuilder().build());
|
||||
this(repository, new ArrayList<>(), new StubRunnerOptionsBuilder().build(), null);
|
||||
}
|
||||
|
||||
public File getPath() {
|
||||
|
||||
@@ -64,7 +64,8 @@ public class StubRunner implements StubRunning {
|
||||
this.stubsConfiguration = stubsConfiguration;
|
||||
this.stubRunnerOptions = stubRunnerOptions;
|
||||
List<HttpServerStub> serverStubs = SpringFactoriesLoader.loadFactories(HttpServerStub.class, null);
|
||||
this.stubRepository = new StubRepository(new File(repositoryPath), serverStubs, this.stubRunnerOptions);
|
||||
this.stubRepository = new StubRepository(new File(repositoryPath), serverStubs, this.stubRunnerOptions,
|
||||
stubsConfiguration);
|
||||
AvailablePortScanner portScanner = new AvailablePortScanner(stubRunnerOptions.getMinPortValue(),
|
||||
stubRunnerOptions.getMaxPortValue());
|
||||
this.localStubRunner = new StubRunnerExecutor(portScanner, contractVerifierMessaging, serverStubs);
|
||||
|
||||
@@ -25,7 +25,7 @@ class StubRepositorySpec extends Specification {
|
||||
def 'should retrieve all descriptors for given project'() {
|
||||
given:
|
||||
StubRepository repository = new StubRepository(REPOSITORY_LOCATION,
|
||||
[], new StubRunnerOptionsBuilder().build())
|
||||
[], new StubRunnerOptionsBuilder().build(), null)
|
||||
int expectedDescriptorsSize = 8
|
||||
when:
|
||||
List<File> descriptors = repository.getStubs()
|
||||
@@ -33,20 +33,18 @@ class StubRepositorySpec extends Specification {
|
||||
descriptors.size() == expectedDescriptorsSize
|
||||
}
|
||||
|
||||
def 'should return empty list if files are missing'() {
|
||||
given:
|
||||
StubRepository repository = new StubRepository(new File('src/test/resources/emptyrepo'),
|
||||
[], new StubRunnerOptionsBuilder().build())
|
||||
def 'should throw an exception when no stubs or contracts are present'() {
|
||||
when:
|
||||
List<File> descriptors = repository.getStubs()
|
||||
new StubRepository(new File('src/test/resources/emptyrepo'),
|
||||
[], new StubRunnerOptionsBuilder().build(), null)
|
||||
then:
|
||||
descriptors.empty
|
||||
thrown(IllegalStateException)
|
||||
}
|
||||
|
||||
def 'should throw an exception if directory with mappings is missing'() {
|
||||
when:
|
||||
new StubRepository(new File('src/test/resources/nonexistingrepo'), [],
|
||||
new StubRunnerOptionsBuilder().build())
|
||||
new StubRunnerOptionsBuilder().build(), null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
@@ -56,7 +54,7 @@ class StubRepositorySpec extends Specification {
|
||||
StubRepository repository = new StubRepository(REPOSITORY_LOCATION,
|
||||
[], new StubRunnerOptionsBuilder()
|
||||
.withStubPerConsumer(true)
|
||||
.withConsumerName("ping").build())
|
||||
.withConsumerName("ping").build(), null)
|
||||
int expectedDescriptorsSize = 1
|
||||
when:
|
||||
List<File> descriptors = repository.stubs
|
||||
|
||||
@@ -40,7 +40,7 @@ class StubRunnerExecutorSpec extends Specification {
|
||||
def setup() {
|
||||
portScanner = new AvailablePortScanner(MIN_PORT, MAX_PORT)
|
||||
repository = new StubRepository(new File('src/test/resources/repository'),
|
||||
[], new StubRunnerOptionsBuilder().build())
|
||||
[], stubRunnerOptions, null)
|
||||
}
|
||||
|
||||
def 'should provide URL for given relative path of stub'() {
|
||||
@@ -173,7 +173,7 @@ class StubRunnerExecutorSpec extends Specification {
|
||||
when:
|
||||
executor.runStubs(stubRunnerOptions,
|
||||
new StubRepository(new File('src/test/resources/repository/httpcontract'),
|
||||
[], new StubRunnerOptionsBuilder().build()), stubConf)
|
||||
[], new StubRunnerOptionsBuilder().build(), null), stubConf)
|
||||
then:
|
||||
!executor.trigger()
|
||||
!executor.trigger("missing", "label")
|
||||
@@ -186,10 +186,11 @@ class StubRunnerExecutorSpec extends Specification {
|
||||
given:
|
||||
def stubConf = new StubConfiguration('asd', 'asd', 'asd', '')
|
||||
StubRunnerExecutor executor = new StubRunnerExecutor(portScanner)
|
||||
stubRunnerOptions = new StubRunnerOptionsBuilder().withFailOnNoStubs(false).build()
|
||||
when:
|
||||
RunningStubs stubs = executor.runStubs(stubRunnerOptions,
|
||||
new StubRepository(new File('src/test/resources/emptyrepo'),
|
||||
[], new StubRunnerOptionsBuilder().build()), stubConf)
|
||||
[], stubRunnerOptions, null), stubConf)
|
||||
then:
|
||||
stubs.getPort('asd') == -1
|
||||
cleanup:
|
||||
@@ -204,7 +205,7 @@ class StubRunnerExecutorSpec extends Specification {
|
||||
def stubConf = new StubConfiguration('asd', 'asd', 'asd', '')
|
||||
executor.runStubs(stubRunnerOptions,
|
||||
new StubRepository(new File('src/test/resources/messages'),
|
||||
[], new StubRunnerOptionsBuilder().build()), stubConf)
|
||||
[], new StubRunnerOptionsBuilder().build(), null), stubConf)
|
||||
boolean triggered = executor.trigger("trigger")
|
||||
then:
|
||||
triggered
|
||||
|
||||
@@ -24,6 +24,22 @@ import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessag
|
||||
|
||||
class StubRunnerFactorySpec extends Specification {
|
||||
|
||||
static final String MAPPING = '''
|
||||
{
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "/hello"
|
||||
},
|
||||
"response": {
|
||||
"status": 200,
|
||||
"body": "Hello world!",
|
||||
"headers": {
|
||||
"Content-Type": "text/plain"
|
||||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
@Rule
|
||||
TemporaryFolder folder = new TemporaryFolder()
|
||||
|
||||
@@ -42,6 +58,7 @@ class StubRunnerFactorySpec extends Specification {
|
||||
def "Should download stub definitions many times"() {
|
||||
given:
|
||||
folder.newFolder("mappings")
|
||||
folder.newFile("hello.json").text = MAPPING
|
||||
1 * downloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(new StubConfiguration('a:b'), folder.root)
|
||||
1 * downloader.downloadAndUnpackStubJar(_) >> new AbstractMap.SimpleEntry(new StubConfiguration('c:d'), folder.root)
|
||||
when:
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 java.util.function.Function
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner
|
||||
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerConfiguration
|
||||
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties
|
||||
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration
|
||||
import org.springframework.cloud.zookeeper.ZookeeperAutoConfiguration
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat
|
||||
|
||||
@AutoConfigureStubRunner(ids = "org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers",
|
||||
repositoryRoot = "classpath:m2repo/repository/",
|
||||
stubsMode = StubRunnerProperties.StubsMode.REMOTE,
|
||||
stubsPerConsumer = true)
|
||||
@ActiveProfiles("streamconsumer")
|
||||
class StubRunnerStubsPerConsumerNotMatchingConsumerSpec {
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(Config))
|
||||
.withPropertyValues("spring.application.name=bar-not-matching-consumer",
|
||||
"stubrunner.jms.enabled=false", "spring.profiles.active=streamconsumer", "spring.cloud.discovery.enabled=false", "spring.cloud.service-registry.auto-registration.enabled=false", "stubrunner.ids=org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers", "stubrunner.repositoryRoot=classpath:m2repo/repository/", "stubrunner.stubsMode=REMOTE", "stubrunner.stubsPerConsumer=true");
|
||||
|
||||
@Test
|
||||
void 'should fail to start when JAR is found but there are no stubs or contracts'() {
|
||||
expect:
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasFailed();
|
||||
assertThat(context.getStartupFailure()).hasMessageContaining("No stubs or contracts were found for [org.springframework.cloud.contract.verifier.stubs:producerWithMultipleConsumers:0.0.1-SNAPSHOT:stubs] and the switch to fail on no stubs was set")
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = [ZookeeperAutoConfiguration])
|
||||
@ImportAutoConfiguration(TestChannelBinderConfiguration.class)
|
||||
@Import(value = StubRunnerConfiguration)
|
||||
static class Config {
|
||||
@Bean
|
||||
Function output() {
|
||||
return { Object o ->
|
||||
println(o)
|
||||
return o
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class StubRepositoryTest {
|
||||
public void should_prefer_custom_yaml_converter_over_standard() {
|
||||
// given:
|
||||
StubRepository repository = new StubRepository(YAML_REPOSITORY_LOCATION, new ArrayList<>(),
|
||||
new StubRunnerOptionsBuilder().build());
|
||||
new StubRunnerOptionsBuilder().build(), null);
|
||||
int expectedDescriptorsSize = 1;
|
||||
|
||||
// when:
|
||||
|
||||
Reference in New Issue
Block a user