You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by sz...@apache.org on 2025/11/20 22:29:27 UTC
(nifi-minifi-cpp) 01/04: MINIFICPP-2665 Move OPC UA tests to modular docker tests
This is an automated email from the ASF dual-hosted git repository.
szaszm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit f34569ee1bbc9bd424f8033a20c4bdd7f5ac4c6e
Author: Gabor Gyimesi <ga...@gmail.com>
AuthorDate: Thu Nov 20 14:33:13 2025 +0100
MINIFICPP-2665 Move OPC UA tests to modular docker tests
- Allow using multiple minifi containers, and use dictionaries for naming and storing containers instead of a list
- Allow using host file resources in test minifi containers
Closes #2052
Signed-off-by: Marton Szasz <sz...@apache.org>
---
.../minifi_test_framework/containers/container.py | 22 +++--
.../minifi_test_framework/containers/host_file.py | 4 +-
.../containers/minifi_container.py | 4 +-
.../src/minifi_test_framework/core/helpers.py | 3 +-
.../src/minifi_test_framework/core/hooks.py | 45 +++++----
.../core/minifi_test_context.py | 23 ++++-
.../minifi_test_framework/steps/checking_steps.py | 59 ++++++------
.../steps/configuration_steps.py | 10 +-
.../src/minifi_test_framework/steps/core_steps.py | 27 ++++--
.../steps/flow_building_steps.py | 101 ++++++++++++++-------
docker/RunBehaveTests.sh | 3 +-
docker/test/integration/cluster/ContainerStore.py | 9 --
.../cluster/DockerTestDirectoryBindings.py | 1 -
docker/test/integration/features/http.feature | 2 +-
docker/test/integration/features/https.feature | 2 +-
docker/test/integration/features/steps/steps.py | 18 +---
extensions/aws/tests/features/steps/steps.py | 14 +--
extensions/azure/tests/features/steps/steps.py | 38 ++++----
extensions/opc/tests/features/environment.py | 28 ++++++
.../opc/tests}/features/opcua.feature | 84 ++++++++++-------
.../features/resources}/opcua_client_cert.der | Bin
.../tests/features/resources}/opcua_client_key.der | Bin
.../features/steps/opc_ua_server_container.py | 32 +++----
extensions/opc/tests/features/steps/steps.py | 47 ++++++++++
extensions/sql/tests/features/steps/steps.py | 12 +--
.../tests/features/steps/steps.py | 4 +-
.../tests/features/steps/syslog_container.py | 2 +-
27 files changed, 375 insertions(+), 219 deletions(-)
diff --git a/behave_framework/src/minifi_test_framework/containers/container.py b/behave_framework/src/minifi_test_framework/containers/container.py
index d3a8316df..dc0cf7353 100644
--- a/behave_framework/src/minifi_test_framework/containers/container.py
+++ b/behave_framework/src/minifi_test_framework/containers/container.py
@@ -29,22 +29,25 @@ from minifi_test_framework.containers.host_file import HostFile
class Container:
- def __init__(self, image_name: str, container_name: str, network: Network):
+ def __init__(self, image_name: str, container_name: str, network: Network, command: str | None = None):
self.image_name: str = image_name
self.container_name: str = container_name
self.network: Network = network
self.user: str = "0:0"
- self.client = docker.from_env()
+ self.client: docker.DockerClient = docker.from_env()
self.container = None
self.files: list[File] = []
self.dirs: list[Directory] = []
self.host_files: list[HostFile] = []
self.volumes = {}
- self.command = None
- self._temp_dir = None
- self.ports = None
+ self.command: str | None = command
+ self._temp_dir: tempfile.TemporaryDirectory | None = None
+ self.ports: dict[str, int] | None = None
self.environment: list[str] = []
+ def add_host_file(self, host_path: str, container_path: str, mode: str = "ro"):
+ self.host_files.append(HostFile(container_path, host_path, mode))
+
def deploy(self) -> bool:
self._temp_dir = tempfile.TemporaryDirectory()
@@ -63,7 +66,7 @@ class Container:
temp_file.write(content)
self.volumes[temp_path] = {"bind": directory.path, "mode": directory.mode}
for host_file in self.host_files:
- self.volumes[host_file.container_path] = {"bind": host_file.host_path, "mode": host_file.mode}
+ self.volumes[host_file.host_path] = {"bind": host_file.container_path, "mode": host_file.mode}
try:
existing_container = self.client.containers.get(self.container_name)
@@ -84,7 +87,10 @@ class Container:
def clean_up(self):
if self.container:
- self.container.remove(force=True)
+ try:
+ self.container.remove(force=True)
+ except Exception as e:
+ logging.error(f"Error cleaning up container '{self.container_name}': {e}")
def exec_run(self, command) -> tuple[int | None, str]:
if self.container:
@@ -110,7 +116,7 @@ class Container:
quoted_content = shlex.quote(expected_content)
command = "sh -c {}".format(shlex.quote(f"grep -l -F -- {quoted_content} {directory_path}/*"))
- exit_code, output = self.exec_run(command)
+ exit_code, _ = self.exec_run(command)
return exit_code == 0
diff --git a/behave_framework/src/minifi_test_framework/containers/host_file.py b/behave_framework/src/minifi_test_framework/containers/host_file.py
index 9b59945d2..1e046f54c 100644
--- a/behave_framework/src/minifi_test_framework/containers/host_file.py
+++ b/behave_framework/src/minifi_test_framework/containers/host_file.py
@@ -16,7 +16,7 @@
#
class HostFile:
- def __init__(self, path, host_path):
+ def __init__(self, path, host_path, mode="ro"):
self.container_path = path
self.host_path = host_path
- self.mode = "ro"
+ self.mode = mode
diff --git a/behave_framework/src/minifi_test_framework/containers/minifi_container.py b/behave_framework/src/minifi_test_framework/containers/minifi_container.py
index 7c2661d44..805b04227 100644
--- a/behave_framework/src/minifi_test_framework/containers/minifi_container.py
+++ b/behave_framework/src/minifi_test_framework/containers/minifi_container.py
@@ -23,8 +23,8 @@ from .container import Container
class MinifiContainer(Container):
- def __init__(self, image_name: str, scenario_id: str, network: Network):
- super().__init__(image_name, f"minifi-{scenario_id}", network)
+ def __init__(self, image_name: str, container_name: str, scenario_id: str, network: Network):
+ super().__init__(image_name, f"{container_name}-{scenario_id}", network)
self.flow_config_str: str = ""
self.flow_definition = FlowDefinition()
self.properties: dict[str, str] = {}
diff --git a/behave_framework/src/minifi_test_framework/core/helpers.py b/behave_framework/src/minifi_test_framework/core/helpers.py
index 01fa506b0..3c551b8d4 100644
--- a/behave_framework/src/minifi_test_framework/core/helpers.py
+++ b/behave_framework/src/minifi_test_framework/core/helpers.py
@@ -27,9 +27,8 @@ from minifi_test_framework.core.minifi_test_context import MinifiTestContext
def log_due_to_failure(context: MinifiTestContext | None):
if context is not None:
- for container in context.containers:
+ for container in context.containers.values():
container.log_app_output()
- context.minifi_container.log_app_output()
def wait_for_condition(condition: Callable[[], bool], timeout_seconds: float, bail_condition: Callable[[], bool],
diff --git a/behave_framework/src/minifi_test_framework/core/hooks.py b/behave_framework/src/minifi_test_framework/core/hooks.py
index 0a4c33861..5513c9f51 100644
--- a/behave_framework/src/minifi_test_framework/core/hooks.py
+++ b/behave_framework/src/minifi_test_framework/core/hooks.py
@@ -17,13 +17,12 @@
import logging
import os
-
import docker
+import types
+
from behave.model import Scenario
-from behave.model import Step
from behave.runner import Context
-from minifi_test_framework.containers.minifi_container import MinifiContainer
from minifi_test_framework.core.minifi_test_context import MinifiTestContext
@@ -35,40 +34,52 @@ def get_minifi_container_image():
return "apacheminificpp:behave"
+def inject_scenario_id(context: MinifiTestContext, step):
+ if "${scenario_id}" in step.name:
+ step.name = step.name.replace("${scenario_id}", context.scenario_id)
+ if getattr(step, "table", None):
+ for row in step.table:
+ row.cells = [cell.replace("${scenario_id}", context.scenario_id) if "${scenario_id}" in cell else cell for cell in row.cells]
+ if hasattr(step, "text") and step.text and "${scenario_id}" in step.text:
+ step.text = step.text.replace("${scenario_id}", context.scenario_id)
+
+
def common_before_scenario(context: Context, scenario: Scenario):
if not hasattr(context, "minifi_container_image"):
context.minifi_container_image = get_minifi_container_image()
+ method_map = {
+ "get_or_create_minifi_container": MinifiTestContext.get_or_create_minifi_container,
+ "get_or_create_default_minifi_container": MinifiTestContext.get_or_create_default_minifi_container,
+ "get_minifi_container": MinifiTestContext.get_minifi_container,
+ "get_default_minifi_container": MinifiTestContext.get_default_minifi_container,
+ }
+ for attr, method in method_map.items():
+ if not hasattr(context, attr):
+ setattr(context, attr, types.MethodType(method, context))
+
logging.info("Running scenario: %s", scenario)
context.scenario_id = scenario.filename.rsplit("/", 1)[1].split(".")[0] + "-" + str(
scenario.parent.scenarios.index(scenario))
network_name = f"{context.scenario_id}-net"
docker_client = docker.client.from_env()
+
try:
existing_network = docker_client.networks.get(network_name)
logging.warning(f"Found existing network '{network_name}'. Removing it first.")
existing_network.remove()
except docker.errors.NotFound:
pass # No existing network found, which is good.
+
context.network = docker_client.networks.create(network_name)
- context.minifi_container = MinifiContainer(context.minifi_container_image, context.scenario_id, context.network)
- context.containers = []
+ context.containers = {}
+ context.resource_dir = None
+
for step in scenario.steps:
inject_scenario_id(context, step)
def common_after_scenario(context: MinifiTestContext, scenario: Scenario):
- for container in context.containers:
+ for container in context.containers.values():
container.clean_up()
- context.minifi_container.clean_up()
context.network.remove()
-
-
-def inject_scenario_id(context: MinifiTestContext, step: Step):
- if "${scenario_id}" in step.name:
- step.name = step.name.replace("${scenario_id}", context.scenario_id)
- if step.table:
- for row in step.table:
- for i in range(len(row.cells)):
- if "${scenario_id}" in row.cells[i]:
- row.cells[i] = row.cells[i].replace("${scenario_id}", context.scenario_id)
diff --git a/behave_framework/src/minifi_test_framework/core/minifi_test_context.py b/behave_framework/src/minifi_test_framework/core/minifi_test_context.py
index 6c7892c05..ab9110de0 100644
--- a/behave_framework/src/minifi_test_framework/core/minifi_test_context.py
+++ b/behave_framework/src/minifi_test_framework/core/minifi_test_context.py
@@ -21,9 +21,28 @@ from docker.models.networks import Network
from minifi_test_framework.containers.container import Container
from minifi_test_framework.containers.minifi_container import MinifiContainer
+DEFAULT_MINIFI_CONTAINER_NAME = "minifi-primary"
+
class MinifiTestContext(Context):
- minifi_container: MinifiContainer
- containers: list[Container]
+ containers: dict[str, Container]
scenario_id: str
network: Network
+ minifi_container_image: str
+ resource_dir: str | None
+
+ def get_or_create_minifi_container(self, container_name: str) -> MinifiContainer:
+ if container_name not in self.containers:
+ self.containers[container_name] = MinifiContainer(self.minifi_container_image, container_name, self.scenario_id, self.network)
+ return self.containers[container_name]
+
+ def get_or_create_default_minifi_container(self) -> MinifiContainer:
+ return self.get_or_create_minifi_container(DEFAULT_MINIFI_CONTAINER_NAME)
+
+ def get_minifi_container(self, container_name: str) -> MinifiContainer:
+ if container_name not in self.containers:
+ raise KeyError(f"MiNiFi container '{container_name}' does not exist in the test context.")
+ return self.containers[container_name]
+
+ def get_default_minifi_container(self) -> MinifiContainer:
+ return self.get_minifi_container(DEFAULT_MINIFI_CONTAINER_NAME)
diff --git a/behave_framework/src/minifi_test_framework/steps/checking_steps.py b/behave_framework/src/minifi_test_framework/steps/checking_steps.py
index e4d46c7b4..231a2be89 100644
--- a/behave_framework/src/minifi_test_framework/steps/checking_steps.py
+++ b/behave_framework/src/minifi_test_framework/steps/checking_steps.py
@@ -23,7 +23,7 @@ from behave import then, step
from minifi_test_framework.containers.http_proxy_container import HttpProxy
from minifi_test_framework.core.helpers import wait_for_condition
-from minifi_test_framework.core.minifi_test_context import MinifiTestContext
+from minifi_test_framework.core.minifi_test_context import DEFAULT_MINIFI_CONTAINER_NAME, MinifiTestContext
@then('there is a file with "{content}" content at {path} in less than {duration}')
@@ -31,8 +31,8 @@ def step_impl(context: MinifiTestContext, content: str, path: str, duration: str
new_content = content.replace("\\n", "\n")
timeout_in_seconds = humanfriendly.parse_timespan(duration)
assert wait_for_condition(
- condition=lambda: context.minifi_container.path_with_content_exists(path, new_content),
- timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.minifi_container.exited, context=context)
+ condition=lambda: context.get_default_minifi_container().path_with_content_exists(path, new_content),
+ timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.get_default_minifi_container().exited, context=context)
@then('there is a single file with "{content}" content in the "{directory}" directory in less than {duration}')
@@ -40,47 +40,52 @@ def step_impl(context: MinifiTestContext, content: str, directory: str, duration
new_content = content.replace("\\n", "\n")
timeout_in_seconds = humanfriendly.parse_timespan(duration)
assert wait_for_condition(
- condition=lambda: context.minifi_container.directory_has_single_file_with_content(directory, new_content),
- timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.minifi_container.exited, context=context)
+ condition=lambda: context.get_default_minifi_container().directory_has_single_file_with_content(directory, new_content),
+ timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.get_default_minifi_container().exited, context=context)
-@then('at least one file with the content "{content}" is placed in the "{directory}" directory in less than {duration}')
-def step_impl(context: MinifiTestContext, content: str, directory: str, duration: str):
+@then('in the "{container_name}" container at least one file with the content "{content}" is placed in the "{directory}" directory in less than {duration}')
+def step_impl(context: MinifiTestContext, container_name: str, content: str, directory: str, duration: str):
timeout_in_seconds = humanfriendly.parse_timespan(duration)
assert wait_for_condition(
- condition=lambda: context.minifi_container.directory_contains_file_with_content(directory, content),
- timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.minifi_container.exited, context=context)
+ condition=lambda: context.get_minifi_container(container_name).directory_contains_file_with_content(directory, content),
+ timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.get_minifi_container(container_name).exited, context=context)
+
+
+@then('at least one file with the content "{content}" is placed in the "{directory}" directory in less than {duration}')
+def step_impl(context: MinifiTestContext, content: str, directory: str, duration: str):
+ context.execute_steps(f'then in the "{DEFAULT_MINIFI_CONTAINER_NAME}" container at least one file with the content "{content}" is placed in the "{directory}" directory in less than {duration}')
@then('the Minifi logs do not contain the following message: "{message}" after {duration}')
def step_impl(context: MinifiTestContext, message: str, duration: str):
duration_seconds = humanfriendly.parse_timespan(duration)
time.sleep(duration_seconds)
- assert message not in context.minifi_container.get_logs()
+ assert message not in context.get_default_minifi_container().get_logs()
@then("the Minifi logs do not contain errors")
def step_impl(context: MinifiTestContext):
- assert "[error]" not in context.minifi_container.get_logs() or context.minifi_container.log_app_output()
+ assert "[error]" not in context.get_default_minifi_container().get_logs() or context.get_default_minifi_container().log_app_output()
@then("the Minifi logs do not contain warnings")
def step_impl(context: MinifiTestContext):
- assert "[warning]" not in context.minifi_container.get_logs() or context.minifi_container.log_app_output()
+ assert "[warning]" not in context.get_default_minifi_container().get_logs() or context.get_default_minifi_container().log_app_output()
@then("the Minifi logs contain the following message: '{message}' in less than {duration}")
@then('the Minifi logs contain the following message: "{message}" in less than {duration}')
def step_impl(context: MinifiTestContext, message: str, duration: str):
duration_seconds = humanfriendly.parse_timespan(duration)
- assert wait_for_condition(condition=lambda: message in context.minifi_container.get_logs(),
- timeout_seconds=duration_seconds, bail_condition=lambda: context.minifi_container.exited,
+ assert wait_for_condition(condition=lambda: message in context.get_default_minifi_container().get_logs(),
+ timeout_seconds=duration_seconds, bail_condition=lambda: context.get_default_minifi_container().exited,
context=context)
@step('no errors were generated on the http-proxy regarding "{url}"')
def step_impl(context: MinifiTestContext, url: str):
- http_proxy_container = next(container for container in context.containers if isinstance(container, HttpProxy))
+ http_proxy_container = next(container for container in context.containers.values() if isinstance(container, HttpProxy))
assert http_proxy_container.check_http_proxy_access(url) or http_proxy_container.log_app_output()
@@ -88,16 +93,16 @@ def step_impl(context: MinifiTestContext, url: str):
@then('there is {num_str} file in the "{directory}" directory in less than {duration}')
def step_impl(context: MinifiTestContext, num_str: str, directory: str, duration: str):
duration_seconds = humanfriendly.parse_timespan(duration)
- assert wait_for_condition(condition=lambda: context.minifi_container.get_number_of_files(directory) == int(num_str),
- timeout_seconds=duration_seconds, bail_condition=lambda: context.minifi_container.exited,
+ assert wait_for_condition(condition=lambda: context.get_default_minifi_container().get_number_of_files(directory) == int(num_str),
+ timeout_seconds=duration_seconds, bail_condition=lambda: context.get_default_minifi_container().exited,
context=context)
@then('there are at least {num_str} files is in the "{directory}" directory in less than {duration}')
def step_impl(context: MinifiTestContext, num_str: str, directory: str, duration: str):
duration_seconds = humanfriendly.parse_timespan(duration)
- assert wait_for_condition(condition=lambda: context.minifi_container.get_number_of_files(directory) >= int(num_str),
- timeout_seconds=duration_seconds, bail_condition=lambda: context.minifi_container.exited,
+ assert wait_for_condition(condition=lambda: context.get_default_minifi_container().get_number_of_files(directory) >= int(num_str),
+ timeout_seconds=duration_seconds, bail_condition=lambda: context.get_default_minifi_container().exited,
context=context)
@@ -105,8 +110,8 @@ def step_impl(context: MinifiTestContext, num_str: str, directory: str, duration
def step_impl(context: MinifiTestContext, directory: str, regex_str: str, duration: str):
duration_seconds = humanfriendly.parse_timespan(duration)
assert wait_for_condition(
- condition=lambda: context.minifi_container.directory_contains_file_with_regex(directory, regex_str),
- timeout_seconds=duration_seconds, bail_condition=lambda: context.minifi_container.exited, context=context)
+ condition=lambda: context.get_default_minifi_container().directory_contains_file_with_regex(directory, regex_str),
+ timeout_seconds=duration_seconds, bail_condition=lambda: context.get_default_minifi_container().exited, context=context)
@then('the contents of {directory} in less than {timeout} are: "{content_one}" and "{content_two}"')
@@ -115,8 +120,8 @@ def step_impl(context: MinifiTestContext, directory: str, timeout: str, content_
c1 = content_one.replace("\\n", "\n")
c2 = content_two.replace("\\n", "\n")
contents_arr = [c1, c2]
- assert wait_for_condition(condition=lambda: context.minifi_container.verify_file_contents(directory, contents_arr),
- timeout_seconds=timeout_seconds, bail_condition=lambda: context.minifi_container.exited,
+ assert wait_for_condition(condition=lambda: context.get_default_minifi_container().verify_file_contents(directory, contents_arr),
+ timeout_seconds=timeout_seconds, bail_condition=lambda: context.get_default_minifi_container().exited,
context=context)
@@ -125,8 +130,8 @@ def step_impl(context: MinifiTestContext, directory: str, timeout: str, contents
timeout_seconds = humanfriendly.parse_timespan(timeout)
new_contents = contents.replace("\\n", "\n")
contents_arr = new_contents.split(",")
- assert wait_for_condition(condition=lambda: context.minifi_container.verify_file_contents(directory, contents_arr),
- timeout_seconds=timeout_seconds, bail_condition=lambda: context.minifi_container.exited,
+ assert wait_for_condition(condition=lambda: context.get_default_minifi_container().verify_file_contents(directory, contents_arr),
+ timeout_seconds=timeout_seconds, bail_condition=lambda: context.get_default_minifi_container().exited,
context=context)
@@ -135,5 +140,5 @@ def step_impl(context: MinifiTestContext, directory: str, timeout: str, contents
def step_impl(context: MinifiTestContext, content: str, directory: str, duration: str):
timeout_in_seconds = humanfriendly.parse_timespan(duration)
assert wait_for_condition(
- condition=lambda: context.minifi_container.verify_path_with_json_content(directory, content),
- timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.minifi_container.exited, context=context)
+ condition=lambda: context.get_default_minifi_container().verify_path_with_json_content(directory, content),
+ timeout_seconds=timeout_in_seconds, bail_condition=lambda: context.get_default_minifi_container().exited, context=context)
diff --git a/behave_framework/src/minifi_test_framework/steps/configuration_steps.py b/behave_framework/src/minifi_test_framework/steps/configuration_steps.py
index 5eaeaa326..a9794936f 100644
--- a/behave_framework/src/minifi_test_framework/steps/configuration_steps.py
+++ b/behave_framework/src/minifi_test_framework/steps/configuration_steps.py
@@ -22,16 +22,16 @@ from minifi_test_framework.core.minifi_test_context import MinifiTestContext
@step('MiNiFi configuration "{config_key}" is set to "{config_value}"')
def step_impl(context: MinifiTestContext, config_key: str, config_value: str):
- context.minifi_container.set_property(config_key, config_value)
+ context.get_or_create_default_minifi_container().set_property(config_key, config_value)
@step("log metrics publisher is enabled in MiNiFi")
def step_impl(context):
- context.minifi_container.set_property("nifi.metrics.publisher.LogMetricsPublisher.metrics", "RepositoryMetrics")
- context.minifi_container.set_property("nifi.metrics.publisher.LogMetricsPublisher.logging.interval", "1s")
- context.minifi_container.set_property("nifi.metrics.publisher.class", "LogMetricsPublisher")
+ context.get_or_create_default_minifi_container().set_property("nifi.metrics.publisher.LogMetricsPublisher.metrics", "RepositoryMetrics")
+ context.get_or_create_default_minifi_container().set_property("nifi.metrics.publisher.LogMetricsPublisher.logging.interval", "1s")
+ context.get_or_create_default_minifi_container().set_property("nifi.metrics.publisher.class", "LogMetricsPublisher")
@step('log property "{log_property_key}" is set to "{log_property_value}"')
def step_impl(context: MinifiTestContext, log_property_key: str, log_property_value: str):
- context.minifi_container.set_log_property(log_property_key, log_property_value)
+ context.get_or_create_default_minifi_container().set_log_property(log_property_key, log_property_value)
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 f4d55357b..552ea2d19 100644
--- a/behave_framework/src/minifi_test_framework/steps/core_steps.py
+++ b/behave_framework/src/minifi_test_framework/steps/core_steps.py
@@ -21,24 +21,24 @@ import string
import os
import humanfriendly
-from behave import when, step
+from behave import when, step, given
+
from minifi_test_framework.containers.directory import Directory
from minifi_test_framework.containers.file import File
-from minifi_test_framework.core.minifi_test_context import MinifiTestContext
+from minifi_test_framework.core.minifi_test_context import DEFAULT_MINIFI_CONTAINER_NAME, MinifiTestContext
@when("both instances start up")
@when("all instances start up")
def step_impl(context: MinifiTestContext):
- for container in context.containers:
- assert container.deploy()
- assert context.minifi_container.deploy() or context.minifi_container.log_app_output()
+ for container in context.containers.values():
+ assert container.deploy() or container.log_app_output()
logging.debug("All instances started up")
@when("the MiNiFi instance starts up")
def step_impl(context):
- assert context.minifi_container.deploy()
+ assert context.get_or_create_default_minifi_container().deploy()
logging.debug("MiNiFi instance started up")
@@ -48,10 +48,21 @@ def step_impl(context: MinifiTestContext, directory: str, size: str):
content = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(size))
new_dir = Directory(directory)
new_dir.files["input.txt"] = content
- context.minifi_container.dirs.append(new_dir)
+ context.get_or_create_default_minifi_container().dirs.append(new_dir)
@step('a file with filename "{file_name}" and content "{content}" is present in "{path}"')
def step_impl(context: MinifiTestContext, file_name: str, content: str, path: str):
new_content = content.replace("\\n", "\n")
- context.minifi_container.files.append(File(os.path.join(path, file_name), new_content))
+ context.get_or_create_default_minifi_container().files.append(File(os.path.join(path, file_name), new_content))
+
+
+@given('a host resource file "{filename}" is bound to the "{container_path}" path in the MiNiFi container "{container_name}"')
+def step_impl(context: MinifiTestContext, filename: str, container_path: str, container_name: str):
+ path = os.path.join(context.resource_dir, filename)
+ context.get_or_create_minifi_container(container_name).add_host_file(path, container_path)
+
+
+@given('a host resource file "{filename}" is bound to the "{container_path}" path in the MiNiFi container')
+def step_impl(context: MinifiTestContext, filename: str, container_path: str):
+ context.execute_steps(f"given a host resource file \"{filename}\" is bound to the \"{container_path}\" path in the MiNiFi container \"{DEFAULT_MINIFI_CONTAINER_NAME}\"")
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 a01ec10f9..a41d096c7 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,7 @@ from behave import given, step
from minifi_test_framework.containers.directory import Directory
from minifi_test_framework.containers.http_proxy_container import HttpProxy
-from minifi_test_framework.core.minifi_test_context import MinifiTestContext
+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
from minifi_test_framework.minifi.funnel import Funnel
@@ -30,8 +30,8 @@ from minifi_test_framework.minifi.processor import Processor
@given("a transient MiNiFi flow with a LogOnDestructionProcessor processor")
def step_impl(context: MinifiTestContext):
- context.minifi_container.command = ["/bin/sh", "-c", "timeout 10s ./bin/minifi.sh run && sleep 100"]
- context.minifi_container.flow_definition.add_processor(
+ context.get_or_create_default_minifi_container().command = ["/bin/sh", "-c", "timeout 10s ./bin/minifi.sh run && sleep 100"]
+ context.get_or_create_default_minifi_container().flow_definition.add_processor(
Processor("LogOnDestructionProcessor", "LogOnDestructionProcessor"))
@@ -41,7 +41,7 @@ def step_impl(context: MinifiTestContext, processor_type: str, processor_name: s
property_value: str):
processor = Processor(processor_type, processor_name)
processor.add_property(property_name, property_value)
- context.minifi_container.flow_definition.add_processor(processor)
+ context.get_or_create_default_minifi_container().flow_definition.add_processor(processor)
@step('a {processor_type} processor with the "{property_name}" property set to "{property_value}"')
@@ -50,75 +50,102 @@ def step_impl(context: MinifiTestContext, processor_type: str, property_name: st
f'Given a {processor_type} processor with the name "{processor_type}" and the "{property_name}" property set to "{property_value}"')
+@step('a {processor_type} processor with the "{property_name}" property set to "{property_value}" in the "{minifi_container_name}" flow')
+def step_impl(context: MinifiTestContext, processor_type: str, property_name: str, property_value: str, minifi_container_name: str):
+ processor = Processor(processor_type, processor_type)
+ processor.add_property(property_name, property_value)
+ context.get_or_create_minifi_container(minifi_container_name).flow_definition.add_processor(processor)
+
+
@given('a {processor_type} processor with the name "{processor_name}"')
def step_impl(context: MinifiTestContext, processor_type: str, processor_name: str):
processor = Processor(processor_type, processor_name)
- context.minifi_container.flow_definition.add_processor(processor)
+ context.get_or_create_default_minifi_container().flow_definition.add_processor(processor)
+
+
+@given("a {processor_type} processor in the \"{minifi_container_name}\" flow")
+def step_impl(context: MinifiTestContext, processor_type: str, minifi_container_name: str):
+ processor = Processor(processor_type, processor_type)
+ context.get_or_create_minifi_container(minifi_container_name).flow_definition.add_processor(processor)
@given("a {processor_type} processor")
def step_impl(context: MinifiTestContext, processor_type: str):
- processor = Processor(processor_type, processor_type)
- context.minifi_container.flow_definition.add_processor(processor)
+ context.execute_steps(f'given a {processor_type} processor in the "{DEFAULT_MINIFI_CONTAINER_NAME}" flow')
@step('the "{property_name}" property of the {processor_name} processor is set to "{property_value}"')
def step_impl(context: MinifiTestContext, property_name: str, processor_name: str, property_value: str):
- processor = context.minifi_container.flow_definition.get_processor(processor_name)
+ processor = context.get_or_create_default_minifi_container().flow_definition.get_processor(processor_name)
processor.add_property(property_name, property_value)
@step('a Funnel with the name "{funnel_name}" is set up')
def step_impl(context: MinifiTestContext, funnel_name: str):
- context.minifi_container.flow_definition.add_funnel(Funnel(funnel_name))
+ context.get_or_create_default_minifi_container().flow_definition.add_funnel(Funnel(funnel_name))
+
+
+@step('in the "{minifi_container_name}" flow the "{relationship_name}" relationship of the {source} processor is connected to the {target}')
+def step_impl(context: MinifiTestContext, relationship_name: str, source: str, target: str, minifi_container_name: str):
+ connection = Connection(source_name=source, source_relationship=relationship_name, target_name=target)
+ context.get_or_create_minifi_container(minifi_container_name).flow_definition.add_connection(connection)
@step('the "{relationship_name}" relationship of the {source} processor is connected to the {target}')
def step_impl(context: MinifiTestContext, relationship_name: str, source: str, target: str):
- connection = Connection(source_name=source, source_relationship=relationship_name, target_name=target)
- context.minifi_container.flow_definition.add_connection(connection)
+ context.execute_steps(f'given in the "{DEFAULT_MINIFI_CONTAINER_NAME}" flow the "{relationship_name}" relationship of the {source} processor is connected to the {target}')
@step('the Funnel with the name "{funnel_name}" is connected to the {target}')
def step_impl(context: MinifiTestContext, funnel_name: str, target: str):
connection = Connection(source_name=funnel_name, source_relationship="success", target_name=target)
- context.minifi_container.flow_definition.add_connection(connection)
+ context.get_or_create_default_minifi_container().flow_definition.add_connection(connection)
+
+
+@step("{processor_name}'s {relationship} relationship is auto-terminated in the \"{minifi_container_name}\" flow")
+def step_impl(context: MinifiTestContext, processor_name: str, relationship: str, minifi_container_name: str):
+ context.get_or_create_minifi_container(minifi_container_name).flow_definition.get_processor(processor_name).auto_terminated_relationships.append(
+ relationship)
@step("{processor_name}'s {relationship} relationship is auto-terminated")
def step_impl(context: MinifiTestContext, processor_name: str, relationship: str):
- context.minifi_container.flow_definition.get_processor(processor_name).auto_terminated_relationships.append(
- relationship)
+ context.execute_steps(f'given {processor_name}\'s {relationship} relationship is auto-terminated in the "{DEFAULT_MINIFI_CONTAINER_NAME}" flow')
@given("a transient MiNiFi flow is set up")
def step_impl(context: MinifiTestContext):
- context.minifi_container.command = ["/bin/sh", "-c", "timeout 10s ./bin/minifi.sh run && sleep 100"]
+ context.get_or_create_default_minifi_container().command = ["/bin/sh", "-c", "timeout 10s ./bin/minifi.sh run && sleep 100"]
@step('the scheduling period of the {processor_name} processor is set to "{duration_str}"')
def step_impl(context: MinifiTestContext, processor_name: str, duration_str: str):
- context.minifi_container.flow_definition.get_processor(processor_name).scheduling_period = duration_str
+ context.get_or_create_default_minifi_container().flow_definition.get_processor(processor_name).scheduling_period = duration_str
@given("parameter context name is set to '{context_name}'")
def step_impl(context: MinifiTestContext, context_name: str):
- context.minifi_container.flow_definition.parameter_contexts.append(ParameterContext(context_name))
+ context.get_or_create_default_minifi_container().flow_definition.parameter_contexts.append(ParameterContext(context_name))
@step(
"a non-sensitive parameter in the flow config called '{parameter_name}' with the value '{parameter_value}' in the parameter context '{context_name}'")
def step_impl(context: MinifiTestContext, parameter_name: str, parameter_value: str, context_name: str):
- parameter_context = context.minifi_container.flow_definition.get_parameter_context(context_name)
+ parameter_context = context.get_or_create_default_minifi_container().flow_definition.get_parameter_context(context_name)
parameter_context.parameters.append(Parameter(parameter_name, parameter_value, False))
-@step('a directory at "{directory}" has a file with the content "{content}"')
-def step_impl(context: MinifiTestContext, directory: str, content: str):
+@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.minifi_container.dirs.append(new_dir)
+ context.get_or_create_minifi_container(flow_name).dirs.append(new_dir)
+
+
+@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}"')
@@ -126,19 +153,26 @@ def step_impl(context: MinifiTestContext, directory: str, file_name: str, conten
new_content = content.replace("\\n", "\n")
new_dir = Directory(directory)
new_dir.files[file_name] = new_content
- context.minifi_container.dirs.append(new_dir)
+ 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:
+ processor = context.get_or_create_minifi_container(minifi_container_name).flow_definition.get_processor(row["processor name"])
+ processor.add_property(row["property name"], row["property value"])
@given("these processor properties are set")
def step_impl(context: MinifiTestContext):
for row in context.table:
- processor = context.minifi_container.flow_definition.get_processor(row["processor name"])
+ processor = context.get_or_create_default_minifi_container().flow_definition.get_processor(row["processor name"])
processor.add_property(row["property name"], row["property value"])
@step("the http proxy server is set up")
def step_impl(context):
- context.containers.append(HttpProxy(context))
+ context.containers["http-proxy"] = HttpProxy(context)
@step("the processors are connected up as described here")
@@ -148,23 +182,28 @@ def step_impl(context: MinifiTestContext):
dest_proc_name = row["destination name"]
relationship = row["relationship name"]
if dest_proc_name == "auto-terminated":
- context.minifi_container.flow_definition.get_processor(
+ context.get_or_create_default_minifi_container().flow_definition.get_processor(
source_proc_name).auto_terminated_relationships.append(relationship)
else:
connection = Connection(source_name=row["source name"], source_relationship=relationship,
target_name=row["destination name"])
- context.minifi_container.flow_definition.add_connection(connection)
+ context.get_or_create_default_minifi_container().flow_definition.add_connection(connection)
+
+
+@step("{processor_name} is EVENT_DRIVEN in the \"{minifi_container_name}\" flow")
+def step_impl(context: MinifiTestContext, processor_name: str, minifi_container_name: str):
+ processor = context.get_or_create_minifi_container(minifi_container_name).flow_definition.get_processor(processor_name)
+ processor.scheduling_strategy = "EVENT_DRIVEN"
@step("{processor_name} is EVENT_DRIVEN")
def step_impl(context: MinifiTestContext, processor_name: str):
- processor = context.minifi_container.flow_definition.get_processor(processor_name)
- processor.scheduling_strategy = "EVENT_DRIVEN"
+ context.execute_steps(f'given {processor_name} is EVENT_DRIVEN in the "{DEFAULT_MINIFI_CONTAINER_NAME}" flow')
@step("{processor_name} is TIMER_DRIVEN with {scheduling_period} scheduling period")
def step_impl(context: MinifiTestContext, processor_name: str, scheduling_period: int):
- processor = context.minifi_container.flow_definition.get_processor(processor_name)
+ processor = context.get_or_create_default_minifi_container().flow_definition.get_processor(processor_name)
processor.scheduling_strategy = "TIMER_DRIVEN"
processor.scheduling_period = scheduling_period
@@ -173,11 +212,11 @@ def step_impl(context: MinifiTestContext, processor_name: str, scheduling_period
@given("an {service_name} controller service is set up")
def step_impl(context: MinifiTestContext, service_name: str):
controller_service = ControllerService(class_name=service_name, service_name=service_name)
- context.minifi_container.flow_definition.controller_services.append(controller_service)
+ context.get_or_create_default_minifi_container().flow_definition.controller_services.append(controller_service)
@given('a {service_name} controller service is set up and the "{property_name}" property set to "{property_value}"')
def step_impl(context: MinifiTestContext, service_name: str, property_name: str, property_value: str):
controller_service = ControllerService(class_name=service_name, service_name=service_name)
controller_service.add_property(property_name, property_value)
- context.minifi_container.flow_definition.controller_services.append(controller_service)
+ context.get_or_create_default_minifi_container().flow_definition.controller_services.append(controller_service)
diff --git a/docker/RunBehaveTests.sh b/docker/RunBehaveTests.sh
index 4bac967f0..89d59f076 100755
--- a/docker/RunBehaveTests.sh
+++ b/docker/RunBehaveTests.sh
@@ -198,4 +198,5 @@ exec \
"${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/llamacpp/tests/features" \
+ "${docker_dir}/../extensions/opc/tests/features"
diff --git a/docker/test/integration/cluster/ContainerStore.py b/docker/test/integration/cluster/ContainerStore.py
index 9b5cba6b3..a78b0712c 100644
--- a/docker/test/integration/cluster/ContainerStore.py
+++ b/docker/test/integration/cluster/ContainerStore.py
@@ -26,7 +26,6 @@ from .containers.FakeGcsServerContainer import FakeGcsServerContainer
from .containers.HttpProxyContainer import HttpProxyContainer
from .containers.PostgreSQLServerContainer import PostgreSQLServerContainer
from .containers.MqttBrokerContainer import MqttBrokerContainer
-from .containers.OPCUAServerContainer import OPCUAServerContainer
from .containers.SplunkContainer import SplunkContainer
from .containers.ElasticsearchContainer import ElasticsearchContainer
from .containers.OpensearchContainer import OpensearchContainer
@@ -184,14 +183,6 @@ class ContainerStore:
network=self.network,
image_store=self.image_store,
command=command))
- elif engine == 'opcua-server':
- return self.containers.setdefault(container_name,
- OPCUAServerContainer(feature_context=feature_context,
- name=container_name,
- vols=self.vols,
- network=self.network,
- image_store=self.image_store,
- command=command))
elif engine == 'splunk':
return self.containers.setdefault(container_name,
SplunkContainer(feature_context=feature_context,
diff --git a/docker/test/integration/cluster/DockerTestDirectoryBindings.py b/docker/test/integration/cluster/DockerTestDirectoryBindings.py
index 25add90ae..9834bc524 100644
--- a/docker/test/integration/cluster/DockerTestDirectoryBindings.py
+++ b/docker/test/integration/cluster/DockerTestDirectoryBindings.py
@@ -55,7 +55,6 @@ class DockerTestDirectoryBindings:
# Add resources
test_dir = os.environ['TEST_DIRECTORY'] # Based on DockerVerify.sh
shutil.copytree(test_dir + "/resources/python", self.data_directories[self.feature_id]["resources_dir"] + "/python")
- shutil.copytree(test_dir + "/resources/opcua", self.data_directories[self.feature_id]["resources_dir"] + "/opcua")
shutil.copytree(test_dir + "/resources/lua", self.data_directories[self.feature_id]["resources_dir"] + "/lua")
shutil.copytree(test_dir + "/resources/minifi", self.data_directories[self.feature_id]["minifi_config_dir"], dirs_exist_ok=True)
shutil.copytree(test_dir + "/resources/minifi-controller", self.data_directories[self.feature_id]["resources_dir"] + "/minifi-controller")
diff --git a/docker/test/integration/features/http.feature b/docker/test/integration/features/http.feature
index 0cd01fbbb..19a9d3745 100644
--- a/docker/test/integration/features/http.feature
+++ b/docker/test/integration/features/http.feature
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-@CORE
+@ENABLE_CIVET
Feature: Sending data using InvokeHTTP to a receiver using ListenHTTP
In order to send and receive data via HTTP
As a user of MiNiFi
diff --git a/docker/test/integration/features/https.feature b/docker/test/integration/features/https.feature
index f4ff9d246..863cc782e 100644
--- a/docker/test/integration/features/https.feature
+++ b/docker/test/integration/features/https.feature
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-@CORE
+@ENABLE_CIVET
Feature: Transfer data from and to MiNiFi using HTTPS
Background:
diff --git a/docker/test/integration/features/steps/steps.py b/docker/test/integration/features/steps/steps.py
index 590fa06d0..87285e409 100644
--- a/docker/test/integration/features/steps/steps.py
+++ b/docker/test/integration/features/steps/steps.py
@@ -680,17 +680,6 @@ def step_impl(context):
context.test.acquire_container(context=context, name="postgresql-server", engine="postgresql-server")
-# OPC UA
-@given("an OPC UA server is set up")
-def step_impl(context):
- context.test.acquire_container(context=context, name="opcua-server", engine="opcua-server")
-
-
-@given("an OPC UA server is set up with access control")
-def step_impl(context):
- context.test.acquire_container(context=context, name="opcua-server", engine="opcua-server", command=["/opt/open62541/examples/access_control_server"])
-
-
@when("the MiNiFi instance starts up")
@when("both instances start up")
@when("all instances start up")
@@ -917,7 +906,7 @@ def step_impl(context, blob_and_snapshot_count, timeout_seconds):
# SQL
@then("the query \"{query}\" returns {number_of_rows:d} rows in less than {timeout_seconds:d} seconds on the PostgreSQL server")
-def step_impl(context, query, number_of_rows, timeout_seconds):
+def step_impl(context, query: str, number_of_rows: int, timeout_seconds: int):
context.test.check_query_results(context.test.get_container_name_with_postfix("postgresql-server"), query, number_of_rows, timeout_seconds)
@@ -943,11 +932,6 @@ def step_impl(context, regex, duration):
context.test.check_minifi_log_matches_regex(regex, humanfriendly.parse_timespan(duration))
-@then("the OPC UA server logs contain the following message: \"{log_message}\" in less than {duration}")
-def step_impl(context, log_message, duration):
- context.test.check_container_log_contents("opcua-server", log_message, humanfriendly.parse_timespan(duration))
-
-
# MQTT
@then("the MQTT broker has a log line matching \"{log_pattern}\"")
def step_impl(context, log_pattern):
diff --git a/extensions/aws/tests/features/steps/steps.py b/extensions/aws/tests/features/steps/steps.py
index e1d6c4cd7..6f8d1d757 100644
--- a/extensions/aws/tests/features/steps/steps.py
+++ b/extensions/aws/tests/features/steps/steps.py
@@ -46,32 +46,32 @@ def step_impl(context: MinifiTestContext, processor_name: str):
processor.add_property('Proxy Username', '')
processor.add_property('Proxy Password', '')
- context.minifi_container.flow_definition.add_processor(processor)
+ 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):
- context.containers.append(S3ServerContainer(context))
+ context.containers["s3-server"] = S3ServerContainer(context)
@step('the object on the s3 server is "{object_data}"')
def step_impl(context: MinifiTestContext, object_data: str):
- s3_server_container = context.containers[0]
+ s3_server_container = context.containers["s3-server"]
assert isinstance(s3_server_container, S3ServerContainer)
assert s3_server_container.check_s3_server_object_data(object_data)
@step('the object content type on the s3 server is "{content_type}" and the object metadata matches use metadata')
def step_impl(context: MinifiTestContext, content_type: str):
- s3_server_container = context.containers[0]
+ s3_server_container = context.containers["s3-server"]
assert isinstance(s3_server_container, S3ServerContainer)
assert s3_server_container.check_s3_server_object_metadata(content_type)
@step("the object bucket on the s3 server is empty in less than 10 seconds")
def step_impl(context):
- s3_server_container = context.containers[0]
+ s3_server_container = context.containers["s3-server"]
assert isinstance(s3_server_container, S3ServerContainer)
assert wait_for_condition(
condition=lambda: s3_server_container.is_s3_bucket_empty(),
@@ -80,7 +80,7 @@ def step_impl(context):
@step("the object on the s3 server is present and matches the original hash")
def step_impl(context):
- s3_server_container = context.containers[0]
+ s3_server_container = context.containers["s3-server"]
assert isinstance(s3_server_container, S3ServerContainer)
assert s3_server_container.check_s3_server_object_hash(context.original_hash)
@@ -98,5 +98,5 @@ def step_impl(context):
content = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(size))
new_dir = Directory("/tmp/input")
new_dir.files["input.txt"] = content
- context.minifi_container.dirs.append(new_dir)
+ context.get_or_create_default_minifi_container().dirs.append(new_dir)
context.original_hash = computeMD5hash(content)
diff --git a/extensions/azure/tests/features/steps/steps.py b/extensions/azure/tests/features/steps/steps.py
index 38721f99b..3331d7e71 100644
--- a/extensions/azure/tests/features/steps/steps.py
+++ b/extensions/azure/tests/features/steps/steps.py
@@ -37,41 +37,39 @@ def step_impl(context: MinifiTestContext, processor_name: str):
f'DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint={hostname}:10000/devstoreaccount1;QueueEndpoint={hostname}:10001/devstoreaccount1;')
processor.add_property('Blob', 'test-blob')
processor.add_property('Create Container', 'true')
- context.minifi_container.flow_definition.add_processor(processor)
+ context.get_or_create_default_minifi_container().flow_definition.add_processor(processor)
@step("an Azure storage server is set up")
def step_impl(context):
- context.containers.append(AzureServerContainer(context))
- azure_server_container = context.containers[0]
- assert isinstance(azure_server_container, AzureServerContainer)
- assert azure_server_container.deploy()
+ context.containers["azure-storage-server"] = AzureServerContainer(context)
+ assert context.containers["azure-storage-server"].deploy()
@then('the object on the Azure storage server is "{object_data}"')
def step_impl(context: MinifiTestContext, object_data: str):
- azure_server_container = context.containers[0]
+ azure_server_container = context.containers["azure-storage-server"]
assert isinstance(azure_server_container, AzureServerContainer)
assert azure_server_container.check_azure_storage_server_data(object_data)
@step('test blob "{blob_name}" with the content "{data}" is created on Azure blob storage')
def step_impl(context: MinifiTestContext, blob_name: str, data: str):
- azure_server_container = context.containers[0]
+ azure_server_container = context.containers["azure-storage-server"]
assert isinstance(azure_server_container, AzureServerContainer)
assert azure_server_container.add_test_blob(blob_name, content=data)
@step('test blob "{blob_name}" is created on Azure blob storage')
def step_impl(context: MinifiTestContext, blob_name: str):
- azure_server_container = context.containers[0]
+ azure_server_container = context.containers["azure-storage-server"]
assert isinstance(azure_server_container, AzureServerContainer)
assert azure_server_container.add_test_blob(blob_name)
@step('test blob "{blob_name}" is created on Azure blob storage with a snapshot')
def step_impl(context: MinifiTestContext, blob_name: str):
- azure_server_container = context.containers[0]
+ azure_server_container = context.containers["azure-storage-server"]
assert isinstance(azure_server_container, AzureServerContainer)
assert azure_server_container.add_test_blob(blob_name, with_snapshot=True)
@@ -79,20 +77,22 @@ def step_impl(context: MinifiTestContext, blob_name: str):
@then("the Azure blob storage becomes empty in {timeout_str}")
def step_impl(context: MinifiTestContext, timeout_str: str):
timeout_in_seconds = humanfriendly.parse_timespan(timeout_str)
- azure_server_container = context.containers[0]
+ azure_server_container = context.containers["azure-storage-server"]
assert isinstance(azure_server_container, AzureServerContainer)
- assert wait_for_condition(condition=lambda: azure_server_container.check_azure_blob_storage_is_empty(),
- timeout_seconds=timeout_in_seconds,
- bail_condition=lambda: context.minifi_container.exited,
- context=context)
+ assert wait_for_condition(
+ condition=lambda: azure_server_container.check_azure_blob_storage_is_empty(),
+ timeout_seconds=timeout_in_seconds,
+ bail_condition=lambda: azure_server_container.exited,
+ context=context)
@then("the blob and snapshot count becomes 1 in {timeout_str}")
def step_impl(context: MinifiTestContext, timeout_str: str):
timeout_in_seconds = humanfriendly.parse_timespan(timeout_str)
- azure_server_container = context.containers[0]
+ azure_server_container = context.containers["azure-storage-server"]
assert isinstance(azure_server_container, AzureServerContainer)
- assert wait_for_condition(condition=lambda: azure_server_container.check_azure_blob_and_snapshot_count(1),
- timeout_seconds=timeout_in_seconds,
- bail_condition=lambda: context.minifi_container.exited,
- context=context)
+ assert wait_for_condition(
+ condition=lambda: azure_server_container.check_azure_blob_and_snapshot_count(1),
+ timeout_seconds=timeout_in_seconds,
+ bail_condition=lambda: azure_server_container.exited,
+ context=context)
diff --git a/extensions/opc/tests/features/environment.py b/extensions/opc/tests/features/environment.py
new file mode 100644
index 000000000..a02cce4c3
--- /dev/null
+++ b/extensions/opc/tests/features/environment.py
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+from minifi_test_framework.core.hooks import common_before_scenario
+from minifi_test_framework.core.hooks import common_after_scenario
+
+
+def before_scenario(context, scenario):
+ common_before_scenario(context, scenario)
+ context.resource_dir = os.path.join(os.path.dirname(__file__), 'resources')
+
+
+def after_scenario(context, scenario):
+ common_after_scenario(context, scenario)
diff --git a/docker/test/integration/features/opcua.feature b/extensions/opc/tests/features/opcua.feature
similarity index 69%
rename from docker/test/integration/features/opcua.feature
rename to extensions/opc/tests/features/opcua.feature
index 8f561f356..064e32d32 100644
--- a/docker/test/integration/features/opcua.feature
+++ b/extensions/opc/tests/features/opcua.feature
@@ -19,16 +19,16 @@ Feature: Putting and fetching data to OPC UA server
As a user of MiNiFi
I need to have PutOPCProcessor and FetchOPCProcessor
- Background:
- Given the content of "/tmp/output" is monitored
-
Scenario Outline: Create and fetch data from an OPC UA node
Given a GetFile processor with the "Input Directory" property set to "/tmp/input" in the "create-opc-ua-node" flow
- And a file with the content "<Value>" is present in "/tmp/input"
+ And a directory at "/tmp/input" has a file with the content "<Value>" in the "create-opc-ua-node" flow
And a PutOPCProcessor processor in the "create-opc-ua-node" flow
+ And PutOPCProcessor is EVENT_DRIVEN in the "create-opc-ua-node" flow
And a FetchOPCProcessor processor in the "fetch-opc-ua-node" flow
And a PutFile processor with the "Directory" property set to "/tmp/output" in the "fetch-opc-ua-node" flow
- And these processor properties are set:
+ And PutFile's success relationship is auto-terminated in the "fetch-opc-ua-node" flow
+ And PutFile is EVENT_DRIVEN in the "fetch-opc-ua-node" flow
+ And these processor properties are set in the "create-opc-ua-node" flow
| processor name | property name | property value |
| PutOPCProcessor | Parent node ID | 85 |
| PutOPCProcessor | Parent node ID type | Int |
@@ -36,21 +36,23 @@ Feature: Putting and fetching data to OPC UA server
| PutOPCProcessor | Target node ID type | Int |
| PutOPCProcessor | Target node namespace index | 1 |
| PutOPCProcessor | Value type | <Value Type> |
- | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| PutOPCProcessor | Target node browse name | testnodename |
+ And these processor properties are set in the "fetch-opc-ua-node" flow
+ | processor name | property name | property value |
| FetchOPCProcessor | Node ID | 9999 |
| FetchOPCProcessor | Node ID type | Int |
| FetchOPCProcessor | Namespace index | 1 |
- | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| FetchOPCProcessor | Max depth | 1 |
- And the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
- And the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
+ And in the "create-opc-ua-node" flow the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
+ And in the "fetch-opc-ua-node" flow the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
And an OPC UA server is set up
When all instances start up
- Then at least one flowfile with the content "<Value>" is placed in the monitored directory in less than 60 seconds
+ Then in the "fetch-opc-ua-node" container at least one file with the content "<Value>" is placed in the "/tmp/output" directory in less than 60 seconds
Examples: Topic names and formats to test
| Value Type | Value |
@@ -61,11 +63,14 @@ Feature: Putting and fetching data to OPC UA server
Scenario Outline: Update and fetch data from an OPC UA node
Given a GetFile processor with the "Input Directory" property set to "/tmp/input" in the "update-opc-ua-node" flow
- And a file with the content "<Value>" is present in "/tmp/input"
+ And a directory at "/tmp/input" has a file with the content "<Value>" in the "update-opc-ua-node" flow
And a PutOPCProcessor processor in the "update-opc-ua-node" flow
+ And PutOPCProcessor is EVENT_DRIVEN in the "update-opc-ua-node" flow
And a FetchOPCProcessor processor in the "fetch-opc-ua-node" flow
And a PutFile processor with the "Directory" property set to "/tmp/output" in the "fetch-opc-ua-node" flow
- And these processor properties are set:
+ And PutFile's success relationship is auto-terminated in the "fetch-opc-ua-node" flow
+ And PutFile is EVENT_DRIVEN in the "fetch-opc-ua-node" flow
+ And these processor properties are set in the "update-opc-ua-node" flow
| processor name | property name | property value |
| PutOPCProcessor | Parent node ID | 85 |
| PutOPCProcessor | Parent node ID type | Int |
@@ -73,21 +78,23 @@ Feature: Putting and fetching data to OPC UA server
| PutOPCProcessor | Target node ID type | <Node ID Type> |
| PutOPCProcessor | Target node namespace index | 1 |
| PutOPCProcessor | Value type | <Value Type> |
- | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| PutOPCProcessor | Target node browse name | testnodename |
+ And these processor properties are set in the "fetch-opc-ua-node" flow
+ | processor name | property name | property value |
| FetchOPCProcessor | Node ID | <Node ID> |
| FetchOPCProcessor | Node ID type | <Node ID Type> |
| FetchOPCProcessor | Namespace index | 1 |
- | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| FetchOPCProcessor | Max depth | 1 |
- And the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
- And the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
+ And in the "update-opc-ua-node" flow the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
+ And in the "fetch-opc-ua-node" flow the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
And an OPC UA server is set up
When all instances start up
- Then at least one flowfile with the content "<Value>" is placed in the monitored directory in less than 60 seconds
+ Then in the "fetch-opc-ua-node" container at least one file with the content "<Value>" is placed in the "/tmp/output" directory in less than 60 seconds
# Node ids starting from 51000 are pre-defined demo node ids in the test server application (server_ctt) of the open62541 docker image. There is one nodeid defined
# for each type supported by OPC UA. These demo nodes can be used for testing purposes. "the.answer" is also a pre-defined string id for the same testing purposes.
@@ -101,11 +108,18 @@ Feature: Putting and fetching data to OPC UA server
Scenario: Create and fetch data from an OPC UA node through secure connection
Given a GetFile processor with the "Input Directory" property set to "/tmp/input" in the "create-opc-ua-node" flow
- 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" in the "create-opc-ua-node" flow
And a PutOPCProcessor processor in the "create-opc-ua-node" flow
+ And PutOPCProcessor is EVENT_DRIVEN in the "create-opc-ua-node" flow
And a FetchOPCProcessor processor in the "fetch-opc-ua-node" flow
And a PutFile processor with the "Directory" property set to "/tmp/output" in the "fetch-opc-ua-node" flow
- And these processor properties are set:
+ And PutFile's success relationship is auto-terminated in the "fetch-opc-ua-node" flow
+ And PutFile is EVENT_DRIVEN in the "fetch-opc-ua-node" flow
+ And a host resource file "opcua_client_cert.der" is bound to the "/tmp/resources/opcua/opcua_client_cert.der" path in the MiNiFi container "create-opc-ua-node"
+ And a host resource file "opcua_client_key.der" is bound to the "/tmp/resources/opcua/opcua_client_key.der" path in the MiNiFi container "create-opc-ua-node"
+ And a host resource file "opcua_client_cert.der" is bound to the "/tmp/resources/opcua/opcua_client_cert.der" path in the MiNiFi container "fetch-opc-ua-node"
+ And a host resource file "opcua_client_key.der" is bound to the "/tmp/resources/opcua/opcua_client_key.der" path in the MiNiFi container "fetch-opc-ua-node"
+ And these processor properties are set in the "create-opc-ua-node" flow
| processor name | property name | property value |
| PutOPCProcessor | Parent node ID | 85 |
| PutOPCProcessor | Parent node ID type | Int |
@@ -113,38 +127,44 @@ Feature: Putting and fetching data to OPC UA server
| PutOPCProcessor | Target node ID type | Int |
| PutOPCProcessor | Target node namespace index | 1 |
| PutOPCProcessor | Value type | String |
- | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| PutOPCProcessor | Target node browse name | testnodename |
| PutOPCProcessor | Certificate path | /tmp/resources/opcua/opcua_client_cert.der |
| PutOPCProcessor | Key path | /tmp/resources/opcua/opcua_client_key.der |
| PutOPCProcessor | Trusted server certificate path | /tmp/resources/opcua/opcua_client_cert.der |
| PutOPCProcessor | Application URI | urn:open62541.server.application |
+ And these processor properties are set in the "fetch-opc-ua-node" flow
+ | processor name | property name | property value |
| FetchOPCProcessor | Node ID | 9999 |
| FetchOPCProcessor | Node ID type | Int |
| FetchOPCProcessor | Namespace index | 1 |
- | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| FetchOPCProcessor | Max depth | 1 |
| FetchOPCProcessor | Certificate path | /tmp/resources/opcua/opcua_client_cert.der |
| FetchOPCProcessor | Key path | /tmp/resources/opcua/opcua_client_key.der |
| FetchOPCProcessor | Trusted server certificate path | /tmp/resources/opcua/opcua_client_cert.der |
| FetchOPCProcessor | Application URI | urn:open62541.server.application |
- And the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
- And the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
+ And in the "create-opc-ua-node" flow the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
+ And in the "fetch-opc-ua-node" flow the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
And an OPC UA server is set up
When all instances start up
- Then at least one flowfile with the content "Test" is placed in the monitored directory in less than 60 seconds
+
+ Then in the "fetch-opc-ua-node" container at least one file with the content "Test" is placed in the "/tmp/output" directory in less than 60 seconds
And the OPC UA server logs contain the following message: "SecureChannel opened with SecurityPolicy http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep" in less than 5 seconds
Scenario: Create and fetch data from an OPC UA node through username and password authenticated connection
Given a GetFile processor with the "Input Directory" property set to "/tmp/input" in the "create-opc-ua-node" flow
- 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" in the "create-opc-ua-node" flow
And a PutOPCProcessor processor in the "create-opc-ua-node" flow
+ And PutOPCProcessor is EVENT_DRIVEN in the "create-opc-ua-node" flow
And a FetchOPCProcessor processor in the "fetch-opc-ua-node" flow
And a PutFile processor with the "Directory" property set to "/tmp/output" in the "fetch-opc-ua-node" flow
- And these processor properties are set:
+ And PutFile's success relationship is auto-terminated in the "fetch-opc-ua-node" flow
+ And PutFile is EVENT_DRIVEN in the "fetch-opc-ua-node" flow
+ And these processor properties are set in the "create-opc-ua-node" flow
| processor name | property name | property value |
| PutOPCProcessor | Parent node ID | 85 |
| PutOPCProcessor | Parent node ID type | Int |
@@ -152,22 +172,24 @@ Feature: Putting and fetching data to OPC UA server
| PutOPCProcessor | Target node ID type | Int |
| PutOPCProcessor | Target node namespace index | 1 |
| PutOPCProcessor | Value type | String |
- | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | PutOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| PutOPCProcessor | Target node browse name | testnodename |
| PutOPCProcessor | Username | peter |
| PutOPCProcessor | Password | peter123 |
+ And these processor properties are set in the "fetch-opc-ua-node" flow
+ | processor name | property name | property value |
| FetchOPCProcessor | Node ID | 9999 |
| FetchOPCProcessor | Node ID type | Int |
| FetchOPCProcessor | Namespace index | 1 |
- | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${feature_id}:4840/ |
+ | FetchOPCProcessor | OPC server endpoint | opc.tcp://opcua-server-${scenario_id}:4840/ |
| FetchOPCProcessor | Max depth | 1 |
| FetchOPCProcessor | Username | peter |
| FetchOPCProcessor | Password | peter123 |
- And the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
- And the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
+ And in the "create-opc-ua-node" flow the "success" relationship of the GetFile processor is connected to the PutOPCProcessor
+ And in the "fetch-opc-ua-node" flow the "success" relationship of the FetchOPCProcessor processor is connected to the PutFile
And an OPC UA server is set up with access control
When all instances start up
- Then at least one flowfile with the content "Test" is placed in the monitored directory in less than 60 seconds
+ Then in the "fetch-opc-ua-node" container at least one file with the content "Test" is placed in the "/tmp/output" directory in less than 60 seconds
diff --git a/docker/test/integration/resources/opcua/opcua_client_cert.der b/extensions/opc/tests/features/resources/opcua_client_cert.der
similarity index 100%
rename from docker/test/integration/resources/opcua/opcua_client_cert.der
rename to extensions/opc/tests/features/resources/opcua_client_cert.der
diff --git a/docker/test/integration/resources/opcua/opcua_client_key.der b/extensions/opc/tests/features/resources/opcua_client_key.der
similarity index 100%
rename from docker/test/integration/resources/opcua/opcua_client_key.der
rename to extensions/opc/tests/features/resources/opcua_client_key.der
diff --git a/docker/test/integration/cluster/containers/OPCUAServerContainer.py b/extensions/opc/tests/features/steps/opc_ua_server_container.py
similarity index 52%
rename from docker/test/integration/cluster/containers/OPCUAServerContainer.py
rename to extensions/opc/tests/features/steps/opc_ua_server_container.py
index fefb8759c..4973b9046 100644
--- a/docker/test/integration/cluster/containers/OPCUAServerContainer.py
+++ b/extensions/opc/tests/features/steps/opc_ua_server_container.py
@@ -13,27 +13,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
-import logging
-from .Container import Container
+from typing import List, Optional
+from minifi_test_framework.containers.container import Container
+from minifi_test_framework.core.helpers import wait_for_condition
+from minifi_test_framework.core.minifi_test_context import MinifiTestContext
class OPCUAServerContainer(Container):
- def __init__(self, feature_context, name, vols, network, image_store, command=None):
- super().__init__(feature_context, name, 'opcua-server', vols, network, image_store, command)
-
- def get_startup_finished_log_entry(self):
- return "New DiscoveryUrl added: opc.tcp://"
+ def __init__(self, test_context: MinifiTestContext, command: Optional[List[str]] = None):
+ super().__init__("lordgamez/open62541:1.4.10", f"opcua-server-{test_context.scenario_id}", test_context.network, command=command)
def deploy(self):
- if not self.set_deployed():
- return
-
- logging.info('Creating and running OPC UA server docker container...')
- self.client.containers.run(
- "lordgamez/open62541:1.4.10",
- detach=True,
- name=self.name,
- network=self.network.name,
- entrypoint=self.command)
- logging.info('Added container \'%s\'', self.name)
+ super().deploy()
+ finished_str = "New DiscoveryUrl added: opc.tcp://"
+ return wait_for_condition(
+ condition=lambda: finished_str in self.get_logs(),
+ timeout_seconds=15,
+ 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
new file mode 100644
index 000000000..f9db97c8a
--- /dev/null
+++ b/extensions/opc/tests/features/steps/steps.py
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import humanfriendly
+from behave import step, then
+
+from minifi_test_framework.steps import checking_steps # noqa: F401
+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 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
+
+
+@step("an OPC UA server is set up")
+def step_impl(context: MinifiTestContext):
+ context.containers["opcua-server"] = OPCUAServerContainer(context)
+
+
+@step("an OPC UA server is set up with access control")
+def step_impl(context: MinifiTestContext):
+ context.containers["opcua-server-access"] = OPCUAServerContainer(context, command=["/opt/open62541/examples/access_control_server"])
+
+
+@then("the OPC UA server logs contain the following message: \"{log_message}\" in less than {duration}")
+def step_impl(context, log_message, duration):
+ timeout_seconds = humanfriendly.parse_timespan(duration)
+ opcua_container = context.containers["opcua-server"]
+ assert isinstance(opcua_container, OPCUAServerContainer)
+ assert wait_for_condition(
+ condition=lambda: log_message in opcua_container.get_logs(),
+ timeout_seconds=timeout_seconds,
+ bail_condition=lambda: opcua_container.exited,
+ context=context)
diff --git a/extensions/sql/tests/features/steps/steps.py b/extensions/sql/tests/features/steps/steps.py
index 60a2059c3..db2f555e4 100644
--- a/extensions/sql/tests/features/steps/steps.py
+++ b/extensions/sql/tests/features/steps/steps.py
@@ -33,20 +33,20 @@ def step_impl(context: MinifiTestContext, processor_name: str, service_name: str
odb_service = ControllerService(class_name="ODBCService", service_name=service_name)
postgres_server_hostname = f"postgres-server-{context.scenario_id}"
odb_service.add_property("Connection String", f"Driver={{PostgreSQL ANSI}};Server={postgres_server_hostname};Port=5432;Database=postgres;Uid=postgres;Pwd=password;")
- context.minifi_container.flow_definition.controller_services.append(odb_service)
- processor = context.minifi_container.flow_definition.get_processor(processor_name)
+ context.get_or_create_default_minifi_container().flow_definition.controller_services.append(odb_service)
+ processor = context.get_or_create_default_minifi_container().flow_definition.get_processor(processor_name)
processor.add_property("DB Controller Service", "ODBCService")
@step("a PostgreSQL server is set up")
def step_impl(context):
- context.containers.append(PostgresContainer(context))
+ context.containers["postgres-server"] = PostgresContainer(context)
-@then('the query "{query}" returns {rows} rows in less than {timeout_str} on the PostgreSQL server')
-def step_impl(context, query: str, rows: str, timeout_str: str):
+@then('the query "{query}" returns {rows:d} rows in less than {timeout_str} on the PostgreSQL server')
+def step_impl(context, query: str, rows: int, timeout_str: str):
timeout_seconds = humanfriendly.parse_timespan(timeout_str)
- postgres_container = context.containers[0]
+ postgres_container = context.containers["postgres-server"]
assert isinstance(postgres_container, PostgresContainer)
assert wait_for_condition(
condition=lambda: postgres_container.check_query_results(query, int(rows)),
diff --git a/extensions/standard-processors/tests/features/steps/steps.py b/extensions/standard-processors/tests/features/steps/steps.py
index df76b292b..a53631e2e 100644
--- a/extensions/standard-processors/tests/features/steps/steps.py
+++ b/extensions/standard-processors/tests/features/steps/steps.py
@@ -27,9 +27,9 @@ from syslog_container import SyslogContainer
@step("a Syslog client with TCP protocol is setup to send logs to minifi")
def step_impl(context: MinifiTestContext):
- context.containers.append(SyslogContainer("tcp", context))
+ context.containers["syslog-tcp"] = SyslogContainer("tcp", context)
@step("a Syslog client with UDP protocol is setup to send logs to minifi")
def step_impl(context):
- context.containers.append(SyslogContainer("udp", context))
+ context.containers["syslog-udp"] = SyslogContainer("udp", context)
diff --git a/extensions/standard-processors/tests/features/steps/syslog_container.py b/extensions/standard-processors/tests/features/steps/syslog_container.py
index 15a3c9551..f2da956f5 100644
--- a/extensions/standard-processors/tests/features/steps/syslog_container.py
+++ b/extensions/standard-processors/tests/features/steps/syslog_container.py
@@ -21,4 +21,4 @@ from minifi_test_framework.containers.container import Container
class SyslogContainer(Container):
def __init__(self, protocol, context):
super(SyslogContainer, self).__init__("ubuntu:24.04", f"syslog-{protocol}-{context.scenario_id}", context.network)
- self.command = f'/bin/bash -c "echo Syslog {protocol} client started; while true; do logger --{protocol} -n minifi-{context.scenario_id} -P 514 sample_log; sleep 1; done"'
+ self.command = f'/bin/bash -c "echo Syslog {protocol} client started; while true; do logger --{protocol} -n minifi-primary-{context.scenario_id} -P 514 sample_log; sleep 1; done"'