summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPierre Rioux <pierre.rioux@amdocs.com>2018-09-27 09:38:31 -0400
committerPierre Rioux <pierre.rioux@amdocs.com>2018-10-03 00:31:28 -0400
commit8d9e717828d97237754a3fce252566ad7e8a554e (patch)
tree8d1c5f0800971f2d72286225f713b84d5c959a46 /src
parent1d79514150cb1617af9c11b58bf11ec4e303bbde (diff)
adding dynamic err message support for violations
Change-Id: I80c1a0cade46ef623fce91921449642d8eafb2f6 Issue-ID: LOG-683 Signed-off-by: Pierre Rioux <pierre.rioux@amdocs.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/onap/aai/validation/config/TopicConfig.java11
-rw-r--r--src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java30
-rw-r--r--src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java13
-rw-r--r--src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java92
-rw-r--r--src/main/java/org/onap/aai/validation/ruledriven/rule/RuleResult.java98
-rw-r--r--src/test/java/org/onap/aai/validation/ruledriven/rule/RuleHelper.java13
-rw-r--r--src/test/java/org/onap/aai/validation/ruledriven/rule/TestRuleExecution.java67
7 files changed, 246 insertions, 78 deletions
diff --git a/src/main/java/org/onap/aai/validation/config/TopicConfig.java b/src/main/java/org/onap/aai/validation/config/TopicConfig.java
index 99742ac..ccf5d51 100644
--- a/src/main/java/org/onap/aai/validation/config/TopicConfig.java
+++ b/src/main/java/org/onap/aai/validation/config/TopicConfig.java
@@ -46,13 +46,12 @@ public class TopicConfig {
List<Topic> publisherTopics = new ArrayList<>();
@Autowired
- public TopicConfig (@Value("${consumer.topic.names}") final String consumerNames, @Value("${publisher.topic.names}") final String publisherNames){
-
- consumerTopicNames = Arrays.asList(consumerNames.split(","));;
- publisherTopicNames = Arrays.asList(publisherNames.split(","));;
-
-
+ public TopicConfig (@Value("${consumer.topic.names}") final String consumerNames,
+ @Value("${publisher.topic.names}") final String publisherNames) {
+ consumerTopicNames = Arrays.asList(consumerNames.split(","));
+ publisherTopicNames = Arrays.asList(publisherNames.split(","));
}
+
/**
* Gets the configuration of topics for consumption.
*
diff --git a/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java b/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java
index 476c098..2bc2d90 100644
--- a/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java
+++ b/src/main/java/org/onap/aai/validation/ruledriven/RuleDrivenValidator.java
@@ -21,6 +21,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -49,6 +50,7 @@ import org.onap.aai.validation.ruledriven.configuration.EntitySection;
import org.onap.aai.validation.ruledriven.configuration.GroovyConfigurationException;
import org.onap.aai.validation.ruledriven.configuration.RulesConfigurationLoader;
import org.onap.aai.validation.ruledriven.rule.Rule;
+import org.onap.aai.validation.ruledriven.rule.RuleResult;
/**
* Validator using explicit rules
@@ -159,28 +161,30 @@ public class RuleDrivenValidator implements Validator {
AttributeValues attributeValues = entity.getAttributeValues(rule.getAttributePaths());
// Execute the rule for this particular set of attribute values.
- boolean valid = false;
+ RuleResult result = null;
try {
- valid = rule.execute(attributeValues);
+ result = rule.execute(attributeValues);
} catch (IllegalArgumentException e) {
throw new ValidationServiceException(ValidationServiceError.RULE_EXECUTION_ERROR, e, rule,
attributeValues);
}
applicationLogger.debug(String.format("%s|%s|\"%s\"|%s", entity.getType(), entity.getIds(), rule.getName(),
- valid ? "pass" : "fail"));
+ result.getSuccess() ? "pass" : "fail"));
+
+ if (!result.getSuccess()) {
+ String errorMessage = MessageFormat.format(rule.getErrorMessage(), result.getErrorArguments().toArray());
- if (!valid) {
//@formatter:off
- Violation violation = builder
- .category(rule.getErrorCategory())
- .severity(rule.getSeverity())
- .violationType(ViolationType.RULE)
- .validationRule(rule.getName())
- .violationDetails(attributeValues.generateReport())
- .errorMessage(rule.getErrorMessage())
- .build();
- //@formatter:on
+ Violation violation = builder
+ .category(rule.getErrorCategory())
+ .severity(rule.getSeverity())
+ .violationType(ViolationType.RULE)
+ .validationRule(rule.getName())
+ .violationDetails(attributeValues.generateReport())
+ .errorMessage(errorMessage)
+ .build();
+ //@formatter:on
validationResult.addViolation(violation);
}
diff --git a/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java b/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java
index b151f6b..df15791 100644
--- a/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java
+++ b/src/main/java/org/onap/aai/validation/ruledriven/rule/GroovyRule.java
@@ -125,7 +125,7 @@ public class GroovyRule implements Rule {
* @return
*/
@Override
- public Boolean execute(AttributeValues attributeValues) {
+ public RuleResult execute(AttributeValues attributeValues) {
// Obtain the values of each of the attributes to pass into the rule
List<Object> valueList = new ArrayList<>();
for (String attrName : this.attributePaths) {
@@ -141,10 +141,10 @@ public class GroovyRule implements Rule {
* @param values
*
* @param groovyObject an instance/object of a Groovy class that implements one or more rule methods
- * @return the Boolean result of evaluating the expression
+ * @return the result of evaluating the expression
*/
@Override
- public Boolean execute(Object... values) {
+ public RuleResult execute(Object... values) {
Object result = null;
try {
result = groovyObject.invokeMethod(getRuleMethod(), values);
@@ -153,12 +153,7 @@ public class GroovyRule implements Rule {
} catch (NullPointerException e) {
throw new IllegalArgumentException("Argument is null", e);
}
-
- if (result instanceof Number) {
- return !result.equals(0);
- } else {
- return (Boolean) result;
- }
+ return new RuleResult(result);
}
@Override
diff --git a/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java b/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java
index 1196db0..60705ea 100644
--- a/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java
+++ b/src/main/java/org/onap/aai/validation/ruledriven/rule/Rule.java
@@ -25,57 +25,57 @@ import org.onap.aai.validation.reader.data.AttributeValues;
*/
public interface Rule {
- /**
- * Gets the name of the rule
- *
- * @return the name
- */
- String getName();
+ /**
+ * Gets the name of the rule
+ *
+ * @return the name
+ */
+ String getName();
- /**
- * Gets the error message.
- *
- * @return the error message
- */
- String getErrorMessage();
+ /**
+ * Gets the error message.
+ *
+ * @return the error message
+ */
+ String getErrorMessage();
- /**
- * Gets the error category.
- *
- * @return the error category
- */
- String getErrorCategory();
+ /**
+ * Gets the error category.
+ *
+ * @return the error category
+ */
+ String getErrorCategory();
- /**
- * Gets the severity.
- *
- * @return the severity
- */
- String getSeverity();
+ /**
+ * Gets the severity.
+ *
+ * @return the severity
+ */
+ String getSeverity();
- /**
- * Gets the paths to the attributes to pass to the rule
- *
- * @return the attribute paths
- */
- List<String> getAttributePaths();
+ /**
+ * Gets the paths to the attributes to pass to the rule
+ *
+ * @return the attribute paths
+ */
+ List<String> getAttributePaths();
- /**
- * Execute the rule.
- *
- * @param values
- * the attribute values to pass to the rule
- * @return a boolean representing the rule evaluation (meaning success/failure)
- */
- Boolean execute(AttributeValues values);
+ /**
+ * Execute the rule.
+ *
+ * @param values
+ * the attribute values to pass to the rule
+ * @return a RuleResult instance representing the rule evaluation (meaning success/failure)
+ */
+ RuleResult execute(AttributeValues values);
- /**
- * Execute the rule.
- *
- * @param values
- * the attribute values to pass to the rule
- * @return a boolean representing the rule evaluation (meaning success/failure)
- */
- Boolean execute(Object... values);
+ /**
+ * Execute the rule.
+ *
+ * @param values
+ * the attribute values to pass to the rule
+ * @return a RuleResult instance representing the rule evaluation (meaning success/failure)
+ */
+ RuleResult execute(Object... values);
}
diff --git a/src/main/java/org/onap/aai/validation/ruledriven/rule/RuleResult.java b/src/main/java/org/onap/aai/validation/ruledriven/rule/RuleResult.java
new file mode 100644
index 0000000..19f77f7
--- /dev/null
+++ b/src/main/java/org/onap/aai/validation/ruledriven/rule/RuleResult.java
@@ -0,0 +1,98 @@
+/*
+ * ============LICENSE_START===================================================
+ * Copyright (c) 2018 Amdocs
+ * ============================================================================
+ * 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.
+ * ============LICENSE_END=====================================================
+ */
+package org.onap.aai.validation.ruledriven.rule;
+
+import groovy.lang.Tuple2;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Encapsulates the results of rule execution
+ *
+ */
+public class RuleResult {
+
+ private Boolean success = true;
+ private List<String> errorArguments = Collections.emptyList();
+
+ /**
+ * Creates an instance of this class using the groovy object returned by rule execution.
+ *
+ * Valid object types:
+ * Boolean: true = success; false = fail
+ * Number: 0 = success; non-zero = fail
+ * Tuple2: contains rule result and argument list
+ * - tuple's "first" contains a boolean representing the results of rule execution
+ * - tuple's "second" contains a list of strings used to expand rule error text
+ *
+ * @param groovyResult
+ */
+ public RuleResult(Object groovyResult) {
+ if (groovyResult instanceof Number) {
+ success = !((Number)groovyResult).equals(0);
+ } else if (groovyResult instanceof Tuple2) {
+ handleTuple(groovyResult);
+ } else {
+ success = (Boolean)groovyResult;
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private RuleResult() {
+ // intentionally empty
+ }
+
+ /**
+ * Returns the results of rule execution, i.e. success or fail
+ * @return
+ */
+ public Boolean getSuccess() {
+ return success;
+ }
+
+ /**
+ * Returns the list of arguments used to expand rule error text.
+ *
+ * For example, this errorText in a rule definition:
+ * 'Error found with "{0}" in "{1}"; value "{2}" is not a valid MAC address'
+ *
+ * used with the following runtime argument list:
+ * ["macaddr", "tenants.tenant.vservers.vserver.l-interfaces.l-interface", "02:fd:59:3"]
+ *
+ * would display:
+ * Error found with "macaddr" in "tenants.tenant.vservers.vserver.l-interfaces.l-interface"; value "02:fd:59:3" is not a valid MAC address
+ *
+ * @return a list of strings; will not return null
+ */
+ public List<String> getErrorArguments() {
+ return errorArguments;
+ }
+
+ /**
+ * Handles a Tuple2 object returned by a groovy rule.
+ * The tuple's "first" contains a boolean representing the results of rule execution.
+ * The tuple's "second" contains a list of strings used to expand rule error text.
+ * @param tupleObject
+ */
+ private void handleTuple(Object tupleObject) {
+ @SuppressWarnings("unchecked")
+ Tuple2<Boolean, List<String>> tuple = (Tuple2<Boolean, List<String>>)tupleObject;
+ success = tuple.getFirst();
+ errorArguments = (tuple.getSecond() == null) ? Collections.emptyList() : tuple.getSecond();
+ }
+}
diff --git a/src/test/java/org/onap/aai/validation/ruledriven/rule/RuleHelper.java b/src/test/java/org/onap/aai/validation/ruledriven/rule/RuleHelper.java
index 456d011..c9d6284 100644
--- a/src/test/java/org/onap/aai/validation/ruledriven/rule/RuleHelper.java
+++ b/src/test/java/org/onap/aai/validation/ruledriven/rule/RuleHelper.java
@@ -21,16 +21,23 @@ import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
+import java.text.MessageFormat;
import org.onap.aai.validation.reader.data.AttributeValues;
-import org.onap.aai.validation.ruledriven.rule.Rule;
public class RuleHelper {
static void assertRuleResult(Rule rule, AttributeValues values, Boolean expectedResult) {
- assertThat(rule + " failed for values [" + values + "]", rule.execute(values), is(equalTo(expectedResult)));
+ assertThat(rule + " failed for values [" + values + "]", rule.execute(values).getSuccess(), is(equalTo(expectedResult)));
}
static void assertRuleResult(Rule rule, Object value, Boolean expectedResult) {
- assertThat(rule + " failed for value [" + value + "]", rule.execute(value), is(equalTo(expectedResult)));
+ assertThat(rule + " failed for value [" + value + "]", rule.execute(value).getSuccess(), is(equalTo(expectedResult)));
+ }
+
+ static void assertRuleErrorMessage(Rule rule, Object value, String expectedErrorMessage) {
+ RuleResult result = rule.execute(value);
+ String errorMessage = MessageFormat.format(rule.getErrorMessage(), result.getErrorArguments().toArray());
+ assertThat(rule + " failed to validate error message [" + expectedErrorMessage + "]",
+ errorMessage, is(equalTo(expectedErrorMessage)));
}
}
diff --git a/src/test/java/org/onap/aai/validation/ruledriven/rule/TestRuleExecution.java b/src/test/java/org/onap/aai/validation/ruledriven/rule/TestRuleExecution.java
index 15e958d..426bbb4 100644
--- a/src/test/java/org/onap/aai/validation/ruledriven/rule/TestRuleExecution.java
+++ b/src/test/java/org/onap/aai/validation/ruledriven/rule/TestRuleExecution.java
@@ -34,7 +34,6 @@ import org.junit.rules.ExpectedException;
import org.onap.aai.validation.reader.data.AttributeValues;
import org.onap.aai.validation.ruledriven.configuration.GroovyConfigurationException;
import org.onap.aai.validation.ruledriven.configuration.RuleSection;
-import org.onap.aai.validation.ruledriven.rule.GroovyRule;
/**
* Tests for creating an AuditRule object and then executing the rule expression against fixed attribute values
@@ -82,6 +81,51 @@ public class TestRuleExecution {
}
/**
+ * Simple example of a rule using error message expansion
+ * @throws Exception
+ */
+ @Test
+ public void testRuleErrorTextWithArguments() throws Exception {
+
+ final String errorMessage = "Error message with arguments: {0}, {1}";
+ final String expectedErrorMessage = "Error message with arguments: arg1, arg2";
+
+ String expression = "return new groovy.lang.Tuple2(true, java.util.Arrays.asList(\"arg1\", \"arg2\"))";
+ GroovyRule rule = buildRuleWithErrorMessage("i", expression, errorMessage);
+ assertRuleResult(rule, 1, expectedErrorMessage);
+
+ String expressionOneArgumentTooMany = "return new groovy.lang.Tuple2(true, java.util.Arrays.asList(\"arg1\", \"arg2\", \"arg3\"))";
+ GroovyRule rule3 = buildRuleWithErrorMessage("i", expressionOneArgumentTooMany, errorMessage);
+ assertRuleResult(rule3, 1, expectedErrorMessage);
+
+ String expressionOneLessArgument = "return new groovy.lang.Tuple2(true, java.util.Arrays.asList(\"arg1\"))";
+ GroovyRule rule2 = buildRuleWithErrorMessage("i", expressionOneLessArgument, errorMessage);
+ assertRuleResult(rule2, 1, "Error message with arguments: arg1, {1}");
+ }
+
+ /**
+ * Simple example of a rule using error message expansion, without arguments
+ * @throws Exception
+ */
+ @Test
+ public void testRuleErrorTextWithoutArguments() throws Exception {
+
+ final String errorMessage = "Error message without arguments";
+
+ String expressionWithArgs = "return new groovy.lang.Tuple2(true, java.util.Arrays.asList(\"arg1\", \"arg2\"))";
+ GroovyRule rule = buildRuleWithErrorMessage("i", expressionWithArgs, errorMessage);
+ assertRuleResult(rule, 1, errorMessage);
+
+ String expressionWithoutArgs = "return new groovy.lang.Tuple2(true, java.util.Collections.emptyList())";
+ GroovyRule rule2 = buildRuleWithErrorMessage("i", expressionWithoutArgs, errorMessage);
+ assertRuleResult(rule2, 1, errorMessage);
+
+ String expressionWithNullAsArgs = "return new groovy.lang.Tuple2(true, null)";
+ GroovyRule rule3 = buildRuleWithErrorMessage("i", expressionWithNullAsArgs, errorMessage);
+ assertRuleResult(rule3, 1, errorMessage);
+ }
+
+ /**
* vserver is related to vpe and vserver-name contains me6
*/
@Test
@@ -468,6 +512,18 @@ public class TestRuleExecution {
return new GroovyRule(ruleConfig);
}
+ private GroovyRule buildRuleWithErrorMessage(String name, String attribute, String expression, String errorMessage)
+ throws IOException, InstantiationException, IllegalAccessException, GroovyConfigurationException {
+ RuleSection ruleConfig = new RuleSection();
+ ruleConfig.setName(name);
+ ruleConfig.setAttributes(Collections.singletonList(attribute));
+ ruleConfig.setExpression(expression);
+ if(errorMessage != null) {
+ ruleConfig.setErrorMessage(errorMessage);
+ }
+ return new GroovyRule(ruleConfig);
+ }
+
/**
* Build a simple rule (with a default name) using a RuleConfiguration object
*
@@ -487,8 +543,17 @@ public class TestRuleExecution {
return buildRule("testRule", attributes, expression);
}
+ private GroovyRule buildRuleWithErrorMessage(String attribute, String expression, String errorText)
+ throws InstantiationException, IllegalAccessException, IOException, GroovyConfigurationException {
+ return buildRuleWithErrorMessage("testRule", attribute, expression, errorText);
+ }
+
private void assertRuleResult(GroovyRule rule, Object value, boolean expectedResult) {
RuleHelper.assertRuleResult(rule, value, expectedResult);
}
+ private void assertRuleResult(GroovyRule rule, Object value, String expectedErrorMessage) {
+ RuleHelper.assertRuleErrorMessage(rule, value, expectedErrorMessage);
+ }
+
}