Skip to content

Commit

Permalink
ITs further fixes and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
nmkoremblum committed Sep 27, 2021
1 parent aeeeb21 commit e180804
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
apply_to_modules:
- test_macos_file_status_when_no_macos
sections:
- section: client
- section: localfile
attributes:
- name: 'localfile_dummy_block'
elements:
- server:
elements:
- address:
value: '127.0.0.1'
- protocol:
value: 'tcp'
- location:
value: FILE_TO_MONITOR
- log_format:
value: 'syslog'
- only-future-events:
value: 'yes'
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import pytest
import wazuh_testing.logcollector as logcollector

from wazuh_testing.tools import LOGCOLLECTOR_FILE_STATUS_PATH, LOG_FILE_PATH
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.tools.monitoring import FileMonitor, wait_file
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

# Marks
pytestmark = [pytest.mark.darwin, pytest.mark.tier(level=0)]
Expand All @@ -33,7 +35,8 @@
# Time in seconds to update the file_status.json
file_status_update_time = 4

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

macos_message = { 'command': 'logger',
Expand All @@ -42,17 +45,18 @@
# Maximum waiting time in seconds to find the logs on ossec.log
file_monitor_timeout = 30

wazuh_log_monitor = None

# 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(LOG_FILE_PATH)
os.remove(LOGCOLLECTOR_FILE_STATUS_PATH) if os.path.exists(LOGCOLLECTOR_FILE_STATUS_PATH) else None
truncate_file(WAZUH_LOCAL_INTERNAL_OPTIONS)


@pytest.fixture(scope='module')
def get_local_internal_options():
Expand All @@ -66,34 +70,47 @@ def get_configuration(request):
return request.param


def wait_macos_uls_log(line):
"""Callback function to wait for the macOS' ULS log collected by logcollector."""
if re.search(expected_message, line):
return True
@pytest.fixture(scope='module')
def restart_required_logcollector_daemons():
"""Wazuh logcollector daemons handler."""

return None
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 wait_logcollector_log_stream(line):
"""Check if 'line' has the logcollector's macOS ULS module start message."""
if re.search(r'Monitoring macOS logs with: (.+?)log stream', line):
return True

return None
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 wait_macos_key_file_status(line):
"""Check if 'line' has the 'macos' key on it."""
if re.search(r'macos', line):
return True

return None
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,
configure_local_internal_options_module,
get_configuration,
configure_environment,
daemons_handler):
restart_required_logcollector_daemons):
"""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
Expand All @@ -112,13 +129,13 @@ def test_macos_file_status_basic(startup_cleanup,

# Watches the ossec.log to check when logcollector starts the macOS ULS module
wazuh_log_monitor.start(timeout=file_monitor_timeout,
callback=wait_logcollector_log_stream,
callback=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=wait_macos_uls_log,
callback=callback_macos_uls_log(),
error_message='MacOS ULS log was not found')

# Waits for file_status.json to be created, with a timeout about the time needed to update the file
Expand All @@ -127,7 +144,7 @@ def test_macos_file_status_basic(startup_cleanup,
# 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=wait_macos_key_file_status,
callback=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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import re

# from wazuh_testing.logcollector import DEFAULT_AUTHD_REMOTED_SIMULATOR_CONFIGURATION
from wazuh_testing.tools import LOGCOLLECTOR_FILE_STATUS_PATH, LOG_FILE_PATH
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.tools.monitoring import FileMonitor, wait_file
from wazuh_testing.logcollector import prefix as logcollector_prefix
from wazuh_testing.tools.file import read_json, truncate_file

# Marks
Expand Down Expand Up @@ -46,44 +47,32 @@
@pytest.fixture(scope='module')
def startup_cleanup():
"""Truncate ossec.log and remove logcollector's file_status.json file."""
truncate_file(WAZUH_LOCAL_INTERNAL_OPTIONS)
truncate_file(LOG_FILE_PATH)
os.remove(LOGCOLLECTOR_FILE_STATUS_PATH) if os.path.exists(LOGCOLLECTOR_FILE_STATUS_PATH) else None


@pytest.fixture(scope='module')
def get_local_internal_options():
"""Get configurations from the module."""
return local_internal_options


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


