* ============LICENSE_START=======================================================
* ONAP
* ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
-import com.att.research.xacml.std.annotations.XACMLAction;
-import com.att.research.xacml.std.annotations.XACMLRequest;
-import com.att.research.xacml.std.annotations.XACMLResource;
-import com.att.research.xacml.std.annotations.XACMLSubject;
-
+import com.att.research.xacml.api.Response;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.sql.Date;
+import java.time.Instant;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import java.util.UUID;
+import javax.persistence.EntityManager;
+import javax.persistence.Persistence;
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.ClassRule;
+import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.junit.runners.MethodSorters;
+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.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.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.application.common.operationshistory.CountRecentOperationsPip;
+import org.onap.policy.pdp.xacml.application.common.operationshistory.Dbao;
+import org.onap.policy.pdp.xacml.xacmltest.TestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class GuardPdpApplicationTest {
+ private static final Logger LOGGER = LoggerFactory.getLogger(GuardPdpApplicationTest.class);
+ private static Properties properties = new Properties();
+ private static File propertiesFile;
+ private static RestServerParameters clientParams = new RestServerParameters();
+ private static XacmlApplicationServiceProvider service;
+ private static DecisionRequest requestVfCount;
+ private static StandardCoder gson = new StandardCoder();
+ private static EntityManager em;
+ private static final String DENY = "Deny";
+ private static final String PERMIT = "Permit";
+
@ClassRule
public static final TemporaryFolder policyFolder = new TemporaryFolder();
/**
- * This is a simple annotation class to simulate
- * requests coming in.
+ * Copies the xacml.properties and policies files into temporary folder and loads the service provider saving
+ * instance of provider off for other tests to use.
*/
- @XACMLRequest(ReturnPolicyIdList = true)
- public class MyXacmlRequest {
+ @BeforeClass
+ public static void setup() throws Exception {
+ LOGGER.info("Setting up class");
+ //
+ // Setup our temporary folder
+ //
+ XacmlPolicyUtils.FileCreator myCreator = (String filename) -> policyFolder.newFile(filename);
+ propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties", properties,
+ myCreator);
+ //
+ // Load service
+ //
+ ServiceLoader<XacmlApplicationServiceProvider> applicationLoader =
+ ServiceLoader.load(XacmlApplicationServiceProvider.class);
+ //
+ // Find the guard service application and save for use in all the tests
+ //
+ StringBuilder strDump = new StringBuilder("Loaded applications:" + XacmlPolicyUtils.LINE_SEPARATOR);
+ Iterator<XacmlApplicationServiceProvider> iterator = applicationLoader.iterator();
+ while (iterator.hasNext()) {
+ XacmlApplicationServiceProvider application = iterator.next();
+ //
+ // Is it our service?
+ //
+ if (application instanceof GuardPdpApplication) {
+ //
+ // Should be the first and only one
+ //
+ assertThat(service).isNull();
+ service = application;
+ }
+ strDump.append(application.applicationName());
+ strDump.append(" supports ");
+ strDump.append(application.supportedPolicyTypes());
+ strDump.append(XacmlPolicyUtils.LINE_SEPARATOR);
+ }
+ LOGGER.info("{}", strDump);
+ //
+ // Tell it to initialize based on the properties file
+ // we just built for it.
+ //
+ service.initialize(propertiesFile.toPath().getParent(), clientParams);
+ //
+ // Load Decision Requests
+ //
+ requestVfCount =
+ gson.decode(TextFileUtils.getTextFileAsString("src/test/resources/requests/guard.vfCount.json"),
+ DecisionRequest.class);
+ //
+ // Create EntityManager for manipulating DB
+ //
+ String persistenceUnit = CountRecentOperationsPip.ISSUER_NAME + ".persistenceunit";
+ em = Persistence
+ .createEntityManagerFactory(GuardPdpApplicationTest.properties.getProperty(persistenceUnit), properties)
+ .createEntityManager();
+ }
- @XACMLSubject(includeInResults = true)
- String onapName = "Drools";
+ /**
+ * Close the entity manager.
+ */
+ @AfterClass
+ public static void cleanup() throws Exception {
+ if (em != null) {
+ em.close();
+ }
+ }
- @XACMLResource(includeInResults = true)
- String resource = "onap.policies.Guard";
+ /**
+ * Clears the database before each test so there are no operations in it.
+ *
+ */
+ @Before
+ public void startClean() throws Exception {
+ em.getTransaction().begin();
+ em.createQuery("DELETE FROM Dbao").executeUpdate();
+ em.getTransaction().commit();
+ }
- @XACMLAction()
- String action = "guard";
+ /**
+ * Check that decision matches expectation.
+ *
+ * @param expected from the response
+ * @param response received
+ *
+ **/
+ public void checkDecision(String expected, DecisionResponse response) throws CoderException {
+ LOGGER.info("Looking for {} Decision", expected);
+ assertThat(response).isNotNull();
+ assertThat(response.getStatus()).isNotNull();
+ assertThat(response.getStatus()).isEqualTo(expected);
+ //
+ // Dump it out as Json
+ //
+ LOGGER.info(gson.encode(response));
}
- @Before
- public void setUp() throws Exception {
+ /**
+ * Request a decision and check that it matches expectation.
+ *
+ * @param request to send to Xacml PDP
+ * @param expected from the response
+ *
+ **/
+ public void requestAndCheckDecision(DecisionRequest request, String expected) throws CoderException {
+ //
+ // Ask for a decision
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(request, null);
+ //
+ // Check decision
+ //
+ checkDecision(expected, decision.getKey());
+ }
+ @Test
+ public void test1Basics() throws CoderException, IOException {
+ LOGGER.info("**************** Running test1Basics ****************");
+ //
+ // Make sure there's an application name
+ //
+ assertThat(service.applicationName()).isNotEmpty();
+ //
+ // Decisions
+ //
+ assertThat(service.actionDecisionsSupported().size()).isEqualTo(1);
+ assertThat(service.actionDecisionsSupported()).contains("guard");
+ //
+ // Ensure it has the supported policy types and
+ // can support the correct policy types.
+ //
+ assertThat(service.supportedPolicyTypes()).isNotEmpty();
+ assertThat(service.supportedPolicyTypes().size()).isEqualTo(4);
+ assertThat(service.canSupportPolicyType(
+ new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.FrequencyLimiter", "1.0.0")))
+ .isTrue();
+ assertThat(service.canSupportPolicyType(
+ new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.FrequencyLimiter", "1.0.1")))
+ .isFalse();
+ assertThat(service.canSupportPolicyType(
+ new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.MinMax", "1.0.0"))).isTrue();
+ assertThat(service.canSupportPolicyType(
+ new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.MinMax", "1.0.1"))).isFalse();
+ assertThat(service.canSupportPolicyType(
+ new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.Blacklist", "1.0.0"))).isTrue();
+ assertThat(service.canSupportPolicyType(
+ new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.Blacklist", "1.0.1"))).isFalse();
+ assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
+ "onap.policies.controlloop.guard.coordination.FirstBlocksSecond", "1.0.0"))).isTrue();
+ assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
+ "onap.policies.controlloop.guard.coordination.FirstBlocksSecond", "1.0.1"))).isFalse();
+ assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier("onap.foo", "1.0.1"))).isFalse();
}
@Test
- public void testBasics() {
- assertThatCode(() -> {
- GuardPdpApplication guard = new GuardPdpApplication();
- //
- // Set the path
- //
- guard.initialize(policyFolder.getRoot().toPath());
- //
- // Application name
- //
- assertThat(guard.applicationName()).isNotEmpty();
- //
- // Decisions
- //
- assertThat(guard.actionDecisionsSupported().size()).isEqualTo(1);
- assertThat(guard.actionDecisionsSupported()).contains("guard");
- //
- // Supported policy types
- //
- assertThat(guard.supportedPolicyTypes()).isNotEmpty();
- assertThat(guard.supportedPolicyTypes().size()).isEqualTo(2);
- assertThat(guard.canSupportPolicyType("onap.policies.controlloop.guard.FrequencyLimiter", "1.0.0"))
- .isTrue();
- assertThat(guard.canSupportPolicyType("onap.policies.controlloop.guard.FrequencyLimiter", "1.0.1"))
- .isFalse();
- assertThat(guard.canSupportPolicyType("onap.policies.controlloop.guard.MinMax", "1.0.0")).isTrue();
- assertThat(guard.canSupportPolicyType("onap.policies.controlloop.guard.MinMax", "1.0.1")).isFalse();
- assertThat(guard.canSupportPolicyType("onap.foo", "1.0.1")).isFalse();
- }).doesNotThrowAnyException();
+ public void test2NoPolicies() throws CoderException {
+ LOGGER.info("**************** Running test2NoPolicies ****************");
+ assertThatCode(() -> requestAndCheckDecision(requestVfCount, PERMIT)).doesNotThrowAnyException();
+ }
+
+ @Test
+ public void test3FrequencyLimiter()
+ throws CoderException, FileNotFoundException, IOException, XacmlApplicationException {
+ LOGGER.info("**************** Running test3FrequencyLimiter ****************");
+ //
+ // Now load the vDNS frequency limiter Policy - make sure
+ // the pdp can support it and have it load
+ // into the PDP.
+ //
+ List<ToscaPolicy> loadedPolicies =
+ TestUtils.loadPolicies("policies/vDNS.policy.guard.frequencylimiter.input.tosca.yaml", service);
+ assertThat(loadedPolicies).hasSize(1);
+ assertThat(loadedPolicies.get(0).getName()).isEqualTo("guard.frequency.scaleout");
+ //
+ // Zero recent actions: should get permit
+ //
+ requestAndCheckDecision(requestVfCount, PERMIT);
+ //
+ // Add entry into operations history DB
+ //
+ insertOperationEvent(requestVfCount);
+ //
+ // Two recent actions, more than specified limit of 2: should get deny
+ //
+ requestAndCheckDecision(requestVfCount, DENY);
}
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test4MinMax() throws CoderException, FileNotFoundException, IOException, XacmlApplicationException {
+ LOGGER.info("**************** Running test4MinMax ****************");
+ //
+ // Now load the vDNS min max Policy - make sure
+ // the pdp can support it and have it load
+ // into the PDP.
+ //
+ List<ToscaPolicy> loadedPolicies =
+ TestUtils.loadPolicies("policies/vDNS.policy.guard.minmaxvnfs.input.tosca.yaml", service);
+ assertThat(loadedPolicies).hasSize(1);
+ assertThat(loadedPolicies.get(0).getName()).isEqualTo("guard.minmax.scaleout");
+ //
+ // vfcount=0 below min of 1: should get a Permit
+ //
+ requestAndCheckDecision(requestVfCount, PERMIT);
+ //
+ // vfcount=1 between min of 1 and max of 2: should get a Permit
+ //
+ ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("vfCount", 1);
+ requestAndCheckDecision(requestVfCount, PERMIT);
+ //
+ // vfcount=2 hits the max of 2: should get a Deny
+ //
+ ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("vfCount", 2);
+ requestAndCheckDecision(requestVfCount, DENY);
+ //
+ // vfcount=3 above max of 2: should get a Deny
+ //
+ ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("vfCount", 3);
+ requestAndCheckDecision(requestVfCount, DENY);
+ //
+ // Insert entry into operations history DB - to indicate a successful
+ // VF Module Create.
+ //
+ insertOperationEvent(requestVfCount);
+ //
+ // vfcount=1 between min of 1 and max of 2; MinMax should succeed,
+ // BUT the frequency limiter should fail
+ //
+ ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("vfCount", 1);
+ requestAndCheckDecision(requestVfCount, DENY);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test5Blacklist() throws CoderException, XacmlApplicationException {
+ LOGGER.info("**************** Running test5Blacklist ****************");
+ //
+ // Load the blacklist policy in with the others.
+ //
+ List<ToscaPolicy> loadedPolicies =
+ TestUtils.loadPolicies("policies/vDNS.policy.guard.blacklist.input.tosca.yaml", service);
+ assertThat(loadedPolicies).hasSize(1);
+ assertThat(loadedPolicies.get(0).getName()).isEqualTo("guard.blacklist.scaleout");
+ //
+ // vfcount=0 below min of 1: should get a Permit because target is NOT blacklisted
+ //
+ requestAndCheckDecision(requestVfCount, PERMIT);
+ //
+ // vfcount=1 between min of 1 and max of 2: change the
+ //
+ ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("target",
+ "the-vfmodule-where-root-is-true");
+ //
+ // vfcount=0 below min of 1: should get a Deny because target IS blacklisted
+ //
+ requestAndCheckDecision(requestVfCount, DENY);
+ //
+ // vfcount=1 between min of 1 and max of 2: change the
+ //
+ ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("target",
+ "another-vfmodule-where-root-is-true");
+ //
+ // vfcount=0 below min of 1: should get a Deny because target IS blacklisted
+ //
+ requestAndCheckDecision(requestVfCount, DENY);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void insertOperationEvent(DecisionRequest request) {
+ //
+ // Get the properties
+ //
+ Map<String, Object> properties = (Map<String, Object>) request.getResource().get("guard");
+ assertThat(properties).isNotNull();
+ //
+ // Add an entry
+ //
+ Dbao newEntry = new Dbao();
+ newEntry.setActor(properties.get("actor").toString());
+ newEntry.setOperation(properties.get("operation").toString());
+ newEntry.setClosedLoopName(properties.get("clname").toString());
+ newEntry.setOutcome("SUCCESS");
+ newEntry.setStarttime(Date.from(Instant.now().minusMillis(20000)));
+ newEntry.setEndtime(Date.from(Instant.now()));
+ newEntry.setRequestId(UUID.randomUUID().toString());
+ newEntry.setTarget(properties.get("target").toString());
+ LOGGER.info("Inserting {}", newEntry);
+ em.getTransaction().begin();
+ em.persist(newEntry);
+ em.getTransaction().commit();
+ }
+
}