Skip to content

Commit

Permalink
test(jms): add controller and binding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
timonback committed Nov 20, 2023
1 parent 4228f42 commit 3cd244e
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 20 deletions.
13 changes: 6 additions & 7 deletions springwolf-examples/springwolf-jms-example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,20 @@ dependencies {
annotationProcessor project(":springwolf-plugins:springwolf-jms")
runtimeOnly project(":springwolf-ui")

implementation 'org.springframework.boot:spring-boot-starter-activemq'

runtimeOnly "org.springframework.boot:spring-boot-starter-web"
compileOnly "jakarta.jms:jakarta.jms-api"

implementation "org.slf4j:slf4j-api:${slf4jApiVersion}"

implementation "io.swagger.core.v3:swagger-annotations:${swaggerVersion}"

implementation "org.springframework.boot:spring-boot-autoconfigure"
implementation "org.springframework.boot:spring-boot"
implementation "org.springframework:spring-context"
implementation "org.springframework:spring-jms"
implementation "org.springframework.boot:spring-boot"
implementation "org.springframework.boot:spring-boot-autoconfigure"
runtimeOnly "org.springframework.boot:spring-boot-starter-web"

testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"

testImplementation "com.vaadin.external.google:android-json:${androidJsonVersion}"

testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"

testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.testcontainers.junit.jupiter.Testcontainers;

import java.io.File;
import java.util.Map;

import static io.github.stavshamir.springwolf.example.jms.dtos.ExamplePayloadDto.ExampleEnum.FOO1;
import static org.mockito.Mockito.timeout;
Expand Down Expand Up @@ -49,15 +50,15 @@ public class ProducerIntegrationWithDockerIntegrationTest {

@Test
@Order(2)
void producerCanUseSpringwolfConfigurationToSendMessage() throws InterruptedException {
void producerCanUseSpringwolfConfigurationToSendMessage() {
// given
ExamplePayloadDto payload = new ExamplePayloadDto();
payload.setSomeString("foo");
payload.setSomeLong(5);
payload.setSomeEnum(FOO1);

// when
springwolfJmsProducer.send("example-queue", payload);
springwolfJmsProducer.send("example-queue", Map.of(), payload);

// then
verify(exampleConsumer, timeout(10000)).receiveExamplePayload(payload);
Expand Down
18 changes: 12 additions & 6 deletions springwolf-plugins/springwolf-jms-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@ plugins {
dependencies {
api project(":springwolf-core")

implementation "jakarta.jms:jakarta.jms-api"

implementation "com.asyncapi:asyncapi-core:${asyncapiCoreVersion}"
implementation "org.slf4j:slf4j-api:${slf4jApiVersion}"

implementation 'org.springframework:spring-jms'
compileOnly 'org.apache.activemq:activemq-broker'
runtimeOnly "org.apache.activemq:activemq-broker"

implementation "org.springframework:spring-context"
implementation "org.springframework:spring-core"
implementation "org.springframework:spring-jms"
implementation "org.springframework:spring-web"

implementation "org.springframework.boot:spring-boot"
implementation "org.springframework.boot:spring-boot-autoconfigure"

Expand All @@ -27,18 +30,21 @@ dependencies {
annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"

testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
testRuntimeOnly "org.springframework.boot:spring-boot-starter-web"

testImplementation "org.assertj:assertj-core:${assertjCoreVersion}"

testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"

testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}"

testImplementation "org.springframework.boot:spring-boot-test"
testImplementation "org.springframework:spring-beans"
testImplementation "org.springframework:spring-test"
testImplementation 'org.apache.activemq:activemq-broker'

testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
testImplementation "org.springframework.boot:spring-boot-test"
testImplementation "org.springframework.boot:spring-boot-test-autoconfigure"

testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ protected boolean isEnabled() {
@Override
protected void publishMessage(String topic, MessageDto message, Object payload) {
log.debug("Publishing to JMS queue {}: {}", topic, message);
producer.send(topic, payload);
producer.send(topic, message.getHeaders(), payload);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.producer;

import jakarta.jms.JMSException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jms.core.JmsTemplate;

import java.util.List;
import java.util.Map;
import java.util.Optional;

@Slf4j
Expand All @@ -20,9 +22,21 @@ public boolean isEnabled() {
return template.isPresent();
}

public void send(String channelName, Object payload) {
public void send(String channelName, Map<String, String> headers, Object payload) {
if (template.isPresent()) {
template.get().convertAndSend(channelName, payload);
template.get().convertAndSend(channelName, payload, message -> {
if (headers != null) {
headers.forEach((name, value) -> {
try {
message.setStringProperty(name, value);
} catch (JMSException ex) {
log.warn("Unable to set JMS Header key=%s value=%s".formatted(name, value), ex);
}
});
}
return message;
});

} else {
log.warn("JMS producer is not configured");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.controller;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.producer.SpringwolfJmsProducer;
import io.github.stavshamir.springwolf.schemas.DefaultSchemasService;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import io.github.stavshamir.springwolf.schemas.example.ExampleJsonGenerator;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;

import java.util.Map;

import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(SpringwolfJmsController.class)
@ContextConfiguration(
classes = {
SpringwolfJmsController.class,
PublishingPayloadCreator.class,
SpringwolfJmsProducer.class,
DefaultSchemasService.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
})
@TestPropertySource(
properties = {
"springwolf.docket.base-package=io.github.stavshamir.springwolf.asyncapi",
"springwolf.docket.info.title=Title",
"springwolf.docket.info.version=1.0",
"springwolf.docket.servers.jms.protocol=jms",
"springwolf.docket.servers.jms.url=127.0.0.1",
"springwolf.plugin.jms.publishing.enabled=true",
"springwolf.use-fqn=true"
})
class SpringwolfJmsControllerIntegrationTest {

@Autowired
private MockMvc mvc;

@Autowired
private SchemasService schemasService;

@MockBean
private SpringwolfJmsProducer springwolfJmsProducer;

@Captor
private ArgumentCaptor<PayloadDto> payloadCaptor;

@Captor
private ArgumentCaptor<Map<String, String>> headerCaptor;

@BeforeEach
void setup() {
when(springwolfJmsProducer.isEnabled()).thenReturn(true);

schemasService.register(PayloadDto.class);
}

@Test
void testControllerShouldReturnBadRequestIfPayloadIsEmpty() {
try {
String content =
"""
{
"bindings": null,
"headers": null,
"payload": ""
}""";
mvc.perform(post("/springwolf/jms/publish?topic=test-topic")
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isBadRequest());
} catch (Exception e) {
verifyNoInteractions(springwolfJmsProducer);
}
}

@Test
void testControllerShouldReturnBadRequestIfPayloadIsNotSet() {
try {
String content =
"""
{
"bindings": null,
"headers": null
}""";
mvc.perform(post("/springwolf/jms/publish?topic=test-topic")
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isBadRequest());
} catch (Exception e) {
verifyNoInteractions(springwolfJmsProducer);
}
}

@Test
void testControllerShouldReturnNotFoundIfNoJmsProducerIsEnabled() throws Exception {
when(springwolfJmsProducer.isEnabled()).thenReturn(false);

String content =
"""
{
"bindings": null,
"headers": null,
"payload": "{ \\"some-payload-key\\" : \\"some-payload-value\\" }"
}""";
mvc.perform(post("/springwolf/jms/publish?topic=test-topic")
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isNotFound());
}

@Test
void testControllerShouldCallJmsProducerIfOnlyPayloadIsSend() throws Exception {
when(springwolfJmsProducer.isEnabled()).thenReturn(true);

String content =
"""
{
"bindings": null,
"headers": null,
"payload": "{ \\"some-payload-key\\" : \\"some-payload-value\\" }",
"payloadType": "io.github.stavshamir.springwolf.asyncapi.controller.SpringwolfJmsControllerIntegrationTest$PayloadDto"
}""";

mvc.perform(post("/springwolf/jms/publish")
.param("topic", "test-topic")
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isOk());

verify(springwolfJmsProducer).send(eq("test-topic"), isNull(), payloadCaptor.capture());

assertThat(payloadCaptor.getValue()).isEqualTo(new PayloadDto("some-payload-value"));
}

@Test
void testControllerShouldCallJmsProducerIfPayloadAndHeadersAreSend() throws Exception {
when(springwolfJmsProducer.isEnabled()).thenReturn(true);

String content =
"""
{
"bindings": null,
"headers": {
"some-header-key": "some-header-value"
},
"payload": "{ \\"some-payload-key\\" : \\"some-payload-value\\" }",
"payloadType": "io.github.stavshamir.springwolf.asyncapi.controller.SpringwolfJmsControllerIntegrationTest$PayloadDto"
}
""";

mvc.perform(post("/springwolf/jms/publish?topic=test-topic")
.contentType(MediaType.APPLICATION_JSON)
.content(content))
.andExpect(status().isOk());

verify(springwolfJmsProducer).send(eq("test-topic"), headerCaptor.capture(), payloadCaptor.capture());

assertThat(headerCaptor.getValue()).isEqualTo(singletonMap("some-header-key", "some-header-value"));
assertThat(payloadCaptor.getValue()).isEqualTo(new PayloadDto("some-payload-value"));
}

@Data
@AllArgsConstructor
@Jacksonized
@Builder
public static class PayloadDto {
@JsonProperty("some-payload-key")
private String field;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.scanners.bindings.processor;

import com.asyncapi.v2.binding.message.jms.JMSMessageBinding;
import io.github.stavshamir.springwolf.asyncapi.scanners.bindings.ProcessedMessageBinding;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.JmsAsyncOperationBinding;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

class JmsMessageBindingProcessorTest {
private final JmsMessageBindingProcessor processor = new JmsMessageBindingProcessor();

@Test
void processTest() throws NoSuchMethodException {
Method method = JmsMessageBindingProcessorTest.class.getMethod("methodWithAnnotation");

ProcessedMessageBinding binding = processor.process(method).get();

assertThat(binding.getType()).isEqualTo("jms");
assertThat(binding.getBinding()).isEqualTo(new JMSMessageBinding());
}

@Test
void processWithoutAnnotationTest() throws NoSuchMethodException {
Method method = JmsMessageBindingProcessorTest.class.getMethod("methodWithoutAnnotation");

Optional<ProcessedMessageBinding> binding = processor.process(method);

assertThat(binding).isNotPresent();
}

@JmsAsyncOperationBinding
public void methodWithAnnotation() {}

public void methodWithoutAnnotation() {}
}
Loading

0 comments on commit 3cd244e

Please sign in to comment.