From 2f19a33bc62d0d77affeafa320c0f80c4c7a0861 Mon Sep 17 00:00:00 2001 From: Mikhail Gordienko Date: Wed, 1 Sep 2021 16:59:35 +0300 Subject: [PATCH] fix #1705: AMQP stub runner NullPointerException (#1708) fixes #1705 --- .../amqp/SpringAmqpStubMessages.java | 43 ++++++++------- .../amqp/SpringAmqpStubMessagesTests.java | 55 +++++++++++++++++++ 2 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessagesTests.java diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessages.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessages.java index 35a9ee96a2..96cbdeffd9 100644 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessages.java +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessages.java @@ -41,6 +41,7 @@ import org.springframework.cloud.contract.verifier.converter.YamlContract; import org.springframework.cloud.contract.verifier.messaging.MessageVerifier; import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessageMetadata; import org.springframework.cloud.contract.verifier.util.MetadataUtil; +import org.springframework.messaging.MessageHeaders; import org.springframework.util.Assert; import static org.mockito.Matchers.eq; @@ -85,21 +86,38 @@ public class SpringAmqpStubMessages implements MessageVerifier { } @Override - public void send(T payload, Map headers, String destination, YamlContract contract) { + public void send(T payload, Map messageHeaders, String destination, YamlContract contract) { + final MessageHeaders headers = new MessageHeaders(messageHeaders); Message message = org.springframework.amqp.core.MessageBuilder.withBody(((String) payload).getBytes()) - .andProperties(MessagePropertiesBuilder.newInstance().setContentType(header(headers, "contentType")) - .copyHeaders(headers).build()) + .andProperties(MessagePropertiesBuilder.newInstance() + .setContentType(header(headers, MessageHeaders.CONTENT_TYPE)).copyHeaders(headers).build()) .build(); - if (headers != null && headers.containsKey(DEFAULT_CLASSID_FIELD_NAME)) { + if (headers.containsKey(DEFAULT_CLASSID_FIELD_NAME)) { message.getMessageProperties().setHeader(DEFAULT_CLASSID_FIELD_NAME, headers.get(DEFAULT_CLASSID_FIELD_NAME)); } - if (headers != null && headers.containsKey(AmqpHeaders.RECEIVED_ROUTING_KEY)) { + if (headers.containsKey(AmqpHeaders.RECEIVED_ROUTING_KEY)) { message.getMessageProperties().setReceivedRoutingKey(header(headers, AmqpHeaders.RECEIVED_ROUTING_KEY)); } send(message, destination, contract); } + private String header(MessageHeaders headers, String headerName) { + Object value = headers.get(headerName); + + if (value == null) { + return ""; + } + else if (value instanceof String) { + return (String) value; + } + else if (value instanceof Iterable) { + Iterable values = ((Iterable) value); + return values.iterator().hasNext() ? (String) values.iterator().next() : ""; + } + return value.toString(); + } + public void mergeMessagePropertiesFromMetadata(YamlContract contract, Message message) { if (contract != null && contract.metadata.containsKey(AmqpMetadata.METADATA_KEY)) { AmqpMetadata amqpMetadata = AmqpMetadata.fromMetadata(contract.metadata); @@ -116,21 +134,6 @@ public class SpringAmqpStubMessages implements MessageVerifier { return messageMetadata.getMessageType() == ContractVerifierMessageMetadata.MessageType.INPUT; } - private String header(Map headers, String headerName) { - if (headers == null) { - return ""; - } - Object value = headers.get(headerName); - if (value instanceof String) { - return (String) value; - } - else if (value instanceof Iterable) { - Iterable values = ((Iterable) value); - return values.iterator().hasNext() ? (String) values.iterator().next() : ""; - } - return value.toString(); - } - @Override public void send(Message message, String destination, YamlContract contract) { mergeMessagePropertiesFromMetadata(contract, message); diff --git a/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessagesTests.java b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessagesTests.java new file mode 100644 index 0000000000..444f81a2e1 --- /dev/null +++ b/spring-cloud-contract-verifier/src/test/java/org/springframework/cloud/contract/verifier/messaging/amqp/SpringAmqpStubMessagesTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2021-2021 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. + */ + +package org.springframework.cloud.contract.verifier.messaging.amqp; + +import java.util.Collections; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import org.springframework.amqp.core.MessageListener; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.boot.autoconfigure.amqp.RabbitProperties; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SpringAmqpStubMessagesTests { + + @Test + void should_send_message_without_headers_and_contract() { + final RabbitTemplate rabbitTemplate = mock(RabbitTemplate.class); + final MessageListenerAccessor messageListenerAccessor = mock(MessageListenerAccessor.class); + final RabbitProperties rabbitProperties = mock(RabbitProperties.class); + final SimpleMessageListenerContainer messageListenerContainer = mock(SimpleMessageListenerContainer.class); + final MessageListener messageListener = mock(MessageListener.class); + + when(messageListenerContainer.getMessageListener()).thenReturn(messageListener); + when(messageListenerAccessor.getListenerContainersForDestination(any(), any())) + .thenReturn(Collections.singletonList(messageListenerContainer)); + + final SpringAmqpStubMessages springAmqpStubMessages = new SpringAmqpStubMessages(rabbitTemplate, + messageListenerAccessor, rabbitProperties); + + Assertions.assertThatCode(() -> springAmqpStubMessages.send(anyString(), null, anyString(), null)) + .doesNotThrowAnyException(); + } + +}