Skip to content

Commit 2e51ec0

Browse files
committed
fix: update MicrosoftTeams notifier colors, JSON serialization, and improve event store capacity test
1 parent e9c1abe commit 2e51ec0

2 files changed

Lines changed: 26 additions & 67 deletions

File tree

spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/notify/MicrosoftTeamsNotifier.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import java.util.Map;
2424
import java.util.Objects;
2525

26+
import com.fasterxml.jackson.annotation.JsonInclude;
27+
import com.fasterxml.jackson.annotation.JsonProperty;
2628
import lombok.Builder;
2729
import lombok.Data;
2830
import lombok.Getter;
@@ -62,6 +64,8 @@ public class MicrosoftTeamsNotifier extends AbstractStatusChangeNotifier {
6264

6365
private static final String SOURCE_KEY = "Source";
6466

67+
// For color definitions see:
68+
// https://adaptivecards.microsoft.com/?topic=TextBlock#color
6569
private static final String DEFAULT_THEME_COLOR_EXPRESSION = "#{event.type == 'STATUS_CHANGED' ? (event.statusInfo.status=='UP' ? 'Good' : 'Attention') : 'Accent'}";
6670

6771
private static final String DEFAULT_DEREGISTER_ACTIVITY_SUBTITLE_EXPRESSION = "#{instance.registration.name} with id #{instance.id} has de-registered from Spring Boot Admin";
@@ -302,6 +306,7 @@ public void setStatusActivitySubtitle(String statusActivitySubtitle) {
302306

303307
@Data
304308
@Builder
309+
@JsonInclude(JsonInclude.Include.NON_NULL)
305310
public static class Message {
306311

307312
private final String type = "message";
@@ -313,6 +318,7 @@ public static class Message {
313318

314319
@Data
315320
@Builder
321+
@JsonInclude(JsonInclude.Include.NON_NULL)
316322
public static class Attachment {
317323

318324
private final String contentType = "application/vnd.microsoft.card.adaptive";
@@ -325,9 +331,11 @@ public static class Attachment {
325331

326332
@Data
327333
@Builder
334+
@JsonInclude(JsonInclude.Include.NON_NULL)
328335
public static class AdaptiveCard {
329336

330337
@Builder.Default
338+
@JsonProperty("$schema")
331339
private final String schema = "http://adaptivecards.io/schemas/adaptive-card.json";
332340

333341
private final String type = "AdaptiveCard";
@@ -341,6 +349,7 @@ public static class AdaptiveCard {
341349

342350
@Data
343351
@Builder
352+
@JsonInclude(JsonInclude.Include.NON_NULL)
344353
public static class CardElement {
345354

346355
private final String type;

spring-boot-admin-server/src/test/java/de/codecentric/boot/admin/server/notify/MicrosoftTeamsNotifierTest.java

Lines changed: 17 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,17 @@
1818

1919
import java.net.URI;
2020

21-
import org.json.JSONObject;
2221
import org.junit.jupiter.api.BeforeEach;
2322
import org.junit.jupiter.api.Test;
2423
import org.mockito.ArgumentCaptor;
24+
import org.skyscreamer.jsonassert.JSONAssert;
25+
import org.skyscreamer.jsonassert.JSONCompareMode;
2526
import org.springframework.http.HttpEntity;
2627
import org.springframework.http.MediaType;
2728
import org.springframework.web.client.RestTemplate;
2829
import reactor.core.publisher.Mono;
2930
import reactor.test.StepVerifier;
31+
import tools.jackson.databind.json.JsonMapper;
3032

3133
import de.codecentric.boot.admin.server.domain.entities.Instance;
3234
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
@@ -46,12 +48,6 @@
4648

4749
class MicrosoftTeamsNotifierTest {
4850

49-
private static final String ACCENT = "Accent";
50-
51-
private static final String ATTENTION = "Attention";
52-
53-
private static final String GOOD = "Good";
54-
5551
private static final String APP_NAME = "Test App";
5652

5753
private static final String APP_ID = "TestAppId";
@@ -97,7 +93,7 @@ void test_onClientApplicationDeRegisteredEvent_resolve() {
9793
assertThat(entity.getValue().getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
9894
assertThat(entity.getValue().getBody()).isNotNull();
9995
assertMessage(entity.getValue().getBody(), notifier.getDeRegisteredTitle(),
100-
"Test App with id TestAppId has de-registered from Spring Boot Admin", ACCENT);
96+
"Test App with id TestAppId has de-registered from Spring Boot Admin", "Accent");
10197
}
10298

10399
@Test
@@ -113,7 +109,7 @@ void test_onApplicationRegisteredEvent_resolve() {
113109
assertThat(entity.getValue().getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
114110
assertThat(entity.getValue().getBody()).isNotNull();
115111
assertMessage(entity.getValue().getBody(), notifier.getRegisteredTitle(),
116-
"Test App with id TestAppId has registered with Spring Boot Admin", ACCENT);
112+
"Test App with id TestAppId has registered with Spring Boot Admin", "Accent");
117113
}
118114

119115
@Test
@@ -129,7 +125,7 @@ void test_onApplicationStatusChangedEvent_resolve() {
129125
assertThat(entity.getValue().getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
130126
assertThat(entity.getValue().getBody()).isNotNull();
131127
assertMessage(entity.getValue().getBody(), notifier.getStatusChangedTitle(),
132-
"Test App with id TestAppId changed status from UNKNOWN to UP", GOOD);
128+
"Test App with id TestAppId changed status from UNKNOWN to UP", "Good");
133129
}
134130

135131
@Test
@@ -150,7 +146,7 @@ void test_getDeregisteredMessageForAppReturns_correctContent() {
150146
notifier.createEvaluationContext(new InstanceDeregisteredEvent(instance.getId(), 1L), instance));
151147

152148
assertMessage(message, notifier.getDeRegisteredTitle(),
153-
"Test App with id TestAppId has de-registered from Spring Boot Admin", ACCENT);
149+
"Test App with id TestAppId has de-registered from Spring Boot Admin", "Accent");
154150
}
155151

156152
@Test
@@ -159,7 +155,7 @@ void test_getRegisteredMessageForAppReturns_correctContent() {
159155
notifier.createEvaluationContext(new InstanceDeregisteredEvent(instance.getId(), 1L), instance));
160156

161157
assertMessage(message, notifier.getRegisteredTitle(),
162-
"Test App with id TestAppId has registered with Spring Boot Admin", ACCENT);
158+
"Test App with id TestAppId has registered with Spring Boot Admin", "Accent");
163159
}
164160

165161
@Test
@@ -168,7 +164,7 @@ void test_getStatusChangedMessageForAppReturns_correctContent() {
168164
new InstanceStatusChangedEvent(instance.getId(), 1L, StatusInfo.ofDown()), instance));
169165

170166
assertMessage(message, notifier.getStatusChangedTitle(),
171-
"Test App with id TestAppId changed status from UNKNOWN to DOWN", ATTENTION);
167+
"Test App with id TestAppId changed status from UNKNOWN to DOWN", "Attention");
172168
}
173169

174170
@Test
@@ -179,7 +175,7 @@ void test_getStatusChangedMessageForAppReturns_UP_to_DOWN() {
179175
new InstanceStatusChangedEvent(instance.getId(), 1L, StatusInfo.ofDown()), instance));
180176

181177
assertMessage(message, notifier.getStatusChangedTitle(),
182-
"Test App with id TestAppId changed status from UP to DOWN", ATTENTION);
178+
"Test App with id TestAppId changed status from UP to DOWN", "Attention");
183179
}
184180

