Skip to content

Commit 227f6c4

Browse files
authored
Add WebhookControllerWithInterceptorTest (#5)
* Add WebhookControllerWithInterceptorTest * Fix checkstyle WebhookControllerWithInterceptorTest * Fix test names WebhookControllerWithInterceptorTest * Fix test for WebhookController
1 parent 91e3767 commit 227f6c4

File tree

5 files changed

+129
-1
lines changed

5 files changed

+129
-1
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@
109109
<artifactId>spring-boot-starter-test</artifactId>
110110
<scope>test</scope>
111111
</dependency>
112+
<dependency>
113+
<groupId>org.springframework.cloud</groupId>
114+
<artifactId>spring-cloud-contract-wiremock</artifactId>
115+
<version>4.1.4</version>
116+
<scope>test</scope>
117+
</dependency>
112118
</dependencies>
113119

114120
<build>

src/main/java/dev/vality/alerting/tg/bot/controller/WebhookController.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import dev.vality.alerting.tg.bot.config.properties.AlertmanagerWebhookProperties;
55
import dev.vality.alerting.tg.bot.model.Webhook;
6+
import dev.vality.alerting.tg.bot.service.AlertBot;
67
import lombok.RequiredArgsConstructor;
78
import lombok.extern.slf4j.Slf4j;
89
import org.springframework.web.bind.annotation.PostMapping;
@@ -22,14 +23,15 @@
2223
public class WebhookController {
2324
private final AlertmanagerWebhookProperties alertmanagerWebhookProperties;
2425
private final ObjectMapper objectMapper;
25-
public static final String FIRING = "firing";
26+
private final AlertBot alertBot;
2627

2728
@PostMapping(value = "/webhook", consumes = MediaType.APPLICATION_JSON_VALUE)
2829
public ResponseEntity<String> processWebhook(HttpServletRequest servletRequest) {
2930
try {
3031
var webhookBody = servletRequest.getReader().lines().collect(Collectors.joining(" "));
3132
log.info("Received webhook from alertmanager: {}", webhookBody);
3233
var webhook = objectMapper.readValue(webhookBody, Webhook.class);
34+
alertBot.sendAlertMessage(webhook);
3335
} catch (Exception e) {
3436
log.error("Unexpected error during webhook parsing:", e);
3537
return ResponseEntity.internalServerError().build();

src/main/java/dev/vality/alerting/tg/bot/model/Webhook.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package dev.vality.alerting.tg.bot.model;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
34
import lombok.Data;
5+
import lombok.NoArgsConstructor;
46

57
import java.util.List;
68
import java.util.Map;
@@ -9,13 +11,17 @@
911
* Alertmanager webhook body
1012
*/
1113
@Data
14+
@NoArgsConstructor
15+
@JsonIgnoreProperties(ignoreUnknown = true)
1216
public class Webhook {
1317

1418
private String status;
1519
private String receiver;
1620
private List<Alert> alerts;
1721

1822
@Data
23+
@NoArgsConstructor
24+
@JsonIgnoreProperties(ignoreUnknown = true)
1925
public static class Alert {
2026

2127
private String status;

src/main/java/dev/vality/alerting/tg/bot/service/AlertBot.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.vality.alerting.tg.bot.service;
22

33
import dev.vality.alerting.tg.bot.config.properties.AlertBotProperties;
4+
import dev.vality.alerting.tg.bot.model.Webhook;
45
import lombok.RequiredArgsConstructor;
56
import lombok.extern.slf4j.Slf4j;
67
import org.springframework.scheduling.annotation.EnableScheduling;
@@ -68,6 +69,11 @@ public void onUpdateReceived(Update update) {
6869
}
6970
}
7071

72+
public void sendAlertMessage(Webhook webhook) {
73+
sendResponse(properties.getChatId(), properties.getTopics().getCommands(), webhook.getAlerts().toString(),
74+
null);
75+
}
76+
7177
public void sendScheduledMetrics() {
7278
send5xxErrorsMetrics(properties.getChatId());
7379
sendFailedMachinesMetrics(properties.getChatId());
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package dev.vality.alerting.tg.bot;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import dev.vality.alerting.tg.bot.config.AlertBotConfig;
5+
import dev.vality.alerting.tg.bot.config.properties.AlertmanagerWebhookProperties;
6+
import dev.vality.alerting.tg.bot.controller.WebhookController;
7+
import dev.vality.alerting.tg.bot.model.Webhook;
8+
import dev.vality.alerting.tg.bot.service.AlertBot;
9+
import lombok.val;
10+
import org.junit.jupiter.api.Test;
11+
import org.mockito.ArgumentCaptor;
12+
import org.springframework.boot.test.context.SpringBootTest;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.mock.web.MockHttpServletRequest;
15+
import org.springframework.test.context.TestPropertySource;
16+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
17+
18+
import java.nio.charset.StandardCharsets;
19+
20+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
21+
import static org.mockito.Mockito.verify;
22+
23+
@SpringBootTest
24+
@TestPropertySource(properties = {
25+
"spring.mvc.pathmatch.matching-strategy=ant_path_matcher",
26+
"bot.token=test",
27+
"bot.name=vality_alerting_bot",
28+
"bot.chatId=1",
29+
"bot.topics.commands=1",
30+
"bot.topics.errors5xx=2",
31+
"bot.topics.altpay-conversion=3",
32+
"bot.topics.failed-machines=4",
33+
"bot.topics.pending-payments=5"
34+
})
35+
public class WebhookControllerTest {
36+
37+
@MockitoBean
38+
AlertmanagerWebhookProperties webhookProperties;
39+
40+
@MockitoBean
41+
AlertBot alertBot;
42+
43+
@MockitoBean
44+
AlertBotConfig alertBotConfig;
45+
46+
String webhookJson = """
47+
{
48+
"status": "firing",
49+
"receiver": "telegram",
50+
"alerts": [
51+
{
52+
"status": "firing",
53+
"labels": {
54+
"alertname": "Errors5xxHigh",
55+
"severity": "critical",
56+
"job": "payments",
57+
"namespace": "prod",
58+
"service": "payments-api",
59+
"instance": "payments-api-1",
60+
"pod": "payments-api-1-abc123"
61+
},
62+
"annotations": {
63+
"summary": "HTTP 5xx rate is too high",
64+
"description": "Payments API is returning >5% 5xx responses for 5m",
65+
"runbook_url": "https://runbook.company/alerts/errors5xx"
66+
}
67+
},
68+
{
69+
"status": "resolved",
70+
"labels": {
71+
"alertname": "AltpayConversionLow",
72+
"severity": "warning",
73+
"job": "altpay",
74+
"namespace": "prod",
75+
"service": "altpay-conversion",
76+
"pod": "altpay-0-xzy987"
77+
},
78+
"annotations": {
79+
"summary": "Altpay conversion dropped",
80+
"description": "Altpay conversion < 2% in last 10m"
81+
}
82+
}
83+
]
84+
}
85+
""";
86+
87+
@Test
88+
public void sendTgMessageTest() {
89+
ObjectMapper objectMapper = new ObjectMapper();
90+
WebhookController webhookController = new WebhookController(webhookProperties, objectMapper, alertBot);
91+
92+
MockHttpServletRequest req = new MockHttpServletRequest();
93+
req.setMethod("POST");
94+
req.setRequestURI("/alertmanager/webhook");
95+
req.setContentType(MediaType.APPLICATION_JSON_VALUE);
96+
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
97+
req.setContent(webhookJson.getBytes(StandardCharsets.UTF_8));
98+
99+
val response = webhookController.processWebhook(req);
100+
assertThat(response.getStatusCode().value()).isEqualTo(200);
101+
102+
ArgumentCaptor<Webhook> webhookCaptor = ArgumentCaptor.forClass(Webhook.class);
103+
verify(alertBot).sendAlertMessage(webhookCaptor.capture());
104+
Webhook passed = webhookCaptor.getValue();
105+
assertThat(passed).isNotNull();
106+
assertThat(passed.getAlerts()).isNotNull();
107+
}
108+
}

0 commit comments

Comments
 (0)