2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2019-2022 AT&T Intellectual Property. All rights reserved.
4 * Modifications Copyright (C) 2022, 2024 Nordix Foundation.
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 * ============LICENSE_END=========================================================
20 package org.onap.policy.drools.server.restful;
22 import static org.assertj.core.api.Assertions.assertThat;
23 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
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;
28 import jakarta.ws.rs.client.Entity;
29 import jakarta.ws.rs.core.Response;
30 import jakarta.ws.rs.core.Response.Status;
31 import java.io.IOException;
32 import java.nio.file.Files;
33 import java.nio.file.Paths;
34 import java.util.Collections;
35 import java.util.List;
36 import java.util.Properties;
37 import org.apache.commons.lang3.StringUtils;
38 import org.junit.jupiter.api.AfterEach;
39 import org.junit.jupiter.api.BeforeEach;
40 import org.junit.jupiter.api.Test;
41 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
42 import org.onap.policy.common.endpoints.event.comm.bus.NoopTopicFactories;
43 import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
44 import org.onap.policy.common.endpoints.http.client.HttpClient;
45 import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
46 import org.onap.policy.common.endpoints.http.server.HttpServletServer;
47 import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance;
48 import org.onap.policy.common.endpoints.http.server.YamlJacksonHandler;
49 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
50 import org.onap.policy.common.gson.JacksonHandler;
51 import org.onap.policy.common.utils.coder.CoderException;
52 import org.onap.policy.common.utils.coder.StandardCoder;
53 import org.onap.policy.common.utils.logging.LoggerUtils;
54 import org.onap.policy.common.utils.network.NetworkUtil;
55 import org.onap.policy.common.utils.resources.ResourceUtils;
56 import org.onap.policy.drools.lifecycle.ControllerSupport;
57 import org.onap.policy.drools.lifecycle.LifecycleFeature;
58 import org.onap.policy.drools.lifecycle.LifecycleFsm;
59 import org.onap.policy.drools.persistence.SystemPersistenceConstants;
60 import org.onap.policy.drools.system.PolicyControllerConstants;
61 import org.onap.policy.models.pdp.enums.PdpState;
62 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
63 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
66 * REST Lifecycle Manager Test.
68 public class RestLifecycleManagerTest {
69 // Native Drools Policy
70 private static final String EXAMPLE_NATIVE_CONTROLLER_POLICY_NAME = "example.controller";
71 private static final String EXAMPLE_NATIVE_CONTROLLER_POLICY_JSON =
72 "src/test/resources/tosca-policy-native-controller-example.json";
74 private static final String EXAMPLE_NATIVE_ARTIFACT_POLICY_NAME = "example.artifact";
75 private static final String EXAMPLE_NATIVE_ARTIFACT_POLICY_JSON =
76 "src/test/resources/tosca-policy-native-artifact-example.json";
78 private static final String EXAMPLE_OTHER_UNVAL_POLICY_NAME = "other-unvalidated";
79 private static final String EXAMPLE_OTHER_UNVAL_POLICY_JSON =
80 "src/test/resources/tosca-policy-other-unvalidated.json";
82 private static final String EXAMPLE_OTHER_VAL_POLICY_NAME = "other-validated";
83 private static final String EXAMPLE_OTHER_VAL_POLICY_JSON =
84 "src/test/resources/tosca-policy-other-validated.json";
86 private static final String EXAMPLE_OTHER_VAL_ERROR_POLICY_NAME = "other-validation-error";
87 private static final String EXAMPLE_OTHER_VAL_ERROR_POLICY_JSON =
88 "src/test/resources/tosca-policy-other-validation-error.json";
90 private static final String OP_POLICY_NAME_VCPE = "operational.restart";
91 private static final String VCPE_OPERATIONAL_DROOLS_POLICY_JSON =
92 "policies/vCPE.policy.operational.input.tosca.json";
94 public static final String PROM_DEPLOY_REQUESTS_TOTAL_UNDEPLOY_ACCEPTED =
95 "pdpd_policy_deployments_total{state=\"ACTIVE\",operation=\"undeploy\",status=\"SUCCESS\",}";
96 public static final String PDPD_DEPLOY_REQUESTS_TOTAL_DEPLOY_ACCEPTED =
97 "pdpd_policy_deployments_total{state=\"ACTIVE\",operation=\"deploy\",status=\"SUCCESS\",}";
98 public static final String PDPD_DEPLOY_REQUESTS_TOTAL_DEPLOY_DECLINED =
99 "pdpd_policy_deployments_total{state=\"ACTIVE\",operation=\"deploy\",status=\"FAIL\",}";
101 private static final StandardCoder coder = new StandardCoder();
102 private static final ControllerSupport controllerSupport = new ControllerSupport("lifecycle");
104 private LifecycleFsm fsm;
105 private HttpClient client;
111 public void setUp() throws Exception {
113 SystemPersistenceConstants.getManager().setConfigurationDir("target/test-classes");
114 fsm = newFsmInstance();
116 LoggerUtils.setLevel(LoggerUtils.ROOT_LOGGER, "INFO");
117 LoggerUtils.setLevel("org.onap.policy.common.endpoints", "WARN");
118 LoggerUtils.setLevel("org.onap.policy.drools", "INFO");
120 HttpServletServerFactoryInstance.getServerFactory().destroy();
121 HttpClientFactoryInstance.getClientFactory().destroy();
122 PolicyControllerConstants.getFactory().destroy();
124 HttpClientFactoryInstance.getClientFactory().build(
125 BusTopicParams.builder()
126 .clientName("lifecycle")
127 .hostname("localhost")
129 .basePath("policy/pdp/engine/lifecycle")
133 HttpServletServer server =
134 HttpServletServerFactoryInstance.getServerFactory().build("lifecycle", "localhost", 8765, "/",
136 server.setPrometheus("/policy/pdp/engine/lifecycle/metrics");
137 server.setSerializationProvider(
138 String.join(",", JacksonHandler.class.getName(), YamlJacksonHandler.class.getName()));
139 server.addServletClass("/*", RestLifecycleManager.class.getName());
140 server.waitedStart(5000L);
142 assertTrue(NetworkUtil.isTcpPortOpen("localhost", 8765, 5, 10000L));
144 controllerSupport.installArtifact();
146 Properties noopTopicProperties = new Properties();
147 noopTopicProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SOURCE_TOPICS,
148 String.join(",", TestConstants.DCAE_TOPIC, TestConstants.APPC_CL_TOPIC,
149 TestConstants.APPC_LCM_WRITE_TOPIC, TestConstants.SDNR_CL_RSP_TOPIC));
150 noopTopicProperties.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS,
151 String.join(",", TestConstants.APPC_CL_TOPIC, TestConstants.APPC_LCM_READ_TOPIC,
152 TestConstants.POLICY_CL_MGT_TOPIC, TestConstants.SDNR_CL_TOPIC, TestConstants.DCAE_CL_RSP_TOPIC));
153 TopicEndpointManager.getManager().addTopics(noopTopicProperties);
155 client = HttpClientFactoryInstance.getClientFactory().get("lifecycle");
162 public void tearDown() {
165 NoopTopicFactories.getSourceFactory().destroy();
166 NoopTopicFactories.getSinkFactory().destroy();
168 HttpClientFactoryInstance.getClientFactory().destroy();
169 HttpServletServerFactoryInstance.getServerFactory().destroy();
171 PolicyControllerConstants.getFactory().destroy();
172 SystemPersistenceConstants.getManager().setConfigurationDir(null);
177 void testMultiPolicyFlow() throws IOException, CoderException {
178 /* group assignments */
183 /* other resources */
188 /* status interval */
192 /* start up configuration */
194 resourceLists("policyTypes", 2);
195 get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
196 get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
197 get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
199 resourceLists("policies", 0);
200 get("policies/example.controller/1.0.0", Status.NOT_FOUND.getStatusCode());
201 get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode());
203 /* start lifecycle */
205 assertTrue(fsm.start());
207 booleanPut(Status.OK.getStatusCode());
208 assertEquals(PdpState.ACTIVE,
209 HttpClient.getBody(get("state", Status.OK.getStatusCode()), PdpState.class));
211 /* add native controller policy */
213 ToscaPolicy nativeControllerPolicy =
214 getPolicyFromFile(EXAMPLE_NATIVE_CONTROLLER_POLICY_JSON, EXAMPLE_NATIVE_CONTROLLER_POLICY_NAME);
215 booleanPost("policies", toString(nativeControllerPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
217 assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
218 assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
219 assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive());
221 get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
223 resourceLists("policies", 1);
224 get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
226 /* add native artifact policy */
228 ToscaPolicy nativeArtifactPolicy =
229 getPolicyFromFile(EXAMPLE_NATIVE_ARTIFACT_POLICY_JSON, EXAMPLE_NATIVE_ARTIFACT_POLICY_NAME);
230 booleanPost("policies", toString(nativeArtifactPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
232 assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
233 assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
234 assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isAlive());
236 /* verify new supported operational policy types */
238 resourceLists("policyTypes", 5);
239 get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
240 get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
241 get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.OK.getStatusCode());
242 get("policyTypes/onap.policies.type1.type2/1.0.0", Status.OK.getStatusCode());
243 get("policyTypes/onap.policies.typeA/1.0.0", Status.OK.getStatusCode());
245 /* verify controller and artifact policies */
247 resourceLists("policies", 2);
248 get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
249 get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
251 /* add tosca compliant operational policy */
253 ToscaPolicy opPolicy = getExamplesPolicy();
254 opPolicy.getProperties().put("controllerName", "lifecycle");
255 if (StringUtils.isBlank(opPolicy.getName())) {
256 opPolicy.setName("" + opPolicy.getMetadata().get("policy-id"));
258 testNotNativePolicy(opPolicy);
260 /* add tosca policy "other-unvalidated" of policy type "type1.type2" with no attached type schema */
262 testNotNativePolicy(getPolicyFromFile(EXAMPLE_OTHER_UNVAL_POLICY_JSON, EXAMPLE_OTHER_UNVAL_POLICY_NAME));
264 /* add tosca policy "other-validated" of policy type "typeA" with an attached type schema */
266 testNotNativePolicy(getPolicyFromFile(EXAMPLE_OTHER_VAL_POLICY_JSON, EXAMPLE_OTHER_VAL_POLICY_NAME));
268 /* try to add invalid tosca policy "other-validation-error" of policy type "typeA" */
270 ToscaPolicy toscaPolicyValError =
271 getPolicyFromFile(EXAMPLE_OTHER_VAL_ERROR_POLICY_JSON, EXAMPLE_OTHER_VAL_ERROR_POLICY_NAME);
273 listPost(toString(toscaPolicyValError),
274 Status.NOT_ACCEPTABLE.getStatusCode())).isNotEmpty();
276 booleanPost("policies", toString(toscaPolicyValError),
277 Status.NOT_ACCEPTABLE.getStatusCode(), Boolean.FALSE);
279 /* individual deploy/undeploy operations */
281 resourceLists("policies/operations", 3);
283 booleanPost("policies/operations/deployment", toString(opPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
285 PolicyControllerConstants
286 .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class).size());
288 resourceLists("policies", 2);
289 get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
290 get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
291 get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
294 "policies/operations/undeployment", toString(opPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
296 PolicyControllerConstants
297 .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class).size());
299 resourceLists("policies", 2);
300 get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
301 get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
302 get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
304 /* delete native artifact policy */
306 booleanDelete("policies/example.artifact/1.0.0", Status.OK.getStatusCode(), Boolean.TRUE);
307 assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
308 assertFalse(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
310 resourceLists("policyTypes", 2);
311 get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
312 get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
313 get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
314 get("policyTypes/onap.policies.type1.type2/1.0.0", Status.NOT_FOUND.getStatusCode());
315 get("policyTypes/onap.policies.typeA/1.0.0", Status.NOT_FOUND.getStatusCode());
317 resourceLists("policies", 1);
318 get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
319 get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode());
320 get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
322 /* delete native controller policy */
324 booleanDelete("policies/example.controller/1.0.0", Status.OK.getStatusCode(), Boolean.TRUE);
326 resourceLists("policyTypes", 2);
327 get("policyTypes/onap.policies.native.drools.Artifact/1.0.0", Status.OK.getStatusCode());
328 get("policyTypes/onap.policies.native.drools.Controller/1.0.0", Status.OK.getStatusCode());
329 get("policyTypes/onap.policies.controlloop.operational.common.Drools/1.0.0", Status.NOT_FOUND.getStatusCode());
330 get("policyTypes/onap.policies.type1.type2/1.0.0", Status.NOT_FOUND.getStatusCode());
331 get("policyTypes/onap.policies.typeA/1.0.0", Status.NOT_FOUND.getStatusCode());
333 resourceLists("policies", 0);
334 get("policies/" + opPolicy.getName() + "/" + opPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
335 get("policies/example.artifact/1.0.0", Status.NOT_FOUND.getStatusCode());
336 get("policies/example.controller/1.0.0", Status.NOT_FOUND.getStatusCode());
338 assertThatIllegalArgumentException().isThrownBy(() -> PolicyControllerConstants.getFactory().get("lifecycle"));
339 opPolicy.getMetadata().remove("policy-id");
341 listPost(toString(opPolicy),
342 Status.NOT_ACCEPTABLE.getStatusCode())).isNotEmpty();
347 private void testNotNativePolicy(ToscaPolicy toscaPolicy) throws CoderException {
349 listPost(toString(toscaPolicy),
350 Status.OK.getStatusCode())).isEmpty();
352 booleanPost("policies", toString(toscaPolicy), Status.OK.getStatusCode(), Boolean.TRUE);
353 assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").isAlive());
354 assertTrue(PolicyControllerConstants.getFactory().get("lifecycle").getDrools().isBrained());
356 PolicyControllerConstants
357 .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class).size());
359 resourceLists("policies", 3);
360 get("policies/" + toscaPolicy.getName() + "/" + toscaPolicy.getVersion(), Status.OK.getStatusCode());
361 get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
362 get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
364 booleanDelete("policies/" + toscaPolicy.getName() + "/" + toscaPolicy.getVersion(),
365 Status.OK.getStatusCode(), Boolean.TRUE);
367 PolicyControllerConstants
368 .getFactory().get("lifecycle").getDrools().facts("junits", ToscaPolicy.class).size());
370 resourceLists("policies", 2);
371 get("policies/" + toscaPolicy.getName() + "/" + toscaPolicy.getVersion(), Status.NOT_FOUND.getStatusCode());
372 get("policies/example.controller/1.0.0", Status.OK.getStatusCode());
373 get("policies/example.artifact/1.0.0", Status.OK.getStatusCode());
376 private Response get(String contextPath, int statusCode) {
377 Response response = client.get(contextPath);
378 assertEquals(statusCode, response.getStatus());
382 private void booleanResponse(Response response, int statusCode, Boolean bool) {
383 assertEquals(statusCode, response.getStatus());
384 assertEquals(bool, HttpClient.getBody(response, Boolean.class));
387 private void booleanPut(int statusCode) {
388 Response response = client.put("state/ACTIVE", Entity.json(""), Collections.emptyMap());
389 booleanResponse(response, statusCode, Boolean.TRUE);
392 private List<?> listPost(String body, int statusCode) {
393 Response response = client.post("policies/operations/validation", Entity.json(body), Collections.emptyMap());
394 assertEquals(statusCode, response.getStatus());
395 return HttpClient.getBody(response, List.class);
398 private void booleanPost(String contextPath, String body, int statusCode, Boolean bool) {
399 Response response = client.post(contextPath, Entity.json(body), Collections.emptyMap());
400 booleanResponse(response, statusCode, bool);
403 private void booleanDelete(String contextPath, int statusCode, Boolean bool) {
404 Response response = client.delete(contextPath, Collections.emptyMap());
405 booleanResponse(response, statusCode, bool);
408 private void resourceLists(String resource, int size) {
409 Response response = client.get(resource);
410 assertEquals(Status.OK.getStatusCode(), response.getStatus());
411 assertEquals(size, HttpClient.getBody(response, List.class).size());
414 private void status() {
415 Response response = client.put("status/interval/240", Entity.json(""), Collections.emptyMap());
416 assertEquals(Status.OK.getStatusCode(), response.getStatus());
417 assertEquals(Long.valueOf(240L), HttpClient.getBody(response, Long.class));
419 response = client.get("status/interval");
420 assertEquals(Status.OK.getStatusCode(), response.getStatus());
421 assertEquals(Long.valueOf(240L), HttpClient.getBody(response, Long.class));
424 private void topics() {
425 assertEquals(Status.OK.getStatusCode(), client.get("topic/source").getStatus());
426 assertEquals(Status.OK.getStatusCode(), client.get("topic/sink").getStatus());
429 private void properties() {
430 Response response = client.get("properties");
431 assertEquals(Status.OK.getStatusCode(), response.getStatus());
432 assertEquals(fsm.getProperties(), HttpClient.getBody(response, Properties.class));
435 private void subgroup() {
436 Response response = client.put("subgroup/YY", Entity.json(""), Collections.emptyMap());
437 assertEquals(Status.OK.getStatusCode(), response.getStatus());
438 assertEquals("YY", HttpClient.getBody(response, String.class));
440 response = client.get("subgroup");
441 assertEquals(Status.OK.getStatusCode(), response.getStatus());
442 assertEquals("YY", HttpClient.getBody(response, String.class));
445 private void group() {
446 Response response = client.put("group/GG", Entity.json(""), Collections.emptyMap());
447 assertEquals(Status.OK.getStatusCode(), response.getStatus());
448 assertEquals("GG", HttpClient.getBody(response, String.class));
450 response = HttpClientFactoryInstance.getClientFactory().get("lifecycle").get("group");
451 assertEquals(Status.OK.getStatusCode(), response.getStatus());
452 assertEquals("GG", HttpClient.getBody(response, String.class));
455 private void metrics() {
456 Response response = client.get("metrics");
457 assertEquals(Status.OK.getStatusCode(), response.getStatus());
458 String body = HttpClient.getBody(response, String.class);
459 assertThat(body).contains(PROM_DEPLOY_REQUESTS_TOTAL_UNDEPLOY_ACCEPTED);
460 assertThat(body).contains(PDPD_DEPLOY_REQUESTS_TOTAL_DEPLOY_ACCEPTED);
461 assertThat(body).contains(PDPD_DEPLOY_REQUESTS_TOTAL_DEPLOY_DECLINED);
464 private LifecycleFsm newFsmInstance() throws NoSuchFieldException, IllegalAccessException {
465 LifecycleFsm fsm = new LifecycleFsm();
466 ControllerSupport.setStaticField(LifecycleFeature.class, "fsm", fsm);
470 protected ToscaPolicy getPolicyFromFile(String filePath, String policyName) throws CoderException, IOException {
471 String policyJson = Files.readString(Paths.get(filePath));
472 ToscaServiceTemplate serviceTemplate = coder.decode(policyJson, ToscaServiceTemplate.class);
473 return serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).get(policyName);
476 protected String toString(ToscaPolicy policy) throws CoderException {
477 return coder.encode(policy);
480 private ToscaPolicy getExamplesPolicy() throws CoderException {
481 String policyJson = ResourceUtils.getResourceAsString(
482 RestLifecycleManagerTest.VCPE_OPERATIONAL_DROOLS_POLICY_JSON);
483 ToscaServiceTemplate serviceTemplate = new StandardCoder().decode(policyJson, ToscaServiceTemplate.class);
484 return serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).get(
485 RestLifecycleManagerTest.OP_POLICY_NAME_VCPE);