Commit 4907e107 authored by Smitha Manjunath's avatar Smitha Manjunath
Browse files

Added Custom class to enable Logging of Health Endpoint Failures along with unit test for the same

parent d3d8d04e
......@@ -20,7 +20,7 @@
<groupId>org.opengroup.osdu</groupId>
<artifactId>core-lib-azure</artifactId>
<packaging>jar</packaging>
<version>0.10.0-Test1-SNAPSHOT</version>
<version>0.10.0-SNAPSHOT</version>
<name>core-lib-azure</name>
<properties>
......
package org.opengroup.osdu.azure.health;
import org.opengroup.osdu.azure.logging.CoreLoggerFactory;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.CompositeHealth;
import org.springframework.boot.actuate.health.HealthComponent;
import org.springframework.boot.actuate.health.HealthContributorRegistry;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.actuate.health.HealthEndpointWebExtension;
import org.springframework.boot.actuate.health.Status;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
/**
* Implementation for logging features of health check failures.
* All services can pick up this class from core-lib-azure from the usual dependency that’s added.
*/
@Configuration
public class ActuatorHealthLogger extends HealthEndpointWebExtension {
private static final String LOGGER_NAME = ActuatorHealthLogger.class.getName();
/**
*
* @param registry the HealthContributorRegistry
* @param groups the HealthEndpointGroups
*/
public ActuatorHealthLogger(final HealthContributorRegistry registry, final HealthEndpointGroups groups) {
super(registry, groups);
}
/**
*
* @param apiVersion
* @param securityContext
* @param showAll
* @param path
* @return
*/
@Override
public WebEndpointResponse<HealthComponent> health(final ApiVersion apiVersion, final SecurityContext securityContext,
final boolean showAll, final String... path) {
WebEndpointResponse<HealthComponent> response = superClassCall(apiVersion, securityContext, showAll, path);
HealthComponent health = response.getBody();
if (health == null) {
return response;
}
Status status = health.getStatus();
if (status != Status.UP) {
Map<String, HealthComponent> map = ((CompositeHealth) health).getComponents();
for (String label : map.keySet()) {
Status componentStatus = map.get(label).getStatus();
if (componentStatus == Status.DOWN) {
CoreLoggerFactory.getInstance().getLogger(LOGGER_NAME).error("Health component {} has status {}", label, componentStatus);
}
}
}
return response;
}
/**
*
* @param apiVersion the Api Version
* @param securityContext the security Context
* @param showAll the boolean flag
* @param path the path
* @return the webEndpointResponse object
*
* */
protected WebEndpointResponse<HealthComponent> superClassCall(final ApiVersion apiVersion, final SecurityContext securityContext, final boolean showAll, final String... path) {
return super.health(apiVersion, securityContext, showAll, path);
}
}
package org.opengroup.osdu.azure.health;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opengroup.osdu.azure.logging.CoreLogger;
import org.opengroup.osdu.azure.logging.CoreLoggerFactory;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.http.ApiVersion;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.health.CompositeHealth;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthComponent;
import org.springframework.boot.actuate.health.HealthContributorRegistry;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.actuate.health.Status;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests for LoggingHealthEndPointWebExtension.
*/
@ExtendWith(MockitoExtension.class)
public class ActuatorHealthLoggerTest {
private static ActuatorHealthLogger loggingHealthEndpointWebExtension;
private static HealthContributorRegistry registry;
private static HealthEndpointGroups groups;
@Mock
private CoreLoggerFactory coreLoggerFactory;
@Mock
private CoreLogger logger;
/**
* Workaround for inability to mock static methods like getInstance().
*
* @param mock CoreLoggerFactory mock instance
*/
private void mockSingleton(CoreLoggerFactory mock) {
try {
Field instance = CoreLoggerFactory.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, mock);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@BeforeEach
public void setup() {
registry = mock(HealthContributorRegistry.class);
groups = mock(HealthEndpointGroups.class);
}
@Mock
SecurityContext securityContext;
@Mock
Health health;
@Mock
CompositeHealth compositeHealth;
@Test
public void healthTest_whenStatusIs_DOWN()
{
String[] path = new String[0];
mockSingleton(coreLoggerFactory);
when(coreLoggerFactory.getLogger(anyString())).thenReturn(logger);
Mockito.when(health.getStatus()).thenReturn(Status.DOWN);
Map<String, HealthComponent> map = new HashMap<>();
map.put("keyvault",health);
Mockito.when(compositeHealth.getComponents()).thenReturn(map);
WebEndpointResponse<HealthComponent> expected = new WebEndpointResponse<>(compositeHealth,WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);
loggingHealthEndpointWebExtension = new ActuatorHealthLogger(registry, groups) {
@Override
protected WebEndpointResponse<HealthComponent> superClassCall(ApiVersion apiVersion,SecurityContext securityContext,
boolean showAll, String... path) {
return expected;
}
};
WebEndpointResponse<HealthComponent> actual = loggingHealthEndpointWebExtension.health(ApiVersion.LATEST,securityContext,true, path);
verify(logger, times(1)).error(anyString() , any() ,any());
}
@Test
public void healthTest_whenStatusIs_UP()
{
String[] path = new String[0];
Mockito.when(health.getStatus()).thenReturn(Status.UP);
Map<String, HealthComponent> map = new HashMap<>();
map.put("keyvault",health);
Mockito.when(compositeHealth.getComponents()).thenReturn(map);
WebEndpointResponse<HealthComponent> expected = new WebEndpointResponse<>(compositeHealth,WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);
loggingHealthEndpointWebExtension = new ActuatorHealthLogger(registry, groups) {
@Override
protected WebEndpointResponse<HealthComponent> superClassCall(ApiVersion apiVersion,SecurityContext securityContext,
boolean showAll, String... path) {
return expected;
}
};
WebEndpointResponse<HealthComponent> actual = loggingHealthEndpointWebExtension.health(ApiVersion.LATEST,securityContext,true, path);
verify(logger, times(0)).error(anyString() , any() ,any());
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment