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

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


The following commit(s) were added to refs/heads/support/nifi-1.x by this push:
     new 3649ade3c7 NIFI-11536 Corrected Keystore and Truststore auto-reloading
3649ade3c7 is described below

commit 3649ade3c74eb88828cb59c7c8923acc7eb27f34
Author: Emilio Setiadarma <[email protected]>
AuthorDate: Mon Jun 26 18:00:06 2023 -0700

    NIFI-11536 Corrected Keystore and Truststore auto-reloading
    
    - Replaced Jetty KeyStoreScanner and custom TrustStoreScanner with shared 
StoreScanner
    - New StoreScanner uses TLS Configuration to reload SSLContext instead of 
relying on Jetty SslContextFactory properties
    
    This closes #7446
    
    Signed-off-by: David Handermann <[email protected]>
    (cherry picked from commit a85ef2c1f49780be93b49ec6cb077a61c8cc063e)
---
 .../connector/FrameworkServerConnectorFactory.java |   7 +-
 .../apache/nifi/web/server/util/StoreScanner.java  | 158 +++++++++++++++++++++
 .../nifi/web/server/util/TrustStoreScanner.java    | 151 --------------------
 .../FrameworkServerConnectorFactoryTest.java       |  11 +-
 .../nifi/web/server/util/StoreScannerTest.java     | 143 +++++++++++++++++++
 .../web/server/util/TrustStoreScannerTest.java     |  85 -----------
 6 files changed, 308 insertions(+), 247 deletions(-)

diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
index c434010f3d..829a5578f6 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
@@ -27,10 +27,9 @@ import org.apache.nifi.security.util.TlsException;
 import org.apache.nifi.security.util.TlsPlatform;
 import org.apache.nifi.util.FormatUtils;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.server.util.TrustStoreScanner;
+import org.apache.nifi.web.server.util.StoreScanner;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.util.ssl.KeyStoreScanner;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 
 import javax.net.ssl.SSLContext;
@@ -149,12 +148,12 @@ public class FrameworkServerConnectorFactory extends 
StandardServerConnectorFact
 
             if (storeScanInterval != null) {
                 
sslContextFactory.setKeyStorePath(tlsConfiguration.getKeystorePath());
-                final KeyStoreScanner keyStoreScanner = new 
KeyStoreScanner(sslContextFactory);
+                final StoreScanner keyStoreScanner = new 
StoreScanner(sslContextFactory, tlsConfiguration, 
sslContextFactory.getKeyStoreResource());
                 keyStoreScanner.setScanInterval(storeScanInterval);
                 getServer().addBean(keyStoreScanner);
 
                 
sslContextFactory.setTrustStorePath(tlsConfiguration.getTruststorePath());
-                final TrustStoreScanner trustStoreScanner = new 
TrustStoreScanner(sslContextFactory);
+                final StoreScanner trustStoreScanner = new 
StoreScanner(sslContextFactory, tlsConfiguration, 
sslContextFactory.getTrustStoreResource());
                 trustStoreScanner.setScanInterval(storeScanInterval);
                 getServer().addBean(trustStoreScanner);
             }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/StoreScanner.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/StoreScanner.java
