Skip to content

Commit ad5822d

Browse files
committed
Adding Test Coverage
1 parent 80beabf commit ad5822d

File tree

4 files changed

+288
-2
lines changed

4 files changed

+288
-2
lines changed
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.springframework.kafka.annotation.KafkaListener;
44
import org.springframework.stereotype.Component;
55
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
6+
import org.springframework.util.StringUtils;
67

78
import dev.luismachadoreis.flighttracker.server.ping.infrastructure.websocket.MapUpdatesHandler;
89
import lombok.AllArgsConstructor;
@@ -15,7 +16,7 @@
1516
@Component
1617
@AllArgsConstructor
1718
@ConditionalOnProperty(prefix = "app.ping.websocket", name = "enabled", havingValue = "true")
18-
public class PingKafkaConsumer {
19+
public class PingEventConsumer {
1920

2021
private final MapUpdatesHandler mapUpdatesHandler;
2122

@@ -27,7 +28,11 @@ public class PingKafkaConsumer {
2728
@KafkaListener(topics = "${spring.kafka.topic.ping-created}", groupId = "${spring.kafka.consumer.group-id}")
2829
public void consumePingCreated(String message) {
2930
log.debug("Received ping created event from Kafka: {}", message);
30-
mapUpdatesHandler.sendMessage(message);
31+
if (StringUtils.hasText(message)) {
32+
mapUpdatesHandler.sendMessage(message);
33+
} else {
34+
log.debug("Skipping empty or null message");
35+
}
3136
}
3237

3338
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package dev.luismachadoreis.flighttracker.server.ping.infrastructure.pubsub;
2+
3+
import org.junit.jupiter.api.BeforeEach;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.api.extension.ExtendWith;
6+
import org.mockito.Mock;
7+
import org.mockito.junit.jupiter.MockitoExtension;
8+
9+
import dev.luismachadoreis.flighttracker.server.ping.infrastructure.websocket.MapUpdatesHandler;
10+
11+
import static org.mockito.Mockito.*;
12+
13+
@ExtendWith(MockitoExtension.class)
14+
class PingEventConsumerTest {
15+
16+
@Mock
17+
private MapUpdatesHandler mapUpdatesHandler;
18+
19+
private PingEventConsumer pingKafkaConsumer;
20+
21+
@BeforeEach
22+
void setUp() {
23+
pingKafkaConsumer = new PingEventConsumer(mapUpdatesHandler);
24+
}
25+
26+
@Test
27+
void consumePingCreated_ShouldForwardMessageToWebSocket() {
28+
// Arrange
29+
String message = "{\"id\":\"123\"}";
30+
31+
// Act
32+
pingKafkaConsumer.consumePingCreated(message);
33+
34+
// Assert
35+
verify(mapUpdatesHandler).sendMessage(message);
36+
}
37+
38+
@Test
39+
void consumePingCreated_WhenMessageIsNull_ShouldNotForwardToWebSocket() {
40+
// Act
41+
pingKafkaConsumer.consumePingCreated(null);
42+
43+
// Assert
44+
verify(mapUpdatesHandler, never()).sendMessage(anyString());
45+
}
46+
47+
@Test
48+
void consumePingCreated_WhenMessageIsEmpty_ShouldNotForwardToWebSocket() {
49+
// Act
50+
pingKafkaConsumer.consumePingCreated("");
51+
52+
// Assert
53+
verify(mapUpdatesHandler, never()).sendMessage(anyString());
54+
}
55+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package dev.luismachadoreis.flighttracker.server.ping.infrastructure.pubsub;
2+
3+
import org.junit.jupiter.api.BeforeEach;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.api.extension.ExtendWith;
6+
import org.mockito.Mock;
7+
import org.mockito.junit.jupiter.MockitoExtension;
8+
import org.springframework.kafka.core.KafkaTemplate;
9+
10+
import dev.luismachadoreis.flighttracker.server.common.utils.JsonUtils;
11+
import dev.luismachadoreis.flighttracker.server.ping.application.dto.PingDTO;
12+
import dev.luismachadoreis.flighttracker.server.ping.application.dto.PingMapper;
13+
import dev.luismachadoreis.flighttracker.server.ping.domain.Ping;
14+
import dev.luismachadoreis.flighttracker.server.ping.domain.PingCreatedEvent;
15+
16+
import java.time.Instant;
17+
import java.util.UUID;
18+
19+
import static org.mockito.Mockito.*;
20+
21+
@ExtendWith(MockitoExtension.class)
22+
class PingEventPublisherTest {
23+
24+
@Mock
25+
private PingMapper pingMapper;
26+
27+
@Mock
28+
private KafkaTemplate<String, String> kafkaTemplate;
29+
30+
@Mock
31+
private JsonUtils jsonUtils;
32+
33+
@Mock
34+
private Ping ping;
35+
36+
private PingEventPublisher pingEventPublisher;
37+
private static final String PING_CREATED_TOPIC = "ping-created-topic";
38+
39+
@BeforeEach
40+
void setUp() {
41+
pingEventPublisher = new PingEventPublisher(pingMapper, kafkaTemplate, jsonUtils, PING_CREATED_TOPIC);
42+
}
43+
44+
@Test
45+
void handlePingCreated_ShouldPublishEventToKafka() {
46+
// Arrange
47+
Instant now = Instant.now();
48+
PingCreatedEvent event = new PingCreatedEvent(ping, now);
49+
50+
PingDTO pingDTO = new PingDTO(
51+
UUID.randomUUID(),
52+
new PingDTO.Aircraft("ABC123", "FL123", "US", now, "7700", true, new Integer[]{1, 2}),
53+
new PingDTO.Vector(500.0, 180.0, 0.0),
54+
new PingDTO.Position(10.0, 20.0, 30000.0, 29000.0, false, 1, now),
55+
now
56+
);
57+
58+
String jsonMessage = "{\"id\":\"123\"}";
59+
60+
when(pingMapper.toDTO(ping)).thenReturn(pingDTO);
61+
when(jsonUtils.toJson(pingDTO)).thenReturn(jsonMessage);
62+
63+
// Act
64+
pingEventPublisher.handlePingCreated(event);
65+
66+
// Assert
67+
verify(pingMapper).toDTO(ping);
68+
verify(jsonUtils).toJson(pingDTO);
69+
verify(kafkaTemplate).send(PING_CREATED_TOPIC, jsonMessage);
70+
}
71+
72+
@Test
73+
void handlePingCreated_WhenJsonConversionFails_ShouldNotPublish() {
74+
// Arrange
75+
Instant now = Instant.now();
76+
PingCreatedEvent event = new PingCreatedEvent(ping, now);
77+
78+
PingDTO pingDTO = new PingDTO(
79+
UUID.randomUUID(),
80+
new PingDTO.Aircraft("ABC123", "FL123", "US", now, "7700", true, new Integer[]{1, 2}),
81+
new PingDTO.Vector(500.0, 180.0, 0.0),
82+
new PingDTO.Position(10.0, 20.0, 30000.0, 29000.0, false, 1, now),
83+
now
84+
);
85+
86+
when(pingMapper.toDTO(ping)).thenReturn(pingDTO);
87+
when(jsonUtils.toJson(pingDTO)).thenThrow(new RuntimeException("JSON conversion failed"));
88+
89+
// Act & Assert
90+
try {
91+
pingEventPublisher.handlePingCreated(event);
92+
} catch (RuntimeException e) {
93+
// Expected exception
94+
}
95+
96+
verify(pingMapper).toDTO(ping);
97+
verify(jsonUtils).toJson(pingDTO);
98+
verify(kafkaTemplate, never()).send(anyString(), anyString());
99+
}
100+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package dev.luismachadoreis.flighttracker.server.ping.infrastructure.websocket;
2+
3+
import org.junit.jupiter.api.BeforeEach;
4+
import org.junit.jupiter.api.Test;
5+
import org.junit.jupiter.api.extension.ExtendWith;
6+
import org.mockito.Mock;
7+
import org.mockito.junit.jupiter.MockitoExtension;
8+
import org.springframework.web.socket.TextMessage;
9+
import org.springframework.web.socket.WebSocketSession;
10+
11+
import java.io.IOException;
12+
import java.lang.reflect.Field;
13+
import java.util.Set;
14+
import java.util.concurrent.ExecutorService;
15+
16+
import static org.mockito.ArgumentMatchers.any;
17+
import static org.mockito.Mockito.*;
18+
import static org.mockito.Mockito.lenient;
19+
20+
@ExtendWith(MockitoExtension.class)
21+
class MapUpdatesHandlerTest {
22+
23+
@Mock
24+
private WebSocketSession session1;
25+
26+
@Mock
27+
private WebSocketSession session2;
28+
29+
@Mock
30+
private ExecutorService executor;
31+
32+
private MapUpdatesHandler mapUpdatesHandler;
33+
private static final String TEST_MESSAGE = "test message";
34+
35+
@BeforeEach
36+
void setUp() throws Exception {
37+
mapUpdatesHandler = new MapUpdatesHandler(executor);
38+
39+
// Clear the static sessions set before each test
40+
Field sessionsField = MapUpdatesHandler.class.getDeclaredField("sessions");
41+
sessionsField.setAccessible(true);
42+
Set<WebSocketSession> sessions = (Set<WebSocketSession>) sessionsField.get(null);
43+
sessions.clear();
44+
45+
// Set up lenient mocks for session methods that might be called
46+
lenient().when(session1.isOpen()).thenReturn(true);
47+
lenient().when(session2.isOpen()).thenReturn(true);
48+
}
49+
50+
@Test
51+
void afterConnectionEstablished_ShouldAddSession() throws Exception {
52+
// Act
53+
mapUpdatesHandler.afterConnectionEstablished(session1);
54+
55+
// Send a message to verify the session was added
56+
mapUpdatesHandler.sendMessage(TEST_MESSAGE);
57+
58+
// Assert
59+
verify(executor, times(1)).submit(any(java.lang.Runnable.class));
60+
}
61+
62+
@Test
63+
void afterConnectionClosed_ShouldRemoveSession() throws Exception {
64+
// Arrange
65+
mapUpdatesHandler.afterConnectionEstablished(session1);
66+
67+
// Act
68+
mapUpdatesHandler.afterConnectionClosed(session1, null);
69+
mapUpdatesHandler.sendMessage(TEST_MESSAGE);
70+
71+
// Assert - no messages should be sent since session was removed
72+
verify(executor, never()).submit(any(java.lang.Runnable.class));
73+
}
74+
75+
@Test
76+
void sendMessage_WithNoSessions_ShouldNotSendAnyMessages() throws Exception {
77+
// Act
78+
mapUpdatesHandler.sendMessage(TEST_MESSAGE);
79+
80+
// Assert
81+
verify(executor, never()).submit(any(java.lang.Runnable.class));
82+
verify(session1, never()).sendMessage(any(TextMessage.class));
83+
verify(session2, never()).sendMessage(any(TextMessage.class));
84+
}
85+
86+
@Test
87+
void sendMessage_WithActiveSessions_ShouldSendToAllSessions() throws Exception {
88+
// Arrange
89+
mapUpdatesHandler.afterConnectionEstablished(session1);
90+
mapUpdatesHandler.afterConnectionEstablished(session2);
91+
92+
// Act
93+
mapUpdatesHandler.sendMessage(TEST_MESSAGE);
94+
95+
// Assert - one submit per active session
96+
verify(executor, times(2)).submit(any(java.lang.Runnable.class));
97+
}
98+
99+
@Test
100+
void sendMessage_WithClosedSession_ShouldNotSendToClosedSession() throws Exception {
101+
// Arrange
102+
lenient().when(session1.isOpen()).thenReturn(false);
103+
mapUpdatesHandler.afterConnectionEstablished(session1);
104+
mapUpdatesHandler.afterConnectionEstablished(session2);
105+
mapUpdatesHandler.afterConnectionClosed(session1, null);
106+
107+
// Act
108+
mapUpdatesHandler.sendMessage(TEST_MESSAGE);
109+
110+
// Assert - should only submit for the remaining session
111+
verify(executor, times(1)).submit(any(java.lang.Runnable.class));
112+
}
113+
114+
@Test
115+
void sendMessage_WhenSessionThrowsException_ShouldLogError() throws Exception {
116+
// Arrange
117+
mapUpdatesHandler.afterConnectionEstablished(session1);
118+
lenient().doThrow(new IOException("Test exception")).when(session1).sendMessage(any(TextMessage.class));
119+
120+
// Act
121+
mapUpdatesHandler.sendMessage(TEST_MESSAGE);
122+
123+
// Assert - should still submit the task even if it throws
124+
verify(executor, times(1)).submit(any(java.lang.Runnable.class));
125+
}
126+
}

0 commit comments

Comments
 (0)