NIFI-9164 Refactored tests in nifi-windows-event-log to JUnit 5

- Used LauncherInterceptor to handle custom class loading

This closes #7623

Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
Emilio Setiadarma 2023-08-10 19:50:09 -07:00 committed by exceptionfactory
parent 96ae5252f5
commit 5d90c9c14b
No known key found for this signature in database
GPG Key ID: 29B6A52D2AAE8DBA
9 changed files with 175 additions and 245 deletions

View File

@ -25,6 +25,22 @@ language governing permissions and limitations under the License. -->
<javassist.version>3.29.2-GA</javassist.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<junit.platform.launcher.interceptors.enabled>
true
</junit.platform.launcher.interceptors.enabled>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
@ -68,8 +84,8 @@ language governing permissions and limitations under the License. -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -1,39 +0,0 @@
/*
* 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.windows.event.log;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* Test scenario where we can't load the native libraries
*/
@RunWith(JNAFailJUnitRunner.class)
public class ConsumeWindowsEventLogFailTest {
/**
* The processor should never be valid because we're using JNAFailJUnitRunner
*/
@Test
public void testValidate() {
TestRunner testRunner = TestRunners.newTestRunner(ConsumeWindowsEventLog.class);
testRunner.assertNotValid();
}
}

View File

@ -14,36 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.processors.windows.event.log;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.W32Errors;
import com.sun.jna.platform.win32.WinError;
import com.sun.jna.platform.win32.WinNT;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.nifi.annotation.lifecycle.OnScheduled;
import org.apache.nifi.annotation.lifecycle.OnStopped;
import org.apache.nifi.processor.exception.ProcessException;
@ -55,13 +32,43 @@ import org.apache.nifi.util.MockSessionFactory;
import org.apache.nifi.util.ReflectionUtils;
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.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@RunWith(JNAJUnitRunner.class)
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Running tests may require {@code junit.platform.launcher.interceptors.enabled}
* property to be set to {@code true} to resolve class loading issues.
*/
@ExtendWith(MockitoExtension.class)
public class ConsumeWindowsEventLogTest {
@Mock
Kernel32 kernel32;
@ -78,36 +85,13 @@ public class ConsumeWindowsEventLogTest {
private ConsumeWindowsEventLog evtSubscribe;
private TestRunner testRunner;
public static List<WinNT.HANDLE> mockEventHandles(WEvtApi wEvtApi, Kernel32 kernel32, List<String> eventXmls) {
List<WinNT.HANDLE> eventHandles = new ArrayList<>();
for (String eventXml : eventXmls) {
WinNT.HANDLE eventHandle = mock(WinNT.HANDLE.class);
when(wEvtApi.EvtRender(isNull(), eq(eventHandle), eq(WEvtApi.EvtRenderFlags.EVENT_XML),
anyInt(), any(Pointer.class), any(Pointer.class), any(Pointer.class))).thenAnswer(invocation -> {
Object[] arguments = invocation.getArguments();
Pointer bufferUsed = (Pointer) arguments[5];
byte[] array = StandardCharsets.UTF_16LE.encode(eventXml).array();
if (array.length > (int) arguments[3]) {
when(kernel32.GetLastError()).thenReturn(W32Errors.ERROR_INSUFFICIENT_BUFFER).thenReturn(W32Errors.ERROR_SUCCESS);
} else {
((Pointer) arguments[4]).write(0, array, 0, array.length);
}
bufferUsed.setInt(0, array.length);
return false;
});
eventHandles.add(eventHandle);
}
return eventHandles;
}
@Before
@BeforeEach
public void setup() {
evtSubscribe = new ConsumeWindowsEventLog(wEvtApi, kernel32);
lenient().when(subscriptionHandle.getPointer()).thenReturn(subscriptionPointer);
when(subscriptionHandle.getPointer()).thenReturn(subscriptionPointer);
when(wEvtApi.EvtSubscribe(isNull(), isNull(), eq(ConsumeWindowsEventLog.DEFAULT_CHANNEL), eq(ConsumeWindowsEventLog.DEFAULT_XPATH),
lenient().when(wEvtApi.EvtSubscribe(isNull(), isNull(), eq(ConsumeWindowsEventLog.DEFAULT_CHANNEL), eq(ConsumeWindowsEventLog.DEFAULT_XPATH),
isNull(), isNull(), isA(EventSubscribeXmlRenderingCallback.class),
eq(WEvtApi.EvtSubscribeFlags.SUBSCRIBE_TO_FUTURE | WEvtApi.EvtSubscribeFlags.EVT_SUBSCRIBE_STRICT)))
.thenReturn(subscriptionHandle);
@ -115,8 +99,9 @@ public class ConsumeWindowsEventLogTest {
testRunner = TestRunners.newTestRunner(evtSubscribe);
}
@Test(timeout = 10 * 1000)
public void testProcessesBlockedEvents() throws UnsupportedEncodingException {
@Test
@Timeout(value = 10)
public void testProcessesBlockedEvents() {
testRunner.setProperty(ConsumeWindowsEventLog.MAX_EVENT_QUEUE_SIZE, "1");
testRunner.run(1, false, true);
EventSubscribeXmlRenderingCallback renderingCallback = getRenderingCallback();
@ -169,10 +154,9 @@ public class ConsumeWindowsEventLogTest {
}
@Test
public void testScheduleErrorThenTriggerSubscribe() throws InvocationTargetException, IllegalAccessException {
public void testScheduleErrorThenTriggerSubscribe() {
evtSubscribe = new ConsumeWindowsEventLog(wEvtApi, kernel32);
when(subscriptionHandle.getPointer()).thenReturn(subscriptionPointer);
when(wEvtApi.EvtSubscribe(isNull(), isNull(), eq(ConsumeWindowsEventLog.DEFAULT_CHANNEL), eq(ConsumeWindowsEventLog.DEFAULT_XPATH),
@ -221,18 +205,20 @@ public class ConsumeWindowsEventLogTest {
verify(wEvtApi).EvtClose(subscriptionHandle);
}
@Test(expected = ProcessException.class)
@Test
public void testScheduleQueueStopThrowsException() throws Throwable {
ReflectionUtils.invokeMethodsWithAnnotation(OnScheduled.class, evtSubscribe, testRunner.getProcessContext());
WinNT.HANDLE handle = mockEventHandles(wEvtApi, kernel32, Arrays.asList("test")).get(0);
getRenderingCallback().onEvent(WEvtApi.EvtSubscribeNotifyAction.DELIVER, null, handle);
try {
ReflectionUtils.invokeMethodsWithAnnotation(OnStopped.class, evtSubscribe, testRunner.getProcessContext());
} catch (InvocationTargetException e) {
throw e.getCause();
}
assertThrows(ProcessException.class, () -> {
try {
ReflectionUtils.invokeMethodsWithAnnotation(OnStopped.class, evtSubscribe, testRunner.getProcessContext());
} catch (final InvocationTargetException e) {
throw e.getCause();
}
});
}
public EventSubscribeXmlRenderingCallback getRenderingCallback() {
@ -257,6 +243,28 @@ public class ConsumeWindowsEventLogTest {
assertEquals(ConsumeWindowsEventLog.RELATIONSHIPS, evtSubscribe.getRelationships());
}
public static List<WinNT.HANDLE> mockEventHandles(WEvtApi wEvtApi, Kernel32 kernel32, List<String> eventXmls) {
List<WinNT.HANDLE> eventHandles = new ArrayList<>();
for (String eventXml : eventXmls) {
WinNT.HANDLE eventHandle = mock(WinNT.HANDLE.class);
when(wEvtApi.EvtRender(isNull(), eq(eventHandle), eq(WEvtApi.EvtRenderFlags.EVENT_XML),
anyInt(), any(Pointer.class), any(Pointer.class), any(Pointer.class))).thenAnswer(invocation -> {
Object[] arguments = invocation.getArguments();
Pointer bufferUsed = (Pointer) arguments[5];
byte[] array = StandardCharsets.UTF_16LE.encode(eventXml).array();
if (array.length > (int) arguments[3]) {
when(kernel32.GetLastError()).thenReturn(W32Errors.ERROR_INSUFFICIENT_BUFFER).thenReturn(W32Errors.ERROR_SUCCESS);
} else {
((Pointer) arguments[4]).write(0, array, 0, array.length);
}
bufferUsed.setInt(0, array.length);
return false;
});
eventHandles.add(eventHandle);
}
return eventHandles;
}
private static Set<MockProcessSession> getCreatedSessions(TestRunner testRunner) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
MockSessionFactory processSessionFactory = (MockSessionFactory) testRunner.getProcessSessionFactory();
Method getCreatedSessions = processSessionFactory.getClass().getDeclaredMethod("getCreatedSessions");

View File

@ -1,42 +0,0 @@
/*
* 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.windows.event.log;
import org.junit.runners.model.InitializationError;
import java.util.HashMap;
import java.util.Map;
/**
* Native load failure to simulate case on all OSes (even Windows)
*/
public class JNAFailJUnitRunner extends JNAOverridingJUnitRunner {
public JNAFailJUnitRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
protected Map<String, Map<String, String>> getClassOverrideMap() {
Map<String, Map<String, String>> classOverrideMap = new HashMap<>();
Map<String, String> nativeOverrideMap = new HashMap<>();
nativeOverrideMap.put(LOAD_LIBRARY, "throw new " + UnsatisfiedLinkError.class.getCanonicalName() + "(\"JNAFailJUnitRunner\");");
classOverrideMap.put(NATIVE_CANONICAL_NAME, nativeOverrideMap);
return classOverrideMap;
}
}

View File

@ -1,51 +0,0 @@
/*
* 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.windows.event.log;
import com.sun.jna.platform.win32.Kernel32Util;
import org.junit.runners.model.InitializationError;
import java.util.HashMap;
import java.util.Map;
/**
* Can't even use the JNA interface classes if the native library won't load. This is a workaround to allow mocking them for unit tests.
*/
public class JNAJUnitRunner extends JNAOverridingJUnitRunner {
public static final String TEST_COMPUTER_NAME = "testComputerName";
public static final String KERNEL_32_UTIL_CANONICAL_NAME = Kernel32Util.class.getCanonicalName();
public JNAJUnitRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
protected Map<String, Map<String, String>> getClassOverrideMap() {
Map<String, Map<String, String>> classOverrideMap = new HashMap<>();
Map<String, String> nativeOverrideMap = new HashMap<>();
nativeOverrideMap.put(LOAD_LIBRARY, "return null;");
classOverrideMap.put(NATIVE_CANONICAL_NAME, nativeOverrideMap);
Map<String, String> kernel32UtilMap = new HashMap<>();
kernel32UtilMap.put("getComputerName", "return \"" + TEST_COMPUTER_NAME + "\";");
classOverrideMap.put(KERNEL_32_UTIL_CANONICAL_NAME, kernel32UtilMap);
return classOverrideMap;
}
}

View File

@ -14,38 +14,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.processors.windows.event.log;
import com.sun.jna.Native;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Assert;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.InitializationError;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Can't even use the JNA interface classes if the native library won't load. This is a workaround to allow mocking them for unit tests.
*/
public abstract class JNAOverridingJUnitRunner extends Runner {
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32Util;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.platform.launcher.LauncherInterceptor;
import static org.junit.jupiter.api.Assertions.fail;
public class JNALauncherInterceptor implements LauncherInterceptor {
public static final String NATIVE_CANONICAL_NAME = Native.class.getCanonicalName();
public static final String LOAD_LIBRARY = "loadLibrary";
private final Runner delegate;
public static final String TEST_COMPUTER_NAME = "testComputerName";
public static final String KERNEL_32_UTIL_CANONICAL_NAME = Kernel32Util.class.getCanonicalName();
public JNAOverridingJUnitRunner(Class<?> klass) throws InitializationError {
private final URLClassLoader jnaMockClassLoader;
public JNALauncherInterceptor() {
Map<String, Map<String, String>> classOverrideMap = getClassOverrideMap();
String classpath = System.getProperty("java.class.path");
URL[] result = Pattern.compile(File.pathSeparator).splitAsStream(classpath).map(Paths::get).map(Path::toAbsolutePath).map(Path::toUri)
@ -54,12 +54,12 @@ public abstract class JNAOverridingJUnitRunner extends Runner {
try {
url = uri.toURL();
} catch (MalformedURLException e) {
Assert.fail(String.format("Unable to create URL for classpath entry '%s'", uri));
fail(String.format("Unable to create URL for classpath entry '%s'", uri));
}
return url;
})
.toArray(URL[]::new);
ClassLoader jnaMockClassloader = new URLClassLoader(result, null) {
jnaMockClassLoader = new URLClassLoader(result, null) {
@Override
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Map<String, String> classOverrides = classOverrideMap.get(name);
@ -86,8 +86,8 @@ public abstract class JNAOverridingJUnitRunner extends Runner {
} catch (Exception e) {
throw new ClassNotFoundException(name, e);
}
} else if (name.startsWith("org.junit.") || name.startsWith("org.mockito")) {
Class<?> result = JNAOverridingJUnitRunner.class.getClassLoader().loadClass(name);
} else if (name.startsWith("org.junit.")) {
Class<?> result = JNALauncherInterceptor.class.getClassLoader().loadClass(name);
if (resolve) {
resolveClass(result);
}
@ -96,23 +96,40 @@ public abstract class JNAOverridingJUnitRunner extends Runner {
return super.loadClass(name, resolve);
}
};
}
@Override
public <T> T intercept(final Invocation<T> invocation) {
final Thread currentThread = Thread.currentThread();
final ClassLoader originalClassLoader = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(jnaMockClassLoader);
try {
delegate = (Runner) jnaMockClassloader.loadClass(MockitoJUnitRunner.class.getCanonicalName()).getConstructor(Class.class)
.newInstance(jnaMockClassloader.loadClass(klass.getCanonicalName()));
} catch (Exception e) {
throw new InitializationError(e);
return invocation.proceed();
} finally {
currentThread.setContextClassLoader(originalClassLoader);
}
}
protected abstract Map<String, Map<String, String>> getClassOverrideMap();
@Override
public Description getDescription() {
return delegate.getDescription();
public void close() {
try {
jnaMockClassLoader.close();
} catch (final IOException e) {
throw new UncheckedIOException("Failed to close custom class loader", e);
}
}
@Override
public void run(RunNotifier notifier) {
delegate.run(notifier);
private Map<String, Map<String, String>> getClassOverrideMap() {
final Map<String, Map<String, String>> classOverrideMap = new HashMap<>();
final Map<String, String> nativeOverrideMap = new HashMap<>();
nativeOverrideMap.put(LOAD_LIBRARY, "return null;");
classOverrideMap.put(NATIVE_CANONICAL_NAME, nativeOverrideMap);
final Map<String, String> kernel32UtilMap = new HashMap<>();
kernel32UtilMap.put("getComputerName", "return \"" + TEST_COMPUTER_NAME + "\";");
classOverrideMap.put(KERNEL_32_UTIL_CANONICAL_NAME, kernel32UtilMap);
return classOverrideMap;
}
}

View File

@ -14,28 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.processors.windows.event.log.jna;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinError;
import org.apache.nifi.processors.windows.event.log.JNAJUnitRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@RunWith(JNAJUnitRunner.class)
/**
* Running tests may require {@code junit.platform.launcher.interceptors.enabled}
* property to be set to {@code true} to resolve class loading issues.
*/
@ExtendWith(MockitoExtension.class)
public class ErrorLookupTest {
@Mock
Kernel32 kernel32;
private ErrorLookup errorLookup;
@Before
@BeforeEach
public void setup() {
errorLookup = new ErrorLookup(kernel32);
}

View File

@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.nifi.processors.windows.event.log.jna;
import com.sun.jna.Pointer;
@ -22,11 +21,11 @@ import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processors.windows.event.log.ConsumeWindowsEventLogTest;
import org.apache.nifi.processors.windows.event.log.JNAJUnitRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import java.util.function.Consumer;
@ -37,7 +36,11 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(JNAJUnitRunner.class)
/**
* Running tests may require {@code junit.platform.launcher.interceptors.enabled}
* property to be set to {@code true} to resolve class loading issues.
*/
@ExtendWith(MockitoExtension.class)
public class EventSubscribeXmlRenderingCallbackTest {
@Mock
ComponentLog logger;
@ -60,7 +63,7 @@ public class EventSubscribeXmlRenderingCallbackTest {
private EventSubscribeXmlRenderingCallback eventSubscribeXmlRenderingCallback;
private int maxBufferSize;
@Before
@BeforeEach
public void setup() {
maxBufferSize = 8;
eventSubscribeXmlRenderingCallback = new EventSubscribeXmlRenderingCallback(logger, consumer, maxBufferSize, wEvtApi, kernel32, errorLookup);

View File

@ -0,0 +1,15 @@
# 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.
org.apache.nifi.processors.windows.event.log.JNALauncherInterceptor