new file mode 100644
index 0000000000..daf7c02db4
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/StoreScanner.java
@@ -0,0 +1,158 @@
+/*
+ * 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.web.server.util;
+
+import org.apache.nifi.security.util.TlsConfiguration;
+import org.apache.nifi.security.util.TlsException;
+import org.eclipse.jetty.util.Scanner;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedOperation;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.apache.nifi.security.util.SslContextFactory.createSslContext;
+
+/**
+ * File Scanner for Keystore or Truststore reloading using provided TLS 
Configuration
+ */
+public class StoreScanner extends ContainerLifeCycle implements 
Scanner.DiscreteListener {
+    private static final Logger LOG = Log.getLogger(StoreScanner.class);
+
+    private final SslContextFactory sslContextFactory;
+    private final TlsConfiguration tlsConfiguration;
+    private final File file;
+    private final Scanner scanner;
+    private final String resourceName;
+
+    public StoreScanner(final SslContextFactory sslContextFactory,
+                           final TlsConfiguration tlsConfiguration,
+                           final Resource resource) {
+        this.sslContextFactory = sslContextFactory;
+        this.tlsConfiguration = tlsConfiguration;
+        this.resourceName = resource.getName();
+        try {
+            File monitoredFile = resource.getFile();
+            if (monitoredFile == null || !monitoredFile.exists()) {
+                throw new IllegalArgumentException(String.format("%s file does 
not exist", resourceName));
+            }
+            if (monitoredFile.isDirectory()) {
+                throw new IllegalArgumentException(String.format("expected %s 
file not directory", resourceName));
+            }
+
+            if (resource.getAlias() != null) {
+                // this resource has an alias, use the alias, as that's what's 
returned in the Scanner
+                monitoredFile = new File(resource.getAlias());
+            }
+
+            file = monitoredFile;
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("File monitoring started {} [{}]", resourceName, 
monitoredFile);
+            }
+        } catch (final IOException e) {
+            throw new IllegalArgumentException(String.format("could not obtain 
%s file", resourceName), e);
+        }
+
+        File parentFile = file.getParentFile();
+        if (!parentFile.exists() || !parentFile.isDirectory()) {
+            throw new IllegalArgumentException(String.format("error obtaining 
%s dir", resourceName));
+        }
+
+        scanner = new Scanner();
+        scanner.setScanDirs(Collections.singletonList(parentFile));
+        scanner.setScanInterval(1);
+        scanner.setReportDirs(false);
+        scanner.setReportExistingFilesOnStartup(false);
+        scanner.setScanDepth(1);
+        scanner.addListener(this);
+        addBean(scanner);
+    }
+
+    @Override
+    public void fileAdded(final String filename) {
+        LOG.debug("Resource [{}] File [{}] added", resourceName, filename);
+        reloadMatched(filename);
+    }
+
+    @Override
+    public void fileChanged(final String filename) {
+        LOG.debug("Resource [{}] File [{}] changed", resourceName, filename);
+        reloadMatched(filename);
+    }
+
+    @Override
+    public void fileRemoved(final String filename) {
+        LOG.debug("Resource [{}] File [{}] removed", resourceName, filename);
+        reloadMatched(filename);
+    }
+
+    @ManagedOperation(
+            value = "Scan for changes in the SSL Keystore/Truststore",
+            impact = "ACTION"
+    )
+    public void scan() {
+        LOG.debug("Resource [{}] scanning started", resourceName);
+
+        this.scanner.scan();
+        this.scanner.scan();
+    }
+
+    @ManagedOperation(
+            value = "Reload the SSL Keystore/Truststore",
+            impact = "ACTION"
+    )
+    public void reload() {
+        LOG.debug("File [{}] reload started", file);
+
+        try {
+            this.sslContextFactory.reload(contextFactory -> 
contextFactory.setSslContext(createContext()));
+            LOG.info("File [{}] reload completed", file);
+        } catch (final Throwable t) {
+            LOG.warn("File [{}] reload failed", file, t);
+        }
+    }
+
+    @ManagedAttribute("scanning interval to detect changes which need 
reloaded")
+    public int getScanInterval() {
+        return this.scanner.getScanInterval();
+    }
+
+    public void setScanInterval(int scanInterval) {
+        this.scanner.setScanInterval(scanInterval);
+    }
+
+    private void reloadMatched(final String filename) {
+        if (file.toPath().toString().equals(filename)) {
+            reload();
+        }
+    }
+
+    private SSLContext createContext() {
+        try {
+            return createSslContext(tlsConfiguration);
+        } catch (final TlsException e) {
+            throw new IllegalArgumentException("Failed to create SSL context 
with the TLS configuration", e);
+        }
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/TrustStoreScanner.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/TrustStoreScanner.java
deleted file mode 100644
index 22913ed811..0000000000
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/util/TrustStoreScanner.java
+++ /dev/null
@@ -1,151 +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.web.server.util;
-
-import org.eclipse.jetty.util.Scanner;
-import org.eclipse.jetty.util.annotation.ManagedAttribute;
-import org.eclipse.jetty.util.annotation.ManagedOperation;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-
-/**
- * <p>The {@link TrustStoreScanner} is used to monitor the TrustStore file 
used by the {@link SslContextFactory}.
- * It will reload the {@link SslContextFactory} if it detects that the 
TrustStore file has been modified.</p>
- * <p>
- * Though it would have been more ideal to simply extend KeyStoreScanner and 
override the keystore resource
- * with the truststore resource, KeyStoreScanner's constructor was written in 
a way that doesn't make this possible.
- */
-public class TrustStoreScanner extends ContainerLifeCycle implements 
Scanner.DiscreteListener {
-    private static final Logger LOG = Log.getLogger(TrustStoreScanner.class);
-
-    private final SslContextFactory sslContextFactory;
-    private final File truststoreFile;
-    private final Scanner _scanner;
-
-    public TrustStoreScanner(SslContextFactory sslContextFactory) {
-        this.sslContextFactory = sslContextFactory;
-        try {
-            Resource truststoreResource = 
sslContextFactory.getTrustStoreResource();
-            File monitoredFile = truststoreResource.getFile();
-            if (monitoredFile == null || !monitoredFile.exists()) {
-                throw new IllegalArgumentException("truststore file does not 
exist");
-            }
-            if (monitoredFile.isDirectory()) {
-                throw new IllegalArgumentException("expected truststore file 
not directory");
-            }
-
-            if (truststoreResource.getAlias() != null) {
-                // this resource has an alias, use the alias, as that's what's 
returned in the Scanner
-                monitoredFile = new File(truststoreResource.getAlias());
-            }
-
-            truststoreFile = monitoredFile;
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("Monitored Truststore File: {}", monitoredFile);
-            }
-        } catch (IOException e) {
-            throw new IllegalArgumentException("could not obtain truststore 
file", e);
-        }
-
-        File parentFile = truststoreFile.getParentFile();
-        if (!parentFile.exists() || !parentFile.isDirectory()) {
-            throw new IllegalArgumentException("error obtaining truststore 
dir");
-        }
-
-        _scanner = new Scanner();
-        _scanner.setScanDirs(Collections.singletonList(parentFile));
-        _scanner.setScanInterval(1);
-        _scanner.setReportDirs(false);
-        _scanner.setReportExistingFilesOnStartup(false);
-        _scanner.setScanDepth(1);
-        _scanner.addListener(this);
-        addBean(_scanner);
-    }
-
-    @Override
-    public void fileAdded(String filename) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("added {}", filename);
-        }
-
-        if (truststoreFile.toPath().toString().equals(filename)) {
-            reload();
-        }
-    }
-
-    @Override
-    public void fileChanged(String filename) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("changed {}", filename);
-        }
-
-        if (truststoreFile.toPath().toString().equals(filename)) {
-            reload();
-        }
-    }
-
-    @Override
-    public void fileRemoved(String filename) {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("removed {}", filename);
-        }
-
-        if (truststoreFile.toPath().toString().equals(filename)) {
-            reload();
-        }
-    }
-
-    @ManagedOperation(value = "Scan for changes in the SSL Truststore", impact 
= "ACTION")
-    public void scan() {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("scanning");
-        }
-
-        _scanner.scan();
-        _scanner.scan();
-    }
-
-    @ManagedOperation(value = "Reload the SSL Truststore", impact = "ACTION")
-    public void reload() {
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("reloading truststore file {}", truststoreFile);
-        }
-
-        try {
-            sslContextFactory.reload(scf -> {
-            });
-        } catch (Throwable t) {
-            LOG.warn("Truststore Reload Failed", t);
-        }
-    }
-
-    @ManagedAttribute("scanning interval to detect changes which need 
reloaded")
-    public int getScanInterval() {
-        return _scanner.getScanInterval();
-    }
-
-    public void setScanInterval(int scanInterval) {
-        _scanner.setScanInterval(scanInterval);
-    }
-}
\ No newline at end of file
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
index e997f25ac6..f4119f76aa 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactoryTest.java
@@ -20,17 +20,17 @@ import 
org.apache.nifi.jetty.configuration.connector.alpn.ALPNServerConnectionFa
 import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
 import org.apache.nifi.security.util.TlsConfiguration;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.server.util.TrustStoreScanner;
+import org.apache.nifi.web.server.util.StoreScanner;
 import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.util.ssl.KeyStoreScanner;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
+import java.util.Collection;
 import java.util.Properties;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -182,11 +182,8 @@ class FrameworkServerConnectorFactoryTest {
 
     private void assertAutoReloadEnabled(final ServerConnector 
serverConnector) {
         final Server server = serverConnector.getServer();
-        final KeyStoreScanner keyStoreScanner = 
server.getBean(KeyStoreScanner.class);
-        assertNotNull(keyStoreScanner);
-
-        final TrustStoreScanner trustStoreScanner = 
server.getBean(TrustStoreScanner.class);
-        assertNotNull(trustStoreScanner);
+        final Collection<StoreScanner> scanners = 
server.getBeans(StoreScanner.class);
+        assertEquals(2, scanners.size());
     }
 
     private NiFiProperties getProperties(final Properties serverProperties) {
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/StoreScannerTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/StoreScannerTest.java
new file mode 100644
index 0000000000..35c971c144
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/StoreScannerTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.web.server.util;
+
+import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
+import org.apache.nifi.security.util.TlsConfiguration;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class StoreScannerTest {
+    private SslContextFactory sslContextFactory;
+    private static TlsConfiguration tlsConfiguration;
+    private static File keyStoreFile;
+    private static File trustStoreFile;
+    private static Map<File, StoreScanner> filesToScannerMap;
+
+    @Captor
+    private ArgumentCaptor<Consumer<SslContextFactory>> consumerArgumentCaptor;
+
+    @BeforeAll
+    public static void initClass() {
+        tlsConfiguration = new TemporaryKeyStoreBuilder().build();
+        keyStoreFile = Paths.get(tlsConfiguration.getKeystorePath()).toFile();
+        trustStoreFile = 
Paths.get(tlsConfiguration.getTruststorePath()).toFile();
+    }
+
+    @BeforeEach
+    public void init() throws IOException {
+        sslContextFactory = mock(SslContextFactory.class);
+        Resource keyStoreResource = mock(Resource.class);
+        when(keyStoreResource.getFile()).thenReturn(keyStoreFile);
+        
when(sslContextFactory.getKeyStoreResource()).thenReturn(keyStoreResource);
+
+        Resource trustStoreResource = mock(Resource.class);
+        when(trustStoreResource.getFile()).thenReturn(trustStoreFile);
+        
when(sslContextFactory.getTrustStoreResource()).thenReturn(trustStoreResource);
+
+        final StoreScanner keyStoreScanner = new 
StoreScanner(sslContextFactory, tlsConfiguration, 
sslContextFactory.getKeyStoreResource());
+        final StoreScanner trustStoreScanner = new 
StoreScanner(sslContextFactory, tlsConfiguration, 
sslContextFactory.getTrustStoreResource());
+        filesToScannerMap = new HashMap<>();
+        filesToScannerMap.put(keyStoreFile, keyStoreScanner);
+        filesToScannerMap.put(trustStoreFile, trustStoreScanner);
+    }
+
+    @Test
+    public void testFileAdded() throws Exception {
+        for (final Map.Entry<File, StoreScanner> entry : 
filesToScannerMap.entrySet()) {
+            final File file = entry.getKey();
+            final StoreScanner scanner = entry.getValue();
+            scanner.fileAdded(file.getAbsolutePath());
+
+            verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+            final Consumer<SslContextFactory> consumer = 
consumerArgumentCaptor.getValue();
+            consumer.accept(sslContextFactory);
+            
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+            clearInvocations(sslContextFactory);
+        }
+    }
+
+    @Test
+    public void testFileChanged() throws Exception {
+        for (final Map.Entry<File, StoreScanner> entry : 
filesToScannerMap.entrySet()) {
+            final File file = entry.getKey();
+            final StoreScanner scanner = entry.getValue();
+            scanner.fileChanged(file.getAbsolutePath());
+
+            verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+            final Consumer<SslContextFactory> consumer = 
consumerArgumentCaptor.getValue();
+            consumer.accept(sslContextFactory);
+            
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+            clearInvocations(sslContextFactory);
+        }
+    }
+
+    @Test
+    public void testFileRemoved() throws Exception {
+        for (final Map.Entry<File, StoreScanner> entry : 
filesToScannerMap.entrySet()) {
+            final File file = entry.getKey();
+            final StoreScanner scanner = entry.getValue();
+            scanner.fileRemoved(file.getAbsolutePath());
+
+            verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+            final Consumer<SslContextFactory> consumer = 
consumerArgumentCaptor.getValue();
+            consumer.accept(sslContextFactory);
+            
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+            clearInvocations(sslContextFactory);
+        }
+    }
+
+    @Test
+    public void testReload() throws Exception {
+        for (final Map.Entry<File, StoreScanner> entry : 
filesToScannerMap.entrySet()) {
+            final StoreScanner scanner = entry.getValue();
+            scanner.reload();
+
+            verify(sslContextFactory).reload(consumerArgumentCaptor.capture());
+
+            final Consumer<SslContextFactory> consumer = 
consumerArgumentCaptor.getValue();
+            consumer.accept(sslContextFactory);
+            
verify(sslContextFactory).setSslContext(ArgumentMatchers.any(SSLContext.class));
+            clearInvocations(sslContextFactory);
+        }
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/TrustStoreScannerTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/TrustStoreScannerTest.java
deleted file mode 100644
index e5ee7df072..0000000000
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/util/TrustStoreScannerTest.java
+++ /dev/null
@@ -1,85 +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.web.server.util;
-
-import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
-import org.apache.nifi.security.util.TlsConfiguration;
-import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentMatchers;
-import org.mockito.Mockito;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.function.Consumer;
-
-public class TrustStoreScannerTest {
-
-    private TrustStoreScanner scanner;
-    private SslContextFactory sslContextFactory;
-    private static File keyStoreFile;
-    private static File trustStoreFile;
-
-    @BeforeAll
-    public static void initClass() {
-        TlsConfiguration tlsConfiguration = new 
TemporaryKeyStoreBuilder().build();
-        keyStoreFile = Paths.get(tlsConfiguration.getKeystorePath()).toFile();
-        trustStoreFile = 
Paths.get(tlsConfiguration.getTruststorePath()).toFile();
-    }
-
-    @BeforeEach
-    public void init() throws IOException {
-        sslContextFactory = Mockito.mock(SslContextFactory.class);
-        Resource trustStoreResource = Mockito.mock(Resource.class);
-        Mockito.when(trustStoreResource.getFile()).thenReturn(trustStoreFile);
-        
Mockito.when(sslContextFactory.getTrustStoreResource()).thenReturn(trustStoreResource);
-
-        scanner = new TrustStoreScanner(sslContextFactory);
-    }
-
-    @Test
-    public void fileAdded() throws Exception {
-        scanner.fileAdded(trustStoreFile.getAbsolutePath());
-
-        
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
-    }
-
-    @Test
-    public void fileChanged() throws Exception {
-        scanner.fileChanged(trustStoreFile.getAbsolutePath());
-
-        
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
-    }
-
-    @Test
-    public void fileRemoved() throws Exception {
-        scanner.fileRemoved(trustStoreFile.getAbsolutePath());
-
-        
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
-    }
-
-    @Test
-    public void reload() throws Exception {
-        scanner.reload();
-
-        
Mockito.verify(sslContextFactory).reload(ArgumentMatchers.any(Consumer.class));
-    }
-}

Reply via email to