This is an automated email from the ASF dual-hosted git repository. lordgamez pushed a commit to branch MINIFICPP-2684 in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit 31b7dccc508d4baae591354af7c83749a981d4f9 Author: Gabor Gyimesi <[email protected]> AuthorDate: Thu Nov 27 11:35:25 2025 +0100 MINIFICPP-2684 Move MiNiFi controller tests to modular docker tests --- .../containers/minifi_container.py | 90 +++++++++++++++- .../resources/minifi-controller/config.yml | 0 docker/test/integration/cluster/ContainerStore.py | 3 - .../test/integration/cluster/DockerTestCluster.py | 84 +-------------- .../cluster/MinifiControllerExecutor.py | 78 -------------- .../cluster/containers/MinifiContainer.py | 7 -- .../features/MiNiFi_integration_test_driver.py | 36 ------- docker/test/integration/features/steps/steps.py | 116 --------------------- .../tests}/features/minifi_controller.feature | 5 +- .../features/steps/minifi_controller_steps.py | 91 ++++++++++++++++ .../tests/features/steps/steps.py | 8 +- 11 files changed, 186 insertions(+), 332 deletions(-) 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 8db562e04..6787ccaa5 100644 --- a/behave_framework/src/minifi_test_framework/containers/minifi_container.py +++ b/behave_framework/src/minifi_test_framework/containers/minifi_container.py @@ -16,12 +16,16 @@ # import logging +import os +from pathlib import Path from OpenSSL import crypto from minifi_test_framework.core.minifi_test_context import MinifiTestContext from minifi_test_framework.containers.file import File +from minifi_test_framework.containers.host_file import HostFile from minifi_test_framework.minifi.minifi_flow_definition import MinifiFlowDefinition from minifi_test_framework.core.ssl_utils import make_cert_without_extended_usage, make_client_cert, make_server_cert +from minifi_test_framework.core.helpers import wait_for_condition, retry_check from .container import Container @@ -48,6 +52,10 @@ class MinifiContainer(Container): crypto.dump_certificate(type=crypto.FILETYPE_PEM, cert=minifi_server_cert) + crypto.dump_privatekey(type=crypto.FILETYPE_PEM, pkey=minifi_server_key))) self.is_fhs = 'MINIFI_INSTALLATION_TYPE=FHS' in str(self.client.images.get(test_context.minifi_container_image).history()) + if self.is_fhs: + self.minifi_controller_path = '/usr/bin/minifi-controller' + else: + self.minifi_controller_path = '/opt/minifi/minifi-current/bin/minifi-controller' self._fill_default_properties() self._fill_default_log_properties() @@ -67,7 +75,16 @@ class MinifiContainer(Container): self.files.append(File("/opt/minifi/minifi-current/conf/minifi-log.properties", self._get_log_properties_file_content())) - return super().deploy() + resource_dir = Path(__file__).resolve().parent / "resources" / "minifi-controller" + self.host_files.append(HostFile("/tmp/resources/minifi-controller/config.yml", os.path.join(resource_dir, "config.yml"))) + + super().deploy() + finished_str = "MiNiFi started" + return wait_for_condition( + condition=lambda: finished_str in self.get_logs(), + timeout_seconds=15, + bail_condition=lambda: self.exited, + context=None) def set_property(self, key: str, value: str): self.properties[key] = value @@ -112,3 +129,74 @@ class MinifiContainer(Container): memory_usage_in_bytes = int(output.strip()) * 1024 logging.info(f"MiNiFi memory usage: {memory_usage_in_bytes} bytes") return memory_usage_in_bytes + + def set_controller_socket_properties(self): + self.properties["controller.socket.enable"] = "true" + self.properties["controller.socket.host"] = "localhost" + self.properties["controller.socket.port"] = "9998" + self.properties["controller.socket.local.any.interface"] = "false" + + def update_flow_config_through_controller(self): + self.exec_run([self.minifi_controller_path, "--updateflow", "/tmp/resources/minifi-controller/config.yml"]) + + def updated_config_is_persisted(self) -> bool: + exit_code, output = self.exec_run(["cat", "/opt/minifi/minifi-current/conf/config.yml" if not self.is_fhs else "/etc/nifi-minifi-cpp/config.yml"]) + if exit_code != 0: + logging.error("Failed to read MiNiFi config file to check if updated config is persisted") + return False + return "2f2a3b47-f5ba-49f6-82b5-bc1c86b96f38" in output + + def stop_component_through_controller(self, component: str): + self.exec_run([self.minifi_controller_path, "--stop", component]) + + def start_component_through_controller(self, component: str): + self.exec_run([self.minifi_controller_path, "--start", component]) + + @retry_check(10, 1) + def is_component_running(self, component: str) -> bool: + (code, output) = self.exec_run([self.minifi_controller_path, "--list", "components"]) + return code == 0 and component + ", running: true" in output + + def get_connections(self): + (_, output) = self.exec_run([self.minifi_controller_path, "--list", "connections"]) + connections = [] + for line in output.split('\n'): + if not line.startswith('[') and not line.startswith('Connection Names'): + connections.append(line) + return connections + + @retry_check(10, 1) + def connection_found_through_controller(self, connection: str) -> bool: + return connection in self.get_connections() + + def get_full_connection_count(self) -> int: + (_, output) = self.exec_run([self.minifi_controller_path, "--getfull"]) + for line in output.split('\n'): + if "are full" in line: + return int(line.split(' ')[0]) + return -1 + + def get_connection_size(self, connection: str): + (_, output) = self.exec_run([self.minifi_controller_path, "--getsize", connection]) + for line in output.split('\n'): + if "Size/Max of " + connection in line: + size_and_max = line.split(connection)[1].split('/') + return (int(size_and_max[0].strip()), int(size_and_max[1].strip())) + return (-1, -1) + + def get_manifest(self) -> str: + (_, output) = self.exec_run([self.minifi_controller_path, "--manifest"]) + manifest = "" + for line in output.split('\n'): + if not line.startswith('['): + manifest += line + return manifest + + def create_debug_bundle(self) -> bool: + (code, _) = self.exec_run([self.minifi_controller_path, "--debug", "/tmp"]) + if code != 0: + logging.error("Minifi controller debug command failed with code: %d", code) + return False + + (code, _) = self.exec_run(["test", "-f", "/tmp/debug.tar.gz"]) + return code == 0 diff --git a/docker/test/integration/resources/minifi-controller/config.yml b/behave_framework/src/minifi_test_framework/containers/resources/minifi-controller/config.yml similarity index 100% rename from docker/test/integration/resources/minifi-controller/config.yml rename to behave_framework/src/minifi_test_framework/containers/resources/minifi-controller/config.yml diff --git a/docker/test/integration/cluster/ContainerStore.py b/docker/test/integration/cluster/ContainerStore.py index 6d87739bb..084bbc45d 100644 --- a/docker/test/integration/cluster/ContainerStore.py +++ b/docker/test/integration/cluster/ContainerStore.py @@ -273,9 +273,6 @@ class ContainerStore: def set_json_in_minifi(self): self.minifi_options.config_format = "json" - def set_controller_socket_properties_in_minifi(self): - self.minifi_options.enable_controller_socket = True - def enable_log_metrics_publisher_in_minifi(self): self.minifi_options.enable_log_metrics_publisher = True diff --git a/docker/test/integration/cluster/DockerTestCluster.py b/docker/test/integration/cluster/DockerTestCluster.py index 93801e83e..458e0bd88 100644 --- a/docker/test/integration/cluster/DockerTestCluster.py +++ b/docker/test/integration/cluster/DockerTestCluster.py @@ -15,22 +15,16 @@ import logging import time import re -import tarfile -import tempfile -import os -import gzip -import shutil from .LogSource import LogSource from .ContainerStore import ContainerStore from .DockerCommunicator import DockerCommunicator -from .MinifiControllerExecutor import MinifiControllerExecutor from .checkers.AzureChecker import AzureChecker from .checkers.PostgresChecker import PostgresChecker from .checkers.PrometheusChecker import PrometheusChecker from .checkers.ModbusChecker import ModbusChecker from .checkers.MqttHelper import MqttHelper -from utils import get_peak_memory_usage, get_minifi_pid, get_memory_usage, retry_check +from utils import get_peak_memory_usage, get_minifi_pid, get_memory_usage class DockerTestCluster: @@ -42,7 +36,6 @@ class DockerTestCluster: self.azure_checker = AzureChecker(self.container_communicator) self.postgres_checker = PostgresChecker(self.container_communicator) self.prometheus_checker = PrometheusChecker() - self.minifi_controller_executor = MinifiControllerExecutor(self.container_communicator) self.modbus_checker = ModbusChecker(self.container_communicator) self.mqtt_helper = MqttHelper() @@ -124,9 +117,6 @@ class DockerTestCluster: def set_json_in_minifi(self): self.container_store.set_json_in_minifi() - def set_controller_socket_properties_in_minifi(self): - self.container_store.set_controller_socket_properties_in_minifi() - def enable_log_metrics_publisher_in_minifi(self): self.container_store.enable_log_metrics_publisher_in_minifi() @@ -283,78 +273,6 @@ class DockerTestCluster: logging.warning(f"Memory usage ({current_memory_usage}) is more than the maximum asserted memory usage ({max_memory_usage})") return False - def update_flow_config_through_controller(self, container_name: str): - self.minifi_controller_executor.update_flow(container_name) - - @retry_check(10, 1) - def check_minifi_controller_updated_config_is_persisted(self, container_name: str) -> bool: - return self.minifi_controller_executor.updated_config_is_persisted(container_name) - - def stop_component_through_controller(self, component: str, container_name: str): - self.minifi_controller_executor.stop_component(component, container_name) - - def start_component_through_controller(self, component: str, container_name: str): - self.minifi_controller_executor.start_component(component, container_name) - - @retry_check(10, 1) - def check_component_not_running_through_controller(self, component: str, container_name: str) -> bool: - return not self.minifi_controller_executor.is_component_running(component, container_name) - - @retry_check(10, 1) - def check_component_running_through_controller(self, component: str, container_name: str) -> bool: - return self.minifi_controller_executor.is_component_running(component, container_name) - - @retry_check(10, 1) - def connection_found_through_controller(self, connection: str, container_name: str) -> bool: - return connection in self.minifi_controller_executor.get_connections(container_name) - - @retry_check(10, 1) - def check_connections_full_through_controller(self, connection_count: int, container_name: str) -> bool: - return self.minifi_controller_executor.get_full_connection_count(container_name) == connection_count - - @retry_check(10, 1) - def check_connection_size_through_controller(self, connection: str, size: int, max_size: int, container_name: str) -> bool: - return self.minifi_controller_executor.get_connection_size(connection, container_name) == (size, max_size) - - @retry_check(10, 1) - def manifest_can_be_retrieved_through_minifi_controller(self, container_name: str) -> bool: - manifest = self.minifi_controller_executor.get_manifest(container_name) - return '"agentManifest": {' in manifest and '"componentManifest": {' in manifest and '"agentType": "cpp"' in manifest - - @retry_check(10, 1) - def debug_bundle_can_be_retrieved_through_minifi_controller(self, container_name: str) -> bool: - with tempfile.TemporaryDirectory() as td: - result = self.minifi_controller_executor.get_debug_bundle(container_name, td) - if not result: - logging.error("Failed to get debug bundle") - return False - - with tarfile.open(os.path.join(td, "debug.tar.gz")) as file: - file.extractall(td) - - if not os.path.exists(os.path.join(td, "config.yml")): - logging.error("config.yml file was not found in debug bundle") - return False - - if not os.path.exists(os.path.join(td, "minifi.properties")): - logging.error("minifi.properties file was not found in debug bundle") - return False - - if not os.path.exists(os.path.join(td, "minifi.log.gz")): - logging.error("minifi.log.gz file was not found in debug bundle") - return False - - with gzip.open(os.path.join(td, "minifi.log.gz"), 'rb') as f_in: - with open(os.path.join(td, "minifi.log"), 'wb') as f_out: - shutil.copyfileobj(f_in, f_out) - - with open(os.path.join(td, "minifi.log")) as f: - if 'MiNiFi started' not in f.read(): - logging.error("'MiNiFi started' log entry was not found in minifi.log file") - return False - - return True - def set_value_on_plc_with_modbus(self, container_name, modbus_cmd): return self.modbus_checker.set_value_on_plc_with_modbus(container_name, modbus_cmd) diff --git a/docker/test/integration/cluster/MinifiControllerExecutor.py b/docker/test/integration/cluster/MinifiControllerExecutor.py deleted file mode 100644 index 880e43e74..000000000 --- a/docker/test/integration/cluster/MinifiControllerExecutor.py +++ /dev/null @@ -1,78 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import logging -from .DockerCommunicator import DockerCommunicator -from .containers.MinifiContainer import MinifiContainer - - -class MinifiControllerExecutor: - def __init__(self, container_communicator: DockerCommunicator): - self.container_communicator = container_communicator - - def update_flow(self, container_name: str): - self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--updateflow", "/tmp/resources/minifi-controller/config.yml"]) - - def updated_config_is_persisted(self, container_name: str) -> bool: - (code, output) = self.container_communicator.execute_command(container_name, ["cat", MinifiContainer.MINIFI_LOCATIONS.config_path]) - return code == 0 and "2f2a3b47-f5ba-49f6-82b5-bc1c86b96f38" in output - - def stop_component(self, component: str, container_name: str): - self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--stop", component]) - - def start_component(self, component: str, container_name: str): - self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--start", component]) - - def is_component_running(self, component: str, container_name: str) -> bool: - (code, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--list", "components"]) - return code == 0 and component + ", running: true" in output - - def get_connections(self, container_name: str): - (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--list", "connections"]) - connections = [] - for line in output.split('\n'): - if not line.startswith('[') and not line.startswith('Connection Names'): - connections.append(line) - return connections - - def get_full_connection_count(self, container_name: str) -> int: - (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--getfull"]) - for line in output.split('\n'): - if "are full" in line: - return int(line.split(' ')[0]) - return -1 - - def get_connection_size(self, connection: str, container_name: str): - (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--getsize", connection]) - for line in output.split('\n'): - if "Size/Max of " + connection in line: - size_and_max = line.split(connection)[1].split('/') - return (int(size_and_max[0].strip()), int(size_and_max[1].strip())) - return (-1, -1) - - def get_manifest(self, container_name: str) -> str: - (_, output) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--manifest"]) - manifest = "" - for line in output.split('\n'): - if not line.startswith('['): - manifest += line - return manifest - - def get_debug_bundle(self, container_name: str, dest: str) -> bool: - (code, _) = self.container_communicator.execute_command(container_name, [MinifiContainer.MINIFI_LOCATIONS.minifi_controller_path, "--debug", "/tmp"]) - if code != 0: - logging.error("Minifi controller debug command failed with code: %d", code) - return False - - return self.container_communicator.copy_file_from_container(container_name, "/tmp/debug.tar.gz", dest) diff --git a/docker/test/integration/cluster/containers/MinifiContainer.py b/docker/test/integration/cluster/containers/MinifiContainer.py index 387a3bd0d..f5185d1be 100644 --- a/docker/test/integration/cluster/containers/MinifiContainer.py +++ b/docker/test/integration/cluster/containers/MinifiContainer.py @@ -41,7 +41,6 @@ class MinifiOptions: self.config_format = "json" self.use_flow_config_from_url = False self.set_ssl_context_properties = False - self.enable_controller_socket = False self.enable_log_metrics_publisher = False self.enable_example_minifi_python_processors = False if "true" in os.environ['MINIFI_FIPS']: @@ -186,12 +185,6 @@ class MinifiContainer(FlowContainer): if self.options.use_flow_config_from_url: f.write(f"nifi.c2.flow.url=http://minifi-c2-server-{self.feature_context.id}:10090/c2/config?class=minifi-test-class\n") - if self.options.enable_controller_socket: - f.write("controller.socket.enable=true\n") - f.write("controller.socket.host=localhost\n") - f.write("controller.socket.port=9998\n") - f.write("controller.socket.local.any.interface=false\n") - if self.options.use_nifi_python_processors_with_virtualenv or self.options.remove_python_requirements_txt or self.options.use_nifi_python_processors_without_dependencies: f.write("nifi.python.virtualenv.directory={minifi_python_venv_parent}/venv\n".format(minifi_python_venv_parent=MinifiContainer.MINIFI_LOCATIONS.minifi_python_venv_parent)) elif self.options.use_nifi_python_processors_with_virtualenv_packages_installed: diff --git a/docker/test/integration/features/MiNiFi_integration_test_driver.py b/docker/test/integration/features/MiNiFi_integration_test_driver.py index d3dd8dd5c..73941ecda 100644 --- a/docker/test/integration/features/MiNiFi_integration_test_driver.py +++ b/docker/test/integration/features/MiNiFi_integration_test_driver.py @@ -374,42 +374,9 @@ class MiNiFi_integration_test: def set_json_in_minifi(self): self.cluster.set_json_in_minifi() - def set_controller_socket_properties_in_minifi(self): - self.cluster.set_controller_socket_properties_in_minifi() - def llama_model_is_downloaded_in_minifi(self): self.cluster.llama_model_is_downloaded_in_minifi() - def update_flow_config_through_controller(self, container_name: str): - self.cluster.update_flow_config_through_controller(container_name) - - def check_minifi_controller_updated_config_is_persisted(self, container_name: str): - assert self.cluster.check_minifi_controller_updated_config_is_persisted(container_name) or self.cluster.log_app_output() - - def stop_component_through_controller(self, component: str, container_name: str): - self.cluster.stop_component_through_controller(component, container_name) - - def start_component_through_controller(self, component: str, container_name: str): - self.cluster.start_component_through_controller(component, container_name) - - def check_component_not_running_through_controller(self, component: str, container_name: str): - assert self.cluster.check_component_not_running_through_controller(component, container_name) or self.cluster.log_app_output() - - def check_component_running_through_controller(self, component: str, container_name: str): - assert self.cluster.check_component_running_through_controller(component, container_name) or self.cluster.log_app_output() - - def connection_found_through_controller(self, connection: str, container_name: str): - assert self.cluster.connection_found_through_controller(connection, container_name) or self.cluster.log_app_output() - - def check_connections_full_through_controller(self, connection_count: int, container_name: str): - assert self.cluster.check_connections_full_through_controller(connection_count, container_name) or self.cluster.log_app_output() - - def check_connection_size_through_controller(self, connection: str, size: int, max_size: int, container_name: str): - assert self.cluster.check_connection_size_through_controller(connection, size, max_size, container_name) or self.cluster.log_app_output() - - def manifest_can_be_retrieved_through_minifi_controller(self, container_name: str): - assert self.cluster.manifest_can_be_retrieved_through_minifi_controller(container_name) or self.cluster.log_app_output() - def enable_log_metrics_publisher_in_minifi(self): self.cluster.enable_log_metrics_publisher_in_minifi() @@ -422,9 +389,6 @@ class MiNiFi_integration_test: def disable_openssl_fips_mode_in_minifi(self): self.cluster.disable_openssl_fips_mode_in_minifi() - def debug_bundle_can_be_retrieved_through_minifi_controller(self, container_name: str): - assert self.cluster.debug_bundle_can_be_retrieved_through_minifi_controller(container_name) or self.cluster.log_app_output() - def set_value_on_plc_with_modbus(self, container_name, modbus_cmd): assert self.cluster.set_value_on_plc_with_modbus(container_name, modbus_cmd) diff --git a/docker/test/integration/features/steps/steps.py b/docker/test/integration/features/steps/steps.py index 9757441dd..606d5d76d 100644 --- a/docker/test/integration/features/steps/steps.py +++ b/docker/test/integration/features/steps/steps.py @@ -896,122 +896,6 @@ def step_impl(context): context.test.set_json_in_minifi() -# MiNiFi controller -@given(u'controller socket properties are set up') -def step_impl(context): - context.test.set_controller_socket_properties_in_minifi() - - -@when(u'MiNiFi config is updated through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, minifi_container_name: str): - context.test.update_flow_config_through_controller(minifi_container_name) - - -@when(u'MiNiFi config is updated through MiNiFi controller') -def step_impl(context): - context.execute_steps(f"when MiNiFi config is updated through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'the updated config is persisted in the \"{minifi_container_name}\" flow') -def step_impl(context, minifi_container_name: str): - context.test.check_minifi_controller_updated_config_is_persisted(minifi_container_name) - - -@then(u'the updated config is persisted') -def step_impl(context): - context.execute_steps(f"then the updated config is persisted in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@when(u'the {component} component is stopped through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, minifi_container_name: str, component: str): - context.test.stop_component_through_controller(component, minifi_container_name) - - -@when(u'the {component} component is stopped through MiNiFi controller') -def step_impl(context, component: str): - context.execute_steps(f"when the {component} component is stopped through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@when(u'the {component} component is started through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, minifi_container_name: str, component: str): - context.test.start_component_through_controller(component, minifi_container_name) - - -@when(u'the {component} component is started through MiNiFi controller') -def step_impl(context, component: str): - context.execute_steps(f"when the {component} component is started through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'the {component} component is not running in the \"{minifi_container_name}\" flow') -def step_impl(context, component: str, minifi_container_name: str): - context.test.check_component_not_running_through_controller(component, minifi_container_name) - - -@then(u'the {component} component is not running') -def step_impl(context, component: str): - context.execute_steps(f"then the {component} component is not running in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'the {component} component is running in the \"{minifi_container_name}\" flow') -def step_impl(context, component: str, minifi_container_name: str): - context.test.check_component_running_through_controller(component, minifi_container_name) - - -@then(u'the {component} component is running') -def step_impl(context, component: str): - context.execute_steps(f"then the {component} component is running in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'connection \"{connection}\" can be seen through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, connection: str, minifi_container_name: str): - context.test.connection_found_through_controller(connection, minifi_container_name) - - -@then(u'connection \"{connection}\" can be seen through MiNiFi controller') -def step_impl(context, connection: str): - context.execute_steps(f"then connection \"{connection}\" can be seen through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'{connection_count:d} connections can be seen full through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, connection_count: int, minifi_container_name: str): - context.test.check_connections_full_through_controller(connection_count, minifi_container_name) - - -@then(u'{connection_count:d} connections can be seen full through MiNiFi controller') -def step_impl(context, connection_count: int): - context.execute_steps(f"then {connection_count:d} connections can be seen full through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'connection \"{connection}\" has {size:d} size and {max_size:d} max size through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, connection: str, size: int, max_size: int, minifi_container_name: str): - context.test.check_connection_size_through_controller(connection, size, max_size, minifi_container_name) - - -@then(u'connection \"{connection}\" has {size:d} size and {max_size:d} max size through MiNiFi controller') -def step_impl(context, connection: str, size: int, max_size: int): - context.execute_steps(f"then connection \"{connection}\" has {size:d} size and {max_size:d} max size through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'manifest can be retrieved through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, minifi_container_name: str): - context.test.manifest_can_be_retrieved_through_minifi_controller(minifi_container_name) - - -@then(u'manifest can be retrieved through MiNiFi controller') -def step_impl(context): - context.execute_steps(f"then manifest can be retrieved through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - -@then(u'debug bundle can be retrieved through MiNiFi controller in the \"{minifi_container_name}\" flow') -def step_impl(context, minifi_container_name: str): - context.test.debug_bundle_can_be_retrieved_through_minifi_controller(minifi_container_name) - - -@then(u'debug bundle can be retrieved through MiNiFi controller') -def step_impl(context): - context.execute_steps(f"then debug bundle can be retrieved through MiNiFi controller in the \"minifi-cpp-flow-{context.feature_id}\" flow") - - @given(u'a SSL context service is set up for the following processor: \"{processor_name}\"') def step_impl(context, processor_name: str): setUpSslContextServiceForProcessor(context, processor_name) diff --git a/docker/test/integration/features/minifi_controller.feature b/extensions/standard-processors/tests/features/minifi_controller.feature similarity index 95% rename from docker/test/integration/features/minifi_controller.feature rename to extensions/standard-processors/tests/features/minifi_controller.feature index c78f91ca4..0995c8f95 100644 --- a/docker/test/integration/features/minifi_controller.feature +++ b/extensions/standard-processors/tests/features/minifi_controller.feature @@ -17,16 +17,13 @@ Feature: MiNiFi Controller functionalities Test MiNiFi Controller functionalities - Background: - Given the content of "/tmp/output" is monitored - 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 controller socket properties are set up When all instances start up And MiNiFi config is updated through MiNiFi controller - Then a flowfile with the content "test" is placed in the monitored directory in less than 60 seconds + Then there is a single file with "test" content in the "/tmp/output" directory in less than 60 seconds And the updated config is persisted Scenario: A component can be stopped diff --git a/extensions/standard-processors/tests/features/steps/minifi_controller_steps.py b/extensions/standard-processors/tests/features/steps/minifi_controller_steps.py new file mode 100644 index 000000000..8cefd0762 --- /dev/null +++ b/extensions/standard-processors/tests/features/steps/minifi_controller_steps.py @@ -0,0 +1,91 @@ +# +# 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. +# + +from behave import given, when, then +from minifi_test_framework.core.helpers import retry_check +from minifi_test_framework.core.minifi_test_context import MinifiTestContext + + +@given(u'controller socket properties are set up') +def step_impl(context: MinifiTestContext): + context.get_or_create_default_minifi_container().set_controller_socket_properties() + + +@when(u'MiNiFi config is updated through MiNiFi controller') +def step_impl(context: MinifiTestContext): + context.get_or_create_default_minifi_container().update_flow_config_through_controller() + + +@then(u'the updated config is persisted') +def step_impl(context: MinifiTestContext): + assert context.get_or_create_default_minifi_container().updated_config_is_persisted() + + +@when(u'the {component} component is stopped through MiNiFi controller') +def step_impl(context: MinifiTestContext, component: str): + context.get_or_create_default_minifi_container().stop_component_through_controller(component) + + +@when(u'the {component} component is started through MiNiFi controller') +def step_impl(context: MinifiTestContext, component: str): + context.get_or_create_default_minifi_container().start_component_through_controller(component) + + +@then(u'the {component} component is not running') +def step_impl(context: MinifiTestContext, component: str): + assert not context.get_or_create_default_minifi_container().is_component_running(component) + + +@then(u'the {component} component is running') +def step_impl(context: MinifiTestContext, component: str): + assert context.get_or_create_default_minifi_container().is_component_running(component) + + +@then(u'connection \"{connection}\" can be seen through MiNiFi controller') +def step_impl(context: MinifiTestContext, connection: str): + assert context.get_or_create_default_minifi_container().connection_found_through_controller(connection) + + +@then(u'{connection_count:d} connections can be seen full through MiNiFi controller') +def step_impl(context: MinifiTestContext, connection_count: int): + assert context.get_or_create_default_minifi_container().get_full_connection_count() == connection_count + + +@retry_check(10, 1) +def check_connection_size_through_controller(context: MinifiTestContext, connection: str, size: int, max_size: int) -> bool: + return context.get_or_create_default_minifi_container().get_connection_size(connection) == (size, max_size) + + +@then(u'connection \"{connection}\" has {size:d} size and {max_size:d} max size through MiNiFi controller') +def step_impl(context: MinifiTestContext, connection: str, size: int, max_size: int): + assert check_connection_size_through_controller(context, connection, size, max_size) + + +@retry_check(10, 1) +def manifest_can_be_retrieved_through_minifi_controller(context: MinifiTestContext) -> bool: + manifest = context.get_or_create_default_minifi_container().get_manifest() + return '"agentManifest": {' in manifest and '"componentManifest": {' in manifest and '"agentType": "cpp"' in manifest + + +@then(u'manifest can be retrieved through MiNiFi controller') +def step_impl(context: MinifiTestContext): + assert manifest_can_be_retrieved_through_minifi_controller(context) + + +@then(u'debug bundle can be retrieved through MiNiFi controller') +def step_impl(context: MinifiTestContext): + assert context.get_or_create_default_minifi_container().create_debug_bundle() diff --git a/extensions/standard-processors/tests/features/steps/steps.py b/extensions/standard-processors/tests/features/steps/steps.py index 779c8b075..f35234ffa 100644 --- a/extensions/standard-processors/tests/features/steps/steps.py +++ b/extensions/standard-processors/tests/features/steps/steps.py @@ -33,21 +33,21 @@ def step_impl(context: MinifiTestContext): @step("a Syslog client with UDP protocol is setup to send logs to minifi") -def step_impl(context): +def step_impl(context: MinifiTestContext): context.containers["syslog-udp"] = SyslogContainer("udp", context) @step(u'there is an accessible PLC with modbus enabled') -def step_impl(context): +def step_impl(context: MinifiTestContext): modbus_container = context.containers["diag-slave-tcp"] = DiagSlave(context) assert modbus_container.deploy() @step(u'PLC register has been set with {modbus_cmd} command') -def step_impl(context, modbus_cmd): +def step_impl(context: MinifiTestContext, modbus_cmd: str): assert context.containers["diag-slave-tcp"].set_value_on_plc_with_modbus(modbus_cmd) or context.containers["diag-slave-tcp"].log_app_output() @step('a TCP client is set up to send a test TCP message to minifi') -def step_impl(context): +def step_impl(context: MinifiTestContext): context.containers["tcp-client"] = TcpClientContainer(context)
