2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019,2022 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2024 Nordix Foundation.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.drools.healthcheck;
24 import static org.junit.jupiter.api.Assertions.assertEquals;
25 import static org.junit.jupiter.api.Assertions.assertFalse;
26 import static org.junit.jupiter.api.Assertions.assertTrue;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.Mockito.doAnswer;
29 import static org.mockito.Mockito.doThrow;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.spy;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
36 import java.io.IOException;
37 import java.nio.file.Paths;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Properties;
41 import org.eclipse.jetty.http.HttpStatus;
42 import org.junit.jupiter.api.AfterAll;
43 import org.junit.jupiter.api.BeforeAll;
44 import org.junit.jupiter.api.Test;
45 import org.kie.api.builder.ReleaseId;
46 import org.mockito.AdditionalAnswers;
47 import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
48 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
49 import org.onap.policy.common.utils.logging.LoggerUtils;
50 import org.onap.policy.common.utils.network.NetworkUtil;
51 import org.onap.policy.drools.healthcheck.HealthCheck.Reports;
52 import org.onap.policy.drools.persistence.SystemPersistenceConstants;
53 import org.onap.policy.drools.properties.DroolsPropertyConstants;
54 import org.onap.policy.drools.system.PolicyController;
55 import org.onap.policy.drools.system.PolicyControllerConstants;
56 import org.onap.policy.drools.system.PolicyEngineConstants;
57 import org.onap.policy.drools.util.KieUtils;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
61 public class HealthCheckFeatureTest {
63 private static final Logger logger = LoggerFactory.getLogger(HealthCheckFeatureTest.class);
64 private static final String EXPECTED = "expected exception";
70 public static void setup() throws IOException {
71 SystemPersistenceConstants.getManager().setConfigurationDir("target/test-classes");
73 LoggerUtils.setLevel("org.onap.policy.common.endpoints", "WARN");
74 LoggerUtils.setLevel("org.eclipse", "ERROR");
75 LoggerUtils.setLevel("org.onap.policy.drools.healthcheck", "DEBUG");
76 LoggerUtils.setLevel("ROOT", "INFO");
78 ReleaseId coords = KieUtils.installArtifact(Paths.get("src/test/resources/echo.kmodule").toFile(),
79 Paths.get("src/test/resources/echo.pom").toFile(),
80 "src/main/resources/kbecho/org/onap/policy/drools/healthcheck/",
81 List.of(Paths.get("src/test/resources/echo.drl").toFile()));
83 Properties controllerProps = new Properties();
84 controllerProps.put(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, "echo");
85 controllerProps.put(DroolsPropertyConstants.RULES_GROUPID, coords.getGroupId());
86 controllerProps.put(DroolsPropertyConstants.RULES_ARTIFACTID, coords.getArtifactId());
87 controllerProps.put(DroolsPropertyConstants.RULES_VERSION, coords.getVersion());
89 PolicyController controller = PolicyControllerConstants.getFactory().build("echo", controllerProps);
97 public static void teardown() {
98 PolicyControllerConstants.getFactory().destroy();
99 HttpClientFactoryInstance.getClientFactory().destroy();
100 HttpServletServerFactoryInstance.getServerFactory().destroy();
104 void test() throws InterruptedException {
105 var manager = spy(HealthCheckManager.class);
106 var feature = new HealthCheckFeatureImpl(manager);
107 when(manager.isEngineAlive()).thenReturn(true);
109 feature.afterStart(PolicyEngineConstants.getManager());
110 feature.afterOpen(PolicyEngineConstants.getManager());
115 var reports = healthcheck(manager);
116 serverChecks(reports);
117 checkReports(reports, List.of("STUCK"),
118 HttpStatus.OK_200, HttpStatus.getMessage(200));
119 checkReports(reports, List.of("echo"), 1, "[echo:{java.lang.String=1}]");
121 /* mock controller and clients stuck */
123 RestMockHealthCheck.stuck = true; // make the server named STUCK unresponsive
124 doAnswer(AdditionalAnswers
125 .answersWithDelay((manager.getTimeoutSeconds() + 2) * 1000L,
126 invocationOnMock -> new HashMap<String, Integer>()))
127 .when(manager).getFactTypes(any(), any());
129 reports = healthcheck(manager);
130 RestMockHealthCheck.stuck = false; // unstuck the server named STUCK
132 serverChecks(reports);
133 checkReports(reports, List.of("STUCK"),
134 HealthCheckManager.TIMEOUT_CODE, HealthCheckManager.TIMEOUT_MESSAGE);
136 assertTrue(RestMockHealthCheck.WAIT * 1000 > HealthCheckManagerTest.select(reports, "STUCK",
137 HealthCheckManager.TIMEOUT_CODE, HealthCheckManager.TIMEOUT_MESSAGE)
138 .get(0).getElapsedTime());
140 feature.afterShutdown(PolicyEngineConstants.getManager());
143 private void checkReports(Reports reports, List<String> reportNames, int code, String message) {
145 .forEach(name -> assertEquals(1,
146 HealthCheckManagerTest.select(reports, name, code, message).size()));
149 private Reports healthcheck(HealthCheck manager) {
150 var reports = manager.healthCheck();
151 logger.info("{}", reports);
155 private void checkOpen(int port) throws InterruptedException {
156 if (!NetworkUtil.isTcpPortOpen("localhost", port, 5, 10000L)) {
157 throw new IllegalStateException("cannot connect to port " + port);
161 private void serverChecks(Reports reports) {
162 checkReports(reports, List.of("HEALTHCHECK", "LIVENESS"),
163 HttpStatus.OK_200, HttpStatus.getMessage(200));
164 checkReports(reports, List.of("UNAUTH"),
165 HttpStatus.UNAUTHORIZED_401, HttpStatus.getMessage(401));
166 checkReports(reports, List.of(HealthCheckManager.ENGINE_NAME),
167 HealthCheckManager.SUCCESS_CODE, HealthCheckManager.ENABLED_MESSAGE);
171 void testGetSequenceNumber() {
172 assertEquals(1000, new HealthCheckFeature().getSequenceNumber());
176 void testAfterStart() {
177 HealthCheck checker = mock(HealthCheck.class);
178 HealthCheckFeature feature = new HealthCheckFeatureImpl(checker);
181 assertFalse(feature.afterStart(null));
182 verify(checker).start();
183 verify(checker, never()).stop();
186 doThrow(new IllegalStateException(EXPECTED)).when(checker).start();
187 assertFalse(feature.afterStart(null));
191 void testAfterOpen() {
192 HealthCheck checker = mock(HealthCheck.class);
193 HealthCheckFeature feature = new HealthCheckFeatureImpl(checker);
196 assertFalse(feature.afterOpen(null));
197 verify(checker).open();
198 verify(checker, never()).stop();
201 doThrow(new IllegalStateException(EXPECTED)).when(checker).open();
202 assertFalse(feature.afterOpen(null));
207 void testAfterShutdown() {
208 HealthCheck checker = mock(HealthCheck.class);
209 HealthCheckFeature feature = new HealthCheckFeatureImpl(checker);
212 assertFalse(feature.afterShutdown(null));
213 verify(checker).stop();
214 verify(checker, never()).start();
217 doThrow(new IllegalStateException(EXPECTED)).when(checker).stop();
218 assertFalse(feature.afterShutdown(null));
222 * Feature that returns a particular monitor.
224 private static class HealthCheckFeatureImpl extends HealthCheckFeature {
225 private final HealthCheck checker;
227 public HealthCheckFeatureImpl(HealthCheck checker) {
228 this.checker = checker;
232 public HealthCheck getManager() {