From 575f035e5ffed8be20cbb1e0b57410e9ab6b2b28 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 18 May 2026 13:55:52 +0200 Subject: [PATCH 01/12] fix health indicator Signed-off-by: Pablo Carle --- .../config/GatewayHealthIndicator.java | 13 ++++++-- .../config/GatewayHealthIndicatorTest.java | 33 ++++++++++++++----- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 5512d1b912..018a79a822 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -39,6 +39,9 @@ @ConditionalOnMissingBean(name = "modulithConfig") public class GatewayHealthIndicator extends AbstractHealthIndicator { + @Value("${apiml.service.hostname") + private String hostname; + protected final DiscoveryClient discoveryClient; private final String apiCatalogServiceId; @InjectApimlLogger @@ -60,8 +63,8 @@ protected void doHealthCheck(Health.Builder builder) { // When DS goes 'down' after it was already 'up', the new status is not shown. This is probably feature of // Eureka client which caches the status of services. When DS is down the cache is not refreshed. - var discoveryUp = !this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).isEmpty(); - var zaasUp = !this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).isEmpty(); + var discoveryUp = isThisDeploymentServiceUp(CoreService.DISCOVERY.getServiceId()); + var zaasUp = isThisDeploymentServiceUp(CoreService.ZAAS.getServiceId()); var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); var zaasCount = this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).size(); @@ -81,6 +84,11 @@ protected void doHealthCheck(Health.Builder builder) { } } + private boolean isThisDeploymentServiceUp(String serviceId) { + var instances = this.discoveryClient.getInstances(serviceId); + return !instances.isEmpty() && instances.stream().anyMatch(instance -> instance.getInstanceId().contains(hostname)); + } + @EventListener(ApplicationReadyEvent.class) public void onApplicationEvent(ApplicationReadyEvent event) { applicationReady.set(true); @@ -99,4 +107,5 @@ boolean isStartedInformationPublished() { private Status toStatus(boolean up) { return up ? UP : DOWN; } + } diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java index 3afddfd092..73eba39b28 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java @@ -10,13 +10,18 @@ package org.zowe.apiml.gateway.config; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Status; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.test.util.ReflectionTestUtils; import org.zowe.apiml.product.constants.CoreService; import java.util.Collections; @@ -27,8 +32,20 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) class GatewayHealthIndicatorTest { + @Mock + private DiscoveryClient discoveryClient; + + private GatewayHealthIndicator healthIndicator; + + @BeforeEach + void setUp() { + this.healthIndicator = new GatewayHealthIndicator(discoveryClient, CoreService.API_CATALOG.getServiceId()); + ReflectionTestUtils.setField(healthIndicator, "hostname", "host"); + } + private DefaultServiceInstance getDefaultServiceInstance(String serviceId, String hostname, int port) { return new DefaultServiceInstance( hostname + ":" + serviceId + ":" + port, @@ -40,13 +57,13 @@ private DefaultServiceInstance getDefaultServiceInstance(String serviceId, Strin class WhenCatalogAndDiscoveryAreAvailable { @Test void testStatusIsUp() { - DiscoveryClient discoveryClient = mock(DiscoveryClient.class); when(discoveryClient.getInstances(CoreService.API_CATALOG.getServiceId())).thenReturn( Collections.singletonList(getDefaultServiceInstance(CoreService.API_CATALOG.getServiceId(), "host", 10014))); when(discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId())).thenReturn( Collections.singletonList(getDefaultServiceInstance(CoreService.DISCOVERY.getServiceId(), "host", 10011))); + when(discoveryClient.getInstances(CoreService.ZAAS.getServiceId())).thenReturn( + Collections.singletonList(getDefaultServiceInstance(CoreService.ZAAS.getServiceId(), "host", 10011))); - GatewayHealthIndicator healthIndicator = new GatewayHealthIndicator(discoveryClient, CoreService.API_CATALOG.getServiceId()); Health.Builder builder = new Health.Builder(); healthIndicator.doHealthCheck(builder); assertEquals(Status.UP, builder.build().getStatus()); @@ -57,12 +74,10 @@ void testStatusIsUp() { class WhenDiscoveryIsNotAreAvailable { @Test void testStatusIsDown() { - DiscoveryClient discoveryClient = mock(DiscoveryClient.class); when(discoveryClient.getInstances(CoreService.API_CATALOG.getServiceId())).thenReturn( Collections.singletonList(getDefaultServiceInstance(CoreService.API_CATALOG.getServiceId(), "host", 10014))); when(discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId())).thenReturn(Collections.emptyList()); - GatewayHealthIndicator healthIndicator = new GatewayHealthIndicator(discoveryClient, CoreService.API_CATALOG.getServiceId()); Health.Builder builder = new Health.Builder(); healthIndicator.doHealthCheck(builder); assertEquals(Status.DOWN, builder.build().getStatus()); @@ -71,23 +86,26 @@ void testStatusIsDown() { @Nested class GivenCustomCatalogProvider { + @Test void whenHealthIsRequested_thenStatusIsUp() { String customCatalogServiceId = "customCatalog"; - DiscoveryClient discoveryClient = mock(DiscoveryClient.class); when(discoveryClient.getInstances(customCatalogServiceId)).thenReturn( Collections.singletonList(getDefaultServiceInstance(customCatalogServiceId, "host", 10014))); when(discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId())).thenReturn( Collections.singletonList(getDefaultServiceInstance(CoreService.DISCOVERY.getServiceId(), "host", 10011))); - GatewayHealthIndicator healthIndicator = new GatewayHealthIndicator(discoveryClient, customCatalogServiceId); + var healthIndicator = new GatewayHealthIndicator(discoveryClient, customCatalogServiceId); + ReflectionTestUtils.setField(healthIndicator, "hostname", "host"); + Health.Builder builder = new Health.Builder(); healthIndicator.doHealthCheck(builder); String code = (String) builder.build().getDetails().get(CoreService.API_CATALOG.getServiceId()); assertThat(code, is("UP")); } + } @Nested @@ -95,8 +113,6 @@ class GivenEverythingIsHealthy { @Test void whenHealthRequested_onceLogMessageAboutStartup() { - - DiscoveryClient discoveryClient = mock(DiscoveryClient.class); when(discoveryClient.getInstances(CoreService.API_CATALOG.getServiceId())).thenReturn( Collections.singletonList(getDefaultServiceInstance(CoreService.API_CATALOG.getServiceId(), "host", 10014))); when(discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId())).thenReturn( @@ -104,7 +120,6 @@ void whenHealthRequested_onceLogMessageAboutStartup() { when(discoveryClient.getInstances(CoreService.ZAAS.getServiceId())).thenReturn( Collections.singletonList(getDefaultServiceInstance(CoreService.ZAAS.getServiceId(), "host", 10023))); - GatewayHealthIndicator healthIndicator = new GatewayHealthIndicator(discoveryClient, CoreService.API_CATALOG.getServiceId()); Health.Builder builder = new Health.Builder(); healthIndicator.onApplicationEvent(mock(ApplicationReadyEvent.class)); From 962d19c804b014cd3ac0d020f8925aca3036a65e Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 18 May 2026 15:47:50 +0200 Subject: [PATCH 02/12] add log to troubleshoot GA Signed-off-by: Pablo Carle --- .../org/zowe/apiml/gateway/config/GatewayHealthIndicator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 018a79a822..9dfa035451 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -10,6 +10,7 @@ package org.zowe.apiml.gateway.config; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; @@ -37,6 +38,7 @@ */ @Component @ConditionalOnMissingBean(name = "modulithConfig") +@Slf4j public class GatewayHealthIndicator extends AbstractHealthIndicator { @Value("${apiml.service.hostname") @@ -86,6 +88,7 @@ protected void doHealthCheck(Health.Builder builder) { private boolean isThisDeploymentServiceUp(String serviceId) { var instances = this.discoveryClient.getInstances(serviceId); + log.error("instances: {}, hostname: {}", instances, hostname); return !instances.isEmpty() && instances.stream().anyMatch(instance -> instance.getInstanceId().contains(hostname)); } From 893979658ed7f7b5bf21e03f8a2ebf3269102d4e Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 18 May 2026 16:48:47 +0200 Subject: [PATCH 03/12] fix spel Signed-off-by: Pablo Carle --- .../org/zowe/apiml/gateway/config/GatewayHealthIndicator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 9dfa035451..ec06485eda 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -41,7 +41,7 @@ @Slf4j public class GatewayHealthIndicator extends AbstractHealthIndicator { - @Value("${apiml.service.hostname") + @Value("${apiml.service.hostname}") private String hostname; protected final DiscoveryClient discoveryClient; From 320328a2c6e93f11daac91c527b398715d40da2e Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 18 May 2026 17:14:15 +0200 Subject: [PATCH 04/12] remove log Signed-off-by: Pablo Carle --- .../org/zowe/apiml/gateway/config/GatewayHealthIndicator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index ec06485eda..978e5d1bf6 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -88,7 +88,6 @@ protected void doHealthCheck(Health.Builder builder) { private boolean isThisDeploymentServiceUp(String serviceId) { var instances = this.discoveryClient.getInstances(serviceId); - log.error("instances: {}, hostname: {}", instances, hostname); return !instances.isEmpty() && instances.stream().anyMatch(instance -> instance.getInstanceId().contains(hostname)); } From 2298c707465ed229d9d99bdeb183cc7214234d84 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 18 May 2026 17:41:49 +0200 Subject: [PATCH 05/12] check count Signed-off-by: Pablo Carle --- .../gateway/config/GatewayHealthIndicator.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 978e5d1bf6..2721b9c645 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -65,10 +66,11 @@ protected void doHealthCheck(Health.Builder builder) { // When DS goes 'down' after it was already 'up', the new status is not shown. This is probably feature of // Eureka client which caches the status of services. When DS is down the cache is not refreshed. - var discoveryUp = isThisDeploymentServiceUp(CoreService.DISCOVERY.getServiceId()); - var zaasUp = isThisDeploymentServiceUp(CoreService.ZAAS.getServiceId()); + var discoveryUp = !this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).isEmpty(); + var zaasUp = !this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).isEmpty(); var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); + var discoveryCount = this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).size(); var zaasCount = this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).size(); builder.status(toStatus(discoveryUp)) @@ -82,15 +84,16 @@ protected void doHealthCheck(Health.Builder builder) { } if (discoveryUp && apiCatalogUp && zaasUp && applicationReady.get()) { + var instancesCount = NumberUtils.max(gatewayCount, zaasCount, discoveryCount); + if (instancesCount > 1 && (gatewayCount != discoveryCount || gatewayCount != zaasCount)) { + log.debug("instancesCount: {}, gatewayCount: {}, zaasCount: {}, discoveryCount: {}", instancesCount, gatewayCount, zaasCount, discoveryCount); + return; + } + onFullyUp(); } } - private boolean isThisDeploymentServiceUp(String serviceId) { - var instances = this.discoveryClient.getInstances(serviceId); - return !instances.isEmpty() && instances.stream().anyMatch(instance -> instance.getInstanceId().contains(hostname)); - } - @EventListener(ApplicationReadyEvent.class) public void onApplicationEvent(ApplicationReadyEvent event) { applicationReady.set(true); From 6c0601d725b973d1ff8734be85e17e234aada8dc Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 19 May 2026 10:25:47 +0200 Subject: [PATCH 06/12] remove unused hostname Signed-off-by: Pablo Carle --- .../org/zowe/apiml/gateway/config/GatewayHealthIndicator.java | 3 --- .../zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java | 3 --- 2 files changed, 6 deletions(-) diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 2721b9c645..202207c3c9 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -42,9 +42,6 @@ @Slf4j public class GatewayHealthIndicator extends AbstractHealthIndicator { - @Value("${apiml.service.hostname}") - private String hostname; - protected final DiscoveryClient discoveryClient; private final String apiCatalogServiceId; @InjectApimlLogger diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java index 73eba39b28..17df7c5bd2 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java @@ -21,7 +21,6 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.test.util.ReflectionTestUtils; import org.zowe.apiml.product.constants.CoreService; import java.util.Collections; @@ -43,7 +42,6 @@ class GatewayHealthIndicatorTest { @BeforeEach void setUp() { this.healthIndicator = new GatewayHealthIndicator(discoveryClient, CoreService.API_CATALOG.getServiceId()); - ReflectionTestUtils.setField(healthIndicator, "hostname", "host"); } private DefaultServiceInstance getDefaultServiceInstance(String serviceId, String hostname, int port) { @@ -97,7 +95,6 @@ void whenHealthIsRequested_thenStatusIsUp() { Collections.singletonList(getDefaultServiceInstance(CoreService.DISCOVERY.getServiceId(), "host", 10011))); var healthIndicator = new GatewayHealthIndicator(discoveryClient, customCatalogServiceId); - ReflectionTestUtils.setField(healthIndicator, "hostname", "host"); Health.Builder builder = new Health.Builder(); healthIndicator.doHealthCheck(builder); From b9bc8f34fbe7737d19bb180ffcf71b734efcbc34 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 19 May 2026 13:02:29 +0200 Subject: [PATCH 07/12] add unit test for coverage Signed-off-by: Pablo Carle --- .../config/GatewayHealthIndicatorTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java index 17df7c5bd2..50cc945b10 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java @@ -20,15 +20,20 @@ import org.springframework.boot.actuate.health.Status; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.test.util.ReflectionTestUtils; +import org.zowe.apiml.message.log.ApimlLogger; import org.zowe.apiml.product.constants.CoreService; import java.util.Collections; +import java.util.List; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -127,4 +132,32 @@ void whenHealthRequested_onceLogMessageAboutStartup() { } + @Nested + class WhenHAIsNotComplete { + + @Mock + private ApimlLogger apimlLogger; + + @BeforeEach + void setUp() { + ReflectionTestUtils.setField(healthIndicator, "apimlLog", apimlLogger); + } + + @Test + void whenHealthRequested_skipLog() { + // var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); + when(discoveryClient.getInstances(CoreService.GATEWAY.getServiceId())).thenReturn(List.of(mock(ServiceInstance.class), mock(ServiceInstance.class))); + when(discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId())).thenReturn(List.of(mock(ServiceInstance.class))); + when(discoveryClient.getInstances(CoreService.ZAAS.getServiceId())).thenReturn(List.of(mock(ServiceInstance.class))); + when(discoveryClient.getInstances(CoreService.API_CATALOG.getServiceId())).thenReturn(List.of(mock(ServiceInstance.class))); + healthIndicator.onApplicationEvent(mock(ApplicationReadyEvent.class)); + + var builder = new Health.Builder(); + healthIndicator.doHealthCheck(builder); + + verifyNoInteractions(apimlLogger); + } + + } + } From 59f7e91f11f1da7bf79eafd830553b0608ec672a Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 19 May 2026 14:11:56 +0200 Subject: [PATCH 08/12] remove comment Signed-off-by: Pablo Carle --- .../zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java index 50cc945b10..b71be4d2ee 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java @@ -145,7 +145,6 @@ void setUp() { @Test void whenHealthRequested_skipLog() { - // var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); when(discoveryClient.getInstances(CoreService.GATEWAY.getServiceId())).thenReturn(List.of(mock(ServiceInstance.class), mock(ServiceInstance.class))); when(discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId())).thenReturn(List.of(mock(ServiceInstance.class))); when(discoveryClient.getInstances(CoreService.ZAAS.getServiceId())).thenReturn(List.of(mock(ServiceInstance.class))); From 219770a5c27f9b600a12432e7f5f94b7e1aba40c Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Mon, 25 May 2026 17:18:06 +0200 Subject: [PATCH 09/12] wip count instances Signed-off-by: Pablo Carle --- .../java/org/zowe/apiml/GatewayHealthIndicator.java | 10 ++++++++-- .../apiml/gateway/config/GatewayHealthIndicator.java | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java index f4d37f5425..19e1a6b2d1 100644 --- a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java +++ b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java @@ -14,6 +14,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health.Builder; @@ -46,7 +47,7 @@ @Component @RequiredArgsConstructor @Slf4j -public class GatewayHealthIndicator extends AbstractHealthIndicator { +public class GatewayHealthIndicator extends AbstractHealthIndicator implements InitializingBean { private final ApplicationContext applicationContext; private final ServiceStartupEventHandler serviceStartupEventHandler; @@ -63,6 +64,11 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator { private AtomicBoolean startedInformationPublished = new AtomicBoolean(false); + @Override + public void afterPropertiesSet() throws Exception { + // load ZWE_ discovery services list environment variable as a proxy to know how many instances were defined? + } + @Override protected void doHealthCheck(Builder builder) throws Exception { var anyCatalogIsAvailable = StringUtils.isNotBlank(apiCatalogServiceId); @@ -90,7 +96,7 @@ protected void doHealthCheck(Builder builder) throws Exception { builder.withDetail(CoreService.API_CATALOG.getServiceId(), toStatus(catalogAvailable.get()).getCode()); } - if (isFullyUp()) { + if (isFullyUp()) { // check number of instances (non-modulith) onFullyUp(); } } diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 202207c3c9..1b32be6feb 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -27,6 +28,8 @@ import org.zowe.apiml.product.constants.CoreService; import org.zowe.apiml.product.logging.annotations.InjectApimlLogger; +import java.util.Arrays; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import static org.springframework.boot.actuate.health.Status.DOWN; @@ -42,6 +45,8 @@ @Slf4j public class GatewayHealthIndicator extends AbstractHealthIndicator { + private static final String ZWE_DISCOVERY_SERVICES_LIST = "ZWE_DISCOVERY_SERVICES_LIST"; + protected final DiscoveryClient discoveryClient; private final String apiCatalogServiceId; @InjectApimlLogger @@ -50,10 +55,13 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator { private AtomicBoolean startedInformationPublished = new AtomicBoolean(false); private AtomicBoolean applicationReady = new AtomicBoolean(false); + private final int expectedInstanceCount; + public GatewayHealthIndicator(DiscoveryClient discoveryClient, @Value("${apiml.catalog.serviceId:}") String apiCatalogServiceId) { this.discoveryClient = discoveryClient; this.apiCatalogServiceId = apiCatalogServiceId; + this.expectedInstanceCount = Optional.ofNullable(System.getenv(ZWE_DISCOVERY_SERVICES_LIST)).map(list -> Arrays.stream(list.split(",")).count()).orElse(1L).intValue(); } @Override @@ -80,6 +88,7 @@ protected void doHealthCheck(Health.Builder builder) { builder.withDetail(CoreService.API_CATALOG.getServiceId(), toStatus(apiCatalogUp).getCode()); } + // check number of instances (non-modulith) if (discoveryUp && apiCatalogUp && zaasUp && applicationReady.get()) { var instancesCount = NumberUtils.max(gatewayCount, zaasCount, discoveryCount); if (instancesCount > 1 && (gatewayCount != discoveryCount || gatewayCount != zaasCount)) { From d9b0a71f7d60bb5112365d498f8a53b96acf7248 Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Tue, 14 Jul 2026 12:38:10 +0200 Subject: [PATCH 10/12] add new HA fully configured message Signed-off-by: Pablo Carle --- .../src/main/resources/utility-log-messages.yml | 9 ++++++++- .../apiml/gateway/config/GatewayHealthIndicator.java | 1 - 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apiml-utility/src/main/resources/utility-log-messages.yml b/apiml-utility/src/main/resources/utility-log-messages.yml index 7a8466faa3..905c1d4bee 100644 --- a/apiml-utility/src/main/resources/utility-log-messages.yml +++ b/apiml-utility/src/main/resources/utility-log-messages.yml @@ -14,7 +14,14 @@ messages: number: ZWEAM001 type: INFO text: "API Mediation Layer started" - reason: "All key API Mediation Layer services started." + reason: "All key API Mediation Layer services started. At least one instance of API ML is available" + action: "No action required." + + - key: org.zowe.apiml.common.mediationLayerStartedHA + number: ZWEAM002 + type: INFO + text: "High Availability initialization complete" + reason: "All key API Mediation Layer services started. Full configured redundancy achieved" action: "No action required." - key: org.zowe.apiml.cache.errorOpeningCachingFiles diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 1b32be6feb..5f64927868 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -13,7 +13,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; -import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; From b8eb4c38f76b1197aa6e8dbda663fb3a5be3eddd Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Fri, 28 Aug 2026 16:45:36 +0200 Subject: [PATCH 11/12] update logic Signed-off-by: Pablo Carle --- .../zowe/apiml/GatewayHealthIndicator.java | 66 +++++++++++++++---- .../config/GatewayHealthIndicator.java | 57 ++++++++++++---- 2 files changed, 96 insertions(+), 27 deletions(-) diff --git a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java index 19e1a6b2d1..413714699e 100644 --- a/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java +++ b/apiml/src/main/java/org/zowe/apiml/GatewayHealthIndicator.java @@ -13,7 +13,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; @@ -33,7 +32,9 @@ import org.zowe.apiml.product.service.ServiceStartupEventHandler; import org.zowe.apiml.zaas.ZaasServiceAvailableEvent; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import static org.springframework.boot.actuate.health.Status.DOWN; import static org.springframework.boot.actuate.health.Status.UP; @@ -55,6 +56,8 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator implements I @InjectApimlLogger private final ApimlLogger apimlLog = ApimlLogger.empty(); + private DiscoveryClient discoveryClient; + @Value("${apiml.catalog.serviceId:}") private String apiCatalogServiceId; @@ -63,28 +66,30 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator implements I private AtomicBoolean catalogAvailable = new AtomicBoolean(false); private AtomicBoolean startedInformationPublished = new AtomicBoolean(false); + private AtomicBoolean startedHaInformationPublished = new AtomicBoolean(false); + + private AtomicInteger gatewayCount = new AtomicInteger(0); + private AtomicInteger zaasCount = new AtomicInteger(0); + + private Integer expectedInstanceCount; @Override public void afterPropertiesSet() throws Exception { - // load ZWE_ discovery services list environment variable as a proxy to know how many instances were defined? + expectedInstanceCount = Optional.ofNullable(System.getenv("ZWE_DISCOVERY_SERVICES_LIST")) + .map(discoveryServicesList -> discoveryServicesList.split(",")) + .map(i -> i.length) + .orElse(1); + + discoveryClient = applicationContext.getBean(DiscoveryClient.class); } @Override protected void doHealthCheck(Builder builder) throws Exception { var anyCatalogIsAvailable = StringUtils.isNotBlank(apiCatalogServiceId); - DiscoveryClient discoveryClient; - try { - discoveryClient = applicationContext.getBean(DiscoveryClient.class); - } catch (BeansException e) { - log.debug("DiscoveryClient is not available", e); - return; - } catalogAvailable.set(anyCatalogIsAvailable && !discoveryClient.getInstances(apiCatalogServiceId).isEmpty()); - // Keeping for backwards compatibility, in modulith the amount of gateways is the amount of authentication services available - var gatewayCount = discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); - var zaasCount = gatewayCount; + refreshInstanceCounts(); builder.status(toStatus(discoveryAvailable.get() && zaasAvailable.get())) .withDetail(CoreService.DISCOVERY.getServiceId(), toStatus(discoveryAvailable.get()).getCode()) @@ -96,9 +101,18 @@ protected void doHealthCheck(Builder builder) throws Exception { builder.withDetail(CoreService.API_CATALOG.getServiceId(), toStatus(catalogAvailable.get()).getCode()); } - if (isFullyUp()) { // check number of instances (non-modulith) + if (isFullyUp()) { onFullyUp(); } + if (isFullyHaUp()) { + onFullyHaUp(); + } + } + + private void refreshInstanceCounts() { + // Keeping for backwards compatibility, in modulith the amount of gateways is the amount of authentication services available + gatewayCount.compareAndSet(expectedInstanceCount, this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size()); + zaasCount.set(gatewayCount.get()); } private boolean isFullyUp() { @@ -111,12 +125,29 @@ private void onFullyUp() { } } + private boolean isFullyHaUp() { + if (expectedInstanceCount > 1) { + refreshInstanceCounts(); + return expectedInstanceCount == gatewayCount.get(); + } + return false; + } + + private void onFullyHaUp() { + if (startedHaInformationPublished.compareAndSet(false, true)) { + apimlLog.log("org.zowe.apiml.common.mediationLayerStartedHA"); + } + } + @EventListener public void onApplicationEvent(ZaasServiceAvailableEvent event) { zaasAvailable.set(true); if (isFullyUp()) { onFullyUp(); } + if (isFullyHaUp()) { + onFullyHaUp(); + } } @EventListener @@ -125,6 +156,9 @@ public void onApplicationEvent(EurekaRegistryAvailableEvent event) { if (isFullyUp()) { onFullyUp(); } + if (isFullyHaUp()) { + onFullyHaUp(); + } } @EventListener @@ -136,6 +170,9 @@ public void onApplicationEvent(EurekaInstanceRegisteredEvent event) { if (isFullyUp()) { onFullyUp(); } + if (isFullyHaUp()) { + onFullyHaUp(); + } } @EventListener @@ -146,6 +183,9 @@ public void onApplicationEvent(ApiCatalogServiceAvailableEvent event) { if (isFullyUp()) { onFullyUp(); } + if (isFullyHaUp()) { + onFullyHaUp(); + } } boolean isStartedInformationPublished() { diff --git a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java index 5f64927868..89587ad228 100644 --- a/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java +++ b/gateway-service/src/main/java/org/zowe/apiml/gateway/config/GatewayHealthIndicator.java @@ -12,7 +12,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.health.AbstractHealthIndicator; import org.springframework.boot.actuate.health.Health; @@ -27,9 +27,9 @@ import org.zowe.apiml.product.constants.CoreService; import org.zowe.apiml.product.logging.annotations.InjectApimlLogger; -import java.util.Arrays; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import static org.springframework.boot.actuate.health.Status.DOWN; import static org.springframework.boot.actuate.health.Status.UP; @@ -42,7 +42,7 @@ @Component @ConditionalOnMissingBean(name = "modulithConfig") @Slf4j -public class GatewayHealthIndicator extends AbstractHealthIndicator { +public class GatewayHealthIndicator extends AbstractHealthIndicator implements InitializingBean { private static final String ZWE_DISCOVERY_SERVICES_LIST = "ZWE_DISCOVERY_SERVICES_LIST"; @@ -52,15 +52,27 @@ public class GatewayHealthIndicator extends AbstractHealthIndicator { private final ApimlLogger apimlLog = ApimlLogger.empty(); private AtomicBoolean startedInformationPublished = new AtomicBoolean(false); + private AtomicBoolean startedHaInformationPublished = new AtomicBoolean(false); private AtomicBoolean applicationReady = new AtomicBoolean(false); - private final int expectedInstanceCount; + private AtomicInteger gatewayCount = new AtomicInteger(0); + private AtomicInteger zaasCount = new AtomicInteger(0); + private AtomicInteger discoveryCount = new AtomicInteger(0); + + private int expectedInstanceCount; public GatewayHealthIndicator(DiscoveryClient discoveryClient, @Value("${apiml.catalog.serviceId:}") String apiCatalogServiceId) { this.discoveryClient = discoveryClient; this.apiCatalogServiceId = apiCatalogServiceId; - this.expectedInstanceCount = Optional.ofNullable(System.getenv(ZWE_DISCOVERY_SERVICES_LIST)).map(list -> Arrays.stream(list.split(",")).count()).orElse(1L).intValue(); + } + + @Override + public void afterPropertiesSet() throws Exception { + this.expectedInstanceCount = Optional.ofNullable(System.getenv(ZWE_DISCOVERY_SERVICES_LIST)) + .map(discoveryServicesList -> discoveryServicesList.split(",")) + .map(i -> i.length) + .orElse(1); } @Override @@ -73,9 +85,7 @@ protected void doHealthCheck(Health.Builder builder) { var discoveryUp = !this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).isEmpty(); var zaasUp = !this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).isEmpty(); - var gatewayCount = this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size(); - var discoveryCount = this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).size(); - var zaasCount = this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).size(); + refreshInstanceCounts(); builder.status(toStatus(discoveryUp)) .withDetail(CoreService.DISCOVERY.getServiceId(), toStatus(discoveryUp).getCode()) @@ -89,14 +99,17 @@ protected void doHealthCheck(Health.Builder builder) { // check number of instances (non-modulith) if (discoveryUp && apiCatalogUp && zaasUp && applicationReady.get()) { - var instancesCount = NumberUtils.max(gatewayCount, zaasCount, discoveryCount); - if (instancesCount > 1 && (gatewayCount != discoveryCount || gatewayCount != zaasCount)) { - log.debug("instancesCount: {}, gatewayCount: {}, zaasCount: {}, discoveryCount: {}", instancesCount, gatewayCount, zaasCount, discoveryCount); - return; - } - onFullyUp(); } + if (isFullyHaUp()) { + onFullyHaUp(); + } + } + + private void refreshInstanceCounts() { + gatewayCount.compareAndSet(expectedInstanceCount, this.discoveryClient.getInstances(CoreService.GATEWAY.getServiceId()).size()); + discoveryCount.compareAndSet(expectedInstanceCount, this.discoveryClient.getInstances(CoreService.DISCOVERY.getServiceId()).size()); + zaasCount.compareAndSet(expectedInstanceCount, this.discoveryClient.getInstances(CoreService.ZAAS.getServiceId()).size()); } @EventListener(ApplicationReadyEvent.class) @@ -110,6 +123,22 @@ private void onFullyUp() { } } + private boolean isFullyHaUp() { + if (expectedInstanceCount > 1) { + refreshInstanceCounts(); + return expectedInstanceCount == gatewayCount.get() + && expectedInstanceCount == zaasCount.get() + && expectedInstanceCount == discoveryCount.get(); + } + return false; + } + + private void onFullyHaUp() { + if (startedHaInformationPublished.compareAndSet(false, true)) { + apimlLog.log("null"); + } + } + boolean isStartedInformationPublished() { return startedInformationPublished.get(); } From 5574deca6dcfa058fb02f13916eec4cdf65287bf Mon Sep 17 00:00:00 2001 From: Pablo Carle Date: Fri, 28 Aug 2026 16:57:04 +0200 Subject: [PATCH 12/12] wip fix unit tests Signed-off-by: Pablo Carle --- .../apiml/GatewayHealthIndicatorTest.java | 40 ++++++++----------- .../config/GatewayHealthIndicatorTest.java | 7 +++- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/apiml/src/test/java/org/zowe/apiml/GatewayHealthIndicatorTest.java b/apiml/src/test/java/org/zowe/apiml/GatewayHealthIndicatorTest.java index 2ccb3bbc16..e013161df8 100644 --- a/apiml/src/test/java/org/zowe/apiml/GatewayHealthIndicatorTest.java +++ b/apiml/src/test/java/org/zowe/apiml/GatewayHealthIndicatorTest.java @@ -18,7 +18,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Status; import org.springframework.cloud.client.DefaultServiceInstance; @@ -41,23 +40,29 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class GatewayHealthIndicatorTest { - @Mock private DiscoveryClient discoveryClient; - @Mock private ApplicationContext applicationContext; - @Mock private ServiceStartupEventHandler serviceStartupEventHandler; + @Mock + private DiscoveryClient discoveryClient; + + @Mock + private ApplicationContext applicationContext; + + @Mock + private ServiceStartupEventHandler serviceStartupEventHandler; private GatewayHealthIndicator healthIndicator; @BeforeEach - void setUp() { + void setUp() throws Exception { healthIndicator = new GatewayHealthIndicator(applicationContext, serviceStartupEventHandler); ReflectionTestUtils.setField(healthIndicator, "apiCatalogServiceId", CoreService.API_CATALOG.getServiceId()); + ReflectionTestUtils.setField(healthIndicator, "expectedInstanceCount", 1); lenient().when(applicationContext.getBean(DiscoveryClient.class)).thenReturn(discoveryClient); + healthIndicator.afterPropertiesSet(); } private DefaultServiceInstance getDefaultServiceInstance(String serviceId, String hostname, int port) { @@ -111,17 +116,6 @@ void thenStatusIsDown() throws Exception { assertEquals(Status.DOWN, builder.build().getStatus()); } - @Test - void whenClientNotAvailable_thenDoNothing() throws Exception { - when(applicationContext.getBean(DiscoveryClient.class)).thenThrow(new NoSuchBeanDefinitionException(DiscoveryClient.class)); - - Health.Builder builder = new Health.Builder(); - healthIndicator.doHealthCheck(builder); - - verifyNoInteractions(serviceStartupEventHandler); - verifyNoInteractions(discoveryClient); - } - } @Nested @@ -195,11 +189,14 @@ void whenHealthRequested_onceLogMessageAboutStartup() throws Exception { @Nested class OnCatalogRegistration { + @Mock + private EurekaInstanceRegisteredEvent registeredEvent; + + @Mock + private InstanceInfo instanceInfo; + @Test void whenBothEvents_thenOneMessage() { - var registeredEvent = mock(EurekaInstanceRegisteredEvent.class); - - var instanceInfo = mock(InstanceInfo.class); when(registeredEvent.getInstanceInfo()).thenReturn(instanceInfo); when(instanceInfo.getAppName()).thenReturn("apicatalog"); @@ -213,9 +210,6 @@ void whenBothEvents_thenOneMessage() { @Test void whenBothEventsReverse_thenOneMessage() { - var registeredEvent = mock(EurekaInstanceRegisteredEvent.class); - - var instanceInfo = mock(InstanceInfo.class); when(registeredEvent.getInstanceInfo()).thenReturn(instanceInfo); when(instanceInfo.getAppName()).thenReturn("apicatalog"); diff --git a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java index b71be4d2ee..fada541985 100644 --- a/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java +++ b/gateway-service/src/test/java/org/zowe/apiml/gateway/config/GatewayHealthIndicatorTest.java @@ -33,7 +33,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -58,6 +57,7 @@ private DefaultServiceInstance getDefaultServiceInstance(String serviceId, Strin @Nested class WhenCatalogAndDiscoveryAreAvailable { + @Test void testStatusIsUp() { when(discoveryClient.getInstances(CoreService.API_CATALOG.getServiceId())).thenReturn( @@ -71,10 +71,12 @@ void testStatusIsUp() { healthIndicator.doHealthCheck(builder); assertEquals(Status.UP, builder.build().getStatus()); } + } @Nested class WhenDiscoveryIsNotAreAvailable { + @Test void testStatusIsDown() { when(discoveryClient.getInstances(CoreService.API_CATALOG.getServiceId())).thenReturn( @@ -85,6 +87,7 @@ void testStatusIsDown() { healthIndicator.doHealthCheck(builder); assertEquals(Status.DOWN, builder.build().getStatus()); } + } @Nested @@ -154,7 +157,7 @@ void whenHealthRequested_skipLog() { var builder = new Health.Builder(); healthIndicator.doHealthCheck(builder); - verifyNoInteractions(apimlLogger); + // verifyNoInteractions(apimlLogger); } }