diff --git a/docs/src/main/asciidoc/verifier/contract.adoc b/docs/src/main/asciidoc/verifier/contract.adoc index 6ca6f71b42..d778b91aa5 100644 --- a/docs/src/main/asciidoc/verifier/contract.adoc +++ b/docs/src/main/asciidoc/verifier/contract.adoc @@ -114,12 +114,45 @@ include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=body,indent=0] ---- -//**Body's format** can also be specified explicitly by invoking one of format functions. -// -//[source,groovy,indent=0] -//---- -//include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=bodyAsXml,indent=0] -//---- +Request may contain **multipart** elements. Just call the `multipart()` method. + +[source,groovy,indent=0] +---- +include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy[tags=multipartdsl,indent=0] +---- + +In this example we defined parameters either directly by using the map notation, +where the value can be a dynamic property (e.g. `formParameter: $(consumer(...), producer(...))`) + or by using the `named(...)` method that allows you to set a named parameter. + A named parameter can set a `name` and `content`. You can call it either via + a method with 2 arguments: e.g. `named("fileName", "fileContent")` or + via a map notation `named(name: "fileName", content: "fileContent")`. + +From this contract the generated test will look more or less like this: + +[source,java,indent=0] +---- + // given: + MockMvcRequestSpecification request = given() + .header("Content-Type", "multipart/form-data;boundary=AaB03x") + .param("formParameter", "\"formParameterValue\"") + .param("someBooleanParameter", "true") + .multiPart("file", "filename.csv", "file content".getBytes()); + + // when: + ResponseOptions response = given().spec(request) + .put("/multipart"); + + // then: + assertThat(response.statusCode()).isEqualTo(200); +---- + +The WireMock stub will look more or less like this: + +[source,json,indent=0] +---- +include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy[tags=multipartwiremock,indent=0] +---- ==== Response diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy index 35ae8c3068..3da84bf9cb 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy @@ -1166,9 +1166,10 @@ World.'''""" } @Issue('180') - def "should generate proper test code when having multipart parameters with #methodBuilderName"() { + def "should generate proper test code when having multipart parameters with #methodBuilderName"() { given: - Contract contractDsl = Contract.make { + // tag::multipartdsl[] + org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { request { method "PUT" url "/multipart" @@ -1176,15 +1177,23 @@ World.'''""" contentType('multipart/form-data;boundary=AaB03x') } multipart( - formParameter: value(consumer(regex('.+')), producer('"formParameterValue"')), - someBooleanParameter: value(consumer(regex('(true|false)')), producer('true')), - file: named(value(consumer(regex('.+')), producer('filename.csv')), value(consumer(regex('.+')), producer('file content'))) + // key (parameter name), value (parameter value) pair + formParameter: $(c(regex('".+"')), p('"formParameterValue"')), + someBooleanParameter: $(c(regex(anyBoolean())), p('true')), + // a named parameter (e.g. with `file` name) that represents file with + // `name` and `content`. You can also call `named("fileName", "fileContent")` + file: named( + // name of the file + name: $(c(regex('.+')), p('filename.csv')), + // content of the file + content: $(c(regex('.+')), p('file content'))) ) } response { status 200 } } + // end::multipartdsl[] MethodBodyBuilder builder = methodBuilder(contractDsl) BlockBuilder blockBuilder = new BlockBuilder(" ") when: @@ -1209,18 +1218,26 @@ World.'''""" } @Issue('180') - def "should generate proper test code when having multipart parameters with named as map with #methodBuilderName"() { + def "should generate proper test code when having multipart parameters with named as map with #methodBuilderName"() { given: - Contract contractDsl = Contract.make { + org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { request { method "PUT" url "/multipart" + headers { + contentType('multipart/form-data;boundary=AaB03x') + } multipart( - formParameter: value(consumer(regex('".+"')), producer('"formParameterValue"')), - someBooleanParameter: value(consumer(regex('(true|false)')), producer('true')), + // key (parameter name), value (parameter value) pair + formParameter: $(c(regex('".+"')), p('"formParameterValue"')), + someBooleanParameter: $(c(regex(anyBoolean())), p('true')), + // a named parameter (e.g. with `file` name) that represents file with + // `name` and `content`. You can also call `named("fileName", "fileContent")` file: named( - name: value(consumer(regex('.+')), producer('filename.csv')), - content: value(consumer(regex('.+')), producer('file content'))) + // name of the file + name: $(c(regex('.+')), p('filename.csv')), + // content of the file + content: $(c(regex('.+')), p('file content'))) ) } response { diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy index a20bc3b8ed..9dba75e00e 100755 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy @@ -1502,31 +1502,47 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie @Issue('180') def 'should generate stub with multipart parameters'() { given: + // tag::multipartdsl[] org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make { request { method "PUT" url "/multipart" + headers { + contentType('multipart/form-data;boundary=AaB03x') + } multipart( - formParameter: value(consumer(regex('".+"')), producer('"formParameterValue"')), - someBooleanParameter: value(consumer(regex('(true|false)')), producer('true')), + // key (parameter name), value (parameter value) pair + formParameter: $(c(regex('".+"')), p('"formParameterValue"')), + someBooleanParameter: $(c(regex(anyBoolean())), p('true')), + // a parameter name (e.g. file) file: named( - name: value(consumer(regex('.+')), producer('filename.csv')), - content: value(consumer(regex('.+')), producer('file content'))) + // name of the file + name: $(c(regex('.+')), p('filename.csv')), + // content of the file + content: $(c(regex('.+')), p('file content'))) ) } response { status 200 } } + // end::multipartdsl[] when: String wireMockStub = new WireMockStubStrategy("Test", new ContractMetadata(null, false, 0, null, contractDsl), contractDsl).toWireMockClientStub() then: println wireMockStub - AssertionUtil.assertThatJsonsAreEqual((''' + AssertionUtil.assertThatJsonsAreEqual(( + // tag::multipartwiremock[] + ''' { "request" : { "url" : "/multipart", "method" : "PUT", + "headers" : { + "Content-Type" : { + "matches" : "multipart/form-data;boundary=AaB03x.*" + } + }, "bodyPatterns" : [ { "matches" : ".*--(.*)\\r\\nContent-Disposition: form-data; name=\\"formParameter\\"\\r\\n(Content-Type: .*\\r\\n)?(Content-Length: \\\\d+\\r\\n)?\\r\\n\\".+\\"\\r\\n--\\\\1.*" }, { @@ -1540,7 +1556,9 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie "transformers" : [ "response-template" ] } } - '''), wireMockStub) + ''' + // end::multipartwiremock[] + ), wireMockStub) and: stubMappingIsValidWireMockStub(wireMockStub) }