def callback_log_bad_predicate(line):
def callback_log_bad_predicate():
"""Check if 'line' has the macOS ULS bad predicate message on it."""
match = re.match(r'.*Execution error \'log:', line)
if match:
return True
return None
return make_callback(pattern="Execution error 'log:", prefix=logcollector_prefix)


def callback_log_exit_log(line):
def callback_log_exit_log():
"""Check if 'line' has the macOS ULS log stream exited message on it."""
match = re.match(r'.*macOS \'log stream\' process exited, pid:', line)
if match:
return True
return None
return make_callback(pattern="macOS 'log stream' process exited, pid:", prefix=logcollector_prefix)


def test_macos_file_status_predicate(startup_cleanup,
configure_local_internal_options,
configure_local_internal_options_module,
get_configuration,
configure_environment,
daemons_handler):

"""Checks that logcollector does not store 'macos'-formatted localfile data since its predicate is erroneous.
The agent is connected to the authd simulator and uses a dummy localfile (/Library/Ossec/logs/active-responses.log)
Expand All @@ -96,12 +85,12 @@ def test_macos_file_status_predicate(startup_cleanup,
wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)

wazuh_log_monitor.start(timeout=file_monitor_timeout,
callback=callback_log_bad_predicate,
callback=callback_log_bad_predicate(),
error_message='Expected log that matches the regex '
'".*Execution error \'log:" could not be found')

wazuh_log_monitor.start(timeout=file_monitor_timeout,
callback=callback_log_exit_log,
callback=callback_log_exit_log(),
error_message='Expected log that matches the regex '
'".*macOS \'log stream\' process exited, pid:" could not be found')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
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.file import read_json, write_json_file, truncate_file
from wazuh_testing.tools import LOGCOLLECTOR_FILE_STATUS_PATH, LOG_FILE_PATH
from wazuh_testing.tools.configuration import load_wazuh_configurations
from wazuh_testing.tools.monitoring import FileMonitor, wait_file
from wazuh_testing.logcollector import prefix as logcollector_prefix
from wazuh_testing.tools.services import control_service
from tempfile import gettempdir
from time import sleep

# Marks
Expand All @@ -19,10 +22,12 @@
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_when_no_macos.yaml')

daemons_handler_configuration = {'daemons': ['wazuh-logcollector'], 'ignore_errors': False}
dummy_file = os.path.join(gettempdir(), 'dummy_file.log')
parameters = [{'FILE_TO_MONITOR': dummy_file}]

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

# Max number of characters to be displayed in the log's debug message
sample_log_length = 100
Expand All @@ -35,37 +40,59 @@
# Maximum waiting time in seconds to find the logs on ossec.log
file_monitor_timeout = 30

# Time to wait for file_status.json to be updated
wait_file_status_update_time = file_status_update_time + 2

wazuh_log_monitor = None


# Fixtures
@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 startup_cleanup():
"""Truncate ossec.log and remove logcollector's file_status.json file."""
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)


@pytest.fixture(scope='module')
def get_local_internal_options():
"""Get configurations from the module."""
return local_internal_options
def startup_cleanup():
"""Truncate local_internals file and create dummy file to be monitored by logcollector."""
truncate_file(WAZUH_LOCAL_INTERNAL_OPTIONS)

with open(dummy_file, 'w') as f:
pass

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

def callback_logcollector_started():
"""Check for 'macos' key."""
return make_callback(pattern='Started', prefix=logcollector_prefix)


def test_macos_file_status_when_no_macos(startup_cleanup,
configure_local_internal_options,
configure_local_internal_options_module,
get_configuration,
configure_environment,
daemons_handler):

restart_required_logcollector_daemons):
"""Checks that logcollector does not store and removes, if exists, previous "macos"-formatted localfile data in the
file_status.json
Expand All @@ -77,10 +104,14 @@ def test_macos_file_status_when_no_macos(startup_cleanup,
TimeoutError: If the callbacks, that checks the expected logs, are not satisfied in the expected time.
"""

file_status_json = ''
file_status_json = {}

wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)

wazuh_log_monitor.start(timeout=file_monitor_timeout,
callback=callback_logcollector_started(),
error_message="Logcollector did not start")

# Check if json_status contains 'macos' data and if not insert it
if os.path.exists(LOGCOLLECTOR_FILE_STATUS_PATH):
file_status_json = read_json(LOGCOLLECTOR_FILE_STATUS_PATH)
Expand Down

0 comments on commit e180804

Please sign in to comment.