:Merge branch '1.0.x'
This commit is contained in:
67
README.adoc
67
README.adoc
@@ -131,15 +131,6 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
}
|
||||
|
||||
/*
|
||||
Since we don't want to force on the user to hardcode values of fields that are dynamic
|
||||
(timestamps, database ids etc.), one can parametrize those entries. If you wrap your field's
|
||||
value in a `$(...)` or `value(...)` and provide a dynamic value of a field then
|
||||
the concrete value will be generated for you. If you want to be really explicit about
|
||||
which side gets which value you can do that by using the `value(consumer(...), producer(...))` notation.
|
||||
That way what's present in the `consumer` section will end up in the produced stub. What's
|
||||
there in the `producer` will end up in the autogenerated test. If you provide only the
|
||||
regular expression side without the concrete value then Spring Cloud Contract will generate one for you.
|
||||
|
||||
From the Consumer perspective, when shooting a request in the integration test:
|
||||
|
||||
(1) - If the consumer sends a request
|
||||
@@ -410,15 +401,6 @@ org.springframework.cloud.contract.spec.Contract.make {
|
||||
}
|
||||
|
||||
/*
|
||||
Since we don't want to force on the user to hardcode values of fields that are dynamic
|
||||
(timestamps, database ids etc.), one can parametrize those entries. If you wrap your field's
|
||||
value in a `$(...)` or `value(...)` and provide a dynamic value of a field then
|
||||
the concrete value will be generated for you. If you want to be really explicit about
|
||||
which side gets which value you can do that by using the `value(consumer(...), producer(...))` notation.
|
||||
That way what's present in the `consumer` section will end up in the produced stub. What's
|
||||
there in the `producer` will end up in the autogenerated test. If you provide only the
|
||||
regular expression side without the concrete value then Spring Cloud Contract will generate one for you.
|
||||
|
||||
From the Consumer perspective, when shooting a request in the integration test:
|
||||
|
||||
(1) - If the consumer sends a request
|
||||
@@ -814,6 +796,12 @@ For `stub-runner` use `spring-cloud-starter-stub-runner` and when you're using a
|
||||
Below you can find some resources related to Spring Cloud Contract Verifier and Stub Runner. Note that some can be outdated since the Spring Cloud Contract Verifier project
|
||||
is under constant development.
|
||||
|
||||
===== Spring Cloud Contract video
|
||||
|
||||
You can check out the video from the Warsaw JUG about Spring Cloud Contract:
|
||||
|
||||
video::sAAklvxmPmk[youtube,start=538,width=640,height=480]
|
||||
|
||||
===== Readings
|
||||
|
||||
- http://www.slideshare.net/MarcinGrzejszczak/stick-to-the-rules-consumer-driven-contracts-201507-confitura[Slides from Marcin Grzejszczak's talk about Accurest]
|
||||
@@ -1501,6 +1489,49 @@ public class WiremockForDocsClassRuleTests {
|
||||
|
||||
The use `@ClassRule` means that the server will shut down after all the methods in this class.
|
||||
|
||||
== Relaxed SSL Validation for Rest Template
|
||||
|
||||
WireMock allows you to stub a "secure" server with an "https" URL protocol. If your application wants to
|
||||
contact that stub server in an integration test, then it will find that the SSL certificates are not
|
||||
valid (it's the usual problem with self-installed certificates). The best option is often to just
|
||||
re-configure the client to use "http", but if that's not open to you then you can ask Spring to configure
|
||||
an HTTP client that ignores SSL validation errors (just for tests).
|
||||
|
||||
To make this work with minimum fuss you need to be using the Spring Boot `RestTemplateBuilder` in your app,
|
||||
e.g.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Bean
|
||||
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
----
|
||||
|
||||
This is because the builder is passed through callbacks to initalize it, so the SSL validation can be set up
|
||||
in the client at that point. This will happen automatically in your test if you are using the
|
||||
`@AutoConfigureWireMock` annotation (or the stub runner). If you are using the JUnit `@Rule` approach you need
|
||||
to add the `@AutoConfigureHttpClient` annotation as well:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest("app.baseUrl=https://localhost:6443")
|
||||
@AutoConfigureHttpClient
|
||||
public class WiremockHttpsServerApplicationTests {
|
||||
|
||||
@ClassRule
|
||||
public static WireMockClassRule wiremock = new WireMockClassRule(
|
||||
WireMockSpring.options().httpsPort(6443));
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
If you are using `spring-boot-starter-test` then you will have the Apache HTTP client on the classpath and it will
|
||||
be selected by the `RestTemplateBuilder` and configured to ignore SSL errors. If you are using the default `java.net`
|
||||
client you don't need the annotation (but it won't do any harm). There is no support currently for other clients, but
|
||||
it may be added in future releases.
|
||||
|
||||
== WireMock and Spring MVC Mocks
|
||||
|
||||
Spring Cloud Contract provides a convenience class that can load JSON WireMock stubs into a
|
||||
|
||||
@@ -73,9 +73,6 @@ class TestGenerator {
|
||||
}
|
||||
|
||||
int generate() {
|
||||
if (!configProperties.basePackageForTests) {
|
||||
|
||||
}
|
||||
generateTestClasses(configProperties.basePackageForTests)
|
||||
return counter.get()
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig
|
||||
@PackageScope
|
||||
class ClassBuilder {
|
||||
|
||||
private static final String SEPARATOR = "_REPLACEME_"
|
||||
|
||||
private final String className
|
||||
private final String packageName
|
||||
private final String baseClass
|
||||
@@ -70,7 +72,7 @@ class ClassBuilder {
|
||||
}
|
||||
|
||||
protected static String retrieveBaseClass(ContractVerifierConfigProperties properties, String includedDirectoryRelativePath) {
|
||||
String contractPackage = includedDirectoryRelativePath.replace(File.separator, '.')
|
||||
String contractPackage = includedDirectoryRelativePath.replace(File.separator, SEPARATOR)
|
||||
// package mapping takes super precedence
|
||||
if (properties.baseClassMappings) {
|
||||
Map.Entry<String, String> mapping = properties.baseClassMappings.find { String pattern, String fqn ->
|
||||
@@ -88,7 +90,7 @@ class ClassBuilder {
|
||||
}
|
||||
|
||||
private static String generateDefaultBaseClassName(String classPackage, ContractVerifierConfigProperties properties) {
|
||||
String[] splitPackage = NamesUtil.convertIllegalPackageChars(classPackage).split("\\.")
|
||||
String[] splitPackage = NamesUtil.convertIllegalPackageChars(classPackage).split(SEPARATOR)
|
||||
if (splitPackage.size() > 1) {
|
||||
String last = NamesUtil.capitalize(splitPackage[-1])
|
||||
String butLast = NamesUtil.capitalize(splitPackage[-2])
|
||||
|
||||
@@ -106,6 +106,6 @@ class NamesUtil {
|
||||
* Converts illegal package characters to underscores
|
||||
*/
|
||||
static String convertIllegalPackageChars(String packageName) {
|
||||
return packageName.replace('-', '_').replace(" ", "_")
|
||||
return packageName.replaceAll('[_\\- .]', '_')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,4 +60,12 @@ class ClassBuilderSpec extends Specification {
|
||||
ClassBuilder.retrieveBaseClass(props, contractRelativeFolder) == 'com.example.base.SuperpackageBase'
|
||||
}
|
||||
|
||||
def "should return a class from the generated path by when external contracts are picked"() {
|
||||
given:
|
||||
ContractVerifierConfigProperties props = new ContractVerifierConfigProperties(packageWithBaseClasses: "foo.Bar")
|
||||
String contractRelativeFolder = ["org","springframework","cloud","contract","verifier","tests","META_INF","com.example","hello_world","1.0.0"].join(File.separator)
|
||||
expect:
|
||||
ClassBuilder.retrieveBaseClass(props, contractRelativeFolder) == 'foo.Bar.Hello_world1_0_0Base'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.springframework.cloud.contract.verifier.util
|
||||
|
||||
import spock.lang.Specification
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
class NamesUtilTestSpec extends Specification {
|
||||
|
||||
def "should return the whole string before the last one"() {
|
||||
given:
|
||||
String string = "a.b.c.d.e"
|
||||
expect:
|
||||
"a.b.c.d" == NamesUtil.beforeLast(string, ".")
|
||||
}
|
||||
|
||||
def "should return empty string when no token was found for before last"() {
|
||||
given:
|
||||
String string = "a.b.c.d.e"
|
||||
expect:
|
||||
"" == NamesUtil.beforeLast(string, "/")
|
||||
}
|
||||
|
||||
def "should return first token after the last one"() {
|
||||
given:
|
||||
String string = "a.b.c.d.e"
|
||||
expect:
|
||||
"e" == NamesUtil.afterLast(string, ".")
|
||||
}
|
||||
|
||||
def "should return the input string when no token was found for after last"() {
|
||||
given:
|
||||
String string = "a.b.c.d.e"
|
||||
expect:
|
||||
string == NamesUtil.afterLast(string, "/")
|
||||
}
|
||||
|
||||
def "should return first token after the last dot"() {
|
||||
given:
|
||||
String string = "a.b.c.d.e"
|
||||
expect:
|
||||
"e" == NamesUtil.afterLastDot(string)
|
||||
}
|
||||
|
||||
def "should return the input string when no token was found for after last dot"() {
|
||||
given:
|
||||
String string = "abcde"
|
||||
expect:
|
||||
string == NamesUtil.afterLastDot(string)
|
||||
}
|
||||
|
||||
def "should return camel case version of a string"() {
|
||||
given:
|
||||
String string = "BlaBlaBla"
|
||||
expect:
|
||||
"blaBlaBla" == NamesUtil.camelCase(string)
|
||||
}
|
||||
|
||||
def "should return capitalized version of a string"() {
|
||||
given:
|
||||
String string = "blaBlaBla"
|
||||
expect:
|
||||
"BlaBlaBla" == NamesUtil.capitalize(string)
|
||||
}
|
||||
|
||||
def "should return all text to last dot"() {
|
||||
given:
|
||||
String string = "a.b.c.d.e"
|
||||
expect:
|
||||
"a.b.c.d" == NamesUtil.toLastDot(string)
|
||||
}
|
||||
|
||||
def "should return the input string when no token was found for to last dot"() {
|
||||
given:
|
||||
String string = "abcde"
|
||||
expect:
|
||||
string == NamesUtil.toLastDot(string)
|
||||
}
|
||||
|
||||
def "should convert a package notation to directory"() {
|
||||
given:
|
||||
String string = "a.b.c.d.e"
|
||||
expect:
|
||||
"a/b/c/d/e".replace("/", File.separator) == NamesUtil.packageToDirectory(string)
|
||||
}
|
||||
|
||||
def "should convert a directory notation to package"() {
|
||||
given:
|
||||
String string = "a/b/c/d/e".replace("/", File.separator)
|
||||
expect:
|
||||
"a.b.c.d.e" == NamesUtil.directoryToPackage(string)
|
||||
}
|
||||
|
||||
def "should convert all illegal package chars to legal ones"() {
|
||||
given:
|
||||
String string = "a-b c.1.0.x"
|
||||
expect:
|
||||
"a_b_c_1_0_x" == NamesUtil.convertIllegalPackageChars(string)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user