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

markap14 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new db148804dc0 NIFI-16183 Add active-polling stopConnector(Duration) to 
connector mock framework (#11528)
db148804dc0 is described below

commit db148804dc08ad7845a7ff770d152aba1e961995
Author: Wojciech <[email protected]>
AuthorDate: Thu Aug 13 16:13:55 2026 +0200

    NIFI-16183 Add active-polling stopConnector(Duration) to connector mock 
framework (#11528)
    
    The mock server previously stopped a Connector with a single fixed 10-second
    blocking wait, which could time out on slower shutdown paths (for example a
    failed table still draining) even though the Connector node retries its stop
    internally and eventually reaches STOPPED.
    
    - ConnectorTestRunner: add a default stopConnector(Duration) overload
    - StandardConnectorMockServer: poll the Connector state until STOPPED within
      the given timeout instead of a single fixed wait
    - StandardConnectorTestRunner: pass the timeout through to the mock server
    - CreateConnectorIT: exercise the new overload end-to-end
---
 .../mock/connector/server/ConnectorTestRunner.java | 14 ++++++++
 .../server/StandardConnectorMockServer.java        | 38 ++++++++++++++++++----
 .../mock/connectors/tests/CreateConnectorIT.java   | 21 ++++++++++++
 .../connector/StandardConnectorTestRunner.java     |  6 ++++
 4 files changed, 72 insertions(+), 7 deletions(-)

diff --git 
a/nifi-connector-mock-bundle/nifi-connector-mock-api/src/main/java/org/apache/nifi/mock/connector/server/ConnectorTestRunner.java
 
b/nifi-connector-mock-bundle/nifi-connector-mock-api/src/main/java/org/apache/nifi/mock/connector/server/ConnectorTestRunner.java
index 449ca64c5de..42f4c1821ee 100644
--- 
a/nifi-connector-mock-bundle/nifi-connector-mock-api/src/main/java/org/apache/nifi/mock/connector/server/ConnectorTestRunner.java
+++ 
b/nifi-connector-mock-bundle/nifi-connector-mock-api/src/main/java/org/apache/nifi/mock/connector/server/ConnectorTestRunner.java
@@ -32,6 +32,7 @@ import java.io.InputStream;
 import java.time.Duration;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeoutException;
 
 public interface ConnectorTestRunner extends Closeable {
 
@@ -144,6 +145,19 @@ public interface ConnectorTestRunner extends Closeable {
      */
     void stopConnector();
 
+    /**
+     * Stops the Connector, waiting up to the given timeout for it to reach a 
stopped state. Implementations
+     * should actively poll the Connector's state until it is stopped or the 
timeout elapses, which is more
+     * tolerant of a flow that takes a while to quiesce (for example a failed 
table still draining) than the
+     * default stop budget.
+     *
+     * @param timeout the maximum duration to wait for the Connector to stop
+     * @throws TimeoutException if the timeout elapses before the Connector 
stops
+     */
+    default void stopConnector(final Duration timeout) throws TimeoutException 
{
+        stopConnector();
+    }
+
     /**
      * Blocks until the Connector has received at least one FlowFile, or until 
the specified timeout elapses.
      *
diff --git 
a/nifi-connector-mock-bundle/nifi-connector-mock-server/src/main/java/org/apache/nifi/mock/connector/server/StandardConnectorMockServer.java
 
b/nifi-connector-mock-bundle/nifi-connector-mock-server/src/main/java/org/apache/nifi/mock/connector/server/StandardConnectorMockServer.java
index 314445d5ad3..15e54d6d971 100644
--- 
a/nifi-connector-mock-bundle/nifi-connector-mock-server/src/main/java/org/apache/nifi/mock/connector/server/StandardConnectorMockServer.java
+++ 
b/nifi-connector-mock-bundle/nifi-connector-mock-server/src/main/java/org/apache/nifi/mock/connector/server/StandardConnectorMockServer.java
@@ -102,7 +102,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.jar.JarFile;
 import java.util.stream.Stream;
 
@@ -113,6 +113,8 @@ public class StandardConnectorMockServer implements 
ConnectorMockServer {
     private static final String NAR_DEPENDENCIES_PATH = 
"NAR-INF/bundled-dependencies";
     private static final String CONNECTOR_WAR_MANIFEST_PATH = 
"META-INF/nifi-connector";
     private static final String WAR_EXTENSION = ".war";
+    private static final Duration DEFAULT_STOP_TIMEOUT = 
Duration.ofSeconds(60);
+    private static final long STOP_POLL_INTERVAL_MILLIS = 250L;
 
     private Bundle systemBundle;
     private Set<Bundle> bundles;
@@ -362,13 +364,35 @@ public class StandardConnectorMockServer implements 
ConnectorMockServer {
 
     @Override
     public void stopConnector() {
+        // The no-arg convenience method keeps its unchecked contract: a 
timeout at the default budget is not
+        // something a caller is expected to recover from, so wrap the checked 
TimeoutException.
         try {
-            connectorNode.stop(flowEngine).get(10, TimeUnit.SECONDS);
-        } catch (final InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new RuntimeException("Interrupted while waiting for 
connector to stop", e);
-        } catch (final Exception e) {
-            throw new RuntimeException("Failed to stop Connector", e);
+            stopConnector(DEFAULT_STOP_TIMEOUT);
+        } catch (final TimeoutException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public void stopConnector(final Duration maxWaitTime) throws 
TimeoutException {
+        // Initiate the asynchronous stop, then actively poll the Connector's 
state until it reports STOPPED.
+        // The node flips its state to STOPPED at the same point it completes 
the stop future, and it retries a
+        // failed component stop internally (every 10 seconds), so polling the 
state rides through those retries
+        // up to maxWaitTime instead of being capped by a single fixed 
blocking wait.
+        connectorNode.stop(flowEngine);
+
+        final long expirationTime = System.currentTimeMillis() + 
maxWaitTime.toMillis();
+        while (connectorNode.getCurrentState() != ConnectorState.STOPPED) {
+            if (System.currentTimeMillis() > expirationTime) {
+                throw new TimeoutException("Timed out waiting for the 
Connector to stop after " + maxWaitTime);
+            }
+
+            try {
+                Thread.sleep(STOP_POLL_INTERVAL_MILLIS);
+            } catch (final InterruptedException e) {
+                Thread.currentThread().interrupt();
+                throw new RuntimeException("Interrupted while waiting for the 
Connector to stop", e);
+            }
         }
     }
 
diff --git 
a/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-integration-tests/src/test/java/org/apache/nifi/mock/connectors/tests/CreateConnectorIT.java
 
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-integration-tests/src/test/java/org/apache/nifi/mock/connectors/tests/CreateConnectorIT.java
index 8d15b2c6c71..1b8c49e49f4 100644
--- 
a/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-integration-tests/src/test/java/org/apache/nifi/mock/connectors/tests/CreateConnectorIT.java
+++ 
b/nifi-connector-mock-bundle/nifi-connector-mock-test-bundle/nifi-connector-mock-integration-tests/src/test/java/org/apache/nifi/mock/connectors/tests/CreateConnectorIT.java
@@ -28,10 +28,12 @@ import org.junit.jupiter.api.Test;
 
 import java.io.File;
 import java.io.IOException;
+import java.time.Duration;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -65,6 +67,25 @@ public class CreateConnectorIT {
         }
     }
 
+    @Test
+    public void testStopConnectorWithTimeoutStopsRunningConnector() throws 
IOException {
+        try (final ConnectorTestRunner testRunner = new 
StandardConnectorTestRunner.Builder()
+                
.connectorClassName("org.apache.nifi.mock.connectors.GenerateAndLog")
+                .narLibraryDirectory(new File("target/libDir"))
+                .build()) {
+
+            testRunner.startConnector();
+
+            // Exercises the timeout-aware overload: it initiates the 
asynchronous stop and actively polls the
+            // Connector's state until it reaches STOPPED, returning as soon 
as it does rather than after a single
+            // fixed blocking wait. Because start is asynchronous, a stop 
issued immediately afterwards may have to
+            // ride through the node's internal stop retries (every 10 
seconds) before the state settles, so the
+            // budget is generous enough to stay deterministic on a slow CI 
runner; the poll still returns the
+            // instant the Connector reports STOPPED.
+            assertDoesNotThrow(() -> 
testRunner.stopConnector(Duration.ofSeconds(120)));
+        }
+    }
+
     @Test
     public void testConnectorWithMissingBundleFailsValidate() throws 
IOException {
 
diff --git 
a/nifi-connector-mock-bundle/nifi-connector-mock/src/main/java/org/apache/nifi/mock/connector/StandardConnectorTestRunner.java
 
b/nifi-connector-mock-bundle/nifi-connector-mock/src/main/java/org/apache/nifi/mock/connector/StandardConnectorTestRunner.java
index 7153f8d868b..186867d7e80 100644
--- 
a/nifi-connector-mock-bundle/nifi-connector-mock/src/main/java/org/apache/nifi/mock/connector/StandardConnectorTestRunner.java
+++ 
b/nifi-connector-mock-bundle/nifi-connector-mock/src/main/java/org/apache/nifi/mock/connector/StandardConnectorTestRunner.java
@@ -50,6 +50,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
+import java.util.concurrent.TimeoutException;
 
 public class StandardConnectorTestRunner implements ConnectorTestRunner, 
Closeable {
     private final File narLibraryDirectory;
@@ -198,6 +199,11 @@ public class StandardConnectorTestRunner implements 
ConnectorTestRunner, Closeab
         mockServer.stopConnector();
     }
 
+    @Override
+    public void stopConnector(final Duration timeout) throws TimeoutException {
+        mockServer.stopConnector(timeout);
+    }
+
     @Override
     public void waitForDataIngested(final Duration maxWaitTime) {
         mockServer.waitForDataIngested(maxWaitTime);

Reply via email to