Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Built out ability to validate meta field names from xml files against filters using ExtractionTest #203

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
153 changes: 153 additions & 0 deletions src/test/java/emissary/test/core/ExtractionTest.java
Expand Up @@ -4,9 +4,12 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -53,6 +56,8 @@ public static Collection<?> data() {

protected String resource;

protected ArrayList<String> filterList = new ArrayList<>();

/**
* Called by the Parameterized Runner
*/
Expand Down Expand Up @@ -214,6 +219,16 @@ protected void checkAnswers(Element el, IBaseDataObject payload, List<IBaseDataO
assertEquals("Broken status in " + tname, broke, payload.isBroken() ? "true" : "false");
}

// Check for Filter to validate against and see if it exists
Element filters = el.getChild("filters");
if (filters != null && !filters.getChildren().isEmpty()) {
int filtersCount = filters.getChildren().size();
for (int i = 1; i <= filtersCount; i++) {
String filterPath = filters.getChildText("filter" + i);
assertTrue(filterPath + " could not be found. Make sure path and filter exist.", findFilter(filterPath));
}
}

// Check specified metadata
for (Element meta : el.getChildren("meta")) {
String key = meta.getChildTextTrim("name");
Expand Down Expand Up @@ -290,7 +305,20 @@ protected void checkStringValue(Element meta, String data, String tname) {
String key = meta.getChildTextTrim("name");
String value = meta.getChildText("value");
String matchMode = "equals";
boolean validateField = false;
Attribute mm = meta.getAttribute("matchMode");
Attribute vf = meta.getAttribute("validateField");

if (vf != null) {
validateField = Boolean.parseBoolean(vf.getValue());
}

// meta validateField must be set to true to validate against LogFilter
// this is currently set to false unless explicitly set to true in .xml
// see method validateFieldInLogFilter() below for more info
if (validateField) {
validateFieldInFilter(key, tname);
}

if (value == null) {
return; // checking the value is optional
Expand Down Expand Up @@ -330,6 +358,131 @@ protected void checkStringValue(Element meta, String data, String tname) {
}
}

/**
* Method to validate a meta key name against fields/params within Filter .cfg files. Currently, this is set to NOT RUN
* unless the meta field specifies it in the .xml file like: meta validateField="true"
*
* Along with this, filter paths must be passed through the .xml within the answers section. This is demonstrated within
* the TestValidateFieldExtractionTest.xml file within resources/emissary/test/core
*
* @param key the current meta key name to validate against LogFilter
* @param tname the current test name
*/
protected void validateFieldInFilter(String key, String tname) {
// config properties to check
String blacklistField = "BLACKLIST_FIELD";
String extraParam = "EXTRA_PARAM";
String extraTldParam = "EXTRA_TLD_PARAM";
// config prefix properties to check
String extraPrefix = "EXTRA_PREFIX";
String extraTldPrefix = "EXTRA_TLD_PREFIX";
// prefix initialization
String prefix;

// check all files in filterList to validate field against
for (int i = 0; i < filterList.size(); i++) {
try {
// initialize current filter variables
String filterPath = filterList.get(i);
int shortenToName = filterPath.lastIndexOf(".");
String filterName = filterPath.substring(shortenToName + 1);

// set-up stream and readers for current filter file
InputStream is = Class.forName(filterPath).getResourceAsStream(filterName + ".cfg");
assert is != null;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);

// Run through current filter with reader
while (reader.ready()) {
String currentLine = reader.readLine();
// if line is commented out, go to next line without check
if (!currentLine.startsWith("#")) {
// check if EXTRA_PARAM = "*" is defined
// if yes, pass validation
if (currentLine.equals("EXTRA_PARAM = \"*\"")) {
logger.debug("In {}: {} validated by EXTRA_PARAM = \"*\".", filterName, key);
reader.close();
isr.close();
is.close();
return;
}
// check if BLACKLIST_FIELD, EXTRA_PARAM, or EXTRA_TLD_PARAM = passed key (meta name)
else if (currentLine.contains(blacklistField) || currentLine.contains(extraParam)
|| currentLine.contains(extraTldParam)) {
if (currentLine.contains(key)) {
logger.debug("In {}: {} is found and validated.", filterName, key);
reader.close();
isr.close();
is.close();
return;
}
}
// check if a prefix is defined in either EXTRA_PREFIX or EXTRA_TLD_PREFIX
// if prefix is defined and key has matching prefix, pass validation
else if (currentLine.contains(extraPrefix) || currentLine.contains(extraTldPrefix)) {
// cut string down to be just the prefix in quotations
int preStart = currentLine.indexOf("\"") + 1;
int preEnd = currentLine.length() - 1;
prefix = currentLine.substring(preStart, preEnd);
if (key.startsWith(prefix)) {
logger.debug("In {}: Parameter Prefix is found. {} validated", filterName, key);
reader.close();
isr.close();
is.close();
return;
}
}
}
}
// meta name not validated by current filter, log this information
if ((i + 1) == filterList.size()) {
logger.debug("{} not found in {}.", key, filterName);
} else {
logger.debug("{} not found in {}. Moving to next file.", key, filterName);
}
// close InputSteam, InputStreamReader, and BufferedReader
reader.close();
isr.close();
is.close();
} catch (Exception e) {
// if NullPointerException is thrown, it is b/c end of file is reached
// this should result in nothing happening.
// however, if another error occurred, it should be output to the log
if (!e.toString().contains("NullPointerException")) {
if ((i + 1) < filterList.size()) {
logger.warn("Error while validating {}", key, e);
} else {
logger.warn("Error while validating {}. Moving to next file.", key, e);
}
}
}
}
// if loops through all files and cannot find matching field/param for key, then validation fails
if (filterList.isEmpty()) {
fail("No filters were passed to validate against from " + tname);
} else {
fail(tname + " - Field \"" + key + "\" not found in Filter: " + filterList);
}

}

/**
* Find filter by seeing if resource for class can be found. If filter cannot be found, error will be thrown from
* checkAnswers. If filter is found, add filterPath to filterList
*
* @param filterPath - filter path passed from xml
* @return boolean for if filter is found
*/
protected boolean findFilter(String filterPath) {
try (InputStream ignored = Class.forName(filterPath).getResourceAsStream(filterPath + ".cfg")) {
filterList.add(filterPath);
return true;
} catch (ClassNotFoundException | IOException e) {
return false;
}
}

protected void setupPayload(IBaseDataObject payload, Document doc) {
kff.hash(payload);
Element root = doc.getRootElement();
Expand Down
116 changes: 115 additions & 1 deletion src/test/java/emissary/test/core/TestExtractionTest.java
@@ -1,9 +1,14 @@
package emissary.test.core;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import emissary.place.IServiceProviderPlace;
import org.jdom2.Document;
Expand Down Expand Up @@ -46,9 +51,118 @@ void testCheckStringValueForCollectionFailure() throws JDOMException, IOExceptio

Element meta = answerDoc.getRootElement().getChild("answers").getChild("meta");

assertThrows(AssertionError.class, () -> test.checkStringValue(meta, "7;0;0;0;2;1", "testCheckStringValueForCollection"));
assertThrows(AssertionError.class, () -> test.checkStringValue(meta, "7;0;0;0;2;1", "testCheckStringValueForCollectionFailure"));
}

/**
* Attempts to find filters. Adds given filter to filterList if found. Validates both individual filters return result,
* as well as final filterList count.
*/
@Test
void testFindFilter() throws IOException {
WhyDoYouMakeMeDoThisExtractionTest test = new WhyDoYouMakeMeDoThisExtractionTest("nonsense");

// verify boolean "result" from findFilter() is returning correctly
assertTrue(test.findFilter("emissary.output.filter.DataFilter"), "DataFilter should be found.");
assertTrue(test.findFilter("emissary.output.filter.JsonOutputFilter"), "JsonOutputFilter should be found.");
assertFalse(test.findFilter("this.should.not.be.found"), "This filter should not be found.");
assertFalse(test.findFilter("DataFilter"), "Should return false since path not provided.");

sambish5 marked this conversation as resolved.
Show resolved Hide resolved
// verify only found filters paths are added to filterList, should be 2 in this case
assertEquals(2, test.filterList.size(), "filterList<InputStream> should have size 2.");
}

/**
* No filter is added to filterList, so validation of meta names should FAIL.
*/
@Test
void testValidateFieldWithNoFilter() throws IOException, JDOMException {
// Try to validate field with no filter, should FAIL
SAXBuilder builder = new SAXBuilder(org.jdom2.input.sax.XMLReaders.NONVALIDATING);
String resourceName = "/emissary/test/core/TestValidateFieldExtractionTest.xml";
InputStream inputStream = TestExtractionTest.class.getResourceAsStream(resourceName);
assertNotNull(inputStream, "Could not locate: " + resourceName);
Document answerDoc = builder.build(inputStream);
inputStream.close();

WhyDoYouMakeMeDoThisExtractionTest test = new WhyDoYouMakeMeDoThisExtractionTest("nonsense");

// put all children of <answers> into a List<> to loop through
List<Element> children = answerDoc.getRootElement().getChild("answers").getChildren();
for (Element meta : children) {
try {
test.checkStringValue(meta, "1;2;3;4;5", "testCheckValidateField");
} catch (AssertionError e) {
logger.info(e.toString());
// ignore as this is expected.
}
}
}

/**
* Filter is added to list to validate against, but filter does not validate meta names. This should FAIL.
*/
@Test
void testValidateFieldWithNonValidatingFilter() throws IOException, JDOMException {
// Try to validate field with no filter, should FAIL
SAXBuilder builder = new SAXBuilder(org.jdom2.input.sax.XMLReaders.NONVALIDATING);
String resourceName = "/emissary/test/core/TestValidateFieldExtractionTest.xml";
InputStream inputStream = TestExtractionTest.class.getResourceAsStream(resourceName);
assertNotNull(inputStream, "Could not locate: " + resourceName);
Document answerDoc = builder.build(inputStream);
inputStream.close();

WhyDoYouMakeMeDoThisExtractionTest test = new WhyDoYouMakeMeDoThisExtractionTest("nonsense");

test.findFilter("emissary.output.filter.DataFilter");

// put all children of <answers> into a List<> to loop through
List<Element> children = answerDoc.getRootElement().getChild("answers").getChildren();
for (Element meta : children) {
try {
test.checkStringValue(meta, "1;2;3;4;5", "testCheckValidateField");
} catch (AssertionError e) {
logger.info(e.toString());
// ignore as this is expected.
}
}
}

/**
* Passes multiple filter to findFilter() then tries to validate meta names against filters. Validates found filters
* return true from findFilter(). Validates only filters that return true are added to filterList Validates
* validateFieldInFilter does not fail when even one filter in list validates meta names
*
* this.filter.not.real: non-existent filter - XmlOutputFilter: real filter, will not validate - JsonOutputFilter: real
* filter, will validate
*/
@Test
void testCheckValidateField() throws IOException, JDOMException {
SAXBuilder builder = new SAXBuilder(org.jdom2.input.sax.XMLReaders.NONVALIDATING);
String resourceName = "/emissary/test/core/TestValidateFieldExtractionTest.xml";
InputStream inputStream = TestExtractionTest.class.getResourceAsStream(resourceName);
assertNotNull(inputStream, "Could not locate: " + resourceName);
Document answerDoc = builder.build(inputStream);
inputStream.close();

WhyDoYouMakeMeDoThisExtractionTest test = new WhyDoYouMakeMeDoThisExtractionTest("nonsense");

// Add Filter to list to validate against
assertFalse(test.findFilter("this.filter.not.real"));
assertTrue(test.findFilter("emissary.output.filter.XmlOutputFilter"));
assertTrue(test.findFilter("emissary.output.filter.JsonOutputFilter"));

// verify only found filters paths are added to filterList, should be 2 in this case
assertEquals(2, test.filterList.size(), "filterList should have size 2.");

// put all children of <answers> into a List<> to loop through
List<Element> children = answerDoc.getRootElement().getChild("answers").getChildren();
for (Element meta : children) {
test.checkStringValue(meta, "1;2;3;4;5", "testCheckValidateField");
}
}


public static class WhyDoYouMakeMeDoThisExtractionTest extends ExtractionTest {

public WhyDoYouMakeMeDoThisExtractionTest(String crazy) throws IOException {
Expand Down
@@ -0,0 +1,18 @@
<result>
<answers>
<filters>
<filter1>emissary.output.filter.JsonOutputFilter</filter1>
<filter2>emissary.output.filter.DataFilter</filter2>
</filters>
<meta validateField="true">
<name>CHECKSUM_MD5</name>
</meta>
<meta matchMode="collection" seperator=";" validateField="true">
<name>NAMESPACE</name>
<value>1;2;3;4;5</value>
</meta>
<meta>
<name>ValidateFieldFalse</name>
</meta>
</answers>
</result>