Skip to content

Commit

Permalink
New ITs changes requested implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
nmkoremblum committed Oct 1, 2021
1 parent 0a532b2 commit c9a41b4
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 212 deletions.
37 changes: 35 additions & 2 deletions deps/wazuh_testing/wazuh_testing/logcollector.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
GENERIC_CALLBACK_ERROR_ANALYZING_MACOS = "The expected analyzing macos log has not been produced"
GENERIC_CALLBACK_ERROR_TARGET_SOCKET = "The expected target socket log has not been produced"
GENERIC_CALLBACK_ERROR_TARGET_SOCKET_NOT_FOUND = "The expected target socket not found error has not been produced"
LOG_COLLECTOR_GLOBAL_TIMEOUT = 20
GENERIC_CALLBACK_ERROR_READING_FILE = "The expected invalid content error log has not been produced"
GENERIC_CALLBACK_ERROR = 'The expected error output has not been produced'

LOG_COLLECTOR_GLOBAL_TIMEOUT = 30

DEFAULT_AUTHD_REMOTED_SIMULATOR_CONFIGURATION = {
'ip_address': 'localhost',
'client_keys': os.path.join(WAZUH_PATH, 'etc', 'client.keys'),
Expand Down Expand Up @@ -690,6 +691,37 @@ def callback_invalid_state_interval(interval):
return monitoring.make_callback(pattern=msg, prefix=prefix, escape=True)


def callback_logcollector_started():
"""Check if logcollector started."""
return monitoring.make_callback(pattern='Started', prefix=prefix)


def callback_log_bad_predicate():
"""Check for the macOS ULS bad predicate message."""
return monitoring.make_callback(pattern="Execution error 'log:", prefix=prefix)


def callback_macos_uls_log(expected_message):
"""Callback function to wait for a macOS' ULS log, collected by logcollector."""
return monitoring.make_callback(pattern=expected_message, prefix=prefix, escape=False)


def callback_logcollector_log_stream_log():
"""Check for logcollector's macOS ULS module start message."""
return monitoring.make_callback(pattern='Monitoring macOS logs with:(.+?)log stream',
prefix=prefix, escape=False)


def callback_file_status_macos_key(line):
"""Check for 'macos' key."""
return monitoring.make_callback(pattern='"macos"', prefix='')


def callback_log_macos_stream_exit():
"""Check for the macOS ULS log stream exit message."""
return monitoring.make_callback(pattern="macOS 'log stream' process exited, pid:", prefix=prefix)


def wait_statistics_file(timeout=LOG_COLLECTOR_GLOBAL_TIMEOUT):
"""Wait until statistics file is available.
Expand Down Expand Up @@ -766,6 +798,7 @@ def format_macos_message_pattern(process_name, message, type='log', subsystem=No

return macos_message


def compose_macos_log_command(type='', level='', predicate='', is_sierra=False):
"""
This function replicates how the command 'log' will be called from the Wazuh agent given the query parameters
Expand All @@ -775,7 +808,7 @@ def compose_macos_log_command(type='', level='', predicate='', is_sierra=False):
level (str): < default | info | debug > Include events at, and below, the given level.
predicate (str): Filter events using the given predicate.
is_sierra (boolean): True if running on macOS Sierra, False otherwise.
Returns:
string: Full log command composed with the given parameters.
"""
Expand Down
12 changes: 11 additions & 1 deletion tests/integration/test_logcollector/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import pytest
import wazuh_testing.tools.configuration as conf
from wazuh_testing.logcollector import LOGCOLLECTOR_DEFAULT_LOCAL_INTERNAL_OPTIONS
from wazuh_testing.tools import LOG_FILE_PATH
from wazuh_testing.tools import LOG_FILE_PATH, LOGCOLLECTOR_FILE_STATUS_PATH
from wazuh_testing.tools.file import truncate_file
from wazuh_testing.tools.monitoring import FileMonitor
from wazuh_testing.tools.services import control_service
from wazuh_testing.tools.remoted_sim import RemotedSimulator
from wazuh_testing.tools.authd_sim import AuthdSimulator
from wazuh_testing.tools import CLIENT_CUSTOM_KEYS_PATH, CLIENT_CUSTOM_CERT_PATH
from os.path import exists
from os import remove

DAEMON_NAME = "wazuh-logcollector"

Expand Down Expand Up @@ -86,3 +88,11 @@ def configure_local_internal_options_logcollector():
control_service('restart')
else:
yield


@pytest.fixture(scope='function')
def delete_file_status_json():
"""Delete file_status.json from logcollector"""
remove(LOGCOLLECTOR_FILE_STATUS_PATH) if exists(LOGCOLLECTOR_FILE_STATUS_PATH) else None

yield
Original file line number Diff line number Diff line change
Expand Up @@ -2,144 +2,96 @@
# Created by Wazuh, Inc. <info@wazuh.com>.
# This program is free software; you can redistribute it and/or modify it under the terms of GPLv2

import os
import re
import pytest
import wazuh_testing.logcollector as logcollector

from wazuh_testing.tools import LOGCOLLECTOR_FILE_STATUS_PATH, LOG_FILE_PATH, WAZUH_LOCAL_INTERNAL_OPTIONS
from wazuh_testing.tools.monitoring import FileMonitor, wait_file, make_callback
from wazuh_testing.tools.configuration import load_wazuh_configurations
from wazuh_testing.logcollector import prefix as logcollector_prefix
from wazuh_testing.tools.file import read_json, truncate_file
from wazuh_testing.tools.services import control_service
from wazuh_testing.logcollector import LOG_COLLECTOR_GLOBAL_TIMEOUT
from wazuh_testing.tools.monitoring import FileMonitor, wait_file
from wazuh_testing.tools import LOGCOLLECTOR_FILE_STATUS_PATH
from wazuh_testing.tools.file import read_json
from os.path import dirname, join, realpath
from re import match


# Marks
pytestmark = [pytest.mark.darwin, pytest.mark.tier(level=0)]

# Configuration
test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data')
configurations_path = os.path.join(test_data_path, 'wazuh_macos_file_status_basic.yaml')
test_data_path = join(dirname(realpath(__file__)), 'data')
configurations_path = join(test_data_path, 'wazuh_macos_file_status_basic.yaml')

parameters = [{'ONLY_FUTURE_EVENTS': 'yes'}, {'ONLY_FUTURE_EVENTS': 'no'}]
metadata = [{'only-future-events': 'yes'}, {'only-future-events': 'no'}]

daemons_handler_configuration = {'daemons': ['wazuh-agentd', 'wazuh-logcollector'], 'ignore_errors': False}

# Configuration data
configurations = load_wazuh_configurations(configurations_path, __name__, params=parameters, metadata=metadata)
configuration_ids = [f"{x['ONLY_FUTURE_EVENTS']}" for x in parameters]

daemons_handler_configuration = {'daemons': ['wazuh-logcollector'], 'ignore_errors': False}
configuration_ids = [f"only_future_events_{x['ONLY_FUTURE_EVENTS']}" for x in parameters]

# Max number of characters to be displayed in the log's debug message
sample_log_length = 100
# Time in seconds to update the file_status.json
file_status_update_time = 4

local_internal_options = { 'logcollector.debug': 2,
'logcollector.vcheck_files': file_status_update_time,
'logcollector.sample_log_length': sample_log_length }
local_internal_options = {'logcollector.debug': 2,
'logcollector.vcheck_files': file_status_update_time,
'logcollector.sample_log_length': sample_log_length}

macos_message = { 'command': 'logger',
'message': 'Logger testing message - file status' }

# Maximum waiting time in seconds to find the logs on ossec.log
file_monitor_timeout = 30
macos_message = {'command': 'logger',
'message': 'Logger testing message - file status'}

# Expected message to be used on the "callback_macos_uls_log" callback
expected_message = logcollector.format_macos_message_pattern(macos_message['command'], macos_message['message'])

wazuh_log_monitor = None


# Fixtures
@pytest.fixture(scope='module')
def startup_cleanup():
"""Truncate ossec.log and remove logcollector's file_status.json file."""
truncate_file(WAZUH_LOCAL_INTERNAL_OPTIONS)


@pytest.fixture(scope='module', params=configurations, ids=configuration_ids)
def get_configuration(request):
"""Get configurations from the module."""
return request.param


@pytest.fixture(scope='module')
def restart_required_logcollector_daemons():
"""Wazuh logcollector daemons handler."""

required_logcollector_daemons = ['wazuh-logcollector']

for daemon in required_logcollector_daemons:
control_service('stop', daemon=daemon)

truncate_file(LOG_FILE_PATH)
os.remove(LOGCOLLECTOR_FILE_STATUS_PATH) if os.path.exists(LOGCOLLECTOR_FILE_STATUS_PATH) else None

for daemon in required_logcollector_daemons:
control_service('start', daemon=daemon)

yield

for daemon in required_logcollector_daemons:
control_service('stop', daemon=daemon)


def callback_macos_uls_log():
"""Callback function to wait for the macOS' ULS log collected by logcollector."""
return make_callback(pattern=expected_message, prefix=logcollector_prefix, escape=False)


def callback_logcollector_log_stream_log():
"""Check for logcollector's macOS ULS module start message."""
return make_callback(pattern='Monitoring macOS logs with:(.+?)log stream', prefix=logcollector_prefix, escape=False)


def callback_file_status_macos_key(line):
"""Check for 'macos' key."""
return make_callback(pattern='"macos"', prefix='')


def test_macos_file_status_basic(startup_cleanup,
configure_local_internal_options_module,
def test_macos_file_status_basic(delete_file_status_json,
configure_local_internal_options_module,
get_configuration,
configure_environment,
restart_required_logcollector_daemons):
file_monitoring,
daemons_handler):
"""Checks if logcollector stores correctly "macos"-formatted localfile data.
This test uses logger tool and a custom log to generate an ULS event. The agent is connected to the authd simulator
and sends an event to trigger the file_status.json update.
This test uses logger tool and a custom log to generate an ULS event. When logcollector receives a valid log, then
the file_status.json is updated.
Raises:
TimeoutError: If the callbacks, that checks the expected logs, are not satisfied in the expected time.
FileNotFoundError: If the file_status.json is not available in the expected time.
"""

wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)

