You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by jo...@apache.org on 2021/12/13 18:43:16 UTC

[nifi] 12/22: NIFI-9372 Corrected NiFi application log messages

This is an automated email from the ASF dual-hosted git repository.

joewitt pushed a commit to branch support/nifi-1.15
in repository https://gitbox.apache.org/repos/asf/nifi.git

commit b981914661998be567ac22d8c1971300a4478e4c
Author: exceptionfactory <ex...@apache.org>
AuthorDate: Tue Nov 9 12:13:59 2021 -0600

    NIFI-9372 Corrected NiFi application log messages
    
    - Removed unnecessary spaces from initialization log
    - Changed bootstrap temporary password file processing messages to debug
    - Updated several log statements using parameterized strings
    - Refactored NiFi unit test class
---
 .../src/main/java/org/apache/nifi/NiFi.java        |  29 +--
 .../groovy/org/apache/nifi/NiFiGroovyTest.groovy   | 285 ---------------------
 .../test/java/org/apache/nifi/ListAppender.java    |  41 +++
 .../src/test/java/org/apache/nifi/NiFiTest.java    | 116 +++++++++
 ...nt_key.properties => encrypted.nifi.properties} |   0
 ...h_sensitive_properties_protected_aes.properties | 183 -------------
 ...nsitive_properties_protected_aes_128.properties | 183 -------------
 ...ties_protected_aes_different_key_128.properties | 186 --------------
 .../src/test/resources/logback-test.xml            |   8 +-
 9 files changed, 171 insertions(+), 860 deletions(-)

diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java
index eef3310..541d4cf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/main/java/org/apache/nifi/NiFi.java
@@ -92,7 +92,7 @@ public class NiFi implements NiFiEntryPoint {
         final File kerberosConfigFile = properties.getKerberosConfigurationFile();
         if (kerberosConfigFile != null) {
             final String kerberosConfigFilePath = kerberosConfigFile.getAbsolutePath();
-            LOGGER.info("Setting java.security.krb5.conf to {}", kerberosConfigFilePath);
+            LOGGER.debug("Setting java.security.krb5.conf to {}", kerberosConfigFilePath);
             System.setProperty("java.security.krb5.conf", kerberosConfigFilePath);
         }
 
@@ -175,8 +175,8 @@ public class NiFi implements NiFiEntryPoint {
             }
 
             final long duration = System.nanoTime() - startTime;
-            LOGGER.info("Controller initialization took {} nanoseconds ( {}  seconds).",
-                    duration, (int) TimeUnit.SECONDS.convert(duration, TimeUnit.NANOSECONDS));
+            final double durationSeconds = TimeUnit.NANOSECONDS.toMillis(duration) / 1000.0;
+            LOGGER.info("Started Application Controller in {} seconds ({} ns)", durationSeconds, duration);
         }
     }
 
@@ -186,8 +186,7 @@ public class NiFi implements NiFiEntryPoint {
 
     protected void setDefaultUncaughtExceptionHandler() {
         Thread.setDefaultUncaughtExceptionHandler((thread, exception) -> {
-            LOGGER.error("An Unknown Error Occurred in Thread {}: {}", thread, exception.toString());
-            LOGGER.error("", exception);
+            LOGGER.error("An Unknown Error Occurred in Thread {}: {}", thread, exception.toString(), exception);
         });
     }
 
@@ -211,7 +210,7 @@ public class NiFi implements NiFiEntryPoint {
                 try {
                     urls.add(p.toUri().toURL());
                 } catch (final MalformedURLException mef) {
-                    LOGGER.warn("Unable to load " + p.getFileName() + " due to " + mef, mef);
+                    LOGGER.warn("Unable to load bootstrap library [{}]", p.getFileName(), mef);
                 }
             });
         } catch (IOException ioe) {
@@ -226,7 +225,7 @@ public class NiFi implements NiFiEntryPoint {
             runDiagnosticsOnShutdown();
             shutdown();
         } catch (final Throwable t) {
-            LOGGER.warn("Problem occurred ensuring Jetty web server was properly terminated due to ", t);
+            LOGGER.warn("Problem occurred ensuring Jetty web server was properly terminated", t);
         }
     }
 
