mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
516 lines
17 KiB
Python
516 lines
17 KiB
Python
"""
|
|
unit tests for the slack engine
|
|
"""
|
|
import pytest
|
|
|
|
import salt.config
|
|
import salt.engines.slack_bolt_engine as slack_bolt_engine
|
|
from tests.support.mock import MagicMock, call, patch
|
|
|
|
pytestmark = [
|
|
pytest.mark.skipif(
|
|
slack_bolt_engine.HAS_SLACKBOLT is False,
|
|
reason="The slack_bolt is not installed",
|
|
)
|
|
]
|
|
|
|
|
|
class MockRunnerClient:
|
|
"""
|
|
Mock RunnerClient class
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
def asynchronous(self, *args, **kwargs):
|
|
"""
|
|
Mock asynchronous method
|
|
"""
|
|
return True
|
|
|
|
|
|
class MockLocalClient:
|
|
"""
|
|
Mock RunnerClient class
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
def __enter__(self, *args, **kwargs):
|
|
return self
|
|
|
|
def __exit__(self, *args, **kwargs):
|
|
pass
|
|
|
|
def cmd_async(self, *args, **kwargs):
|
|
"""
|
|
Mock cmd_async method
|
|
"""
|
|
return True
|
|
|
|
|
|
class MockSlackBoltSocketMode:
|
|
def __init__(self, *args, **kwargs):
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
def connect(self, *args, **kwargs):
|
|
return True
|
|
|
|
|
|
class MockSlackBoltApp:
|
|
def __init__(self, *args, **kwargs):
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
self.client = MockSlackBoltAppClient()
|
|
self.logger = None
|
|
self.proxy = None
|
|
|
|
def message(self, *args, **kwargs):
|
|
return MagicMock(return_value=True)
|
|
|
|
|
|
class MockSlackBoltAppClient:
|
|
def __init__(self, *args, **kwargs):
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
|
|
def chat_postMessage(self, *args, **kwargs):
|
|
return MagicMock(return_value=True)
|
|
|
|
def files_upload(self, *args, **kwargs):
|
|
return MagicMock(return_value=True)
|
|
|
|
|
|
@pytest.fixture
|
|
def configure_loader_modules():
|
|
return {slack_bolt_engine: {}}
|
|
|
|
|
|
@pytest.fixture
|
|
def slack_client(minion_opts):
|
|
mock_opts = salt.config.DEFAULT_MINION_OPTS.copy()
|
|
app_token = "xapp-x-xxxxxxxxxxx-xxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
bot_token = "xoxb-xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
trigger = "!"
|
|
|
|
with patch.dict(slack_bolt_engine.__opts__, minion_opts):
|
|
with patch(
|
|
"slack_bolt.App", MagicMock(autospec=True, return_value=MockSlackBoltApp())
|
|
):
|
|
with patch(
|
|
"slack_bolt.adapter.socket_mode.SocketModeHandler",
|
|
MagicMock(autospec=True, return_value=MockSlackBoltSocketMode()),
|
|
):
|
|
slack_client = slack_bolt_engine.SlackClient(
|
|
app_token, bot_token, trigger
|
|
)
|
|
yield slack_client
|
|
|
|
|
|
def test_control_message_target(slack_client):
|
|
"""
|
|
Test slack engine: control_message_target
|
|
"""
|
|
trigger_string = "!"
|
|
|
|
loaded_groups = {
|
|
"default": {
|
|
"targets": {},
|
|
"commands": {"cmd.run", "test.ping"},
|
|
"default_target": {"tgt_type": "glob", "target": "*"},
|
|
"users": {"gareth"},
|
|
"aliases": {
|
|
"whoami": {"cmd": "cmd.run whoami"},
|
|
"list_pillar": {"cmd": "pillar.items"},
|
|
},
|
|
}
|
|
}
|
|
|
|
slack_user_name = "gareth"
|
|
|
|
# Check for correct cmdline
|
|
_expected = (True, {"tgt_type": "glob", "target": "*"}, ["cmd.run", "whoami"])
|
|
text = "!cmd.run whoami"
|
|
target_commandline = slack_client.control_message_target(
|
|
slack_user_name, text, loaded_groups, trigger_string
|
|
)
|
|
|
|
assert target_commandline == _expected
|
|
|
|
# Check aliases result in correct cmdline
|
|
text = "!whoami"
|
|
target_commandline = slack_client.control_message_target(
|
|
slack_user_name, text, loaded_groups, trigger_string
|
|
)
|
|
|
|
assert target_commandline == _expected
|
|
|
|
# Check pillar is overridden
|
|
_expected = (
|
|
True,
|
|
{"tgt_type": "glob", "target": "*"},
|
|
["pillar.items", 'pillar={"hello": "world"}'],
|
|
)
|
|
text = r"""!list_pillar pillar='{"hello": "world"}'"""
|
|
target_commandline = slack_client.control_message_target(
|
|
slack_user_name, text, loaded_groups, trigger_string
|
|
)
|
|
|
|
assert target_commandline == _expected
|
|
|
|
# Check target is overridden
|
|
_expected = (
|
|
True,
|
|
{"tgt_type": "glob", "target": "localhost"},
|
|
["cmd.run", "whoami"],
|
|
)
|
|
text = "!cmd.run whoami target='localhost'"
|
|
target_commandline = slack_client.control_message_target(
|
|
slack_user_name, text, loaded_groups, trigger_string
|
|
)
|
|
|
|
assert target_commandline == _expected
|
|
|
|
|
|
def test_run_commands_from_slack_async(slack_client):
|
|
"""
|
|
Test slack engine: test_run_commands_from_slack_async
|
|
"""
|
|
|
|
mock_job_status = {
|
|
"20221027001127600438": {
|
|
"data": {"minion": {"return": True, "retcode": 0, "success": True}},
|
|
"function": "test.ping",
|
|
}
|
|
}
|
|
|
|
message_generator = [
|
|
{
|
|
"message_data": {
|
|
"client_msg_id": "c1d0c13d-5e78-431e-9921-4786a7d27543",
|
|
"type": "message",
|
|
"text": '!test.ping target="minion"',
|
|
"user": "U02QY11UJ",
|
|
"ts": "1666829486.542159",
|
|
"blocks": [
|
|
{
|
|
"type": "rich_text",
|
|
"block_id": "2vdy",
|
|
"elements": [
|
|
{
|
|
"type": "rich_text_section",
|
|
"elements": [
|
|
{
|
|
"type": "text",
|
|
"text": '!test.ping target="minion"',
|
|
}
|
|
],
|
|
}
|
|
],
|
|
}
|
|
],
|
|
"team": "T02QY11UG",
|
|
"channel": "C02QY11UQ",
|
|
"event_ts": "1666829486.542159",
|
|
"channel_type": "channel",
|
|
},
|
|
"channel": "C02QY11UQ",
|
|
"user": "U02QY11UJ",
|
|
"user_name": "garethgreenaway",
|
|
"cmdline": ["test.ping"],
|
|
"target": {"target": "minion", "tgt_type": "glob"},
|
|
}
|
|
]
|
|
|
|
mock_files_upload_resp = {
|
|
"ok": True,
|
|
"file": {
|
|
"id": "F047YTDGJF9",
|
|
"created": 1666883749,
|
|
"timestamp": 1666883749,
|
|
"name": "salt-results-20221027081549173603.yaml",
|
|
"title": "salt-results-20221027081549173603",
|
|
"mimetype": "text/plain",
|
|
"filetype": "yaml",
|
|
"pretty_type": "YAML",
|
|
"user": "U0485K894PN",
|
|
"user_team": "T02QY11UG",
|
|
"editable": True,
|
|
"size": 18,
|
|
"mode": "snippet",
|
|
"is_external": False,
|
|
"external_type": "",
|
|
"is_public": True,
|
|
"public_url_shared": False,
|
|
"display_as_bot": False,
|
|
"username": "",
|
|
"url_private": "",
|
|
"url_private_download": "",
|
|
"permalink": "",
|
|
"permalink_public": "",
|
|
"edit_link": "",
|
|
"preview": "minion:\n True",
|
|
"preview_highlight": "",
|
|
"lines": 2,
|
|
"lines_more": 0,
|
|
"preview_is_truncated": False,
|
|
"comments_count": 0,
|
|
"is_starred": False,
|
|
"shares": {
|
|
"public": {
|
|
"C02QY11UQ": [
|
|
{
|
|
"reply_users": [],
|
|
"reply_users_count": 0,
|
|
"reply_count": 0,
|
|
"ts": "1666883749.485979",
|
|
"channel_name": "general",
|
|
"team_id": "T02QY11UG",
|
|
"share_user_id": "U0485K894PN",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"channels": ["C02QY11UQ"],
|
|
"groups": [],
|
|
"ims": [],
|
|
"has_rich_preview": False,
|
|
"file_access": "visible",
|
|
},
|
|
}
|
|
|
|
patch_app_client_files_upload = patch.object(
|
|
MockSlackBoltAppClient,
|
|
"files_upload",
|
|
MagicMock(autospec=True, return_value=mock_files_upload_resp),
|
|
)
|
|
patch_app_client_chat_postMessage = patch.object(
|
|
MockSlackBoltAppClient,
|
|
"chat_postMessage",
|
|
MagicMock(autospec=True, return_value=True),
|
|
)
|
|
patch_slack_client_run_until = patch.object(
|
|
slack_client, "_run_until", MagicMock(autospec=True, side_effect=[True, False])
|
|
)
|
|
patch_slack_client_run_command_async = patch.object(
|
|
slack_client,
|
|
"run_command_async",
|
|
MagicMock(autospec=True, return_value="20221027001127600438"),
|
|
)
|
|
patch_slack_client_get_jobs_from_runner = patch.object(
|
|
slack_client,
|
|
"get_jobs_from_runner",
|
|
MagicMock(autospec=True, return_value=mock_job_status),
|
|
)
|
|
|
|
upload_calls = call(
|
|
channels="C02QY11UQ",
|
|
content="minion:\n True",
|
|
filename="salt-results-20221027090136014442.yaml",
|
|
)
|
|
|
|
chat_postMessage_calls = [
|
|
call(
|
|
channel="C02QY11UQ",
|
|
text="@garethgreenaway's job is submitted as salt jid 20221027001127600438",
|
|
),
|
|
call(
|
|
channel="C02QY11UQ",
|
|
text="@garethgreenaway's job `['test.ping']` (id: 20221027001127600438) (target: {'target': 'minion', 'tgt_type': 'glob'}) returned",
|
|
),
|
|
]
|
|
|
|
#
|
|
# test with control as True and fire_all as False
|
|
#
|
|
with patch_slack_client_run_until, patch_slack_client_run_command_async, patch_slack_client_get_jobs_from_runner, patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage:
|
|
slack_client.run_commands_from_slack_async(
|
|
message_generator=message_generator,
|
|
fire_all=False,
|
|
tag="salt/engines/slack",
|
|
control=True,
|
|
)
|
|
app_client_files_upload.asser_has_calls(upload_calls)
|
|
app_client_chat_postMessage.asser_has_calls(chat_postMessage_calls)
|
|
|
|
#
|
|
# test with control and fire_all as True
|
|
#
|
|
patch_slack_client_run_until = patch.object(
|
|
slack_client, "_run_until", MagicMock(autospec=True, side_effect=[True, False])
|
|
)
|
|
|
|
mock_event_send = MagicMock(return_value=True)
|
|
patch_event_send = patch.dict(
|
|
slack_bolt_engine.__salt__, {"event.send": mock_event_send}
|
|
)
|
|
|
|
event_send_calls = [
|
|
call(
|
|
"salt/engines/slack/message",
|
|
{
|
|
"message_data": {
|
|
"client_msg_id": "c1d0c13d-5e78-431e-9921-4786a7d27543",
|
|
"type": "message",
|
|
"text": '!test.ping target="minion"',
|
|
"user": "U02QY11UJ",
|
|
"ts": "1666829486.542159",
|
|
"blocks": [
|
|
{
|
|
"type": "rich_text",
|
|
"block_id": "2vdy",
|
|
"elements": [
|
|
{
|
|
"type": "rich_text_section",
|
|
"elements": [
|
|
{
|
|
"type": "text",
|
|
"text": '!test.ping target="minion"',
|
|
}
|
|
],
|
|
}
|
|
],
|
|
}
|
|
],
|
|
"team": "T02QY11UG",
|
|
"channel": "C02QY11UQ",
|
|
"event_ts": "1666829486.542159",
|
|
"channel_type": "channel",
|
|
},
|
|
"channel": "C02QY11UQ",
|
|
"user": "U02QY11UJ",
|
|
"user_name": "garethgreenaway",
|
|
"cmdline": ["test.ping"],
|
|
"target": {"target": "minion", "tgt_type": "glob"},
|
|
},
|
|
)
|
|
]
|
|
with patch_slack_client_run_until, patch_slack_client_run_command_async, patch_slack_client_get_jobs_from_runner, patch_event_send, patch_app_client_files_upload as app_client_files_upload, patch_app_client_chat_postMessage as app_client_chat_postMessage:
|
|
slack_client.run_commands_from_slack_async(
|
|
message_generator=message_generator,
|
|
fire_all=True,
|
|
tag="salt/engines/slack",
|
|
control=True,
|
|
)
|
|
app_client_files_upload.asser_has_calls(upload_calls)
|
|
app_client_chat_postMessage.asser_has_calls(chat_postMessage_calls)
|
|
mock_event_send.asser_has_calls(event_send_calls)
|
|
|
|
|
|
def test_run_command_async(slack_client):
|
|
"""
|
|
Test slack engine: test_run_command_async
|
|
"""
|
|
|
|
msg = {
|
|
"message_data": {
|
|
"client_msg_id": "6c71d7f9-a44d-402f-8f9f-d1bb5b650853",
|
|
"type": "message",
|
|
"text": '!test.ping target="minion"',
|
|
"user": "U02QY11UJ",
|
|
"ts": "1667427929.764169",
|
|
"blocks": [
|
|
{
|
|
"type": "rich_text",
|
|
"block_id": "AjL",
|
|
"elements": [
|
|
{
|
|
"type": "rich_text_section",
|
|
"elements": [
|
|
{"type": "text", "text": '!test.ping target="minion"'}
|
|
],
|
|
}
|
|
],
|
|
}
|
|
],
|
|
"team": "T02QY11UG",
|
|
"channel": "C02QY11UQ",
|
|
"event_ts": "1667427929.764169",
|
|
"channel_type": "channel",
|
|
},
|
|
"channel": "C02QY11UQ",
|
|
"user": "U02QY11UJ",
|
|
"user_name": "garethgreenaway",
|
|
"cmdline": ["test.ping"],
|
|
"target": {"target": "minion", "tgt_type": "glob"},
|
|
}
|
|
|
|
local_client_mock = MagicMock(autospec=True, return_value=MockLocalClient())
|
|
patch_local_client = patch("salt.client.LocalClient", local_client_mock)
|
|
|
|
local_client_cmd_async_mock = MagicMock(
|
|
autospec=True, return_value={"jid": "20221027001127600438"}
|
|
)
|
|
patch_local_client_cmd_async = patch.object(
|
|
MockLocalClient, "cmd_async", local_client_cmd_async_mock
|
|
)
|
|
|
|
expected_calls = [call("minion", "test.ping", arg=[], kwarg={}, tgt_type="glob")]
|
|
with patch_local_client, patch_local_client_cmd_async as local_client_cmd_async:
|
|
ret = slack_client.run_command_async(msg)
|
|
local_client_cmd_async.assert_has_calls(expected_calls)
|
|
|
|
msg = {
|
|
"message_data": {
|
|
"client_msg_id": "35f4783f-8913-4687-8f04-21182bcacd5a",
|
|
"type": "message",
|
|
"text": "!test.arg arg1 arg2 arg3 key1=value1 key2=value2",
|
|
"user": "U02QY11UJ",
|
|
"ts": "1667429460.576889",
|
|
"blocks": [
|
|
{
|
|
"type": "rich_text",
|
|
"block_id": "EAzTy",
|
|
"elements": [
|
|
{
|
|
"type": "rich_text_section",
|
|
"elements": [
|
|
{
|
|
"type": "text",
|
|
"text": "!test.arg arg1 arg2 arg3 key1=value1 key2=value2",
|
|
}
|
|
],
|
|
}
|
|
],
|
|
}
|
|
],
|
|
"team": "T02QY11UG",
|
|
"channel": "C02QY11UQ",
|
|
"event_ts": "1667429460.576889",
|
|
"channel_type": "channel",
|
|
},
|
|
"channel": "C02QY11UQ",
|
|
"user": "U02QY11UJ",
|
|
"user_name": "garethgreenaway",
|
|
"cmdline": ["test.arg", "arg1", "arg2", "arg3", "key1=value1", "key2=value2"],
|
|
"target": {"target": "*", "tgt_type": "glob"},
|
|
}
|
|
|
|
runner_client_mock = MagicMock(autospec=True, return_value=MockRunnerClient())
|
|
patch_runner_client = patch("salt.runner.RunnerClient", runner_client_mock)
|
|
|
|
runner_client_asynchronous_mock = MagicMock(
|
|
autospec=True, return_value={"jid": "20221027001127600438"}
|
|
)
|
|
patch_runner_client_asynchronous = patch.object(
|
|
MockRunnerClient, "asynchronous", runner_client_asynchronous_mock
|
|
)
|
|
|
|
expected_calls = [
|
|
call(
|
|
"test.arg",
|
|
{
|
|
"arg": ["arg1", "arg2", "arg3"],
|
|
"kwarg": {"key1": "value1", "key2": "value2"},
|
|
},
|
|
)
|
|
]
|
|
with patch_runner_client, patch_runner_client_asynchronous as runner_client_asynchronous:
|
|
ret = slack_client.run_command_async(msg)
|
|
runner_client_asynchronous.assert_has_calls(expected_calls)
|