Skip to content

Commit 8979844

Browse files
manusaclaude
andauthored
fix(spring-boot): fix backward compatibility logic for health probes property
- Fix backward compatibility check to use full semver string instead of just major version - The old property (management.health.probes.enabled) now correctly works for Spring Boot < 2.3 - Add comprehensive tests for backward compatibility across Spring Boot versions - Add missing @test annotation in SpringBoot3 test class - Fix indentation and remove dead code comment - Add trailing newline to application.properties Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 22b48e3 commit 8979844

File tree

5 files changed

+269
-20
lines changed

5 files changed

+269
-20
lines changed

gradle-plugin/it/src/it/spring-boot-managementhealthprobes/src/main/resources/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# Red Hat, Inc. - initial API and implementation
1313
#
1414

15-
management.endpoint.health.probes.enabled=true
15+
management.endpoint.health.probes.enabled=true

jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/SemanticVersionUtil.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,24 @@ public class SemanticVersionUtil {
1919
private SemanticVersionUtil() { }
2020

2121
public static boolean isVersionAtLeast(int majorVersion, int minorVersion, String version) {
22+
return isVersionAtLeast(majorVersion, minorVersion, 0, version);
23+
}
24+
25+
public static boolean isVersionAtLeast(int majorVersion, int minorVersion, int patchVersion, String version) {
2226
if (StringUtils.isNotBlank(version) && version.contains(".")) {
2327
final String[] versionParts = version.split("\\.");
2428
final int parsedMajorVersion = parseInt(versionParts[0]);
2529
if (parsedMajorVersion > majorVersion) {
2630
return true;
2731
} else if (parsedMajorVersion == majorVersion) {
28-
return parseInt(versionParts[1]) >= minorVersion;
32+
final int parsedMinorVersion = parseInt(versionParts[1]);
33+
if (parsedMinorVersion > minorVersion) {
34+
return true;
35+
} else if (parsedMinorVersion == minorVersion) {
36+
// If no patch version in the string, treat as .0
37+
final int parsedPatchVersion = versionParts.length > 2 ? parseInt(versionParts[2]) : 0;
38+
return parsedPatchVersion >= patchVersion;
39+
}
2940
}
3041
}
3142
return false;

jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/SpringBootConfiguration.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,8 @@ public static SpringBootConfiguration from(JavaProject project) {
4444
final Properties properties = SpringBootUtil.getSpringBootApplicationProperties(
4545
SpringBootUtil.getSpringBootActiveProfile(project),
4646
JKubeProjectUtil.getClassLoader(project));
47-
final int majorVersion = SpringBootUtil.getSpringBootVersion(project)
48-
.map(semVer -> {
49-
try {
50-
return Integer.parseInt(semVer.substring(0, semVer.indexOf('.')));
51-
} catch (Exception e) {
52-
return null;
53-
}
54-
})
55-
// Defaults to Spring 1
56-
.orElse(1);
47+
final String springBootVersion = SpringBootUtil.getSpringBootVersion(project).orElse("1.0.0");
48+
final int majorVersion = parseMajorVersion(springBootVersion);
5749
final SpringBootConfiguration.SpringBootConfigurationBuilder configBuilder = SpringBootConfiguration.builder();
5850
// Spring Boot 1 and common properties
5951
final String serverKeystore = properties.getProperty("server.ssl.key-store");
@@ -96,12 +88,22 @@ public static SpringBootConfiguration from(JavaProject project) {
9688
.servletPath(properties.getProperty("spring.mvc.servlet.path"))
9789
.managementContextPath(properties.getProperty("management.server.base-path"));
9890
}
99-
// keep backward compatibility with spring-boot < 2.3.x
100-
// prioritize the new property in case both are set
101-
// if (majorVersion < 3 && minorVersion < 4 && properties.getProperty("management.endpoint.health.probes.enabled") == null) {
102-
if (SemanticVersionUtil.isVersionAtLeast(2, 3, Integer.toString(majorVersion)) && properties.getProperty("management.endpoint.health.probes.enabled") == null) {
103-
configBuilder.managementHealthProbesEnabled(Boolean.parseBoolean(properties.getProperty("management.health.probes.enabled")));
91+
// Spring Boot 2.3.0 and 2.3.1 used property: management.health.probes.enabled
92+
// Spring Boot 2.3.2+ renamed it to: management.endpoint.health.probes.enabled
93+
// For backward compatibility, if the new property is not set and version is < 2.3.2, use the old property
94+
if (properties.getProperty("management.endpoint.health.probes.enabled") == null
95+
&& !SemanticVersionUtil.isVersionAtLeast(2, 3, 2, springBootVersion)) {
96+
configBuilder.managementHealthProbesEnabled(Boolean.parseBoolean(properties.getProperty("management.health.probes.enabled")));
10497
}
10598
return configBuilder.build();
10699
}
100+
101+
private static int parseMajorVersion(String semVer) {
102+
try {
103+
return Integer.parseInt(semVer.substring(0, semVer.indexOf('.')));
104+
} catch (Exception e) {
105+
// Defaults to Spring Boot 1
106+
return 1;
107+
}
108+
}
107109
}

jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/SemanticVersionUtilTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,51 @@ public static Stream<Arguments> versionTestData() {
4545
);
4646
}
4747

48+
@DisplayName("Major-Minor-Patch version tests")
49+
@ParameterizedTest(name = "{0}")
50+
@MethodSource("patchVersionTestData")
51+
void patchVersionTest(String testDesc, int majorVersion, int minorVersion, int patchVersion, String version, boolean expected) {
52+
assertThat(isVersionAtLeast(majorVersion, minorVersion, patchVersion, version)).isEqualTo(expected);
53+
}
54+
55+
public static Stream<Arguments> patchVersionTestData() {
56+
return Stream.of(
57+
// Major version comparisons
58+
Arguments.arguments("With larger major version should return false", 3, 0, 0, "2.3.2", false),
59+
Arguments.arguments("With smaller major version should return true", 1, 0, 0, "2.3.2", true),
60+
// Minor version comparisons (same major)
61+
Arguments.arguments("With same major and larger minor version should return false", 2, 4, 0, "2.3.2", false),
62+
Arguments.arguments("With same major and smaller minor version should return true", 2, 2, 0, "2.3.2", true),
63+
Arguments.arguments("With same major and smaller minor version ignores patch", 2, 2, 9, "2.3.2", true),
64+
// Patch version comparisons (same major and minor)
65+
Arguments.arguments("With same major.minor and larger patch should return false", 2, 3, 3, "2.3.2", false),
66+
Arguments.arguments("With same major.minor and same patch should return true", 2, 3, 2, "2.3.2", true),
67+
Arguments.arguments("With same major.minor and smaller patch should return true", 2, 3, 1, "2.3.2", true),
68+
Arguments.arguments("With same major.minor and zero patch should return true", 2, 3, 0, "2.3.2", true),
69+
// Edge cases for Spring Boot version check (2.3.2 cutoff)
70+
Arguments.arguments("Spring Boot 2.3.0 is not at least 2.3.2", 2, 3, 2, "2.3.0", false),
71+
Arguments.arguments("Spring Boot 2.3.1 is not at least 2.3.2", 2, 3, 2, "2.3.1", false),
72+
Arguments.arguments("Spring Boot 2.3.2 is at least 2.3.2", 2, 3, 2, "2.3.2", true),
73+
Arguments.arguments("Spring Boot 2.3.3 is at least 2.3.2", 2, 3, 2, "2.3.3", true),
74+
Arguments.arguments("Spring Boot 2.4.0 is at least 2.3.2", 2, 3, 2, "2.4.0", true),
75+
Arguments.arguments("Spring Boot 3.0.0 is at least 2.3.2", 2, 3, 2, "3.0.0", true),
76+
Arguments.arguments("Spring Boot 2.2.13 is not at least 2.3.2", 2, 3, 2, "2.2.13", false),
77+
Arguments.arguments("Spring Boot 1.5.0 is not at least 2.3.2", 2, 3, 2, "1.5.0", false),
78+
// Version without patch (e.g., "2.3") should treat patch as 0
79+
Arguments.arguments("Version 2.3 (no patch) is not at least 2.3.2", 2, 3, 2, "2.3", false),
80+
Arguments.arguments("Version 2.3 (no patch) is at least 2.3.0", 2, 3, 0, "2.3", true),
81+
Arguments.arguments("Version 2.4 (no patch) is at least 2.3.2", 2, 3, 2, "2.4", true),
82+
// Version with suffix (e.g., "1.13.7.Final")
83+
Arguments.arguments("Version with suffix and larger patch should return false", 1, 13, 8, "1.13.7.Final", false),
84+
Arguments.arguments("Version with suffix and same patch should return true", 1, 13, 7, "1.13.7.Final", true),
85+
Arguments.arguments("Version with suffix and smaller patch should return true", 1, 13, 6, "1.13.7.Final", true),
86+
// Invalid versions
87+
Arguments.arguments("With invalid version should return false", 2, 3, 2, "invalid.version", false),
88+
Arguments.arguments("With empty version should return false", 2, 3, 2, "", false),
89+
Arguments.arguments("With null-like version should return false", 2, 3, 2, " ", false)
90+
);
91+
}
92+
4893
@ParameterizedTest(name = "given {0} should return {1} without metadata")
4994
@CsvSource({
5095
"0.31.0+git-3a994bd.build-5086,0.31.0",

jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/SpringBootConfigurationTest.java

Lines changed: 194 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,31 @@ void isServerSslEnabled_defaultsToFalseWithoutKeystore(@TempDir Path target) thr
233233
assertThat(config.isServerSslEnabled()).isFalse();
234234
}
235235

236-
@DisplayName("getManagementHealthProbesEnabled defaults to 'true'")
236+
@Test
237+
@DisplayName("isManagementHealthProbesEnabled returns true when new property is set")
237238
void getManagementHealthProbesEnabled() {
238-
assertThat(springBootConfiguration.isManagementHealthProbesEnabled()).isTrue();
239+
assertThat(springBootConfiguration.isManagementHealthProbesEnabled()).isTrue();
240+
}
241+
242+
@Test
243+
@DisplayName("isManagementHealthProbesEnabled returns false when only old property is set (Spring Boot >= 2.3.2)")
244+
void getManagementHealthProbesEnabled_withOnlyOldProperty(@TempDir Path target) throws IOException {
245+
final Properties properties = new Properties();
246+
properties.put("management.health.probes.enabled", "true");
247+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
248+
properties.store(fos, null);
249+
}
250+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
251+
.properties(properties)
252+
.outputDirectory(target.toFile())
253+
.dependency(Dependency.builder()
254+
.groupId("org.springframework.boot")
255+
.artifactId("spring-boot")
256+
.version("3.0.0")
257+
.build())
258+
.build());
259+
// Old property should NOT work for Spring Boot >= 2.3.2
260+
assertThat(config.isManagementHealthProbesEnabled()).isFalse();
239261
}
240262
}
241263

