http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java new file mode 100644 index 0000000..2e5e90d --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java @@ -0,0 +1,481 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx; + +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.flowfile.attributes.CoreAttributes; +import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.processor.ProcessSession; +import org.apache.nifi.processor.io.OutputStreamCallback; +import org.apache.nifi.processors.evtx.parser.ChunkHeader; +import org.apache.nifi.processors.evtx.parser.FileHeader; +import org.apache.nifi.processors.evtx.parser.FileHeaderFactory; +import org.apache.nifi.processors.evtx.parser.MalformedChunkException; +import org.apache.nifi.processors.evtx.parser.Record; +import org.apache.nifi.processors.evtx.parser.bxml.RootNode; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLStreamException; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ParseEvtxTest { + public static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); + public static final String USER_DATA = "UserData"; + public static final String EVENT_DATA = "EventData"; + public static final Set DATA_TAGS = new HashSet<>(Arrays.asList(EVENT_DATA, USER_DATA)); + + @Mock + FileHeaderFactory fileHeaderFactory; + + @Mock + MalformedChunkHandler malformedChunkHandler; + + @Mock + RootNodeHandlerFactory rootNodeHandlerFactory; + + @Mock + ResultProcessor resultProcessor; + + @Mock + ComponentLog componentLog; + + @Mock + InputStream in; + + @Mock + OutputStream out; + + @Mock + FileHeader fileHeader; + + ParseEvtx parseEvtx; + + @Before + public void setup() throws XMLStreamException, IOException { + parseEvtx = new ParseEvtx(fileHeaderFactory, malformedChunkHandler, rootNodeHandlerFactory, resultProcessor); + when(fileHeaderFactory.create(in, componentLog)).thenReturn(fileHeader); + } + + @Test + public void testGetNameFile() { + String basename = "basename"; + assertEquals(basename + ".xml", parseEvtx.getName(basename, null, null, ParseEvtx.XML_EXTENSION)); + } + + @Test + public void testGetNameFileChunk() { + String basename = "basename"; + assertEquals(basename + "-chunk1.xml", parseEvtx.getName(basename, 1, null, ParseEvtx.XML_EXTENSION)); + } + + @Test + public void testGetNameFileChunkRecord() { + String basename = "basename"; + assertEquals(basename + "-chunk1-record2.xml", parseEvtx.getName(basename, 1, 2, ParseEvtx.XML_EXTENSION)); + } + + @Test + public void testGetBasenameEvtxExtension() { + String basename = "basename"; + FlowFile flowFile = mock(FlowFile.class); + + when(flowFile.getAttribute(CoreAttributes.FILENAME.key())).thenReturn(basename + ".evtx"); + + assertEquals(basename, parseEvtx.getBasename(flowFile, componentLog)); + verifyNoMoreInteractions(componentLog); + } + + @Test + public void testGetBasenameExtension() { + String basename = "basename.wrongextension"; + FlowFile flowFile = mock(FlowFile.class); + ComponentLog componentLog = mock(ComponentLog.class); + + when(flowFile.getAttribute(CoreAttributes.FILENAME.key())).thenReturn(basename); + + assertEquals(basename, parseEvtx.getBasename(flowFile, componentLog)); + verify(componentLog).warn(anyString(), isA(Object[].class)); + } + + @Test + public void testGetRelationships() { + assertEquals(ParseEvtx.RELATIONSHIPS, parseEvtx.getRelationships()); + } + + @Test + public void testGetSupportedPropertyDescriptors() { + assertEquals(ParseEvtx.PROPERTY_DESCRIPTORS, parseEvtx.getSupportedPropertyDescriptors()); + } + + @Test + public void testProcessFileGranularity() throws IOException, MalformedChunkException, XMLStreamException { + String basename = "basename"; + int chunkNum = 5; + int offset = 10001; + byte[] badChunk = {8}; + + RootNodeHandler rootNodeHandler = mock(RootNodeHandler.class); + when(rootNodeHandlerFactory.create(out)).thenReturn(rootNodeHandler); + ChunkHeader chunkHeader1 = mock(ChunkHeader.class); + ChunkHeader chunkHeader2 = mock(ChunkHeader.class); + Record record1 = mock(Record.class); + Record record2 = mock(Record.class); + Record record3 = mock(Record.class); + RootNode rootNode1 = mock(RootNode.class); + RootNode rootNode2 = mock(RootNode.class); + RootNode rootNode3 = mock(RootNode.class); + ProcessSession session = mock(ProcessSession.class); + FlowFile flowFile = mock(FlowFile.class); + AtomicReference<Exception> reference = new AtomicReference<>(); + MalformedChunkException malformedChunkException = new MalformedChunkException("Test", null, offset, chunkNum, badChunk); + + when(record1.getRootNode()).thenReturn(rootNode1); + when(record2.getRootNode()).thenReturn(rootNode2); + when(record3.getRootNode()).thenReturn(rootNode3); + + when(fileHeader.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false); + when(fileHeader.next()).thenThrow(malformedChunkException).thenReturn(chunkHeader1).thenReturn(chunkHeader2).thenReturn(null); + + when(chunkHeader1.hasNext()).thenReturn(true).thenReturn(false); + when(chunkHeader1.next()).thenReturn(record1).thenReturn(null); + + when(chunkHeader2.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); + when(chunkHeader2.next()).thenReturn(record2).thenReturn(record3).thenReturn(null); + + parseEvtx.processFileGranularity(session, componentLog, flowFile, basename, reference, in, out); + + verify(malformedChunkHandler).handle(flowFile, session, parseEvtx.getName(basename, chunkNum, null, ParseEvtx.EVTX_EXTENSION), badChunk); + verify(rootNodeHandler).handle(rootNode1); + verify(rootNodeHandler).handle(rootNode2); + verify(rootNodeHandler).handle(rootNode3); + verify(rootNodeHandler).close(); + } + + @Test + public void testProcessChunkGranularity() throws IOException, MalformedChunkException, XMLStreamException { + String basename = "basename"; + int chunkNum = 5; + int offset = 10001; + byte[] badChunk = {8}; + + RootNodeHandler rootNodeHandler1 = mock(RootNodeHandler.class); + RootNodeHandler rootNodeHandler2 = mock(RootNodeHandler.class); + OutputStream out2 = mock(OutputStream.class); + when(rootNodeHandlerFactory.create(out)).thenReturn(rootNodeHandler1); + when(rootNodeHandlerFactory.create(out2)).thenReturn(rootNodeHandler2); + ChunkHeader chunkHeader1 = mock(ChunkHeader.class); + ChunkHeader chunkHeader2 = mock(ChunkHeader.class); + Record record1 = mock(Record.class); + Record record2 = mock(Record.class); + Record record3 = mock(Record.class); + RootNode rootNode1 = mock(RootNode.class); + RootNode rootNode2 = mock(RootNode.class); + RootNode rootNode3 = mock(RootNode.class); + ProcessSession session = mock(ProcessSession.class); + FlowFile flowFile = mock(FlowFile.class); + FlowFile created1 = mock(FlowFile.class); + FlowFile updated1 = mock(FlowFile.class); + FlowFile created2 = mock(FlowFile.class); + FlowFile updated2 = mock(FlowFile.class); + MalformedChunkException malformedChunkException = new MalformedChunkException("Test", null, offset, chunkNum, badChunk); + + when(session.create(flowFile)).thenReturn(created1).thenReturn(created2).thenReturn(null); + + when(session.write(eq(created1), any(OutputStreamCallback.class))).thenAnswer(invocation -> { + ((OutputStreamCallback) invocation.getArguments()[1]).process(out); + return updated1; + }); + + when(session.write(eq(created2), any(OutputStreamCallback.class))).thenAnswer(invocation -> { + ((OutputStreamCallback) invocation.getArguments()[1]).process(out2); + return updated2; + }); + + when(record1.getRootNode()).thenReturn(rootNode1); + when(record2.getRootNode()).thenReturn(rootNode2); + when(record3.getRootNode()).thenReturn(rootNode3); + + when(fileHeader.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false); + when(fileHeader.next()).thenThrow(malformedChunkException).thenReturn(chunkHeader1).thenReturn(chunkHeader2).thenReturn(null); + + when(chunkHeader1.hasNext()).thenReturn(true).thenReturn(false); + when(chunkHeader1.next()).thenReturn(record1).thenReturn(null); + + when(chunkHeader2.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); + when(chunkHeader2.next()).thenReturn(record2).thenReturn(record3).thenReturn(null); + + parseEvtx.processChunkGranularity(session, componentLog, flowFile, basename, in); + + verify(malformedChunkHandler).handle(flowFile, session, parseEvtx.getName(basename, chunkNum, null, ParseEvtx.EVTX_EXTENSION), badChunk); + verify(rootNodeHandler1).handle(rootNode1); + verify(rootNodeHandler1).close(); + verify(rootNodeHandler2).handle(rootNode2); + verify(rootNodeHandler2).handle(rootNode3); + verify(rootNodeHandler2).close(); + } + + @Test + public void testProcess1RecordGranularity() throws IOException, MalformedChunkException, XMLStreamException { + String basename = "basename"; + int chunkNum = 5; + int offset = 10001; + byte[] badChunk = {8}; + + RootNodeHandler rootNodeHandler1 = mock(RootNodeHandler.class); + RootNodeHandler rootNodeHandler2 = mock(RootNodeHandler.class); + RootNodeHandler rootNodeHandler3 = mock(RootNodeHandler.class); + OutputStream out2 = mock(OutputStream.class); + OutputStream out3 = mock(OutputStream.class); + when(rootNodeHandlerFactory.create(out)).thenReturn(rootNodeHandler1); + when(rootNodeHandlerFactory.create(out2)).thenReturn(rootNodeHandler2); + when(rootNodeHandlerFactory.create(out3)).thenReturn(rootNodeHandler3); + ChunkHeader chunkHeader1 = mock(ChunkHeader.class); + ChunkHeader chunkHeader2 = mock(ChunkHeader.class); + Record record1 = mock(Record.class); + Record record2 = mock(Record.class); + Record record3 = mock(Record.class); + RootNode rootNode1 = mock(RootNode.class); + RootNode rootNode2 = mock(RootNode.class); + RootNode rootNode3 = mock(RootNode.class); + ProcessSession session = mock(ProcessSession.class); + FlowFile flowFile = mock(FlowFile.class); + FlowFile created1 = mock(FlowFile.class); + FlowFile updated1 = mock(FlowFile.class); + FlowFile created2 = mock(FlowFile.class); + FlowFile updated2 = mock(FlowFile.class); + FlowFile created3 = mock(FlowFile.class); + FlowFile updated3 = mock(FlowFile.class); + MalformedChunkException malformedChunkException = new MalformedChunkException("Test", null, offset, chunkNum, badChunk); + + when(session.create(flowFile)).thenReturn(created1).thenReturn(created2).thenReturn(created3).thenReturn(null); + + when(session.write(eq(created1), any(OutputStreamCallback.class))).thenAnswer(invocation -> { + ((OutputStreamCallback) invocation.getArguments()[1]).process(out); + return updated1; + }); + + when(session.write(eq(created2), any(OutputStreamCallback.class))).thenAnswer(invocation -> { + ((OutputStreamCallback) invocation.getArguments()[1]).process(out2); + return updated2; + }); + + when(session.write(eq(created3), any(OutputStreamCallback.class))).thenAnswer(invocation -> { + ((OutputStreamCallback) invocation.getArguments()[1]).process(out3); + return updated3; + }); + + when(record1.getRootNode()).thenReturn(rootNode1); + when(record2.getRootNode()).thenReturn(rootNode2); + when(record3.getRootNode()).thenReturn(rootNode3); + + when(fileHeader.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false); + when(fileHeader.next()).thenThrow(malformedChunkException).thenReturn(chunkHeader1).thenReturn(chunkHeader2).thenReturn(null); + + when(chunkHeader1.hasNext()).thenReturn(true).thenReturn(false); + when(chunkHeader1.next()).thenReturn(record1).thenReturn(null); + + when(chunkHeader2.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); + when(chunkHeader2.next()).thenReturn(record2).thenReturn(record3).thenReturn(null); + + parseEvtx.processRecordGranularity(session, componentLog, flowFile, basename, in); + + verify(malformedChunkHandler).handle(flowFile, session, parseEvtx.getName(basename, chunkNum, null, ParseEvtx.EVTX_EXTENSION), badChunk); + verify(rootNodeHandler1).handle(rootNode1); + verify(rootNodeHandler1).close(); + verify(rootNodeHandler2).handle(rootNode2); + verify(rootNodeHandler2).close(); + verify(rootNodeHandler3).handle(rootNode3); + verify(rootNodeHandler3).close(); + } + + @Test + public void fileGranularityLifecycleTest() throws IOException, ParserConfigurationException, SAXException { + String baseName = "testFileName"; + String name = baseName + ".evtx"; + TestRunner testRunner = TestRunners.newTestRunner(ParseEvtx.class); + testRunner.setProperty(ParseEvtx.GRANULARITY, ParseEvtx.FILE); + Map<String, String> attributes = new HashMap<>(); + attributes.put(CoreAttributes.FILENAME.key(), name); + testRunner.enqueue(this.getClass().getClassLoader().getResourceAsStream("application-logs.evtx"), attributes); + testRunner.run(); + + List<MockFlowFile> originalFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_ORIGINAL); + assertEquals(1, originalFlowFiles.size()); + MockFlowFile originalFlowFile = originalFlowFiles.get(0); + originalFlowFile.assertAttributeEquals(CoreAttributes.FILENAME.key(), name); + originalFlowFile.assertContentEquals(this.getClass().getClassLoader().getResourceAsStream("application-logs.evtx")); + + // We expect the same bad chunks no matter the granularity + List<MockFlowFile> badChunkFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_BAD_CHUNK); + assertEquals(2, badChunkFlowFiles.size()); + badChunkFlowFiles.get(0).assertAttributeEquals(CoreAttributes.FILENAME.key(), parseEvtx.getName(baseName, 1, null, ParseEvtx.EVTX_EXTENSION)); + badChunkFlowFiles.get(1).assertAttributeEquals(CoreAttributes.FILENAME.key(), parseEvtx.getName(baseName, 2, null, ParseEvtx.EVTX_EXTENSION)); + + List<MockFlowFile> failureFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_FAILURE); + assertEquals(1, failureFlowFiles.size()); + validateFlowFiles(failureFlowFiles); + // We expect the same number of records to come out no matter the granularity + assertEquals(960, validateFlowFiles(failureFlowFiles)); + + // Whole file fails if there is a failure parsing + List<MockFlowFile> successFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_SUCCESS); + assertEquals(0, successFlowFiles.size()); + } + + @Test + public void chunkGranularityLifecycleTest() throws IOException, ParserConfigurationException, SAXException { + String baseName = "testFileName"; + String name = baseName + ".evtx"; + TestRunner testRunner = TestRunners.newTestRunner(ParseEvtx.class); + Map<String, String> attributes = new HashMap<>(); + attributes.put(CoreAttributes.FILENAME.key(), name); + testRunner.enqueue(this.getClass().getClassLoader().getResourceAsStream("application-logs.evtx"), attributes); + testRunner.run(); + + List<MockFlowFile> originalFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_ORIGINAL); + assertEquals(1, originalFlowFiles.size()); + MockFlowFile originalFlowFile = originalFlowFiles.get(0); + originalFlowFile.assertAttributeEquals(CoreAttributes.FILENAME.key(), name); + originalFlowFile.assertContentEquals(this.getClass().getClassLoader().getResourceAsStream("application-logs.evtx")); + + // We expect the same bad chunks no matter the granularity + List<MockFlowFile> badChunkFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_BAD_CHUNK); + assertEquals(2, badChunkFlowFiles.size()); + badChunkFlowFiles.get(0).assertAttributeEquals(CoreAttributes.FILENAME.key(), parseEvtx.getName(baseName, 1, null, ParseEvtx.EVTX_EXTENSION)); + badChunkFlowFiles.get(1).assertAttributeEquals(CoreAttributes.FILENAME.key(), parseEvtx.getName(baseName, 2, null, ParseEvtx.EVTX_EXTENSION)); + + List<MockFlowFile> failureFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_FAILURE); + assertEquals(1, failureFlowFiles.size()); + + List<MockFlowFile> successFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_SUCCESS); + assertEquals(8, successFlowFiles.size()); + + // We expect the same number of records to come out no matter the granularity + assertEquals(960, validateFlowFiles(successFlowFiles) + validateFlowFiles(failureFlowFiles)); + } + + @Test + public void recordGranularityLifecycleTest() throws IOException, ParserConfigurationException, SAXException { + String baseName = "testFileName"; + String name = baseName + ".evtx"; + TestRunner testRunner = TestRunners.newTestRunner(ParseEvtx.class); + testRunner.setProperty(ParseEvtx.GRANULARITY, ParseEvtx.RECORD); + Map<String, String> attributes = new HashMap<>(); + attributes.put(CoreAttributes.FILENAME.key(), name); + testRunner.enqueue(this.getClass().getClassLoader().getResourceAsStream("application-logs.evtx"), attributes); + testRunner.run(); + + List<MockFlowFile> originalFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_ORIGINAL); + assertEquals(1, originalFlowFiles.size()); + MockFlowFile originalFlowFile = originalFlowFiles.get(0); + originalFlowFile.assertAttributeEquals(CoreAttributes.FILENAME.key(), name); + originalFlowFile.assertContentEquals(this.getClass().getClassLoader().getResourceAsStream("application-logs.evtx")); + + // We expect the same bad chunks no matter the granularity + List<MockFlowFile> badChunkFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_BAD_CHUNK); + assertEquals(2, badChunkFlowFiles.size()); + badChunkFlowFiles.get(0).assertAttributeEquals(CoreAttributes.FILENAME.key(), parseEvtx.getName(baseName, 1, null, ParseEvtx.EVTX_EXTENSION)); + badChunkFlowFiles.get(1).assertAttributeEquals(CoreAttributes.FILENAME.key(), parseEvtx.getName(baseName, 2, null, ParseEvtx.EVTX_EXTENSION)); + + List<MockFlowFile> failureFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_FAILURE); + assertEquals(0, failureFlowFiles.size()); + + // Whole file fails if there is a failure parsing + List<MockFlowFile> successFlowFiles = testRunner.getFlowFilesForRelationship(ParseEvtx.REL_SUCCESS); + assertEquals(960, successFlowFiles.size()); + + // We expect the same number of records to come out no matter the granularity + assertEquals(960, validateFlowFiles(successFlowFiles)); + } + + private int validateFlowFiles(List<MockFlowFile> successFlowFiles) throws SAXException, IOException, ParserConfigurationException { + assertTrue(successFlowFiles.size() > 0); + int totalSize = 0; + for (MockFlowFile successFlowFile : successFlowFiles) { + // Verify valid XML output + Document document = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().parse(new ByteArrayInputStream(successFlowFile.toByteArray())); + Element documentElement = document.getDocumentElement(); + assertEquals(XmlRootNodeHandler.EVENTS, documentElement.getTagName()); + NodeList eventNodes = documentElement.getChildNodes(); + int length = eventNodes.getLength(); + totalSize += length; + assertTrue(length > 0); + for (int i = 0; i < length; i++) { + Node eventNode = eventNodes.item(i); + assertEquals("Event", eventNode.getNodeName()); + + NodeList eventChildNodes = eventNode.getChildNodes(); + assertEquals(2, eventChildNodes.getLength()); + + Node systemNode = eventChildNodes.item(0); + assertEquals("System", systemNode.getNodeName()); + + NodeList childNodes = systemNode.getChildNodes(); + String userId = ""; + for (int i1 = 0; i1 < childNodes.getLength(); i1++) { + Node systemChild = childNodes.item(i1); + if ("Security".equals(systemChild.getNodeName())) { + userId = systemChild.getAttributes().getNamedItem("UserID").getNodeValue(); + } + } + + Node eventDataNode = eventChildNodes.item(1); + String eventDataNodeNodeName = eventDataNode.getNodeName(); + assertTrue(DATA_TAGS.contains(eventDataNodeNodeName)); + assertTrue(userId.length() == 0 || userId.startsWith("S-")); + } + } + return totalSize; + } +}
http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ResultProcessorTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ResultProcessorTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ResultProcessorTest.java new file mode 100644 index 0000000..117eade --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ResultProcessorTest.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx; + +import com.google.common.net.MediaType; +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.flowfile.attributes.CoreAttributes; +import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.processor.ProcessSession; +import org.apache.nifi.processor.Relationship; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ResultProcessorTest { + Relationship successRelationship; + Relationship failureRelationship; + + ResultProcessor resultProcessor; + + @Before + public void setup() { + successRelationship = new Relationship.Builder().build(); + failureRelationship = new Relationship.Builder().build(); + resultProcessor = new ResultProcessor(successRelationship, failureRelationship); + } + + @Test + public void testProcessResultFileSuccess() { + ProcessSession processSession = mock(ProcessSession.class); + ComponentLog componentLog = mock(ComponentLog.class); + FlowFile flowFile = mock(FlowFile.class); + Exception exception = null; + String name = "basename"; + + when(processSession.putAttribute(eq(flowFile), anyString(), anyString())).thenReturn(flowFile); + + resultProcessor.process(processSession, componentLog, flowFile, exception, name); + verify(processSession).putAttribute(flowFile, CoreAttributes.FILENAME.key(), name); + verify(processSession).putAttribute(flowFile, CoreAttributes.MIME_TYPE.key(), MediaType.APPLICATION_XML_UTF_8.toString()); + verify(processSession).transfer(flowFile, successRelationship); + verifyNoMoreInteractions(componentLog); + } + + @Test + public void testProcessResultFileFalure() { + ProcessSession processSession = mock(ProcessSession.class); + ComponentLog componentLog = mock(ComponentLog.class); + FlowFile flowFile = mock(FlowFile.class); + Exception exception = new Exception(); + String name = "name"; + + when(processSession.putAttribute(eq(flowFile), anyString(), anyString())).thenReturn(flowFile); + + resultProcessor.process(processSession, componentLog, flowFile, exception, name); + verify(processSession).putAttribute(flowFile, CoreAttributes.FILENAME.key(), name); + verify(processSession).putAttribute(flowFile, CoreAttributes.MIME_TYPE.key(), MediaType.APPLICATION_XML_UTF_8.toString()); + verify(processSession).transfer(flowFile, failureRelationship); + verify(componentLog).error(eq(ResultProcessor.UNABLE_TO_PROCESS_DUE_TO), any(Object[].class), eq(exception)); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitorTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitorTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitorTest.java new file mode 100644 index 0000000..35c760f --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitorTest.java @@ -0,0 +1,325 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx; + +import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor; +import org.apache.nifi.processors.evtx.parser.bxml.AttributeNode; +import org.apache.nifi.processors.evtx.parser.bxml.BxmlNode; +import org.apache.nifi.processors.evtx.parser.bxml.CDataSectionNode; +import org.apache.nifi.processors.evtx.parser.bxml.ConditionalSubstitutionNode; +import org.apache.nifi.processors.evtx.parser.bxml.EntityReferenceNode; +import org.apache.nifi.processors.evtx.parser.bxml.NormalSubstitutionNode; +import org.apache.nifi.processors.evtx.parser.bxml.OpenStartElementNode; +import org.apache.nifi.processors.evtx.parser.bxml.RootNode; +import org.apache.nifi.processors.evtx.parser.bxml.TemplateInstanceNode; +import org.apache.nifi.processors.evtx.parser.bxml.TemplateNode; +import org.apache.nifi.processors.evtx.parser.bxml.ValueNode; +import org.apache.nifi.processors.evtx.parser.bxml.value.BXmlTypeNode; +import org.apache.nifi.processors.evtx.parser.bxml.value.VariantTypeNode; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class XmlBxmlNodeVisitorTest { + @Mock + private XMLStreamWriter xmlStreamWriter; + + @Mock + private RootNode rootNode; + + @Mock + private BxmlNode bxmlNode; + private List<VariantTypeNode> substitutions; + private List<BxmlNode> children; + private XmlBxmlNodeVisitor xmlBxmlNodeVisitor; + + @Before + public void setup() throws IOException { + substitutions = new ArrayList<>(); + children = new ArrayList<>(Arrays.asList(bxmlNode)); + when(rootNode.getSubstitutions()).thenReturn(substitutions); + when(rootNode.getChildren()).thenReturn(children); + xmlBxmlNodeVisitor = new XmlBxmlNodeVisitor(xmlStreamWriter, rootNode); + } + + @Test + public void testConstructor() throws IOException { + verify(bxmlNode).accept(xmlBxmlNodeVisitor); + } + + @Test + public void testVisitOpenStartElementNode() throws IOException, XMLStreamException { + String tagName = "open"; + OpenStartElementNode openStartElementNode = mock(OpenStartElementNode.class); + AttributeNode attributeNode = mock(AttributeNode.class); + AttributeNode attributeNode2 = mock(AttributeNode.class); + BxmlNode bxmlNode = mock(BxmlNode.class); + + when(openStartElementNode.getTagName()).thenReturn(tagName); + when(openStartElementNode.getChildren()).thenReturn(Arrays.asList(attributeNode, bxmlNode, attributeNode2)); + + xmlBxmlNodeVisitor.visit(openStartElementNode); + + InOrder inOrder = inOrder(xmlStreamWriter, attributeNode, attributeNode2, bxmlNode); + inOrder.verify(xmlStreamWriter).writeStartElement(tagName); + inOrder.verify(attributeNode).accept(xmlBxmlNodeVisitor); + inOrder.verify(attributeNode2).accept(xmlBxmlNodeVisitor); + inOrder.verify(bxmlNode).accept(xmlBxmlNodeVisitor); + inOrder.verify(xmlStreamWriter).writeEndElement(); + } + + @Test + public void testVisitAttributeNodeValueType() throws IOException, XMLStreamException { + String attributeName = "attributeName"; + + AttributeNode attributeNode = mock(AttributeNode.class); + ValueNode valueNode = mock(ValueNode.class); + BxmlNode child = mock(BxmlNode.class); + + when(attributeNode.getAttributeName()).thenReturn(attributeName); + when(attributeNode.getValue()).thenReturn(valueNode); + when(valueNode.getChildren()).thenReturn(Arrays.asList(child)); + doAnswer(invocation -> { + ((BxmlNodeVisitor) invocation.getArguments()[0]).visit(valueNode); + return null; + }).when(valueNode).accept(any(BxmlNodeVisitor.class)); + + xmlBxmlNodeVisitor.visit(attributeNode); + + verify(xmlStreamWriter).writeAttribute(attributeName, null); + verify(child).accept(any(BxmlNodeVisitor.class)); + } + + @Test + public void testVisitAttributeNodeVariantType() throws IOException, XMLStreamException { + String attributeName = "attributeName"; + String attributeValue = "attributeValue"; + + AttributeNode attributeNode = mock(AttributeNode.class); + VariantTypeNode variantTypeNode = mock(VariantTypeNode.class); + + when(attributeNode.getAttributeName()).thenReturn(attributeName); + when(attributeNode.getValue()).thenReturn(variantTypeNode); + doAnswer(invocation -> { + ((BxmlNodeVisitor) invocation.getArguments()[0]).visit(variantTypeNode); + return null; + }).when(variantTypeNode).accept(any(BxmlNodeVisitor.class)); + when(variantTypeNode.getValue()).thenReturn(attributeValue); + + xmlBxmlNodeVisitor.visit(attributeNode); + + verify(xmlStreamWriter).writeAttribute(attributeName, attributeValue); + } + + @Test + public void testVisitAttributeNormalSubstitutionNode() throws IOException, XMLStreamException { + String attributeName = "attributeName"; + String attributeValue = "attributeValue"; + + VariantTypeNode sub = mock(VariantTypeNode.class); + when(sub.getValue()).thenReturn(attributeValue); + substitutions.add(sub); + + AttributeNode attributeNode = mock(AttributeNode.class); + NormalSubstitutionNode normalSubstitutionNode = mock(NormalSubstitutionNode.class); + + when(attributeNode.getAttributeName()).thenReturn(attributeName); + when(attributeNode.getValue()).thenReturn(normalSubstitutionNode); + doAnswer(invocation -> { + ((BxmlNodeVisitor) invocation.getArguments()[0]).visit(normalSubstitutionNode); + return null; + }).when(normalSubstitutionNode).accept(any(BxmlNodeVisitor.class)); + when(normalSubstitutionNode.getIndex()).thenReturn(0); + + xmlBxmlNodeVisitor.visit(attributeNode); + + verify(xmlStreamWriter).writeAttribute(attributeName, attributeValue); + } + + @Test + public void testVisitAttributeConditionalSubstitutionNode() throws IOException, XMLStreamException { + String attributeName = "attributeName"; + String attributeValue = "attributeValue"; + + VariantTypeNode sub = mock(VariantTypeNode.class); + when(sub.getValue()).thenReturn(attributeValue); + substitutions.add(sub); + + AttributeNode attributeNode = mock(AttributeNode.class); + ConditionalSubstitutionNode conditionalSubstitutionNode = mock(ConditionalSubstitutionNode.class); + + when(attributeNode.getAttributeName()).thenReturn(attributeName); + when(attributeNode.getValue()).thenReturn(conditionalSubstitutionNode); + doAnswer(invocation -> { + ((BxmlNodeVisitor) invocation.getArguments()[0]).visit(conditionalSubstitutionNode); + return null; + }).when(conditionalSubstitutionNode).accept(any(BxmlNodeVisitor.class)); + when(conditionalSubstitutionNode.getIndex()).thenReturn(0); + + xmlBxmlNodeVisitor.visit(attributeNode); + + verify(xmlStreamWriter).writeAttribute(attributeName, attributeValue); + } + + @Test + public void testVisitTemplateInstanceNode() throws IOException { + TemplateInstanceNode templateInstanceNode = mock(TemplateInstanceNode.class); + TemplateNode templateNode = mock(TemplateNode.class); + + when(templateInstanceNode.getTemplateNode()).thenReturn(templateNode); + + xmlBxmlNodeVisitor.visit(templateInstanceNode); + verify(templateNode).accept(xmlBxmlNodeVisitor); + } + + @Test + public void testVisitTemplateNode() throws IOException { + TemplateNode templateNode = mock(TemplateNode.class); + BxmlNode child = mock(BxmlNode.class); + + when(templateNode.getChildren()).thenReturn(Arrays.asList(child)); + + xmlBxmlNodeVisitor.visit(templateNode); + + verify(child).accept(xmlBxmlNodeVisitor); + } + + @Test + public void testVisitCDataSectionNode() throws IOException, XMLStreamException { + String cdata = "cdata"; + CDataSectionNode cDataSectionNode = mock(CDataSectionNode.class); + + when(cDataSectionNode.getCdata()).thenReturn(cdata); + + xmlBxmlNodeVisitor.visit(cDataSectionNode); + + verify(xmlStreamWriter).writeCData(cdata); + } + + @Test + public void testVisitEntityReferenceNode() throws IOException, XMLStreamException { + String value = "value"; + EntityReferenceNode entityReferenceNode = mock(EntityReferenceNode.class); + + when(entityReferenceNode.getValue()).thenReturn(value); + + xmlBxmlNodeVisitor.visit(entityReferenceNode); + + verify(xmlStreamWriter).writeCharacters(value); + } + + @Test + public void testVisitValueNode() throws IOException { + ValueNode valueNode = mock(ValueNode.class); + BxmlNode child = mock(BxmlNode.class); + + when(valueNode.getChildren()).thenReturn(Arrays.asList(child)); + + xmlBxmlNodeVisitor.visit(valueNode); + + verify(child).accept(xmlBxmlNodeVisitor); + } + + @Test + public void testVisitConditionalSubstitutionNode() throws IOException { + ConditionalSubstitutionNode conditionalSubstitutionNode = mock(ConditionalSubstitutionNode.class); + VariantTypeNode sub = mock(VariantTypeNode.class); + + substitutions.add(sub); + when(conditionalSubstitutionNode.getIndex()).thenReturn(0); + + xmlBxmlNodeVisitor.visit(conditionalSubstitutionNode); + + verify(sub).accept(xmlBxmlNodeVisitor); + } + + @Test + public void testVisitNormalSubstitutionNode() throws IOException { + NormalSubstitutionNode normalSubstitutionNode = mock(NormalSubstitutionNode.class); + VariantTypeNode sub = mock(VariantTypeNode.class); + + substitutions.add(sub); + when(normalSubstitutionNode.getIndex()).thenReturn(0); + + xmlBxmlNodeVisitor.visit(normalSubstitutionNode); + + verify(sub).accept(xmlBxmlNodeVisitor); + } + + @Test + public void testVisitBxmlTypeNode() throws IOException { + BXmlTypeNode bXmlTypeNode = mock(BXmlTypeNode.class); + RootNode rootNode = mock(RootNode.class); + + when(bXmlTypeNode.getRootNode()).thenReturn(rootNode); + + xmlBxmlNodeVisitor.visit(bXmlTypeNode); + + verify(rootNode).accept(xmlBxmlNodeVisitor); + } + + @Test + public void testVisitVariantTypeNode() throws IOException, XMLStreamException { + String variantValue = "variantValue"; + VariantTypeNode variantTypeNode = mock(VariantTypeNode.class); + + when(variantTypeNode.getValue()).thenReturn(variantValue); + + xmlBxmlNodeVisitor.visit(variantTypeNode); + + verify(xmlStreamWriter).writeCharacters(variantValue); + } + + @Test + public void testVisitRootNode() throws IOException { + RootNode rootNode = mock(RootNode.class); + BxmlNode child = mock(BxmlNode.class); + + when(rootNode.getChildren()).thenReturn(Arrays.asList(child)); + + xmlBxmlNodeVisitor.visit(rootNode); + + ArgumentCaptor<BxmlNodeVisitor> captor = ArgumentCaptor.forClass(BxmlNodeVisitor.class); + verify(child).accept(captor.capture()); + + BxmlNodeVisitor value = captor.getValue(); + assertTrue(value instanceof XmlBxmlNodeVisitor); + assertNotEquals(xmlBxmlNodeVisitor, value); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlRootNodeHandlerTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlRootNodeHandlerTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlRootNodeHandlerTest.java new file mode 100644 index 0000000..07a1f86 --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/XmlRootNodeHandlerTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.io.IOException; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +@RunWith(MockitoJUnitRunner.class) +public class XmlRootNodeHandlerTest { + @Mock + XMLStreamWriter xmlStreamWriter; + + @Mock + XmlBxmlNodeVisitorFactory xmlBxmlNodeVisitorFactory; + + XmlRootNodeHandler xmlRootNodeHandler; + + @Before + public void setup() throws IOException { + xmlRootNodeHandler = new XmlRootNodeHandler(xmlStreamWriter, xmlBxmlNodeVisitorFactory); + } + + @Test + public void testConstructor() throws XMLStreamException { + verify(xmlStreamWriter).writeStartDocument(); + verify(xmlStreamWriter).writeStartElement(XmlRootNodeHandler.EVENTS); + } + + @Test(expected = IOException.class) + public void testConstructorException() throws XMLStreamException, IOException { + xmlStreamWriter = mock(XMLStreamWriter.class); + doThrow(new XMLStreamException()).when(xmlStreamWriter).writeStartElement(XmlRootNodeHandler.EVENTS); + new XmlRootNodeHandler(xmlStreamWriter, xmlBxmlNodeVisitorFactory); + } + + @Test + public void testClose() throws IOException, XMLStreamException { + xmlRootNodeHandler.close(); + verify(xmlStreamWriter).writeEndElement(); + verify(xmlStreamWriter).close(); + } + + @Test(expected = IOException.class) + public void testCloseException() throws IOException, XMLStreamException { + doThrow(new XMLStreamException()).when(xmlStreamWriter).close(); + xmlRootNodeHandler.close(); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/BinaryReaderTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/BinaryReaderTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/BinaryReaderTest.java new file mode 100644 index 0000000..10d403c --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/BinaryReaderTest.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser; + +import com.google.common.base.Charsets; +import com.google.common.primitives.UnsignedInteger; +import com.google.common.primitives.UnsignedLong; +import org.junit.Before; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Base64; +import java.util.Date; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +public class BinaryReaderTest { + private TestBinaryReaderBuilder testBinaryReaderBuilder; + + @Before + public void setup() { + testBinaryReaderBuilder = new TestBinaryReaderBuilder(); + } + + @Test + public void testRead() throws IOException { + byte b = 0x23; + BinaryReader binaryReader = testBinaryReaderBuilder.put(b).build(); + assertEquals(b, binaryReader.read()); + assertEquals(1, binaryReader.getPosition()); + } + + @Test + public void testPeek() throws IOException { + byte b = 0x23; + BinaryReader binaryReader = testBinaryReaderBuilder.put(new byte[]{b}).build(); + assertEquals(b, binaryReader.peek()); + assertEquals(0, binaryReader.getPosition()); + } + + @Test + public void testReadBytesJustLength() throws IOException { + byte[] bytes = "Hello world".getBytes(Charsets.US_ASCII); + BinaryReader binaryReader = testBinaryReaderBuilder.put(bytes).build(); + assertArrayEquals(Arrays.copyOfRange(bytes, 0, 5), binaryReader.readBytes(5)); + assertEquals(5, binaryReader.getPosition()); + } + + @Test + public void testPeekBytes() throws IOException { + byte[] bytes = "Hello world".getBytes(Charsets.US_ASCII); + BinaryReader binaryReader = testBinaryReaderBuilder.put(bytes).build(); + assertArrayEquals(Arrays.copyOfRange(bytes, 0, 5), binaryReader.peekBytes(5)); + assertEquals(0, binaryReader.getPosition()); + } + + @Test + public void testReadBytesBufOffsetLength() throws IOException { + byte[] bytes = "Hello world".getBytes(Charsets.US_ASCII); + byte[] buf = new byte[5]; + + BinaryReader binaryReader = testBinaryReaderBuilder.put(bytes).build(); + binaryReader.readBytes(buf, 0, 5); + assertArrayEquals(Arrays.copyOfRange(bytes, 0, 5), buf); + assertEquals(5, binaryReader.getPosition()); + } + + @Test + public void testReadGuid() throws IOException { + String guid = "33323130-3534-3736-3839-616263646566"; + BinaryReader binaryReader = testBinaryReaderBuilder.putGuid(guid).build(); + assertEquals(guid, binaryReader.readGuid()); + assertEquals(16, binaryReader.getPosition()); + } + + @Test(expected = IOException.class) + public void testReadStringNotNullTerminated() throws IOException { + String value = "Hello world"; + + BinaryReader binaryReader = testBinaryReaderBuilder.put(value.getBytes(Charsets.US_ASCII)).build(); + binaryReader.readString(value.length()); + } + + @Test + public void testReadString() throws IOException { + String value = "Hello world"; + + BinaryReader binaryReader = testBinaryReaderBuilder.putString(value).build(); + assertEquals(value, binaryReader.readString(value.length() + 1)); + assertEquals(value.length() + 1, binaryReader.getPosition()); + } + + @Test + public void testReadWString() throws IOException { + String value = "Hello world"; + BinaryReader binaryReader = testBinaryReaderBuilder.putWString(value).build(); + + assertEquals(value, binaryReader.readWString(value.length())); + assertEquals(value.length() * 2, binaryReader.getPosition()); + } + + @Test + public void testReadQWord() throws IOException { + UnsignedLong longValue = UnsignedLong.fromLongBits(Long.MAX_VALUE + 500); + BinaryReader binaryReader = testBinaryReaderBuilder.putQWord(longValue).build(); + + assertEquals(longValue, binaryReader.readQWord()); + assertEquals(8, binaryReader.getPosition()); + } + + @Test + public void testReadDWord() throws IOException { + UnsignedInteger intValue = UnsignedInteger.fromIntBits(Integer.MAX_VALUE + 500); + BinaryReader binaryReader = testBinaryReaderBuilder.putDWord(intValue).build(); + + assertEquals(intValue, binaryReader.readDWord()); + assertEquals(4, binaryReader.getPosition()); + } + + @Test + public void testReadDWordBE() throws IOException { + UnsignedInteger intValue = UnsignedInteger.fromIntBits(Integer.MAX_VALUE + 500); + BinaryReader binaryReader = testBinaryReaderBuilder.putDWordBE(intValue).build(); + + assertEquals(intValue, binaryReader.readDWordBE()); + assertEquals(4, binaryReader.getPosition()); + } + + @Test + public void testReadWord() throws IOException { + int intValue = Short.MAX_VALUE + 500; + BinaryReader binaryReader = testBinaryReaderBuilder.putWord(intValue).build(); + + assertEquals(intValue, binaryReader.readWord()); + assertEquals(2, binaryReader.getPosition()); + } + + @Test + public void testReadWordBE() throws IOException { + int intValue = Short.MAX_VALUE + 500; + BinaryReader binaryReader = testBinaryReaderBuilder.putWordBE(intValue).build(); + + assertEquals(intValue, binaryReader.readWordBE()); + assertEquals(2, binaryReader.getPosition()); + } + + @Test + public void testReadFileTIme() throws IOException { + Date date = new Date(); + BinaryReader binaryReader = testBinaryReaderBuilder.putFileTime(date).build(); + + assertEquals(date.getTime(), binaryReader.readFileTime().getTime()); + assertEquals(8, binaryReader.getPosition()); + } + + @Test + public void testReadAndBase64EncodeBinary() throws IOException { + String orig = "Hello World"; + String stringValue = Base64.getEncoder().encodeToString(orig.getBytes(Charsets.US_ASCII)); + BinaryReader binaryReader = testBinaryReaderBuilder.putBase64EncodedBinary(stringValue).build(); + + assertEquals(stringValue, binaryReader.readAndBase64EncodeBinary(orig.length())); + assertEquals(orig.length(), binaryReader.getPosition()); + } + + @Test + public void testSkip() throws IOException { + BinaryReader binaryReader = new BinaryReader(null); + binaryReader.skip(10); + assertEquals(10, binaryReader.getPosition()); + } + + @Test + public void testReaderPositionConstructor() throws IOException { + String value = "Hello world"; + BinaryReader binaryReader = new BinaryReader(new BinaryReader(value.getBytes(Charsets.UTF_16LE)), 2); + + assertEquals(value.substring(1), binaryReader.readWString(value.length() - 1)); + assertEquals(value.length() * 2, binaryReader.getPosition()); + } + + @Test + public void testInputStreamSizeConstructor() throws IOException { + String value = "Hello world"; + BinaryReader binaryReader = new BinaryReader(new ByteArrayInputStream(value.getBytes(Charsets.UTF_16LE)), 10); + + assertEquals(value.substring(0, 5), binaryReader.readWString(5)); + assertEquals(10, binaryReader.getPosition()); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/ChunkHeaderTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/ChunkHeaderTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/ChunkHeaderTest.java new file mode 100644 index 0000000..1cb52db --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/ChunkHeaderTest.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser; + +import com.google.common.primitives.UnsignedInteger; +import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.processors.evtx.parser.bxml.BxmlNode; +import org.apache.nifi.processors.evtx.parser.bxml.EndOfStreamNode; +import org.apache.nifi.processors.evtx.parser.bxml.NameStringNode; +import org.apache.nifi.processors.evtx.parser.bxml.NameStringNodeTest; +import org.apache.nifi.processors.evtx.parser.bxml.RootNode; +import org.apache.nifi.processors.evtx.parser.bxml.TemplateNode; +import org.apache.nifi.processors.evtx.parser.bxml.TemplateNodeTest; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.TreeMap; +import java.util.zip.CRC32; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class ChunkHeaderTest { + private final Random random = new Random(); + private int headerOffset = 101; + private int chunkNumber = 102; + private ChunkHeader chunkHeader; + private int fileFirstRecordNumber = 103; + private int fileLastRecordNumber = 105; + private int logFirstRecordNumber = 106; + private int logLastRecordNumber = 107; + private int headerSize = 112; + private int lastRecordOffset = 12380; + private int nextRecordOffset = 2380; + private int dataChecksum = 1111; + private List<String> guids; + + @Before + public void setup() throws IOException { + TestBinaryReaderBuilder testBinaryReaderBuilder = new TestBinaryReaderBuilder(); + testBinaryReaderBuilder.putString(ChunkHeader.ELF_CHNK); + testBinaryReaderBuilder.putQWord(fileFirstRecordNumber); + testBinaryReaderBuilder.putQWord(fileLastRecordNumber); + testBinaryReaderBuilder.putQWord(logFirstRecordNumber); + testBinaryReaderBuilder.putQWord(logLastRecordNumber); + testBinaryReaderBuilder.putDWord(headerSize); + testBinaryReaderBuilder.putDWord(lastRecordOffset); + testBinaryReaderBuilder.putDWord(nextRecordOffset); + testBinaryReaderBuilder.putDWord(dataChecksum); + byte[] bytes = new byte[67]; + random.nextBytes(bytes); + testBinaryReaderBuilder.put(bytes); + testBinaryReaderBuilder.put((byte) 0); + + // Checksum placeholder + testBinaryReaderBuilder.putDWord(0); + + TestBinaryReaderBuilder dataBuilder = new TestBinaryReaderBuilder(); + int offset = 545; + for (int i = 0; i < 64; i++) { + String string = Integer.toString(i); + testBinaryReaderBuilder.putDWord(offset); + offset += NameStringNodeTest.putNode(dataBuilder, 0, string.hashCode(), string); + } + + guids = new ArrayList<>(); + for (int i = 0; i < 32; i++) { + testBinaryReaderBuilder.putDWord(offset + 10); + dataBuilder.put((byte) 0x0C); + dataBuilder.put(new byte[5]); + dataBuilder.putDWord(offset + 10); + byte[] guidBytes = new byte[16]; + random.nextBytes(guidBytes); + String guid = new TestBinaryReaderBuilder().put(guidBytes).build().readGuid(); + guids.add(guid); + offset += TemplateNodeTest.putNode(dataBuilder, 0, guid, i); + dataBuilder.put((byte) BxmlNode.END_OF_STREAM_TOKEN); + offset += 11; + } + + RecordTest.putNode(testBinaryReaderBuilder, fileLastRecordNumber, new Date()); + + testBinaryReaderBuilder.put(dataBuilder.toByteArray()); + + CRC32 dataChecksum = new CRC32(); + dataChecksum.update(testBinaryReaderBuilder.toByteArray(), 512, nextRecordOffset - 512); + testBinaryReaderBuilder.putDWordAt(UnsignedInteger.valueOf(dataChecksum.getValue()).intValue(), 52); + + CRC32 headerChecksum = new CRC32(); + byte[] array = testBinaryReaderBuilder.toByteArray(); + headerChecksum.update(array, 0, 120); + headerChecksum.update(array, 128, 384); + testBinaryReaderBuilder.putDWordAt(UnsignedInteger.valueOf(headerChecksum.getValue()).intValue(), 124); + chunkHeader = new ChunkHeader(testBinaryReaderBuilder.build(), mock(ComponentLog.class), headerOffset, chunkNumber); + } + + @Test + public void testInit() throws IOException { + int count = 0; + for (Map.Entry<Integer, NameStringNode> integerNameStringNodeEntry : new TreeMap<>(chunkHeader.getNameStrings()).entrySet()) { + assertEquals(Integer.toString(count++), integerNameStringNodeEntry.getValue().getString()); + } + + Iterator<String> iterator = guids.iterator(); + for (Map.Entry<Integer, TemplateNode> integerTemplateNodeEntry : new TreeMap<>(chunkHeader.getTemplateNodes()).entrySet()) { + assertEquals(iterator.next(), integerTemplateNodeEntry.getValue().getGuid()); + } + + assertTrue(chunkHeader.hasNext()); + + Record next = chunkHeader.next(); + assertEquals(fileLastRecordNumber, next.getRecordNum().intValue()); + RootNode rootNode = next.getRootNode(); + List<BxmlNode> children = rootNode.getChildren(); + assertEquals(1, children.size()); + assertTrue(children.get(0) instanceof EndOfStreamNode); + assertEquals(0, rootNode.getSubstitutions().size()); + + assertFalse(chunkHeader.hasNext()); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/FileHeaderTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/FileHeaderTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/FileHeaderTest.java new file mode 100644 index 0000000..7a07981 --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/FileHeaderTest.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser; + +import com.google.common.primitives.UnsignedInteger; +import org.apache.nifi.logging.ComponentLog; +import org.junit.Before; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Random; +import java.util.zip.CRC32; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +public class FileHeaderTest { + private final Random random = new Random(); + private FileHeader fileHeader; + private int oldestChunk = 111; + private int currentChunkNumber = 112; + private int nextRecordNumber = 113; + private int headerSize = 114; + private int minorVersion = 1; + private int majorVersion = 3; + private int headerChunkSize = 4096; + private int chunkCount = 0; + private int flags = 340942; + + @Before + public void setup() throws IOException { + TestBinaryReaderBuilder testBinaryReaderBuilder = new TestBinaryReaderBuilder(); + testBinaryReaderBuilder.putString(FileHeader.ELF_FILE); + testBinaryReaderBuilder.putQWord(oldestChunk); + testBinaryReaderBuilder.putQWord(currentChunkNumber); + testBinaryReaderBuilder.putQWord(nextRecordNumber); + testBinaryReaderBuilder.putDWord(headerSize); + testBinaryReaderBuilder.putWord(minorVersion); + testBinaryReaderBuilder.putWord(majorVersion); + testBinaryReaderBuilder.putWord(headerChunkSize); + testBinaryReaderBuilder.putWord(chunkCount); + byte[] unused = new byte[75]; + random.nextBytes(unused); + testBinaryReaderBuilder.put(unused); + testBinaryReaderBuilder.put((byte) 0); + + CRC32 crc32 = new CRC32(); + crc32.update(testBinaryReaderBuilder.toByteArray()); + + testBinaryReaderBuilder.putDWord(flags); + testBinaryReaderBuilder.putDWord(UnsignedInteger.valueOf(crc32.getValue())); + + fileHeader = new FileHeader(new ByteArrayInputStream(testBinaryReaderBuilder.toByteArray(4096)), mock(ComponentLog.class)); + } + + @Test + public void testInit() { + assertEquals(FileHeader.ELF_FILE, fileHeader.getMagicString()); + assertEquals(oldestChunk, fileHeader.getOldestChunk().intValue()); + assertEquals(currentChunkNumber, fileHeader.getCurrentChunkNumber().intValue()); + assertEquals(nextRecordNumber, fileHeader.getNextRecordNumber().intValue()); + assertEquals(headerSize, fileHeader.getHeaderSize().intValue()); + assertEquals(minorVersion, fileHeader.getMinorVersion()); + assertEquals(majorVersion, fileHeader.getMajorVersion()); + assertEquals(headerChunkSize, fileHeader.getHeaderChunkSize()); + assertEquals(chunkCount, fileHeader.getChunkCount()); + assertEquals(flags, fileHeader.getFlags().intValue()); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/RecordTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/RecordTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/RecordTest.java new file mode 100644 index 0000000..4d4996f --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/RecordTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser; + +import org.apache.nifi.processors.evtx.parser.bxml.BxmlNode; +import org.apache.nifi.processors.evtx.parser.bxml.EndOfStreamNode; +import org.apache.nifi.processors.evtx.parser.bxml.RootNode; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +@RunWith(MockitoJUnitRunner.class) +public class RecordTest { + @Mock + ChunkHeader chunkHeader; + + private Record record; + private int recordNum = 120; + + public static void putNode(TestBinaryReaderBuilder testBinaryReaderBuilder, int recordNum, Date fileTime) { + testBinaryReaderBuilder.putDWord(10794); + int size = 20; + testBinaryReaderBuilder.putDWord(size); + testBinaryReaderBuilder.putQWord(recordNum); + testBinaryReaderBuilder.putFileTime(new Date()); + + testBinaryReaderBuilder.put((byte) BxmlNode.END_OF_STREAM_TOKEN); + testBinaryReaderBuilder.putDWord(0); + testBinaryReaderBuilder.putDWord(size); + } + + @Before + public void setup() throws IOException { + TestBinaryReaderBuilder testBinaryReaderBuilder = new TestBinaryReaderBuilder(); + putNode(testBinaryReaderBuilder, recordNum, new Date()); + + record = new Record(testBinaryReaderBuilder.build(), chunkHeader); + } + + @Test + public void testInit() { + assertEquals(recordNum, record.getRecordNum().intValue()); + RootNode rootNode = record.getRootNode(); + List<BxmlNode> children = rootNode.getChildren(); + assertEquals(1, children.size()); + assertTrue(children.get(0) instanceof EndOfStreamNode); + assertEquals(0, rootNode.getSubstitutions().size()); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/TestBinaryReaderBuilder.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/TestBinaryReaderBuilder.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/TestBinaryReaderBuilder.java new file mode 100644 index 0000000..8230fa4 --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/TestBinaryReaderBuilder.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser; + +import com.google.common.base.Charsets; +import com.google.common.primitives.UnsignedInteger; +import com.google.common.primitives.UnsignedLong; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +public class TestBinaryReaderBuilder { + private final List<byte[]> data = new ArrayList<>(); + + public TestBinaryReaderBuilder put(byte val) { + data.add(new byte[]{val}); + return this; + } + + public TestBinaryReaderBuilder put(byte[] bytes) { + data.add(bytes); + return this; + } + + public TestBinaryReaderBuilder putGuid(String guid) { + byte[] bytes = new byte[16]; + String[] split = guid.split("-"); + int count = 0; + int offset = 0; + int[][] indexArrays = BinaryReader.INDEX_ARRAYS; + for (int i = 0; i < indexArrays.length; i++) { + String segment = split[i]; + for (int o = 0; o < indexArrays[i].length; o++) { + int beginIndex = (indexArrays[i][o] * 2) - offset; + bytes[count++] = (byte) Integer.parseInt(segment.substring(beginIndex, beginIndex + 2), 16); + } + offset += segment.length(); + } + put(bytes); + return this; + } + + public TestBinaryReaderBuilder putString(String val) { + data.add(val.getBytes(Charsets.US_ASCII)); + data.add(new byte[]{0}); + return this; + } + + public TestBinaryReaderBuilder putWString(String val) { + data.add(val.getBytes(Charsets.UTF_16LE)); + return this; + } + + public TestBinaryReaderBuilder putQWord(long longBits) { + data.add(ByteBuffer.wrap(new byte[8]).order(ByteOrder.LITTLE_ENDIAN).putLong(longBits).array()); + return this; + } + + public TestBinaryReaderBuilder putQWord(UnsignedLong val) { + return putQWord(val.longValue()); + } + + public TestBinaryReaderBuilder putDWord(int intBits) { + data.add(ByteBuffer.wrap(new byte[4]).order(ByteOrder.LITTLE_ENDIAN).putInt(intBits).array()); + return this; + } + + public TestBinaryReaderBuilder putDWordAt(int intBits, int position) throws IOException { + ByteBuffer.wrap(toByteArray(), position, 4).order(ByteOrder.LITTLE_ENDIAN).putInt(intBits); + return this; + } + + public TestBinaryReaderBuilder putDWord(UnsignedInteger val) { + return putDWord(val.intValue()); + } + + public TestBinaryReaderBuilder putDWordBE(int intBits) { + data.add(ByteBuffer.wrap(new byte[4]).order(ByteOrder.BIG_ENDIAN).putInt(intBits).array()); + return this; + } + + public TestBinaryReaderBuilder putDWordBE(UnsignedInteger val) { + return putDWordBE(val.intValue()); + } + + public TestBinaryReaderBuilder putWord(int val) { + data.add(ByteBuffer.wrap(new byte[2]).order(ByteOrder.LITTLE_ENDIAN).putShort((short) val).array()); + return this; + } + + public TestBinaryReaderBuilder putWordBE(int val) { + data.add(ByteBuffer.wrap(new byte[2]).order(ByteOrder.BIG_ENDIAN).putShort((short) val).array()); + return this; + } + + public TestBinaryReaderBuilder putFileTime(Date date) { + UnsignedLong javaMillis = UnsignedLong.valueOf(date.getTime()); + UnsignedLong windowsMillis = javaMillis.plus(UnsignedLong.valueOf(BinaryReader.EPOCH_OFFSET)); + UnsignedLong windowsStamp = windowsMillis.times(UnsignedLong.valueOf(10000)); + return putQWord(windowsStamp); + } + + public TestBinaryReaderBuilder putSystemtime(Calendar calendar) { + putWord(calendar.get(Calendar.YEAR)); + putWord(calendar.get(Calendar.MONTH)); + putWord(calendar.get(Calendar.DAY_OF_WEEK)); + putWord(calendar.get(Calendar.DAY_OF_MONTH)); + putWord(calendar.get(Calendar.HOUR_OF_DAY)); + putWord(calendar.get(Calendar.MINUTE)); + putWord(calendar.get(Calendar.SECOND)); + putWord(calendar.get(Calendar.MILLISECOND)); + return this; + } + + public TestBinaryReaderBuilder putBase64EncodedBinary(String base64EncodedBinary) { + return put(Base64.getDecoder().decode(base64EncodedBinary)); + } + + public BinaryReader build() throws IOException { + return new BinaryReader(toByteArray()); + } + + public byte[] toByteArray() throws IOException { + if (data.size() == 0) { + return new byte[0]; + } else if (data.size() == 1) { + return data.get(0); + } else { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + for (byte[] bytes : data) { + byteArrayOutputStream.write(bytes); + } + byte[] bytes = byteArrayOutputStream.toByteArray(); + data.clear(); + data.add(bytes); + return bytes; + } + } + + public byte[] toByteArray(int size) throws IOException { + byte[] bytes = toByteArray(); + byte[] result = new byte[size]; + System.arraycopy(bytes, 0, result, 0, Math.min(bytes.length, result.length)); + return result; + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNodeTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNodeTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNodeTest.java new file mode 100644 index 0000000..d6eb07d --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNodeTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser.bxml; + +import org.apache.nifi.processors.evtx.parser.BinaryReader; +import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor; +import org.apache.nifi.processors.evtx.parser.bxml.value.NullTypeNode; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +public class AttributeNodeTest extends BxmlNodeWithTokenAndStringTestBase { + public static final String ATTRIBUTE_NAME = "AttributeName"; + private BinaryReader binaryReader; + private AttributeNode attributeNode; + + @Override + public void setup() throws IOException { + super.setup(); + testBinaryReaderBuilder.put((byte) BxmlNode.VALUE_TOKEN); + testBinaryReaderBuilder.put((byte) 0); + attributeNode = new AttributeNode(testBinaryReaderBuilder.build(), chunkHeader, parent); + } + + @Override + protected byte getToken() { + return BxmlNode.ATTRIBUTE_TOKEN; + } + + @Override + protected String getString() { + return ATTRIBUTE_NAME; + } + + @Test + public void testInit() { + assertEquals(ATTRIBUTE_NAME, attributeNode.getAttributeName()); + BxmlNode attributeNodeValue = attributeNode.getValue(); + assertTrue(attributeNodeValue instanceof ValueNode); + List<BxmlNode> children = ((ValueNode) attributeNodeValue).getChildren(); + assertEquals(1, children.size()); + assertTrue(children.get(0) instanceof NullTypeNode); + } + + @Test + public void testVisit() throws IOException { + BxmlNodeVisitor mock = mock(BxmlNodeVisitor.class); + attributeNode.accept(mock); + verify(mock).visit(attributeNode); + verifyNoMoreInteractions(mock); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeTestBase.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeTestBase.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeTestBase.java new file mode 100644 index 0000000..4c7c8ea --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeTestBase.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser.bxml; + +import org.apache.nifi.processors.evtx.parser.ChunkHeader; +import org.apache.nifi.processors.evtx.parser.TestBinaryReaderBuilder; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.IOException; + +@RunWith(MockitoJUnitRunner.class) +public abstract class BxmlNodeTestBase { + public TestBinaryReaderBuilder testBinaryReaderBuilder; + + @Mock + public ChunkHeader chunkHeader; + + @Mock + public BxmlNode parent; + + @Before + public void setup() throws IOException { + testBinaryReaderBuilder = new TestBinaryReaderBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndStringTestBase.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndStringTestBase.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndStringTestBase.java new file mode 100644 index 0000000..94d638d --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndStringTestBase.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser.bxml; + +import java.io.IOException; + +import static org.mockito.Mockito.when; + +public abstract class BxmlNodeWithTokenAndStringTestBase extends BxmlNodeWithTokenTestBase { + @Override + public void setup() throws IOException { + super.setup(); + testBinaryReaderBuilder.putDWord(0); + when(chunkHeader.getOffset()).thenReturn(4096L); + when(chunkHeader.getString(0)).thenReturn(getString()); + } + + protected abstract String getString(); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenTestBase.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenTestBase.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenTestBase.java new file mode 100644 index 0000000..742c70d --- /dev/null +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenTestBase.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.nifi.processors.evtx.parser.bxml; + +import java.io.IOException; + +public abstract class BxmlNodeWithTokenTestBase extends BxmlNodeTestBase { + @Override + public void setup() throws IOException { + super.setup(); + testBinaryReaderBuilder.put(getToken()); + } + + protected abstract byte getToken(); +}