From 4ae133a0f885084a16435e4df37beff01397ea47 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 6 Aug 2019 11:54:52 +0200 Subject: [PATCH] Add a switch to fail on no stubs (#1153) * Add a switch to fail on no stubs without this change we throw an exception if no stubs / contracts were found with this change we catch exceptions from aether stub downloader and if there are no stubs found whatsover, and a switch is set to fail in that case, then we do throw an exception that no stubs / contracts were found fixes gh-895 --- .../stubrunner/AetherStubDownloader.java | 37 +++++++++---------- .../CompositeStubDownloaderBuilder.java | 15 ++++++++ .../stubrunner/StubRunnerOptions.java | 15 +++++++- .../stubrunner/StubRunnerOptionsBuilder.java | 11 +++++- .../stubrunner/junit/StubRunnerExtension.java | 6 +++ .../junit/StubRunnerExtensionOptions.java | 7 ++++ .../stubrunner/junit/StubRunnerRule.java | 8 +++- .../junit/StubRunnerRuleOptions.java | 7 ++++ .../spring/AutoConfigureStubRunner.java | 6 +++ .../spring/StubRunnerProperties.java | 14 +++++++ .../AetherStubDownloaderSpec.groovy | 10 ++--- .../StubRunnerOptionsBuilderSpec.groovy | 7 +++- .../CompositeStubDownloaderBuilderTests.java | 28 ++++++++++++++ .../StubDownloaderBuilderProviderTests.java | 3 +- .../plugin/ContractVerifierExtension.groovy | 13 ++++++- .../plugin/GradleContractsDownloader.groovy | 1 + .../contract/maven/verifier/ConvertMojo.java | 12 +++++- .../maven/verifier/GenerateTestsMojo.java | 12 +++++- .../verifier/MavenContractsDownloader.java | 8 +++- .../FailFastLoanApplicationServiceTests.java | 3 +- 20 files changed, 182 insertions(+), 41 deletions(-) diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java index c7b24a2c84..fa7ecc8169 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java @@ -29,7 +29,6 @@ import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.Proxy; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactRequest; @@ -205,14 +204,6 @@ public class AetherStubDownloader implements StubDownloader { } } - private boolean resolvedFromLocalRepo(ArtifactResult result) { - return result.getRepository() instanceof LocalRepository; - } - - private boolean shouldDownloadFromRemote() { - return !remoteReposMissing() && !this.workOffline; - } - private String getVersion(String stubsGroup, String stubsModule, String version, String classifier) { if (StringUtils.isEmpty(version) || LATEST_VERSION_IN_IVY.equals(version)) { @@ -228,20 +219,26 @@ public class AetherStubDownloader implements StubDownloader { @Override public Map.Entry downloadAndUnpackStubJar( StubConfiguration stubConfiguration) { - String version = getVersion(stubConfiguration.groupId, - stubConfiguration.artifactId, stubConfiguration.version, - stubConfiguration.classifier); - if (log.isDebugEnabled()) { - log.debug("Will download the stub for version [" + version + "]"); + try { + String version = getVersion(stubConfiguration.groupId, + stubConfiguration.artifactId, stubConfiguration.version, + stubConfiguration.classifier); + if (log.isDebugEnabled()) { + log.debug("Will download the stub for version [" + version + "]"); + } + File unpackedJar = unpackedJar(version, stubConfiguration.groupId, + stubConfiguration.artifactId, stubConfiguration.classifier); + if (unpackedJar == null) { + return null; + } + return new AbstractMap.SimpleEntry<>(new StubConfiguration( + stubConfiguration.groupId, stubConfiguration.artifactId, version, + stubConfiguration.classifier), unpackedJar); } - File unpackedJar = unpackedJar(version, stubConfiguration.groupId, - stubConfiguration.artifactId, stubConfiguration.classifier); - if (unpackedJar == null) { + catch (Exception ex) { + log.warn("Exception occurred while trying to fetch the stubs", ex); return null; } - return new AbstractMap.SimpleEntry<>(new StubConfiguration( - stubConfiguration.groupId, stubConfiguration.artifactId, version, - stubConfiguration.classifier), unpackedJar); } private String resolveHighestArtifactVersion(String stubsGroup, String stubsModule, diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java index ed635d1d1c..5c64665f84 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilder.java @@ -67,6 +67,21 @@ class CompositeStubDownloader implements StubDownloader { @Override public Map.Entry downloadAndUnpackStubJar( StubConfiguration stubConfiguration) { + Map.Entry entry = entry(stubConfiguration); + if (entry != null) { + return entry; + } + log.warn("No matching stubs or contracts were found"); + if (this.stubRunnerOptions.isFailOnNoStubs()) { + throw new IllegalArgumentException("No stubs or contracts were found for [" + + stubConfiguration.toColonSeparatedDependencyNotation() + + "] and the switch to fail on no stubs was set."); + } + return null; + } + + private Map.Entry entry( + StubConfiguration stubConfiguration) { for (StubDownloaderBuilder builder : this.builders) { StubDownloader downloader = builder.build(this.stubRunnerOptions); if (downloader == null) { diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java index 233fab56fa..ac5cfff7c5 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptions.java @@ -122,6 +122,12 @@ public class StubRunnerOptions { */ private boolean generateStubs; + /** + * When enabled, this flag will tell stub runner to throw an exception when no stubs / + * contracts were found. + */ + private boolean failOnNoStubs = true; + /** * Map of properties that can be passed to custom * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. @@ -134,7 +140,7 @@ public class StubRunnerOptions { Map stubIdsToPortMapping, String username, String password, final StubRunnerProxyOptions stubRunnerProxyOptions, boolean stubsPerConsumer, String consumerName, String mappingsOutputFolder, - boolean deleteStubsAfterTest, boolean generateStubs, + boolean deleteStubsAfterTest, boolean generateStubs, boolean failOnNoStubs, Map properties, Class httpServerStubConfigurer) { this.minPortValue = minPortValue; @@ -153,6 +159,7 @@ public class StubRunnerOptions { this.mappingsOutputFolder = mappingsOutputFolder; this.deleteStubsAfterTest = deleteStubsAfterTest; this.generateStubs = generateStubs; + this.failOnNoStubs = failOnNoStubs; this.properties = properties; this.httpServerStubConfigurer = httpServerStubConfigurer; } @@ -179,6 +186,8 @@ public class StubRunnerOptions { System.getProperty("stubrunner.delete-stubs-after-test", "true"))) .withGenerateStubs(Boolean.parseBoolean( System.getProperty("stubrunner.generate-stubs", "false"))) + .withFailOnNoStubs(Boolean.parseBoolean( + System.getProperty("stubrunner.fail-on-no-stubs", "false"))) .withProperties(stubRunnerProps()); builder = httpStubConfigurer(builder); String proxyHost = System.getProperty("stubrunner.proxy.host"); @@ -332,6 +341,10 @@ public class StubRunnerOptions { return this.generateStubs; } + public boolean isFailOnNoStubs() { + return this.failOnNoStubs; + } + public Map getProperties() { return this.properties; } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java index 5c09456185..64d99e7dfd 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilder.java @@ -71,6 +71,8 @@ public class StubRunnerOptionsBuilder { private boolean generateStubs; + private boolean failOnNoStubs = true; + private Map properties = new HashMap<>(); private Class httpServerStubConfigurer = HttpServerStubConfigurer.NoOpHttpServerStubConfigurer.class; @@ -197,6 +199,7 @@ public class StubRunnerOptionsBuilder { ? options.stubIdsToPortMapping : new LinkedHashMap<>(); this.deleteStubsAfterTest = options.isDeleteStubsAfterTest(); this.generateStubs = options.isGenerateStubs(); + this.failOnNoStubs = options.isFailOnNoStubs(); this.properties = options.getProperties(); this.httpServerStubConfigurer = options.getHttpServerStubConfigurer(); return this; @@ -219,6 +222,11 @@ public class StubRunnerOptionsBuilder { return this; } + public StubRunnerOptionsBuilder withFailOnNoStubs(boolean failOnNoStubs) { + this.failOnNoStubs = failOnNoStubs; + return this; + } + public StubRunnerOptionsBuilder withProperties(Map properties) { this.properties = properties; return this; @@ -236,7 +244,8 @@ public class StubRunnerOptionsBuilder { buildDependencies(), this.stubIdsToPortMapping, this.username, this.password, this.stubRunnerProxyOptions, this.stubsPerConsumer, this.consumerName, this.mappingsOutputFolder, this.deleteStubsAfterTest, - this.generateStubs, this.properties, this.httpServerStubConfigurer); + this.generateStubs, this.failOnNoStubs, this.properties, + this.httpServerStubConfigurer); } private Collection buildDependencies() { diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java index 8911323787..ea49351172 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtension.java @@ -258,6 +258,12 @@ public class StubRunnerExtension implements BeforeAllCallback, AfterAllCallback, return new PortStubRunnerExtension(this.delegate); } + @Override + public StubRunnerExtension failOnNoStubs(boolean failOnNoStubs) { + builder().withFailOnNoStubs(failOnNoStubs); + return new PortStubRunnerExtension(this.delegate); + } + @Override public StubRunnerExtension withProperties(Map properties) { builder().withProperties(properties); diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java index b8dac75b39..4e17decd1c 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerExtensionOptions.java @@ -156,6 +156,13 @@ interface StubRunnerExtensionOptions { */ StubRunnerExtension withGenerateStubs(boolean generateStubs); + /** + * @param failOnNoStubs when enabled, this flag will tell stub runner to throw an + * exception when no stubs / contracts were found. + * @return the rule + */ + StubRunnerExtension failOnNoStubs(boolean failOnNoStubs); + /** * @param properties Map of properties that can be passed to custom * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java index ba52f4f04d..9e6c2653ca 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRule.java @@ -192,10 +192,16 @@ public class StubRunnerRule implements TestRule, StubFinder, StubRunnerRuleOptio @Override public StubRunnerRule withGenerateStubs(boolean generateStubs) { - builder().withGenerateStubs(true); + builder().withGenerateStubs(generateStubs); return this.delegate; } + @Override + public StubRunnerRule failOnNoStubs(boolean failOnNoStubs) { + builder().withFailOnNoStubs(failOnNoStubs); + return null; + } + @Override public StubRunnerRule withProperties(Map properties) { builder().withProperties(properties); diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java index 510970f341..4a0da66c33 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/junit/StubRunnerRuleOptions.java @@ -152,6 +152,13 @@ interface StubRunnerRuleOptions { */ StubRunnerRule withGenerateStubs(boolean generateStubs); + /** + * @param failOnNoStubs when enabled, this flag will tell stub runner to throw an + * exception when no stubs / contracts were found. + * @return the rule + */ + StubRunnerRule failOnNoStubs(boolean failOnNoStubs); + /** * @param properties Map of properties that can be passed to custom * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java index 679724f8ae..387f3dfa61 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/AutoConfigureStubRunner.java @@ -144,6 +144,12 @@ public @interface AutoConfigureStubRunner { */ boolean generateStubs() default false; + /** + * @return when enabled, this flag will tell stub runner to throw an exception when no + * stubs / contracts were found. + */ + boolean failOnNoStubs() default true; + /** * Configuration for an HTTP server stub. * @return class that allows to perform additional HTTP server stub configuration diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java index 41bd683a3f..d4422ab7a1 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java @@ -114,6 +114,12 @@ public class StubRunnerProperties { */ private boolean generateStubs; + /** + * When enabled, this flag will tell stub runner to throw an exception when no stubs / + * contracts were found. + */ + private boolean failOnNoStubs = true; + /** * Map of properties that can be passed to custom * {@link org.springframework.cloud.contract.stubrunner.StubDownloaderBuilder}. @@ -260,6 +266,14 @@ public class StubRunnerProperties { this.generateStubs = generateStubs; } + public boolean isFailOnNoStubs() { + return this.failOnNoStubs; + } + + public void setFailOnNoStubs(boolean failOnNoStubs) { + this.failOnNoStubs = failOnNoStubs; + } + public Class getHttpServerStubConfigurer() { return this.httpServerStubConfigurer; } diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy index 23b6ced6c8..b9a19a4bd9 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/AetherStubDownloaderSpec.groovy @@ -43,11 +43,10 @@ class AetherStubDownloaderSpec extends Specification { AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions) when: - aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("non.existing.group", "missing-artifact-id", "1.0-SNAPSHOT")) + def entry = aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("non.existing.group", "missing-artifact-id", "1.0-SNAPSHOT")) then: - IllegalStateException e = thrown(IllegalStateException) - e.message.contains("Exception occurred while trying to download a stub for group") + entry == null } def 'should throw an exception when local m2 gets replaced with a temp dir and a jar is not found in remote'() { @@ -65,11 +64,10 @@ class AetherStubDownloaderSpec extends Specification { AetherStubDownloader aetherStubDownloader = new AetherStubDownloader(stubRunnerOptions) when: - aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("org.springframework.cloud", "spring-cloud-contract-spec", "+", "")) + def entry = aetherStubDownloader.downloadAndUnpackStubJar(new StubConfiguration("org.springframework.cloud", "spring-cloud-contract-spec", "+", "")) then: - IllegalArgumentException e = thrown(IllegalArgumentException) - e.message.contains("Could not find metadata org.springframework.cloud:spring-cloud-contract-spec/maven-metadata.xml in remote0") + entry == null } @RestoreSystemProperties diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy index 4c13826727..752c999a4f 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerOptionsBuilderSpec.groovy @@ -231,7 +231,7 @@ class StubRunnerOptionsBuilderSpec extends Specification { given: StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, new FileSystemResource("root"), StubRunnerProperties.StubsMode.LOCAL, "classifier", [new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "foo", "bar", - new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, true, [foo: "bar"], Foo)) + new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, true, false, [foo: "bar"], Foo)) builder.withStubs("foo:bar:baz") when: StubRunnerOptions options = builder.build() @@ -252,6 +252,7 @@ class StubRunnerOptionsBuilderSpec extends Specification { options.mappingsOutputFolder == "folder" options.deleteStubsAfterTest == false options.generateStubs == true + options.failOnNoStubs == false options.properties == [foo: "bar"] options.httpServerStubConfigurer == Foo } @@ -261,7 +262,7 @@ class StubRunnerOptionsBuilderSpec extends Specification { StubRunnerOptionsBuilder builder = builder.withOptions(new StubRunnerOptions(1, 2, new FileSystemResource("root"), StubRunnerProperties.StubsMode.CLASSPATH, "classifier", [new StubConfiguration("a:b:c")], [(new StubConfiguration("a:b:c")): 3], "username123", "password123", - new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, true, [:], Foo)) + new StubRunnerOptions.StubRunnerProxyOptions("host", 4), true, "consumer", "folder", false, true, true, [:], Foo)) builder.withStubs("foo:bar:baz") when: String options = builder.build().toString() @@ -293,6 +294,7 @@ class StubRunnerOptionsBuilderSpec extends Specification { System.setProperty("stubrunner.properties.bar.bar", "foo") System.setProperty("stubrunner.delete-stubs-after-test", "false") System.setProperty("stubrunner.generate-stubs", "true") + System.setProperty("stubrunner.fail-on-no-stubs", "false") System.setProperty("stubrunner.http-server-stub-configurer", "org.springframework.cloud.contract.stubrunner.Foo") when: StubRunnerOptions options = StubRunnerOptions.fromSystemProps() @@ -310,6 +312,7 @@ class StubRunnerOptionsBuilderSpec extends Specification { options.stubsPerConsumer == true options.deleteStubsAfterTest == false options.generateStubs == true + options.failOnNoStubs == false options.consumerName == "consumer" options.mappingsOutputFolder == "folder" options.properties == ["foo-bar": "bar", "foo-baz": "baz", "bar.bar": "foo"] diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java index 7b8f99da80..f7dd4c4e50 100644 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java +++ b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/CompositeStubDownloaderBuilderTests.java @@ -19,6 +19,7 @@ package org.springframework.cloud.contract.stubrunner; import java.io.File; import java.util.AbstractMap; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -57,6 +58,33 @@ public class CompositeStubDownloaderBuilderTests { BDDAssertions.then(downloader).isNull(); } + @Test + public void should_return_null_when_no_entries_were_found() { + EmptyStubDownloaderBuilder emptyStubDownloaderBuilder = new EmptyStubDownloaderBuilder(); + CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder( + Collections.singletonList(emptyStubDownloaderBuilder)); + StubDownloader downloader = builder + .build(new StubRunnerOptionsBuilder().withFailOnNoStubs(false).build()); + + Map.Entry entry = downloader + .downloadAndUnpackStubJar(new StubConfiguration("a:b:v")); + + BDDAssertions.then(entry).isNull(); + } + + @Test + public void should_throw_exception_when_no_entries_were_found_and_a_switch_to_throw_exception_was_set() { + EmptyStubDownloaderBuilder emptyStubDownloaderBuilder = new EmptyStubDownloaderBuilder(); + CompositeStubDownloaderBuilder builder = new CompositeStubDownloaderBuilder( + Collections.singletonList(emptyStubDownloaderBuilder)); + StubDownloader downloader = builder + .build(new StubRunnerOptionsBuilder().withFailOnNoStubs(true).build()); + + BDDAssertions.thenThrownBy( + () -> downloader.downloadAndUnpackStubJar(new StubConfiguration("a:b:v"))) + .isInstanceOf(IllegalArgumentException.class); + } + } class EmptyStubDownloaderBuilder implements StubDownloaderBuilder { diff --git a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java index 31519cc631..91a643ca87 100644 --- a/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java +++ b/spring-cloud-contract-stub-runner/src/test/java/org/springframework/cloud/contract/stubrunner/StubDownloaderBuilderProviderTests.java @@ -50,7 +50,8 @@ public class StubDownloaderBuilderProviderTests { .singletonList(StubDownloaderBuilderProviderTests.this.two); } }; - StubRunnerOptions options = new StubRunnerOptionsBuilder().build(); + StubRunnerOptions options = new StubRunnerOptionsBuilder() + .withFailOnNoStubs(false).build(); provider.get(options, this.three) .downloadAndUnpackStubJar(new StubConfiguration("a:b:c")); diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy index c4313411f1..975b5f6b65 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/ContractVerifierExtension.groovy @@ -267,7 +267,8 @@ class ContractVerifierExtension { password: this.contractRepository.password, proxyPort: this.contractRepository.proxyPort, proxyHost: this.contractRepository.proxyHost, - cacheDownloadedContracts: this.contractRepository.cacheDownloadedContracts + cacheDownloadedContracts: this.contractRepository.cacheDownloadedContracts, + failOnNoStubs: this.contractRepository.failOnNoStubs ), contractDependency: new Dependency( groupId: this.contractDependency.groupId, @@ -366,6 +367,12 @@ class ContractVerifierExtension { */ boolean cacheDownloadedContracts = true + /** + * When enabled, this flag will tell stub runner to throw an exception when no stubs / + * contracts were found. + */ + boolean failOnNoStubs = true + void repositoryUrl(String repositoryUrl) { this.repositoryUrl = repositoryUrl } @@ -389,5 +396,9 @@ class ContractVerifierExtension { void cacheDownloadedContracts(boolean cacheDownloadedContracts) { this.cacheDownloadedContracts = cacheDownloadedContracts } + + void failOnNoStubs(boolean failOnNoStubs) { + this.failOnNoStubs = failOnNoStubs + } } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy index fe5e82b887..e86d99c8b9 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-gradle-plugin/src/main/groovy/org/springframework/cloud/contract/verifier/plugin/GradleContractsDownloader.groovy @@ -91,6 +91,7 @@ class GradleContractsDownloader { if (extension.contractRepository.proxyPort) { options = options.withProxy(extension.contractRepository.proxyHost, extension.contractRepository.proxyPort) } + options = options.withFailOnNoStubs(extension.contractRepository.failOnNoStubs) return options.build() } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java index 1bef296575..80c475ba30 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/ConvertMojo.java @@ -181,6 +181,13 @@ public class ConvertMojo extends AbstractMojo { @Component(role = MavenResourcesFiltering.class, hint = "default") private MavenResourcesFiltering mavenResourcesFiltering; + /** + * When enabled, this flag will tell stub runner to throw an exception when no stubs / + * contracts were found. + */ + @Parameter(property = "failOnNoStubs", defaultValue = "true") + private boolean failOnNoStubs; + @Override public void execute() throws MojoExecutionException { if (this.skip) { @@ -271,8 +278,9 @@ public class ConvertMojo extends AbstractMojo { getLog(), this.contractsRepositoryUsername, this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, this.contractsRepositoryProxyPort, this.deleteStubsAfterTest, - this.contractsProperties).downloadAndUnpackContractsIfRequired(config, - this.contractsDirectory); + this.contractsProperties, this.failOnNoStubs) + .downloadAndUnpackContractsIfRequired(config, + this.contractsDirectory); } private File stubsOutputDir(String rootPath) { diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java index f596bc4087..50a3f6c0fc 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java @@ -229,6 +229,13 @@ public class GenerateTestsMojo extends AbstractMojo { @Parameter(property = "contractsProperties") private Map contractsProperties = new HashMap<>(); + /** + * When enabled, this flag will tell stub runner to throw an exception when no stubs / + * contracts were found. + */ + @Parameter(property = "failOnNoStubs", defaultValue = "true") + private boolean failOnNoStubs; + @Override public void execute() throws MojoExecutionException, MojoFailureException { if (this.skip || this.mavenTestSkip || this.skipTests) { @@ -258,8 +265,9 @@ public class GenerateTestsMojo extends AbstractMojo { this.contractsMode, getLog(), this.contractsRepositoryUsername, this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, this.contractsRepositoryProxyPort, this.deleteStubsAfterTest, - this.contractsProperties).downloadAndUnpackContractsIfRequired(config, - this.contractsDirectory); + this.contractsProperties, this.failOnNoStubs) + .downloadAndUnpackContractsIfRequired(config, + this.contractsDirectory); getLog().info( "Directory with contract is present at [" + contractsDirectory + "]"); setupConfig(config, contractsDirectory); diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java index ada1e128f6..45ca682e1d 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/MavenContractsDownloader.java @@ -71,12 +71,14 @@ class MavenContractsDownloader { private final Map contractsProperties; + private final boolean failOnNoStubs; + MavenContractsDownloader(MavenProject project, Dependency contractDependency, String contractsPath, String contractsRepositoryUrl, StubRunnerProperties.StubsMode stubsMode, Log log, String repositoryUsername, String repositoryPassword, String repositoryProxyHost, Integer repositoryProxyPort, boolean deleteStubsAfterTest, - Map contractsProperties) { + Map contractsProperties, boolean failOnNoStubs) { this.project = project; this.contractDependency = contractDependency; this.contractsPath = contractsPath; @@ -90,6 +92,7 @@ class MavenContractsDownloader { this.stubDownloaderBuilderProvider = new StubDownloaderBuilderProvider(); this.deleteStubsAfterTest = deleteStubsAfterTest; this.contractsProperties = contractsProperties; + this.failOnNoStubs = failOnNoStubs; } File downloadAndUnpackContractsIfRequired(ContractVerifierConfigProperties config, @@ -144,7 +147,8 @@ class MavenContractsDownloader { .withStubsMode(this.stubsMode).withUsername(this.repositoryUsername) .withPassword(this.repositoryPassword) .withDeleteStubsAfterTest(this.deleteStubsAfterTest) - .withProperties(this.contractsProperties); + .withProperties(this.contractsProperties) + .withFailOnNoStubs(this.failOnNoStubs); if (StringUtils.hasText(this.contractsRepositoryUrl)) { builder.withStubRepositoryRoot(this.contractsRepositoryUrl); } 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..0e83d7ddec 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 @@ -49,8 +49,7 @@ public class FailFastLoanApplicationServiceTests { assertThat(throwable.getCause()).isInstanceOf(BeanInstantiationException.class); assertThat(throwable.getCause().getCause()) .isInstanceOf(IllegalArgumentException.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"); + "No stubs or contracts were found for [org.springframework.cloud.contract.verifier.stubs:should-not-be-found:+:stubs] and the switch to fail on no stubs was set."); } @Test