diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java index d05767254b..65c6e31474 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRunnerExecutor.java @@ -35,13 +35,14 @@ import org.springframework.beans.BeanUtils; import org.springframework.cloud.contract.spec.Contract; import org.springframework.cloud.contract.spec.internal.DslProperty; +import org.springframework.cloud.contract.spec.internal.FromFileProperty; import org.springframework.cloud.contract.spec.internal.Headers; import org.springframework.cloud.contract.spec.internal.OutputMessage; import org.springframework.cloud.contract.stubrunner.AvailablePortScanner.PortCallback; import org.springframework.cloud.contract.stubrunner.provider.wiremock.WireMockHttpServerStub; import org.springframework.cloud.contract.verifier.converter.YamlContract; import org.springframework.cloud.contract.verifier.converter.YamlContractConverter; -import org.springframework.cloud.contract.verifier.messaging.MessageVerifier; +import org.springframework.cloud.contract.verifier.messaging.MessageVerifierSender; import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessageMetadata; import org.springframework.cloud.contract.verifier.messaging.noop.NoOpStubMessages; import org.springframework.cloud.contract.verifier.util.BodyExtractor; @@ -57,7 +58,7 @@ class StubRunnerExecutor implements StubFinder { private final AvailablePortScanner portScanner; - private final MessageVerifier contractVerifierMessaging; + private final MessageVerifierSender messageVerifierSender; private final List serverStubs; @@ -65,10 +66,10 @@ class StubRunnerExecutor implements StubFinder { private final YamlContractConverter yamlContractConverter = new YamlContractConverter(); - StubRunnerExecutor(AvailablePortScanner portScanner, MessageVerifier contractVerifierMessaging, + StubRunnerExecutor(AvailablePortScanner portScanner, MessageVerifierSender messageVerifierSender, List serverStubs) { this.portScanner = portScanner; - this.contractVerifierMessaging = contractVerifierMessaging; + this.messageVerifierSender = messageVerifierSender; this.serverStubs = serverStubs; } @@ -248,11 +249,22 @@ private void sendMessage(Contract groovyDsl) { List yamlContracts = yamlContractConverter.convertTo(Collections.singleton(groovyDsl)); YamlContract contract = yamlContracts.get(0); setMessageType(contract, ContractVerifierMessageMetadata.MessageType.OUTPUT); - // TODO: Json is harcoded here - this.contractVerifierMessaging.send( - JsonOutput - .toJson(BodyExtractor.extractClientValueFromBody(body == null ? null : body.getClientValue())), - headers == null ? null : headers.asStubSideMap(), outputMessage.getSentTo().getClientValue(), contract); + + Object payload = null; + if (body.getClientValue() instanceof FromFileProperty) { + FromFileProperty fromFile = (FromFileProperty) body.getClientValue(); + if (fromFile.isByte()) { + payload = fromFile.asBytes(); + } else { + payload = fromFile.asString(); + } + } + else { + payload = JsonOutput.toJson(BodyExtractor.extractClientValueFromBody(body == null ? null : body.getClientValue())); + } + + this.messageVerifierSender.send(payload, headers == null ? null : headers.asStubSideMap(), + outputMessage.getSentTo().getClientValue(), contract); } private void setMessageType(YamlContract contract, ContractVerifierMessageMetadata.MessageType output) { diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy index b514028471..c2c5b59633 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/StubRunnerExecutorSpec.groovy @@ -99,6 +99,54 @@ class StubRunnerExecutorSpec extends Specification { executor.shutdown() } + def 'should ensure that triggered contracts have properly parsed message body from file as bytes when a message is sent'() { + given: + StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) + executor.runStubs(stubRunnerOptions, repository, stub) + when: + executor.trigger('send_order_bin') + then: + noExceptionThrown() + cleanup: + executor.shutdown() + } + + def 'should ensure that triggered contracts have properly parsed message body from file as json when a message is sent'() { + given: + StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) + executor.runStubs(stubRunnerOptions, repository, stub) + when: + executor.trigger('send_order_json') + then: + noExceptionThrown() + cleanup: + executor.shutdown() + } + + def 'should ensure that triggered contracts have properly parsed message body from file as xml when a message is sent'() { + given: + StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) + executor.runStubs(stubRunnerOptions, repository, stub) + when: + executor.trigger('send_order_xml') + then: + noExceptionThrown() + cleanup: + executor.shutdown() + } + + def 'should ensure that triggered contracts have properly parsed message body from file as text when a message is sent'() { + given: + StubRunnerExecutor executor = new StubRunnerExecutor(portScanner, new AssertingStubMessages(), []) + executor.runStubs(stubRunnerOptions, repository, stub) + when: + executor.trigger('send_order_csv') + then: + noExceptionThrown() + cleanup: + executor.shutdown() + } + def 'should match stub with empty classifier'() { given: def stubConf = new StubConfiguration('groupX', 'artifactX', 'versionX', '') @@ -208,7 +256,9 @@ class StubRunnerExecutorSpec extends Specification { @Override void send(T payload, Map headers, String destination, YamlContract contract) { - assert !(JsonOutput.toJson(payload).contains("serverValue")) + if(payload instanceof String) { + assert !(JsonOutput.toJson(payload).contains("serverValue")) + } assert headers.entrySet().every { !(it.value.toString().contains("serverValue")) } } diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract1.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract1.groovy new file mode 100644 index 0000000000..ab8578e008 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract1.groovy @@ -0,0 +1,32 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +org.springframework.cloud.contract.spec.Contract.make { + description 'issue #1864' + label 'send_order_bin' + input { + triggeredBy('sendOrder()') + } + outputMessage { + sentTo 'orderEventsTopic' + headers { + [ + header('contentType': 'application/vnd.orderplaced.v1+avro') + ] + } + body(fileAsBytes("orderplaced-event.bin")) + } +} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract2.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract2.groovy new file mode 100644 index 0000000000..13cd178572 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract2.groovy @@ -0,0 +1,32 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +org.springframework.cloud.contract.spec.Contract.make { + description 'issue #1864' + label 'send_order_json' + input { + triggeredBy('sendOrderJson()') + } + outputMessage { + sentTo 'orderEventsTopic' + headers { + [ + header('contentType': 'application/json') + ] + } + body(file("orderplaced-event.json")) + } +} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract3.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract3.groovy new file mode 100644 index 0000000000..4aefcf7b6d --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract3.groovy @@ -0,0 +1,32 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +org.springframework.cloud.contract.spec.Contract.make { + description 'issue #1864' + label 'send_order_xml' + input { + triggeredBy('sendOrderXml()') + } + outputMessage { + sentTo 'orderEventsTopic' + headers { + [ + header('contentType': 'application/xml') + ] + } + body(file("orderplaced-event.xml")) + } +} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract4.groovy b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract4.groovy new file mode 100644 index 0000000000..d31b91d419 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/contract4.groovy @@ -0,0 +1,32 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +org.springframework.cloud.contract.spec.Contract.make { + description 'issue #1864' + label 'send_order_csv' + input { + triggeredBy('sendOrderCsv()') + } + outputMessage { + sentTo 'orderEventsTopic' + headers { + [ + header('contentType': 'text/plain') + ] + } + body(file("orderplaced-event.csv")) + } +} diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.bin b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.bin new file mode 100644 index 0000000000..3522c31111 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.bin @@ -0,0 +1 @@ +H505c50a7-0c26-4582-b9ae-bc1c0f65fec10fakeCustomer@example.com��ٳ�a \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.csv b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.csv new file mode 100644 index 0000000000..8ca6f9ca0b --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.csv @@ -0,0 +1,2 @@ +orderId,customerId,orderCreated +505c50a7-0c26-4582-b9ae-bc1c0f65fec1,fakeUser@example.com,orderCreated": "2023-01-30T15:11:00Z \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.json b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.json new file mode 100644 index 0000000000..c258dcc8c4 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.json @@ -0,0 +1,5 @@ +{ + "orderId": "505c50a7-0c26-4582-b9ae-bc1c0f65fec1", + "customerId": "fakeUser@example.com", + "orderCreated": "2023-01-30T15:11:00Z" +} \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.xml b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.xml new file mode 100644 index 0000000000..2c168cc670 --- /dev/null +++ b/spring-cloud-contract-stub-runner/src/test/resources/repository/messagecontract/orderplaced-event.xml @@ -0,0 +1,6 @@ + + + 505c50a7-0c26-4582-b9ae-bc1c0f65fec1 + fakeCustomer@example.com + 2023-01-30T15:11:00Z + \ No newline at end of file