wazuh_log_monitor.start(timeout=file_monitor_timeout,
callback=logcollector.callback_monitoring_macos_logs,
error_message=logcollector.GENERIC_CALLBACK_ERROR_TARGET_SOCKET)
log_monitor.start(timeout=LOG_COLLECTOR_GLOBAL_TIMEOUT,
callback=logcollector.callback_monitoring_macos_logs,
error_message=logcollector.GENERIC_CALLBACK_ERROR_TARGET_SOCKET)

# Watches the ossec.log to check when logcollector starts the macOS ULS module
wazuh_log_monitor.start(timeout=file_monitor_timeout,
callback=callback_logcollector_log_stream_log(),
error_message='Logcollector did not start')
log_monitor.start(timeout=LOG_COLLECTOR_GLOBAL_TIMEOUT,
callback=logcollector.callback_logcollector_log_stream_log(),
error_message='Logcollector did not start.')

logcollector.generate_macos_logger_log(macos_message['message'])

wazuh_log_monitor.start(timeout=file_monitor_timeout,
callback=callback_macos_uls_log(),
error_message='MacOS ULS log was not found')
log_monitor.start(timeout=LOG_COLLECTOR_GLOBAL_TIMEOUT,
callback=logcollector.callback_macos_uls_log(expected_message),
error_message="MacOS ULS log was not found: '{}'.".format(expected_message))

