Spring Cloud Compatibility Verification

Due to the fact that some users have problem with setting up Spring Cloud application, we've decided
to add a compatibility verification mechanism. It will break if your current setup is not compatible
with Spring Cloud requirements, together with a report, showing what exactly went wrong.

At the moment we verify which version of Spring Boot is added to your classpath.

Example of a report

```
***************************
APPLICATION FAILED TO START
***************************

Description:

Your project setup is incompatible with our requirements due to following reasons:

- Spring Boot [1.5.16.RELEASE] is not compatible with this Spring Cloud release train


Action:

Consider applying the following actions:

- Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] .
You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn].
If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.
```


In order to disable this feature, set `spring.cloud.compatibility-verifier.enabled` to `false`.
If you want to override the compatible Spring Boot versions, just set the
`spring.cloud.compatibility-verifier.compatible-boot-versions` property with a comma separated list
of compatible Spring Boot versions.

fixes gh-442
This commit is contained in:
Marcin Grzejszczak
2018-11-15 15:40:29 +01:00
committed by GitHub
parent a2ba7a57e3
commit 80659a36b1
16 changed files with 979 additions and 1 deletions

View File

@@ -576,4 +576,41 @@ HTTP client and `OkHttpClientConnectionPoolFactory` for the OK HTTP client. You
your own implementation of these beans if you would like to customize how the HTTP clients are created
in downstream projects. You can also disable the creation of these beans by setting
`spring.cloud.httpclientfactories.apache.enabled` or `spring.cloud.httpclientfactories.ok.enabled` to
`false`.
`false`.
=== Spring Cloud Compatibility Verification
Due to the fact that some users have problem with setting up Spring Cloud application, we've decided
to add a compatibility verification mechanism. It will break if your current setup is not compatible
with Spring Cloud requirements, together with a report, showing what exactly went wrong.
At the moment we verify which version of Spring Boot is added to your classpath.
Example of a report
----
***************************
APPLICATION FAILED TO START
***************************
Description:
Your project setup is incompatible with our requirements due to following reasons:
- Spring Boot [1.5.16.RELEASE] is not compatible with this Spring Cloud release train
Action:
Consider applying the following actions:
- Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] .
You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn].
If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.
----
In order to disable this feature, set `spring.cloud.compatibility-verifier.enabled` to `false`.
If you want to override the compatible Spring Boot versions, just set the
`spring.cloud.compatibility-verifier.compatible-boot-versions` property with a comma separated list
of compatible Spring Boot versions.

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import java.util.List;
/**
* Exception thrown when the current setup is not compatible
*
* @author Marcin Grzejszczak
* @since 1.3.6
*/
class CompatibilityNotMetException extends RuntimeException {
final List<VerificationResult> results;
CompatibilityNotMetException(List<VerificationResult> results) {
this.results = results;
}
}

View File

