Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Integration and system tests to ensure removed agent files are deleted" #2014

Merged
merged 1 commit into from
Oct 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions deps/wazuh_testing/wazuh_testing/tools/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def make_api_call(self, host, port=55000, method='GET', endpoint='/', request_bo
token (str, optional): Request token. Default `None`
check ( bool, optional): Ansible check mode("Dry Run")(https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html), by default it is enabled so no changes will be applied. Default `False`

Returns:
Returns:
API response (dict) : Return the response in JSON format.
"""
request_body = 'body="{}"'.format(
Expand All @@ -229,18 +229,3 @@ def run_command(self, host: str, cmd: str, check: bool = False):
stdout (str): The output of the command execution.
"""
return self.get_host(host).ansible("command", cmd, check=check)["stdout"]

def run_shell(self, host: str, cmd: str, check: bool = False):
"""Run a shell command on the specified host and return its stdout.

The difference with run_command is that here, shell symbols like &, |, etc. are interpreted.

Args:
host (str) : Hostname
cmd (str): Shell command to execute
check (bool, optional): Ansible check mode("Dry Run")(https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html), by default it is enabled so no changes will be applied. Default `False`

Returns:
stdout (str): The output of the command execution.
"""
return self.get_host(host).ansible('shell', cmd, check=check)['stdout']

This file was deleted.

1 change: 0 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,6 @@ nav:
- Test cluster:
- tests/system/test_cluster/index.md
- Test agent info sync: tests/system/test_cluster/test_agent_info_sync/test_agent_info_sync.md
- Test agent files deletion: tests/system/test_cluster/test_agent_files_deletion/test_agent_files_deletion.md
- Test agent enrollment: tests/system/test_cluster/test_agent_enrollment/test_agent_enrollment.md
- Test agent key polling: tests/system/test_cluster/test_agent_key_polling/test_agent_key_polling.md
- Test integrity sync: tests/system/test_cluster/test_integrity_sync/test_integrity_sync.md
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,3 @@
input: 'agent 000 sql SELECT * FROM vuln_cves'
output: 'ok []'
stage: "agent vuln_cve checking empty table again"
-
name: 'Not existing agent'
description: 'Check messages from not registered agents.'
test_case:
-
input: 'agent 003 syscheck delete'
output: 'err Agent not found'
stage: 'Syscheck query to a non-existing agent'
Original file line number Diff line number Diff line change
Expand Up @@ -372,15 +372,15 @@
stage: "global setting sync_status before disconnecting-agents command"
-
input: 'global disconnect-agents 0 175 syncreq'
output: 'ok [{"id":1},{"id":2}]'
output: 'ok [{"id":1}]'
stage: "global disconnect-agents success"
-
input: 'global sql SELECT id,sync_status FROM agent WHERE id =1'
output: 'ok [{"id":1,"sync_status":"syncreq"}]'
stage: "global testing sync_status after disconnecting-agents command"
-
input: 'global get-agents-by-connection-status 0 disconnected'
output: 'ok [{"id":1},{"id":2}]'
output: 'ok [{"id":1}]'
stage: "global get-agents-by-connection-status disconnected after disconnecting agents success"
-
name: "Delete commands"
Expand Down
206 changes: 51 additions & 155 deletions tests/integration/test_wazuh_db/test_wazuh_db.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import os
import re
import time
import json

import pytest
import yaml
from wazuh_testing.tools import WAZUH_PATH
from wazuh_testing.tools.services import control_service, delete_dbs
from wazuh_testing.tools.wazuh_manager import remove_all_agents

# Marks

Expand All @@ -15,19 +13,11 @@
# Configurations

test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data')
agent_message_files = os.path.join(test_data_path, 'agent')
global_message_files = os.path.join(test_data_path, 'global')

agent_module_tests = []
global_module_tests = []

for file in os.listdir(agent_message_files):
with open(os.path.join(agent_message_files, file)) as f:
agent_module_tests.append((yaml.safe_load(f), file.split('_')[0]))

for file in os.listdir(global_message_files):
with open(os.path.join(global_message_files, file)) as f:
global_module_tests.append((yaml.safe_load(f), file.split('_')[0]))
messages_files = os.listdir(test_data_path)
module_tests = list()
for file in messages_files:
with open(os.path.join(test_data_path, file)) as f:
module_tests.append((yaml.safe_load(f), file.split("_")[0]))

# Variables

Expand All @@ -50,174 +40,80 @@


def regex_match(regex, string):
regex = regex.replace('*', '.*')
regex = regex.replace('[', '')
regex = regex.replace(']', '')
regex = regex.replace('(', '')
regex = regex.replace(')', '')
string = string.replace('[', '')
string = string.replace(']', '')
string = string.replace('(', '')
string = string.replace(')', '')
regex = regex.replace("*", ".*")
regex = regex.replace("[", "")
regex = regex.replace("]", "")
regex = regex.replace("(", "")
regex = regex.replace(")", "")
string = string.replace("[", "")
string = string.replace("]", "")
string = string.replace("(", "")
string = string.replace(")", "")
return re.match(regex, string)


@pytest.fixture(scope="module")
def clean_registered_agents():
remove_all_agents('wazuhdb')
time.sleep(5)

# Tests

@pytest.fixture(scope='module')
@pytest.fixture(scope="function")
def pre_insert_agents():
"""Insert agents. Only used for the global queries"""
AGENTS_CANT = 14000
AGENTS_OFFSET = 20
for id in range(AGENTS_OFFSET, AGENTS_OFFSET + AGENTS_CANT):
insert_agent(id)

yield

for id in range(AGENTS_OFFSET, AGENTS_OFFSET + AGENTS_CANT):
remove_agent(id)


@pytest.fixture(scope='function')
def insert_agents_test():
"""Insert agents. Only used for the agent queries"""
agent_list = [1, 2]
for agent in agent_list:
insert_agent(agent)

yield

for agent in agent_list:
remove_agent(agent)


@pytest.fixture(scope='module')
def restart_wazuh(request):
control_service('start')
yield

delete_dbs()
control_service('stop')


def execute_wazuh_db_query(command):
"""Function to send a command to the wazuh-db socket.
Args:
command(str): Message to send to the socket.
Returns:
str: A response from the socket
"""
receiver_sockets[0].send(command, size=True)
return receiver_sockets[0].receive(size=True).decode()


def insert_agent(agent_id, agent_name='TestName'):
"""Function that wraps the needed queries to register an agent.
Args:
agent_id(int): Unique identifier of an agent
Raises:
AssertionError: If the agent couldn't be inserted in the DB
"""
insert_data = json.dumps({'id': agent_id,
'name': f"{agent_name}{agent_id}",
'date_add': 1599223378
})

update_data = json.dumps({'id': agent_id,
'sync_status': 'syncreq',
'connection_status': 'active'
})
command = f'global insert-agent {{"id":{id},"name":"TestName{id}","date_add":1599223378}}'
receiver_sockets[0].send(command, size=True)
response = receiver_sockets[0].receive(size=True).decode()
data = response.split(" ", 1)
assert data[0] == 'ok', f'Unable to add agent {id}'

command = f"global insert-agent {insert_data}"
data = execute_wazuh_db_query(command).split(' ', 1)
assert data[0] == 'ok', f"Unable to add agent {agent_id} - {data[1]}"
command = f'global update-keepalive {{"id":{id},"sync_status":"syncreq","connection_status":"active"}}'
receiver_sockets[0].send(command, size=True)
response = receiver_sockets[0].receive(size=True).decode()
data = response.split(" ", 1)
assert data[0] == 'ok', f'Unable to update agent {id}'

command = f"global update-keepalive {update_data}"
data = execute_wazuh_db_query(command).split(' ', 1)
assert data[0] == 'ok', f"Unable to update agent {agent_id} - {data[1]}"


def remove_agent(agent_id):
"""Function that wraps the needed queries to remove an agent.
Args:
agent_id(int): Unique identifier of an agent
"""
data = execute_wazuh_db_query(f"global delete-agent {agent_id}").split(' ', 1)
assert data[0] == 'ok', f"Unable to remove agent {agent_id} - {data[1]}"


# Tests

@pytest.mark.parametrize('test_case',
[case['test_case'] for module_data in agent_module_tests for case in module_data[0]],
[case['test_case'] for module_data in module_tests for case in module_data[0]],
ids=[f"{module_name}: {case['name']}"
for module_data, module_name in agent_module_tests
for module_data, module_name in module_tests
for case in module_data]
)
def test_wazuh_db_messages_agent(restart_wazuh, clean_registered_agents, configure_sockets_environment,
connect_to_sockets_module, insert_agents_test, test_case):
"""Check that every input agent message in wazuh-db socket generates the adequate output to wazuh-db socket.

Args:
test_case(list): List of test_case stages (dicts with input, output and stage keys).
"""
def test_wazuh_db_messages(configure_sockets_environment, connect_to_sockets_module, test_case: list):
for index, stage in enumerate(test_case):
if 'ignore' in stage and stage['ignore'] == 'yes':
if 'ignore' in stage and stage['ignore'] == "yes":
continue

command = stage['input']
expected_output = stage['output']

response = execute_wazuh_db_query(command)
expected = stage['output']
receiver_sockets[0].send(stage['input'], size=True)
response = receiver_sockets[0].receive(size=True).decode()

if 'use_regex' in stage and stage['use_regex'] == 'yes':
match = True if regex_match(expected_output, response) else False
match = True if regex_match(expected, response) else False
else:
match = (expected_output == response)
match = (expected == response)
assert match, 'Failed test case stage {}: {}. Expected: {}. Response: {}' \
.format(index + 1, stage['stage'], expected_output, response)
.format(index + 1, stage['stage'], expected, response)


@pytest.mark.parametrize('test_case',
[case['test_case'] for module_data in global_module_tests for case in module_data[0]],
ids=[f"{module_name}: {case['name']}"
for module_data, module_name in global_module_tests
for case in module_data]
)
def test_wazuh_db_messages_global(connect_to_sockets_module, restart_wazuh, test_case):
"""Check that every input global message in wazuh-db socket generates the adequate output to wazuh-db socket.
def test_wazuh_db_create_agent(test_case, connect_to_sockets_module):
test = {"name": "Create agent",
"description": "Wazuh DB creates automatically the agent's database the first time a query with a new agent"
" ID reaches it. Once the database is created, the query is processed as expected.",
"test_case": [{"input": "agent 999 syscheck integrity_check_left",
"output": "err Invalid FIM query syntax, near 'integrity_check_left'",
"stage": "Syscheck - Agent does not exits yet"}]}
test_wazuh_db_messages(configure_sockets_environment, connect_to_sockets_module, test['test_case'])
assert os.path.exists(os.path.join(WAZUH_PATH, 'queue', 'db', "999.db"))

Args:
test_case(list): List of test_case stages (dicts with input, output and stage keys).
"""
for index, stage in enumerate(test_case):
if 'ignore' in stage and stage['ignore'] == 'yes':
continue

command = stage['input']
expected_output = stage['output']

response = execute_wazuh_db_query(command)

if 'use_regex' in stage and stage['use_regex'] == 'yes':
match = True if regex_match(expected_output, response) else False
else:
match = (expected_output == response)
assert match, 'Failed test case stage {}: {}. Expected: {}. Response: {}' \
.format(index + 1, stage['stage'], expected_output, response)


def test_wazuh_db_chunks(restart_wazuh, configure_sockets_environment, clean_registered_agents,
connect_to_sockets_module, pre_insert_agents):
def test_wazuh_db_chunks(configure_sockets_environment, connect_to_sockets_module, pre_insert_agents):
"""Check that commands by chunks work properly when agents amount exceed the response maximum size"""

def send_chunk_command(command):
response = execute_wazuh_db_query(command)
status = response.split(' ', 1)[0]
receiver_sockets[0].send(command, size=True)
response = receiver_sockets[0].receive(size=True).decode()

status = response.split(" ", 1)[0]
assert status == 'due', 'Failed chunks check on < {} >. Expected: {}. Response: {}' \
.format(command, 'due', status)

Expand Down
15 changes: 7 additions & 8 deletions tests/system/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,13 @@ our [testing environment guide](#setting-up-a-test-environment).
Our cluster system tests are located in `wazuh-qa/tests/system/`. They are organized by functionalities and each one may
required an specific testing environment located in `wazuh-qa/tests/system/provisioning`:

| Functionality | Required environment |
|----------------------------------------|----------------------|
| test_cluster/test_agent_enrollment | enrollment_cluster |
| test_cluster/test_agent_info_sync | basic_cluster |
| test_cluster/test_agent_key_polling | basic_cluster |
| test_cluster/test_agent_files_deletion | basic_cluster |
| test_cluster/test_integrity_sync | agentless_cluster |
| test_jwt_invalidation | agentless_cluster |
| Functionality | Required environment |
|-------------------------------------|----------------------|
| test_cluster/test_agent_enrollment | enrollment_cluster |
| test_cluster/test_agent_info_sync | basic_cluster |
| test_cluster/test_agent_key_polling | basic_cluster |
| test_cluster/test_integrity_sync | agentless_cluster |
| test_jwt_invalidation | agentless_cluster |

### Test structure

Expand Down
Loading