@@ -254,11 +276,159 @@ void setUp() {
254276
}
255277

256278
@Test
257-
@DisplayName("getManagementHealthProbesEnabled defaults to 'true'")
279+
@DisplayName("isManagementHealthProbesEnabled returns true when new property is set")
258280
void getManagementHealthProbesEnabled() {
259281
assertThat(springBootConfiguration.isManagementHealthProbesEnabled()).isTrue();
260282
}
261283

284+
@Test
285+
@DisplayName("isManagementHealthProbesEnabled returns true when only old property is set (Spring Boot 2.0 < 2.3.2)")
286+
void getManagementHealthProbesEnabled_withOnlyOldProperty(@TempDir Path target) throws IOException {
287+
final Properties properties = new Properties();
288+
properties.put("management.health.probes.enabled", "true");
289+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
290+
properties.store(fos, null);
291+
}
292+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
293+
.properties(properties)
294+
.outputDirectory(target.toFile())
295+
.dependency(Dependency.builder()
296+
.groupId("org.springframework.boot")
297+
.artifactId("spring-boot")
298+
.version("2.0.0")
299+
.build())
300+
.build());
301+
// Old property should work for Spring Boot < 2.3.2
302+
assertThat(config.isManagementHealthProbesEnabled()).isTrue();
303+
}
304+
305+
@Test
306+
@DisplayName("isManagementHealthProbesEnabled returns true when only old property is set (Spring Boot 2.2.x < 2.3.2)")
307+
void getManagementHealthProbesEnabled_withOnlyOldPropertySpringBoot22(@TempDir Path target) throws IOException {
308+
final Properties properties = new Properties();
309+
properties.put("management.health.probes.enabled", "true");
310+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
311+
properties.store(fos, null);
312+
}
313+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
314+
.properties(properties)
315+
.outputDirectory(target.toFile())
316+
.dependency(Dependency.builder()
317+
.groupId("org.springframework.boot")
318+
.artifactId("spring-boot")
319+
.version("2.2.13")
320+
.build())
321+
.build());
322+
// Old property should work for Spring Boot 2.2.x (< 2.3.2)
323+
assertThat(config.isManagementHealthProbesEnabled()).isTrue();
324+
}
325+
326+
@Test
327+
@DisplayName("isManagementHealthProbesEnabled returns true when only old property is set (Spring Boot 2.3.0 < 2.3.2)")
328+
void getManagementHealthProbesEnabled_withOnlyOldPropertySpringBoot230(@TempDir Path target) throws IOException {
329+
final Properties properties = new Properties();
330+
properties.put("management.health.probes.enabled", "true");
331+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
332+
properties.store(fos, null);
333+
}
334+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
335+
.properties(properties)
336+
.outputDirectory(target.toFile())
337+
.dependency(Dependency.builder()
338+
.groupId("org.springframework.boot")
339+
.artifactId("spring-boot")
340+
.version("2.3.0")
341+
.build())
342+
.build());
343+
// Old property should work for Spring Boot 2.3.0 and 2.3.1 (< 2.3.2)
344+
assertThat(config.isManagementHealthProbesEnabled()).isTrue();
345+
}
346+
347+
@Test
348+
@DisplayName("isManagementHealthProbesEnabled returns true when only old property is set (Spring Boot 2.3.1 < 2.3.2)")
349+
void getManagementHealthProbesEnabled_withOnlyOldPropertySpringBoot231(@TempDir Path target) throws IOException {
350+
final Properties properties = new Properties();
351+
properties.put("management.health.probes.enabled", "true");
352+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
353+
properties.store(fos, null);
354+
}
355+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
356+
.properties(properties)
357+
.outputDirectory(target.toFile())
358+
.dependency(Dependency.builder()
359+
.groupId("org.springframework.boot")
360+
.artifactId("spring-boot")
361+
.version("2.3.1")
362+
.build())
363+
.build());
364+
// Old property should work for Spring Boot 2.3.0 and 2.3.1 (< 2.3.2)
365+
assertThat(config.isManagementHealthProbesEnabled()).isTrue();
366+
}
367+
368+
@Test
369+
@DisplayName("isManagementHealthProbesEnabled returns false when only old property is set (Spring Boot 2.3.2 >= 2.3.2)")
370+
void getManagementHealthProbesEnabled_withOnlyOldPropertySpringBoot232(@TempDir Path target) throws IOException {
371+
final Properties properties = new Properties();
372+
properties.put("management.health.probes.enabled", "true");
373+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
374+
properties.store(fos, null);
375+
}
376+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
377+
.properties(properties)
378+
.outputDirectory(target.toFile())
379+
.dependency(Dependency.builder()
380+
.groupId("org.springframework.boot")
381+
.artifactId("spring-boot")
382+
.version("2.3.2")
383+
.build())
384+
.build());
385+
// Old property should NOT work for Spring Boot >= 2.3.2
386+
assertThat(config.isManagementHealthProbesEnabled()).isFalse();
387+
}
388+
389+
@Test
390+
@DisplayName("isManagementHealthProbesEnabled returns false when only old property is set (Spring Boot 2.3.3 >= 2.3.2)")
391+
void getManagementHealthProbesEnabled_withOnlyOldPropertySpringBoot233(@TempDir Path target) throws IOException {
392+
final Properties properties = new Properties();
393+
properties.put("management.health.probes.enabled", "true");
394+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
395+
properties.store(fos, null);
396+
}
397+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
398+
.properties(properties)
399+
.outputDirectory(target.toFile())
400+
.dependency(Dependency.builder()
401+
.groupId("org.springframework.boot")
402+
.artifactId("spring-boot")
403+
.version("2.3.3")
404+
.build())
405+
.build());
406+
// Old property should NOT work for Spring Boot >= 2.3.2
407+
assertThat(config.isManagementHealthProbesEnabled()).isFalse();
408+
}
409+
410+
@Test
411+
@DisplayName("isManagementHealthProbesEnabled new property takes precedence over old property")
412+
void getManagementHealthProbesEnabled_newPropertyTakesPrecedence(@TempDir Path target) throws IOException {
413+
final Properties properties = new Properties();
414+
properties.put("management.health.probes.enabled", "true");
415+
properties.put("management.endpoint.health.probes.enabled", "false");
416+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
417+
properties.store(fos, null);
418+
}
419+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
420+
.properties(properties)
421+
.outputDirectory(target.toFile())
422+
.dependency(Dependency.builder()
423+
.groupId("org.springframework.boot")
424+
.artifactId("spring-boot")
425+
.version("2.0.0")
426+
.build())
427+
.build());
428+
// New property should take precedence
429+
assertThat(config.isManagementHealthProbesEnabled()).isFalse();
430+
}
431+
262432
@Test
263433
@DisplayName("getManagementPort defaults to 'management.server.port'")
264434
void getManagementPort() {
@@ -529,6 +699,27 @@ void isServerSslEnabled_whenExplicitlyTrue(String version) {
529699
assertThat(springBootConfiguration.isServerSslEnabled()).isTrue();
530700
}
531701

702+
@Test
703+
@DisplayName("isManagementHealthProbesEnabled returns true when old property is set (Spring Boot 1)")
704+
void getManagementHealthProbesEnabled_withOldProperty(@TempDir Path target) throws IOException {
705+
final Properties properties = new Properties();
706+
properties.put("management.health.probes.enabled", "true");
707+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
708+
properties.store(fos, null);
709+
}
710+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
711+
.properties(properties)
712+
.outputDirectory(target.toFile())
713+
.dependency(Dependency.builder()
714+
.groupId("org.springframework.boot")
715+
.artifactId("spring-boot")
716+
.version("1.5.0")
717+
.build())
718+
.build());
719+
// Old property should work for Spring Boot 1.x (< 2.3.2)
720+
assertThat(config.isManagementHealthProbesEnabled()).isTrue();
721+
}
722+
532723
@Test
533724
@DisplayName("isManagementSslEnabled uses management.ssl.enabled property (Spring Boot 1)")
534725
void isManagementSslEnabled_withManagementSslEnabled(@TempDir Path target) throws IOException {

0 commit comments

Comments
 (0)