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..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 @@ -10,7 +10,9 @@ package org.zowe.apiml.gateway.config; +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; @@ -37,6 +39,7 @@ */ @Component @ConditionalOnMissingBean(name = "modulithConfig") +@Slf4j public class GatewayHealthIndicator extends AbstractHealthIndicator { protected final DiscoveryClient discoveryClient; @@ -64,6 +67,7 @@ protected void doHealthCheck(Health.Builder builder) { 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)) @@ -77,6 +81,12 @@ 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(); } } @@ -99,4 +109,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..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 @@ -10,25 +10,45 @@ 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.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) class GatewayHealthIndicatorTest { + @Mock + private DiscoveryClient discoveryClient; + + private GatewayHealthIndicator healthIndicator; + + @BeforeEach + void setUp() { + this.healthIndicator = new GatewayHealthIndicator(discoveryClient, CoreService.API_CATALOG.getServiceId()); + } + private DefaultServiceInstance getDefaultServiceInstance(String serviceId, String hostname, int port) { return new DefaultServiceInstance( hostname + ":" + serviceId + ":" + port, @@ -40,13 +60,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 +77,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 +89,25 @@ 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); + 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 +115,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 +122,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)); @@ -115,4 +132,31 @@ void whenHealthRequested_onceLogMessageAboutStartup() { } + @Nested + class WhenHAIsNotComplete { + + @Mock + private ApimlLogger apimlLogger; + + @BeforeEach + void setUp() { + ReflectionTestUtils.setField(healthIndicator, "apimlLog", apimlLogger); + } + + @Test + void whenHealthRequested_skipLog() { + 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); + } + + } + }