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

martinzink pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit 91481eff7b85d4c36c419b3f3f10b50ddf38db8d
Author: Gabor Gyimesi <[email protected]>
AuthorDate: Tue Mar 10 13:13:46 2026 +0100

    MINIFICPP-2716 Refactor and stabilize modular docker tests
    
    This closes #2104
    
    Signed-off-by: Martin Zink <[email protected]>
---
 .../containers/http_proxy_container.py             |   2 +-
 .../src/minifi_test_framework/steps/core_steps.py  |  36 +++++-
 .../steps/flow_building_steps.py                   |  24 ----
 docker/RunBehaveTests.sh                           |  22 +---
 .../kinesis_server_container.py                    |   0
 .../{steps => containers}/s3_server_container.py   |   2 +-
 extensions/aws/tests/features/kinesis.feature      |   2 +-
 extensions/aws/tests/features/s3.feature           |  38 +++----
 extensions/aws/tests/features/steps/steps.py       |  10 +-
 .../azure_server_container.py                      |   0
 extensions/azure/tests/features/steps/steps.py     |   2 +-
 extensions/civetweb/tests/features/http.feature    | 125 +++++++++++----------
 extensions/civetweb/tests/features/https.feature   | 117 ++++++++++---------
 .../couchbase_server_container.py                  |   2 +-
 extensions/couchbase/tests/features/steps/steps.py |   2 +-
 .../elastic_base_container.py                      |   0
 .../elasticsearch_container.py                     |   0
 .../{steps => containers}/opensearch_container.py  |   0
 .../tests/features/elasticsearch.feature           |   6 +-
 .../tests/features/opensearch.feature              |   6 +-
 .../elasticsearch/tests/features/steps/steps.py    |   4 +-
 .../fake_gcs_server_container.py                   |   0
 .../tests/features/google_cloud_storage.feature    |   2 +-
 extensions/gcp/tests/features/steps/steps.py       |   2 +-
 .../grafana_loki_container.py                      |   0
 .../reverse_proxy_container.py                     |   0
 .../grafana-loki/tests/features/steps/steps.py     |   4 +-
 .../kafka_server_container.py                      |   0
 extensions/kafka/tests/features/steps/steps.py     |   2 +-
 .../{steps => containers}/mqtt_broker_container.py |   0
 extensions/mqtt/tests/features/mqtt.feature        |  10 +-
 extensions/mqtt/tests/features/steps/steps.py      |   2 +-
 .../opc_ua_server_container.py                     |   2 +-
 extensions/opc/tests/features/steps/steps.py       |   2 +-
 .../{steps => containers}/prometheus_container.py  |   0
 .../prometheus/tests/features/prometheus.feature   |   6 +-
 .../prometheus/tests/features/steps/steps.py       |   2 +-
 extensions/python/tests/features/python.feature    |  14 +--
 .../{steps => containers}/splunk_container.py      |   0
 extensions/splunk/tests/features/splunk.feature    |   4 +-
 extensions/splunk/tests/features/steps/steps.py    |   2 +-
 .../postgress_server_container.py                  |   2 +-
 extensions/sql/tests/features/steps/steps.py       |   2 +-
 .../tests/features/attributes_to_json.feature      |   2 +-
 .../{steps => containers}/diag_slave_container.py  |   2 +-
 .../{steps => containers}/syslog_container.py      |   0
 .../{steps => containers}/tcp_client_container.py  |   2 +-
 .../tests/features/core_functionality.feature      |   2 +-
 .../tests/features/evaluate_json_path.feature      |   4 +-
 .../tests/features/file_system_operations.feature  |   4 +-
 .../tests/features/hashcontent.feature             |  12 +-
 .../tests/features/minifi_c2_server.feature        |   8 +-
 .../tests/features/minifi_controller.feature       |  12 +-
 .../standard-processors/tests/features/s2s.feature |  24 ++--
 .../tests/features/split_json.feature              |   2 +-
 .../tests/features/steps/steps.py                  |   6 +-
 56 files changed, 273 insertions(+), 265 deletions(-)

diff --git 
a/behave_framework/src/minifi_test_framework/containers/http_proxy_container.py 
b/behave_framework/src/minifi_test_framework/containers/http_proxy_container.py
index 54e766fa7..202878ae3 100644
--- 
a/behave_framework/src/minifi_test_framework/containers/http_proxy_container.py
+++ 
b/behave_framework/src/minifi_test_framework/containers/http_proxy_container.py
@@ -52,7 +52,7 @@ class HttpProxy(Container):
         finished_str = "Accepting HTTP Socket connections at"
         return wait_for_condition(
             condition=lambda: finished_str in self.get_logs(),
-            timeout_seconds=5,
+            timeout_seconds=30,
             bail_condition=lambda: self.exited,
             context=None
         )
diff --git a/behave_framework/src/minifi_test_framework/steps/core_steps.py 
b/behave_framework/src/minifi_test_framework/steps/core_steps.py
index ba07d27f5..fc85af9c1 100644
--- a/behave_framework/src/minifi_test_framework/steps/core_steps.py
+++ b/behave_framework/src/minifi_test_framework/steps/core_steps.py
@@ -50,9 +50,41 @@ def step_impl(context: MinifiTestContext):
 def step_impl(context: MinifiTestContext, directory: str, size: str):
     size = humanfriendly.parse_size(size)
     content = ''.join(random.choice(string.ascii_uppercase + string.digits) 
for _ in range(size))
+    dirs = context.get_or_create_default_minifi_container().dirs
+    if directory in dirs:
+        dirs[directory].files[str(uuid.uuid4())] = content
+        return
     new_dir = Directory(directory)
