diff --git a/Makefile b/Makefile index c538335..48180b8 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ testIntegration: _setUpGradle _testComposeUp testFunctional: _setUpGradle _functionalComposeUp make _waitForLocalService echo "Running Functional tests" - ./gradlew testFunctional + ./gradlew testFunctional --stacktrace make _functionalComposeDown analyseWithJacoco: _setUpGradle @@ -56,4 +56,4 @@ analyseWithSonar: _gitFetchUnshallow _setUpGradle package: _setUpGradle echo "Packaging service" - ./gradlew bootJar \ No newline at end of file + ./gradlew clean bootJar \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0e44016..3f7dd0b 100644 --- a/build.gradle +++ b/build.gradle @@ -21,8 +21,8 @@ dependencies { implementation('org.springframework.boot:spring-boot-starter-validation') implementation('org.projectlombok:lombok:1.18.12') - // For Message Queue - implementation('org.springframework.boot:spring-boot-starter-activemq') + // For Kafka + implementation('org.springframework.kafka:spring-kafka') // For Database implementation('org.springframework.boot:spring-boot-starter-data-jpa') @@ -49,6 +49,7 @@ dependencies { testImplementation('io.rest-assured:rest-assured:4.2.0') testImplementation('io.rest-assured:json-path:4.2.0') testImplementation('io.rest-assured:xml-path:4.2.0') + testImplementation('org.awaitility:awaitility:3.1.6') // Annotations annotationProcessor('org.springframework.boot:spring-boot-configuration-processor') @@ -75,7 +76,7 @@ tasks.withType(JavaCompile) { configurations.all { exclude group:'junit', module:'junit' - exclude group:'org.junit.vintage', module:'junit-vintage-engine' + exclude group: 'org.junit.vintage', module:'junit-vintage-engine' exclude group:'org.mockito', module:'mockito-all' exclude group:'org.slf4j', module:'slf4j-log4j12' exclude group:'org.springframework.boot', module:'spring-boot-starter-logging' diff --git a/docker-compose-test.yml b/docker-compose-test.yml index 9341967..00da344 100644 --- a/docker-compose-test.yml +++ b/docker-compose-test.yml @@ -12,11 +12,27 @@ services: - 8081:8081 depends_on: - database - activemq: - image: rmohr/activemq:5.15.9-alpine + - kafka + links: + - kafka + - database + + kafka: + image: obsidiandynamics/kafka + restart: "no" ports: - - 61616:61616 - - 8161:8161 + - "2181:2181" + - "9092:9092" + environment: + KAFKA_LISTENERS: "INTERNAL://:29092,EXTERNAL://:9092" + KAFKA_ADVERTISED_LISTENERS: "INTERNAL://kafka:29092,EXTERNAL://kafka:9092" + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT" + KAFKA_INTER_BROKER_LISTENER_NAME: "INTERNAL" + KAFKA_ZOOKEEPER_SESSION_TIMEOUT: "6000" + KAFKA_RESTART_ATTEMPTS: "10" + KAFKA_RESTART_DELAY: "5" + ZOOKEEPER_AUTOPURGE_PURGE_INTERVAL: "0" + database: image: postgres:12 ports: diff --git a/docker-compose.yml b/docker-compose.yml index d88a1e9..9ac0e02 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,5 @@ version: "3.7" services: - activemq: - image: rmohr/activemq:5.15.9-alpine - ports: - - 61616:61616 - - 8161:8161 database: image: postgres:12 ports: @@ -14,3 +9,29 @@ services: POSTGRES_PASSWORD: postgres POSTGRES_DB: java_component + kafka: + image: obsidiandynamics/kafka + restart: "no" + ports: + - "2181:2181" + - "9092:9092" + environment: + KAFKA_LISTENERS: "INTERNAL://:29092,EXTERNAL://:9092" + KAFKA_ADVERTISED_LISTENERS: "INTERNAL://kafka:29092,EXTERNAL://localhost:9092" + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT" + KAFKA_INTER_BROKER_LISTENER_NAME: "INTERNAL" + KAFKA_ZOOKEEPER_SESSION_TIMEOUT: "6000" + KAFKA_RESTART_ATTEMPTS: "10" + KAFKA_RESTART_DELAY: "5" + ZOOKEEPER_AUTOPURGE_PURGE_INTERVAL: "0" + + kafdrop: + image: obsidiandynamics/kafdrop + restart: "no" + ports: + - "9000:9000" + environment: + KAFKA_BROKERCONNECT: "kafka:29092" + JVM_OPTS: "-Xms16M -Xmx48M -Xss180K -XX:-TieredCompilation -XX:+UseStringDeduplication -noverify" + depends_on: + - "kafka" \ No newline at end of file diff --git a/gradle/docker-compose.gradle b/gradle/docker-compose.gradle new file mode 100644 index 0000000..e69de29 diff --git a/scripts/wait-for-url.sh b/scripts/wait-for-url.sh index 6ed457f..42e6035 100755 --- a/scripts/wait-for-url.sh +++ b/scripts/wait-for-url.sh @@ -9,7 +9,7 @@ fi echo "Waiting for $1" -MAX_ATTEMPTS=5 +MAX_ATTEMPTS=10 CURRENT_ATTEMPT=0 # Check if the provided URL can be reached diff --git a/src/functional-test/java/com/roboautomator/component/health/HealthActuatorFuncTest.java b/src/functional-test/java/com/roboautomator/component/health/HealthActuatorFuncTest.java index fe21c4f..251e7df 100644 --- a/src/functional-test/java/com/roboautomator/component/health/HealthActuatorFuncTest.java +++ b/src/functional-test/java/com/roboautomator/component/health/HealthActuatorFuncTest.java @@ -53,17 +53,6 @@ void shouldReturnDiskSpaceStatusWhenRunning() { .body("components.diskSpace.details.threshold", any(Number.class)); } - @Test - void shouldReturnJMSStatusWhenRunning() { - given() - .when() - .get(HEALTH_PROBE_ENDPOINT) - .then() - .statusCode(200) - .body("components.jms.status", equalTo("UP")) - .body("components.jms.details.provider", equalTo("ActiveMQ")); - } - @Test void shouldReturnPingStatusWhenRunning() { given() diff --git a/src/main/java/com/roboautomator/component/QueueConsumer.java b/src/main/java/com/roboautomator/component/QueueConsumer.java deleted file mode 100644 index b59b7ac..0000000 --- a/src/main/java/com/roboautomator/component/QueueConsumer.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.roboautomator.component; - -import javax.jms.JMSException; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.handler.annotation.Headers; -import org.springframework.messaging.handler.annotation.Payload; - -import javax.jms.Message; -import javax.jms.Session; - -public interface QueueConsumer { - - /** - *

A listener that listens to the queueName for messages. When a onMessage event is - * emitted. It will only log the {@link Payload}, {@link Headers}, {@link Message} and {@link Session}.

- * - *

Requires the annotation {@link org.springframework.jms.annotation.JmsListener} to be configured with the - * queue name

- * - * @param message - The de-serialized message of type {@link T} - * @param headers - The message {@link Headers} from the message queue. - * @param rawMessage - The raw message ({@link Message}), unprocessed from the queue. - * @param session - The session information ({@link Session}) - */ - void handleMessage(@Payload T message, @Headers MessageHeaders headers, - Message rawMessage, Session session) throws JMSException; -} diff --git a/src/main/java/com/roboautomator/component/QueueProducer.java b/src/main/java/com/roboautomator/component/QueueProducer.java deleted file mode 100644 index 5916dbe..0000000 --- a/src/main/java/com/roboautomator/component/QueueProducer.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.roboautomator.component; - -public interface QueueProducer { - - /** - *

Simplest working solution to be able to send a message to a message queue.

- * - * @param message the message object (type {@link T}) to send to the message queue. - */ - void sendMessage(T message); -} diff --git a/src/main/java/com/roboautomator/component/config/queue/ActiveMQConfig.java b/src/main/java/com/roboautomator/component/config/queue/ActiveMQConfig.java deleted file mode 100644 index 6ae7d64..0000000 --- a/src/main/java/com/roboautomator/component/config/queue/ActiveMQConfig.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.roboautomator.component.config.queue; - -import java.util.List; -import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.ActiveMQSslConnectionFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.jms.config.DefaultJmsListenerContainerFactory; -import org.springframework.jms.connection.CachingConnectionFactory; -import org.springframework.jms.core.JmsTemplate; - -@Configuration -public class ActiveMQConfig implements QueueConfig { - - @Value("${spring.activemq.broker-url}") - private String brokerUrl; - - @Value("${spring.activemq.user}") - private String user; - - @Value("${spring.activemq.password}") - private String password; - - private ActiveMQSslConnectionFactory getSslConnectionFactory() { - return new ActiveMQSslConnectionFactory(); - } - - /** - *

Strategy: If URL contains ssl then it will use {@link ActiveMQSslConnectionFactory} instead of - * {@link ActiveMQConnectionFactory}.

- * - *

Trusted Packages: - *

- * - * @return the {@link ActiveMQConnectionFactory} to be used. - */ - public ActiveMQConnectionFactory configureActiveMQConnectionFactory() { - - var activeMQConnectionFactory = brokerUrl.contains("ssl") - ? getSslConnectionFactory() - : new ActiveMQConnectionFactory(); - - activeMQConnectionFactory.setBrokerURL(brokerUrl); - activeMQConnectionFactory.setUserName(user); - activeMQConnectionFactory.setPassword(password); - - activeMQConnectionFactory.setTrustedPackages(List.of( - "com.roboautomator.component.message", - "com.roboautomator.component.patient" - )); - - return activeMQConnectionFactory; - } - - @Override - public CachingConnectionFactory getConnectionFactory() { - return new CachingConnectionFactory( - configureActiveMQConnectionFactory()); - } - - @Bean - @Override - public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() { - var defaultJmsListenerContainerFactory = new DefaultJmsListenerContainerFactory(); - defaultJmsListenerContainerFactory.setConnectionFactory(getConnectionFactory()); - defaultJmsListenerContainerFactory.setConcurrency("1-1"); - return defaultJmsListenerContainerFactory; - } - - @Override - public JmsTemplate jmsTemplate() { - return new JmsTemplate(getConnectionFactory()); - } -} \ No newline at end of file diff --git a/src/main/java/com/roboautomator/component/config/queue/QueueConfig.java b/src/main/java/com/roboautomator/component/config/queue/QueueConfig.java deleted file mode 100644 index 550a426..0000000 --- a/src/main/java/com/roboautomator/component/config/queue/QueueConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.roboautomator.component.config.queue; - -import org.springframework.jms.annotation.EnableJms; -import org.springframework.jms.config.DefaultJmsListenerContainerFactory; -import org.springframework.jms.connection.CachingConnectionFactory; -import org.springframework.jms.core.JmsTemplate; - -@EnableJms -public interface QueueConfig { - - /** - * Required by JmsListener annotation (Assumed to have either DefaultJmsListnenerCobtainerFactory - * as jmsListenerContainerFactory or JmsListenerContainerFactory) - * - * @return {@link DefaultJmsListenerContainerFactory} - */ - DefaultJmsListenerContainerFactory jmsListenerContainerFactory(); - - /** - * not required to be bean {@link CachingConnectionFactory}. - * - * @return the configured {@link CachingConnectionFactory} - */ - CachingConnectionFactory getConnectionFactory(); - - /** - * Configures the {@link JmsTemplate} to include the {@link CachingConnectionFactory}. - * - * @return the configured {@link JmsTemplate} - */ - JmsTemplate jmsTemplate(); - -} - diff --git a/src/main/java/com/roboautomator/component/message/ActiveMQConsumer.java b/src/main/java/com/roboautomator/component/message/ActiveMQConsumer.java deleted file mode 100644 index 1e04dc4..0000000 --- a/src/main/java/com/roboautomator/component/message/ActiveMQConsumer.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.roboautomator.component.message; - -import static com.roboautomator.component.util.StringHelper.cleanString; -import com.roboautomator.component.QueueConsumer; -import java.util.UUID; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.Session; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.MDC; -import org.springframework.jms.annotation.JmsListener; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.handler.annotation.Headers; -import org.springframework.messaging.handler.annotation.Payload; -import org.springframework.stereotype.Component; - -/** - *

Simple consumer for ActiveMQ

- * - * See: {@link org.springframework.jms.config.AbstractJmsListenerContainerFactory} - * for event emitter configuration. - * - * Required in config (application.yml): - * - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class ActiveMQConsumer implements QueueConsumer { - - private static final String QUEUE_NAME = "testQueue"; - - private static final String UUID_PATTERN = "[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}"; - - private final MessageRepository messageRepository; - - @Override - @JmsListener(destination = QUEUE_NAME) - public void handleMessage(@Payload String message, @Headers MessageHeaders headers, - Message rawMessage, Session session) { - - var cleanMessage = cleanString(message); - - var correlationId = extractCorrelationId(rawMessage); - - MDC.put("correlationId", correlationId.toString()); - - var messageEntity = MessageEntity.builder() - .message(cleanMessage) - .correlationId(correlationId) - .build(); - - messageRepository.save(messageEntity); - } - - private UUID extractCorrelationId(Message jmsMessage) { - try { - var correlationId = jmsMessage.getJMSCorrelationID(); - - return correlationId != null && correlationId.matches(UUID_PATTERN) - ? UUID.fromString(correlationId) - : UUID.randomUUID(); - - } catch (JMSException exception) { - log.info("Could not extract JMSCorrelationID, generated new UUID"); - return UUID.randomUUID(); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/roboautomator/component/message/ActiveMQProducer.java b/src/main/java/com/roboautomator/component/message/ActiveMQProducer.java deleted file mode 100644 index b1eca2f..0000000 --- a/src/main/java/com/roboautomator/component/message/ActiveMQProducer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.roboautomator.component.message; - -import com.roboautomator.component.QueueProducer; -import com.roboautomator.component.config.queue.ActiveMQConfig; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.MDC; -import org.springframework.jms.core.JmsTemplate; -import org.springframework.stereotype.Component; - -/** - *

Producer for ActiveMQ implementation

- * - * Required in config (application.yml): - *
    - *
  • mq.queueName
  • - *
  • spring.activemq.broker-url
  • - *
  • spring.activemq.user
  • - *
  • spring.activemq.password
  • - *
- * - * Usage: - *

The ActiveMQ configuration is setup in - * {@link ActiveMQConfig} and access to - * {@link #sendMessage(String)} will be through instantiating this class.

- * - *

An example implementation of usage can be found in - * {@link MessageController}

- */ -@Slf4j -@Component -@AllArgsConstructor -public class ActiveMQProducer implements QueueProducer { - - private static final String QUEUE_NAME = "testQueue"; - - private final JmsTemplate jmsTemplate; - - @Override - public void sendMessage(String message) { - log.info("Sending message \"{}\" to the \"{}\" queue", message, QUEUE_NAME); - jmsTemplate.convertAndSend(QUEUE_NAME, message, msg -> { - msg.setJMSCorrelationID(MDC.get("correlationId")); - return msg; - }); - } -} \ No newline at end of file diff --git a/src/main/java/com/roboautomator/component/message/KafkaConsumer.java b/src/main/java/com/roboautomator/component/message/KafkaConsumer.java new file mode 100644 index 0000000..32d7147 --- /dev/null +++ b/src/main/java/com/roboautomator/component/message/KafkaConsumer.java @@ -0,0 +1,45 @@ +package com.roboautomator.component.message; + +import static com.roboautomator.component.util.StringHelper.cleanString; +import java.util.Map; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Headers; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class KafkaConsumer { + + private static final String TOPIC_NAME = "Test.Topic"; + + private final MessageRepository messageRepository; + + @KafkaListener(topics = TOPIC_NAME) + public void onMessage(@Payload String payload, @Headers Map headers) { + var cleanString = cleanString(payload); + log.info("New message on topic {}: {}", TOPIC_NAME, cleanString); + + var correlationId = extractCorrelationId(headers); + MDC.put("correlationId", correlationId.toString()); + + var messageEntity = MessageEntity.builder() + .message(cleanString) + .correlationId(correlationId) + .build(); + messageRepository.save(messageEntity); + } + + private UUID extractCorrelationId(Map headers) { + var correlationId = headers.get(KafkaHeaders.CORRELATION_ID); + return (correlationId == null) + ? UUID.randomUUID() + : UUID.fromString((String) correlationId); + } +} diff --git a/src/main/java/com/roboautomator/component/message/KafkaProducer.java b/src/main/java/com/roboautomator/component/message/KafkaProducer.java new file mode 100644 index 0000000..727c1c8 --- /dev/null +++ b/src/main/java/com/roboautomator/component/message/KafkaProducer.java @@ -0,0 +1,32 @@ +package com.roboautomator.component.message; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class KafkaProducer { + + private static final String TOPIC_NAME = "Test.Topic"; + + private final KafkaTemplate producer; + + public void send(String message) { + log.info("Sending message to Topic {}: {}", TOPIC_NAME, message); + + var record = MessageBuilder + .withPayload(message) + .setHeader(KafkaHeaders.TOPIC, TOPIC_NAME) + .setHeader(KafkaHeaders.MESSAGE_KEY, MDC.get("correlationId")) + .setHeader(KafkaHeaders.CORRELATION_ID, MDC.get("correlationId")) + .build(); + + producer.send(record); + } +} diff --git a/src/main/java/com/roboautomator/component/message/MessageController.java b/src/main/java/com/roboautomator/component/message/MessageController.java index ed29d06..5f603fe 100644 --- a/src/main/java/com/roboautomator/component/message/MessageController.java +++ b/src/main/java/com/roboautomator/component/message/MessageController.java @@ -4,9 +4,7 @@ import java.util.UUID; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.jms.JmsException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -21,7 +19,7 @@ public class MessageController { private final MessageRepository messageRepository; - private final ActiveMQProducer producer; + private final KafkaProducer producer; @PostMapping public ResponseEntity sendMessageToQueue(@RequestBody UserMessage userMessage) { @@ -30,12 +28,7 @@ public ResponseEntity sendMessageToQueue(@RequestBody UserMessage userMe log.info("Received request to send the message \"{}\" to queue", message); - try { - producer.sendMessage(message); - } catch (JmsException e) { - log.error("Could not process the message \"{}\", returning", message); - return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(e.toString()); - } + producer.send(message); return ResponseEntity.ok(message); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e47c4ce..f4a79e6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -12,8 +12,16 @@ management: spring: main: banner-mode: off - profiles: - active: "dev" + kafka: + bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:kafka:9092} + properties: + security.protocol: "PLAINTEXT" + consumer: + group-id: component + auto-offset-reset: earliest + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.apache.kafka.common.serialization.StringSerializer swagger: endpoint: /swagger-ui.html jpa: @@ -26,42 +34,6 @@ spring: connection-timeout: 20000 maximum-pool-size: 5 driver-class-name: org.postgresql.Driver - ---- - -spring: - profiles: dev - activemq: - broker-url: tcp://localhost:61616 - user: admin - password: admin - datasource: - url: jdbc:postgresql://localhost:5432/java_component + url: ${DATABASE_URL:jdbc:postgresql://database:5432/java_component} username: postgres password: postgres - ---- - -spring: - profiles: test - activemq: - broker-url: tcp://localhost:61616 - user: admin - password: admin - datasource: - url: jdbc:postgresql://localhost:5432/java_component - username: postgres - password: postgres - ---- - -spring: - profiles: prod - activemq: - broker-url: tcp://activemq:61616 - user: admin - password: admin - datasource: - url: jdbc:postgresql://database:5432/java_component - username: postgres - password: postgres \ No newline at end of file diff --git a/src/test/java/com/roboautomator/component/MainApplicationTestIT.java b/src/test/java/com/roboautomator/component/MainApplicationTestIT.java index 02d0082..a766f47 100644 --- a/src/test/java/com/roboautomator/component/MainApplicationTestIT.java +++ b/src/test/java/com/roboautomator/component/MainApplicationTestIT.java @@ -7,9 +7,11 @@ import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class MainApplicationTestIT { diff --git a/src/test/java/com/roboautomator/component/config/logging/LoggingConfigTest.java b/src/test/java/com/roboautomator/component/config/logging/LoggingConfigTest.java index 368dcf4..7bdfcb7 100644 --- a/src/test/java/com/roboautomator/component/config/logging/LoggingConfigTest.java +++ b/src/test/java/com/roboautomator/component/config/logging/LoggingConfigTest.java @@ -1,6 +1,7 @@ package com.roboautomator.component.config.logging; -import com.roboautomator.component.config.logging.LoggingConfig; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import com.roboautomator.component.middleware.LoggingMiddleware; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -9,9 +10,6 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - @ExtendWith(MockitoExtension.class) class LoggingConfigTest { @@ -34,6 +32,6 @@ void shouldAddLoggingMiddlewareToInteceptorRegistry() { loggingConfig.addInterceptors(interceptorRegistry); verify(interceptorRegistry, times(1)) - .addInterceptor(loggingMiddleware); + .addInterceptor(loggingMiddleware); } } diff --git a/src/test/java/com/roboautomator/component/config/queue/ActiveMQConfigTestIT.java b/src/test/java/com/roboautomator/component/config/queue/ActiveMQConfigTestIT.java deleted file mode 100644 index b77f5a1..0000000 --- a/src/test/java/com/roboautomator/component/config/queue/ActiveMQConfigTestIT.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.roboautomator.component.config.queue; - -import org.apache.activemq.ActiveMQConnectionFactory; -import org.apache.activemq.ActiveMQSslConnectionFactory; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.jms.core.JmsTemplate; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static org.assertj.core.api.Assertions.assertThat; - -@ExtendWith(SpringExtension.class) -@SpringBootTest -class ActiveMQConfigTestIT { - - @Value("${spring.activemq.broker-url}") - private String brokerUrl; - - @Value("${spring.activemq.user}") - private String user; - - @Value("${spring.activemq.password}") - private String password; - - @Autowired - private ActiveMQConfig activeMQConfig; - - @Test - void testJmsTemplateReturnsJmsTemplate() { - assertThat(activeMQConfig.jmsTemplate().getClass()) - .isEqualTo(JmsTemplate.class); - } - - @Test - void testConnectionFactoryReturnsObject() { - assertThat(activeMQConfig.configureActiveMQConnectionFactory().getClass()) - .isEqualTo(ActiveMQConnectionFactory.class); - } - - @Test - void testConnectionFactoryCallsActiveMQWithBrokerUrl() { - assertThat(activeMQConfig.configureActiveMQConnectionFactory().getBrokerURL()) - .isEqualTo(brokerUrl); - } - - @Test - void testConnectionFactoryCallsActiveMQWithUser() { - assertThat(activeMQConfig.configureActiveMQConnectionFactory().getUserName()) - .isEqualTo(user); - } - - @Test - void testConnectionFactoryCallsActiveMQWithPassword() { - assertThat(activeMQConfig.configureActiveMQConnectionFactory().getPassword()) - .isEqualTo(password); - } - - @Test - void testSSLConnectionFactoryUsedWhenURLContainsSSL() { - org.springframework.test.util.ReflectionTestUtils - .setField(activeMQConfig, "brokerUrl", "tcp+ssl://127.0.0.1:61616"); - - assertThat(activeMQConfig.configureActiveMQConnectionFactory().getClass()).isEqualTo(ActiveMQSslConnectionFactory.class); - } -} diff --git a/src/test/java/com/roboautomator/component/config/swagger/SwaggerConfigTest.java b/src/test/java/com/roboautomator/component/config/swagger/SwaggerConfigTest.java index 8bde366..95949d7 100644 --- a/src/test/java/com/roboautomator/component/config/swagger/SwaggerConfigTest.java +++ b/src/test/java/com/roboautomator/component/config/swagger/SwaggerConfigTest.java @@ -1,13 +1,13 @@ package com.roboautomator.component.config.swagger; -import com.roboautomator.component.config.swagger.SwaggerConfig; +import static com.roboautomator.component.config.swagger.SwaggerConfig.APPLICATION_DESCRIPTION; +import static com.roboautomator.component.config.swagger.SwaggerConfig.APPLICATION_NAME; +import static com.roboautomator.component.config.swagger.SwaggerConfig.APPLICATION_VERSION; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import springfox.documentation.spi.DocumentationType; -import static com.roboautomator.component.config.swagger.SwaggerConfig.*; -import static org.assertj.core.api.Assertions.assertThat; - class SwaggerConfigTest { private SwaggerConfig testConfig; diff --git a/src/test/java/com/roboautomator/component/config/swagger/SwaggerControllerTestIT.java b/src/test/java/com/roboautomator/component/config/swagger/SwaggerControllerTestIT.java index b170e14..948fbe7 100644 --- a/src/test/java/com/roboautomator/component/config/swagger/SwaggerControllerTestIT.java +++ b/src/test/java/com/roboautomator/component/config/swagger/SwaggerControllerTestIT.java @@ -1,24 +1,22 @@ package com.roboautomator.component.config.swagger; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; -import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @EnableAutoConfiguration @@ -37,7 +35,7 @@ void setUp() { @Test void testThatUserIsRedirectedToSwaggerDocsFromRoot() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/")) - .andExpect(status().is3xxRedirection()) - .andExpect(redirectedUrl("/swagger-ui.html")); + .andExpect(status().is3xxRedirection()) + .andExpect(redirectedUrl("/swagger-ui.html")); } } \ No newline at end of file diff --git a/src/test/java/com/roboautomator/component/message/ActiveMQConsumerTest.java b/src/test/java/com/roboautomator/component/message/ActiveMQConsumerTest.java deleted file mode 100644 index 3461bb1..0000000 --- a/src/test/java/com/roboautomator/component/message/ActiveMQConsumerTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.roboautomator.component.message; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.willReturn; -import static org.mockito.BDDMockito.willThrow; -import static org.mockito.Mockito.verify; -import ch.qos.logback.classic.spi.ILoggingEvent; -import com.roboautomator.component.util.AbstractLoggingTest; -import java.util.UUID; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.Session; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentMatchers; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.slf4j.MDC; -import org.springframework.messaging.MessageHeaders; - -@ExtendWith(MockitoExtension.class) -class ActiveMQConsumerTest extends AbstractLoggingTest { - - private static final String UUID_PATTERN = "[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}"; - @Mock - private MessageRepository messageRepository; - - @Mock - private MessageHeaders mockHeaders; - - @Mock - private Message mockMessage; - - @Mock - private Session mockSession; - - @InjectMocks - private ActiveMQConsumer activeMQConsumer; - - @BeforeEach - void setUpLoggingTestConfig() { - setupLoggingAppender(activeMQConsumer); - } - - @Test - void shouldSetMDCCorrelationIdWhenSetInMessageHeader() throws JMSException { - var correlationId = UUID.randomUUID(); - - willReturn(correlationId.toString()) - .given(mockMessage) - .getJMSCorrelationID(); - - activeMQConsumer.handleMessage("Some Message", mockHeaders, mockMessage, mockSession); - - assertThat(MDC.get("correlationId")).isEqualTo(correlationId.toString()); - } - - @Test - void shouldSaveMessageToMessageRepository() { - willReturn(MessageEntity.builder().build()) - .given(messageRepository) - .save(any(MessageEntity.class)); - - activeMQConsumer.handleMessage("Some Message", mockHeaders, mockMessage, mockSession); - - verify(messageRepository).save(ArgumentMatchers.any(MessageEntity.class)); - } - - @Test - void shouldLogErrorWhenFailedToGetJmsCorrelationId() throws JMSException { - willThrow(new JMSException("Failed")) - .given(mockMessage) - .getJMSCorrelationID(); - - activeMQConsumer.handleMessage("Some Message", mockHeaders, mockMessage, mockSession); - - assertThat(getLoggingEventListAppender().list) - .flatExtracting(ILoggingEvent::getFormattedMessage) - .contains("Could not extract JMSCorrelationID, generated new UUID"); - } - - @Test - void shouldGenerateRandomUUIDForCorrelationIdWhenCorrelationIdIsWrong() throws JMSException { - var correlationId = "not-a-uuid"; - - willReturn(correlationId) - .given(mockMessage) - .getJMSCorrelationID(); - - activeMQConsumer.handleMessage("Some Message", mockHeaders, mockMessage, mockSession); - - assertThat(MDC.get("correlationId")).isNotEqualTo(correlationId); - assertThat(MDC.get("correlationId")).matches(UUID_PATTERN); - } - @Test - void shouldGenerateCorrelationIdWhenOneIsNotProvided() { - activeMQConsumer.handleMessage("Some Message", mockHeaders, mockMessage, mockSession); - - assertThat(MDC.get("correlationId")).matches(UUID_PATTERN); - } -} diff --git a/src/test/java/com/roboautomator/component/message/ActiveMQProducerTest.java b/src/test/java/com/roboautomator/component/message/ActiveMQProducerTest.java deleted file mode 100644 index 7c85f31..0000000 --- a/src/test/java/com/roboautomator/component/message/ActiveMQProducerTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.roboautomator.component.message; - -import ch.qos.logback.classic.spi.ILoggingEvent; -import com.roboautomator.component.util.AbstractLoggingTest; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.jms.core.JmsTemplate; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ActiveMQProducer.class) -class ActiveMQProducerTest extends AbstractLoggingTest { - - @MockBean - private JmsTemplate jmsTemplate; - - private ActiveMQProducer activeMQProducer; - - @BeforeEach - void setupProducer() { - activeMQProducer = new ActiveMQProducer(jmsTemplate); - setupLoggingAppender(activeMQProducer); - } - - @Test - void shouldCallJmsTemplateWithMessageToBeSent() { - activeMQProducer.sendMessage("Message"); - - verify(jmsTemplate, times(1)) - .convertAndSend(anyString(), eq("Message"), any()); - } - - @Test - void shouldCallJmsTemplateWithCorrectQueueName() { - activeMQProducer.sendMessage("Any"); - - verify(jmsTemplate, times(1)) - .convertAndSend(eq("testQueue"), anyString(), any()); - } - - @Test - void shouldCallLogWithMessageInformation() { - activeMQProducer.sendMessage("Message"); - - assertThat(getLoggingEventListAppender().list) - .extracting(ILoggingEvent::getFormattedMessage) - .contains("Sending message \"Message\" to the \"testQueue\" queue"); - } -} diff --git a/src/test/java/com/roboautomator/component/message/KafkaConsumerTest.java b/src/test/java/com/roboautomator/component/message/KafkaConsumerTest.java new file mode 100644 index 0000000..d637c73 --- /dev/null +++ b/src/test/java/com/roboautomator/component/message/KafkaConsumerTest.java @@ -0,0 +1,79 @@ +package com.roboautomator.component.message; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; +import static org.mockito.Mockito.verify; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import com.roboautomator.component.util.AbstractLoggingTest; +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.MDC; +import org.springframework.kafka.support.KafkaHeaders; + +@ExtendWith(MockitoExtension.class) +class KafkaConsumerTest extends AbstractLoggingTest { + + @Mock + private MessageRepository messageRepository; + + @Captor + private ArgumentCaptor argumentCaptor; + + private KafkaConsumer kafkaConsumer; + + @BeforeEach + void setup() { + kafkaConsumer = new KafkaConsumer(messageRepository); + setupLoggingAppender(kafkaConsumer); + } + + @Test + void shouldSaveMessageToMessageRepository() { + var payload = "Hello Payload"; + var correlationId = UUID.randomUUID(); + + kafkaConsumer.onMessage(payload, Map.of(KafkaHeaders.CORRELATION_ID, correlationId.toString())); + + verify(messageRepository).save(argumentCaptor.capture()); + var messageEntity = argumentCaptor.getValue(); + assertThat(messageEntity).isNotNull(); + assertThat(messageEntity.getMessage()).isEqualTo(payload); + assertThat(messageEntity.getCorrelationId()).isEqualTo(correlationId); + } + + @Test + void shouldCreateUUIDValueIfReceived() { + var payload = "Hello Payload"; + + kafkaConsumer.onMessage(payload, Collections.emptyMap()); + + verify(messageRepository).save(argumentCaptor.capture()); + + var messageEntity = argumentCaptor.getValue(); + assertThat(messageEntity).isNotNull(); + assertThat(messageEntity.getMessage()).isEqualTo(payload); + assertThat(messageEntity.getCorrelationId()).isNotNull(); + } + + @Test + void shouldLogWhenMessageReceived() { + var payload = "Hello Payload"; + var correlationId = UUID.randomUUID(); + + kafkaConsumer.onMessage(payload, Map.of(KafkaHeaders.CORRELATION_ID, correlationId.toString())); + + assertThat(MDC.get("correlationId")).isEqualTo(correlationId.toString()); + assertThat(getLoggingEventListAppender().list) + .extracting(ILoggingEvent::getMessage, ILoggingEvent::getLevel) + .containsExactly(tuple("New message on topic {}: {}", Level.INFO)); + } +} diff --git a/src/test/java/com/roboautomator/component/message/KafkaProducerTest.java b/src/test/java/com/roboautomator/component/message/KafkaProducerTest.java new file mode 100644 index 0000000..0fa4259 --- /dev/null +++ b/src/test/java/com/roboautomator/component/message/KafkaProducerTest.java @@ -0,0 +1,66 @@ +package com.roboautomator.component.message; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; +import static org.mockito.Mockito.verify; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import com.roboautomator.component.util.AbstractLoggingTest; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.MDC; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.Message; + +@ExtendWith(MockitoExtension.class) +class KafkaProducerTest extends AbstractLoggingTest { + + @Mock + private KafkaTemplate kafkaTemplate; + + @Captor + private ArgumentCaptor> argumentCaptor; + + private KafkaProducer kafkaProducer; + + @BeforeEach + void setup() { + kafkaProducer = new KafkaProducer(kafkaTemplate); + setupLoggingAppender(kafkaProducer); + } + + @Test + void shouldSentMessageToKafka() { + var message = "some message"; + var correlationId = UUID.randomUUID().toString(); + MDC.put("correlationId", correlationId); + + kafkaProducer.send(message); + + verify(kafkaTemplate).send(argumentCaptor.capture()); + var sentMessage = argumentCaptor.getValue(); + assertThat(sentMessage).isNotNull(); + assertThat(sentMessage.getPayload()).isEqualTo(message); + assertThat(sentMessage.getHeaders()).isNotEmpty(); + assertThat(sentMessage.getHeaders().get(KafkaHeaders.MESSAGE_KEY)).isEqualTo(correlationId); + assertThat(sentMessage.getHeaders().get(KafkaHeaders.CORRELATION_ID)).isEqualTo(correlationId); + } + + @Test + void shouldLogWhenMessageReceived() { + var payload = "Hello Payload"; + + kafkaProducer.send(payload); + + assertThat(getLoggingEventListAppender().list) + .extracting(ILoggingEvent::getMessage, ILoggingEvent::getLevel) + .containsExactly(tuple("Sending message to Topic {}: {}", Level.INFO)); + } +} diff --git a/src/test/java/com/roboautomator/component/message/MessageControllerTest.java b/src/test/java/com/roboautomator/component/message/MessageControllerTest.java index 711e0f3..6a9b809 100644 --- a/src/test/java/com/roboautomator/component/message/MessageControllerTest.java +++ b/src/test/java/com/roboautomator/component/message/MessageControllerTest.java @@ -1,8 +1,13 @@ package com.roboautomator.component.message; -import ch.qos.logback.classic.Level; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.BDDMockito.willReturn; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import ch.qos.logback.classic.spi.ILoggingEvent; - import com.roboautomator.component.util.AbstractLoggingTest; import java.util.Optional; import java.util.UUID; @@ -12,23 +17,11 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; - import org.springframework.http.MediaType; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import javax.jms.MessageNotWriteableException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.willDoNothing; -import static org.mockito.BDDMockito.willReturn; -import static org.mockito.BDDMockito.willThrow; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @ExtendWith(SpringExtension.class) @SpringBootTest(classes = MessageController.class) @AutoConfigureMockMvc @@ -40,12 +33,8 @@ class MessageControllerTest extends AbstractLoggingTest { "\"messageBody\": \"Hello Message\"" + "}"; - private static final String ERROR_JSON = "{" + - "\"messageBody\": \"error\"" + - "}"; - @MockBean - private ActiveMQProducer activeMQProducer; + private KafkaProducer kafkaProducer; @MockBean private MessageRepository messageRepository; @@ -54,14 +43,14 @@ class MessageControllerTest extends AbstractLoggingTest { @BeforeEach void setupMockMvc() { - var messageController = new MessageController(messageRepository, activeMQProducer); + var messageController = new MessageController(messageRepository, kafkaProducer); setupLoggingAppender(messageController); mockMvc = MockMvcBuilders.standaloneSetup(messageController).build(); } @Test void shouldCallLogWithMessage() throws Exception { - willDoNothing().given(activeMQProducer).sendMessage(any()); + willDoNothing().given(kafkaProducer).send(any()); mockMvc .perform(post(TEST_ENDPOINT) @@ -70,19 +59,19 @@ void shouldCallLogWithMessage() throws Exception { .andExpect(status().isOk()); assertThat(getLoggingEventListAppender().list) - .extracting(ILoggingEvent::getMessage) - .contains("Received request to send the message \"{}\" to queue"); + .extracting(ILoggingEvent::getMessage) + .contains("Received request to send the message \"{}\" to queue"); - var listOfArgs = new String[]{"Hello Message"}; + var listOfArgs = new String[] {"Hello Message"}; assertThat(getLoggingEventListAppender().list) - .extracting(ILoggingEvent::getArgumentArray) - .contains(listOfArgs); + .extracting(ILoggingEvent::getArgumentArray) + .contains(listOfArgs); } @Test void shouldReturnOkWhenMessageSent() throws Exception { - willDoNothing().given(activeMQProducer).sendMessage(any()); + willDoNothing().given(kafkaProducer).send(any()); mockMvc .perform(post(TEST_ENDPOINT) @@ -93,7 +82,7 @@ void shouldReturnOkWhenMessageSent() throws Exception { @Test void shouldReturnMessageInResponseBody() throws Exception { - willDoNothing().given(activeMQProducer).sendMessage(any()); + willDoNothing().given(kafkaProducer).send(any()); var result = mockMvc .perform(post(TEST_ENDPOINT) @@ -104,57 +93,6 @@ void shouldReturnMessageInResponseBody() throws Exception { assertThat(result.getResponse().getContentAsString()).isEqualTo("Hello Message"); } - @Test - void shouldReturn503WhenMessageNotSent() throws Exception { - willThrow(new org.springframework.jms.MessageNotWriteableException(new MessageNotWriteableException("Error Occurred"))) - .given(activeMQProducer) - .sendMessage("error"); - - mockMvc - .perform(post(TEST_ENDPOINT) - .contentType(MediaType.APPLICATION_JSON) - .content(ERROR_JSON)) - .andExpect(status().is5xxServerError()); - } - - @Test - void shouldReturnErrorMessageWhenMessageHasNotBeenSent() throws Exception { - var exception = new org.springframework.jms.MessageNotWriteableException(new MessageNotWriteableException("Error Occurred")); - willThrow(exception) - .given(activeMQProducer) - .sendMessage("error"); - - var result = mockMvc - .perform(post(TEST_ENDPOINT) - .contentType(MediaType.APPLICATION_JSON) - .content(ERROR_JSON)) - .andReturn(); - - assertThat(result.getResponse().getContentAsString()) - .isEqualTo(exception.toString()); - } - - @Test - void shouldLogAnErrorWhenMessageCanNotBeProcessed() throws Exception { - var exception = new org.springframework.jms.MessageNotWriteableException(new MessageNotWriteableException("Error Occurred")); - willThrow(exception) - .given(activeMQProducer) - .sendMessage("error"); - - mockMvc - .perform(post(TEST_ENDPOINT) - .contentType(MediaType.APPLICATION_JSON) - .content(ERROR_JSON)); - - assertThat(getLoggingEventListAppender().list) - .extracting(ILoggingEvent::getLevel) - .contains(Level.ERROR); - - assertThat(getLoggingEventListAppender().list) - .extracting(ILoggingEvent::getFormattedMessage) - .contains("Could not process the message \"error\", returning"); - } - @Test void shouldReturn404NotFoundIfCorrelationIdNotFound() throws Exception { var correlationId = UUID.randomUUID(); diff --git a/src/test/java/com/roboautomator/component/message/MessageControllerTestIT.java b/src/test/java/com/roboautomator/component/message/MessageControllerTestIT.java index 92b9ce6..12d7c17 100644 --- a/src/test/java/com/roboautomator/component/message/MessageControllerTestIT.java +++ b/src/test/java/com/roboautomator/component/message/MessageControllerTestIT.java @@ -1,11 +1,13 @@ package com.roboautomator.component.message; import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; import com.roboautomator.component.message.MessageEntity; import com.roboautomator.component.message.MessageRepository; import com.roboautomator.component.message.Message; import java.net.URL; import java.util.UUID; +import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpSessionEvent; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -18,8 +20,10 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class MessageControllerTestIT { @@ -80,9 +84,13 @@ void shouldGetMessageFromDatabaseWithCorrectCorrelationId() { var responseBody = template.getForEntity(uri, Message.class).getBody(); System.out.println(responseBody); - assertThat(responseBody).isNotNull(); - assertThat(responseBody.getCorrelationId()).isEqualTo(correlationId); - assertThat(responseBody.getMessageBody()).isEqualTo("Hello World!"); + await() + .atMost(20, TimeUnit.SECONDS) + .untilAsserted(() -> { + assertThat(responseBody).isNotNull(); + assertThat(responseBody.getCorrelationId()).isEqualTo(correlationId); + assertThat(responseBody.getMessageBody()).isEqualTo("Hello World!"); + }); } @Test diff --git a/src/test/java/com/roboautomator/component/message/MessageRepositoryTestIT.java b/src/test/java/com/roboautomator/component/message/MessageRepositoryTestIT.java index 68caec6..5542257 100644 --- a/src/test/java/com/roboautomator/component/message/MessageRepositoryTestIT.java +++ b/src/test/java/com/roboautomator/component/message/MessageRepositoryTestIT.java @@ -10,6 +10,7 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; import javax.persistence.EntityManager; @@ -17,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) diff --git a/src/test/java/com/roboautomator/component/middleware/CorrelationMiddlewareTestIT.java b/src/test/java/com/roboautomator/component/middleware/CorrelationMiddlewareTestIT.java index 70df239..b16ef6c 100644 --- a/src/test/java/com/roboautomator/component/middleware/CorrelationMiddlewareTestIT.java +++ b/src/test/java/com/roboautomator/component/middleware/CorrelationMiddlewareTestIT.java @@ -6,6 +6,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import javax.servlet.http.HttpServletRequest; @@ -16,6 +17,7 @@ import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @SpringBootTest @AutoConfigureMockMvc diff --git a/src/test/java/com/roboautomator/component/middleware/LoggingMiddlewareTestIT.java b/src/test/java/com/roboautomator/component/middleware/LoggingMiddlewareTestIT.java index 2ab2304..a977663 100644 --- a/src/test/java/com/roboautomator/component/middleware/LoggingMiddlewareTestIT.java +++ b/src/test/java/com/roboautomator/component/middleware/LoggingMiddlewareTestIT.java @@ -6,6 +6,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; @@ -15,6 +16,7 @@ import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @SpringBootTest @AutoConfigureMockMvc diff --git a/src/test/java/com/roboautomator/component/patient/PatientControllerTestIT.java b/src/test/java/com/roboautomator/component/patient/PatientControllerTestIT.java index aeeef30..1c52289 100644 --- a/src/test/java/com/roboautomator/component/patient/PatientControllerTestIT.java +++ b/src/test/java/com/roboautomator/component/patient/PatientControllerTestIT.java @@ -15,8 +15,10 @@ import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class PatientControllerTestIT { diff --git a/src/test/java/com/roboautomator/component/patient/PatientRepositoryTestIT.java b/src/test/java/com/roboautomator/component/patient/PatientRepositoryTestIT.java index 3e747a4..549d787 100644 --- a/src/test/java/com/roboautomator/component/patient/PatientRepositoryTestIT.java +++ b/src/test/java/com/roboautomator/component/patient/PatientRepositoryTestIT.java @@ -11,8 +11,10 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; +@ActiveProfiles("test") @ExtendWith(SpringExtension.class) @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) diff --git a/src/test/java/com/roboautomator/component/util/AbstractMockMvcTest.java b/src/test/java/com/roboautomator/component/util/AbstractMockMvcTest.java index fbeb445..24e290c 100644 --- a/src/test/java/com/roboautomator/component/util/AbstractMockMvcTest.java +++ b/src/test/java/com/roboautomator/component/util/AbstractMockMvcTest.java @@ -1,17 +1,17 @@ package com.roboautomator.component.util; -import com.roboautomator.component.message.ActiveMQConsumer; import com.roboautomator.component.message.MessageRepository; import com.roboautomator.component.patient.PatientRepository; import javax.persistence.EntityManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.kafka.core.KafkaTemplate; import org.springframework.test.web.servlet.MockMvc; public abstract class AbstractMockMvcTest { @MockBean - private ActiveMQConsumer activeMQConsumer; + private KafkaTemplate kafkaTemplate; @MockBean private MessageRepository messageRepository; diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml new file mode 100644 index 0000000..1e27b1d --- /dev/null +++ b/src/test/resources/application-test.yml @@ -0,0 +1,39 @@ +server: + port: 8080 +management: + server: + port: 8081 + endpoint: + info: + enabled: false + health: + show-details: always + +spring: + main: + banner-mode: off + kafka: + bootstrap-servers: localhost:9092 + properties: + security.protocol: "PLAINTEXT" + consumer: + group-id: component + auto-offset-reset: earliest + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + value-serializer: org.apache.kafka.common.serialization.StringSerializer + swagger: + endpoint: /swagger-ui.html + jpa: + hibernate: + ddl-auto: create + open-in-view: true + database: postgresql + datasource: + hikari: + connection-timeout: 20000 + maximum-pool-size: 5 + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/java_component + username: postgres + password: postgres diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml deleted file mode 100644 index e47c4ce..0000000 --- a/src/test/resources/application.yml +++ /dev/null @@ -1,67 +0,0 @@ -server: - port: 8080 -management: - server: - port: 8081 - endpoint: - info: - enabled: false - health: - show-details: always - -spring: - main: - banner-mode: off - profiles: - active: "dev" - swagger: - endpoint: /swagger-ui.html - jpa: - hibernate: - ddl-auto: create - open-in-view: true - database: postgresql - datasource: - hikari: - connection-timeout: 20000 - maximum-pool-size: 5 - driver-class-name: org.postgresql.Driver - ---- - -spring: - profiles: dev - activemq: - broker-url: tcp://localhost:61616 - user: admin - password: admin - datasource: - url: jdbc:postgresql://localhost:5432/java_component - username: postgres - password: postgres - ---- - -spring: - profiles: test - activemq: - broker-url: tcp://localhost:61616 - user: admin - password: admin - datasource: - url: jdbc:postgresql://localhost:5432/java_component - username: postgres - password: postgres - ---- - -spring: - profiles: prod - activemq: - broker-url: tcp://activemq:61616 - user: admin - password: admin - datasource: - url: jdbc:postgresql://database:5432/java_component - username: postgres - password: postgres \ No newline at end of file