* ============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;
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 {
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();
//
// 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
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 =
// 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();
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");
// 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");
+ }
+ }
}