From 3b755ec2e3d9776980236db6ba754ae6b7cc2402 Mon Sep 17 00:00:00 2001 From: Pamela Dragosh Date: Wed, 18 Mar 2020 07:50:22 -0400 Subject: Re-factor matchable to reduce complexity This solution is much cleaner than what is in StdMatchableTranslator. Over 90% code coverage on it - utilizes a callback to retrieve DataType and PolicyTypes. Support for missing timestamp TOSCA type. Also can do a better job differentiating between a property contained in the policy vs a schema. Changed StdMatchableTranslator to utilize these classes. And removed the old spaghetti. Added some JUnit coverage for ToscaPolicyTranslatorUtils. Removed duplicate code in the XACML Native Exception classes. Issue-ID: POLICY-2242 Change-Id: I18f898d9e65f6da28e3b27517d40f8d389de18a0 Signed-off-by: Pamela Dragosh --- .../common/ToscaPolicyTranslatorUtilsTest.java | 25 +- .../common/matchable/MatchablePolicyTypeTest.java | 300 +++++++++++++++++++++ .../common/std/StdMatchableTranslatorTest.java | 2 +- 3 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/matchable/MatchablePolicyTypeTest.java (limited to 'applications/common/src/test/java') diff --git a/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/ToscaPolicyTranslatorUtilsTest.java b/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/ToscaPolicyTranslatorUtilsTest.java index 8b85a0df..5d451e2c 100644 --- a/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/ToscaPolicyTranslatorUtilsTest.java +++ b/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/ToscaPolicyTranslatorUtilsTest.java @@ -27,7 +27,10 @@ import static org.junit.Assert.assertTrue; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; - +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType; import org.junit.Test; public class ToscaPolicyTranslatorUtilsTest { @@ -45,4 +48,24 @@ public class ToscaPolicyTranslatorUtilsTest { assertThat(ToscaPolicyTranslatorUtils.generateTimeInRange("T00:00:00Z", "T08:00:00Z")).isNotNull(); } + @Test + public void testBuildAndAppend() { + assertThat(ToscaPolicyTranslatorUtils.buildAndAppendAllof(null, new MatchType())).isInstanceOf(AnyOfType.class); + assertThat(ToscaPolicyTranslatorUtils.buildAndAppendAllof(null, new AllOfType())).isInstanceOf(AnyOfType.class); + assertThat(ToscaPolicyTranslatorUtils.buildAndAppendAllof(null, new String())).isNull(); + + assertThat(ToscaPolicyTranslatorUtils.buildAndAppendTarget(new TargetType(), + new AnyOfType()).getAnyOf()).hasSize(1); + assertThat(ToscaPolicyTranslatorUtils.buildAndAppendTarget(new TargetType(), + new MatchType()).getAnyOf()).hasSize(1); + assertThat(ToscaPolicyTranslatorUtils.buildAndAppendTarget(new TargetType(), + new String()).getAnyOf()).isEmpty(); + } + + @Test + public void testInteger() { + assertThat(ToscaPolicyTranslatorUtils.parseInteger("foo")).isNull(); + assertThat(ToscaPolicyTranslatorUtils.parseInteger("1")).isEqualTo(1); + assertThat(ToscaPolicyTranslatorUtils.parseInteger("1.0")).isEqualTo(1); + } } diff --git a/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/matchable/MatchablePolicyTypeTest.java b/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/matchable/MatchablePolicyTypeTest.java new file mode 100644 index 00000000..c23f7028 --- /dev/null +++ b/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/matchable/MatchablePolicyTypeTest.java @@ -0,0 +1,300 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdp.xacml.application.common.matchable; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import com.att.research.xacml.api.Identifier; +import com.att.research.xacml.api.XACML3; +import com.att.research.xacml.std.IdentifierImpl; +import com.att.research.xacml.util.XACMLPolicyWriter; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardYamlCoder; +import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.models.tosca.authorative.concepts.ToscaDataType; +import org.onap.policy.models.tosca.authorative.concepts.ToscaEntrySchema; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; +import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType; +import org.onap.policy.models.tosca.authorative.concepts.ToscaProperty; +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.ToscaDictionary; +import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MatchablePolicyTypeTest implements MatchableCallback { + private static final Logger LOGGER = LoggerFactory.getLogger(MatchablePolicyTypeTest.class); + private static final StandardYamlCoder yamlCoder = new StandardYamlCoder(); + private static final String TEST_POLICYTYPE_FILE = "src/test/resources/matchable/onap.policies.Test-1.0.0.yaml"; + private static final String TEST_POLICY_FILE = "src/test/resources/matchable/test.policies.input.tosca.yaml"; + private static final String TEST_POLICYTYPE = "onap.policies.base.middle.Test"; + private static ToscaServiceTemplate testTemplate; + private static ToscaPolicy testPolicy; + + /** + * Loads our resources. + * + * @throws CoderException object + */ + @BeforeClass + public static void setupLoadPolicy() throws CoderException { + // + // Load our test policy type + // + String policyType = ResourceUtils.getResourceAsString(TEST_POLICYTYPE_FILE); + // + // Serialize it into a class + // + ToscaServiceTemplate serviceTemplate = yamlCoder.decode(policyType, ToscaServiceTemplate.class); + // + // Make sure all the fields are setup properly + // + JpaToscaServiceTemplate jtst = new JpaToscaServiceTemplate(); + jtst.fromAuthorative(serviceTemplate); + testTemplate = jtst.toAuthorative(); + // + // Make sure the Policy Types are there + // + assertEquals(3, testTemplate.getPolicyTypes().size()); + assertNotNull(testTemplate.getPolicyTypes().get("onap.policies.Base")); + assertNotNull(testTemplate.getPolicyTypes().get("onap.policies.base.Middle")); + assertNotNull(testTemplate.getPolicyTypes().get(TEST_POLICYTYPE)); + // + // Load our test policy + // + String policy = ResourceUtils.getResourceAsString(TEST_POLICY_FILE); + // + // Serialize it into a class + // + serviceTemplate = yamlCoder.decode(policy, ToscaServiceTemplate.class); + // + // Make sure all the fields are setup properly + // + jtst = new JpaToscaServiceTemplate(); + jtst.fromAuthorative(serviceTemplate); + ToscaServiceTemplate policyTemplate = jtst.toAuthorative(); + assertEquals(1, policyTemplate.getToscaTopologyTemplate().getPolicies().size()); + testPolicy = policyTemplate.getToscaTopologyTemplate().getPolicies().get(0).get("Test.policy"); + assertNotNull(testPolicy); + } + + @Test + public void testAllCodeCoverage() { + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> + new MatchablePolicyType(null, null)); + + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> + new MatchablePropertyTypeMap(null)); + assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> + MatchablePolicyType.isMatchable(null)); + assertThat(MatchablePolicyType.isMatchable(new ToscaProperty())).isFalse(); + // + // Unlikely these would be called - just get code coverage on them + // + ToscaEntrySchema schema = new ToscaEntrySchema(); + schema.setType("integer"); + assertThat(MatchablePolicyType.handlePrimitive("foo", schema)).isNotNull(); + schema.setType("float"); + assertThat(MatchablePolicyType.handlePrimitive("foo", schema)).isNotNull(); + schema.setType("boolean"); + assertThat(MatchablePolicyType.handlePrimitive("foo", schema)).isNotNull(); + schema.setType("timestamp"); + assertThat(MatchablePolicyType.handlePrimitive("foo", schema)).isNotNull(); + schema.setType("footype"); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> + MatchablePolicyType.handlePrimitive("foo", schema) + ); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> + MatchablePolicyType.handlePrimitive("foo", schema) + ); + ToscaProperty toscaProperty = new ToscaProperty(); + Map metadata = new HashMap<>(); + metadata.put("matchable", "true"); + toscaProperty.setMetadata(metadata); + toscaProperty.setType("garbage"); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> + MatchablePolicyType.handlePrimitive("foo", toscaProperty) + ); + Map matchables = null; + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> + MatchablePolicyType.handleList("foo", toscaProperty, matchables, this) + ); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> + MatchablePolicyType.handleMap("foo", toscaProperty, matchables, this) + ); + } + + @Test + public void testPrimitiveValidation() throws Exception { + ToscaProperty property = new ToscaProperty(); + MatchablePropertyTypeBoolean booleanValue = new MatchablePropertyTypeBoolean(property); + assertThat(booleanValue.validate(Boolean.TRUE)).isEqualTo(Boolean.TRUE); + assertThat(booleanValue.validate("no")).isEqualTo(Boolean.FALSE); + assertThat(booleanValue.validate("foo")).isEqualTo(Boolean.FALSE); + + MatchablePropertyTypeInteger integerValue = new MatchablePropertyTypeInteger(property); + assertThat(integerValue.validate("5")).isEqualTo(5); + assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() -> integerValue.validate("foo")); + + MatchablePropertyTypeFloat floatValue = new MatchablePropertyTypeFloat(property); + assertThat(floatValue.validate("5")).isEqualTo(5); + assertThat(floatValue.validate(Float.MIN_NORMAL)).isEqualTo(Float.MIN_NORMAL); + assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() -> floatValue.validate("foo")); + + MatchablePropertyTypeTimestamp timestampValue = new MatchablePropertyTypeTimestamp(property); + assertThat(timestampValue.validate("2018-10-11T22:12:44").getHour()).isEqualTo(22); + assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() -> + timestampValue.validate("foo")); + + ToscaEntrySchema schema = new ToscaEntrySchema(); + schema.setType("string"); + property.setEntrySchema(schema); + MatchablePropertyTypeMap mapValue = new MatchablePropertyTypeMap(property); + assertThat(mapValue.validate(new String("foo"))).hasSize(0); + + MatchablePropertyTypeList listValue = new MatchablePropertyTypeList(property); + assertThat(listValue.validate(new String("foo"))).hasSize(0); + } + + @Test + public void testMatchables() throws ToscaPolicyConversionException { + // + // Step 1: Create matchables from the PolicyType + // + MatchablePolicyType matchablePolicyType = new MatchablePolicyType(testTemplate.getPolicyTypes() + .get(TEST_POLICYTYPE), this); + assertThat(matchablePolicyType).isNotNull(); + assertThat(matchablePolicyType.getPolicyId()).isNotNull(); + assertThat(matchablePolicyType.getPolicyId().getName()).isEqualTo(TEST_POLICYTYPE); + // + // Dump them out to see what we have + // + matchablePolicyType.getMatchables().forEach((matchable, property) -> { + LOGGER.info("matchable: {}: {}", matchable, property); + }); + // + // Sanity check - these are the total possible match types available + // + assertThat(matchablePolicyType.getMatchables()).hasSize(19); + // + // Step 2) Go through example policy and generate data for our Target + // + final TargetType target = new TargetType(); + target.getAnyOf().add(new AnyOfType()); + generateTargetType(target, matchablePolicyType, testPolicy.getProperties()); + // + // Stuff results in a simple Policy + // + final PolicyType policy = new PolicyType(); + policy.setTarget(target); + policy.setPolicyId("foo"); + policy.setVersion("1"); + policy.setRuleCombiningAlgId(XACML3.DENY_UNLESS_PERMIT); + // + // Dump it out so we can see what was created + // + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + XACMLPolicyWriter.writePolicyFile(os, policy); + LOGGER.info("{}", os); + } catch (IOException e) { + LOGGER.error("Failed to create byte array stream", e); + } + // + // Sanity check - the example policy should have each possible match type plus + // an extra one for the list and an extra one for the map. + // + assertThat(policy.getTarget().getAnyOf()).hasSize(20); + } + + @Override + public ToscaPolicyType retrievePolicyType(String derivedFrom) { + for (Entry entrySet : testTemplate.getPolicyTypes().entrySet()) { + if (entrySet.getValue().getName().equals(derivedFrom)) { + return entrySet.getValue(); + } + } + return null; + } + + @Override + public ToscaDataType retrieveDataType(String datatype) { + return testTemplate.getDataTypes().get(datatype); + } + + @SuppressWarnings("unchecked") + private void generateTargetType(TargetType target, MatchablePolicyType matchablePolicyType, + Map properties) throws ToscaPolicyConversionException { + for (Entry entrySet : properties.entrySet()) { + String propertyName = entrySet.getKey(); + Object propertyValue = entrySet.getValue(); + MatchableProperty matchable = matchablePolicyType.get(propertyName); + if (matchable != null) { + Identifier id = new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + propertyName); + Object object = matchable.getType().generate(propertyValue, id); + // + // Depending on what type it is, add it into the target + // + if (object instanceof AnyOfType) { + target.getAnyOf().add((AnyOfType) object); + } else if (object instanceof MatchType) { + AllOfType allOf = new AllOfType(); + allOf.getMatch().add((MatchType) object); + AnyOfType anyOf = new AnyOfType(); + anyOf.getAllOf().add(allOf); + target.getAnyOf().add(anyOf); + } + } else { + // + // Here is the special case where we look for a Collection of values that may + // contain potential matchables + // + if (propertyValue instanceof List) { + for (Object listValue : ((List)propertyValue)) { + if (listValue instanceof Map) { + generateTargetType(target, matchablePolicyType, (Map) listValue); + } + } + } else if (propertyValue instanceof Map) { + generateTargetType(target, matchablePolicyType, (Map) propertyValue); + } + } + } + } +} diff --git a/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslatorTest.java b/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslatorTest.java index 584390cd..1de1d79d 100644 --- a/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslatorTest.java +++ b/applications/common/src/test/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslatorTest.java @@ -160,7 +160,7 @@ public class StdMatchableTranslatorTest { } @Test - public void test() throws CoderException, ToscaPolicyConversionException, ParseException { + public void testMatchableTranslator() throws CoderException, ToscaPolicyConversionException, ParseException { // // Create our translator // -- cgit 1.2.3-korg