-    new_dir.files["input.txt"] = content
-    context.get_or_create_default_minifi_container().dirs.append(new_dir)
+    new_dir.files[str(uuid.uuid4())] = content
+    dirs.append(new_dir)
+
+
+def __add_directory_with_file_to_container(context: MinifiTestContext, 
directory: str, file_name: str, content: str, container_name: str):
+    dirs = context.get_or_create_minifi_container(container_name).dirs
+    new_content = content.replace("\\n", "\n")
+    if directory in dirs:
+        dirs[directory].files[file_name] = new_content
+        return
+    new_dir = Directory(directory)
+    new_dir.files[file_name] = new_content
+    dirs.append(new_dir)
+
+
+@step('a directory at "{directory}" has a file with the content "{content}" in 
the "{flow_name}" flow')
+@step("a directory at '{directory}' has a file with the content '{content}' in 
the '{flow_name}' flow")
+def step_impl(context: MinifiTestContext, directory: str, content: str, 
flow_name: str):
+    __add_directory_with_file_to_container(context, directory, 
str(uuid.uuid4()), content, flow_name)
+
+
+@step('a directory at "{directory}" has a file with the content "{content}"')
+@step("a directory at '{directory}' has a file with the content '{content}'")
+def step_impl(context: MinifiTestContext, directory: str, content: str):
+    context.execute_steps(f'given a directory at "{directory}" has a file with 
the content "{content}" in the "{DEFAULT_MINIFI_CONTAINER_NAME}" flow')
+
+
+@step('a directory at "{directory}" has a file "{file_name}" with the content 
"{content}"')
+def step_impl(context: MinifiTestContext, directory: str, file_name: str, 
content: str):
+    __add_directory_with_file_to_container(context, directory, file_name, 
content, DEFAULT_MINIFI_CONTAINER_NAME)
 
 
 @step('a file with filename "{file_name}" and content "{content}" is present 
in "{path}"')
diff --git 
a/behave_framework/src/minifi_test_framework/steps/flow_building_steps.py 
b/behave_framework/src/minifi_test_framework/steps/flow_building_steps.py
index a8c07c3be..08c6bd04d 100644
--- a/behave_framework/src/minifi_test_framework/steps/flow_building_steps.py
+++ b/behave_framework/src/minifi_test_framework/steps/flow_building_steps.py
@@ -19,7 +19,6 @@ import logging
 import uuid
 from behave import given, step
 
-from minifi_test_framework.containers.directory import Directory
 from minifi_test_framework.core.minifi_test_context import 
DEFAULT_MINIFI_CONTAINER_NAME, MinifiTestContext
 from minifi_test_framework.minifi.connection import Connection
 from minifi_test_framework.minifi.controller_service import ControllerService
@@ -227,29 +226,6 @@ def step_impl(context: MinifiTestContext, parameter_name: 
str, parameter_value:
     parameter_context.parameters.append(Parameter(parameter_name, 
parameter_value, False))
 
 
-@step('a directory at "{directory}" has a file with the content "{content}" in 
the "{flow_name}" flow')
-@step("a directory at '{directory}' has a file with the content '{content}' in 
the '{flow_name}' flow")
-def step_impl(context: MinifiTestContext, directory: str, content: str, 
flow_name: str):
-    new_content = content.replace("\\n", "\n")
-    new_dir = Directory(directory)
-    new_dir.files["input.txt"] = new_content
-    context.get_or_create_minifi_container(flow_name).dirs.append(new_dir)
-
-
-@step('a directory at "{directory}" has a file with the content "{content}"')
-@step("a directory at '{directory}' has a file with the content '{content}'")
-def step_impl(context: MinifiTestContext, directory: str, content: str):
-    context.execute_steps(f'given a directory at "{directory}" has a file with 
the content "{content}" in the "{DEFAULT_MINIFI_CONTAINER_NAME}" flow')
-
-
-@step('a directory at "{directory}" has a file ("{file_name}") with the 
content "{content}"')
-def step_impl(context: MinifiTestContext, directory: str, file_name: str, 
content: str):
-    new_content = content.replace("\\n", "\n")
-    new_dir = Directory(directory)
-    new_dir.files[file_name] = new_content
-    context.get_or_create_default_minifi_container().dirs.append(new_dir)
-
-
 @given("these processor properties are set in the \"{minifi_container_name}\" 
flow")
 def step_impl(context: MinifiTestContext, minifi_container_name: str):
     for row in context.table:
diff --git a/docker/RunBehaveTests.sh b/docker/RunBehaveTests.sh
index 02e31d381..bcfe34640 100755
--- a/docker/RunBehaveTests.sh
+++ b/docker/RunBehaveTests.sh
@@ -192,22 +192,6 @@ fi
 
 echo "${BEHAVE_OPTS[@]}"
 
-exec \
-  behavex "${BEHAVE_OPTS[@]}" \
-    "${docker_dir}/../extensions/standard-processors/tests/features" \
-    "${docker_dir}/../extensions/aws/tests/features" \
-    "${docker_dir}/../extensions/azure/tests/features" \
-    "${docker_dir}/../extensions/sql/tests/features" \
-    "${docker_dir}/../extensions/llamacpp/tests/features" \
-    "${docker_dir}/../extensions/opc/tests/features" \
-    "${docker_dir}/../extensions/kafka/tests/features" \
-    "${docker_dir}/../extensions/couchbase/tests/features" \
-    "${docker_dir}/../extensions/elasticsearch/tests/features" \
-    "${docker_dir}/../extensions/splunk/tests/features" \
-    "${docker_dir}/../extensions/gcp/tests/features" \
-    "${docker_dir}/../extensions/grafana-loki/tests/features" \
-    "${docker_dir}/../extensions/lua/tests/features/" \
-    "${docker_dir}/../extensions/civetweb/tests/features/" \
-    "${docker_dir}/../extensions/mqtt/tests/features/" \
-    "${docker_dir}/../extensions/prometheus/tests/features/" \
-    "${docker_dir}/../extensions/python/tests/features/"
+mapfile -t FEATURE_FILES < <(find "${docker_dir}/../extensions" -type f -name 
'*.feature')
+
+behavex "${BEHAVE_OPTS[@]}" "${FEATURE_FILES[@]}"
diff --git a/extensions/aws/tests/features/steps/kinesis_server_container.py 
b/extensions/aws/tests/features/containers/kinesis_server_container.py
similarity index 100%
rename from extensions/aws/tests/features/steps/kinesis_server_container.py
rename to extensions/aws/tests/features/containers/kinesis_server_container.py
diff --git a/extensions/aws/tests/features/steps/s3_server_container.py 
b/extensions/aws/tests/features/containers/s3_server_container.py
similarity index 99%
rename from extensions/aws/tests/features/steps/s3_server_container.py
rename to extensions/aws/tests/features/containers/s3_server_container.py
index 01db20030..42ac64454 100644
--- a/extensions/aws/tests/features/steps/s3_server_container.py
+++ b/extensions/aws/tests/features/containers/s3_server_container.py
@@ -31,7 +31,7 @@ class S3ServerContainer(Container):
         finished_str = "Started S3MockApplication"
         return wait_for_condition(
             condition=lambda: finished_str in self.get_logs(),
-            timeout_seconds=15,
+            timeout_seconds=60,
             bail_condition=lambda: self.exited,
             context=None)
 
diff --git a/extensions/aws/tests/features/kinesis.feature 
b/extensions/aws/tests/features/kinesis.feature
index 6f903cd56..03823ab78 100644
--- a/extensions/aws/tests/features/kinesis.feature
+++ b/extensions/aws/tests/features/kinesis.feature
@@ -22,7 +22,7 @@ Feature: Sending data from MiNiFi-C++ to an AWS Kinesis server
   Scenario: A MiNiFi instance can send data to AWS Kinesis
     Given a kinesis server is set up in correspondence with the 
PutKinesisStream
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "Schnappi, das kleine Krokodil" is present in 
"/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "Schnappi, das 
kleine Krokodil"
     And a PutKinesisStream processor
     And these processor properties are set
       | processor name     | property name              | property value       
                    |
diff --git a/extensions/aws/tests/features/s3.feature 
b/extensions/aws/tests/features/s3.feature
index b16ea1f25..caebe83fc 100644
--- a/extensions/aws/tests/features/s3.feature
+++ b/extensions/aws/tests/features/s3.feature
@@ -29,9 +29,9 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     And the "failure" relationship of the PutS3Object processor is connected 
to the PutS3Object
     And PutFile's success relationship is auto-terminated
 
-    And an s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
 
-    When both instances start up
+    When the MiNiFi instance starts up
 
     Then a single file with the content "LH_O#L|FD<FASD{FO#@$#$%^ 
\"#\"$L%:\"@#$L\":test_data#$#%#$%?{\"F{" is placed in the "/tmp/output" 
directory in less than 20 seconds
     And the object on the s3 server is "LH_O#L|FD<FASD{FO#@$#$%^ 
\"#\"$L%:\"@#$L\":test_data#$#%#$%?{\"F{"
@@ -54,7 +54,7 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     And the "failure" relationship of the PutS3Object processor is connected 
to the PutS3Object
     And PutFile's success relationship is auto-terminated
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
     And the http proxy server is set up
     When all instances start up
 
@@ -77,9 +77,9 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
       | DeleteS3Object | success           | PutFile          |
       | PutFile        | success           | auto-terminated  |
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
 
-    When both instances start up
+    When the MiNiFi instance starts up
 
     Then a single file with the content "LH_O#L|FD<FASD{FO#@$#$%^ 
\"#\"$L%:\"@#$L\":test_data#$#%#$%?{\"F{" is placed in the "/tmp/output" 
directory in less than 20 seconds
     And the object bucket on the s3 server is empty in less than 10 seconds
@@ -92,9 +92,9 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     And the "success" relationship of the GetFile processor is connected to 
the DeleteS3Object
     And the "success" relationship of the DeleteS3Object processor is 
connected to the PutFile
 
-    And a s3 server is set up in correspondence with the DeleteS3Object
+    And the s3 server starts up
 
-    When both instances start up
+    When the MiNiFi instance starts up
 
     Then a single file with the content "test" is placed in the "/tmp/output" 
directory in less than 20 seconds
     And the object bucket on the s3 server is empty in less than 10 seconds
@@ -119,7 +119,7 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
       | DeleteS3Object | success           | PutFile          |
       | PutFile        | success           | auto-terminated  |
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
     And the http proxy server is set up
 
     When all instances start up
@@ -145,9 +145,9 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
       | PutS3Object      | success           | auto-terminated  |
       | PutS3Object      | failure           | PutS3Object      |
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
 
-    When all instances start up
+    When the MiNiFi instance starts up
 
     Then a single file with the content "test" is placed in the "/tmp/output" 
directory in less than 20 seconds
 
@@ -171,7 +171,7 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
       | GenerateFlowFile | success           | FetchS3Object    |
       | FetchS3Object    | success           | PutFile          |
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
     And the http proxy server is set up
 
     When all instances start up
@@ -183,8 +183,8 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Batch Size" property of the GetFile processor is set to "1"
     And the scheduling period of the GetFile processor is set to "5 sec"
-    And a file with filename "test_file_1.log" and content "test_data1" is 
present in "/tmp/input"
-    And a file with filename "test_file_2.log" and content "test_data2" is 
present in "/tmp/input"
+    And a directory at "/tmp/input" has a file "test_file_1.log" with the 
content "test_data1"
+    And a directory at "/tmp/input" has a file "test_file_2.log" with the 
content "test_data2"
     And a PutS3Object processor set up to communicate with an s3 server
     And the "Object Key" property of the PutS3Object processor is set to 
"${filename}"
     And the "success" relationship of the GetFile processor is connected to 
the PutS3Object
@@ -193,9 +193,9 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And the "success" relationship of the ListS3 processor is connected to the 
PutFile
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
 
-    When all instances start up
+    When the MiNiFi instance starts up
 
     Then 2 files are placed in the "/tmp/output" directory in less than 20 
seconds
 
@@ -215,7 +215,7 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And the "success" relationship of the ListS3 processor is connected to the 
PutFile
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
     And the http proxy server is set up
 
     When all instances start up
@@ -232,9 +232,9 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     And the "success" relationship of the GetFile processor is connected to 
the PutS3Object
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And the "success" relationship of the PutS3Object processor is connected 
to the PutFile
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
 
-    When all instances start up
+    When the MiNiFi instance starts up
 
     Then 1 file is placed in the "/tmp/output" directory in less than 20 
seconds
     And the object on the s3 server is present and matches the original hash
@@ -256,7 +256,7 @@ Feature: Sending data from MiNiFi-C++ to an AWS server
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And the "success" relationship of the PutS3Object processor is connected 
to the PutFile
 
-    And a s3 server is set up in correspondence with the PutS3Object
+    And the s3 server starts up
     And the http proxy server is set up
     When all instances start up
 
diff --git a/extensions/aws/tests/features/steps/steps.py 
b/extensions/aws/tests/features/steps/steps.py
index 682685582..9f40d26f3 100644
--- a/extensions/aws/tests/features/steps/steps.py
+++ b/extensions/aws/tests/features/steps/steps.py
@@ -29,8 +29,8 @@ from minifi_test_framework.core.minifi_test_context import 
MinifiTestContext
 from minifi_test_framework.minifi.processor import Processor
 from minifi_test_framework.core.helpers import wait_for_condition, 
log_due_to_failure
 
-from s3_server_container import S3ServerContainer
-from kinesis_server_container import KinesisServerContainer
+from containers.s3_server_container import S3ServerContainer
+from containers.kinesis_server_container import KinesisServerContainer
 
 
 @step('a {processor_name} processor set up to communicate with an s3 server')
@@ -50,10 +50,10 @@ def step_impl(context: MinifiTestContext, processor_name: 
str):
     
context.get_or_create_default_minifi_container().flow_definition.add_processor(processor)
 
 
-@step('a s3 server is set up in correspondence with the {processor_name}')
-@step('an s3 server is set up in correspondence with the {processor_name}')
-def step_impl(context: MinifiTestContext, processor_name: str):
+@step('the s3 server starts up')
+def step_impl(context: MinifiTestContext):
     context.containers["s3-server"] = S3ServerContainer(context)
+    assert context.containers["s3-server"].deploy()
 
 
 @step('the object on the s3 server is "{object_data}"')
diff --git a/extensions/azure/tests/features/steps/azure_server_container.py 
b/extensions/azure/tests/features/containers/azure_server_container.py
similarity index 100%
rename from extensions/azure/tests/features/steps/azure_server_container.py
rename to extensions/azure/tests/features/containers/azure_server_container.py
diff --git a/extensions/azure/tests/features/steps/steps.py 
b/extensions/azure/tests/features/steps/steps.py
index 3331d7e71..00cc3cc16 100644
--- a/extensions/azure/tests/features/steps/steps.py
+++ b/extensions/azure/tests/features/steps/steps.py
@@ -25,7 +25,7 @@ from minifi_test_framework.steps import configuration_steps  
# noqa: F401
 from minifi_test_framework.steps import core_steps  # noqa: F401
 from minifi_test_framework.steps import flow_building_steps  # noqa: F401
 
-from azure_server_container import AzureServerContainer
+from containers.azure_server_container import AzureServerContainer
 
 
 @step("a {processor_name} processor set up to communicate with an Azure blob 
storage")
diff --git a/extensions/civetweb/tests/features/http.feature 
b/extensions/civetweb/tests/features/http.feature
index 395d068e6..f667ca6d9 100644
--- a/extensions/civetweb/tests/features/http.feature
+++ b/extensions/civetweb/tests/features/http.feature
@@ -20,30 +20,37 @@ Feature: Sending data using InvokeHTTP to a receiver using 
ListenHTTP
   I need to have ListenHTTP and InvokeHTTP processors
 
   Scenario: A MiNiFi instance transfers data to another MiNiFi instance with 
message body
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
+    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "secondary" flow
+    And PutFile is EVENT_DRIVEN in the "secondary" flow
+    And in the "secondary" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
+    And PutFile's success relationship is auto-terminated in the "secondary" 
flow
+
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"http://secondary-${scenario_id}:8080/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
     And the "success" relationship of the GetFile processor is connected to 
the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
-
-    And a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
-    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "secondary" flow
-    And PutFile is EVENT_DRIVEN in the "secondary" flow
-    And in the "secondary" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
-    And PutFile's success relationship is auto-terminated in the "secondary" 
flow
+    And InvokeHTTP's failure relationship is auto-terminated
 
     When both instances start up
     Then in the "secondary" container at least one file with the content 
"test" is placed in the "/tmp/output" directory in less than 60 seconds
 
   Scenario: A MiNiFi instance sends data through a HTTP proxy and another one 
listens
-    Given the http proxy server is set up
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "minifi-listen" flow
+    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "minifi-listen" flow
+    And PutFile is EVENT_DRIVEN in the "minifi-listen" flow
+    And in the "minifi-listen" flow the "success" relationship of the 
ListenHTTP processor is connected to the PutFile
+    And PutFile's success relationship is auto-terminated in the 
"minifi-listen" flow
+
+    And the http proxy server is set up
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"http://minifi-listen-${scenario_id}:8080/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
     And these processor properties are set
@@ -56,21 +63,22 @@ Feature: Sending data using InvokeHTTP to a receiver using 
ListenHTTP
     And the "success" relationship of the GetFile processor is connected to 
the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
-
-    And a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "minifi-listen" flow
-    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "minifi-listen" flow
-    And PutFile is EVENT_DRIVEN in the "minifi-listen" flow
-    And in the "minifi-listen" flow the "success" relationship of the 
ListenHTTP processor is connected to the PutFile
-    And PutFile's success relationship is auto-terminated in the 
"minifi-listen" flow
+    And InvokeHTTP's failure relationship is auto-terminated
 
     When all instances start up
     Then in the "minifi-listen" container at least one file with the content 
"test" is placed in the "/tmp/output" directory in less than 60 seconds
     And no errors were generated on the http-proxy regarding 
"http://minifi-listen-${scenario_id}:8080/contentListener";
 
   Scenario: A MiNiFi instance and transfers hashed data to another MiNiFi 
instance
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
+    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "secondary" flow
+    And PutFile is EVENT_DRIVEN in the "secondary" flow
+    And in the "secondary" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
+    And PutFile's success relationship is auto-terminated in the "secondary" 
flow
+
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a HashContent processor with the "Hash Attribute" property set to 
"hash"
     And HashContent is EVENT_DRIVEN
     And a InvokeHTTP processor with the "Remote URL" property set to 
"http://secondary-${scenario_id}:8080/contentListener";
@@ -80,20 +88,21 @@ Feature: Sending data using InvokeHTTP to a receiver using 
ListenHTTP
     And the "success" relationship of the HashContent processor is connected 
to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
 
-    And a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
+    When both instances start up
+    Then in the "secondary" container at least one file with the content 
"test" is placed in the "/tmp/output" directory in less than 60 seconds
+
+  Scenario: A MiNiFi instance transfers data to another MiNiFi instance 
without message body
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
     And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "secondary" flow
     And PutFile is EVENT_DRIVEN in the "secondary" flow
     And in the "secondary" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "secondary" 
flow
 
-    When both instances start up
-    Then in the "secondary" container at least one file with the content 
"test" is placed in the "/tmp/output" directory in less than 60 seconds
-
-  Scenario: A MiNiFi instance transfers data to another MiNiFi instance 
without message body
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"http://secondary-${scenario_id}:8080/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
@@ -101,36 +110,40 @@ Feature: Sending data using InvokeHTTP to a receiver 
using ListenHTTP
     And the "success" relationship of the GetFile processor is connected to 
the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
-
-    And a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
-    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "secondary" flow
-    And PutFile is EVENT_DRIVEN in the "secondary" flow
-    And in the "secondary" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
-    And PutFile's success relationship is auto-terminated in the "secondary" 
flow
+    And InvokeHTTP's failure relationship is auto-terminated
 
     When both instances start up
     Then in the "secondary" container at least one empty file is placed in the 
"/tmp/output" directory in less than 60 seconds
 
   Scenario: A MiNiFi instance transfers data to a NiFi instance with message 
body
-    Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And the "Keep Source File" property of the GetFile processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
-    And a InvokeHTTP processor with the "Remote URL" property set to 
"http://nifi-${scenario_id}:8081/contentListener";
-    And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
-    And the "success" relationship of the GetFile processor is connected to 
the InvokeHTTP
-
-    And a NiFi container is set up
+    Given a NiFi container is set up
     And a ListenHTTP processor with the "Listening Port" property set to 
"8081" in the NiFi flow
     And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the NiFi flow
     And in the NiFi flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the NiFi flow
     And PutFile's failure relationship is auto-terminated in the NiFi flow
 
+    And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
+    And the "Keep Source File" property of the GetFile processor is set to 
"true"
+    And a directory at "/tmp/input" has a file with the content "test"
+    And a InvokeHTTP processor with the "Remote URL" property set to 
"http://nifi-${scenario_id}:8081/contentListener";
+    And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
+    And the "success" relationship of the GetFile processor is connected to 
the InvokeHTTP
+    And InvokeHTTP's success relationship is auto-terminated
+    And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
+
     When both instances start up
     Then in the "nifi" container at least one empty file is placed in the 
"/tmp/output" directory in less than 60 seconds
 
   Scenario: A MiNiFi instance transfers data to another MiNiFi instance with 
message body and limited speed
-    Given a GenerateFlowFile processor with the "File Size" property set to 
"10 MB"
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
+    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "secondary" flow
+    And PutFile is EVENT_DRIVEN in the "secondary" flow
+    And in the "secondary" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
+    And PutFile's success relationship is auto-terminated in the "secondary" 
flow
+
+    And a GenerateFlowFile processor with the "File Size" property set to "10 
MB"
     And the scheduling period of the GenerateFlowFile processor is set to "30 
sec"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"http://secondary-${scenario_id}:8080/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
@@ -141,19 +154,25 @@ Feature: Sending data using InvokeHTTP to a receiver 
using ListenHTTP
     And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
-
-    And a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
-    And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "secondary" flow
-    And PutFile is EVENT_DRIVEN in the "secondary" flow
-    And in the "secondary" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
-    And PutFile's success relationship is auto-terminated in the "secondary" 
flow
+    And InvokeHTTP's failure relationship is auto-terminated
 
     When both instances start up
     Then in the "secondary" container at least one file with minimum size of 
"1 MB" is placed in the "/tmp/output" directory in less than 60 seconds
     And the Minifi logs contain the following message: "[warning] 
InvokeHTTP::onTrigger has been running for" in less than 10 seconds
 
   Scenario: A MiNiFi instance retrieves data from another MiNiFi instance with 
message body and limited speed
-    Given a InvokeHTTP processor with the "Remote URL" property set to 
"http://secondary-${scenario_id}:8080/contentListener&testfile";
+    Given a GenerateFlowFile processor with the "File Size" property set to 
"10 MB" in the "secondary" flow
+    And a UpdateAttribute processor with the "http.type" property set to 
"response_body" in the "secondary" flow
+    And UpdateAttribute is EVENT_DRIVEN in the "secondary" flow
+    And the "filename" property of the UpdateAttribute processor is set to 
"testfile" in the "secondary" flow
+    And the scheduling period of the GenerateFlowFile processor is set to "30 
sec" in the "secondary" flow
+    And a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
+    And ListenHTTP is EVENT_DRIVEN in the "secondary" flow
+    And in the "secondary" flow the "success" relationship of the 
GenerateFlowFile processor is connected to the UpdateAttribute
+    And in the "secondary" flow the "success" relationship of the 
UpdateAttribute processor is connected to the ListenHTTP
+    And ListenHTTP's success relationship is auto-terminated in the 
"secondary" flow
+
+    And a InvokeHTTP processor with the "Remote URL" property set to 
"http://secondary-${scenario_id}:8080/contentListener&testfile";
     And the scheduling period of the InvokeHTTP processor is set to "3 sec"
     And the "HTTP Method" property of the InvokeHTTP processor is set to "GET"
     And the "Connection Timeout" property of the InvokeHTTP processor is set 
to "30 s"
@@ -165,17 +184,7 @@ Feature: Sending data using InvokeHTTP to a receiver using 
ListenHTTP
     And the "response" relationship of the InvokeHTTP processor is connected 
to the PutFile
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
-
-    And a GenerateFlowFile processor with the "File Size" property set to "10 
MB" in the "secondary" flow
-    And a UpdateAttribute processor with the "http.type" property set to 
"response_body" in the "secondary" flow
-    And UpdateAttribute is EVENT_DRIVEN in the "secondary" flow
-    And the "filename" property of the UpdateAttribute processor is set to 
"testfile" in the "secondary" flow
-    And the scheduling period of the GenerateFlowFile processor is set to "30 
sec" in the "secondary" flow
-    And a ListenHTTP processor with the "Listening Port" property set to 
"8080" in the "secondary" flow
-    And ListenHTTP is EVENT_DRIVEN in the "secondary" flow
-    And in the "secondary" flow the "success" relationship of the 
GenerateFlowFile processor is connected to the UpdateAttribute
-    And in the "secondary" flow the "success" relationship of the 
UpdateAttribute processor is connected to the ListenHTTP
-    And ListenHTTP's success relationship is auto-terminated in the 
"secondary" flow
+    And InvokeHTTP's failure relationship is auto-terminated
 
     When both instances start up
     Then at least one file with minimum size of "10 MB" is placed in the 
"/tmp/output" directory in less than 60 seconds
diff --git a/extensions/civetweb/tests/features/https.feature 
b/extensions/civetweb/tests/features/https.feature
index b3d4eb6bd..ff31824ab 100644
--- a/extensions/civetweb/tests/features/https.feature
+++ b/extensions/civetweb/tests/features/https.feature
@@ -17,59 +17,50 @@
 Feature: Transfer data from and to MiNiFi using HTTPS
 
   Scenario: InvokeHTTP to ListenHTTP without an SSLContextService works (no 
mutual TLS in this case)
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
-    And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
-    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"Lorem ipsum dolor sit amet"
-    And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
-    And InvokeHTTP is EVENT_DRIVEN
-    And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
-    And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
-    And InvokeHTTP's success relationship is auto-terminated
-    And InvokeHTTP's response relationship is auto-terminated
-
-    And a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
     And the "SSL Certificate" property of the ListenHTTP processor is set to 
"/tmp/resources/minifi_server.crt" in the "server" flow
     And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "server" flow
     And PutFile is EVENT_DRIVEN in the "server" flow
     And in the "server" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "server" flow
 
-    When both instances start up
-    Then in the "server" container at least one file with the content "Lorem 
ipsum dolor sit amet" is placed in the "/tmp/output" directory in less than 10 
seconds
-
-  Scenario: InvokeHTTP to ListenHTTP without an SSLContextService requires a 
server cert signed by a CA
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
     And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
-    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"consectetur adipiscing elit"
+    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"Lorem ipsum dolor sit amet"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
     And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
+
+    When both instances start up
+    Then in the "server" container at least one file with the content "Lorem 
ipsum dolor sit amet" is placed in the "/tmp/output" directory in less than 10 
seconds
 
-    And a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
+  Scenario: InvokeHTTP to ListenHTTP without an SSLContextService requires a 
server cert signed by a CA
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
     And the "SSL Certificate" property of the ListenHTTP processor is set to 
"/tmp/resources/self_signed_server.crt" in the "server" flow
     And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "server" flow
     And in the "server" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "server" flow
 
-    When both instances start up
-    Then in the "server" container no files are placed in the "/tmp/output" 
directory in 10s of running time
-
-  Scenario: InvokeHTTP to ListenHTTP with mutual TLS, using certificate files
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
     And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
-    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"ut labore et dolore magna aliqua"
+    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"consectetur adipiscing elit"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
-    And an ssl context service with a manual CA cert file is set up for 
InvokeHTTP
     And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
 
-    And a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
+    When both instances start up
+    Then in the "server" container no files are placed in the "/tmp/output" 
directory in 10s of running time
+
+  Scenario: InvokeHTTP to ListenHTTP with mutual TLS, using certificate files
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
     And the "SSL Certificate" property of the ListenHTTP processor is set to 
"/tmp/resources/minifi_server.crt" in the "server" flow
     And the "SSL Certificate Authority" property of the ListenHTTP processor 
is set to "/usr/local/share/certs/ca-root-nss.crt" in the "server" flow
     And the "SSL Verify Peer" property of the ListenHTTP processor is set to 
"yes" in the "server" flow
@@ -78,34 +69,31 @@ Feature: Transfer data from and to MiNiFi using HTTPS
     And in the "server" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "server" flow
 
-    When both instances start up
-    Then in the "server" container at least one file with the content "ut 
labore et dolore magna aliqua" is placed in the "/tmp/output" directory in less 
than 10s
-
-  Scenario: InvokeHTTP to ListenHTTP without mutual TLS, using the system 
certificate store
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
     And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
-    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"Ut enim ad minim veniam"
+    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"ut labore et dolore magna aliqua"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
-    And an ssl context service using the system CA cert store is set up for 
InvokeHTTP
+    And an ssl context service with a manual CA cert file is set up for 
InvokeHTTP
     And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
+
+    When both instances start up
+    Then in the "server" container at least one file with the content "ut 
labore et dolore magna aliqua" is placed in the "/tmp/output" directory in less 
than 10s
 
-    And a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
+  Scenario: InvokeHTTP to ListenHTTP without mutual TLS, using the system 
certificate store
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
     And the "SSL Certificate" property of the ListenHTTP processor is set to 
"/tmp/resources/minifi_server.crt" in the "server" flow
     And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "server" flow
     And in the "server" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "server" flow
 
-    When both instances start up
-    Then in the "server" container at least one file with the content "Ut enim 
ad minim veniam" is placed in the "/tmp/output" directory in less than 10s
-
-  Scenario: InvokeHTTP to ListenHTTP with mutual TLS, using the system 
certificate store
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
     And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
-    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"quis nostrud exercitation ullamco laboris nisi"
+    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"Ut enim ad minim veniam"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
     And InvokeHTTP is EVENT_DRIVEN
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
@@ -113,8 +101,13 @@ Feature: Transfer data from and to MiNiFi using HTTPS
     And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
 
-    And a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
+    When both instances start up
+    Then in the "server" container at least one file with the content "Ut enim 
ad minim veniam" is placed in the "/tmp/output" directory in less than 10s
+
+  Scenario: InvokeHTTP to ListenHTTP with mutual TLS, using the system 
certificate store
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
     And the "SSL Certificate" property of the ListenHTTP processor is set to 
"/tmp/resources/minifi_server.crt" in the "server" flow
     And the "SSL Certificate Authority" property of the ListenHTTP processor 
is set to "/usr/local/share/certs/ca-root-nss.crt" in the "server" flow
     And the "SSL Verify Peer" property of the ListenHTTP processor is set to 
"yes" in the "server" flow
@@ -123,41 +116,44 @@ Feature: Transfer data from and to MiNiFi using HTTPS
     And in the "server" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "server" flow
 
-    When both instances start up
-    Then in the "server" container at least one file with the content "quis 
nostrud exercitation ullamco laboris nisi" is placed in the "/tmp/output" 
directory in less than 10s
-
-  Scenario: InvokeHTTP to ListenHTTP without mutual TLS, using the system 
certificate store, requires a server cert signed by a CA
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
     And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
-    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"ut aliquip ex ea commodo consequat"
+    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"quis nostrud exercitation ullamco laboris nisi"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
+    And InvokeHTTP is EVENT_DRIVEN
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
     And an ssl context service using the system CA cert store is set up for 
InvokeHTTP
     And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
+
+    When both instances start up
+    Then in the "server" container at least one file with the content "quis 
nostrud exercitation ullamco laboris nisi" is placed in the "/tmp/output" 
directory in less than 10s
 
-    And a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
+  Scenario: InvokeHTTP to ListenHTTP without mutual TLS, using the system 
certificate store, requires a server cert signed by a CA
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
     And the "SSL Certificate" property of the ListenHTTP processor is set to 
"/tmp/resources/self_signed_server.crt" in the "server" flow
     And a PutFile processor with the "Directory" property set to "/tmp/output" 
in the "server" flow
     And in the "server" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "server" flow
 
-    When both instances start up
-    Then in the "server" container no files are placed in the "/tmp/output" 
directory in 10s of running time
-
-  Scenario: InvokeHTTP to ListenHTTP with mutual TLS, using the system 
certificate store, requires a server cert signed by a CA
-    Given a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
     And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
-    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"Duis aute irure dolor in reprehenderit in voluptate"
+    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"ut aliquip ex ea commodo consequat"
     And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
     And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
     And an ssl context service using the system CA cert store is set up for 
InvokeHTTP
     And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
     And InvokeHTTP's success relationship is auto-terminated
     And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
+
+    When both instances start up
+    Then in the "server" container no files are placed in the "/tmp/output" 
directory in 10s of running time
 
-    And a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
+  Scenario: InvokeHTTP to ListenHTTP with mutual TLS, using the system 
certificate store, requires a server cert signed by a CA
+    Given a ListenHTTP processor with the "Listening Port" property set to 
"4430" in the "server" flow
     And the "SSL Certificate" property of the ListenHTTP processor is set to 
"/tmp/resources/self_signed_server.crt" in the "server" flow
     And the "SSL Certificate Authority" property of the ListenHTTP processor 
is set to "/usr/local/share/certs/ca-root-nss.crt" in the "server" flow
     And the "SSL Verify Peer" property of the ListenHTTP processor is set to 
"yes" in the "server" flow
@@ -166,5 +162,16 @@ Feature: Transfer data from and to MiNiFi using HTTPS
     And in the "server" flow the "success" relationship of the ListenHTTP 
processor is connected to the PutFile
     And PutFile's success relationship is auto-terminated in the "server" flow
 
+    And a GenerateFlowFile processor with the "Data Format" property set to 
"Text"
+    And the "Unique FlowFiles" property of the GenerateFlowFile processor is 
set to "false"
+    And the "Custom Text" property of the GenerateFlowFile processor is set to 
"Duis aute irure dolor in reprehenderit in voluptate"
+    And a InvokeHTTP processor with the "Remote URL" property set to 
"https://server-${scenario_id}:4430/contentListener";
+    And the "HTTP Method" property of the InvokeHTTP processor is set to "POST"
+    And an ssl context service using the system CA cert store is set up for 
InvokeHTTP
+    And the "success" relationship of the GenerateFlowFile processor is 
connected to the InvokeHTTP
+    And InvokeHTTP's success relationship is auto-terminated
+    And InvokeHTTP's response relationship is auto-terminated
+    And InvokeHTTP's failure relationship is auto-terminated
+
     When both instances start up
     Then in the "server" container no files are placed in the "/tmp/output" 
directory in 10s of running time
diff --git 
a/extensions/couchbase/tests/features/steps/couchbase_server_container.py 
b/extensions/couchbase/tests/features/containers/couchbase_server_container.py
similarity index 99%
rename from 
extensions/couchbase/tests/features/steps/couchbase_server_container.py
rename to 
extensions/couchbase/tests/features/containers/couchbase_server_container.py
index 893ba9de9..002aa9c41 100644
--- a/extensions/couchbase/tests/features/steps/couchbase_server_container.py
+++ 
b/extensions/couchbase/tests/features/containers/couchbase_server_container.py
@@ -42,7 +42,7 @@ class CouchbaseServerContainer(Container):
         finished_str = "logs available in"
         assert wait_for_condition(
             condition=lambda: finished_str in self.get_logs(),
-            timeout_seconds=15,
+            timeout_seconds=30,
             bail_condition=lambda: self.exited,
             context=None)
         return self.run_post_startup_commands()
diff --git a/extensions/couchbase/tests/features/steps/steps.py 
b/extensions/couchbase/tests/features/steps/steps.py
index f20cfda2e..0e8ff3c56 100644
--- a/extensions/couchbase/tests/features/steps/steps.py
+++ b/extensions/couchbase/tests/features/steps/steps.py
@@ -22,7 +22,7 @@ from minifi_test_framework.steps.flow_building_steps import 
add_ssl_context_serv
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
 from minifi_test_framework.core.helpers import log_due_to_failure
 from minifi_test_framework.minifi.controller_service import ControllerService
-from couchbase_server_container import CouchbaseServerContainer
+from containers.couchbase_server_container import CouchbaseServerContainer
 
 
 @step("a Couchbase server is started")
diff --git 
a/extensions/elasticsearch/tests/features/steps/elastic_base_container.py 
b/extensions/elasticsearch/tests/features/containers/elastic_base_container.py
similarity index 100%
rename from 
extensions/elasticsearch/tests/features/steps/elastic_base_container.py
rename to 
extensions/elasticsearch/tests/features/containers/elastic_base_container.py
diff --git 
a/extensions/elasticsearch/tests/features/steps/elasticsearch_container.py 
b/extensions/elasticsearch/tests/features/containers/elasticsearch_container.py
similarity index 100%
rename from 
extensions/elasticsearch/tests/features/steps/elasticsearch_container.py
rename to 
extensions/elasticsearch/tests/features/containers/elasticsearch_container.py
diff --git 
a/extensions/elasticsearch/tests/features/steps/opensearch_container.py 
b/extensions/elasticsearch/tests/features/containers/opensearch_container.py
similarity index 100%
rename from 
extensions/elasticsearch/tests/features/steps/opensearch_container.py
rename to 
extensions/elasticsearch/tests/features/containers/opensearch_container.py
diff --git a/extensions/elasticsearch/tests/features/elasticsearch.feature 
b/extensions/elasticsearch/tests/features/elasticsearch.feature
index a3fc05acb..5379847d8 100644
--- a/extensions/elasticsearch/tests/features/elasticsearch.feature
+++ b/extensions/elasticsearch/tests/features/elasticsearch.feature
@@ -19,7 +19,7 @@ Feature: Managing documents on Elasticsearch with 
PostElasticsearch
   Scenario Outline: MiNiFi instance indexes a document on Elasticsearch using 
Basic Authentication
     Given an Elasticsearch server is set up and running
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "{ "field1" : "value1" }" is present in 
"/tmp/input"
+    And a directory at '/tmp/input' has a file with the content '{ "field1" : 
"value1" }'
     And a PostElasticsearch processor
     And PostElasticsearch is EVENT_DRIVEN
     And the "Hosts" property of the PostElasticsearch processor is set to 
"https://elasticsearch-${scenario_id}:9200";
@@ -47,7 +47,7 @@ Feature: Managing documents on Elasticsearch with 
PostElasticsearch
   Scenario: MiNiFi instance deletes a document from Elasticsearch using API 
Key authentication
     Given an Elasticsearch server is set up and a single document is present 
with "preloaded_id" in "my_index"
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "hello world" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "hello world"
     And a PostElasticsearch processor
     And PostElasticsearch is EVENT_DRIVEN
     And the "Hosts" property of the PostElasticsearch processor is set to 
"https://elasticsearch-${scenario_id}:9200";
@@ -70,7 +70,7 @@ Feature: Managing documents on Elasticsearch with 
PostElasticsearch
   Scenario: MiNiFi instance partially updates a document in Elasticsearch 
using Basic Authentication
     Given an Elasticsearch server is set up and a single document is present 
with "preloaded_id" in "my_index" with "value1" in "field1"
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "{ "field2" : "value2" }" is present in 
"/tmp/input"
+    And a directory at '/tmp/input' has a file with the content '{ "field2" : 
"value2" }'
     And a PostElasticsearch processor
     And PostElasticsearch is EVENT_DRIVEN
     And the "Hosts" property of the PostElasticsearch processor is set to 
"https://elasticsearch-${scenario_id}:9200";
diff --git a/extensions/elasticsearch/tests/features/opensearch.feature 
b/extensions/elasticsearch/tests/features/opensearch.feature
index 7e7cc7c60..18c949a79 100644
--- a/extensions/elasticsearch/tests/features/opensearch.feature
+++ b/extensions/elasticsearch/tests/features/opensearch.feature
@@ -19,7 +19,7 @@ Feature: PostElasticsearch works on Opensearch (Opensearch 
doesnt support API Ke
   Scenario Outline: MiNiFi instance creates a document on Opensearch using 
Basic Authentication
     Given an Opensearch server is set up and running
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "{ "field1" : "value1" }" is present in 
"/tmp/input"
+    And a directory at '/tmp/input' has a file with the content '{ "field1" : 
"value1" }'
     And a PostElasticsearch processor
     And PostElasticsearch is EVENT_DRIVEN
     And the "Hosts" property of the PostElasticsearch processor is set to 
"https://opensearch-${scenario_id}:9200";
@@ -47,7 +47,7 @@ Feature: PostElasticsearch works on Opensearch (Opensearch 
doesnt support API Ke
   Scenario: MiNiFi instance deletes a document from Opensearch using Basic 
Authentication
     Given an Opensearch server is set up and a single document is present with 
"preloaded_id" in "my_index"
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "hello world" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "hello world"
     And a PostElasticsearch processor
     And PostElasticsearch is EVENT_DRIVEN
     And the "Hosts" property of the PostElasticsearch processor is set to 
"https://opensearch-${scenario_id}:9200";
@@ -70,7 +70,7 @@ Feature: PostElasticsearch works on Opensearch (Opensearch 
doesnt support API Ke
   Scenario: MiNiFi instance partially updates a document in Opensearch using 
Basic Authentication
     Given an Opensearch server is set up and a single document is present with 
"preloaded_id" in "my_index" with "value1" in "field1"
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "{ "field2" : "value2" }" is present in 
"/tmp/input"
+    And a directory at '/tmp/input' has a file with the content '{ "field2" : 
"value2" }'
     And a PostElasticsearch processor
     And PostElasticsearch is EVENT_DRIVEN
     And the "Hosts" property of the PostElasticsearch processor is set to 
"https://opensearch-${scenario_id}:9200";
diff --git a/extensions/elasticsearch/tests/features/steps/steps.py 
b/extensions/elasticsearch/tests/features/steps/steps.py
index 810c1516d..ea1e90739 100644
--- a/extensions/elasticsearch/tests/features/steps/steps.py
+++ b/extensions/elasticsearch/tests/features/steps/steps.py
@@ -21,8 +21,8 @@ from minifi_test_framework.steps import flow_building_steps   
# noqa: F401
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
 from minifi_test_framework.minifi.controller_service import ControllerService
 from minifi_test_framework.core.helpers import log_due_to_failure
-from elasticsearch_container import ElasticsearchContainer
-from opensearch_container import OpensearchContainer
+from containers.elasticsearch_container import ElasticsearchContainer
+from containers.opensearch_container import OpensearchContainer
 
 
 @step('an Elasticsearch server is set up and running')
diff --git a/extensions/gcp/tests/features/steps/fake_gcs_server_container.py 
b/extensions/gcp/tests/features/containers/fake_gcs_server_container.py
similarity index 100%
rename from extensions/gcp/tests/features/steps/fake_gcs_server_container.py
rename to extensions/gcp/tests/features/containers/fake_gcs_server_container.py
diff --git a/extensions/gcp/tests/features/google_cloud_storage.feature 
b/extensions/gcp/tests/features/google_cloud_storage.feature
index 2c19abcf3..433024cd4 100644
--- a/extensions/gcp/tests/features/google_cloud_storage.feature
+++ b/extensions/gcp/tests/features/google_cloud_storage.feature
@@ -18,7 +18,7 @@ Feature: Sending data to Google Cloud Storage using 
PutGCSObject
 
   Scenario: A MiNiFi instance can upload data to Google Cloud storage
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "hello_gcs" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "hello_gcs"
     And a Google Cloud storage server is set up
     And a PutGCSObject processor
     And PutGCSObject is EVENT_DRIVEN
diff --git a/extensions/gcp/tests/features/steps/steps.py 
b/extensions/gcp/tests/features/steps/steps.py
index 639434d9d..130907e18 100644
--- a/extensions/gcp/tests/features/steps/steps.py
+++ b/extensions/gcp/tests/features/steps/steps.py
@@ -20,7 +20,7 @@ from minifi_test_framework.steps import core_steps            
# noqa: F401
 from minifi_test_framework.steps import flow_building_steps   # noqa: F401
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
 from minifi_test_framework.core.helpers import log_due_to_failure
-from fake_gcs_server_container import FakeGcsServerContainer
+from containers.fake_gcs_server_container import FakeGcsServerContainer
 
 
 @step("a Google Cloud storage server is set up")
diff --git 
a/extensions/grafana-loki/tests/features/steps/grafana_loki_container.py 
b/extensions/grafana-loki/tests/features/containers/grafana_loki_container.py
similarity index 100%
rename from 
extensions/grafana-loki/tests/features/steps/grafana_loki_container.py
rename to 
extensions/grafana-loki/tests/features/containers/grafana_loki_container.py
diff --git 
a/extensions/grafana-loki/tests/features/steps/reverse_proxy_container.py 
b/extensions/grafana-loki/tests/features/containers/reverse_proxy_container.py
similarity index 100%
rename from 
extensions/grafana-loki/tests/features/steps/reverse_proxy_container.py
rename to 
extensions/grafana-loki/tests/features/containers/reverse_proxy_container.py
diff --git a/extensions/grafana-loki/tests/features/steps/steps.py 
b/extensions/grafana-loki/tests/features/steps/steps.py
index bd675e110..865fbc30b 100644
--- a/extensions/grafana-loki/tests/features/steps/steps.py
+++ b/extensions/grafana-loki/tests/features/steps/steps.py
@@ -20,8 +20,8 @@ from minifi_test_framework.steps import core_steps            
# noqa: F401
 from minifi_test_framework.steps import flow_building_steps   # noqa: F401
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
 from minifi_test_framework.core.helpers import log_due_to_failure
-from grafana_loki_container import GrafanaLokiContainer, GrafanaLokiOptions
-from reverse_proxy_container import ReverseProxyContainer
+from containers.grafana_loki_container import GrafanaLokiContainer, 
GrafanaLokiOptions
+from containers.reverse_proxy_container import ReverseProxyContainer
 
 
 @step("a Grafana Loki server is set up")
diff --git a/extensions/kafka/tests/features/steps/kafka_server_container.py 
b/extensions/kafka/tests/features/containers/kafka_server_container.py
similarity index 100%
rename from extensions/kafka/tests/features/steps/kafka_server_container.py
rename to extensions/kafka/tests/features/containers/kafka_server_container.py
diff --git a/extensions/kafka/tests/features/steps/steps.py 
b/extensions/kafka/tests/features/steps/steps.py
index 474cc7bf1..f0f15c1db 100644
--- a/extensions/kafka/tests/features/steps/steps.py
+++ b/extensions/kafka/tests/features/steps/steps.py
@@ -24,7 +24,7 @@ from minifi_test_framework.steps import core_steps            
# noqa: F401
 from minifi_test_framework.steps import flow_building_steps   # noqa: F401
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
 from minifi_test_framework.minifi.processor import Processor
-from kafka_server_container import KafkaServer
+from containers.kafka_server_container import KafkaServer
 
 
 @step("a Kafka server is set up")
diff --git a/extensions/mqtt/tests/features/steps/mqtt_broker_container.py 
b/extensions/mqtt/tests/features/containers/mqtt_broker_container.py
similarity index 100%
rename from extensions/mqtt/tests/features/steps/mqtt_broker_container.py
rename to extensions/mqtt/tests/features/containers/mqtt_broker_container.py
diff --git a/extensions/mqtt/tests/features/mqtt.feature 
b/extensions/mqtt/tests/features/mqtt.feature
index 1f4bd10d4..f77d5e4ea 100644
--- a/extensions/mqtt/tests/features/mqtt.feature
+++ b/extensions/mqtt/tests/features/mqtt.feature
@@ -21,7 +21,7 @@ Feature: Sending data to MQTT streaming platform using 
PublishMQTT
 
   Scenario Outline: A MiNiFi instance transfers data to an MQTT broker
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a PublishMQTT processor set up to communicate with an MQTT broker 
instance
     And the "MQTT Version" property of the PublishMQTT processor is set to 
"<version>"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
@@ -43,7 +43,7 @@ Feature: Sending data to MQTT streaming platform using 
PublishMQTT
 
   Scenario Outline: If the MQTT broker does not exist, then no flow files are 
processed
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a PublishMQTT processor set up to communicate with an MQTT broker 
instance
     And the "MQTT Version" property of the PublishMQTT processor is set to 
"<version>"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
@@ -63,7 +63,7 @@ Feature: Sending data to MQTT streaming platform using 
PublishMQTT
 
   Scenario Outline: Verify delivery of message when MQTT broker is unstable
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a PublishMQTT processor set up to communicate with an MQTT broker 
instance
     And the "MQTT Version" property of the PublishMQTT processor is set to 
"<version>"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
@@ -339,7 +339,7 @@ Feature: Sending data to MQTT streaming platform using 
PublishMQTT
     # publishing MQTT client
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input" in the "publisher-client" flow
     And the scheduling period of the GetFile processor is set to "120 seconds" 
in the "publisher-client" flow
-    And a file with the content "test" is present in "/tmp/input" in the 
"publisher-client" flow
+    And a directory at "/tmp/input" has a file with the content "test" in the 
"publisher-client" flow
     And a PublishMQTT processor set up to communicate with an MQTT broker 
instance in the "publisher-client" flow
     And PublishMQTT is EVENT_DRIVEN in the "publisher-client" flow
     And the "MQTT Version" property of the PublishMQTT processor is set to 
"<version>" in the "publisher-client" flow
@@ -600,7 +600,7 @@ Feature: Sending data to MQTT streaming platform using 
PublishMQTT
     And the "Name of Record Tag" property of the XMLRecordSetWriter controller 
service is set to "record"
     And the "Name of Root Tag" property of the XMLRecordSetWriter controller 
service is set to "root"
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content '[{"string": "test"}, {"int": 42}]' is present 
in '/tmp/input'
+    And a directory at '/tmp/input' has a file with the content '[{"string": 
"test"}, {"int": 42}]'
     And a PublishMQTT processor set up to communicate with an MQTT broker 
instance
     And PublishMQTT is EVENT_DRIVEN
     And the "MQTT Version" property of the PublishMQTT processor is set to 
"3.x AUTO"
diff --git a/extensions/mqtt/tests/features/steps/steps.py 
b/extensions/mqtt/tests/features/steps/steps.py
index 4bff1b2a1..39a8f4429 100644
--- a/extensions/mqtt/tests/features/steps/steps.py
+++ b/extensions/mqtt/tests/features/steps/steps.py
@@ -24,7 +24,7 @@ from minifi_test_framework.core.minifi_test_context import 
DEFAULT_MINIFI_CONTAI
 from minifi_test_framework.minifi.processor import Processor
 from minifi_test_framework.core.helpers import wait_for_condition
 
-from mqtt_broker_container import MqttBrokerContainer
+from containers.mqtt_broker_container import MqttBrokerContainer
 
 
 @given("a {processor_name} processor set up to communicate with an MQTT broker 
instance in the \"{container_name}\" flow")
diff --git a/extensions/opc/tests/features/steps/opc_ua_server_container.py 
b/extensions/opc/tests/features/containers/opc_ua_server_container.py
similarity index 98%
rename from extensions/opc/tests/features/steps/opc_ua_server_container.py
rename to extensions/opc/tests/features/containers/opc_ua_server_container.py
index 4973b9046..2646bb403 100644
--- a/extensions/opc/tests/features/steps/opc_ua_server_container.py
+++ b/extensions/opc/tests/features/containers/opc_ua_server_container.py
@@ -28,6 +28,6 @@ class OPCUAServerContainer(Container):
         finished_str = "New DiscoveryUrl added: opc.tcp://"
         return wait_for_condition(
             condition=lambda: finished_str in self.get_logs(),
-            timeout_seconds=15,
+            timeout_seconds=30,
             bail_condition=lambda: self.exited,
             context=None)
diff --git a/extensions/opc/tests/features/steps/steps.py 
b/extensions/opc/tests/features/steps/steps.py
index f9db97c8a..d12ed0338 100644
--- a/extensions/opc/tests/features/steps/steps.py
+++ b/extensions/opc/tests/features/steps/steps.py
@@ -22,7 +22,7 @@ from minifi_test_framework.steps import core_steps            
# noqa: F401
 from minifi_test_framework.steps import flow_building_steps   # noqa: F401
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
 from minifi_test_framework.core.helpers import wait_for_condition
-from opc_ua_server_container import OPCUAServerContainer
+from containers.opc_ua_server_container import OPCUAServerContainer
 
 
 @step("an OPC UA server is set up")
diff --git a/extensions/prometheus/tests/features/steps/prometheus_container.py 
b/extensions/prometheus/tests/features/containers/prometheus_container.py
similarity index 100%
rename from extensions/prometheus/tests/features/steps/prometheus_container.py
rename to 
extensions/prometheus/tests/features/containers/prometheus_container.py
diff --git a/extensions/prometheus/tests/features/prometheus.feature 
b/extensions/prometheus/tests/features/prometheus.feature
index 0457db5f5..508329529 100644
--- a/extensions/prometheus/tests/features/prometheus.feature
+++ b/extensions/prometheus/tests/features/prometheus.feature
@@ -18,7 +18,7 @@ Feature: MiNiFi can publish metrics to Prometheus server
 
   Scenario: Published metrics are scraped by Prometheus server
     Given a GetFile processor with the name "GetFile1" and the "Input 
Directory" property set to "/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And PutFile is EVENT_DRIVEN
     And the "success" relationship of the GetFile1 processor is connected to 
the PutFile
@@ -37,7 +37,7 @@ Feature: MiNiFi can publish metrics to Prometheus server
 
   Scenario: Published metrics are scraped by Prometheus server through SSL 
connection
     Given a GetFile processor with the name "GetFile1" and the "Input 
Directory" property set to "/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And PutFile is EVENT_DRIVEN
     And the "success" relationship of the GetFile1 processor is connected to 
the PutFile
@@ -58,7 +58,7 @@ Feature: MiNiFi can publish metrics to Prometheus server
     And a GetFile processor with the name "GetFile2" and the "Input Directory" 
property set to "/tmp/input"
     And the "Keep Source File" property of the GetFile1 processor is set to 
"true"
     And the "Keep Source File" property of the GetFile2 processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And the "success" relationship of the GetFile1 processor is connected to 
the PutFile
     And the "success" relationship of the GetFile2 processor is connected to 
the PutFile
diff --git a/extensions/prometheus/tests/features/steps/steps.py 
b/extensions/prometheus/tests/features/steps/steps.py
index a10a4a26b..51a70cf51 100644
--- a/extensions/prometheus/tests/features/steps/steps.py
+++ b/extensions/prometheus/tests/features/steps/steps.py
@@ -20,7 +20,7 @@ from minifi_test_framework.steps import core_steps            
# noqa: F401
 from minifi_test_framework.steps import flow_building_steps   # noqa: F401
 from minifi_test_framework.core.helpers import wait_for_condition
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
-from prometheus_container import PrometheusContainer
+from containers.prometheus_container import PrometheusContainer
 
 
 @step('a Prometheus server is set up')
diff --git a/extensions/python/tests/features/python.feature 
b/extensions/python/tests/features/python.feature
index 906782d90..657137c99 100644
--- a/extensions/python/tests/features/python.feature
+++ b/extensions/python/tests/features/python.feature
@@ -84,7 +84,7 @@ Feature: MiNiFi can use python processors in its flows
   @USE_NIFI_PYTHON_PROCESSORS_WITH_LANGCHAIN
   Scenario Outline: MiNiFi C++ can use native NiFi python processors
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with filename "test_file.log" and content "test_data" is 
present in "/tmp/input"
+    And a directory at "/tmp/input" has a file "test_file.log" with the 
content "test_data"
     And a 
org.apache.nifi.minifi.processors.nifi_python_processors.ParseDocument 
processor with the name "ParseDocument"
     And ParseDocument is EVENT_DRIVEN
     And a 
org.apache.nifi.minifi.processors.nifi_python_processors.ChunkDocument 
processor with the name "ChunkDocument"
@@ -132,10 +132,10 @@ Feature: MiNiFi can use python processors in its flows
 
   Scenario: MiNiFi C++ can use custom relationships in NiFi native python 
processors
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with filename "test_file.log" and content "test_data_one" is 
present in "/tmp/input"
-    And a file with filename "test_file2.log" and content "test_data_two" is 
present in "/tmp/input"
-    And a file with filename "test_file3.log" and content "test_data_three" is 
present in "/tmp/input"
-    And a file with filename "test_file4.log" and content "test_data_four" is 
present in "/tmp/input"
+    And a directory at "/tmp/input" has a file "test_file.log" with the 
content "test_data_one"
+    And a directory at "/tmp/input" has a file "test_file2.log" with the 
content "test_data_two"
+    And a directory at "/tmp/input" has a file "test_file3.log" with the 
content "test_data_three"
+    And a directory at "/tmp/input" has a file "test_file4.log" with the 
content "test_data_four"
     And a 
org.apache.nifi.minifi.processors.nifi_python_processors.RotatingForwarder 
processor with the name "RotatingForwarder"
     And RotatingForwarder is EVENT_DRIVEN
     And a PutFile processor with the "Directory" property set to "/tmp/output"
@@ -253,8 +253,8 @@ Feature: MiNiFi can use python processors in its flows
 
   Scenario: MiNiFi C++ supports RecordTransform native python processors
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content '{"group": "group1", "name": 
"John"}\n{"group": "group1", "name": "Jane"}\n{"group": "group2", "name": 
"Kyle"}\n{"name": "Zoe"}' is present in '/tmp/input'
-    And a file with the content '{"group": "group1", "name": "Steve"}\n{}' is 
present in '/tmp/input'
+    And a directory at '/tmp/input' has a file with the content '{"group": 
"group1", "name": "John"}\n{"group": "group1", "name": "Jane"}\n{"group": 
"group2", "name": "Kyle"}\n{"name": "Zoe"}'
+    And a directory at '/tmp/input' has a file with the content '{"group": 
"group1", "name": "Steve"}\n{}'
     And a 
org.apache.nifi.minifi.processors.nifi_python_processors.SetRecordField 
processor with the name "SetRecordField"
     And SetRecordField is EVENT_DRIVEN
     And the "Record Reader" property of the SetRecordField processor is set to 
"JsonTreeReader"
diff --git a/extensions/splunk/tests/features/steps/splunk_container.py 
b/extensions/splunk/tests/features/containers/splunk_container.py
similarity index 100%
rename from extensions/splunk/tests/features/steps/splunk_container.py
rename to extensions/splunk/tests/features/containers/splunk_container.py
diff --git a/extensions/splunk/tests/features/splunk.feature 
b/extensions/splunk/tests/features/splunk.feature
index 8f929e315..81a5fe4ab 100644
--- a/extensions/splunk/tests/features/splunk.feature
+++ b/extensions/splunk/tests/features/splunk.feature
@@ -20,7 +20,7 @@ Feature: Sending data to Splunk HEC using PutSplunkHTTP
   Scenario: A MiNiFi instance transfers data to a Splunk HEC
     Given a Splunk HEC is set up and running
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "foobar" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "foobar"
     And a PutSplunkHTTP processor
     And PutSplunkHTTP is EVENT_DRIVEN
     And a QuerySplunkIndexingStatus processor
@@ -51,7 +51,7 @@ Feature: Sending data to Splunk HEC using PutSplunkHTTP
   Scenario: A MiNiFi instance transfers data to a Splunk HEC with SSL enabled
     Given a Splunk HEC is set up and running
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "foobar" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "foobar"
     And a PutSplunkHTTP processor
     And PutSplunkHTTP is EVENT_DRIVEN
     And a QuerySplunkIndexingStatus processor
diff --git a/extensions/splunk/tests/features/steps/steps.py 
b/extensions/splunk/tests/features/steps/steps.py
index 16a8d66e9..dda17dabe 100644
--- a/extensions/splunk/tests/features/steps/steps.py
+++ b/extensions/splunk/tests/features/steps/steps.py
@@ -20,7 +20,7 @@ from minifi_test_framework.steps import core_steps            
# noqa: F401
 from minifi_test_framework.steps import flow_building_steps   # noqa: F401
 from minifi_test_framework.core.helpers import log_due_to_failure
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
-from splunk_container import SplunkContainer
+from containers.splunk_container import SplunkContainer
 
 
 @step("a Splunk HEC is set up and running")
diff --git a/extensions/sql/tests/features/steps/postgress_server_container.py 
b/extensions/sql/tests/features/containers/postgress_server_container.py
similarity index 99%
rename from extensions/sql/tests/features/steps/postgress_server_container.py
rename to extensions/sql/tests/features/containers/postgress_server_container.py
index 96e0eb7eb..c95f808ef 100644
--- a/extensions/sql/tests/features/steps/postgress_server_container.py
+++ b/extensions/sql/tests/features/containers/postgress_server_container.py
@@ -53,7 +53,7 @@ class PostgresContainer(Container):
         finished_str = "database system is ready to accept connections"
         return wait_for_condition(
             condition=lambda: finished_str in self.get_logs(),
-            timeout_seconds=5,
+            timeout_seconds=60,
             bail_condition=lambda: self.exited,
             context=None)
 
diff --git a/extensions/sql/tests/features/steps/steps.py 
b/extensions/sql/tests/features/steps/steps.py
index db2f555e4..31645138f 100644
--- a/extensions/sql/tests/features/steps/steps.py
+++ b/extensions/sql/tests/features/steps/steps.py
@@ -25,7 +25,7 @@ from minifi_test_framework.steps import flow_building_steps   
# noqa: F401
 from minifi_test_framework.core.helpers import wait_for_condition
 from minifi_test_framework.minifi.controller_service import ControllerService
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
-from postgress_server_container import PostgresContainer
+from containers.postgress_server_container import PostgresContainer
 
 
 @given("an ODBCService is setup up for {processor_name} with the name 
\"{service_name}\"")
diff --git 
a/extensions/standard-processors/tests/features/attributes_to_json.feature 
b/extensions/standard-processors/tests/features/attributes_to_json.feature
index 337847ebb..7f68c0b63 100644
--- a/extensions/standard-processors/tests/features/attributes_to_json.feature
+++ b/extensions/standard-processors/tests/features/attributes_to_json.feature
@@ -18,7 +18,7 @@ Feature: Writing attribute data using AttributesToJSON 
processor
 
   Scenario: Write selected attribute data to file
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a directory at "/tmp/input" has a file ("test_file.log") with the 
content "test_data"
+    And a directory at "/tmp/input" has a file "test_file.log" with the 
content "test_data"
     And a AttributesToJSON processor with the "Attributes List" property set 
to "filename,invalid"
     And the "Destination" property of the AttributesToJSON processor is set to 
"flowfile-content"
     And the "Null Value" property of the AttributesToJSON processor is set to 
"true"
diff --git 
a/extensions/standard-processors/tests/features/steps/diag_slave_container.py 
b/extensions/standard-processors/tests/features/containers/diag_slave_container.py
similarity index 98%
rename from 
extensions/standard-processors/tests/features/steps/diag_slave_container.py
rename to 
extensions/standard-processors/tests/features/containers/diag_slave_container.py
index a168c7325..e4827e0f6 100644
--- 
a/extensions/standard-processors/tests/features/steps/diag_slave_container.py
+++ 
b/extensions/standard-processors/tests/features/containers/diag_slave_container.py
@@ -45,7 +45,7 @@ ENV PROTOCOL=tcp
         finished_str = "Server started up successfully."
         return wait_for_condition(
             condition=lambda: finished_str in self.get_logs(),
-            timeout_seconds=5,
+            timeout_seconds=30,
             bail_condition=lambda: self.exited,
             context=None
         )
diff --git 
a/extensions/standard-processors/tests/features/steps/syslog_container.py 
b/extensions/standard-processors/tests/features/containers/syslog_container.py
similarity index 100%
rename from 
extensions/standard-processors/tests/features/steps/syslog_container.py
rename to 
extensions/standard-processors/tests/features/containers/syslog_container.py
diff --git 
a/extensions/standard-processors/tests/features/steps/tcp_client_container.py 
b/extensions/standard-processors/tests/features/containers/tcp_client_container.py
similarity index 98%
rename from 
extensions/standard-processors/tests/features/steps/tcp_client_container.py
rename to 
extensions/standard-processors/tests/features/containers/tcp_client_container.py
index d3f02d16a..ddffc7d4f 100644
--- 
a/extensions/standard-processors/tests/features/steps/tcp_client_container.py
+++ 
b/extensions/standard-processors/tests/features/containers/tcp_client_container.py
@@ -34,7 +34,7 @@ class TcpClientContainer(Container):
         finished_str = "TCP client container started"
         return wait_for_condition(
             condition=lambda: finished_str in self.get_logs(),
-            timeout_seconds=5,
+            timeout_seconds=30,
             bail_condition=lambda: self.exited,
             context=None
         )
diff --git 
a/extensions/standard-processors/tests/features/core_functionality.feature 
b/extensions/standard-processors/tests/features/core_functionality.feature
index 4b5f6b38b..bab09863f 100644
--- a/extensions/standard-processors/tests/features/core_functionality.feature
+++ b/extensions/standard-processors/tests/features/core_functionality.feature
@@ -77,7 +77,7 @@ Feature: Core flow functionalities
     And a non-sensitive parameter in the flow config called 'FILE_INPUT_PATH' 
with the value '/tmp/input' in the parameter context 'my-context'
     And a non-sensitive parameter in the flow config called 
'FILE_OUTPUT_UPPER_PATH_ATTR' with the value 'upper_out_path_attr' in the 
parameter context 'my-context'
     And a GetFile processor with the "Input Directory" property set to 
"#{FILE_INPUT_PATH}"
-    And a file with filename "test_file_name" and content "test content" is 
present in "/tmp/input"
+    And a directory at "/tmp/input" has a file "test_file_name" with the 
content "test content"
     And a UpdateAttribute processor with the "expr-lang-filename" property set 
to "#{FILENAME}"
     And the "is-upper-correct" property of the UpdateAttribute processor is 
set to "${#{FILENAME_IN_EXPRESSION}:toUpper():equals('TEST_FILE_NAME')}"
     And the "upper_out_path_attr" property of the UpdateAttribute processor is 
set to "/TMP/OUTPUT"
diff --git 
a/extensions/standard-processors/tests/features/evaluate_json_path.feature 
b/extensions/standard-processors/tests/features/evaluate_json_path.feature
index d2c503363..c87f91c42 100644
--- a/extensions/standard-processors/tests/features/evaluate_json_path.feature
+++ b/extensions/standard-processors/tests/features/evaluate_json_path.feature
@@ -18,7 +18,7 @@ Feature: Writing JSON path query result to attribute or flow 
file using Evaluate
 
   Scenario: Write query result to flow file
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with filename "test_file.json" and content "{"books": 
[{"title": "The Great Gatsby", "author": "F. Scott Fitzgerald"}, {"title": 
"1984", "author": "George Orwell"}]}" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file "test_file.json" with the 
content "{"books": [{"title": "The Great Gatsby", "author": "F. Scott 
Fitzgerald"}, {"title": "1984", "author": "George Orwell"}]}"
     And a EvaluateJsonPath processor with the "Destination" property set to 
"flowfile-content"
     And the "JsonPath" property of the EvaluateJsonPath processor is set to 
"$.books[*].title"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
@@ -32,7 +32,7 @@ Feature: Writing JSON path query result to attribute or flow 
file using Evaluate
 
   Scenario: Write query result to attributes
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with filename "test_file.json" and content "{"title": "1984", 
"author": null}" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file "test_file.json" with the 
content "{"title": "1984", "author": null}"
     And a EvaluateJsonPath processor with the "Destination" property set to 
"flowfile-attribute"
     And the "Null Value Representation" property of the EvaluateJsonPath 
processor is set to "the string 'null'"
     And the "Path Not Found Behavior" property of the EvaluateJsonPath 
processor is set to "skip"
diff --git 
a/extensions/standard-processors/tests/features/file_system_operations.feature 
b/extensions/standard-processors/tests/features/file_system_operations.feature
index d7341ddb0..5bec6a6f4 100644
--- 
a/extensions/standard-processors/tests/features/file_system_operations.feature
+++ 
b/extensions/standard-processors/tests/features/file_system_operations.feature
@@ -21,7 +21,7 @@ Feature: File system operations are handled by the GetFile, 
PutFile, ListFile an
 
   Scenario: Get and put operations run in a simple flow
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a PutFile processor with the "Directory" property set to "/tmp/output"
     And PutFile is EVENT_DRIVEN
     And the "success" relationship of the GetFile processor is connected to 
the PutFile
@@ -56,7 +56,7 @@ Feature: File system operations are handled by the GetFile, 
PutFile, ListFile an
     And PutFile_3's success relationship is auto-terminated
     And PutFile_3's failure relationship is auto-terminated
 
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     When the MiNiFi instance starts up
     Then a single file with the content "test" is placed in the "/tmp/output" 
directory in less than 10 seconds
 
diff --git a/extensions/standard-processors/tests/features/hashcontent.feature 
b/extensions/standard-processors/tests/features/hashcontent.feature
index 8e24bf62b..096ba183f 100644
--- a/extensions/standard-processors/tests/features/hashcontent.feature
+++ b/extensions/standard-processors/tests/features/hashcontent.feature
@@ -21,7 +21,7 @@ Feature: Hash value is added to Flowfiles by HashContent 
processor
 
   Scenario Outline: HashContent adds hash attribute to flowfiles
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content <content> is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "<content>"
     And a HashContent processor with the "Hash Attribute" property set to 
"hash"
     And the "Hash Algorithm" property of the HashContent processor is set to 
"<hash_algorithm>"
     And HashContent is EVENT_DRIVEN
@@ -34,10 +34,10 @@ Feature: Hash value is added to Flowfiles by HashContent 
processor
     Then the Minifi logs contain the following message: "key:hash 
value:<hash_value>" in less than 10 seconds
 
     Examples:
-      | content  | hash_algorithm | hash_value                                 
                      |
-      | "apple"  | MD5            | 1F3870BE274F6C49B3E31A0C6728957F           
                      |
-      | "test"   | SHA1           | A94A8FE5CCB19BA61C4C0873D391E987982FBBD3   
                      |
-      | "coffee" | SHA256         | 
37290D74AC4D186E3A8E5785D259D2EC04FAC91AE28092E7620EC8BC99E830AA |
+      | content | hash_algorithm | hash_value                                  
                     |
+      | apple   | MD5            | 1F3870BE274F6C49B3E31A0C6728957F            
                     |
+      | test    | SHA1           | A94A8FE5CCB19BA61C4C0873D391E987982FBBD3    
                     |
+      | coffee  | SHA256         | 
37290D74AC4D186E3A8E5785D259D2EC04FAC91AE28092E7620EC8BC99E830AA |
 
   Scenario: HashContent fails for an empty file if 'fail on empty' property is 
set to true
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
@@ -57,7 +57,7 @@ Feature: Hash value is added to Flowfiles by HashContent 
processor
   Scenario: HashContent can use MD5 in FIPS mode
     Given OpenSSL FIPS mode is enabled in MiNiFi
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "apple" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "apple"
     And a HashContent processor with the "Hash Attribute" property set to 
"hash"
     And the "Hash Algorithm" property of the HashContent processor is set to 
"MD5"
     And HashContent is EVENT_DRIVEN
diff --git 
a/extensions/standard-processors/tests/features/minifi_c2_server.feature 
b/extensions/standard-processors/tests/features/minifi_c2_server.feature
index 29d11295a..26680eeda 100644
--- a/extensions/standard-processors/tests/features/minifi_c2_server.feature
+++ b/extensions/standard-processors/tests/features/minifi_c2_server.feature
@@ -19,7 +19,7 @@ Feature: MiNiFi can communicate with Apache NiFi MiNiFi C2 
server
   Scenario: MiNiFi flow config is updated from MiNiFi C2 server
     Given a GetFile processor with the name "GetFile1" and the "Input 
Directory" property set to "/tmp/non-existent"
     And C2 is enabled in MiNiFi
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a MiNiFi C2 server is set up
     When all instances start up
     Then the MiNiFi C2 server logs contain the following message: 
"acknowledged with a state of FULLY_APPLIED(DONE)" in less than 30 seconds
@@ -29,14 +29,14 @@ Feature: MiNiFi can communicate with Apache NiFi MiNiFi C2 
server
   Scenario: MiNiFi can get flow config from C2 server through flow url when it 
is not available at start
     Given flow configuration path is set up in flow url property
     And C2 is enabled in MiNiFi
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a MiNiFi C2 server is started
     When the MiNiFi instance starts up
     Then the MiNiFi C2 server logs contain the following message: 
"acknowledged with a state of FULLY_APPLIED(DONE)" in less than 30 seconds
     And a single file with the content "test" is placed in the "/tmp/output" 
directory in less than 10 seconds
 
   Scenario: MiNiFi flow config is updated from MiNiFi C2 server through SSL 
with SSL properties
-    Given a file with the content "test" is present in "/tmp/input"
+    Given a directory at "/tmp/input" has a file with the content "test"
     And a GenerateFlowFile processor
     And ssl properties are set up for MiNiFi C2 server
     And a MiNiFi C2 server is set up with SSL
@@ -49,7 +49,7 @@ Feature: MiNiFi can communicate with Apache NiFi MiNiFi C2 
server
     And parameter context name is set to 'my-context'
     And a non-sensitive parameter in the flow config called 'INPUT_DIR' with 
the value '/tmp/non-existent' in the parameter context 'my-context'
     And C2 is enabled in MiNiFi
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a MiNiFi C2 server is set up
     When all instances start up
     Then the MiNiFi C2 server logs contain the following message: 
"acknowledged with a state of FULLY_APPLIED(DONE)" in less than 30 seconds
diff --git 
a/extensions/standard-processors/tests/features/minifi_controller.feature 
b/extensions/standard-processors/tests/features/minifi_controller.feature
index b73f4b9d6..a5eba8bcf 100644
--- a/extensions/standard-processors/tests/features/minifi_controller.feature
+++ b/extensions/standard-processors/tests/features/minifi_controller.feature
@@ -19,7 +19,7 @@ Feature: MiNiFi Controller functionalities
 
   Scenario: Flow config can be updated through MiNiFi controller
     Given a GenerateFlowFile processor
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And controller socket properties are set up
     When all instances start up
     And MiNiFi config is updated through MiNiFi controller
@@ -28,7 +28,7 @@ Feature: MiNiFi Controller functionalities
 
   Scenario: A component can be stopped
     Given a GenerateFlowFile processor
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And controller socket properties are set up
     When all instances start up
     And the GenerateFlowFile component is stopped through MiNiFi controller
@@ -37,7 +37,7 @@ Feature: MiNiFi Controller functionalities
 
   Scenario: If FlowController is stopped all other components are stopped
     Given a GenerateFlowFile processor
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And controller socket properties are set up
     When all instances start up
     And the FlowController component is stopped through MiNiFi controller
@@ -46,7 +46,7 @@ Feature: MiNiFi Controller functionalities
 
   Scenario: FlowController can be stopped and restarted
     Given a GenerateFlowFile processor
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And controller socket properties are set up
     When all instances start up
     And the FlowController component is stopped through MiNiFi controller
@@ -67,14 +67,14 @@ Feature: MiNiFi Controller functionalities
 
   Scenario: Manifest can be retrieved
     Given a GenerateFlowFile processor
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And controller socket properties are set up
     When all instances start up
     Then manifest can be retrieved through MiNiFi controller
 
   Scenario: Debug bundle can be retrieved
     Given a GenerateFlowFile processor
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And controller socket properties are set up
     When all instances start up
     Then debug bundle can be retrieved through MiNiFi controller
diff --git a/extensions/standard-processors/tests/features/s2s.feature 
b/extensions/standard-processors/tests/features/s2s.feature
index 2383f0349..89ebd58c6 100644
--- a/extensions/standard-processors/tests/features/s2s.feature
+++ b/extensions/standard-processors/tests/features/s2s.feature
@@ -21,7 +21,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
 
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a RemoteProcessGroup node with name "RemoteProcessGroup" is opened on 
"http://nifi-${scenario_id}:8080/nifi";
     And an input port with name "to_nifi" is created on the RemoteProcessGroup 
named "RemoteProcessGroup"
     And the "success" relationship of the GetFile processor is connected to 
the to_nifi
@@ -41,7 +41,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
 
   Scenario: A MiNiFi instance produces and transfers a large data file to a 
NiFi instance via s2s
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "this is a very long file we want to send by 
site-to-site" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "this is a 
very long file we want to send by site-to-site"
     And a RemoteProcessGroup node with name "RemoteProcessGroup" is opened on 
"http://nifi-${scenario_id}:8080/nifi";
     And an input port with name "to_nifi" is created on the RemoteProcessGroup 
named "RemoteProcessGroup"
     And the "success" relationship of the GetFile processor is connected to 
the to_nifi
@@ -104,7 +104,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     Given an ssl context service is set up
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a RemoteProcessGroup node with name "RemoteProcessGroup" is opened on 
"https://nifi-${scenario_id}:8443/nifi";
     And an input port with name "to_nifi" is created on the RemoteProcessGroup 
named "RemoteProcessGroup"
     And the "SSL Context Service" property of the "to_nifi" port in the 
"RemoteProcessGroup" remote process group is set to "SSLContextService"
@@ -126,7 +126,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s using SSL config defined in minifi.properties
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
     And the "Keep Source File" property of the GetFile processor is set to 
"true"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a RemoteProcessGroup node with name "RemoteProcessGroup" is opened on 
"https://nifi-${scenario_id}:8443/nifi";
     And an input port with name "to_nifi" is created on the RemoteProcessGroup 
named "RemoteProcessGroup"
     And the "success" relationship of the GetFile processor is connected to 
the to_nifi
@@ -147,7 +147,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
 
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s using HTTP protocol
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a RemoteProcessGroup node with name "RemoteProcessGroup" is opened on 
"http://nifi-${scenario_id}:8080/nifi"; with transport protocol set to "HTTP"
     And an input port with name "to_nifi" is created on the RemoteProcessGroup 
named "RemoteProcessGroup"
     And the "success" relationship of the GetFile processor is connected to 
the to_nifi
@@ -175,7 +175,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And PutFile's success relationship is auto-terminated
 
     And a NiFi container is set up
-    And a file with the content "test" is present in "/tmp/input" in the 
"nifi" flow
+    And a directory at "/tmp/input" has a file with the content "test" in the 
"nifi" flow
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input" in the "nifi" flow
     And a NiFi flow is sending data to an output port named 
"to-minifi-in-nifi" with the id of the port named "from_nifi" from the 
RemoteProcessGroup named "RemoteProcessGroup"
     And in the "nifi" flow the "success" relationship of the GetFile processor 
is connected to the to-minifi-in-nifi
@@ -195,7 +195,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And PutFile's success relationship is auto-terminated
 
     And a NiFi container is set up
-    And a file with the content "test" is present in "/tmp/input" in the 
"nifi" flow
+    And a directory at "/tmp/input" has a file with the content "test" in the 
"nifi" flow
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input" in the "nifi" flow
     And a NiFi flow is sending data to an output port named 
"to-minifi-in-nifi" with the id of the port named "from_nifi" from the 
RemoteProcessGroup named "RemoteProcessGroup"
     And in the "nifi" flow the "success" relationship of the GetFile processor 
is connected to the to-minifi-in-nifi
@@ -217,7 +217,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And PutFile's success relationship is auto-terminated
 
     And a NiFi container is set up with SSL enabled
-    And a file with the content "test" is present in "/tmp/input" in the 
"nifi" flow
+    And a directory at "/tmp/input" has a file with the content "test" in the 
"nifi" flow
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input" in the "nifi" flow
     And a NiFi flow is sending data to an output port named 
"to-minifi-in-nifi" with the id of the port named "from_nifi" from the 
RemoteProcessGroup named "RemoteProcessGroup"
     And in the "nifi" flow the "success" relationship of the GetFile processor 
is connected to the to-minifi-in-nifi
@@ -238,7 +238,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And PutFile's success relationship is auto-terminated
 
     And a NiFi container is set up with SSL enabled
-    And a file with the content "test" is present in "/tmp/input" in the 
"nifi" flow
+    And a directory at "/tmp/input" has a file with the content "test" in the 
"nifi" flow
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input" in the "nifi" flow
     And a NiFi flow is sending data to an output port named 
"to-minifi-in-nifi" with the id of the port named "from_nifi" from the 
RemoteProcessGroup named "RemoteProcessGroup"
     And in the "nifi" flow the "success" relationship of the GetFile processor 
is connected to the to-minifi-in-nifi
@@ -252,7 +252,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
 
   Scenario: A MiNiFi instance produces and transfers data to a NiFi instance 
via s2s using compression
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with the content "test" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file with the content "test"
     And a RemoteProcessGroup node with name "RemoteProcessGroup" is opened on 
"http://nifi-${scenario_id}:8080/nifi";
     And an input port using compression with name "to_nifi" is created on the 
RemoteProcessGroup named "RemoteProcessGroup"
     And the "success" relationship of the GetFile processor is connected to 
the to_nifi
@@ -279,7 +279,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And PutFile's success relationship is auto-terminated
 
     And a NiFi container is set up
-    And a file with the content "test" is present in "/tmp/input" in the 
"nifi" flow
+    And a directory at "/tmp/input" has a file with the content "test" in the 
"nifi" flow
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input" in the "nifi" flow
     And a NiFi flow is sending data to an output port named 
"to-minifi-in-nifi" with the id of the port named "from_nifi" from the 
RemoteProcessGroup named "RemoteProcessGroup"
     And in the "nifi" flow the "success" relationship of the GetFile processor 
is connected to the to-minifi-in-nifi
@@ -299,7 +299,7 @@ Feature: Sending data from MiNiFi-C++ to NiFi using S2S 
protocol
     And PutFile's success relationship is auto-terminated
 
     And a NiFi container is set up
-    And a file with the content "test" is present in "/tmp/input" in the 
"nifi" flow
+    And a directory at "/tmp/input" has a file with the content "test" in the 
"nifi" flow
     And a GetFile processor with the "Input Directory" property set to 
"/tmp/input" in the "nifi" flow
     And a NiFi flow is sending data to an output port named 
"to-minifi-in-nifi" with the id of the port named "from_nifi" from the 
RemoteProcessGroup named "RemoteProcessGroup"
     And in the "nifi" flow the "success" relationship of the GetFile processor 
is connected to the to-minifi-in-nifi
diff --git a/extensions/standard-processors/tests/features/split_json.feature 
b/extensions/standard-processors/tests/features/split_json.feature
index 98ea1fd72..887d3832a 100644
--- a/extensions/standard-processors/tests/features/split_json.feature
+++ b/extensions/standard-processors/tests/features/split_json.feature
@@ -18,7 +18,7 @@ Feature: Splitting JSON content using SplitJson processor
 
   Scenario: Split multiple query results to separate flow files
     Given a GetFile processor with the "Input Directory" property set to 
"/tmp/input"
-    And a file with filename "test_file.json" and content "{"company": 
{"departments": [{"name": "Engineering", "employees": ["Alice", "Bob"]}, 
{"name": "Marketing", "employees": "Dave"}, {"name": "Sales", "employees": 
null}]}}" is present in "/tmp/input"
+    And a directory at "/tmp/input" has a file "test_file.json" with the 
content "{"company": {"departments": [{"name": "Engineering", "employees": 
["Alice", "Bob"]}, {"name": "Marketing", "employees": "Dave"}, {"name": 
"Sales", "employees": null}]}}"
     And a SplitJson processor with the "JsonPath Expression" property set to 
"$.company.departments[*].employees"
     And the "Null Value Representation" property of the SplitJson processor is 
set to "the string 'null'"
     And SplitJson is EVENT_DRIVEN
diff --git a/extensions/standard-processors/tests/features/steps/steps.py 
b/extensions/standard-processors/tests/features/steps/steps.py
index 517bff039..5fa17f32c 100644
--- a/extensions/standard-processors/tests/features/steps/steps.py
+++ b/extensions/standard-processors/tests/features/steps/steps.py
@@ -24,9 +24,9 @@ from minifi_test_framework.steps import core_steps            
# noqa: F401
 from minifi_test_framework.steps import flow_building_steps   # noqa: F401
 from minifi_test_framework.core.minifi_test_context import MinifiTestContext
 from minifi_test_framework.core.helpers import wait_for_condition
-from syslog_container import SyslogContainer
-from diag_slave_container import DiagSlave
-from tcp_client_container import TcpClientContainer
+from containers.syslog_container import SyslogContainer
+from containers.diag_slave_container import DiagSlave
+from containers.tcp_client_container import TcpClientContainer
 from minifi_c2_server_container import MinifiC2Server
 
 

Reply via email to