[ 
https://issues.apache.org/jira/browse/NIFI-1975?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15321521#comment-15321521
 ] 

ASF GitHub Bot commented on NIFI-1975:
--------------------------------------

Github user brosander commented on a diff in the pull request:

    https://github.com/apache/nifi/pull/492#discussion_r66348434
  
    --- Diff: 
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 {
    --- End diff --
    
    @mattyb149 lifecycle tests of the 3 different granularities using a 
doctored evtx file that has good chunks, bad chunk headers, and a malformed 
record


> Processor to Parse .evtx files
> ------------------------------
>
>                 Key: NIFI-1975
>                 URL: https://issues.apache.org/jira/browse/NIFI-1975
>             Project: Apache NiFi
>          Issue Type: Sub-task
>            Reporter: Bryan Rosander
>
> Windows event logs are stored in .evtx format as-of Windows Vista.  If we 
> port the pure python implementation of an evtx parser  at 
> https://github.com/williballenthin/python-evtx to Java, we should be able to 
> ingest those files in NiFi on any operating system



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to