185181
@Test
@@ -230,13 +226,15 @@ void test_messageSerializesToExpectedJsonStructure() throws Exception {
230226
Message message = notifier.getStatusChangedMessage(upInstance, notifier.createEvaluationContext(
231227
new InstanceStatusChangedEvent(upInstance.getId(), 1L, StatusInfo.ofUp()), upInstance));
232228

233-
// Build expected JSON structure using JSONObject with actual values
234-
JSONObject expectedJson = new JSONObject("""
229+
JsonMapper mapper = JsonMapper.builder().build();
230+
String actual = mapper.writeValueAsString(message);
231+
232+
// Build expected JSON structure
233+
String expectedJson = """
235234
{
236235
"type": "message",
237236
"attachments": [{
238237
"contentType": "application/vnd.microsoft.card.adaptive",
239-
"contentUrl": null,
240238
"content": {
241239
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
242240
"type": "AdaptiveCard",
@@ -273,57 +271,9 @@ void test_messageSerializesToExpectedJsonStructure() throws Exception {
273271
}
274272
}]
275273
}
276-
""");
277-
278-
// Verify message structure matches expected format
279-
assertThat(message.getType()).isEqualTo(expectedJson.getString("type"));
280-
281-
assertThat(message.getAttachments()).hasSize(1);
282-
var attachment = message.getAttachments().get(0);
283-
assertThat(attachment.getContentType())
284-
.isEqualTo(expectedJson.getJSONArray("attachments").getJSONObject(0).getString("contentType"));
285-
286-
var content = attachment.getContent();
287-
var expectedContent = expectedJson.getJSONArray("attachments").getJSONObject(0).getJSONObject("content");
288-
assertThat(content.getSchema()).isEqualTo(expectedContent.getString("$schema"));
289-
assertThat(content.getType()).isEqualTo(expectedContent.getString("type"));
290-
assertThat(content.getVersion()).isEqualTo(expectedContent.getString("version"));
291-
292-
// Verify body structure and content
293-
var body = content.getBody();
294-
var expectedBody = expectedContent.getJSONArray("body");
295-
assertThat(body).hasSize(expectedBody.length());
296-
297-
// Verify Title TextBlock
298-
assertThat(body.get(0).getType()).isEqualTo("TextBlock");
299-
assertThat(body.get(0).getText()).isEqualTo("Status Changed");
300-
assertThat(body.get(0).getSize()).isEqualTo("Large");
301-
assertThat(body.get(0).getWeight()).isEqualTo("Bolder");
302-
assertThat(body.get(0).getColor()).isEqualTo("Good");
274+
""";
303275

304-
// Verify Service Name TextBlock
305-
assertThat(body.get(1).getType()).isEqualTo("TextBlock");
306-
assertThat(body.get(1).getText()).isEqualTo(APP_NAME);
307-
assertThat(body.get(1).getSize()).isEqualTo("Medium");
308-
assertThat(body.get(1).getWeight()).isEqualTo("Bolder");
309-
310-
// Verify Activity Subtitle TextBlock
311-
assertThat(body.get(2).getType()).isEqualTo("TextBlock");
312-
assertThat(body.get(2).getText()).isEqualTo("Test App with id TestAppId changed status from UNKNOWN to UP");
313-
assertThat(body.get(2).getWrap()).isTrue();
314-
315-
// Verify FactSet
316-
assertThat(body.get(3).getType()).isEqualTo("FactSet");
317-
assertThat(body.get(3).getFacts()).hasSize(4); // Source is omitted because it's
318-
// null
319-
assertThat(body.get(3).getFacts().get(0).title()).isEqualTo("Status");
320-
assertThat(body.get(3).getFacts().get(0).value()).isEqualTo("UP");
321-
assertThat(body.get(3).getFacts().get(1).title()).isEqualTo("Service URL");
322-
assertThat(body.get(3).getFacts().get(1).value()).isEqualTo(SERVICE_URL);
323-
assertThat(body.get(3).getFacts().get(2).title()).isEqualTo("Health URL");
324-
assertThat(body.get(3).getFacts().get(2).value()).isEqualTo(HEALTH_URL);
325-
assertThat(body.get(3).getFacts().get(3).title()).isEqualTo("Management URL");
326-
assertThat(body.get(3).getFacts().get(3).value()).isEqualTo(MANAGEMENT_URL);
276+
JSONAssert.assertEquals(expectedJson, actual, JSONCompareMode.NON_EXTENSIBLE);
327277
}
328278

329279
private String getActivitySubtitleFromMessage(Message message) {

0 commit comments

Comments
 (0)