From 421dd43f33b069d2938685cb7d54d2072ecdd0c5 Mon Sep 17 00:00:00 2001 From: jmv74211 Date: Wed, 28 Sep 2022 17:39:33 +0200 Subject: [PATCH] feat(#2947): add new EPS limit tests --- ...ration_drop_events_when_queue_is_full.yaml | 21 + ...ocessing_events_in_order_multi_thread.yaml | 23 + ...cessing_events_in_order_single_thread.yaml | 23 + ...tion_queueing_events_after_limitation.yaml | 21 + .../basic_test_module/cases_enabled.yaml | 2 +- .../cases_accepted_values.yaml | 2 +- .../cases_drop_events_when_queue_is_full.yaml | 17 + .../cases_limitation.yaml | 6 +- ...ocessing_events_in_order_multi_thread.yaml | 23 + ...cessing_events_in_order_single_thread.yaml | 19 + ...ases_queueing_events_after_limitation.yaml | 16 + .../test_analysisd/test_eps/test_basic.py | 112 +++- .../test_eps/test_configuration.py | 181 +++++- .../test_eps/test_event_processing.py | 550 +++++++++++++++++- 14 files changed, 986 insertions(+), 30 deletions(-) create mode 100644 tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_drop_events_when_queue_is_full.yaml create mode 100644 tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_multi_thread.yaml create mode 100644 tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_single_thread.yaml create mode 100644 tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_queueing_events_after_limitation.yaml create mode 100644 tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_drop_events_when_queue_is_full.yaml create mode 100644 tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_multi_thread.yaml create mode 100644 tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_single_thread.yaml create mode 100644 tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_queueing_events_after_limitation.yaml diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_drop_events_when_queue_is_full.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_drop_events_when_queue_is_full.yaml new file mode 100644 index 0000000000..fa168de5a0 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_drop_events_when_queue_is_full.yaml @@ -0,0 +1,21 @@ +- sections: + - section: remote + elements: + - connection: + value: syslog + - port: + value: PORT + - protocol: + value: PROTOCOL + - allowed-ips: + value: 0.0.0.0/0 + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUM + - timeframe: + value: TIMEFRAME diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_multi_thread.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_multi_thread.yaml new file mode 100644 index 0000000000..35820bf959 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_multi_thread.yaml @@ -0,0 +1,23 @@ +- sections: + - section: remote + elements: + - connection: + value: syslog + - port: + value: PORT + - protocol: + value: PROTOCOL + - allowed-ips: + value: 0.0.0.0/0 + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUM + - timeframe: + value: TIMEFRAME + - logall: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_single_thread.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_single_thread.yaml new file mode 100644 index 0000000000..35820bf959 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_processing_events_in_order_single_thread.yaml @@ -0,0 +1,23 @@ +- sections: + - section: remote + elements: + - connection: + value: syslog + - port: + value: PORT + - protocol: + value: PROTOCOL + - allowed-ips: + value: 0.0.0.0/0 + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUM + - timeframe: + value: TIMEFRAME + - logall: + value: 'yes' diff --git a/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_queueing_events_after_limitation.yaml b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_queueing_events_after_limitation.yaml new file mode 100644 index 0000000000..fa168de5a0 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/configuration_template/event_processing_test_module/configuration_queueing_events_after_limitation.yaml @@ -0,0 +1,21 @@ +- sections: + - section: remote + elements: + - connection: + value: syslog + - port: + value: PORT + - protocol: + value: PROTOCOL + - allowed-ips: + value: 0.0.0.0/0 + - section: global + elements: + - limits: + elements: + - eps: + elements: + - maximum: + value: MAXIMUM + - timeframe: + value: TIMEFRAME diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/basic_test_module/cases_enabled.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/basic_test_module/cases_enabled.yaml index 1d9de44ea6..945a2343ea 100644 --- a/tests/integration/test_analysisd/test_eps/data/test_cases/basic_test_module/cases_enabled.yaml +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/basic_test_module/cases_enabled.yaml @@ -1,4 +1,4 @@ -- name: maximum 20 - timeframe 5 +- name: enabled description: EPS Limits enabled configuration_parameters: MAXIMUM: '20' diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/configuration_test_module/cases_accepted_values.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/configuration_test_module/cases_accepted_values.yaml index 5c2c98eca0..daf9da4ad5 100644 --- a/tests/integration/test_analysisd/test_eps/data/test_cases/configuration_test_module/cases_accepted_values.yaml +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/configuration_test_module/cases_accepted_values.yaml @@ -1,5 +1,5 @@ - name: maximum 5000 - timeframe 10 - description: acepted value + description: accepted value configuration_parameters: MAXIMUM: '5000' TIMEFRAME: '10' diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_drop_events_when_queue_is_full.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_drop_events_when_queue_is_full.yaml new file mode 100644 index 0000000000..90b8a20cd3 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_drop_events_when_queue_is_full.yaml @@ -0,0 +1,17 @@ +- name: drop events + description: Drop events when events queue is full + configuration_parameters: + PORT: 514 + PROTOCOL: tcp + MAXIMUM: '1' + TIMEFRAME: '100' + metadata: + maximum: 1 + timeframe: 100 + # syslog simulator parameters + address: 'localhost' + port: 514 + protocol: 'tcp' + messages_number: 50000 + eps: 5000 + diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_limitation.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_limitation.yaml index 7eb4d60638..c165036836 100644 --- a/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_limitation.yaml +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_limitation.yaml @@ -1,12 +1,12 @@ -- name: maximum 500 - timeframe 5 +- name: not process events after exceeding the limit description: EPS limitation configuration_parameters: PORT: 514 PROTOCOL: tcp - MAXIMUM: '250' + MAXIMUM: '500' TIMEFRAME: '10' metadata: - maximum: 250 + maximum: 500 timeframe: 10 # syslog simulator parameters address: 'localhost' diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_multi_thread.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_multi_thread.yaml new file mode 100644 index 0000000000..9af21009c9 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_multi_thread.yaml @@ -0,0 +1,23 @@ +- name: batch events order - multi-thread + description: Process events in batch order + configuration_parameters: + PORT: 514 + PROTOCOL: tcp + MAXIMUM: '20' + TIMEFRAME: '5' + metadata: + maximum: 20 + timeframe: 5 + # syslog simulator parameters + address: 'localhost' + num_batches: 5 + batch_sending_time: 3 + message_1: 'Login failed: admin, test - Group 1' + message_2: 'Login failed: admin, test - Group 2' + message_3: 'Login failed: admin, test - Group 3' + message_4: 'Login failed: admin, test - Group 4' + message_5: 'Login failed: admin, test - Group 5' + port: 514 + protocol: 'tcp' + eps: 100 + messages_number: 100 diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_single_thread.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_single_thread.yaml new file mode 100644 index 0000000000..b1daca80f4 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_processing_events_in_order_single_thread.yaml @@ -0,0 +1,19 @@ +- name: messages events order - single-thread + description: Process events in messages order + configuration_parameters: + PORT: 514 + PROTOCOL: tcp + MAXIMUM: '20' + TIMEFRAME: '5' + metadata: + maximum: 20 + timeframe: 5 + # syslog simulator parameters + address: 'localhost' + message: 'Login failed: admin, test' + port: 514 + protocol: 'tcp' + numbered_messages: 1 + messages_number_1: 300 + eps: 300 + messages_number_2: 200 \ No newline at end of file diff --git a/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_queueing_events_after_limitation.yaml b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_queueing_events_after_limitation.yaml new file mode 100644 index 0000000000..c378e00201 --- /dev/null +++ b/tests/integration/test_analysisd/test_eps/data/test_cases/event_processing_test_module/cases_queueing_events_after_limitation.yaml @@ -0,0 +1,16 @@ +- name: queue non-processed events + description: Queueing events after processing limitation + configuration_parameters: + PORT: 514 + PROTOCOL: tcp + MAXIMUM: '100' + TIMEFRAME: '10' + metadata: + maximum: 100 + timeframe: 10 + # syslog simulator parameters + address: 'localhost' + port: 514 + protocol: 'tcp' + messages_number: 10000 + eps: 1000 diff --git a/tests/integration/test_analysisd/test_eps/test_basic.py b/tests/integration/test_analysisd/test_eps/test_basic.py index 8a76d80a62..497cd5ea77 100644 --- a/tests/integration/test_analysisd/test_eps/test_basic.py +++ b/tests/integration/test_analysisd/test_eps/test_basic.py @@ -3,7 +3,6 @@ from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data from wazuh_testing.modules.analysisd import event_monitor as evm -from wazuh_testing.modules.analysisd import ANALYSISD_STATE_INTERNAL_DEFAULT from wazuh_testing.processes import check_if_daemons_are_running pytestmark = [pytest.mark.server] @@ -13,10 +12,9 @@ TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template', 'basic_test_module') TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases', 'basic_test_module') -local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0', - 'analysisd.state_interval': f"{ANALYSISD_STATE_INTERNAL_DEFAULT}"} +local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0'} -# ------------------------------- TEST_ENABLED ------------------------------------------------------------------------- +# ---------------------------------------------------- TEST_ENABLED ---------------------------------------------------- # Configuration and cases data configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_enabled.yaml') t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_enabled.yaml') @@ -26,7 +24,7 @@ t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters, t1_configuration_metadata) -# ------------------------------- TEST_DISABLED ------------------------------------------------------------------------ +# ---------------------------------------------------- TEST_DISABLED --------------------------------------------------- # Configuration and cases data t2_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_disabled.yaml') t2_cases_path = os.path.join(TEST_CASES_PATH, 'cases_disabled.yaml') @@ -40,7 +38,57 @@ @pytest.mark.tier(level=0) @pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) def test_enabled(configuration, metadata, load_wazuh_basic_configuration, set_wazuh_configuration, - configure_local_internal_options_module, truncate_monitored_files, restart_wazuh_daemon_function): + configure_local_internal_options_function, truncate_monitored_files, restart_wazuh_daemon_function): + """ + description: Check whether the event analysis limitation is activated after its activation in the configuration. + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Check in the ossec.log that a line has appeared indicating that EPS limiting has been enabled. + - Check that wazuh-analysisd is running (it has not been crashed). + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check in the log that the EPS limitation has been activated. + - Check that wazuh-analysisd daemon does not crash. + + input_description: + - The `configuration_enabled` file provides the module configuration for this test. + - The `cases_enabled` file provides the test cases. + """ evm.check_eps_enabled(metadata['maximum'], metadata['timeframe']) # Check that wazuh-analysisd is running @@ -50,7 +98,57 @@ def test_enabled(configuration, metadata, load_wazuh_basic_configuration, set_wa @pytest.mark.tier(level=0) @pytest.mark.parametrize('configuration, metadata', zip(t2_configurations, t2_configuration_metadata), ids=t2_case_ids) def test_disabled(configuration, metadata, load_wazuh_basic_configuration, set_wazuh_configuration, - configure_local_internal_options_module, truncate_monitored_files, restart_wazuh_daemon_function): + configure_local_internal_options_function, truncate_monitored_files, restart_wazuh_daemon_function): + """ + description: Check if when the EPS limitation setting is not applied, the feature is not activated. + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Look in the ossec.log to see if the EPS limitation activation does not appear. + - Check that wazuh-analysisd is running (it has not been crashed). + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check in the ossec.log to see if the EPS limitation activation does not appear. + - Check that wazuh-analysisd daemon does not crash. + + input_description: + - The `configuration_disabled` file provides the module configuration for this test. + - The `cases_disabled` file provides the test cases. + """ evm.check_eps_disabled() # Check that wazuh-analysisd is running diff --git a/tests/integration/test_analysisd/test_eps/test_configuration.py b/tests/integration/test_analysisd/test_eps/test_configuration.py index f5057efb9d..6009ed5b51 100644 --- a/tests/integration/test_analysisd/test_eps/test_configuration.py +++ b/tests/integration/test_analysisd/test_eps/test_configuration.py @@ -4,7 +4,6 @@ from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data from wazuh_testing.modules.analysisd import event_monitor as evm from wazuh_testing.tools.services import control_service -from wazuh_testing.modules.analysisd import ANALYSISD_STATE_INTERNAL_DEFAULT from wazuh_testing.processes import check_if_daemons_are_running from wazuh_testing.tools import file from wazuh_testing import WAZUH_CONF_PATH @@ -13,10 +12,9 @@ TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template', 'configuration_test_module') TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases', 'configuration_test_module') -local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0', - 'analysisd.state_interval': f"{ANALYSISD_STATE_INTERNAL_DEFAULT}"} +local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0'} -# ------------------------------- TEST_ACCEPTED_VALUES ------------------------------------------------------------------- +# ------------------------------------------------ TEST_ACCEPTED_VALUES ------------------------------------------------ # Configuration and cases data t1_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_accepted_values.yaml') t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_accepted_values.yaml') @@ -26,7 +24,7 @@ t1_configurations = load_configuration_template(t1_configurations_path, t1_configuration_parameters, t1_configuration_metadata) -# ------------------------------- TEST_INVALID_VALUES ------------------------------------------------------------------ +# ------------------------------------------------- TEST_INVALID_VALUES ------------------------------------------------ # Configuration and cases data t2_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_invalid_values.yaml') t2_cases_path = os.path.join(TEST_CASES_PATH, 'cases_invalid_values.yaml') @@ -36,7 +34,7 @@ t2_configurations = load_configuration_template(t2_configurations_path, t2_configuration_parameters, t2_configuration_metadata) -# ------------------------------- TEST_MISSING_CONFIGURATION ----------------------------------------------------------- +# --------------------------------------------- TEST_MISSING_CONFIGURATION --------------------------------------------- # Configuration and cases data t3_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_missing_configuration.yaml') t3_cases_path = os.path.join(TEST_CASES_PATH, 'cases_missing_configuration.yaml') @@ -52,7 +50,56 @@ def test_accepted_values(configuration, metadata, load_wazuh_basic_configuration, set_wazuh_configuration, configure_local_internal_options_module, truncate_monitored_files, restart_wazuh_daemon_function): + """ + description: Check that the EPS limitation is activated under accepted parameters. + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Check in the log that the EPS limitation has been activated with the specified parameters. + - Check that wazuh-analysisd is running (it has not been crashed). + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check in the log that the EPS limitation has been activated with the specified parameters. + - Check that wazuh-analysisd daemon does not crash. + + input_description: + - The `configuration_accepted_values` file provides the module configuration for this test. + - The `cases_accepted_values` file provides the test cases. + """ evm.check_eps_enabled(metadata['maximum'], metadata['timeframe']) # Check that wazuh-analysisd is running @@ -64,6 +111,62 @@ def test_accepted_values(configuration, metadata, load_wazuh_basic_configuration def test_invalid_values(configuration, metadata, restart_wazuh_daemon_after_finishing_function, load_wazuh_basic_configuration, set_wazuh_configuration, configure_local_internal_options_module, truncate_monitored_files): + """ + description: Check for configuration error and wazuh-analysisd if the EPS limiting configuration has unaccepted + values. Done for the following cases: + - Maximum value above the allowed value. + - Timeframe value above the allowed value. + - Timeframe = 0 + - Maximum, timeframe = 0 + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - test: + - Restart wazuh-manager service to apply configuration changes. + - Check that a configuration error is raised when trying to start wazuh-manager. + - Check that wazuh-analysisd is not running (due to configuration error). + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + - Restart the wazuh-manager service to apply initial configuration and start wazuh-analysisd daemon. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - restart_wazuh_daemon_after_finishing_function: + type: fixture + brief: Restart the wazuh service in tierdown stage. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + + assertions: + - Check that a configuration error is raised when trying to start wazuh-manager. + - Check that wazuh-analysisd is not running (due to configuration error). + + input_description: + - The `configuration_invalid_values` file provides the module configuration for this test. + - The `cases_invalid_values` file provides the test cases. + """ try: control_service('restart') except ValueError: @@ -72,24 +175,84 @@ def test_invalid_values(configuration, metadata, restart_wazuh_daemon_after_fini evm.check_configuration_error() # Check that wazuh-analysisd is not running assert not check_if_daemons_are_running(['wazuh-analysisd'])[0], 'wazuh-analysisd is running and was not ' \ - 'expected to' + 'expected to' @pytest.mark.tier(level=0) @pytest.mark.parametrize('configuration, metadata', zip(t3_configurations, t3_configuration_metadata), ids=t3_case_ids) def test_missing_configuration(configuration, metadata, restart_wazuh_daemon_after_finishing_function, - load_wazuh_basic_configuration, set_wazuh_configuration, - truncate_monitored_files): + load_wazuh_basic_configuration, set_wazuh_configuration, truncate_monitored_files): + """ + description: Checks what happens if tags are missing in the event analysis limitation settings. Done for the + following cases: + - Missing . + - Missing . + - Missing and . + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - test: + - Remove the specified tag in ossec.conf + - Restart wazuh-manager service to apply configuration changes. + - Check whether the EPS limitation is activated, deactivated or generates a configuration error due to a + missing label. + - Check if wazuh-analysisd is running or not (according to the expected behavior). + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + - Restart the wazuh-manager service to apply initial configuration and start wazuh-analysisd daemon. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - restart_wazuh_daemon_after_finishing_function: + type: fixture + brief: Restart the wazuh service in tierdown stage. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + + assertions: + - Check whether the EPS limitation is activated, deactivated or generates a configuration error due to a + missing label. + - Check if wazuh-analysisd is running or not (according to the expected behavior). + input_description: + - The `configuration_missing_values` file provides the module configuration for this test. + - The `cases_missing_values` file provides the test cases. + """ # Remove test case tags from ossec.conf file.replace_regex_in_file(metadata['remove_tags'], [''] * len(metadata['remove_tags']), WAZUH_CONF_PATH) if metadata['behavior'] == 'works': control_service('restart') evm.check_eps_enabled(metadata['maximum'], 10) # 10 is the default timeframe + assert check_if_daemons_are_running(['wazuh-analysisd'])[0], 'wazuh-analysisd is not running. Maybe it has ' \ + 'crashed' elif metadata['behavior'] == 'disabled': control_service('restart') evm.check_eps_disabled() + assert check_if_daemons_are_running(['wazuh-analysisd'])[0], 'wazuh-analysisd is not running. Maybe it has ' \ + 'crashed' else: try: control_service('restart') diff --git a/tests/integration/test_analysisd/test_eps/test_event_processing.py b/tests/integration/test_analysisd/test_eps/test_event_processing.py index 8e32d0c07d..8723cae082 100644 --- a/tests/integration/test_analysisd/test_eps/test_event_processing.py +++ b/tests/integration/test_analysisd/test_eps/test_event_processing.py @@ -2,12 +2,17 @@ import pytest import threading import time +import re from math import ceil +from copy import deepcopy from wazuh_testing.tools.configuration import load_configuration_template, get_test_cases_data +from wazuh_testing import ARCHIVES_LOG_PATH from wazuh_testing.modules.analysisd import event_monitor as evm from wazuh_testing.tools.services import control_service -from wazuh_testing.modules.analysisd import ANALYSISD_STATE_INTERNAL_DEFAULT +from wazuh_testing.tools import file +from wazuh_testing.modules.analysisd import QUEUE_EVENTS_SIZE, ANALYSISD_ONE_THREAD_CONFIG +from wazuh_testing.scripts.syslog_simulator import DEFAULT_MESSAGE_SIZE from wazuh_testing.processes import check_if_daemons_are_running from wazuh_testing.tools.run_simulator import syslog_simulator from wazuh_testing.tools.thread_executor import ThreadExecutor @@ -16,10 +21,9 @@ TEST_DATA_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data') CONFIGURATIONS_PATH = os.path.join(TEST_DATA_PATH, 'configuration_template', 'event_processing_test_module') TEST_CASES_PATH = os.path.join(TEST_DATA_PATH, 'test_cases', 'event_processing_test_module') -local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0', - 'analysisd.state_interval': '1'} +local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0', 'analysisd.state_interval': '1'} -# ------------------------------- TEST_LIMITATION ---------------------------------------------------------------------- +# --------------------------------------------------- TEST_LIMITATION -------------------------------------------------- # Configuration and cases data t1_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_limitation.yaml') t1_cases_path = os.path.join(TEST_CASES_PATH, 'cases_limitation.yaml') @@ -29,11 +33,110 @@ t1_configurations = load_configuration_template(t1_configurations_path, t1_configuration_parameters, t1_configuration_metadata) +# ---------------------------------------- TEST_QUEUEING_EVENTS_AFTER_LIMITATION --------------------------------------- +# Configuration and cases data +t2_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_queueing_events_after_limitation.yaml') +t2_cases_path = os.path.join(TEST_CASES_PATH, 'cases_queueing_events_after_limitation.yaml') + +# Queing event test configurations (t2) +t2_configuration_parameters, t2_configuration_metadata, t2_case_ids = get_test_cases_data(t2_cases_path) +t2_configurations = load_configuration_template(t2_configurations_path, t2_configuration_parameters, + t2_configuration_metadata) + +# --------------------------------------- TEST_DROPPING_EVENTS_WHEN_QUEUE_IS_FULL -------------------------------------- +# Configuration and cases data +t3_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_drop_events_when_queue_is_full.yaml') +t3_cases_path = os.path.join(TEST_CASES_PATH, 'cases_drop_events_when_queue_is_full.yaml') + +# Dropping events when queue is full test configurations (t3) +t3_configuration_parameters, t3_configuration_metadata, t3_case_ids = get_test_cases_data(t3_cases_path) +t3_configurations = load_configuration_template(t3_configurations_path, t3_configuration_parameters, + t3_configuration_metadata) + +# ------------------------------------ TEST_PROCESSING_EVENTS_IN_ORDER_SINGLE_THREAD ----------------------------------- +# Configuration and cases data +t4_configurations_path = os.path.join(CONFIGURATIONS_PATH, + 'configuration_processing_events_in_order_single_thread.yaml') +t4_cases_path = os.path.join(TEST_CASES_PATH, 'cases_processing_events_in_order_single_thread.yaml') + +# Processing events in order single thread test configurations (t4) +t4_configuration_parameters, t4_configuration_metadata, t4_case_ids = get_test_cases_data(t4_cases_path) +t4_configurations = load_configuration_template(t4_configurations_path, t4_configuration_parameters, + t4_configuration_metadata) +t4_local_internal_options = {'wazuh_modules.debug': '2', 'monitord.rotate_log': '0', 'analysisd.state_interval': '1'} +t4_local_internal_options.update(ANALYSISD_ONE_THREAD_CONFIG) + +# ------------------------------------ TEST_PROCESSING_EVENTS_IN_ORDER_MULTI_THREAD ------------------------------------ +# Configuration and cases data +t5_configurations_path = os.path.join(CONFIGURATIONS_PATH, 'configuration_processing_events_in_order_multi_thread.yaml') +t5_cases_path = os.path.join(TEST_CASES_PATH, 'cases_processing_events_in_order_multi_thread.yaml') + +# Processing events in order multi thread test configurations (t5) +t5_configuration_parameters, t5_configuration_metadata, t5_case_ids = get_test_cases_data(t5_cases_path) +t5_configurations = load_configuration_template(t5_configurations_path, t5_configuration_parameters, + t5_configuration_metadata) + + @pytest.mark.tier(level=0) @pytest.mark.parametrize('configuration, metadata', zip(t1_configurations, t1_configuration_metadata), ids=t1_case_ids) -def test_limitation(configuration, metadata, load_wazuh_basic_configuration, - set_wazuh_configuration, configure_local_internal_options_module, - truncate_monitored_files, restart_wazuh_daemon_function): +def test_limitation(configuration, metadata, load_wazuh_basic_configuration, set_wazuh_configuration, + configure_local_internal_options_function, truncate_monitored_files, restart_wazuh_daemon_function): + """ + description: Check if after passing the event processing limit, the processing is stopped until the next timeframe. + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Start the event simulator and check that the events are being received and analyzed. + - Wait until the event limit is reached and check that the events are still being received but not + processed. + - Wait until the next analysis period (next timeframe) and check that events are still being + processed, in this case the queued ones. + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check that events are received when expected. + - Check that events are processed when expected. + - Check that events are still received when expected. + - Check that no events are processed due to blocking. + - Check that events are still processed after blocking. + + input_description: + - The `configuration_limitation` file provides the module configuration for this test. + - The `cases_limitation` file provides the test cases. + """ # Set syslog simulator parameters according to the use case data syslog_simulator_parameters = {'address': metadata['address'], 'port': metadata['port'], 'protocol': metadata['protocol'], 'eps': metadata['eps'], @@ -42,6 +145,7 @@ def test_limitation(configuration, metadata, load_wazuh_basic_configuration, # Run syslog simulator thread syslog_simulator_thread = ThreadExecutor(syslog_simulator, {'parameters': syslog_simulator_parameters}) syslog_simulator_thread.start() + waited_simulator_time = 0 # Wait until syslog simulator is started time.sleep(1) @@ -55,8 +159,10 @@ def test_limitation(configuration, metadata, load_wazuh_basic_configuration, assert events_received > 0, '(0): No events are being received when it is expected' assert events_processed > 0, 'No events are being processed when it is expected' - # Wait until the limitation period has expired - time.sleep(ceil((metadata['maximum'] * metadata['timeframe']) / metadata['eps'])) + # Wait for the event non-processing phase to arrive (limit reached) + waiting_limit_time = ceil((metadata['maximum'] * metadata['timeframe']) / metadata['eps']) + 1 # Offset 1s + time.sleep(waiting_limit_time) + waited_simulator_time += waiting_limit_time # Get analysisd stats in limitation stage analysisd_state = evm.get_analysisd_state() @@ -67,5 +173,431 @@ def test_limitation(configuration, metadata, load_wazuh_basic_configuration, assert events_received > 0, '(1): No events are being received when it is expected' assert events_processed == 0, f"Events are being processed when the limit has been reached. {events_processed} != 0" + # Wait until the limited timeframe has elapsed + time.sleep(metadata['timeframe'] + 1 - waited_simulator_time) ## Offset 1s + + # Get analysisd stats in limitation stage + analysisd_state = evm.get_analysisd_state() + events_processed = int(analysisd_state['events_processed']) + + # Check whether events continue to be processed after blocking + assert events_processed > 0, f"Event processing has not been continued after blocking" + + # Wait until syslog simulator ends + syslog_simulator_thread.join() + + +@pytest.mark.tier(level=0) +@pytest.mark.parametrize('configuration, metadata', zip(t2_configurations, t2_configuration_metadata), ids=t2_case_ids) +def test_queueing_events_after_limitation(configuration, metadata, load_wazuh_basic_configuration, + set_wazuh_configuration, configure_local_internal_options_function, + truncate_monitored_files, restart_wazuh_daemon_function): + """ + description: Check if after stopping processing events (due to limit reached), the received events are stored in + the events queue if it is not full. + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Check that the initial events queue usage rate is 0%. + - Calculate when the limit of processed events is reached, waits a few seconds for events to be stored in + the events queue and takes a sample of the usage to check that it is higher than 0%. + - Wait a few seconds and takes a second sample again, to check that the events queue usage is higher than + the first sample. + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check that the queue usage at startup is 0%. + - Check that the queue usage grows after stopping processing events. + - Check that the queue usage continues to grow after stopping processing events. + + input_description: + - The `configuration_queueing_events_after_limitation` file provides the module configuration for this test. + - The `cases_queueing_events_after_limitation` file provides the test cases. + """ + # Get initial queue usage + analysisd_state = evm.get_analysisd_state() + event_queue_usage = float(analysisd_state['event_queue_usage']) + + # Check that there are no events in the queue + assert event_queue_usage == 0.0, f"The initial events queue is not at 0%" + + # Set syslog simulator parameters according to the use case data + syslog_simulator_parameters = {'address': metadata['address'], 'port': metadata['port'], + 'protocol': metadata['protocol'], 'eps': metadata['eps'], + 'messages_number': metadata['messages_number']} + + # Run syslog simulator thread + syslog_simulator_thread = ThreadExecutor(syslog_simulator, {'parameters': syslog_simulator_parameters}) + syslog_simulator_thread.start() + + # Wait for the event non-processing stage (limit reached) + waiting_limit_time = ceil((metadata['maximum'] * metadata['timeframe']) / metadata['eps']) + 1 # Offset 1s + time.sleep(waiting_limit_time) + + # Get queue usage in limitation stage + analysisd_state = evm.get_analysisd_state() + event_queue_usage_sample_1 = float(analysisd_state['event_queue_usage']) + + # Check that received and unprocessed events are being queued + assert event_queue_usage_sample_1 > 0.0, 'Events received after processing limitation are not being queued' + + # Wait a few more seconds before passing the timeframe + waiting_time_sample_2 = ceil((metadata['timeframe'] - waiting_limit_time) / 2) + time.sleep(waiting_time_sample_2) + + # Get queue usage in limitation stage + analysisd_state = evm.get_analysisd_state() + event_queue_usage_sample_2 = float(analysisd_state['event_queue_usage']) + + # Check that events received and not processed are still being queued + assert event_queue_usage_sample_2 > event_queue_usage_sample_1, 'Events queue has not grown as expected during ' \ + 'event limitation' + # Wait until syslog simulator ends + syslog_simulator_thread.join() + + +@pytest.mark.tier(level=0) +@pytest.mark.parametrize('configuration, metadata', zip(t3_configurations, t3_configuration_metadata), ids=t3_case_ids) +def test_dropping_events_when_queue_is_full(configuration, metadata, load_wazuh_basic_configuration, + set_wazuh_configuration, configure_local_internal_options_function, + truncate_monitored_files, restart_wazuh_daemon_function): + """ + description: Check that after the event analysis block, if the events queue is full, the events are dropped. + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Check that the initial queue usage rate is 0%. + - Calculate when the event analysis blocking phase is expected and the queue is full, then it measures the + use of the event queue to check that it is 100%, and that the received events are being dropped. + - tierdown: + - Truncate wazuh logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_monitored_files: + type: fixture + brief: Truncate wazuh logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check that the initial queue is at 0%. + - Check that after the event analysis block and the queue is full, events are still being received. + - Check that no events are processed when it is expected. + - Check that the event queue usage is at 100% when it is expected. + - Check that all events received are being dropped because the queue is full. + + input_description: + - The `configuration_dropping_events_when_queue_is_full` file provides the module configuration for this test. + - The `cases_dropping_events_when_queue_is_full` file provides the test cases. + """ + # Get initial queue usage + analysisd_state = evm.get_analysisd_state() + event_queue_usage = float(analysisd_state['event_queue_usage']) + + # Check that there are no events in the queue + assert event_queue_usage == 0.0, f"The initial events queue is not at 0%" + + # Set syslog simulator parameters according to the use case data + syslog_simulator_parameters = {'address': metadata['address'], 'port': metadata['port'], + 'protocol': metadata['protocol'], 'eps': metadata['eps'], + 'messages_number': metadata['messages_number']} + + # Run syslog simulator thread + syslog_simulator_thread = ThreadExecutor(syslog_simulator, {'parameters': syslog_simulator_parameters}) + syslog_simulator_thread.start() + + # Calculate the non-processing stage (limit reached) + waiting_limit_time = ceil((metadata['maximum'] * metadata['timeframe']) / metadata['eps']) + 1 # Offset 1s + + # Calculate the stage when the events queue is full (offset 4 sec to check all received-dropped events) + waiting_time_queue_is_full = waiting_limit_time + ((QUEUE_EVENTS_SIZE / DEFAULT_MESSAGE_SIZE) / metadata['eps']) + 4 + time.sleep(waiting_time_queue_is_full) + + # Get analysisd stats + analysisd_state = evm.get_analysisd_state() + event_queue_usage = float(analysisd_state['event_queue_usage']) + events_dropped = float(analysisd_state['events_dropped']) + events_received = int(analysisd_state['events_received']) + events_processed = int(analysisd_state['events_processed']) + + # Check that events are received, not processed and that they are dropped when the queue is full + assert events_received > 0, ' No events are being received when it is expected' + assert events_processed == 0, 'Events are being processed when they are not expected (due to the limit)' + assert event_queue_usage == 1.0, 'The events queue is not full as expected' + assert events_dropped == events_received, 'No events are being dropped even though the queue is full' + # Wait until syslog simulator ends syslog_simulator_thread.join() + + +@pytest.mark.tier(level=0) +@pytest.mark.parametrize('configuration, metadata', zip(t4_configurations, t4_configuration_metadata), ids=t4_case_ids) +@pytest.mark.parametrize('configure_local_internal_options_function', [t4_local_internal_options], indirect=True) +def test_event_processing_in_order_single_thread(configuration, metadata, load_wazuh_basic_configuration, + set_wazuh_configuration, configure_local_internal_options_function, + truncate_event_logs, restart_wazuh_daemon_function): + """ + description: Check that events are processed in order according to the position within the queue, and + that events that are being received during the blocking phase are being added to the end of the queue when + using single-thread processing. + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh event logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Send a batch of identified events. + - Wait a few seconds, then send another batch of identified events. + - Wait until all events are processed. + - Read the event log (archives.log) and check that the events have been processed in the expected order. + - tierdown: + - Truncate wazuh event logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_event_logs: + type: fixture + brief: Truncate wazuh event logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check that all expected events have been stored in the archives.log. + - Check that all events have been generated in the archives.log according to the expected order. + + input_description: + - The `configuration_event_processing_in_order_single_thread` file provides the module configuration for this + test. + - The `cases_event_processing_in_order_single_thread` file provides the test cases. + """ + # Set syslog simulator parameters according to the use case data + syslog_simulator_parameters_1 = {'address': metadata['address'], 'port': metadata['port'], + 'protocol': metadata['protocol'], 'eps': metadata['eps'], + 'messages_number': metadata['messages_number_1'], 'message': metadata['message'], + 'numbered_messages': metadata['numbered_messages']} + + # Run syslog simulator thread + syslog_simulator_thread_1 = ThreadExecutor(syslog_simulator, {'parameters': syslog_simulator_parameters_1}) + syslog_simulator_thread_1.start() + + # Wait until the first processing interval has passed. + waiting_time = metadata['timeframe'] + time.sleep(waiting_time) + + # Run syslog simulator to send new events when events sent previously still have to be processed + # (they are in the queue) + syslog_simulator_parameters_2 = {'address': metadata['address'], 'port': metadata['port'], + 'protocol': metadata['protocol'], 'eps': metadata['eps'], + 'messages_number': metadata['messages_number_2'], 'message': metadata['message'], + 'numbered_messages': metadata['messages_number_1'] + 1} + syslog_simulator_thread_2 = ThreadExecutor(syslog_simulator, {'parameters': syslog_simulator_parameters_2}) + syslog_simulator_thread_2.start() + + # Wait until all events have been processed + waiting_time = ((metadata['messages_number_1'] + metadata['messages_number_2']) / \ + (metadata['maximum'] * metadata['timeframe'])) * metadata['timeframe'] + 1 # Offset 1s + time.sleep(waiting_time) + + # Read the events log data + events_data = file.read_file(ARCHIVES_LOG_PATH).split('\n') + expected_num_events = metadata['messages_number_1'] + metadata['messages_number_2'] + + # Check that all events have been recorded in the log file + assert len(events_data) >= expected_num_events, \ + f"Not all expected events were found in the archives.log. Found={len(events_data)}, " \ + f"expected>={expected_num_events}" + + # Get the IDs of event messages + event_ids = [int(re.search(fr"{metadata['message']} - (\d+)", event).group(1)) for event in events_data \ + if bool(re.match(fr".*{metadata['message']} - (\d+)", event))] + + # Check that the event message IDs are in order + assert all(event_ids[i] <= event_ids[i+1] for i in range(len(event_ids) - 1)), 'Events have not been processed ' \ + 'in the expected order' + + # Wait until syslog simulator ends + syslog_simulator_thread_1.join() + syslog_simulator_thread_2.join() + + +@pytest.mark.tier(level=0) +@pytest.mark.parametrize('configuration, metadata', zip(t5_configurations, t5_configuration_metadata), ids=t5_case_ids) +def test_event_processing_in_order_multi_thread(configuration, metadata, load_wazuh_basic_configuration, + set_wazuh_configuration, configure_local_internal_options_function, + truncate_event_logs, restart_wazuh_daemon_function): + """ + description: Check that events are processed in order according to the position within the queue, and + that events that are being received during the blocking phase are being added to the end of the queue when + using multi-thread processing. + + test_phases: + - setup: + - Load Wazuh light configuration. + - Apply ossec.conf configuration changes according to the configuration template and use case. + - Apply custom settings in local_internal_options.conf. + - Truncate wazuh event logs. + - Restart wazuh-manager service to apply configuration changes. + - test: + - Send a batch of identified events. + - Wait a few seconds, then send another batch of identified events. This is repeated n times. + - Wait until all events are processed. + - Read the event log (archives.log) and check that the events have been processed in the expected order. + - tierdown: + - Truncate wazuh event logs. + - Restore initial configuration, both ossec.conf and local_internal_options.conf. + + wazuh_min_version: 4.4.0 + + parameters: + - configuration: + type: dict + brief: Get configurations from the module. + - metadata: + type: dict + brief: Get metadata from the module. + - load_wazuh_basic_configuration: + type: fixture + brief: Load basic wazuh configuration. + - set_wazuh_configuration: + type: fixture + brief: Apply changes to the ossec.conf configuration. + - configure_local_internal_options_function: + type: fixture + brief: Apply changes to the local_internal_options.conf configuration. + - truncate_event_logs: + type: fixture + brief: Truncate wazuh event logs. + - restart_wazuh_daemon_function: + type: fixture + brief: Restart the wazuh service. + + assertions: + - Check that all expected events have been stored in the archives.log. + - Check that all events have been generated in the archives.log according to the expected order. + + input_description: + - The `configuration_event_processing_in_order_multi_thread` file provides the module configuration for this + test. + - The `cases_event_processing_in_order_multi_thread` file provides the test cases. + """ + # Set syslog simulator parameters according to the use case data + parameters = [] + syslog_simulator_threads = [] + syslog_simulator_parameters = {'address': metadata['address'], 'port': metadata['port'], + 'protocol': metadata['protocol'], 'eps': metadata['eps'], + 'messages_number': metadata['messages_number'], 'message': metadata['message_1']} + # Create syslog simulator threads + for index, parameter in enumerate(range(metadata['num_batches'])): + parameters.append(deepcopy(syslog_simulator_parameters)) + parameters[index].update({'message': metadata[f"message_{index + 1}"]}) + syslog_simulator_threads.append(ThreadExecutor(syslog_simulator, {'parameters': parameters[index]})) + + # Start syslog simulator threads + for thread in syslog_simulator_threads: + thread.start() + time.sleep(metadata['batch_sending_time']) + + # Wait until all events have been processed + waiting_time_to_process_all_events= ((metadata['messages_number'] * metadata['num_batches']) / \ + (metadata['maximum'] * metadata['timeframe'])) * metadata['timeframe'] + 1 # Offset 1s + waited_time_to_create_threads = metadata['batch_sending_time'] * metadata['num_batches'] + time.sleep(waiting_time_to_process_all_events - waited_time_to_create_threads) + + # Read the events log data + events_data = file.read_file(ARCHIVES_LOG_PATH).split('\n') + expected_num_events = metadata['batch_sending_time'] * metadata['num_batches'] + + # Check that all events have been recorded in the log file + assert len(events_data) >= expected_num_events, \ + f"Not all expected events were found in the archives.log. Found={len(events_data)}, " \ + f"expected>={expected_num_events}" + + # Get the IDs of event messages + event_ids = [int(re.search(fr"{metadata['message_1']} - Group (\d+)", event).group(1)) for event in events_data \ + if bool(re.match(fr".*{metadata['message_1']} - Group (\d+)", event))] + + # Check that the event message IDs are in order + assert all(event_ids[i] <= event_ids[i+1] for i in range(len(event_ids) - 1)), 'Events have not been processed ' \ + 'in the expected order' + # Wait until all syslog simulator threads finish + for thread in syslog_simulator_threads: + thread.join()