/* * Copyright 2013, The Sporting Exchange Limited * * Licensed under the Apache License, Version 3.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-3.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.betfair.cougar.health; import com.betfair.cougar.api.ContainerContext; import com.betfair.cougar.api.LogExtension; import com.betfair.cougar.api.LoggableEvent; import com.betfair.cougar.api.RequestContext; import com.betfair.cougar.api.RequestUUID; import com.betfair.cougar.api.ServiceInfo; import com.betfair.cougar.api.geolocation.GeoLocationDetails; import com.betfair.cougar.api.security.IdentityChain; import com.betfair.cougar.core.impl.DefaultTimeConstraints; import com.betfair.cougar.health.service.v3.HealthService; import com.betfair.cougar.health.service.v3.enumerations.HealthStatus; import com.betfair.cougar.health.service.v3.enumerations.RestrictedHealthStatus; import com.betfair.cougar.health.service.v3.exception.HealthException; import com.betfair.cougar.health.service.v3.to.HealthDetailResponse; import com.betfair.cougar.health.service.v3.to.HealthSummaryResponse; import com.betfair.cougar.health.service.v3.to.SubComponentStatus; import com.betfair.cougar.logging.CougarLoggingUtils; import org.slf4j.LoggerFactory; import com.betfair.tornjak.monitor.ActiveMethodMonitor; import com.betfair.tornjak.monitor.ErrorCountingPolicy; import com.betfair.tornjak.monitor.Monitor; import com.betfair.tornjak.monitor.MonitorRegistry; import com.betfair.tornjak.monitor.Status; import com.betfair.tornjak.monitor.StatusAggregator; import com.betfair.tornjak.monitor.StatusChangeListener; import com.betfair.tornjak.monitor.active.Check; import com.betfair.tornjak.monitor.service.InOutServiceMonitor; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class HealthServiceImplTest { private HealthServiceImpl impl; private HealthService service; private HealthService otherService; private MonitorRegistry monitorRegistry; private ContainerContext containerContext; private SavingRequestContext requestContext; private InOutServiceMonitor inOutServiceMonitor; @BeforeClass public static void suppressLogs() { CougarLoggingUtils.suppressAllRootLoggerOutput(); } @Before public void before() throws IOException { monitorRegistry = mock(MonitorRegistry.class); impl = new HealthServiceImpl(); containerContext = mock(ContainerContext.class); when(containerContext.getMonitorRegistry()).thenReturn(monitorRegistry); impl.init(containerContext); service = impl; inOutServiceMonitor = new InOutServiceMonitor(new File("service.status")); inOutServiceMonitor.setInService(true); when(monitorRegistry.getMonitorSet()).thenReturn(monitors(inOutServiceMonitor)); otherService = mock(HealthService.class); requestContext = new SavingRequestContext(); } private static Set<Monitor> monitors(Monitor... monitors) { final Map<Monitor, Integer> monitorIndexes = new HashMap<>(); for (int i=0; i<monitors.length; i++) { monitorIndexes.put(monitors[i], i); } Set<Monitor> ret = new TreeSet<>(new Comparator<Monitor>() { @Override public int compare(Monitor o1, Monitor o2) { return monitorIndexes.get(o1) - monitorIndexes.get(o2); } }); ret.addAll(Arrays.asList(monitors)); return ret; } @Test public void isHealthy_Disabled() throws HealthException, IOException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()) }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.OK)); inOutServiceMonitor.setInService(false); HealthSummaryResponse response = service.isHealthy(requestContext, DefaultTimeConstraints.NO_CONSTRAINTS); response.validateMandatory(); assertEquals(RestrictedHealthStatus.FAIL, response.getHealthy()); } @Test public void isHealthy_Ok() throws HealthException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()) }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.OK)); HealthSummaryResponse response = getResponse(); assertEquals(RestrictedHealthStatus.OK, response.getHealthy()); } @Test public void isHealthy_Warn() throws HealthException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()) }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.WARN)); HealthSummaryResponse response = getResponse(); assertEquals(RestrictedHealthStatus.OK, response.getHealthy()); } @Test public void isHealthy_Fail() throws HealthException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()) }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.FAIL)); HealthSummaryResponse response = getResponse(); assertEquals(RestrictedHealthStatus.FAIL, response.getHealthy()); } @Test public void getDetailedHealthStatus_OutOfService_NoOtherSubComponents() throws HealthException, IOException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()) }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.OK)); inOutServiceMonitor.setInService(false); HealthDetailResponse response = service.getDetailedHealthStatus(requestContext, DefaultTimeConstraints.NO_CONSTRAINTS); response.validateMandatory(); assertEquals(HealthStatus.OUT_OF_SERVICE, response.getHealth()); assertEquals(1, response.getSubComponentList().size()); } @Test public void getDetailedHealthStatus_Ok_NoOtherSubComponents() throws HealthException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()) }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.OK)); HealthDetailResponse response = service.getDetailedHealthStatus(requestContext, DefaultTimeConstraints.NO_CONSTRAINTS); response.validateMandatory(); assertEquals(HealthStatus.OK, response.getHealth()); assertEquals(1, response.getSubComponentList().size()); } @Test public void getDetailedHealthStatus_Ok_OtherSubComponents() throws HealthException, IOException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()), otherServiceInfo() }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.OK)); inOutServiceMonitor.setInService(true); DefaultMonitor otherMonitor = new DefaultMonitor("Fred", Status.OK); when(monitorRegistry.getMonitorSet()).thenReturn(monitors(inOutServiceMonitor, otherMonitor)); HealthDetailResponse response = service.getDetailedHealthStatus(requestContext, DefaultTimeConstraints.NO_CONSTRAINTS); response.validateMandatory(); assertEquals(HealthStatus.OK, response.getHealth()); List<SubComponentStatus> subComponents = response.getSubComponentList(); assertEquals(2, subComponents.size()); assertEquals(HealthStatus.OK, subComponents.get(0).getStatus()); assertEquals("InOutServiceMonitor", subComponents.get(0).getName()); assertEquals(HealthStatus.OK, subComponents.get(1).getStatus()); assertEquals("Fred", subComponents.get(1).getName()); } @Test public void getDetailedHealthStatus_Warn_WithSubComponents() throws HealthException, IOException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()), otherServiceInfo() }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.WARN)); inOutServiceMonitor.setInService(true); DefaultMonitor otherMonitor = new DefaultMonitor("Fred", Status.OK); when(monitorRegistry.getMonitorSet()).thenReturn(monitors(inOutServiceMonitor, otherMonitor)); HealthDetailResponse response = service.getDetailedHealthStatus(requestContext, DefaultTimeConstraints.NO_CONSTRAINTS); response.validateMandatory(); assertEquals(HealthStatus.WARN, response.getHealth()); List<SubComponentStatus> subComponents = response.getSubComponentList(); assertEquals(2, subComponents.size()); assertEquals(HealthStatus.OK, subComponents.get(0).getStatus()); assertEquals("InOutServiceMonitor", subComponents.get(0).getName()); assertEquals(HealthStatus.OK, subComponents.get(1).getStatus()); assertEquals("Fred", subComponents.get(1).getName()); } @Test public void getDetailedHealthStatus_Fail_WithSubComponents() throws HealthException, IOException { when(containerContext.getRegisteredServices()).thenReturn(new ServiceInfo[] { new ServiceInfo(null, service, "HealthService", "3.0", new ArrayList<String>()), otherServiceInfo() }); when(monitorRegistry.getStatusAggregator()).thenReturn(new DefaultStatusAggregator(Status.FAIL)); inOutServiceMonitor.setInService(true); DefaultMonitor otherMonitor = new DefaultMonitor("Fred", Status.OK); when(monitorRegistry.getMonitorSet()).thenReturn(monitors(inOutServiceMonitor, otherMonitor)); HealthDetailResponse response = service.getDetailedHealthStatus(requestContext, DefaultTimeConstraints.NO_CONSTRAINTS); response.validateMandatory(); assertEquals(HealthStatus.FAIL, response.getHealth()); List<SubComponentStatus> subComponents = response.getSubComponentList(); assertEquals(2, subComponents.size()); assertEquals(HealthStatus.OK, subComponents.get(0).getStatus()); assertEquals("InOutServiceMonitor", subComponents.get(0).getName()); assertEquals(HealthStatus.OK, subComponents.get(1).getStatus()); assertEquals("Fred", subComponents.get(1).getName()); } private HealthSummaryResponse getResponse() throws HealthException { HealthSummaryResponse response = service.isHealthy(requestContext, DefaultTimeConstraints.NO_CONSTRAINTS); response.validateMandatory(); return response; } private ServiceInfo otherServiceInfo() { List<String> operations = new ArrayList<>(); operations.add("isHealthy"); operations.add("getDetailedHealthStatus"); return new ServiceInfo(null, otherService, "OtherService", "1.0", operations); } private class DefaultMonitor implements ActiveMethodMonitor { private String name; private Status status; private DefaultMonitor(String name, Status status) { this.name = name; this.status = status; } @Override public void success() { throw new UnsupportedOperationException(); } @Override public void failure(Throwable throwable) { throw new UnsupportedOperationException(); } @Override public void failure(String s) { throw new UnsupportedOperationException(); } @Override public ErrorCountingPolicy getErrorCountingPolicy() { throw new UnsupportedOperationException(); } @Override public Check getActiveMonitor() { throw new UnsupportedOperationException(); } @Override public Status getMaxImpactToOverallStatus() { throw new UnsupportedOperationException(); } @Override public String getName() { return name; } @Override public void addStatusChangeListener(StatusChangeListener statusChangeListener) { throw new UnsupportedOperationException(); } @Override public void removeStatusChangeListener(StatusChangeListener statusChangeListener) { throw new UnsupportedOperationException(); } @Override public Status getStatus() { return status; } } private class DefaultStatusAggregator implements StatusAggregator { private Status status; private DefaultStatusAggregator(Status status) { this.status = status; } @Override public void addStatusChangeListener(StatusChangeListener statusChangeListener) { throw new UnsupportedOperationException(); } @Override public void removeStatusChangeListener(StatusChangeListener statusChangeListener) { throw new UnsupportedOperationException(); } @Override public Status getStatus() { return status; } } private class SavingRequestContext implements RequestContext { @Override public void addEventLogRecord(LoggableEvent record) { } @Override public RequestUUID getRequestUUID() { return null; } @Override public void setRequestLogExtension(LogExtension extension) { } @Override public void setConnectedObjectLogExtension(LogExtension extension) { } @Override public LogExtension getConnectedObjectLogExtension() { return null; } @Override public void trace(String msg, Object... args) { } @Override public GeoLocationDetails getLocation() { return null; } @Override public IdentityChain getIdentity() { return null; } @Override public Date getReceivedTime() { return null; } @Override public Date getRequestTime() { return null; } @Override public boolean traceLoggingEnabled() { return false; } @Override public int getTransportSecurityStrengthFactor() { return 0; } @Override public boolean isTransportSecure() { return false; } } }