@@ -258,14 +257,14 @@ public class NiFi implements NiFiEntryPoint {
     protected void shutdown() {
         this.shutdown = true;
 
-        LOGGER.info("Initiating shutdown of Jetty web server...");
+        LOGGER.info("Application Server shutdown started");
         if (nifiServer != null) {
             nifiServer.stop();
         }
         if (bootstrapListener != null) {
             bootstrapListener.stop();
         }
-        LOGGER.info("Jetty web server shutdown completed (nicely or otherwise).");
+        LOGGER.info("Application Server shutdown completed");
     }
 
     /**
@@ -330,7 +329,7 @@ public class NiFi implements NiFiEntryPoint {
             NiFiProperties properties = convertArgumentsToValidatedNiFiProperties(args);
             new NiFi(properties);
         } catch (final Throwable t) {
-            LOGGER.error("Failure to launch NiFi due to " + t, t);
+            LOGGER.error("Failure to launch NiFi", t);
         }
     }
 
@@ -367,7 +366,7 @@ public class NiFi implements NiFiEntryPoint {
             final Object loaderInstance = withKeyMethod.invoke(null, key);
             final Method getMethod = propsLoaderClass.getMethod("get");
             final NiFiProperties properties = (NiFiProperties) getMethod.invoke(loaderInstance);
-            LOGGER.info("Loaded {} properties", properties.size());
+            LOGGER.info("Application Properties loaded [{}]", properties.size());
             return properties;
         } catch (InvocationTargetException wrappedException) {
             final String msg = "There was an issue decrypting protected properties";
@@ -405,7 +404,7 @@ public class NiFi implements NiFiEntryPoint {
 
     private static String getKeyFromKeyFileAndPrune(List<String> parsedArgs) {
         String key = null;
-        LOGGER.debug("The bootstrap process provided the " + KEY_FILE_FLAG + " flag");
+        LOGGER.debug("The bootstrap process provided the {} flag", KEY_FILE_FLAG);
         int i = parsedArgs.indexOf(KEY_FILE_FLAG);
         if (parsedArgs.size() <= i + 1) {
             LOGGER.error("The bootstrap process passed the {} flag without a filename", KEY_FILE_FLAG);
@@ -419,7 +418,7 @@ public class NiFi implements NiFiEntryPoint {
             if (0 == key.length())
                 throw new IllegalArgumentException("Key in keyfile " + passwordfilePath + " yielded an empty key");
 
-            LOGGER.info("Now overwriting file in {}", passwordfilePath);
+            LOGGER.debug("Overwriting temporary bootstrap key file [{}]", passwordfilePath);
 
             // Overwrite the contents of the file (to avoid littering file system
             // unlinked with key material):
@@ -434,11 +433,10 @@ public class NiFi implements NiFiEntryPoint {
                 sb.append(Integer.toHexString(random.nextInt()));
             }
             String pad = sb.toString();
-            LOGGER.info("Overwriting key material with pad: {}", pad);
             overwriter.write(pad);
             overwriter.close();
 
-            LOGGER.info("Removing/unlinking file: {}", passwordfilePath);
+            LOGGER.debug("Removing temporary bootstrap key file [{}]", passwordfilePath);
             passwordFile.delete();
 
         } catch (IOException e) {
@@ -446,7 +444,6 @@ public class NiFi implements NiFiEntryPoint {
             System.exit(1);
         }
 
-        LOGGER.info("Read property protection key from key file provided by bootstrap process");
         return key;
     }
 
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/groovy/org/apache/nifi/NiFiGroovyTest.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/groovy/org/apache/nifi/NiFiGroovyTest.groovy
deleted file mode 100644
index 7fdc4dd..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/groovy/org/apache/nifi/NiFiGroovyTest.groovy
+++ /dev/null
@@ -1,285 +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
-
-import ch.qos.logback.classic.spi.LoggingEvent
-import ch.qos.logback.core.AppenderBase
-import org.apache.nifi.properties.ApplicationPropertiesProtector
-import org.apache.nifi.properties.NiFiPropertiesLoader
-import org.apache.nifi.properties.PropertyProtectionScheme
-import org.apache.nifi.properties.ProtectedPropertyContext
-import org.apache.nifi.properties.SensitivePropertyProvider
-import org.apache.nifi.properties.StandardSensitivePropertyProviderFactory
-import org.apache.nifi.util.NiFiProperties
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.junit.After
-import org.junit.AfterClass
-import org.junit.BeforeClass
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.slf4j.bridge.SLF4JBridgeHandler
-
-import javax.crypto.Cipher
-import java.security.Security
-
-@RunWith(JUnit4.class)
-class NiFiGroovyTest extends GroovyTestCase {
-    private static final Logger logger = LoggerFactory.getLogger(NiFiGroovyTest.class)
-
-    private static String originalPropertiesPath = System.getProperty(NiFiProperties.PROPERTIES_FILE_PATH)
-
-    private static final String TEST_RES_PATH = NiFiGroovyTest.getClassLoader().getResource(".").toURI().getPath()
-
-    private static int getMaxKeyLength() {
-        return (Cipher.getMaxAllowedKeyLength("AES") > 128) ? 256 : 128
-    }
-
-    @BeforeClass
-    static void setUpOnce() throws Exception {
-        Security.addProvider(new BouncyCastleProvider())
-
-        SLF4JBridgeHandler.install()
-
-        logger.metaClass.methodMissing = { String name, args ->
-            logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
-        }
-
-        logger.info("Identified test resources path as ${TEST_RES_PATH}")
-    }
-
-    @After
-    void tearDown() throws Exception {
-        TestAppender.reset()
-        System.setIn(System.in)
-    }
-
-    @AfterClass
-    static void tearDownOnce() {
-        if (originalPropertiesPath) {
-            System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, originalPropertiesPath)
-        }
-    }
-
-    @Test
-    void testInitializePropertiesShouldHandleNoBootstrapKey() throws Exception {
-        // Arrange
-        def args = [] as String[]
-
-        String plainPropertiesPath = "${TEST_RES_PATH}/NiFiProperties/conf/nifi.properties"
-        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, plainPropertiesPath)
-
-        // Act
-        NiFiProperties loadedProperties = NiFi.initializeProperties(args, NiFiGroovyTest.class.classLoader)
-
-        // Assert
-        assert loadedProperties.size() > 0
-    }
-
-    @Test
-    void testMainShouldHandleNoBootstrapKeyWithProtectedProperties() throws Exception {
-        // Arrange
-        def args = [] as String[]
-
-        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, "${TEST_RES_PATH}/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_different_key.properties")
-
-        // Act
-        NiFi.main(args)
-
-        // Assert
-        assert TestAppender.events.last().getMessage() == "Failure to launch NiFi due to java.lang.IllegalArgumentException: There was an issue decrypting protected properties"
-    }
-
-    @Test
-    void testParseArgsShouldSplitCombinedArgs() throws Exception {
-        // Arrange
-        def args = ["-K filename"] as String[]
-
-        // Act
-        def parsedArgs = NiFi.parseArgs(args)
-
-        // Assert
-        assert parsedArgs.size() == 2
-        assert parsedArgs == args.join(" ").split(" ") as List
-    }
-
-    @Test
-    void testMainShouldHandleBadArgs() throws Exception {
-        // Arrange
-        def args = ["-K"] as String[]
-
-        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, "${TEST_RES_PATH}/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes.properties")
-
-        // Act
-        NiFi.main(args)
-
-        // Assert
-        assert TestAppender.events.collect {
-            it.getFormattedMessage()
-        }.contains("The bootstrap process passed the -K flag without a filename")
-        assert TestAppender.events.last().getMessage() == "Failure to launch NiFi due to java.lang.IllegalArgumentException: The bootstrap process did not provide a valid key"
-    }
-
-    @Test
-    void testMainShouldHandleMalformedBootstrapKeyFromFile() throws Exception {
-        // Arrange
-        def passwordFile = new File("${TEST_RES_PATH}/NiFiProperties/password-testMainShouldHandleMalformedBootstrapKeyFromFile.txt")
-        passwordFile.text = "BAD KEY"
-        def args = ["-K", passwordFile.absolutePath] as String[]
-
-        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, "${TEST_RES_PATH}/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes.properties")
-
-        // Act
-        NiFi.main(args)
-
-        // Assert
-        assert TestAppender.events.last().getMessage() == "Failure to launch NiFi due to java.lang.IllegalArgumentException: The bootstrap process did not provide a valid key"
-    }
-
-    @Test
-    void testInitializePropertiesShouldSetBootstrapKeyFromFile() throws Exception {
-        // Arrange
-        int currentMaxKeyLengthInBits = getMaxKeyLength()
-
-        // 64 chars of '0' for a 256 bit key; 32 chars for 128 bit
-        final String DIFFERENT_KEY = "0" * (currentMaxKeyLengthInBits / 4)
-        def passwordFile = new File("${TEST_RES_PATH}/NiFiProperties/password-testInitializePropertiesShouldSetBootstrapKeyFromFile.txt")
-        passwordFile.text = DIFFERENT_KEY
-        def args = ["-K", passwordFile.absolutePath] as String[]
-
-        String testPropertiesPath =  "${TEST_RES_PATH}/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_different_key${currentMaxKeyLengthInBits == 256 ? "" : "_128"}.properties"
-        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, testPropertiesPath)
-
-        def protectedNiFiProperties = new NiFiPropertiesLoader().readProtectedPropertiesFromDisk(new File(testPropertiesPath))
-        NiFiProperties unprocessedProperties = protectedNiFiProperties.getApplicationProperties()
-        def protectedKeys = getProtectedKeys(unprocessedProperties)
-        logger.info("Reading from raw properties file gives protected properties: ${protectedKeys}")
-
-        // Act
-        NiFiProperties properties = NiFi.initializeProperties(args, NiFiGroovyTest.class.classLoader)
-
-        // Assert
-
-        // Ensure that there were protected properties, they were encrypted using AES/GCM (128/256 bit key), and they were decrypted (raw value != retrieved value)
-        assert !hasProtectedKeys(properties)
-        def unprotectedProperties = decrypt(protectedNiFiProperties, DIFFERENT_KEY)
-        def protectedPropertyKeys = getProtectedPropertyKeys(unprocessedProperties)
-        protectedPropertyKeys.every { k, v ->
-            String rawValue = protectedNiFiProperties.getProperty(k)
-            logger.raw("${k} -> ${rawValue}")
-            String retrievedValue = properties.getProperty(k)
-            logger.decrypted("${k} -> ${retrievedValue}")
-
-            assert v =~ "aes/gcm"
-
-            logger.assert("${retrievedValue} != ${rawValue}")
-            assert retrievedValue != rawValue
-
-            String decryptedProperty = unprotectedProperties.getProperty(k)
-            logger.assert("${retrievedValue} == ${decryptedProperty}")
-            assert retrievedValue == decryptedProperty
-            true
-        }
-    }
-
-    private static boolean hasProtectedKeys(NiFiProperties properties) {
-        properties.getPropertyKeys().any { it.endsWith(ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX) }
-    }
-
-    private static Map<String, String> getProtectedPropertyKeys(NiFiProperties properties) {
-        getProtectedKeys(properties).collectEntries { String key ->
-            [(key): properties.getProperty(key + ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX)]
-        }
-    }
-
-    private static Set<String> getProtectedKeys(NiFiProperties properties) {
-        properties.getPropertyKeys().findAll { it.endsWith(ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX) }.collect { it - ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX }
-    }
-
-    private static NiFiProperties decrypt(NiFiProperties encryptedProperties, String keyHex) {
-        SensitivePropertyProvider spp = StandardSensitivePropertyProviderFactory.withKey(keyHex)
-                .getProvider(PropertyProtectionScheme.AES_GCM)
-        def map = encryptedProperties.getPropertyKeys().collectEntries { String key ->
-            if (encryptedProperties.getProperty(key + ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX) == spp.getIdentifierKey()) {
-                [(key): spp.unprotect(encryptedProperties.getProperty(key), ProtectedPropertyContext.defaultContext(key))]
-            } else if (!key.endsWith(ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX)) {
-                [(key): encryptedProperties.getProperty(key)]
-            }
-        }
-        new NiFiProperties(map as Properties)
-    }
-
-    @Test
-    void testShouldValidateKeys() {
-        // Arrange
-        final List<String> VALID_KEYS = [
-                "0" * 64, // 256 bit keys
-                "ABCDEF01" * 8,
-                "0123" * 8, // 128 bit keys
-                "0123456789ABCDEFFEDCBA9876543210",
-                "0123456789ABCDEFFEDCBA9876543210".toLowerCase(),
-        ]
-
-        // Act
-        def isValid = VALID_KEYS.collectEntries { String key -> [(key): NiFi.isHexKeyValid(key)] }
-        logger.info("Key validity: ${isValid}")
-
-        // Assert
-        assert isValid.every { k, v -> v }
-    }
-
-    @Test
-    void testShouldNotValidateInvalidKeys() {
-        // Arrange
-        final List<String> VALID_KEYS = [
-                "0" * 63,
-                "ABCDEFG1" * 8,
-                "0123" * 9,
-                "0123456789ABCDEFFEDCBA987654321",
-                "0123456789ABCDEF FEDCBA9876543210".toLowerCase(),
-                null,
-                "",
-                "        "
-        ]
-
-        // Act
-        def isValid = VALID_KEYS.collectEntries { String key -> [(key): NiFi.isHexKeyValid(key)] }
-        logger.info("Key validity: ${isValid}")
-
-        // Assert
-        assert isValid.every { k, v -> !v }
-    }
-}
-
-class TestAppender extends AppenderBase<LoggingEvent> {
-    static List<LoggingEvent> events = new ArrayList<>()
-
-    @Override
-    protected void append(LoggingEvent e) {
-        synchronized (events) {
-            events.add(e)
-        }
-    }
-
-    static void reset() {
-        synchronized (events) {
-            events.clear()
-        }
-    }
-}
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/java/org/apache/nifi/ListAppender.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/java/org/apache/nifi/ListAppender.java
new file mode 100644
index 0000000..f27f935
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/java/org/apache/nifi/ListAppender.java
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ListAppender extends AppenderBase<LoggingEvent> {
+    private static final List<LoggingEvent> LOGGING_EVENTS = Collections.synchronizedList(new ArrayList<>());
+
+    public static List<LoggingEvent> getLoggingEvents() {
+        return LOGGING_EVENTS;
+    }
+
+    public static void clear() {
+        LOGGING_EVENTS.clear();
+    }
+
+    @Override
+    protected void append(final LoggingEvent loggingEvent) {
+        LOGGING_EVENTS.add(loggingEvent);
+    }
+}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/java/org/apache/nifi/NiFiTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/java/org/apache/nifi/NiFiTest.java
new file mode 100644
index 0000000..f95024a
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/java/org/apache/nifi/NiFiTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.util.NiFiProperties;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class NiFiTest {
+    private static final String[] ARGUMENTS = new String[]{};
+
+    private static final String KEY_ARGUMENT = "-K";
+
+    private static final String[] FILE_NOT_SPECIFIED_ARGUMENTS = new String[]{ KEY_ARGUMENT };
+
+    private static final String FAILURE_TO_LAUNCH = "Failure to launch NiFi";
+
+    private static final String PROPERTIES_LOADED = "Application Properties loaded";
+
+    private static final String PROPERTIES_PATH = "/NiFiProperties/conf/nifi.properties";
+
+    private static final String ENCRYPTED_PROPERTIES_PATH = "/NiFiProperties/conf/encrypted.nifi.properties";
+
+    private static final String ROOT_KEY = StringUtils.repeat("0", 64);
+
+    @BeforeEach
+    public void setAppender() {
+        ListAppender.clear();
+    }
+
+    @AfterEach
+    public void clearPropertiesFilePath() {
+        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, StringUtils.EMPTY);
+    }
+
+    @Test
+    public void testMainBootstrapKeyFileNotSpecified() {
+        setPropertiesFilePath(PROPERTIES_PATH);
+
+        NiFi.main(FILE_NOT_SPECIFIED_ARGUMENTS);
+
+        assertFailureToLaunch();
+    }
+
+    @Test
+    public void testMainBootstrapKeyNotSpecified() {
+        setPropertiesFilePath(PROPERTIES_PATH);
+
+        NiFi.main(ARGUMENTS);
+
+        assertFailureToLaunch();
+    }
+
+    @Test
+    public void testMainEncryptedNiFiProperties() throws IOException {
+        final File rootKeyFile = File.createTempFile(getClass().getSimpleName(), ".root.key");
+        rootKeyFile.deleteOnExit();
+        try (final PrintWriter writer = new PrintWriter(new FileWriter(rootKeyFile))) {
+            writer.println(ROOT_KEY);
+        }
+
+        setPropertiesFilePath(ENCRYPTED_PROPERTIES_PATH);
+
+        NiFi.main(new String[]{ KEY_ARGUMENT, rootKeyFile.getAbsolutePath() });
+
+        assertApplicationPropertiesLoaded();
+        assertFailureToLaunch();
+    }
+
+    private void assertApplicationPropertiesLoaded() {
+        final Optional<LoggingEvent> event = ListAppender.getLoggingEvents().stream().filter(
+                loggingEvent -> loggingEvent.getMessage().startsWith(PROPERTIES_LOADED)
+        ).findFirst();
+        assertTrue(event.isPresent(), "Properties loaded log not found");
+    }
+
+    private void assertFailureToLaunch() {
+        final Optional<LoggingEvent> event = ListAppender.getLoggingEvents().stream().filter(
+                loggingEvent -> loggingEvent.getMessage().startsWith(FAILURE_TO_LAUNCH)
+        ).findFirst();
+        assertTrue(event.isPresent(), "Failure log not found");
+    }
+
+    private void setPropertiesFilePath(final String relativePath) {
+        System.setProperty(NiFiProperties.PROPERTIES_FILE_PATH, getResourcesPath(relativePath));
+    }
+
+    private String getResourcesPath(final String relativePath) {
+        return getClass().getResource(relativePath).getPath();
+    }
+}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_different_key.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/encrypted.nifi.properties
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_different_key.properties
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/encrypted.nifi.properties
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes.properties
deleted file mode 100644
index ec3e440..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes.properties
+++ /dev/null
@@ -1,183 +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.
-
-# Core Properties #
-nifi.flow.configuration.file=./target/conf/flow.xml.gz
-nifi.flow.configuration.archive.enabled=true
-nifi.flow.configuration.archive.dir=./target/conf/archive/
-nifi.flow.configuration.archive.max.time=30 days
-nifi.flow.configuration.archive.max.storage=500 MB
-nifi.flowcontroller.autoResumeState=true
-nifi.flowcontroller.graceful.shutdown.period=10 sec
-nifi.flowservice.writedelay.interval=500 ms
-nifi.administrative.yield.duration=30 sec
-# If a component has no work to do (is "bored"), how long should we wait before checking again for work?
-nifi.bored.yield.duration=10 millis
-
-nifi.authorizer.configuration.file=./target/conf/authorizers.xml
-nifi.login.identity.provider.configuration.file=./target/conf/login-identity-providers.xml
-nifi.templates.directory=./target/conf/templates
-nifi.ui.banner.text=n8hL1zgQcYpG70Vm||e1hYsrc7FLvi1E9LcHM1VYeN5atWJIGg/WCsyuxxNqN1lK1ASGEZR8040NFZNqwsnbx+
-nifi.ui.banner.text.protected=aes/gcm/256
-nifi.ui.autorefresh.interval=30 sec
-nifi.nar.library.directory=./target/lib
-nifi.nar.working.directory=./target/work/nar/
-nifi.documentation.working.directory=./target/work/docs/components
-
-####################
-# State Management #
-####################
-nifi.state.management.configuration.file=./target/conf/state-management.xml
-# The ID of the local state provider
-nifi.state.management.provider.local=local-provider
-# The ID of the cluster-wide state provider. This will be ignored if NiFi is not clustered but must be populated if running in a cluster.
-nifi.state.management.provider.cluster=zk-provider
-# Specifies whether or not this instance of NiFi should run an embedded ZooKeeper server
-nifi.state.management.embedded.zookeeper.start=false
-# Properties file that provides the ZooKeeper properties to use if <nifi.state.management.embedded.zookeeper.start> is set to true
-nifi.state.management.embedded.zookeeper.properties=./target/conf/zookeeper.properties
-
-
-# H2 Settings
-nifi.database.directory=./target/database_repository
-nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
-
-# FlowFile Repository
-nifi.flowfile.repository.implementation=org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
-nifi.flowfile.repository.directory=./target/flowfile_repository
-nifi.flowfile.repository.partitions=256
-nifi.flowfile.repository.checkpoint.interval=2 mins
-nifi.flowfile.repository.always.sync=false
-
-nifi.swap.manager.implementation=org.apache.nifi.controller.FileSystemSwapManager
-nifi.queue.swap.threshold=20000
-nifi.swap.in.period=5 sec
-nifi.swap.in.threads=1
-nifi.swap.out.period=5 sec
-nifi.swap.out.threads=4
-
-# Content Repository
-nifi.content.repository.implementation=org.apache.nifi.controller.repository.FileSystemRepository
-nifi.content.claim.max.appendable.size=10 MB
-nifi.content.claim.max.flow.files=100
-nifi.content.repository.directory.default=./target/content_repository
-nifi.content.repository.archive.max.retention.period=12 hours
-nifi.content.repository.archive.max.usage.percentage=50%
-nifi.content.repository.archive.enabled=true
-nifi.content.repository.always.sync=false
-nifi.content.viewer.url=/nifi-content-viewer/
-
-# Provenance Repository Properties
-nifi.provenance.repository.implementation=org.apache.nifi.provenance.PersistentProvenanceRepository
-
-# Persistent Provenance Repository Properties
-nifi.provenance.repository.directory.default=./target/provenance_repository
-nifi.provenance.repository.max.storage.time=24 hours
-nifi.provenance.repository.max.storage.size=1 GB
-nifi.provenance.repository.rollover.time=30 secs
-nifi.provenance.repository.rollover.size=100 MB
-nifi.provenance.repository.query.threads=2
-nifi.provenance.repository.index.threads=1
-nifi.provenance.repository.compress.on.rollover=true
-nifi.provenance.repository.always.sync=false
-nifi.provenance.repository.journal.count=16
-# Comma-separated list of fields. Fields that are not indexed will not be searchable. Valid fields are:
-# EventType, FlowFileUUID, Filename, TransitURI, ProcessorID, AlternateIdentifierURI, Relationship, Details
-nifi.provenance.repository.indexed.fields=EventType, FlowFileUUID, Filename, ProcessorID, Relationship
-# FlowFile Attributes that should be indexed and made searchable.  Some examples to consider are filename, uuid, mime.type
-nifi.provenance.repository.indexed.attributes=
-# Large values for the shard size will result in more Java heap usage when searching the Provenance Repository
-# but should provide better performance
-nifi.provenance.repository.index.shard.size=500 MB
-# Indicates the maximum length that a FlowFile attribute can be when retrieving a Provenance Event from
-# the repository. If the length of any attribute exceeds this value, it will be truncated when the event is retrieved.
-nifi.provenance.repository.max.attribute.length=65536
-
-# Volatile Provenance Respository Properties
-nifi.provenance.repository.buffer.size=100000
-
-# Component Status Repository
-nifi.components.status.repository.implementation=org.apache.nifi.controller.status.history.VolatileComponentStatusRepository
-nifi.components.status.repository.buffer.size=1440
-nifi.components.status.snapshot.frequency=1 min
-
-# Site to Site properties
-nifi.remote.input.host=
-nifi.remote.input.secure=false
-nifi.remote.input.socket.port=
-nifi.remote.input.http.enabled=true
-nifi.remote.input.http.transaction.ttl=30 sec
-
-# web properties #
-nifi.web.war.directory=./target/lib
-nifi.web.http.host=
-nifi.web.http.port=8080
-nifi.web.https.host=
-nifi.web.https.port=
-nifi.web.jetty.working.directory=./target/work/jetty
-nifi.web.jetty.threads=200
-
-# security properties #
-nifi.sensitive.props.key=
-nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
-nifi.sensitive.props.additional.keys=nifi.ui.banner.text
-
-nifi.security.keystore=
-nifi.security.keystoreType=
-nifi.security.keystorePasswd=
-nifi.security.keyPasswd=
-nifi.security.truststore=
-nifi.security.truststoreType=
-nifi.security.truststorePasswd=
-nifi.security.user.authorizer=file-provider
-nifi.security.user.login.identity.provider=
-nifi.security.ocsp.responder.url=
-nifi.security.ocsp.responder.certificate=
-
-# Identity Mapping Properties #
-# These properties allow normalizing user identities such that identities coming from different identity providers
-# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
-# DNs from certificates and principals from Kerberos into a common identity string:
-#
-# nifi.security.identity.mapping.pattern.dn=^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$
-# nifi.security.identity.mapping.value.dn=$1@$2
-# nifi.security.identity.mapping.pattern.kerb=^(.*?)/instance@(.*?)$
-# nifi.security.identity.mapping.value.kerb=$1@$2
-
-# cluster common properties (all nodes must have same values) #
-nifi.cluster.protocol.heartbeat.interval=5 sec
-nifi.cluster.protocol.is.secure=false
-
-# cluster node properties (only configure for cluster nodes) #
-nifi.cluster.is.node=false
-nifi.cluster.node.address=
-nifi.cluster.node.protocol.port=
-nifi.cluster.node.protocol.threads=10
-nifi.cluster.node.event.history.size=25
-nifi.cluster.node.connection.timeout=5 sec
-nifi.cluster.node.read.timeout=5 sec
-nifi.cluster.firewall.file=
-
-# zookeeper properties, used for cluster management #
-nifi.zookeeper.connect.string=
-nifi.zookeeper.connect.timeout=3 secs
-nifi.zookeeper.session.timeout=3 secs
-nifi.zookeeper.root.node=/nifi
-
-# kerberos #
-nifi.kerberos.krb5.file=
-nifi.kerberos.service.principal=
-nifi.kerberos.keytab.location=
-nifi.kerberos.authentication.expiration=12 hours
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_128.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_128.properties
deleted file mode 100644
index eba1ad1..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_128.properties
+++ /dev/null
@@ -1,183 +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.
-
-# Core Properties #
-nifi.flow.configuration.file=./target/conf/flow.xml.gz
-nifi.flow.configuration.archive.enabled=true
-nifi.flow.configuration.archive.dir=./target/conf/archive/
-nifi.flow.configuration.archive.max.time=30 days
-nifi.flow.configuration.archive.max.storage=500 MB
-nifi.flowcontroller.autoResumeState=true
-nifi.flowcontroller.graceful.shutdown.period=10 sec
-nifi.flowservice.writedelay.interval=500 ms
-nifi.administrative.yield.duration=30 sec
-# If a component has no work to do (is "bored"), how long should we wait before checking again for work?
-nifi.bored.yield.duration=10 millis
-
-nifi.authorizer.configuration.file=./target/conf/authorizers.xml
-nifi.login.identity.provider.configuration.file=./target/conf/login-identity-providers.xml
-nifi.templates.directory=./target/conf/templates
-nifi.ui.banner.text=27BJszAmDdMuexAk||fYvTyQ3k/jlV9aiu8Ff7rF6cDDlVO0eXtGOQqR0LQDISq5VlnpHMvHVFgHxAaIRMWZy0
-nifi.ui.banner.text.protected=aes/gcm/128
-nifi.ui.autorefresh.interval=30 sec
-nifi.nar.library.directory=./target/lib
-nifi.nar.working.directory=./target/work/nar/
-nifi.documentation.working.directory=./target/work/docs/components
-
-####################
-# State Management #
-####################
-nifi.state.management.configuration.file=./target/conf/state-management.xml
-# The ID of the local state provider
-nifi.state.management.provider.local=local-provider
-# The ID of the cluster-wide state provider. This will be ignored if NiFi is not clustered but must be populated if running in a cluster.
-nifi.state.management.provider.cluster=zk-provider
-# Specifies whether or not this instance of NiFi should run an embedded ZooKeeper server
-nifi.state.management.embedded.zookeeper.start=false
-# Properties file that provides the ZooKeeper properties to use if <nifi.state.management.embedded.zookeeper.start> is set to true
-nifi.state.management.embedded.zookeeper.properties=./target/conf/zookeeper.properties
-
-
-# H2 Settings
-nifi.database.directory=./target/database_repository
-nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
-
-# FlowFile Repository
-nifi.flowfile.repository.implementation=org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
-nifi.flowfile.repository.directory=./target/flowfile_repository
-nifi.flowfile.repository.partitions=256
-nifi.flowfile.repository.checkpoint.interval=2 mins
-nifi.flowfile.repository.always.sync=false
-
-nifi.swap.manager.implementation=org.apache.nifi.controller.FileSystemSwapManager
-nifi.queue.swap.threshold=20000
-nifi.swap.in.period=5 sec
-nifi.swap.in.threads=1
-nifi.swap.out.period=5 sec
-nifi.swap.out.threads=4
-
-# Content Repository
-nifi.content.repository.implementation=org.apache.nifi.controller.repository.FileSystemRepository
-nifi.content.claim.max.appendable.size=10 MB
-nifi.content.claim.max.flow.files=100
-nifi.content.repository.directory.default=./target/content_repository
-nifi.content.repository.archive.max.retention.period=12 hours
-nifi.content.repository.archive.max.usage.percentage=50%
-nifi.content.repository.archive.enabled=true
-nifi.content.repository.always.sync=false
-nifi.content.viewer.url=/nifi-content-viewer/
-
-# Provenance Repository Properties
-nifi.provenance.repository.implementation=org.apache.nifi.provenance.PersistentProvenanceRepository
-
-# Persistent Provenance Repository Properties
-nifi.provenance.repository.directory.default=./target/provenance_repository
-nifi.provenance.repository.max.storage.time=24 hours
-nifi.provenance.repository.max.storage.size=1 GB
-nifi.provenance.repository.rollover.time=30 secs
-nifi.provenance.repository.rollover.size=100 MB
-nifi.provenance.repository.query.threads=2
-nifi.provenance.repository.index.threads=1
-nifi.provenance.repository.compress.on.rollover=true
-nifi.provenance.repository.always.sync=false
-nifi.provenance.repository.journal.count=16
-# Comma-separated list of fields. Fields that are not indexed will not be searchable. Valid fields are:
-# EventType, FlowFileUUID, Filename, TransitURI, ProcessorID, AlternateIdentifierURI, Relationship, Details
-nifi.provenance.repository.indexed.fields=EventType, FlowFileUUID, Filename, ProcessorID, Relationship
-# FlowFile Attributes that should be indexed and made searchable.  Some examples to consider are filename, uuid, mime.type
-nifi.provenance.repository.indexed.attributes=
-# Large values for the shard size will result in more Java heap usage when searching the Provenance Repository
-# but should provide better performance
-nifi.provenance.repository.index.shard.size=500 MB
-# Indicates the maximum length that a FlowFile attribute can be when retrieving a Provenance Event from
-# the repository. If the length of any attribute exceeds this value, it will be truncated when the event is retrieved.
-nifi.provenance.repository.max.attribute.length=65536
-
-# Volatile Provenance Respository Properties
-nifi.provenance.repository.buffer.size=100000
-
-# Component Status Repository
-nifi.components.status.repository.implementation=org.apache.nifi.controller.status.history.VolatileComponentStatusRepository
-nifi.components.status.repository.buffer.size=1440
-nifi.components.status.snapshot.frequency=1 min
-
-# Site to Site properties
-nifi.remote.input.host=
-nifi.remote.input.secure=false
-nifi.remote.input.socket.port=
-nifi.remote.input.http.enabled=true
-nifi.remote.input.http.transaction.ttl=30 sec
-
-# web properties #
-nifi.web.war.directory=./target/lib
-nifi.web.http.host=
-nifi.web.http.port=8080
-nifi.web.https.host=
-nifi.web.https.port=
-nifi.web.jetty.working.directory=./target/work/jetty
-nifi.web.jetty.threads=200
-
-# security properties #
-nifi.sensitive.props.key=
-nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
-nifi.sensitive.props.additional.keys=nifi.ui.banner.text
-
-nifi.security.keystore=
-nifi.security.keystoreType=
-nifi.security.keystorePasswd=
-nifi.security.keyPasswd=
-nifi.security.truststore=
-nifi.security.truststoreType=
-nifi.security.truststorePasswd=
-nifi.security.user.authorizer=file-provider
-nifi.security.user.login.identity.provider=
-nifi.security.ocsp.responder.url=
-nifi.security.ocsp.responder.certificate=
-
-# Identity Mapping Properties #
-# These properties allow normalizing user identities such that identities coming from different identity providers
-# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
-# DNs from certificates and principals from Kerberos into a common identity string:
-#
-# nifi.security.identity.mapping.pattern.dn=^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$
-# nifi.security.identity.mapping.value.dn=$1@$2
-# nifi.security.identity.mapping.pattern.kerb=^(.*?)/instance@(.*?)$
-# nifi.security.identity.mapping.value.kerb=$1@$2
-
-# cluster common properties (all nodes must have same values) #
-nifi.cluster.protocol.heartbeat.interval=5 sec
-nifi.cluster.protocol.is.secure=false
-
-# cluster node properties (only configure for cluster nodes) #
-nifi.cluster.is.node=false
-nifi.cluster.node.address=
-nifi.cluster.node.protocol.port=
-nifi.cluster.node.protocol.threads=10
-nifi.cluster.node.event.history.size=25
-nifi.cluster.node.connection.timeout=5 sec
-nifi.cluster.node.read.timeout=5 sec
-nifi.cluster.firewall.file=
-
-# zookeeper properties, used for cluster management #
-nifi.zookeeper.connect.string=
-nifi.zookeeper.connect.timeout=3 secs
-nifi.zookeeper.session.timeout=3 secs
-nifi.zookeeper.root.node=/nifi
-
-# kerberos #
-nifi.kerberos.krb5.file=
-nifi.kerberos.service.principal=
-nifi.kerberos.keytab.location=
-nifi.kerberos.authentication.expiration=12 hours
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_different_key_128.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_different_key_128.properties
deleted file mode 100644
index 4ca2dfd..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/NiFiProperties/conf/nifi_with_sensitive_properties_protected_aes_different_key_128.properties
+++ /dev/null
@@ -1,186 +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.
-
-# Core Properties #
-nifi.flow.configuration.file=./target/conf/flow.xml.gz
-nifi.flow.configuration.archive.enabled=true
-nifi.flow.configuration.archive.dir=./target/conf/archive/
-nifi.flow.configuration.archive.max.time=30 days
-nifi.flow.configuration.archive.max.storage=500 MB
-nifi.flowcontroller.autoResumeState=true
-nifi.flowcontroller.graceful.shutdown.period=10 sec
-nifi.flowservice.writedelay.interval=500 ms
-nifi.administrative.yield.duration=30 sec
-# If a component has no work to do (is "bored"), how long should we wait before checking again for work?
-nifi.bored.yield.duration=10 millis
-
-nifi.authorizer.configuration.file=./target/conf/authorizers.xml
-nifi.login.identity.provider.configuration.file=./target/conf/login-identity-providers.xml
-nifi.templates.directory=./target/conf/templates
-nifi.ui.banner.text=Oz8CaBm6MBkMt/Qq||VUgDFT/PBSjTqJsKXZwdn9hMADEwmp+7Ezx5zHSMXVxLcC947pgqJTf8I0bFrLQqE6i6
-nifi.ui.banner.text.protected=aes/gcm/128
-nifi.ui.autorefresh.interval=30 sec
-nifi.nar.library.directory=./target/lib
-nifi.nar.working.directory=./target/work/nar/
-nifi.documentation.working.directory=./target/work/docs/components
-
-####################
-# State Management #
-####################
-nifi.state.management.configuration.file=./target/conf/state-management.xml
-# The ID of the local state provider
-nifi.state.management.provider.local=local-provider
-# The ID of the cluster-wide state provider. This will be ignored if NiFi is not clustered but must be populated if running in a cluster.
-nifi.state.management.provider.cluster=zk-provider
-# Specifies whether or not this instance of NiFi should run an embedded ZooKeeper server
-nifi.state.management.embedded.zookeeper.start=false
-# Properties file that provides the ZooKeeper properties to use if <nifi.state.management.embedded.zookeeper.start> is set to true
-nifi.state.management.embedded.zookeeper.properties=./target/conf/zookeeper.properties
-
-
-# H2 Settings
-nifi.database.directory=./target/database_repository
-nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
-
-# FlowFile Repository
-nifi.flowfile.repository.implementation=org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
-nifi.flowfile.repository.directory=./target/flowfile_repository
-nifi.flowfile.repository.partitions=256
-nifi.flowfile.repository.checkpoint.interval=2 mins
-nifi.flowfile.repository.always.sync=false
-
-nifi.swap.manager.implementation=org.apache.nifi.controller.FileSystemSwapManager
-nifi.queue.swap.threshold=20000
-nifi.swap.in.period=5 sec
-nifi.swap.in.threads=1
-nifi.swap.out.period=5 sec
-nifi.swap.out.threads=4
-
-# Content Repository
-nifi.content.repository.implementation=org.apache.nifi.controller.repository.FileSystemRepository
-nifi.content.claim.max.appendable.size=10 MB
-nifi.content.claim.max.flow.files=100
-nifi.content.repository.directory.default=./target/content_repository
-nifi.content.repository.archive.max.retention.period=12 hours
-nifi.content.repository.archive.max.usage.percentage=50%
-nifi.content.repository.archive.enabled=true
-nifi.content.repository.always.sync=false
-nifi.content.viewer.url=/nifi-content-viewer/
-
-# Provenance Repository Properties
-nifi.provenance.repository.implementation=org.apache.nifi.provenance.PersistentProvenanceRepository
-
-# Persistent Provenance Repository Properties
-nifi.provenance.repository.directory.default=./target/provenance_repository
-nifi.provenance.repository.max.storage.time=24 hours
-nifi.provenance.repository.max.storage.size=1 GB
-nifi.provenance.repository.rollover.time=30 secs
-nifi.provenance.repository.rollover.size=100 MB
-nifi.provenance.repository.query.threads=2
-nifi.provenance.repository.index.threads=1
-nifi.provenance.repository.compress.on.rollover=true
-nifi.provenance.repository.always.sync=false
-nifi.provenance.repository.journal.count=16
-# Comma-separated list of fields. Fields that are not indexed will not be searchable. Valid fields are:
-# EventType, FlowFileUUID, Filename, TransitURI, ProcessorID, AlternateIdentifierURI, Relationship, Details
-nifi.provenance.repository.indexed.fields=EventType, FlowFileUUID, Filename, ProcessorID, Relationship
-# FlowFile Attributes that should be indexed and made searchable.  Some examples to consider are filename, uuid, mime.type
-nifi.provenance.repository.indexed.attributes=
-# Large values for the shard size will result in more Java heap usage when searching the Provenance Repository
-# but should provide better performance
-nifi.provenance.repository.index.shard.size=500 MB
-# Indicates the maximum length that a FlowFile attribute can be when retrieving a Provenance Event from
-# the repository. If the length of any attribute exceeds this value, it will be truncated when the event is retrieved.
-nifi.provenance.repository.max.attribute.length=65536
-
-# Volatile Provenance Respository Properties
-nifi.provenance.repository.buffer.size=100000
-
-# Component Status Repository
-nifi.components.status.repository.implementation=org.apache.nifi.controller.status.history.VolatileComponentStatusRepository
-nifi.components.status.repository.buffer.size=1440
-nifi.components.status.snapshot.frequency=1 min
-
-# Site to Site properties
-nifi.remote.input.host=
-nifi.remote.input.secure=false
-nifi.remote.input.socket.port=
-nifi.remote.input.http.enabled=true
-nifi.remote.input.http.transaction.ttl=30 sec
-
-# web properties #
-nifi.web.war.directory=./target/lib
-nifi.web.http.host=
-nifi.web.http.port=8080
-nifi.web.https.host=
-nifi.web.https.port=
-nifi.web.jetty.working.directory=./target/work/jetty
-nifi.web.jetty.threads=200
-
-# security properties #
-nifi.sensitive.props.key=rs7OIQ1levcunDAt||9iJDLs0XREoyAjiV9BTCYLdsoHJQ9DxSvRmOhnVs9wC5ffl24pvLjZkeGkNzbQ
-nifi.sensitive.props.key.protected=aes/gcm/128
-nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
-nifi.sensitive.props.additional.keys=nifi.ui.banner.text
-
-nifi.security.keystore=/path/to/keystore.jks
-nifi.security.keystoreType=JKS
-nifi.security.keystorePasswd=zvww8lpJFCXBmdiW||SqHaIINVVjBVPGxaDfp3a1qWKRIkf1qCSIooduFOmQOMWiZLbvJ6eHoH
-nifi.security.keystorePasswd.protected=aes/gcm/128
-nifi.security.keyPasswd=9xLoWaOzNotWRLcd||HSlgmdUjOzkSuvxcWVuVH290nUzrUPL9E9Au1txDQqzpLYW/jQ
-nifi.security.keyPasswd.protected=aes/gcm/128
-nifi.security.truststore=
-nifi.security.truststoreType=
-nifi.security.truststorePasswd=
-nifi.security.user.authorizer=file-provider
-nifi.security.user.login.identity.provider=
-nifi.security.ocsp.responder.url=
-nifi.security.ocsp.responder.certificate=
-
-# Identity Mapping Properties #
-# These properties allow normalizing user identities such that identities coming from different identity providers
-# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
-# DNs from certificates and principals from Kerberos into a common identity string:
-#
-# nifi.security.identity.mapping.pattern.dn=^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$
-# nifi.security.identity.mapping.value.dn=$1@$2
-# nifi.security.identity.mapping.pattern.kerb=^(.*?)/instance@(.*?)$
-# nifi.security.identity.mapping.value.kerb=$1@$2
-
-# cluster common properties (all nodes must have same values) #
-nifi.cluster.protocol.heartbeat.interval=5 sec
-nifi.cluster.protocol.is.secure=false
-
-# cluster node properties (only configure for cluster nodes) #
-nifi.cluster.is.node=false
-nifi.cluster.node.address=
-nifi.cluster.node.protocol.port=
-nifi.cluster.node.protocol.threads=10
-nifi.cluster.node.event.history.size=25
-nifi.cluster.node.connection.timeout=5 sec
-nifi.cluster.node.read.timeout=5 sec
-nifi.cluster.firewall.file=
-
-# zookeeper properties, used for cluster management #
-nifi.zookeeper.connect.string=
-nifi.zookeeper.connect.timeout=3 secs
-nifi.zookeeper.session.timeout=3 secs
-nifi.zookeeper.root.node=/nifi
-
-# kerberos #
-nifi.kerberos.krb5.file=
-nifi.kerberos.service.principal=
-nifi.kerberos.keytab.location=
-nifi.kerberos.authentication.expiration=12 hours
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/logback-test.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/logback-test.xml
index 7f0a03b..7a7385c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/logback-test.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/src/test/resources/logback-test.xml
@@ -15,12 +15,7 @@
 -->
 
 <configuration>
-    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
-        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
-            <pattern>%-4r [%t] %-5p %c - %m%n</pattern>
-        </encoder>
-    </appender>
-    <appender name="TEST" class="org.apache.nifi.TestAppender">
+    <appender name="TEST" class="org.apache.nifi.ListAppender">
         <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
             <pattern>%-4r [%t] %-5p %c - %m%n</pattern>
         </encoder>
@@ -28,7 +23,6 @@
 
     <logger name="org.apache.nifi.processor" level="DEBUG"/>
     <root level="DEBUG">
-        <appender-ref ref="CONSOLE"/>
         <appender-ref ref="TEST"/>
     </root>
 </configuration>