Merge "Include returned attributes in Decision"
[policy/xacml-pdp.git] / applications / optimization / src / test / java / org / onap / policy / xacml / pdp / application / optimization / OptimizationPdpApplicationTest.java
index e593d5f..9c92294 100644 (file)
@@ -2,7 +2,8 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2019-2021 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 package org.onap.policy.xacml.pdp.application.optimization;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 
+import com.att.research.xacml.api.Response;
+import com.google.common.collect.Lists;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.ServiceLoader;
-
+import org.apache.commons.lang3.tuple.Pair;
+import org.assertj.core.api.Condition;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.FixMethodOrder;
@@ -44,16 +48,21 @@ import org.junit.rules.TemporaryFolder;
 import org.junit.runners.MethodSorters;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardYamlCoder;
+import org.onap.policy.common.utils.resources.ResourceUtils;
 import org.onap.policy.common.utils.resources.TextFileUtils;
 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 import org.onap.policy.models.decisions.concepts.DecisionResponse;
-import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate;
 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationException;
 import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider;
 import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
+import org.onap.policy.pdp.xacml.xacmltest.TestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.yaml.snakeyaml.Yaml;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class OptimizationPdpApplicationTest {
@@ -63,7 +72,20 @@ public class OptimizationPdpApplicationTest {
     private static File propertiesFile;
     private static XacmlApplicationServiceProvider service;
     private static StandardCoder gson = new StandardCoder();
-    private static DecisionRequest requestAffinity;
+    private static DecisionRequest baseRequest;
+    private static String[] listPolicyTypeFiles = {
+        "onap.policies.Optimization",
+        "onap.policies.optimization.Resource",
+        "onap.policies.optimization.Service",
+        "onap.policies.optimization.resource.AffinityPolicy",
+        "onap.policies.optimization.resource.DistancePolicy",
+        "onap.policies.optimization.resource.HpaPolicy",
+        "onap.policies.optimization.resource.OptimizationPolicy",
+        "onap.policies.optimization.resource.PciPolicy",
+        "onap.policies.optimization.service.QueryPolicy",
+        "onap.policies.optimization.service.SubscriberPolicy",
+        "onap.policies.optimization.resource.Vim_fit",
+        "onap.policies.optimization.resource.VnfPolicy"};
 
     @ClassRule
     public static final TemporaryFolder policyFolder = new TemporaryFolder();
@@ -78,10 +100,10 @@ public class OptimizationPdpApplicationTest {
         //
         // Load Single Decision Request
         //
-        requestAffinity = gson.decode(
+        baseRequest = gson.decode(
                 TextFileUtils
                     .getTextFileAsString(
-                            "../../main/src/test/resources/decisions/decision.optimization.affinity.input.json"),
+                            "src/test/resources/decision.optimization.input.json"),
                     DecisionRequest.class);
         //
         // Setup our temporary folder
@@ -90,6 +112,15 @@ public class OptimizationPdpApplicationTest {
         propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties",
                 properties, myCreator);
         //
+        // Copy the test policy types into data area
+        //
+        for (String policy : listPolicyTypeFiles) {
+            String policyType = ResourceUtils.getResourceAsString("policytypes/" + policy + ".yaml");
+            LOGGER.info("Copying {}", policyType);
+            Files.write(Paths.get(policyFolder.getRoot().getAbsolutePath(), policy + "-1.0.0.yaml"),
+                    policyType.getBytes());
+        }
+        //
         // Load service
         //
         ServiceLoader<XacmlApplicationServiceProvider> applicationLoader =
@@ -99,7 +130,7 @@ public class OptimizationPdpApplicationTest {
         // the optimization service. Save it for use throughout
         // all the Junit tests.
         //
-        StringBuilder strDump = new StringBuilder("Loaded applications:" + System.lineSeparator());
+        StringBuilder strDump = new StringBuilder("Loaded applications:" + XacmlPolicyUtils.LINE_SEPARATOR);
         Iterator<XacmlApplicationServiceProvider> iterator = applicationLoader.iterator();
         while (iterator.hasNext()) {
             XacmlApplicationServiceProvider application = iterator.next();
@@ -116,24 +147,28 @@ public class OptimizationPdpApplicationTest {
             strDump.append(application.applicationName());
             strDump.append(" supports ");
             strDump.append(application.supportedPolicyTypes());
-            strDump.append(System.lineSeparator());
+            strDump.append(XacmlPolicyUtils.LINE_SEPARATOR);
         }
         LOGGER.debug("{}", strDump);
+        assertThat(service).isNotNull();
         //
         // Tell it to initialize based on the properties file
         // we just built for it.
         //
-        service.initialize(propertiesFile.toPath().getParent());
+        service.initialize(propertiesFile.toPath().getParent(), null);
     }
 
+    /**
+     * Simply test some of the simple methods for the application.
+     */
     @Test
-    public void test1Basics() {
+    public void test01Basics() {
         //
         // Make sure there's an application name
         //
         assertThat(service.applicationName()).isNotEmpty();
         //
-        // Decisions
+        // Does it return the correct decisions
         //
         assertThat(service.actionDecisionsSupported().size()).isEqualTo(1);
         assertThat(service.actionDecisionsSupported()).contains("optimize");
@@ -141,77 +176,327 @@ public class OptimizationPdpApplicationTest {
         // Ensure it has the supported policy types and
         // can support the correct policy types.
         //
-        assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
-                "onap.policies.optimization.AffinityPolicy", "1.0.0"))).isTrue();
-        assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
+        assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
+                "onap.policies.optimization.resource.AffinityPolicy", "1.0.0"))).isTrue();
+        assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
+                "onap.policies.optimization.service.SubscriberPolicy", "1.0.0"))).isTrue();
+        assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
+                "onap.policies.optimization.service.CustomUseCase", "1.0.0"))).isTrue();
+        assertThat(service.canSupportPolicyType(new ToscaConceptIdentifier(
                 "onap.foobar", "1.0.0"))).isFalse();
     }
 