# Waits for file_status.json to be created, with a timeout about the time needed to update the file
wait_file(LOGCOLLECTOR_FILE_STATUS_PATH, file_monitor_timeout)
wait_file(LOGCOLLECTOR_FILE_STATUS_PATH, LOG_COLLECTOR_GLOBAL_TIMEOUT)

# Watches the file_status.json file for the "macos" key
file_status_monitor = FileMonitor(LOGCOLLECTOR_FILE_STATUS_PATH)
file_status_monitor.start(timeout=file_monitor_timeout,
callback=callback_file_status_macos_key,
error_message="The 'macos' key could not be found on the file_status.json file")

file_status_monitor.start(timeout=LOG_COLLECTOR_GLOBAL_TIMEOUT,
callback=logcollector.callback_file_status_macos_key,
error_message="The 'macos' key could not be found on the file_status.json file")

file_status_json = read_json(LOGCOLLECTOR_FILE_STATUS_PATH)

Expand All @@ -152,13 +104,10 @@ def test_macos_file_status_basic(startup_cleanup,

assert file_status_json['macos']['timestamp'], "Error finding 'timestamp' key inside 'macos'"

assert re.match(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}-\d{4}$',
file_status_json['macos']['timestamp']), \
'Error of timestamp format'
assert match(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[-+]\d{4}$', file_status_json['macos']['timestamp']), \
'Error of timestamp format'

assert file_status_json['macos']['settings'], "Error finding 'settings' key inside 'macos'"

assert file_status_json['macos']['settings'] \
== logcollector.compose_macos_log_command(conf_type,
conf_level,
conf_predicate)
== logcollector.compose_macos_log_command(conf_type, conf_level, conf_predicate)
Loading

0 comments on commit c9a41b4

Please sign in to comment.