diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy index bc6f35adde..2765d7114b 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/SingleTestGenerator.groovy @@ -11,6 +11,7 @@ import static io.codearte.accurest.builder.MethodBuilder.createTestMethod import static io.codearte.accurest.util.NamesUtil.capitalize class SingleTestGenerator { + private final AccurestConfigProperties configProperties SingleTestGenerator(AccurestConfigProperties configProperties) { @@ -34,7 +35,9 @@ class SingleTestGenerator { } } - if (configProperties.testMode == TestMode.MOCKMVC) { + if (configProperties.testMode == TestMode.JAXRSCLIENT) { + clazz.addStaticImport('javax.ws.rs.client.Entity.*') + } else if (configProperties.testMode == TestMode.MOCKMVC) { clazz.addStaticImport('com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.*') } else { clazz.addStaticImport('com.jayway.restassured.RestAssured.*') @@ -52,7 +55,7 @@ class SingleTestGenerator { } listOfFiles.each { - clazz.addMethod(createTestMethod(it, configProperties.targetFramework)) + clazz.addMethod(createTestMethod(it, configProperties)) } return clazz.build() } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/JaxRsClientSpockMethodBodyBuilder.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/JaxRsClientSpockMethodBodyBuilder.groovy new file mode 100644 index 0000000000..d3e07d7942 --- /dev/null +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/JaxRsClientSpockMethodBodyBuilder.groovy @@ -0,0 +1,95 @@ +package io.codearte.accurest.builder + +import groovy.transform.PackageScope +import groovy.transform.TypeChecked +import io.codearte.accurest.dsl.GroovyDsl +import io.codearte.accurest.dsl.internal.Header +import io.codearte.accurest.dsl.internal.QueryParameter + +@PackageScope +@TypeChecked +class JaxRsClientSpockMethodBodyBuilder extends SpockMethodBodyBuilder { + + JaxRsClientSpockMethodBodyBuilder(GroovyDsl stubDefinition) { + super(stubDefinition) + } + + @Override + protected void givenBlock(BlockBuilder bb) { + } + + @Override + protected void when(BlockBuilder bb) { + bb.addLine("def response = webTarget") + bb.indent() + + appendUrlPathAndQueryParameters(bb) + appendRequestWithRequiredResponseContentType(bb) + appendHeaders(bb) + appendMethodAndBody(bb) + + bb.unindent() + + bb.addEmptyLine() + bb.addLine("String responseAsString = response.readEntity(String)") + } + + protected void appendRequestWithRequiredResponseContentType(BlockBuilder bb) { + String acceptHeader = getHeader("Accept") + if (acceptHeader) { + bb.addLine(".request('$acceptHeader')") + } else { + bb.addLine(".request()") + } + } + + protected void appendUrlPathAndQueryParameters(BlockBuilder bb) { + if (request.url) { + bb.addLine(".path('$request.url.serverValue')") + } else if (request.urlPath) { + bb.addLine(".path('$request.urlPath.serverValue')") + request.urlPath.queryParameters?.parameters.findAll(this.&allowedQueryParameter).each { QueryParameter param -> + bb.addLine(".queryParam('$param.name', '${resolveParamValue(param).toString()}')") + } + } + } + + protected void appendMethodAndBody(BlockBuilder bb) { + String method = request.method.serverValue.toString().toLowerCase() + if (request.body) { + String contentType = getHeader('Content-Type') ?: getRequestContentType().mimeType + bb.addLine(".method('$method', entity('$bodyAsString', '$contentType'))") + } else { + bb.addLine(".method('$method')") + } + } + + protected appendHeaders(BlockBuilder bb) { + request.headers?.collect { Header header -> + if (header.name == 'Content-Type' || header.name == 'Accept') return // Particular headers are set via 'request' / 'entity' methods + bb.addLine(".header('${header.name}', '${header.serverValue}')") + } + } + + protected String getHeader(String name) { + return request.headers?.entries.find { it.name == name }?.serverValue + } + + @Override + protected void validateResponseCodeBlock(BlockBuilder bb) { + bb.addLine("response.status == $response.status.serverValue") + } + + @Override + protected void validateResponseHeadersBlock(BlockBuilder bb) { + response.headers?.collect { Header header -> + bb.addLine("response.getHeaderString('$header.name') == '$header.serverValue'") + } + } + + @Override + protected String getResponseAsString() { + return 'responseAsString' + } + +} diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy index dd791fb666..c4e8da6d04 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MethodBuilder.groovy @@ -1,7 +1,9 @@ package io.codearte.accurest.builder import groovy.util.logging.Slf4j +import io.codearte.accurest.config.AccurestConfigProperties import io.codearte.accurest.config.TestFramework +import io.codearte.accurest.config.TestMode import io.codearte.accurest.dsl.GroovyDsl import io.codearte.accurest.util.NamesUtil @@ -13,28 +15,36 @@ class MethodBuilder { private final String methodName private final GroovyDsl stubContent - private final TestFramework lang + private final AccurestConfigProperties configProperties - private MethodBuilder(String methodName, GroovyDsl stubContent, TestFramework lang) { + private MethodBuilder(String methodName, GroovyDsl stubContent, AccurestConfigProperties configProperties) { this.stubContent = stubContent this.methodName = methodName - this.lang = lang + this.configProperties = configProperties } - static MethodBuilder createTestMethod(File stubsFile, TestFramework lang) { + static MethodBuilder createTestMethod(File stubsFile, AccurestConfigProperties configProperties) { log.debug("Stub content from file [${stubsFile.text}]") GroovyDsl stubContent = new GroovyShell(this.classLoader).evaluate(stubsFile) log.debug("Stub content Groovy DSL [$stubContent]") String methodName = NamesUtil.camelCase(NamesUtil.toLastDot(NamesUtil.afterLast(stubsFile.path, File.separator))) - return new MethodBuilder(methodName, stubContent, lang) + return new MethodBuilder(methodName, stubContent, configProperties) } void appendTo(BlockBuilder blockBuilder) { - if (lang == TestFramework.JUNIT) { + if (configProperties.targetFramework == TestFramework.JUNIT) { blockBuilder.addLine('@Test') } - blockBuilder.addLine(lang.methodModifier + "$methodName() {") - new SpockMethodBodyBuilder(stubContent).appendTo(blockBuilder) + blockBuilder.addLine(configProperties.targetFramework.methodModifier + "$methodName() {") + getMethodBodyBuilder().appendTo(blockBuilder) blockBuilder.addLine('}') } + + private SpockMethodBodyBuilder getMethodBodyBuilder() { + if (configProperties.testMode == TestMode.JAXRSCLIENT) { + return new JaxRsClientSpockMethodBodyBuilder(stubContent) + } + return new MockMvcSpockMethodBodyBuilder(stubContent) + } + } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBodyBuilder.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBodyBuilder.groovy new file mode 100644 index 0000000000..40d6a24416 --- /dev/null +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBodyBuilder.groovy @@ -0,0 +1,77 @@ +package io.codearte.accurest.builder + +import groovy.transform.PackageScope +import groovy.transform.TypeChecked +import groovy.transform.TypeCheckingMode +import io.codearte.accurest.dsl.GroovyDsl +import io.codearte.accurest.dsl.internal.Header +import io.codearte.accurest.dsl.internal.QueryParameter +import io.codearte.accurest.dsl.internal.Request +import io.codearte.accurest.dsl.internal.UrlPath + +@PackageScope +@TypeChecked +class MockMvcSpockMethodBodyBuilder extends SpockMethodBodyBuilder { + + MockMvcSpockMethodBodyBuilder(GroovyDsl stubDefinition) { + super(stubDefinition) + } + + protected void given(BlockBuilder bb) { + bb.addLine('def request = given()') + bb.indent() + request.headers?.collect { Header header -> + bb.addLine(".header('${header.name}', '${header.serverValue}')") + } + if (request.body) { + bb.addLine(".body('$bodyAsString')") + } + bb.unindent() + } + + protected void when(BlockBuilder bb) { + bb.addLine('def response = given().spec(request)') + bb.indent() + + String url = buildUrl(request) + String method = request.method.serverValue.toString().toLowerCase() + + bb.addLine(/.${method}("$url")/) + bb.unindent() + } + + protected void validateResponseCodeBlock(BlockBuilder bb) { + bb.addLine("response.statusCode == $response.status.serverValue") + } + + protected void validateResponseHeadersBlock(BlockBuilder bb) { + response.headers?.collect { Header header -> + bb.addLine("response.header('$header.name') == '$header.serverValue'") + } + } + + @Override + protected String getResponseAsString() { + return 'response.body.asString()' + } + + protected String buildUrl(Request request) { + if (request.url) + return request.url.serverValue; + if (request.urlPath) + return buildUrlFromUrlPath(request.urlPath) + throw new IllegalStateException("URL is not set!") + } + + @TypeChecked(TypeCheckingMode.SKIP) + protected String buildUrlFromUrlPath(UrlPath urlPath) { + String params = urlPath.queryParameters.parameters + .findAll(this.&allowedQueryParameter) + .inject([] as List) { List result, QueryParameter param -> + result << "${param.name}=${resolveParamValue(param).toString()}" + } + .join('&') + return "$urlPath.serverValue?$params" + } + +} diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy index 1b26c272ab..0101a64c9c 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/builder/SpockMethodBodyBuilder.groovy @@ -1,16 +1,14 @@ package io.codearte.accurest.builder - import groovy.json.JsonOutput import groovy.transform.PackageScope +import groovy.transform.TypeChecked import io.codearte.accurest.dsl.GroovyDsl import io.codearte.accurest.dsl.internal.DslProperty import io.codearte.accurest.dsl.internal.ExecutionProperty -import io.codearte.accurest.dsl.internal.Header import io.codearte.accurest.dsl.internal.MatchingStrategy import io.codearte.accurest.dsl.internal.QueryParameter import io.codearte.accurest.dsl.internal.Request import io.codearte.accurest.dsl.internal.Response -import io.codearte.accurest.dsl.internal.UrlPath import io.codearte.accurest.util.ContentType import io.codearte.accurest.util.JsonConverter @@ -24,87 +22,95 @@ import static io.codearte.accurest.util.ContentUtils.recognizeContentTypeFromHea * @author Jakub Kubrynski */ @PackageScope -class SpockMethodBodyBuilder { - private final GroovyDsl stubDefinition +@TypeChecked +abstract class SpockMethodBodyBuilder { + + protected final Request request + protected final Response response SpockMethodBodyBuilder(GroovyDsl stubDefinition) { - this.stubDefinition = stubDefinition + this.request = stubDefinition.request + this.response = stubDefinition.response } void appendTo(BlockBuilder blockBuilder) { - Request request = stubDefinition.request - Response response = stubDefinition.response - blockBuilder.with { - startBlock() - addLine('given:').startBlock() - addLine('def request = given()') - indent() - request.headers?.collect { Header header -> - addLine(".header('${header.name}', '${header.serverValue}')") - } - if (request.body) { - Object bodyValue = extractServerValueFromBody(request.body.serverValue) - String matches = trimRepeatedQuotes(new JsonOutput().toJson(bodyValue)) - addLine(".body('$matches')") - } + blockBuilder.startBlock() - unindent().endBlock().addEmptyLine() + givenBlock(blockBuilder) + whenBlock(blockBuilder) + thenBlock(blockBuilder) - addLine('when:').startBlock() - addLine('def response = given().spec(request)') - indent() + blockBuilder.endBlock() + } - String url = buildUrl(request) - String method = request.method.serverValue.toLowerCase() + protected void thenBlock(BlockBuilder bb) { + bb.addLine('then:') + bb.startBlock() + then(bb) + bb.endBlock() + } - blockBuilder.addLine(/.${method}("$url")/) - unindent().endBlock().addEmptyLine() + protected void whenBlock(BlockBuilder bb) { + bb.addLine('when:') + bb.startBlock() + when(bb) + bb.endBlock().addEmptyLine() + } - addLine('then:').startBlock() - addLine("response.statusCode == $response.status.serverValue") + protected void givenBlock(BlockBuilder bb) { + bb.addLine('given:') + bb.startBlock() + given(bb) + bb.endBlock().addEmptyLine() + } - response.headers?.collect { Header header -> - addLine("response.header('$header.name') == '$header.serverValue'") - } - if (response.body) { - endBlock() - addLine('and:').startBlock() - def responseBody = response.body.serverValue - ContentType contentType = recognizeContentTypeFromHeader(response.headers) - if (contentType == ContentType.UNKNOWN) { - contentType = recognizeContentTypeFromContent(responseBody) - } - if (responseBody instanceof GString) { - responseBody = extractValue(responseBody, contentType, { DslProperty dslProperty -> dslProperty.serverValue }) - } - if (contentType == ContentType.JSON) { - addLine('def responseBody = new JsonSlurper().parseText(response.body.asString())') - if (responseBody instanceof List) { - processArrayElements(responseBody, "", blockBuilder) - } else if (responseBody instanceof Map) { - processMapElement(responseBody, blockBuilder, "") - } else { - processBodyElement(blockBuilder, '', responseBody) - } - } else if (contentType == ContentType.XML) { - addLine('def responseBody = new XmlSlurper().parseText(response.body.asString())') - // TODO xml validation - } - } - endBlock() + protected void given(BlockBuilder bb) {} - endBlock() + protected abstract void when(BlockBuilder bb) + + protected abstract void validateResponseCodeBlock(BlockBuilder bb) + + protected abstract void validateResponseHeadersBlock(BlockBuilder bb) + + protected abstract String getResponseAsString() + + protected void then(BlockBuilder bb) { + validateResponseCodeBlock(bb) + if (response.headers) { + validateResponseHeadersBlock(bb) + } + if (response.body) { + bb.endBlock() + bb.addLine('and:').startBlock() + validateResponseBodyBlock(bb) } } - private String trimRepeatedQuotes(String toTrim) { - if (toTrim.startsWith('"')) { - return toTrim.replaceAll('"', '') + protected void validateResponseBodyBlock(BlockBuilder bb) { + def responseBody = response.body.serverValue + ContentType contentType = getResponseContentType() + if (responseBody instanceof GString) { + responseBody = extractValue(responseBody, contentType, { DslProperty dslProperty -> dslProperty.serverValue }) + } + if (contentType == ContentType.JSON) { + bb.addLine("def responseBody = new JsonSlurper().parseText($responseAsString)") + processBodyElement(bb, "", responseBody) + } else if (contentType == ContentType.XML) { + bb.addLine("def responseBody = new XmlSlurper().parseText($responseAsString)") + // TODO xml validation } - return toTrim } - private Object extractServerValueFromBody(bodyValue) { + protected String getBodyAsString() { + Object bodyValue = extractServerValueFromBody(request.body.serverValue) + return trimRepeatedQuotes(new JsonOutput().toJson(bodyValue)) + } + + protected String trimRepeatedQuotes(String toTrim) { + return toTrim.startsWith('"') ? toTrim.replaceAll('"', '') : toTrim + } + + protected Object extractServerValueFromBody(bodyValue) { if (bodyValue instanceof GString) { bodyValue = extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue }) } else { @@ -113,88 +119,86 @@ class SpockMethodBodyBuilder { return bodyValue } - private String buildUrl(Request request) { - if (request.url) - return request.url.serverValue; - if (request.urlPath) - return buildUrlFromUrlPath(request.urlPath) - throw new IllegalStateException("URL is not set!") - } - - private String buildUrlFromUrlPath(UrlPath urlPath) { - String params = urlPath.queryParameters.parameters - .findAll(this.&allowedQueryParameter) - .inject([]) { result, param -> - result << "${param.name}=${resolveParamValue(param).toString()}" - }.join('&') - return "$urlPath.serverValue?$params" - } - - private boolean allowedQueryParameter(QueryParameter param) { + protected boolean allowedQueryParameter(QueryParameter param) { return allowedQueryParameter(param.serverValue) } - private boolean allowedQueryParameter(MatchingStrategy matchingStrategy) { + protected boolean allowedQueryParameter(MatchingStrategy matchingStrategy) { return matchingStrategy.type != MatchingStrategy.Type.ABSENT } - private boolean allowedQueryParameter(Object o) { + protected boolean allowedQueryParameter(Object o) { return true } - private String resolveParamValue(QueryParameter param) { - resolveParamValue(param.serverValue) + protected String resolveParamValue(QueryParameter param) { + return resolveParamValue(param.serverValue) } - private String resolveParamValue(Object value) { - value.toString() + protected String resolveParamValue(Object value) { + return value.toString() } - private String resolveParamValue(MatchingStrategy matchingStrategy) { - matchingStrategy.serverValue.toString() + protected String resolveParamValue(MatchingStrategy matchingStrategy) { + return matchingStrategy.serverValue.toString() } - private void processBodyElement(BlockBuilder blockBuilder, String property, def value) { - if (value instanceof String) { - if (value.startsWith('$')) { - value = value.substring(1).replaceAll('\\$value', "responseBody$property") - blockBuilder.addLine(value) - } else { - blockBuilder.addLine("responseBody$property == \"${value}\"") - } - } else if (value instanceof Map) { - processMapElement(value, blockBuilder, property) - } else if (value instanceof Map.Entry) { - processEntryElement(blockBuilder, property, value) - } else if (value instanceof List) { - processArrayElements(value, property, blockBuilder) - } else if (value instanceof Pattern) { - blockBuilder.addLine("responseBody$property ==~ java.util.regex.Pattern.compile('${value}')") - } else if (value instanceof DslProperty) { - processBodyElement(blockBuilder, property, value.serverValue) - } else if (value instanceof ExecutionProperty) { - ExecutionProperty exec = (ExecutionProperty) value - blockBuilder.addLine("${exec.insertValue("responseBody$property")}") + protected void processBodyElement(BlockBuilder blockBuilder, String property, Object value) { + blockBuilder.addLine("responseBody$property == ${value}") + } + + protected void processBodyElement(BlockBuilder blockBuilder, String property, String value) { + if (value.startsWith('$')) { + value = value.substring(1).replaceAll('\\$value', "responseBody$property") + blockBuilder.addLine(value) } else { - blockBuilder.addLine("responseBody$property == ${value}") + blockBuilder.addLine("responseBody$property == \"${value}\"") } } - private void processMapElement(def value, BlockBuilder blockBuilder, String property) { - value.each { entry -> processEntryElement(blockBuilder, property, entry) } + protected void processBodyElement(BlockBuilder blockBuilder, String property, Pattern pattern) { + blockBuilder.addLine("responseBody$property ==~ java.util.regex.Pattern.compile('${pattern.pattern()}')") } - private def processEntryElement(BlockBuilder blockBuilder, String property, def entry) { - return processBodyElement(blockBuilder, property + "." + entry.key, entry.value) + protected void processBodyElement(BlockBuilder blockBuilder, String property, DslProperty dslProperty) { + processBodyElement(blockBuilder, property, dslProperty.serverValue) } - private void processArrayElements(List responseBody, String property, BlockBuilder blockBuilder) { - responseBody.eachWithIndex { - listElement, listIndex -> - listElement.each { entry -> - String prop = "$property[$listIndex]" ?: '' - processBodyElement(blockBuilder, prop, entry) - } + protected void processBodyElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) { + blockBuilder.addLine("${exec.insertValue("responseBody$property")}") + } + + protected void processBodyElement(BlockBuilder blockBuilder, String property, Map.Entry entry) { + processBodyElement(blockBuilder, property + "." + entry.key, entry.value) + } + + protected void processBodyElement(BlockBuilder blockBuilder, String property, Map map) { + map.each { + processBodyElement(blockBuilder, property, it) } } + + protected void processBodyElement(BlockBuilder blockBuilder, String property, List list) { + list.eachWithIndex { listElement, listIndex -> + String prop = "$property[$listIndex]" ?: '' + processBodyElement(blockBuilder, prop, listElement) + } + } + + protected ContentType getRequestContentType() { + ContentType contentType = recognizeContentTypeFromHeader(request.headers) + if (contentType == ContentType.UNKNOWN) { + contentType = recognizeContentTypeFromContent(request.body.serverValue) + } + return contentType + } + + protected ContentType getResponseContentType() { + ContentType contentType = recognizeContentTypeFromHeader(response.headers) + if (contentType == ContentType.UNKNOWN) { + contentType = recognizeContentTypeFromContent(response.body.serverValue) + } + return contentType + } + } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/config/TestMode.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/config/TestMode.groovy index e8a232e37c..1c7732d49e 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/config/TestMode.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/config/TestMode.groovy @@ -4,5 +4,5 @@ package io.codearte.accurest.config * @author Jakub Kubrynski */ enum TestMode { - MOCKMVC, EXPLICIT + MOCKMVC, EXPLICIT, JAXRSCLIENT } \ No newline at end of file diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy index 142c93a945..7b9e402985 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentType.groovy @@ -1,5 +1,15 @@ package io.codearte.accurest.util enum ContentType { - JSON, XML, UNKNOWN + + JSON("application/json"), + XML("application/xml"), + UNKNOWN("application/octet-stream") + + final String mimeType + + ContentType(String mimeType) { + this.mimeType = mimeType + } + } \ No newline at end of file diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/builder/JaxRsClientSpockMethodBuilderSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/builder/JaxRsClientSpockMethodBuilderSpec.groovy new file mode 100644 index 0000000000..6b39c26e8d --- /dev/null +++ b/accurest-core/src/test/groovy/io/codearte/accurest/builder/JaxRsClientSpockMethodBuilderSpec.groovy @@ -0,0 +1,362 @@ +package io.codearte.accurest.builder + +import io.codearte.accurest.dsl.GroovyDsl +import spock.lang.Issue +import spock.lang.Specification + +class JaxRsClientSpockMethodBuilderSpec extends Specification { + + def "should generate assertions for simple response body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body """{ + "property1": "a", + "property2": "b" +}""" + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1 == \"a\"") + blockBuilder.toString().contains("responseBody.property2 == \"b\"") + } + + @Issue("#79") + def "should generate assertions for simple response body constructed from map with a list"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body( + property1: 'a', + property2: [ + [a: 'sth'], + [b: 'sthElse'] + ] + ) + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1 == \"a\"") + blockBuilder.toString().contains("responseBody.property2[0].a == \"sth\"") + blockBuilder.toString().contains("responseBody.property2[1].b == \"sthElse\"") + } + + @Issue("#82") + def "should generate proper request when body constructed from map with a list"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + body( + items: ['HOP'] + ) + } + response { + status 200 + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("entity('{\"items\":[\"HOP\"]}', 'application/json')") + } + + @Issue("#88") + def "should generate proper request when body constructed from GString"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + body( + "property1=VAL1" + ) + } + response { + status 200 + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("entity('property1=VAL1', 'application/octet-stream')") + } + + def "should generate assertions for array in response body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body """[ +{ + "property1": "a" +}, +{ + "property2": "b" +}]""" + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody[0].property1 == \"a\"") + blockBuilder.toString().contains("responseBody[1].property2 == \"b\"") + } + + def "should generate assertions for array inside response body element"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body """{ + "property1": [ + { "property2": "test1"}, + { "property3": "test2"} + ] +}""" + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1[0].property2 == \"test1\"") + blockBuilder.toString().contains("responseBody.property1[1].property3 == \"test2\"") + } + + def "should generate assertions for nested objects in response body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body '''\ +{ + "property1": "a", + "property2": {"property3": "b"} +} +''' + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1 == \"a\"") + blockBuilder.toString().contains("responseBody.property2.property3 == \"b\"") + } + + def "should generate regex assertions for map objects in response body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body( + property1: "a", + property2: value( + client('123'), + server(regex('[0-9]{3}')) + ) + ) + headers { + header('Content-Type': 'application/json') + + } + + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1 == \"a\"") + blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('[0-9]{3}')") + } + + def "should generate regex assertions for string objects in response body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + } + response { + status 200 + body("""{"property1":"a","property2":"${value(client('123'), server(regex('[0-9]{3}')))}"}""") + headers { + header('Content-Type': 'application/json') + + } + + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("responseBody.property1 == \"a\"") + blockBuilder.toString().contains("responseBody.property2 ==~ java.util.regex.Pattern.compile('[0-9]{3}')") + } + + def "should ignore 'Accept' header and use 'request' method"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + headers { + header("Accept", "text/plain") + } + } + response { + status 200 + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("request('text/plain')") + } + + def "should ignore 'Content-Type' header and use 'entity' method"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method "GET" + url "test" + headers { + header("Content-Type", "text/plain") + header("Timer", "123") + } + body '' + } + response { + status 200 + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("entity('', 'text/plain')") + blockBuilder.toString().contains("header('Timer', '123')") + !blockBuilder.toString().contains("header('Content-Type'") + + } + + def "should generate a call with an url path and query parameters"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method 'GET' + urlPath('/users') { + queryParameters { + parameter 'limit': $(client(equalTo("20")), server(equalTo("10"))) + parameter 'offset': $(client(containing("20")), server(equalTo("20"))) + parameter 'filter': "email" + parameter 'sort': equalTo("name") + parameter 'search': $(client(notMatching(~/^\/[0-9]{2}$/)), server("55")) + parameter 'age': $(client(notMatching("^\\w*\$")), server("99")) + parameter 'name': $(client(matching("Denis.*")), server("Denis.Stepanov")) + parameter 'email': "bob@email.com" + parameter 'hello': $(client(matching("Denis.*")), server(absent())) + parameter 'hello': absent() + } + } + } + response { + status 200 + body """ + { + "property1": "a", + "property2": "b" + } + """ + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def spockTest = blockBuilder.toString() + then: + spockTest.contains("queryParam('limit', '10'") + spockTest.contains("queryParam('offset', '20'") + spockTest.contains("queryParam('filter', 'email'") + spockTest.contains("queryParam('sort', 'name'") + spockTest.contains("queryParam('search', '55'") + spockTest.contains("queryParam('age', '99'") + spockTest.contains("queryParam('name', 'Denis.Stepanov'") + spockTest.contains("queryParam('email', 'bob@email.com'") + spockTest.contains('responseBody.property1 == "a"') + spockTest.contains('responseBody.property2 == "b"') + } + + def "should generate test for empty body"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + request { + method('POST') + url("/ws/payments") + body("") + } + response { + status 406 + } + } + JaxRsClientSpockMethodBodyBuilder builder = new JaxRsClientSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def spockTest = blockBuilder.toString() + then: + spockTest.contains("entity('', 'application/octet-stream')") + } +} diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/builder/SpockMethodBuilderSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy similarity index 87% rename from accurest-core/src/test/groovy/io/codearte/accurest/builder/SpockMethodBuilderSpec.groovy rename to accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy index 49c1d94981..55a43d2961 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/builder/SpockMethodBuilderSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy @@ -7,7 +7,7 @@ import spock.lang.Specification /** * @author Jakub Kubrynski */ -class SpockMethodBuilderSpec extends Specification { +class MockMvcSpockMethodBuilderSpec extends Specification { def "should generate assertions for simple response body"() { given: @@ -24,7 +24,7 @@ class SpockMethodBuilderSpec extends Specification { }""" } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -52,7 +52,7 @@ class SpockMethodBuilderSpec extends Specification { ) } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -77,7 +77,7 @@ class SpockMethodBuilderSpec extends Specification { status 200 } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -100,7 +100,7 @@ class SpockMethodBuilderSpec extends Specification { status 200 } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -126,7 +126,7 @@ class SpockMethodBuilderSpec extends Specification { }]""" } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -152,7 +152,7 @@ class SpockMethodBuilderSpec extends Specification { }""" } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -178,7 +178,7 @@ class SpockMethodBuilderSpec extends Specification { ''' } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -210,7 +210,7 @@ class SpockMethodBuilderSpec extends Specification { } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -236,7 +236,7 @@ class SpockMethodBuilderSpec extends Specification { } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -275,7 +275,7 @@ class SpockMethodBuilderSpec extends Specification { """ } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -298,7 +298,7 @@ class SpockMethodBuilderSpec extends Specification { status 406 } } - SpockMethodBodyBuilder builder = new SpockMethodBodyBuilder(contractDsl) + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) diff --git a/accurest-gradle-plugin/src/test/groovy/io/codearte/accurest/plugin/SampleJerseyProjectSpec.groovy b/accurest-gradle-plugin/src/test/groovy/io/codearte/accurest/plugin/SampleJerseyProjectSpec.groovy new file mode 100755 index 0000000000..789d897199 --- /dev/null +++ b/accurest-gradle-plugin/src/test/groovy/io/codearte/accurest/plugin/SampleJerseyProjectSpec.groovy @@ -0,0 +1,21 @@ +package io.codearte.accurest.plugin + +import nebula.test.IntegrationSpec +import spock.lang.Stepwise + +@Stepwise +class SampleJerseyProjectSpec extends IntegrationSpec { + + void setup() { + copyResources("functionalTest/sampleJerseyProject", "") + runTasksSuccessfully('clean') //delete accidental output when previously importing SimpleBoot into Idea to tweak it + } + + def "should pass basic flow"() { + given: + assert fileExists('build.gradle') + expect: + runTasksSuccessfully('check') + } + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/build.gradle b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/build.gradle new file mode 100644 index 0000000000..0ae605c532 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/build.gradle @@ -0,0 +1,95 @@ +buildscript { + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath "org.springframework.boot:spring-boot-gradle-plugin:1.2.1.RELEASE" + } +} + +ext { + spockVersion = '0.7-groovy-2.0' + restAssuredVersion = '2.4.0' + + accurestStubsBaseDirectory = 'src/test/resources/stubs' +} + +subprojects { + apply plugin: 'groovy' + + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testCompile "org.codehaus.groovy:groovy-all:2.3.7" + testCompile "org.spockframework:spock-core:$spockVersion" + testCompile("junit:junit:4.12") + testCompile('com.github.tomakehurst:wiremock:1.52') { + exclude group: 'org.mortbay.jetty', module: 'servlet-api' + } + } +} + +configure([project(':fraudDetectionService'), project(':loanApplicationService')]) { + apply plugin: 'spring-boot' + apply plugin: 'accurest' + + ext { + wireMockStubsOutputDirRoot = file("${project.buildDir}/production/${project.name}-stubs/") + wireMockStubsOutputDir = new File(wireMockStubsOutputDirRoot, 'mappings/') + } + + accurest { + targetFramework = 'Spock' + testMode = 'JaxRsClient' + baseClassForTests = 'com.blogspot.toomuchcoding.MvcSpec' + contractsDslDir = file("${project.projectDir.absolutePath}/mappings/") + generatedTestSourcesDir = file("${project.buildDir}/generated-sources/") + stubsOutputDir = wireMockStubsOutputDir + } + + jar { + version = '0.0.1' + } + + dependencies { + compile "javax.ws.rs:javax.ws.rs-api:2.0.1" + compile 'org.glassfish.jersey.containers:jersey-container-jetty-http:2.15' + compile('org.springframework.boot:spring-boot-starter-jersey:1.2.5.RELEASE') { + exclude module: "spring-boot-starter-tomcat" + } + compile 'org.springframework.boot:spring-boot-starter-jetty:1.2.5.RELEASE' + + testRuntime "org.spockframework:spock-spring:$spockVersion" + + compile 'org.glassfish.jersey.connectors:jersey-apache-connector:2.15' + testCompile 'org.springframework:spring-test:4.1.7.RELEASE' + } + + task cleanup(type: Delete) { + delete 'src/test/resources/mappings', 'src/test/resources/stubs' + } + + clean.dependsOn('cleanup') + +} + +configure(project(':fraudDetectionService')) { + test.dependsOn('generateWireMockClientStubs') +} + +configure(project(':loanApplicationService')) { + + task copyCollaboratorStubs(type: Copy) { + File fraudBuildDir = project(':fraudDetectionService').buildDir + from(new File(fraudBuildDir, "/production/${project(':fraudDetectionService').name}-stubs/")) + into "src/test/resources/" + } + + generateAccurest.dependsOn('copyCollaboratorStubs') +} + diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/mappings/fraudDetectionService/shouldMarkClientAsFraud.groovy b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/mappings/fraudDetectionService/shouldMarkClientAsFraud.groovy new file mode 100644 index 0000000000..a47dff32e4 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/mappings/fraudDetectionService/shouldMarkClientAsFraud.groovy @@ -0,0 +1,27 @@ +io.codearte.accurest.dsl.GroovyDsl.make { + request { + method """PUT""" + url """/fraudcheck""" + body(""" + { + "clientPesel":"${value(client(regex('[0-9]{10}')), server('1234567890'))}", + "loanAmount":99999} + """ + ) + headers { + header("""Content-Type""", """application/vnd.fraud.v1+json""") + } + + } + response { + status 200 + body( """{ + "fraudCheckStatus": "${value(client('FRAUD'), server(regex('[A-Z]{5}')))}", + "rejectionReason": "Amount too high" +}""") + headers { + header('Content-Type': 'application/vnd.fraud.v1+json') + } + } + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/mappings/fraudDetectionService/shouldMarkClientAsNotFraud.groovy b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/mappings/fraudDetectionService/shouldMarkClientAsNotFraud.groovy new file mode 100644 index 0000000000..fa8cd88ade --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/mappings/fraudDetectionService/shouldMarkClientAsNotFraud.groovy @@ -0,0 +1,28 @@ +io.codearte.accurest.dsl.GroovyDsl.make { + request { + method 'PUT' + url '/fraudcheck' + body(""" + { + "clientPesel":"${value(client(regex('[0-9]{10}')), server('1234567890'))}", + "loanAmount":123.123 + } + """ + ) + headers { + header('Content-Type', 'application/vnd.fraud.v1+json') + } + + } + response { + status 200 + body( + fraudCheckStatus: "OK", + rejectionReason: $(client(null), server(execute('assertThatRejectionReasonIsNull($it)'))) + ) + headers { + header('Content-Type': 'application/vnd.fraud.v1+json') + } + } + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java new file mode 100644 index 0000000000..2089bda142 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java @@ -0,0 +1,25 @@ +package com.blogspot.toomuchcoding.frauddetection; + +import org.glassfish.jersey.client.HttpUrlConnectorProvider; +import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableAutoConfiguration +@ComponentScan +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + ResourceConfig resourceConfig() { + return ResourceConfig.forApplication(new FraudRestApplication()); + } + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java new file mode 100644 index 0000000000..bb015f08a4 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudDetectionController.java @@ -0,0 +1,38 @@ +package com.blogspot.toomuchcoding.frauddetection; + +import com.blogspot.toomuchcoding.frauddetection.model.FraudCheck; +import com.blogspot.toomuchcoding.frauddetection.model.FraudCheckResult; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.*; +import java.math.BigDecimal; + +import static com.blogspot.toomuchcoding.frauddetection.model.FraudCheckStatus.FRAUD; +import static com.blogspot.toomuchcoding.frauddetection.model.FraudCheckStatus.OK; + +@Controller +@Path("/") +public class FraudDetectionController { + + private static final String FRAUD_SERVICE_JSON_VERSION_1 = "application/vnd.fraud.v1+json"; + private static final String NO_REASON = null; + private static final String AMOUNT_TOO_HIGH = "Amount too high"; + private static final BigDecimal MAX_AMOUNT = new BigDecimal("5000"); + + @PUT + @Path("/fraudcheck") + @Produces(FRAUD_SERVICE_JSON_VERSION_1) + @Consumes(FRAUD_SERVICE_JSON_VERSION_1) + public FraudCheckResult fraudCheck(@RequestBody(required = false) FraudCheck fraudCheck) { + if (amountGreaterThanThreshold(fraudCheck)) { + return new FraudCheckResult(FRAUD, AMOUNT_TOO_HIGH); + } + return new FraudCheckResult(OK, NO_REASON); + } + + private boolean amountGreaterThanThreshold(FraudCheck fraudCheck) { + return MAX_AMOUNT.compareTo(fraudCheck.getLoanAmount()) < 0; + } + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudRestApplication.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudRestApplication.java new file mode 100644 index 0000000000..ce70aa1050 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/FraudRestApplication.java @@ -0,0 +1,13 @@ +package com.blogspot.toomuchcoding.frauddetection; + +import java.util.Collections; +import java.util.Set; + +public class FraudRestApplication extends javax.ws.rs.core.Application { + + @Override + public Set> getClasses() { + return Collections.>singleton(FraudDetectionController.class); + } + +} \ No newline at end of file diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java new file mode 100644 index 0000000000..77471aee19 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheck.java @@ -0,0 +1,29 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +import java.math.BigDecimal; + +public class FraudCheck { + + private String clientPesel; + + private BigDecimal loanAmount; + + public FraudCheck() { + } + + public String getClientPesel() { + return clientPesel; + } + + public void setClientPesel(String clientPesel) { + this.clientPesel = clientPesel; + } + + public BigDecimal getLoanAmount() { + return loanAmount; + } + + public void setLoanAmount(BigDecimal loanAmount) { + this.loanAmount = loanAmount; + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java new file mode 100644 index 0000000000..28efc573f5 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckResult.java @@ -0,0 +1,32 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +public class FraudCheckResult { + + private FraudCheckStatus fraudCheckStatus; + + private String rejectionReason; + + public FraudCheckResult() { + } + + public FraudCheckResult(FraudCheckStatus fraudCheckStatus, String rejectionReason) { + this.fraudCheckStatus = fraudCheckStatus; + this.rejectionReason = rejectionReason; + } + + public FraudCheckStatus getFraudCheckStatus() { + return fraudCheckStatus; + } + + public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { + this.fraudCheckStatus = fraudCheckStatus; + } + + public String getRejectionReason() { + return rejectionReason; + } + + public void setRejectionReason(String rejectionReason) { + this.rejectionReason = rejectionReason; + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java new file mode 100644 index 0000000000..b87c365d51 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java @@ -0,0 +1,5 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +public enum FraudCheckStatus { + OK, FRAUD +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/resources/application.yml b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/resources/application.yml new file mode 100644 index 0000000000..a30a91f034 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/main/resources/application.yml @@ -0,0 +1 @@ +server.port=8085 \ No newline at end of file diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/test/groovy/com/blogspot/toomuchcoding/MvcSpec.groovy b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/test/groovy/com/blogspot/toomuchcoding/MvcSpec.groovy new file mode 100644 index 0000000000..621d20ded4 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/fraudDetectionService/src/test/groovy/com/blogspot/toomuchcoding/MvcSpec.groovy @@ -0,0 +1,57 @@ +package com.blogspot.toomuchcoding +import com.blogspot.toomuchcoding.frauddetection.Application +import com.blogspot.toomuchcoding.frauddetection.FraudRestApplication +import org.eclipse.jetty.server.Server +import org.glassfish.jersey.apache.connector.ApacheConnectorProvider +import org.glassfish.jersey.client.ClientConfig +import org.glassfish.jersey.jetty.JettyHttpContainerFactory +import org.glassfish.jersey.server.ResourceConfig +import org.springframework.context.annotation.AnnotationConfigApplicationContext +import spock.lang.Shared +import spock.lang.Specification + +import javax.ws.rs.client.Client +import javax.ws.rs.client.ClientBuilder +import javax.ws.rs.client.WebTarget +import javax.ws.rs.core.UriBuilder + +import static org.springframework.util.SocketUtils.findAvailableTcpPort + +abstract class MvcSpec extends Specification { + + @Shared + WebTarget webTarget + + @Shared + private Server server + + @Shared + private Client client + + def setupSpec() { + + URI baseUri = UriBuilder.fromUri("http://localhost").port(findAvailableTcpPort(8000)).build() + + + ResourceConfig resourceConfig = ResourceConfig.forApplication(new FraudRestApplication()) + resourceConfig.property("contextConfig", new AnnotationConfigApplicationContext(Application)) + server = JettyHttpContainerFactory.createServer(baseUri, resourceConfig, true) + + ClientConfig clientConfig = new ClientConfig() + clientConfig.connectorProvider(new ApacheConnectorProvider()) + client = ClientBuilder.newClient(clientConfig) + + webTarget = client.target(baseUri) + + server.start() + } + + def cleanupSpec() { + client?.close() + server?.stop() + } + + void assertThatRejectionReasonIsNull(def rejectionReason) { + assert !rejectionReason + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradle/wrapper/gradle-wrapper.jar b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..667288ad6c Binary files /dev/null and b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradle/wrapper/gradle-wrapper.jar differ diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradle/wrapper/gradle-wrapper.properties b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b4603dcb69 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Jan 28 00:32:44 CET 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-2.4-all.zip diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradlew b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradlew new file mode 100755 index 0000000000..91a7e269e1 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradlew.bat b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradlew.bat new file mode 100644 index 0000000000..8a0b282aa6 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/mappings/.gitkeep b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/mappings/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java new file mode 100644 index 0000000000..5a1a60244e --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/Application.java @@ -0,0 +1,17 @@ +package com.blogspot.toomuchcoding.frauddetection; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableAutoConfiguration +@ComponentScan +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/LoanApplicationService.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/LoanApplicationService.java new file mode 100644 index 0000000000..82476a3a46 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/LoanApplicationService.java @@ -0,0 +1,62 @@ +package com.blogspot.toomuchcoding.frauddetection; + +import com.blogspot.toomuchcoding.frauddetection.model.FraudCheckStatus; +import com.blogspot.toomuchcoding.frauddetection.model.FraudServiceRequest; +import com.blogspot.toomuchcoding.frauddetection.model.FraudServiceResponse; +import com.blogspot.toomuchcoding.frauddetection.model.LoanApplication; +import com.blogspot.toomuchcoding.frauddetection.model.LoanApplicationResult; +import com.blogspot.toomuchcoding.frauddetection.model.LoanApplicationStatus; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +public class LoanApplicationService { + + private static final String FRAUD_SERVICE_JSON_VERSION_1 = + "application/vnd.fraud.v1+json"; + + private final RestTemplate restTemplate; + + public LoanApplicationService() { + this.restTemplate = new RestTemplate(); + } + + public LoanApplicationResult loanApplication(LoanApplication loanApplication) { + FraudServiceRequest request = + new FraudServiceRequest(loanApplication); + + FraudServiceResponse response = + sendRequestToFraudDetectionService(request); + + return buildResponseFromFraudResult(response); + } + + private FraudServiceResponse sendRequestToFraudDetectionService( + FraudServiceRequest request) { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(HttpHeaders.CONTENT_TYPE, FRAUD_SERVICE_JSON_VERSION_1); + + ResponseEntity response = + restTemplate.exchange("http://localhost:8080/fraudcheck", HttpMethod.PUT, + new HttpEntity<>(request, httpHeaders), + FraudServiceResponse.class); + + return response.getBody(); + } + + private LoanApplicationResult buildResponseFromFraudResult(FraudServiceResponse response) { + LoanApplicationStatus applicationStatus = null; + if (FraudCheckStatus.OK == response.getFraudCheckStatus()) { + applicationStatus = LoanApplicationStatus.LOAN_APPLIED; + } else if (FraudCheckStatus.FRAUD == response.getFraudCheckStatus()) { + applicationStatus = LoanApplicationStatus.LOAN_APPLICATION_REJECTED; + } + + return new LoanApplicationResult(applicationStatus, response.getRejectionReason()); + } + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/Client.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/Client.java new file mode 100644 index 0000000000..5e91273eda --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/Client.java @@ -0,0 +1,14 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +public class Client { + + private String pesel; + + public String getPesel() { + return pesel; + } + + public void setPesel(String pesel) { + this.pesel = pesel; + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java new file mode 100644 index 0000000000..b87c365d51 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudCheckStatus.java @@ -0,0 +1,5 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +public enum FraudCheckStatus { + OK, FRAUD +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudServiceRequest.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudServiceRequest.java new file mode 100644 index 0000000000..ac595998bc --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudServiceRequest.java @@ -0,0 +1,34 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +import java.math.BigDecimal; + +public class FraudServiceRequest { + + private String clientPesel; + + private BigDecimal loanAmount; + + public FraudServiceRequest() { + } + + public FraudServiceRequest(LoanApplication loanApplication) { + this.clientPesel = loanApplication.getClient().getPesel(); + this.loanAmount = loanApplication.getAmount(); + } + + public String getClientPesel() { + return clientPesel; + } + + public void setClientPesel(String clientPesel) { + this.clientPesel = clientPesel; + } + + public BigDecimal getLoanAmount() { + return loanAmount; + } + + public void setLoanAmount(BigDecimal loanAmount) { + this.loanAmount = loanAmount; + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudServiceResponse.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudServiceResponse.java new file mode 100644 index 0000000000..9f3353ecbf --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/FraudServiceResponse.java @@ -0,0 +1,27 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +public class FraudServiceResponse { + + private FraudCheckStatus fraudCheckStatus; + + private String rejectionReason; + + public FraudServiceResponse() { + } + + public FraudCheckStatus getFraudCheckStatus() { + return fraudCheckStatus; + } + + public void setFraudCheckStatus(FraudCheckStatus fraudCheckStatus) { + this.fraudCheckStatus = fraudCheckStatus; + } + + public String getRejectionReason() { + return rejectionReason; + } + + public void setRejectionReason(String rejectionReason) { + this.rejectionReason = rejectionReason; + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplication.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplication.java new file mode 100644 index 0000000000..816087988b --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplication.java @@ -0,0 +1,36 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +import java.math.BigDecimal; + +public class LoanApplication { + + private Client client; + + private BigDecimal amount; + + private String loanApplicationId; + + public Client getClient() { + return client; + } + + public void setClient(Client client) { + this.client = client; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public String getLoanApplicationId() { + return loanApplicationId; + } + + public void setLoanApplicationId(String loanApplicationId) { + this.loanApplicationId = loanApplicationId; + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplicationResult.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplicationResult.java new file mode 100644 index 0000000000..523f4f2ea3 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplicationResult.java @@ -0,0 +1,32 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +public class LoanApplicationResult { + + private LoanApplicationStatus loanApplicationStatus; + + private String rejectionReason; + + public LoanApplicationResult() { + } + + public LoanApplicationResult(LoanApplicationStatus loanApplicationStatus, String rejectionReason) { + this.loanApplicationStatus = loanApplicationStatus; + this.rejectionReason = rejectionReason; + } + + public LoanApplicationStatus getLoanApplicationStatus() { + return loanApplicationStatus; + } + + public void setLoanApplicationStatus(LoanApplicationStatus loanApplicationStatus) { + this.loanApplicationStatus = loanApplicationStatus; + } + + public String getRejectionReason() { + return rejectionReason; + } + + public void setRejectionReason(String rejectionReason) { + this.rejectionReason = rejectionReason; + } +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplicationStatus.java b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplicationStatus.java new file mode 100644 index 0000000000..7f7f86e0ea --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/java/com/blogspot/toomuchcoding/frauddetection/model/LoanApplicationStatus.java @@ -0,0 +1,5 @@ +package com.blogspot.toomuchcoding.frauddetection.model; + +public enum LoanApplicationStatus { + LOAN_APPLIED, LOAN_APPLICATION_REJECTED +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/resources/application.yml b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/resources/application.yml new file mode 100644 index 0000000000..e86bbd0e0f --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/main/resources/application.yml @@ -0,0 +1 @@ +server.port=8090 \ No newline at end of file diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/groovy/com/blogspot/toomuchcoding/LoanApplicationServiceSpec.groovy b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/groovy/com/blogspot/toomuchcoding/LoanApplicationServiceSpec.groovy new file mode 100644 index 0000000000..58d17673ce --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/groovy/com/blogspot/toomuchcoding/LoanApplicationServiceSpec.groovy @@ -0,0 +1,50 @@ +package com.blogspot.toomuchcoding + +import com.blogspot.toomuchcoding.frauddetection.Application +import com.blogspot.toomuchcoding.frauddetection.LoanApplicationService +import com.blogspot.toomuchcoding.frauddetection.model.Client +import com.blogspot.toomuchcoding.frauddetection.model.LoanApplication +import com.blogspot.toomuchcoding.frauddetection.model.LoanApplicationResult +import com.blogspot.toomuchcoding.frauddetection.model.LoanApplicationStatus +import com.github.tomakehurst.wiremock.junit.WireMockClassRule +import org.junit.ClassRule +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.SpringApplicationContextLoader +import org.springframework.test.context.ContextConfiguration +import spock.lang.Shared +import spock.lang.Specification + +@ContextConfiguration(loader = SpringApplicationContextLoader, classes = Application) +class LoanApplicationServiceSpec extends Specification { + + @ClassRule + @Shared + WireMockClassRule wireMockRule = new WireMockClassRule() + + @Autowired + LoanApplicationService sut + + def 'should successfully apply for loan'() { + given: + LoanApplication application = + new LoanApplication(client: new Client(pesel: '1234567890'), amount: 123.123) + when: + LoanApplicationResult loanApplication = sut.loanApplication(application) + then: + loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLIED + loanApplication.rejectionReason == null + } + + def 'should be rejected due to abnormal loan amount'() { + given: + LoanApplication application = + new LoanApplication(client: new Client(pesel: '1234567890'), amount: 99_999) + when: + LoanApplicationResult loanApplication = sut.loanApplication(application) + then: + loanApplication.loanApplicationStatus == LoanApplicationStatus.LOAN_APPLICATION_REJECTED + loanApplication.rejectionReason == 'Amount too high' + } + + +} diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/resources/mappings/fraudDetectionService/shouldMarkClientAsFraud.json b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/resources/mappings/fraudDetectionService/shouldMarkClientAsFraud.json new file mode 100644 index 0000000000..90383f2ce1 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/resources/mappings/fraudDetectionService/shouldMarkClientAsFraud.json @@ -0,0 +1,23 @@ +{ + "request": { + "method": "PUT", + "headers": { + "Content-Type": { + "equalTo": "application/vnd.fraud.v1+json" + } + }, + "url": "/fraudcheck", + "bodyPatterns": [ + { + "matches": "\\s*\\{\\s*\"clientPesel\"\\s*:\\s*\"?[0-9]{10}\"?\\s*,\\s*\"loanAmount\"\\s*:\\s*\"?99999\"?\\s*\\}\\s*" + } + ] + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/vnd.fraud.v1+json" + }, + "body": "{\"fraudCheckStatus\":\"FRAUD\",\"rejectionReason\":\"Amount too high\"}" + } +} \ No newline at end of file diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/resources/mappings/fraudDetectionService/shouldMarkClientAsNotFraud.json b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/resources/mappings/fraudDetectionService/shouldMarkClientAsNotFraud.json new file mode 100644 index 0000000000..2f47855910 --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/loanApplicationService/src/test/resources/mappings/fraudDetectionService/shouldMarkClientAsNotFraud.json @@ -0,0 +1,23 @@ +{ + "request": { + "method": "PUT", + "headers": { + "Content-Type": { + "equalTo": "application/vnd.fraud.v1+json" + } + }, + "url": "/fraudcheck", + "bodyPatterns": [ + { + "matches": "\\s*\\{\\s*\"clientPesel\"\\s*:\\s*\"?[0-9]{10}\"?\\s*,\\s*\"loanAmount\"\\s*:\\s*\"?123.123\"?\\s*\\}\\s*" + } + ] + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/vnd.fraud.v1+json" + }, + "body": "{\"fraudCheckStatus\":\"OK\",\"rejectionReason\":null}" + } +} \ No newline at end of file diff --git a/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/settings.gradle b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/settings.gradle new file mode 100644 index 0000000000..6a42a6c7ce --- /dev/null +++ b/accurest-gradle-plugin/src/test/resources/functionalTest/sampleJerseyProject/settings.gradle @@ -0,0 +1,2 @@ +include ':fraudDetectionService' +include ':loanApplicationService'