* ============LICENSE_START=======================================================
* ONAP
* ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
+ Modifications Copyright (C) 2019 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 static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.att.research.xacml.api.Response;
+import com.google.common.collect.Lists;
import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
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.onap.policy.common.endpoints.parameters.RestServerParameters;
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.ToscaPolicy;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
+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;
private static File propertiesFile;
private static XacmlApplicationServiceProvider service;
private static StandardCoder gson = new StandardCoder();
- private static DecisionRequest requestAffinity;
+ private static DecisionRequest baseRequest;
private static RestServerParameters clientParams;
private static String[] listPolicyTypeFiles = {
"onap.policies.Optimization",
- "onap.policies.optimization.AffinityPolicy",
- "onap.policies.optimization.DistancePolicy",
- "onap.policies.optimization.HpaPolicy",
- "onap.policies.optimization.OptimizationPolicy",
- "onap.policies.optimization.PciPolicy",
- "onap.policies.optimization.QueryPolicy",
- "onap.policies.optimization.SubscriberPolicy",
- "onap.policies.optimization.Vim_fit",
- "onap.policies.optimization.VnfPolicy"};
+ "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
service.initialize(propertiesFile.toPath().getParent(), clientParams);
}
+ /**
+ * 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");
// can support the correct policy types.
//
assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
- "onap.policies.optimization.AffinityPolicy", "1.0.0"))).isTrue();
+ "onap.policies.optimization.resource.AffinityPolicy", "1.0.0"))).isTrue();
+ assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
+ "onap.policies.optimization.service.SubscriberPolicy", "1.0.0"))).isTrue();
+ assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
+ "onap.policies.optimization.service.CustomUseCase", "1.0.0"))).isTrue();
assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
"onap.foobar", "1.0.0"))).isFalse();
}
+ /**
+ * With no policies loaded, there should be 0 policies returned.
+ *
+ * @throws CoderException CoderException
+ */
@Test
- public void test2NoPolicies() {
+ public void test02NoPolicies() throws CoderException {
//
- // Ask for a decision
+ // Ask for a decision when there are no policies loaded
//
- Pair<DecisionResponse, Response> decision = service.makeDecision(requestAffinity, null);
+ 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().size()).isEqualTo(0);
}
+ /**
+ * Should return ONLY default policies.
+ *
+ * @throws XacmlApplicationException could not load policies
+ */
+ @Test
+ public void test03OptimizationDefault() throws XacmlApplicationException {
+ //
+ // Now load all the optimization policies
+ //
+ List<ToscaPolicy> loadedPolicies = TestUtils.loadPolicies("src/test/resources/test-optimization-policies.yaml",
+ service);
+ assertThat(loadedPolicies).isNotNull();
+ assertThat(loadedPolicies).hasSize(14);
+ //
+ // Ask for a decision for available default policies
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies().size()).isEqualTo(2);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * 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(1);
+ response.getPolicies().forEach((key, value) -> {
+ assertThat(((Map<String, Object>) value).get("type"))
+ .isEqualTo(("onap.policies.optimization.resource.HpaPolicy"));
+ });
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * Refine for US only policies.
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test05OptimizationDefaultGeography() throws CoderException {
+ //
+ // Remove all the policy-type resources from the request
+ //
+ cleanOutResources();
+ //
+ // Add US to the geography list
+ //
+ ((List<String>) baseRequest.getResource().get("geography")).add("US");
+ //
+ // Ask for a decision for default US Policy
+ //
+ DecisionResponse response = makeDecision();
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies().size()).isEqualTo(2);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * 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");
+ //
+ // Ask for a decision for default US policy for vCPE service
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies().size()).isEqualTo(3);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * 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");
+ //
+ // Ask for a decision for default US service vCPE resource vG policy
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies().size()).isEqualTo(6);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * Now we need to add in subscriberName in order to get scope for gold.
+ */
+ @SuppressWarnings("unchecked")
@Test
- public void test3AddOptimizationPolicies() throws CoderException, FileNotFoundException, IOException,
- XacmlApplicationException {
+ public void test08OptimizationGeographyAndServiceAndResourceAndScopeIsGoldSubscriber() {
+ //
+ // Add gold as a scope
//
- // Now load the optimization policies
+ ((List<String>) baseRequest.getContext().get("subscriberName")).add("subscriber_a");
//
- TestUtils.loadPolicies("src/test/resources/vCPE.policies.optimization.input.tosca.yaml", service);
+ // Ask for a decision for specific US vCPE vG gold
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies()).hasSize(6);
+ assertThat(response.getAdvice()).hasSize(2);
//
- // Ask for a decision
+ // Validate it
//
- Pair<DecisionResponse, Response> decision = service.makeDecision(requestAffinity, null);
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * 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");
+ //
+ // Ask for a decision for specific US vCPE vG (gold or platinum)
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies()).hasSize(8);
+ assertThat(response.getAdvice()).hasSize(2);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * 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");
+ //
+ // Ask for a decision for specific US vCPE vG gold
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies().size()).isEqualTo(7);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * 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);
+ //
+ // Ask for a decision for default
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies().size()).isEqualTo(1);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ /**
+ * 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");
+ //
+ // Ask for a decision for default
+ //
+ DecisionResponse response = makeDecision();
+
+ assertThat(response).isNotNull();
+ assertThat(response.getPolicies().size()).isEqualTo(2);
+ //
+ // Validate it
+ //
+ validateDecision(response, baseRequest);
+ }
+
+ @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
+ //
+ ToscaServiceTemplate serviceTemplate;
+ try {
+ serviceTemplate = yamlCoder.decode(policyYaml, ToscaServiceTemplate.class);
+ } catch (CoderException e) {
+ throw new XacmlApplicationException("Failed to decode policy from resource file", e);
+ }
+ //
+ // Make sure all the fields are setup properly
+ //
+ JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate();
+ jtst.fromAuthorative(serviceTemplate);
+ 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));
+ }
+ }
+ }
+ }
+
+ 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();
+ }
- assertThat(decision.getKey()).isNotNull();
- assertThat(decision.getKey().getPolicies().size()).isEqualTo(4);
+ @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")).isTrue();
+ 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);
//
- // Dump it out as Json
+ // Null or empty implies '*' - that is any value is acceptable
+ // for this policy.
//
- LOGGER.info(gson.encode(decision.getKey()));
+ 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");
+ }
}
}