/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The SF licenses this file * to you under the Apache License, Version 2.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-2.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 org.apache.sling.hc.core.impl.executor; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.MockitoAnnotations.initMocks; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.sling.hc.api.HealthCheck; import org.apache.sling.hc.api.Result; import org.apache.sling.hc.api.execution.HealthCheckExecutionResult; import org.apache.sling.hc.util.HealthCheckMetadata; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; public class HealthCheckResultCacheTest { private static final int HC_TIMEOUT_NOT_SET = -1; private static final int DUR_1_MIN = 60 * 1000; private static final int DUR_2_MIN = 2 * DUR_1_MIN; private static final int DUR_3_MIN = 3 * DUR_1_MIN; private static final int DUR_4_MIN = 4 * DUR_1_MIN; private HealthCheckResultCache healthCheckResultCache = new HealthCheckResultCache(); @Mock ServiceReference serviceRef; @Before public void setup() { initMocks(this); } private HealthCheckMetadata setupHealthCheckMetadata(long id, long ttl) { reset(serviceRef); doReturn(id).when(serviceRef).getProperty(Constants.SERVICE_ID); doReturn(ttl).when(serviceRef).getProperty(HealthCheck.RESULT_CACHE_TTL_IN_MS); doReturn("HC id="+id).when(serviceRef).getProperty(HealthCheck.NAME); return new HealthCheckMetadata(serviceRef); } @Test public void testHealthCheckResultCache() { HealthCheckMetadata hc1 = setupHealthCheckMetadata(1, HC_TIMEOUT_NOT_SET); ExecutionResult executionResult1 = spy(new ExecutionResult(hc1, new Result(Result.Status.OK, "result for hc1"), 1)); doReturn(new Date(new Date().getTime() - DUR_1_MIN)).when(executionResult1).getFinishedAt(); healthCheckResultCache.updateWith(executionResult1); HealthCheckMetadata hc2 = setupHealthCheckMetadata(2, HC_TIMEOUT_NOT_SET); ExecutionResult executionResult2 = spy(new ExecutionResult(hc2, new Result(Result.Status.OK, "result for hc2"), 1)); doReturn(new Date(new Date().getTime() - DUR_3_MIN)).when(executionResult2).getFinishedAt(); healthCheckResultCache.updateWith(executionResult2); HealthCheckMetadata hc3 = setupHealthCheckMetadata(3, DUR_4_MIN); ExecutionResult executionResult3 = spy(new ExecutionResult(hc3, new Result(Result.Status.OK, "result for hc3"), 1)); doReturn(new Date(new Date().getTime() - DUR_3_MIN)).when(executionResult3).getFinishedAt(); healthCheckResultCache.updateWith(executionResult3); HealthCheckMetadata hc4 = setupHealthCheckMetadata(4, HC_TIMEOUT_NOT_SET); // no result for this yet List<HealthCheckMetadata> hcList = new ArrayList<HealthCheckMetadata>(Arrays.asList(hc1,hc2,hc3,hc4)); List<HealthCheckExecutionResult> results = new ArrayList<HealthCheckExecutionResult>(); healthCheckResultCache.useValidCacheResults(hcList, results, DUR_2_MIN); assertTrue(hcList.contains(hc2)); // result too old, left in hcList for later execution assertTrue(hcList.contains(hc4)); // no result was added to cache via updateWith() assertTrue(results.contains(executionResult1)); // true <= result one min old, global timeout 2min assertFalse(results.contains(executionResult2)); // false <= result three min old, global timeout 2min assertTrue(results.contains(executionResult3)); // true <= result one three old, HC timeout 4min // values not found in cache are left in hcList assertEquals(2, hcList.size()); assertEquals(2, results.size()); } @Test public void testHealthCheckResultCacheTtl() { //-- test cache miss due to HC TTL HealthCheckMetadata hcWithTtl = setupHealthCheckMetadata(1, DUR_1_MIN); ExecutionResult executionResult = spy(new ExecutionResult(hcWithTtl, new Result(Result.Status.OK, "result for hc"), 1)); doReturn(new Date(new Date().getTime() - DUR_2_MIN)).when(executionResult).getFinishedAt(); healthCheckResultCache.updateWith(executionResult); HealthCheckExecutionResult result = healthCheckResultCache.getValidCacheResult(hcWithTtl, DUR_3_MIN); assertNull(result); // even though global timeout would be ok (2min<3min, the hc timeout of 1min invalidates the result) //-- test cache hit due to HC TTL hcWithTtl = setupHealthCheckMetadata(2, DUR_3_MIN); executionResult = spy(new ExecutionResult(hcWithTtl, new Result(Result.Status.OK, "result for hc"), 1)); doReturn(new Date(new Date().getTime() - DUR_2_MIN)).when(executionResult).getFinishedAt(); healthCheckResultCache.updateWith(executionResult); result = healthCheckResultCache.getValidCacheResult(hcWithTtl, DUR_1_MIN); assertEquals(executionResult, result); // even though global timeout would invalidate this result (1min<2min, the hc timeout of 3min allows the result) //-- test Long.MAX_VALUE hcWithTtl = setupHealthCheckMetadata(3, Long.MAX_VALUE); executionResult = spy(new ExecutionResult(hcWithTtl, new Result(Result.Status.OK, "result for hc"), 1)); doReturn(new Date(new Date().getTime() - DUR_4_MIN)).when(executionResult).getFinishedAt(); healthCheckResultCache.updateWith(executionResult); result = healthCheckResultCache.getValidCacheResult(hcWithTtl, DUR_1_MIN); assertEquals(executionResult, result); } }