Skip to content

Commit 4d7d312

Browse files
riky2124SteKoehzpz
authored
fix(#4164): client reg with spring boot configured to use snake case (#4208)
Co-authored-by: Stephan Köninger <[email protected]> Co-authored-by: Timo <[email protected]>
1 parent 6dbbd84 commit 4d7d312

File tree

5 files changed

+98
-78
lines changed

5 files changed

+98
-78
lines changed

spring-boot-admin-client/src/test/java/de/codecentric/boot/admin/client/AbstractClientApplicationTest.java

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
import java.net.InetAddress;
2020
import java.net.UnknownHostException;
21+
import java.util.Arrays;
2122
import java.util.concurrent.CountDownLatch;
23+
import java.util.stream.Stream;
2224

2325
import com.github.tomakehurst.wiremock.WireMockServer;
2426
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
@@ -27,9 +29,12 @@
2729
import org.junit.jupiter.api.AfterEach;
2830
import org.junit.jupiter.api.Test;
2931
import org.springframework.beans.factory.annotation.Autowired;
32+
import org.springframework.boot.SpringApplication;
3033
import org.springframework.boot.SpringBootConfiguration;
34+
import org.springframework.boot.WebApplicationType;
3135
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
3236
import org.springframework.boot.context.event.ApplicationReadyEvent;
37+
import org.springframework.context.ConfigurableApplicationContext;
3338
import org.springframework.context.event.EventListener;
3439

3540
import de.codecentric.boot.admin.client.registration.ApplicationRegistrator;
@@ -45,11 +50,21 @@
4550

4651
public abstract class AbstractClientApplicationTest {
4752

48-
public WireMockServer wireMock = new WireMockServer(options().dynamicPort().notifier(new ConsoleNotifier(true)));
53+
private final WireMockServer wireMock = new WireMockServer(
54+
options().dynamicPort().notifier(new ConsoleNotifier(true)));
55+
56+
private SpringApplication application;
57+
58+
private ConfigurableApplicationContext instance;
4959

5060
private static final CountDownLatch cdl = new CountDownLatch(1);
5161

52-
public void setUp() throws Exception {
62+
protected void setUp(WebApplicationType type) throws Exception {
63+
setUpWiremock();
64+
setUpApplication(type);
65+
}
66+
67+
private void setUpWiremock() {
5368
wireMock.start();
5469
ResponseDefinitionBuilder response = created().withHeader("Content-Type", "application/json")
5570
.withHeader("Connection", "close")
@@ -58,13 +73,33 @@ public void setUp() throws Exception {
5873
wireMock.stubFor(post(urlEqualTo("/instances")).willReturn(response));
5974
}
6075

76+
private void setUpApplication(WebApplicationType type) {
77+
application = new SpringApplication(TestClientApplication.class);
78+
application.setWebApplicationType(type);
79+
}
80+
81+
private void setUpApplicationContext(String... additionalArgs) {
82+
Stream<String> defaultArgs = Stream.of("--spring.application.name=Test-Client", "--server.port=0",
83+
"--management.endpoints.web.base-path=/mgmt", "--endpoints.health.enabled=true",
84+
"--spring.boot.admin.client.url=" + wireMock.url("/"));
85+
86+
String[] args = Stream.concat(defaultArgs, Arrays.stream(additionalArgs)).toArray(String[]::new);
87+
88+
this.instance = application.run(args);
89+
}
90+
6191
@AfterEach
6292
void tearDown() {
6393
wireMock.stop();
94+
if (instance != null) {
95+
instance.close();
96+
}
6497
}
6598

6699
@Test
67100
public void test_context() throws InterruptedException, UnknownHostException {
101+
setUpApplicationContext();
102+
68103
cdl.await();
69104
Thread.sleep(2500);
70105
String hostName = InetAddress.getLocalHost().getCanonicalHostName();
@@ -81,9 +116,33 @@ public void test_context() throws InterruptedException, UnknownHostException {
81116
wireMock.verify(request);
82117
}
83118

84-
protected abstract int getServerPort();
119+
@Test
120+
public void test_context_with_snake_case() throws InterruptedException, UnknownHostException {
121+
setUpApplicationContext("--spring.jackson.property-naming-strategy=SNAKE_CASE");
85122

86-
protected abstract int getManagementPort();
123+
cdl.await();
124+
Thread.sleep(2500);
125+
String hostName = InetAddress.getLocalHost().getCanonicalHostName();
126+
String serviceHost = "http://" + hostName + ":" + getServerPort();
127+
String managementHost = "http://" + hostName + ":" + getManagementPort();
128+
RequestPatternBuilder request = postRequestedFor(urlEqualTo("/instances"));
129+
request.withHeader("Content-Type", equalTo("application/json"))
130+
.withRequestBody(matchingJsonPath("$.name", equalTo("Test-Client")))
131+
.withRequestBody(matchingJsonPath("$.health_url", equalTo(managementHost + "/mgmt/health")))
132+
.withRequestBody(matchingJsonPath("$.management_url", equalTo(managementHost + "/mgmt")))
133+
.withRequestBody(matchingJsonPath("$.service_url", equalTo(serviceHost + "/")))
134+
.withRequestBody(matchingJsonPath("$.metadata.startup", matching(".+")));
135+
136+
wireMock.verify(request);
137+
}
138+
139+
private int getServerPort() {
140+
return instance.getEnvironment().getProperty("local.server.port", Integer.class, 0);
141+
}
142+
143+
private int getManagementPort() {
144+
return instance.getEnvironment().getProperty("local.management.port", Integer.class, 0);
145+
}
87146

88147
@SpringBootConfiguration
89148
@EnableAutoConfiguration

spring-boot-admin-client/src/test/java/de/codecentric/boot/admin/client/ClientReactiveApplicationTest.java

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,14 @@
1616

1717
package de.codecentric.boot.admin.client;
1818

19-
import org.junit.jupiter.api.AfterEach;
2019
import org.junit.jupiter.api.BeforeEach;
21-
import org.springframework.boot.SpringApplication;
2220
import org.springframework.boot.WebApplicationType;
23-
import org.springframework.context.ConfigurableApplicationContext;
2421

2522
public class ClientReactiveApplicationTest extends AbstractClientApplicationTest {
2623

27-
private ConfigurableApplicationContext instance;
28-
2924
@BeforeEach
30-
@Override
3125
public void setUp() throws Exception {
32-
super.setUp();
33-
34-
SpringApplication application = new SpringApplication(TestClientApplication.class);
35-
application.setWebApplicationType(WebApplicationType.REACTIVE);
36-
instance = application.run("--spring.application.name=Test-Client", "--server.port=0",
37-
"--management.endpoints.web.base-path=/mgmt", "--endpoints.health.enabled=true",
38-
"--spring.boot.admin.client.url=" + wireMock.url("/"));
39-
}
40-
41-
@AfterEach
42-
public void shutdown() {
43-
instance.close();
44-
}
45-
46-
@Override
47-
protected int getServerPort() {
48-
return instance.getEnvironment().getProperty("local.server.port", Integer.class, 0);
49-
}
50-
51-
@Override
52-
protected int getManagementPort() {
53-
return instance.getEnvironment().getProperty("local.management.port", Integer.class, 0);
54-
26+
super.setUp(WebApplicationType.REACTIVE);
5527
}
5628

5729
}

spring-boot-admin-client/src/test/java/de/codecentric/boot/admin/client/ClientServletApplicationTest.java

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,14 @@
1616

1717
package de.codecentric.boot.admin.client;
1818

19-
import org.junit.jupiter.api.AfterEach;
2019
import org.junit.jupiter.api.BeforeEach;
21-
import org.springframework.boot.SpringApplication;
2220
import org.springframework.boot.WebApplicationType;
23-
import org.springframework.context.ConfigurableApplicationContext;
2421

2522
public class ClientServletApplicationTest extends AbstractClientApplicationTest {
2623

27-
private ConfigurableApplicationContext instance;
28-
2924
@BeforeEach
30-
@Override
3125
public void setUp() throws Exception {
32-
super.setUp();
33-
34-
SpringApplication application = new SpringApplication(TestClientApplication.class);
35-
application.setWebApplicationType(WebApplicationType.SERVLET);
36-
instance = application.run("--spring.application.name=Test-Client", "--server.port=0",
37-
"--management.endpoints.web.base-path=/mgmt", "--endpoints.health.enabled=true",
38-
"--spring.boot.admin.client.url=" + wireMock.url("/"));
39-
}
40-
41-
@AfterEach
42-
public void shutdown() {
43-
instance.close();
44-
}
45-
46-
@Override
47-
protected int getServerPort() {
48-
return instance.getEnvironment().getProperty("local.server.port", Integer.class, 0);
49-
}
50-
51-
@Override
52-
protected int getManagementPort() {
53-
return instance.getEnvironment().getProperty("local.management.port", Integer.class, 0);
54-
26+
super.setUp(WebApplicationType.SERVLET);
5527
}
5628

5729
}

spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/utils/jackson/RegistrationDeserializer.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,16 @@ public Registration deserialize(JsonParser p, DeserializationContext ctxt) throw
4040
JsonNode node = p.readValueAsTree();
4141
Registration.Builder builder = Registration.builder();
4242

43-
if (node.hasNonNull("name")) {
44-
builder.name(node.get("name").asText());
45-
}
43+
builder.name(firstNonNullAsText(node, "name"));
44+
4645
if (node.hasNonNull("url")) {
47-
String url = node.get("url").asText();
46+
String url = firstNonNullAsText(node, "url");
4847
builder.healthUrl(url.replaceFirst("/+$", "") + "/health").managementUrl(url);
4948
}
5049
else {
51-
if (node.hasNonNull("healthUrl")) {
52-
builder.healthUrl(node.get("healthUrl").asText());
53-
}
54-
if (node.hasNonNull("managementUrl")) {
55-
builder.managementUrl(node.get("managementUrl").asText());
56-
}
57-
if (node.hasNonNull("serviceUrl")) {
58-
builder.serviceUrl(node.get("serviceUrl").asText());
59-
}
50+
builder.healthUrl(firstNonNullAsText(node, "healthUrl", "health_url"));
51+
builder.managementUrl(firstNonNullAsText(node, "managementUrl", "management_url"));
52+
builder.serviceUrl(firstNonNullAsText(node, "serviceUrl", "service_url"));
6053
}
6154

6255
if (node.has("metadata")) {
@@ -67,11 +60,18 @@ public Registration deserialize(JsonParser p, DeserializationContext ctxt) throw
6760
}
6861
}
6962

70-
if (node.hasNonNull("source")) {
71-
builder.source(node.get("source").asText());
72-
}
63+
builder.source(firstNonNullAsText(node, "source"));
7364

7465
return builder.build();
7566
}
7667

68+
private String firstNonNullAsText(JsonNode node, String... fieldNames) {
69+
for (String fieldName : fieldNames) {
70+
if (node.hasNonNull(fieldName)) {
71+
return node.get(fieldName).asText();
72+
}
73+
}
74+
return null;
75+
}
76+
7777
}

spring-boot-admin-server/src/test/java/de/codecentric/boot/admin/server/utils/jackson/RegistrationDeserializerTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,21 @@ public void test_sanitize_metadata() throws JsonProcessingException {
123123
assertThat(json).contains("humptydumpty");
124124
}
125125

126+
@Test
127+
void test_snake_case() throws Exception {
128+
String json = new JSONObject().put("name", "test")
129+
.put("management_url", "http://test")
130+
.put("health_url", "http://health")
131+
.put("service_url", "http://service")
132+
.put("metadata", new JSONObject().put("labels", "foo,bar"))
133+
.toString();
134+
Registration value = objectMapper.readValue(json, Registration.class);
135+
assertThat(value.getName()).isEqualTo("test");
136+
assertThat(value.getManagementUrl()).isEqualTo("http://test");
137+
assertThat(value.getHealthUrl()).isEqualTo("http://health");
138+
assertThat(value.getServiceUrl()).isEqualTo("http://service");
139+
assertThat(value.getMetadata()).isEqualTo(singletonMap("labels", "foo,bar"));
140+
141+
}
142+
126143
}

0 commit comments

Comments
 (0)