@@ -0,0 +1,46 @@
package org.springframework.cloud.configuration;
import java.util.List;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
import org.springframework.boot.diagnostics.FailureAnalysis;
/**
* Analyzer for the {@link CompatibilityNotMetException}. Prints a list of found
* issues and actions that should be taken to fix them.
*
* @author Marcin Grzejszczak
* @since 1.3.6
*/
public final class CompatibilityNotMetFailureAnalyzer extends AbstractFailureAnalyzer<CompatibilityNotMetException> {
@Override
protected FailureAnalysis analyze(Throwable rootFailure, CompatibilityNotMetException cause) {
return new FailureAnalysis(getDescription(cause), getAction(cause), cause);
}
private String getDescription(CompatibilityNotMetException ex) {
return String.format("Your project setup is incompatible with our requirements "
+ "due to following reasons:%s", descriptions(ex.results));
}
private String descriptions(List<VerificationResult> results) {
StringBuilder builder = new StringBuilder("\n\n");
for (VerificationResult result : results) {
builder.append("- ").append(result.description).append("\n");
}
return builder.toString();
}
private String getAction(CompatibilityNotMetException ex) {
return String.format("Consider applying the following actions:%s",
actions(ex.results));
}
private String actions(List<VerificationResult> results) {
StringBuilder builder = new StringBuilder("\n\n");
for (VerificationResult result : results) {
builder.append("- ").append(result.action).append("\n");
}
return builder.toString();
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
/**
* So that can be used for jdk 7 - otherwise we would use a predicate
* @author Marcin Grzejszczak
*/
interface CompatibilityPredicate {
boolean isCompatible();
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
/**
* Implementations will verify the compatibility and return a result that
* says whether the check is compatible or not for the current release train
*
* @author Marcin Grzejszczak
* @since 1.3.6
*/
interface CompatibilityVerifier {
VerificationResult verify();
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import java.util.List;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} that fails the build fast for incompatible
* versions of dependencies (e.g. invalid version of Boot).
*
* @author Marcin Grzejszczak
* @since 1.3.6
*/
@Configuration
@ConditionalOnProperty(value = "spring.cloud.compatibility-verifier.enabled", matchIfMissing = true)
@AutoConfigureOrder(0)
@EnableConfigurationProperties(CompatibilityVerifierProperties.class)
public class CompatibilityVerifierAutoConfiguration {
@Bean
CompositeCompatibilityVerifier compositeCompatibilityVerifier(List<CompatibilityVerifier> verifiers) {
CompositeCompatibilityVerifier verifier = new CompositeCompatibilityVerifier(verifiers);
verifier.verifyDependencies();
return verifier;
}
@Bean
SpringBootVersionVerifier springBootVersionVerifier(
CompatibilityVerifierProperties properties) {
return new SpringBootVersionVerifier(properties.getCompatibleBootVersions());
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Marcin Grzejszczak
*/
@ConfigurationProperties("spring.cloud.compatibility-verifier")
public class CompatibilityVerifierProperties {
/**
* Enables creation of Spring Cloud compatibility verification.
*/
private boolean enabled;
/**
* Default accepted versions for the Spring Boot dependency. You can set {@code x}
* for the patch version if you don't want to specify a concrete value.
* Example: {@code 3.4.x}
*/
private List<String> compatibleBootVersions = Collections.singletonList("1.5.x");
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public List<String> getCompatibleBootVersions() {
return this.compatibleBootVersions;
}
public void setCompatibleBootVersions(List<String> compatibleBootVersions) {
this.compatibleBootVersions = compatibleBootVersions;
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Iterates over {@link CompatibilityVerifier} and prepares a report if exceptions were found
*/
class CompositeCompatibilityVerifier {
private static final Log log = LogFactory.getLog(CompositeCompatibilityVerifier.class);
private final List<CompatibilityVerifier> verifiers;
CompositeCompatibilityVerifier(List<CompatibilityVerifier> verifiers) {
this.verifiers = verifiers;
}
void verifyDependencies() {
List<VerificationResult> errors = verifierErrors();
if (errors.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("All conditions are passing");
}
return;
}
throw new CompatibilityNotMetException(errors);
}
private List<VerificationResult> verifierErrors() {
List<VerificationResult> errors = new ArrayList<>();
for (CompatibilityVerifier verifier : this.verifiers) {
VerificationResult result = verifier.verify();
if (result.isNotCompatible()) {
errors.add(result);
}
}
return errors;
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.util.StringUtils;
/**
* Verifies if Spring Boot has proper version
*/
class SpringBootVersionVerifier implements CompatibilityVerifier {
private static final Log log = LogFactory.getLog(SpringBootVersionVerifier.class);
final Map<String, CompatibilityPredicate> ACCEPTED_VERSIONS = new HashMap<String, CompatibilityPredicate>() {
{
this.put("1.5", is1_5());
this.put("2.0", is2_0());
this.put("2.1", is2_1());
}
};
private final List<String> acceptedVersions;
SpringBootVersionVerifier(List<String> acceptedVersions) {
this.acceptedVersions = acceptedVersions;
}
@Override
public VerificationResult verify() {
boolean matches = springBootVersionMatches();
if (matches) {
return VerificationResult.compatible();
}
return VerificationResult.notCompatible(errorDescription(), action());
}
CompatibilityPredicate is1_5() {
return new CompatibilityPredicate() {
@Override
public String toString() {
return "Predicate for Boot 1.5";
}
@Override
public boolean isCompatible() {
try {
// deprecated 1.5
Class.forName("org.springframework.boot.context.config.ResourceNotFoundException");
return true;
}
catch (ClassNotFoundException e) {
return false;
}
}
};
}
private boolean bootVersionFromManifest(String s) {
String version = getVersionFromManifest();
if (log.isDebugEnabled()) {
log.debug("Version found in Boot manifest [" + version + "]");
}
return StringUtils.hasText(version) && version.startsWith(s);
}
String getVersionFromManifest() {
return SpringBootVersion.getVersion();
}
CompatibilityPredicate is2_0() {
return new CompatibilityPredicate() {
@Override
public String toString() {
return "Predicate for Boot 2.0";
}
@Override
public boolean isCompatible() {
try {
// present in 2.0, 1.5 missing in 2.1
SpringApplicationBuilder.class.getMethod("web", boolean.class);
return !is1_5().isCompatible();
}
catch (NoSuchMethodException e) {
return false;
}
}
};
}
CompatibilityPredicate is2_1() {
return new CompatibilityPredicate() {
@Override
public String toString() {
return "Predicate for Boot 2.1";
}
@Override
public boolean isCompatible() {
try {
// since 2.1
Class.forName("org.springframework.boot.task.TaskExecutorCustomizer");
return true;
}
catch (ClassNotFoundException e) {
return false;
}
}
};
}
private String errorDescription() {
String versionFromManifest = getVersionFromManifest();
if (StringUtils.hasText(versionFromManifest)) {
return String.format("Spring Boot [%s] is not compatible with this Spring Cloud release train", versionFromManifest);
}
return "Spring Boot is not compatible with this Spring Cloud release train";
}
private String action() {
return String.format("Change Spring Boot version to one of the following versions %s .\n"
+ "You can find the latest Spring Boot versions here [%s]. \n"
+ "If you want to learn more about the Spring Cloud Release train compatibility, you "
+ "can visit this page [%s] and check the [Release Trains] section.",
this.acceptedVersions, "https://spring.io/projects/spring-boot#learn", "https://spring.io/projects/spring-cloud#overview");
}
private boolean springBootVersionMatches() {
for (String acceptedVersion : acceptedVersions) {
if (bootVersionFromManifest(acceptedVersion)) {
return true;
}
else {
// 2.0, 2.1
CompatibilityPredicate predicate = ACCEPTED_VERSIONS.get(
acceptedVersionWithoutX(acceptedVersion));
if (predicate != null && predicate.isCompatible()) {
if (log.isDebugEnabled()) {
log.debug("Predicate [" + predicate + "] was matched");
}
return true;
}
}
}
return false;
}
private String acceptedVersionWithoutX(String acceptedVersion) {
if (acceptedVersion.endsWith(".x")) {
return acceptedVersion.substring(0, acceptedVersion.indexOf(".x"));
}
return acceptedVersion;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import org.springframework.util.StringUtils;
/**
* @author Marcin Grzejszczak
*/
class VerificationResult {
final String description;
final String action;
// if OK
private VerificationResult() {
this.description = "";
this.action = "";
}
// if not OK
private VerificationResult(String errorDescription, String action) {
this.description = errorDescription;
this.action = action;
}
static VerificationResult compatible() {
return new VerificationResult();
}
static VerificationResult notCompatible(String errorDescription, String action) {
return new VerificationResult(errorDescription, action);
}
boolean isNotCompatible() {
return StringUtils.hasText(this.description) || StringUtils.hasText(this.action);
}
}

View File

@@ -7,6 +7,7 @@ org.springframework.cloud.client.loadbalancer.AsyncLoadBalancerAutoConfiguration
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,\
org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration,\
org.springframework.cloud.commons.util.UtilAutoConfiguration,\
org.springframework.cloud.configuration.CompatibilityVerifierAutoConfiguration,\
org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration,\
org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
org.springframework.cloud.commons.httpclient.HttpClientConfiguration,\
@@ -16,3 +17,7 @@ org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConf
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.cloud.configuration.CompatibilityNotMetFailureAnalyzer

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import org.assertj.core.api.BDDAssertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Marcin Grzejszczak
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CompatibilityVerifierAutoConfigurationTests {
@Autowired
MyCompatibilityVerifier myMismatchVerifier;
@Test
public void contextLoads() {
BDDAssertions.then(this.myMismatchVerifier.called).isTrue();
}
@Configuration
@EnableAutoConfiguration
static class TestConfiguration {
@Bean
MyCompatibilityVerifier myMismatchVerifier() {
return new MyCompatibilityVerifier();
}
}
private static class MyCompatibilityVerifier implements CompatibilityVerifier {
boolean called;
@Override
public VerificationResult verify() {
this.called = true;
return VerificationResult.compatible();
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import org.assertj.core.api.BDDAssertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Marcin Grzejszczak
*/
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.cloud.compatibility-verifier.enabled=false")
public class CompatibilityVerifierDisabledAutoConfigurationTests {
@Autowired(required = false)
CompositeCompatibilityVerifier compositeCompatibilityVerifier;
@Test
public void contextLoads() {
BDDAssertions.then(this.compositeCompatibilityVerifier).isNull();
}
@Configuration
@EnableAutoConfiguration
static class TestConfiguration {
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import org.assertj.core.api.BDDAssertions;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.NestedExceptionUtils;
/**
* @author Marcin Grzejszczak
*/
public class CompatibilityVerifierFailureAutoConfigurationTests {
@Rule public OutputCapture outputCapture = new OutputCapture();
@Test
public void contextFailsToLoad() {
try {
SpringApplication.run(TestConfiguration.class,
"--spring.cloud.compatibility-verifier.compatible-boot-versions=1.2.x,1.3.x");
BDDAssertions.fail("should throw exception");
} catch (BeanCreationException ex) {
Throwable cause = NestedExceptionUtils.getRootCause(ex);
BDDAssertions.then(((CompatibilityNotMetException) cause).results).hasSize(1);
}
}
@Configuration
@EnableAutoConfiguration
static class TestConfiguration {
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import java.util.ArrayList;
import java.util.List;
import org.assertj.core.api.BDDAssertions;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.test.rule.OutputCapture;
/**
* @author Marcin Grzejszczak
*/
public class CompatibilityVerifierTests {
@Rule public OutputCapture outputCapture = new OutputCapture();
@Test
public void should_not_print_the_report_when_no_errors_were_found() {
CompositeCompatibilityVerifier verifier = new CompositeCompatibilityVerifier(new ArrayList<CompatibilityVerifier>());
verifier.verifyDependencies();
BDDAssertions.then(outputCapture.toString()).doesNotContain("SPRING CLOUD VERIFICATION FAILED");
}
@Test
public void should_print_the_report_when_errors_were_found() {
List<CompatibilityVerifier> list = new ArrayList<>();
list.add(new CompatibilityVerifier() {
@Override
public VerificationResult verify() {
return VerificationResult.notCompatible("Wrong Boot version", "Use Boot version 1.2");
}
});
list.add(new CompatibilityVerifier() {
@Override
public VerificationResult verify() {
return VerificationResult.notCompatible("Wrong JDK version", "Use JDK 25");
}
});
CompositeCompatibilityVerifier verifier = new CompositeCompatibilityVerifier(list);
try {
verifier.verifyDependencies();
BDDAssertions.fail("should fail");
} catch (CompatibilityNotMetException ex) {
BDDAssertions.then(ex.results).hasSize(2);
}
}
}

View File

@@ -0,0 +1,209 @@
/*
* Copyright 2002-2018 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
*
* http://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.configuration;
import java.util.Collections;
import java.util.List;
import org.assertj.core.api.BDDAssertions;
import org.junit.Test;
/**
* @author Marcin Grzejszczak
*/
public class SpringBootDependencyTests {
@Test
public void should_read_concrete_version_from_manifest() {
List<String> acceptedVersions = Collections.singletonList("2.0.3.RELEASE");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
@Override
String getVersionFromManifest() {
return "2.0.3.RELEASE";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isEmpty();
BDDAssertions.then(verificationResult.action).isEmpty();
}
@Test
public void should_read_concrete_version_from_manifest_and_return_false_when_version_is_not_matched() {
List<String> acceptedVersions = Collections.singletonList("2.0.9.RELEASE");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
@Override
String getVersionFromManifest() {
return "2.0.3.RELEASE";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isNotEmpty();
BDDAssertions.then(verificationResult.action).isNotEmpty();
}
@Test
public void should_read_concrete_version_from_manifest_and_return_false_when_minor_version_is_not_matched() {
List<String> acceptedVersions = Collections.singletonList("2.0");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
@Override
String getVersionFromManifest() {
return "2.1.3.RELEASE";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isNotEmpty();
BDDAssertions.then(verificationResult.action).isNotEmpty();
}
@Test
public void should_read_concrete_version_from_manifest_and_match_it_against_minor_version() {
List<String> acceptedVersions = Collections.singletonList("2.0");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
@Override
String getVersionFromManifest() {
return "2.0.3.RELEASE";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isEmpty();
BDDAssertions.then(verificationResult.action).isEmpty();
}
@Test
public void should_match_against_predicate() {
List<String> acceptedVersions = Collections.singletonList("2.5");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
@Override
String getVersionFromManifest() {
return "";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
versionVerifier.ACCEPTED_VERSIONS.put("2.5", new CompatibilityPredicate() {
@Override
public boolean isCompatible() {
return true;
}
});
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isEmpty();
BDDAssertions.then(verificationResult.action).isEmpty();
}
@Test
public void should_fail_to_match_against_predicate_when_none_is_matching() {
List<String> acceptedVersions = Collections.singletonList("2.5");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
@Override
String getVersionFromManifest() {
return "";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isNotEmpty();
BDDAssertions.then(verificationResult.action).isNotEmpty();
}
@Test
public void should_match_against_current_manifest() {
List<String> acceptedVersions = Collections.singletonList("1.5");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions);
versionVerifier.ACCEPTED_VERSIONS.clear();
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isEmpty();
BDDAssertions.then(verificationResult.action).isEmpty();
}
@Test
public void should_match_against_current_predicate() {
List<String> acceptedVersions = Collections.singletonList("1.5");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions){
@Override
String getVersionFromManifest() {
return "";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
versionVerifier.ACCEPTED_VERSIONS.put("1.5", versionVerifier.is1_5());
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isEmpty();
BDDAssertions.then(verificationResult.action).isEmpty();
}
@Test
public void should_match_against_current_predicate_with_version_ending_with_x() {
List<String> acceptedVersions = Collections.singletonList("1.5.x");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions){
@Override
String getVersionFromManifest() {
return "";
}
};
versionVerifier.ACCEPTED_VERSIONS.clear();
versionVerifier.ACCEPTED_VERSIONS.put("1.5", versionVerifier.is1_5());
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isEmpty();
BDDAssertions.then(verificationResult.action).isEmpty();
}
@Test
public void should_fail_to_match_against_predicate_for_non_current_versions() {
List<String> acceptedVersions = Collections.singletonList("1.5");
SpringBootVersionVerifier
versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
@Override
String getVersionFromManifest() {
return "";
}
};
versionVerifier.ACCEPTED_VERSIONS.remove("1.5");
VerificationResult verificationResult = versionVerifier.verify();
BDDAssertions.then(verificationResult.description).isNotEmpty();
BDDAssertions.then(verificationResult.action).isNotEmpty();
}
}