+    /**
+     * With no policies loaded, there should be 0 policies returned.
+     *
+     * @throws CoderException CoderException
+     */
+    @Test
+    public void test02NoPolicies() throws CoderException {
+        //
+        // Ask for a decision when there are no policies loaded
+        //
+        LOGGER.info("Request {}", gson.encode(baseRequest));
+        Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+        LOGGER.info("Decision {}", decision.getKey());
+
+        assertThat(decision.getKey()).isNotNull();
+        assertThat(decision.getKey().getPolicies()).isEmpty();
+        //
+        // Optimization applications should not have this information returned. Except advice
+        // for subscriber details, which does get checked in the tests following.
+        //
+        assertThat(decision.getKey().getAdvice()).isNull();
+        assertThat(decision.getKey().getObligations()).isNull();
+        assertThat(decision.getKey().getAttributes()).isNull();
+    }
+
+    /**
+     * Should return ONLY default policies.
+     *
+     * @throws XacmlApplicationException could not load policies
+     */
     @Test
-    public void test2NoPolicies() {
+    public void test03OptimizationDefault() throws XacmlApplicationException {
         //
-        // Ask for a decision
+        // Now load all the optimization policies
         //
-        DecisionResponse response = service.makeDecision(requestAffinity);
-        LOGGER.info("Decision {}", response);
+        List<ToscaPolicy> loadedPolicies = TestUtils.loadPolicies("src/test/resources/test-optimization-policies.yaml",
+                service);
+        assertThat(loadedPolicies).isNotNull().hasSize(14);
+
+        validateDecisionCount(2);
+    }
+
+    /**
+     * Should only return default HPA policy type.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test04OptimizationDefaultHpa() {
+        //
+        // Add in policy type
+        //
+        List<String> policyTypes = Lists.newArrayList("onap.policies.optimization.resource.HpaPolicy");
+        baseRequest.getResource().put("policy-type", policyTypes);
+        //
+        // Ask for a decision for default HPA policy
+        //
+        DecisionResponse response = makeDecision();
 
         assertThat(response).isNotNull();
-        assertThat(response.getPolicies().size()).isEqualTo(0);
+        assertThat(response.getPolicies()).hasSize(1);
+        response.getPolicies().forEach((key, value) -> {
+            assertThat(((Map<String, Object>) value)).containsEntry("type",
+                            "onap.policies.optimization.resource.HpaPolicy");
+        });
+        //
+        // Validate it
+        //
+        validateDecision(response, baseRequest);
     }
 
+    /**
+     * Refine for US only policies.
+     */
     @SuppressWarnings("unchecked")
     @Test
-    public void test3AddOptimizationPolicies() throws CoderException, FileNotFoundException, IOException,
-        XacmlApplicationException {
+    public void test05OptimizationDefaultGeography() throws CoderException {
         //
-        // Now load the optimization policies
+        // Remove all the policy-type resources from the request
         //
-        try (InputStream is = new FileInputStream("src/test/resources/vCPE.policies.optimization.input.tosca.yaml")) {
-            //
-            // Have yaml parse it
-            //
-            Yaml yaml = new Yaml();
-            Map<String, Object> toscaObject = yaml.load(is);
-            List<Object> policies = (List<Object>) toscaObject.get("policies");
-            //
-            // Sanity check to ensure the policy type and version are supported
-            //
-            for (Object policyObject : policies) {
-                //
-                // Get the contents
-                //
-                Map<String, Object> policyContents = (Map<String, Object>) policyObject;
-                for (Entry<String, Object> entrySet : policyContents.entrySet()) {
-                    LOGGER.info("Entry set {}", entrySet.getKey());
-                    Map<String, Object> policyDefinition = (Map<String, Object>) entrySet.getValue();
-                    //
-                    // Find the type and make sure the engine supports it
-                    //
-                    assertThat(policyDefinition.containsKey("type")).isTrue();
-                    assertThat(service.canSupportPolicyType(
-                            new ToscaPolicyTypeIdentifier(
-                            policyDefinition.get("type").toString(),
-                            policyDefinition.get("version").toString())))
-                        .isTrue();
+        cleanOutResources();
+        //
+        // Add US to the geography list
+        //
+        ((List<String>) baseRequest.getResource().get("geography")).add("US");
+
+        validateDecisionCount(2);
+    }
+
+    /**
+     * Add more refinement for service.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test06OptimizationDefaultGeographyAndService() {
+        //
+        // Add vCPE to the service list
+        //
+        ((List<String>) baseRequest.getResource().get("services")).add("vCPE");
+
+        validateDecisionCount(3);
+    }
+
+    /**
+     * Add more refinement for specific resource.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test07OptimizationDefaultGeographyAndServiceAndResource() {
+        //
+        // Add vG to the resource list
+        //
+        ((List<String>) baseRequest.getResource().get("resources")).add("vG");
+
+        validateDecisionCount(6);
+    }
+
+    /**
+     * Now we need to add in subscriberName in order to get scope for gold.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test08OptimizationGeographyAndServiceAndResourceAndScopeIsGoldSubscriber() {
+        //
+        // Add gold as a scope
+        //
+        ((List<String>) baseRequest.getContext().get("subscriberName")).add("subscriber_a");
+
+        validateDecisionCount(6, 2);
+    }
+
+    /**
+     * Add a subscriber that should be platinum.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test09OptimizationGeographyAndServiceAndResourceAndScopeGoldOrPlatinumSubscriber() {
+        //
+        // Add platinum to the scope list: this is now gold OR platinum
+        //
+        ((List<String>) baseRequest.getResource().get("scope")).remove("gold");
+        ((List<String>) baseRequest.getContext().get("subscriberName")).add("subscriber_x");
+
+        validateDecisionCount(8, 2);
+    }
+
+    /**
+     * Remove gold subscriber, keep the platinum one.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test10OptimizationGeographyAndServiceAndResourceAndScopeNotGoldStillPlatinum() {
+        //
+        // Add gold as a scope
+        //
+        ((List<String>) baseRequest.getResource().get("scope")).remove("gold");
+        ((List<String>) baseRequest.getResource().get("scope")).remove("platinum");
+        ((List<String>) baseRequest.getContext().get("subscriberName")).remove("subscriber_a");
+
+        validateDecisionCount(7);
+    }
+
+    /**
+     * Filter by Affinity policy.
+     */
+    @Test
+    public void test11OptimizationPolicyTypeDefault() {
+        //
+        // Add in policy type
+        //
+        List<String> policyTypes = Lists.newArrayList("onap.policies.optimization.resource.AffinityPolicy");
+        baseRequest.getResource().put("policy-type", policyTypes);
+
+        validateDecisionCount(1);
+    }
+
+    /**
+     * Now filter by HPA policy type.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test12OptimizationPolicyTypeDefault() {
+        //
+        // Add in another policy type
+        //
+        ((List<String>) baseRequest.getResource().get("policy-type"))
+            .add("onap.policies.optimization.resource.HpaPolicy");
+
+        validateDecisionCount(2);
+    }
+
+    @Test
+    public void test999BadSubscriberPolicies() throws Exception {
+        final StandardYamlCoder yamlCoder = new StandardYamlCoder();
+        //
+        // Decode it
+        //
+        String policyYaml = ResourceUtils.getResourceAsString("src/test/resources/bad-subscriber-policies.yaml");
+        //
+        // Serialize it into a class
+        //
+        JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate();
+        ToscaServiceTemplate serviceTemplate = yamlCoder.decode(policyYaml, ToscaServiceTemplate.class);
+        jtst.fromAuthorative(serviceTemplate);
+        //
+        // Make sure all the fields are setup properly
+        //
+        ToscaServiceTemplate completedJtst = jtst.toAuthorative();
+        //
+        // Get the policies
+        //
+        for (Map<String, ToscaPolicy> policies : completedJtst.getToscaTopologyTemplate().getPolicies()) {
+            for (ToscaPolicy policy : policies.values()) {
+                if ("missing-subscriberProperties".equals(policy.getName())) {
+                    assertThatExceptionOfType(XacmlApplicationException.class).isThrownBy(() ->
+                        service.loadPolicy(policy));
+                } else if ("missing-subscriberName".equals(policy.getName())) {
+                    assertThatExceptionOfType(XacmlApplicationException.class).isThrownBy(() ->
+                        service.loadPolicy(policy));
+                } else if ("missing-subscriberRole".equals(policy.getName())) {
+                    assertThatExceptionOfType(XacmlApplicationException.class).isThrownBy(() ->
+                        service.loadPolicy(policy));
                 }
             }
-            //
-            // Load the policies
-            //
-            service.loadPolicies(toscaObject);
-            //
-            // Ask for a decision
-            //
-            DecisionResponse response = service.makeDecision(requestAffinity);
-            LOGGER.info("Decision {}", response);
+        }
+    }
 
-            assertThat(response).isNotNull();
-            assertThat(response.getPolicies().size()).isEqualTo(1);
-            //
-            // Dump it out as Json
-            //
-            LOGGER.info(gson.encode(response));
+    private DecisionResponse makeDecision() {
+        Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+        LOGGER.info("Request Resources {}", baseRequest.getResource());
+        LOGGER.info("Decision {}", decision.getKey());
+        for (Entry<String, Object> entrySet : decision.getKey().getPolicies().entrySet()) {
+            LOGGER.info("Policy {}", entrySet.getKey());
+        }
+        return decision.getKey();
+    }
+
+    private DecisionResponse validateDecisionCount(int expectedPolicyCount) {
+        //
+        // Ask for a decision for default
+        //
+        DecisionResponse response = makeDecision();
+
+        assertThat(response).isNotNull();
+        assertThat(response.getPolicies()).hasSize(expectedPolicyCount);
+        //
+        // Optimization applications should not have this information returned
+        //
+        assertThat(response.getObligations()).isNull();
+        assertThat(response.getAttributes()).isNull();
+        //
+        // Validate it
+        //
+        validateDecision(response, baseRequest);
+
+        return response;
+    }
+
+    private void validateDecisionCount(int expectedPolicyCount, int expectedAdviceCount) {
+        DecisionResponse response = validateDecisionCount(expectedPolicyCount);
+
+        assertThat(response.getAdvice()).hasSize(expectedAdviceCount);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void validateDecision(DecisionResponse decision, DecisionRequest request) {
+        for (Entry<String, Object> entrySet : decision.getPolicies().entrySet()) {
+            LOGGER.info("Decision Returned Policy {}", entrySet.getKey());
+            assertThat(entrySet.getValue()).isInstanceOf(Map.class);
+            Map<String, Object> policyContents = (Map<String, Object>) entrySet.getValue();
+            assertThat(policyContents).containsKey("properties");
+            assertThat(policyContents.get("properties")).isInstanceOf(Map.class);
+            Map<String, Object> policyProperties = (Map<String, Object>) policyContents.get("properties");
+
+            validateMatchable((Collection<String>) request.getResource().get("scope"),
+                    (Collection<String>) policyProperties.get("scope"));
+
+            validateMatchable((Collection<String>) request.getResource().get("services"),
+                    (Collection<String>) policyProperties.get("services"));
+
+            validateMatchable((Collection<String>) request.getResource().get("resources"),
+                    (Collection<String>) policyProperties.get("resources"));
+
+            validateMatchable((Collection<String>) request.getResource().get("geography"),
+                    (Collection<String>) policyProperties.get("geography"));
         }
     }
 
+    private void validateMatchable(Collection<String> requestList, Collection<String> policyProperties) {
+        LOGGER.info("Validating matchable: {} with {}", policyProperties, requestList);
+        //
+        // Null or empty implies '*' - that is any value is acceptable
+        // for this policy.
+        //
+        if (policyProperties == null || policyProperties.isEmpty()) {
+            return;
+        }
+        Condition<String> condition = new Condition<>(
+                requestList::contains,
+                "Request list is contained");
+        assertThat(policyProperties).haveAtLeast(1, condition);
+
+    }
+
+    @SuppressWarnings("unchecked")
+    private void cleanOutResources() {
+        ((List<String>) baseRequest.getResource().get("scope")).clear();
+        ((List<String>) baseRequest.getResource().get("services")).clear();
+        ((List<String>) baseRequest.getResource().get("resources")).clear();
+        ((List<String>) baseRequest.getResource().get("geography")).clear();
+        if (((List<String>) baseRequest.getResource().get("policy-type")) != null) {
+            baseRequest.getResource().remove("policy-type");
+        }
+    }
 }