Fixed missing escaping of . in folder name

fixes #276
This commit is contained in:
Marcin Grzejszczak
2017-04-25 13:06:41 +02:00
parent fdd457e912
commit 0a09695b5c
6 changed files with 157 additions and 8 deletions

View File

@@ -147,6 +147,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
@@ -198,8 +241,7 @@ Spring Boot container if there is one.
https://projects.spring.io/spring-restdocs[Spring RestDocs] can be
used to generate documentation (e.g. in asciidoctor format) for an
HTTP API with https://docs.spring.io/spring/docs/current/spring-framework-reference/html/integration-testing.html#spring-mvc-test-framework[Spring MockMvc]
or http://rest-assured.io/[RestAssured]. At the same time as you
HTTP API with Spring MockMvc or RestEasy. At the same time as you
generate documentation for your API, you can also generate WireMock
stubs, by using Spring Cloud Contract WireMock. Just write your normal
RestDocs test cases and use `@AutoConfigureRestDocs` to have stubs

View File

@@ -63,9 +63,6 @@ class TestGenerator {
}
int generate() {
if (!configProperties.basePackageForTests) {
}
generateTestClasses(configProperties.basePackageForTests)
return counter.get()
}

View File

@@ -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])

View File

@@ -106,6 +106,6 @@ class NamesUtil {
* Converts illegal package characters to underscores
*/
static String convertIllegalPackageChars(String packageName) {
return packageName.replace('-', '_')
return packageName.replaceAll('[_\\- .]', '_')
}
}

View File

@@ -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'
}
}

View File

@@ -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)
}
}