mirror of https://github.com/home-assistant/core
411 lines
13 KiB
Python
411 lines
13 KiB
Python
"""Tests for the aws component config and setup."""
|
|
|
|
import json
|
|
from typing import Any
|
|
from unittest.mock import AsyncMock, MagicMock, call, patch as async_patch
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.setup import async_setup_component
|
|
|
|
|
|
class MockAioSession:
|
|
"""Mock AioSession."""
|
|
|
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
"""Init a mock session."""
|
|
self.get_user = AsyncMock()
|
|
self.invoke = AsyncMock()
|
|
self.publish = AsyncMock()
|
|
self.send_message = AsyncMock()
|
|
self.put_events = AsyncMock()
|
|
|
|
def create_client(self, *args, **kwargs):
|
|
"""Create a mocked client."""
|
|
return MagicMock(
|
|
__aenter__=AsyncMock(
|
|
return_value=AsyncMock(
|
|
get_user=self.get_user, # iam
|
|
invoke=self.invoke, # lambda
|
|
publish=self.publish, # sns
|
|
send_message=self.send_message, # sqs
|
|
put_events=self.put_events, # events
|
|
)
|
|
),
|
|
__aexit__=AsyncMock(),
|
|
)
|
|
|
|
async def get_available_regions(self, *args, **kwargs):
|
|
"""Return list of available regions."""
|
|
return ["us-east-1", "us-east-2", "us-west-1", "us-west-2"]
|
|
|
|
|
|
async def test_empty_config(hass: HomeAssistant) -> None:
|
|
"""Test a default config will be create for empty config."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(hass, "aws", {"aws": {}})
|
|
await hass.async_block_till_done()
|
|
|
|
# we don't validate auto-created default profile
|
|
mock_session.get_user.assert_not_awaited()
|
|
|
|
|
|
async def test_empty_credential(hass: HomeAssistant) -> None:
|
|
"""Test a default config will be create for empty credential section."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"notify": [
|
|
{
|
|
"service": "lambda",
|
|
"name": "New Lambda Test",
|
|
"region_name": "us-east-1",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "new_lambda_test") is True
|
|
await hass.services.async_call(
|
|
"notify", "new_lambda_test", {"message": "test", "target": "ARN"}, blocking=True
|
|
)
|
|
mock_session.invoke.assert_awaited_once()
|
|
|
|
|
|
async def test_profile_credential(hass: HomeAssistant) -> None:
|
|
"""Test credentials with profile name."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"credentials": {"name": "test", "profile_name": "test-profile"},
|
|
"notify": [
|
|
{
|
|
"service": "sns",
|
|
"credential_name": "test",
|
|
"name": "SNS Test",
|
|
"region_name": "us-east-1",
|
|
}
|
|
],
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "sns_test") is True
|
|
await hass.services.async_call(
|
|
"notify",
|
|
"sns_test",
|
|
{"title": "test", "message": "test", "target": "ARN"},
|
|
blocking=True,
|
|
)
|
|
mock_session.publish.assert_awaited_once()
|
|
|
|
|
|
async def test_access_key_credential(hass: HomeAssistant) -> None:
|
|
"""Test credentials with access key."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"credentials": [
|
|
{"name": "test", "profile_name": "test-profile"},
|
|
{
|
|
"name": "key",
|
|
"aws_access_key_id": "test-key",
|
|
"aws_secret_access_key": "test-secret",
|
|
},
|
|
],
|
|
"notify": [
|
|
{
|
|
"service": "sns",
|
|
"credential_name": "key",
|
|
"name": "SNS Test",
|
|
"region_name": "us-east-1",
|
|
}
|
|
],
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "sns_test") is True
|
|
await hass.services.async_call(
|
|
"notify",
|
|
"sns_test",
|
|
{"title": "test", "message": "test", "target": "ARN"},
|
|
blocking=True,
|
|
)
|
|
mock_session.publish.assert_awaited_once()
|
|
|
|
|
|
async def test_notify_credential(hass: HomeAssistant) -> None:
|
|
"""Test notify service can use access key directly."""
|
|
mock_session = MockAioSession()
|
|
with (
|
|
async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
),
|
|
async_patch(
|
|
"homeassistant.components.aws.notify.AioSession", return_value=mock_session
|
|
),
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"notify": [
|
|
{
|
|
"service": "sqs",
|
|
"credential_name": "test",
|
|
"name": "SQS Test",
|
|
"region_name": "us-east-1",
|
|
"aws_access_key_id": "some-key",
|
|
"aws_secret_access_key": "some-secret",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "sqs_test") is True
|
|
await hass.services.async_call(
|
|
"notify", "sqs_test", {"message": "test", "target": "ARN"}, blocking=True
|
|
)
|
|
|
|
|
|
async def test_notify_credential_profile(hass: HomeAssistant) -> None:
|
|
"""Test notify service can use profile directly."""
|
|
mock_session = MockAioSession()
|
|
with (
|
|
async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
),
|
|
async_patch(
|
|
"homeassistant.components.aws.notify.AioSession", return_value=mock_session
|
|
),
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"notify": [
|
|
{
|
|
"service": "sqs",
|
|
"name": "SQS Test",
|
|
"region_name": "us-east-1",
|
|
"profile_name": "test",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "sqs_test") is True
|
|
await hass.services.async_call(
|
|
"notify", "sqs_test", {"message": "test", "target": "ARN"}, blocking=True
|
|
)
|
|
|
|
|
|
async def test_credential_skip_validate(hass: HomeAssistant) -> None:
|
|
"""Test credential can skip validate."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"credentials": [
|
|
{
|
|
"name": "key",
|
|
"aws_access_key_id": "not-valid",
|
|
"aws_secret_access_key": "dont-care",
|
|
"validate": False,
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
mock_session.get_user.assert_not_awaited()
|
|
|
|
|
|
async def test_service_call_extra_data(hass: HomeAssistant) -> None:
|
|
"""Test service call extra data are parsed properly."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"notify": [
|
|
{
|
|
"service": "sns",
|
|
"name": "SNS Test",
|
|
"region_name": "us-east-1",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "sns_test") is True
|
|
await hass.services.async_call(
|
|
"notify",
|
|
"sns_test",
|
|
{
|
|
"message": "test",
|
|
"target": "ARN",
|
|
"data": {"AWS.SNS.SMS.SenderID": "HA-notify"},
|
|
},
|
|
blocking=True,
|
|
)
|
|
mock_session.publish.assert_called_once_with(
|
|
TargetArn="ARN",
|
|
Message="test",
|
|
Subject="Home Assistant",
|
|
MessageAttributes={
|
|
"AWS.SNS.SMS.SenderID": {"StringValue": "HA-notify", "DataType": "String"}
|
|
},
|
|
)
|
|
|
|
|
|
async def test_events_service_call(hass: HomeAssistant) -> None:
|
|
"""Test events service (EventBridge) call works as expected."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"notify": [
|
|
{
|
|
"service": "events",
|
|
"name": "Events Test",
|
|
"region_name": "us-east-1",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "events_test") is True
|
|
|
|
mock_session.put_events.return_value = {
|
|
"Entries": [{"EventId": "", "ErrorCode": 0, "ErrorMessage": "test-error"}]
|
|
}
|
|
|
|
await hass.services.async_call(
|
|
"notify",
|
|
"events_test",
|
|
{
|
|
"message": "test",
|
|
"target": "ARN",
|
|
"data": {},
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
mock_session.put_events.assert_called_once_with(
|
|
Entries=[
|
|
{
|
|
"EventBusName": "ARN",
|
|
"Detail": json.dumps({"message": "test"}),
|
|
"DetailType": "",
|
|
"Source": "homeassistant",
|
|
"Resources": [],
|
|
}
|
|
]
|
|
)
|
|
|
|
|
|
async def test_events_service_call_10_targets(hass: HomeAssistant) -> None:
|
|
"""Test events service (EventBridge) call works with more than 10 targets."""
|
|
mock_session = MockAioSession()
|
|
with async_patch(
|
|
"homeassistant.components.aws.AioSession", return_value=mock_session
|
|
):
|
|
await async_setup_component(
|
|
hass,
|
|
"aws",
|
|
{
|
|
"aws": {
|
|
"notify": [
|
|
{
|
|
"service": "events",
|
|
"name": "Events Test",
|
|
"region_name": "us-east-1",
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert hass.services.has_service("notify", "events_test") is True
|
|
await hass.services.async_call(
|
|
"notify",
|
|
"events_test",
|
|
{
|
|
"message": "",
|
|
"target": [f"eventbus{i}" for i in range(11)],
|
|
"data": {
|
|
"detail_type": "test_event",
|
|
"detail": {"eventkey": "eventvalue"},
|
|
"source": "HomeAssistant-test",
|
|
"resources": ["resource1", "resource2"],
|
|
},
|
|
},
|
|
blocking=True,
|
|
)
|
|
|
|
entry = {
|
|
"Detail": json.dumps({"eventkey": "eventvalue"}),
|
|
"DetailType": "test_event",
|
|
"Source": "HomeAssistant-test",
|
|
"Resources": ["resource1", "resource2"],
|
|
}
|
|
|
|
mock_session.put_events.assert_has_calls(
|
|
[
|
|
call(Entries=[entry | {"EventBusName": f"eventbus{i}"} for i in range(10)]),
|
|
call(Entries=[entry | {"EventBusName": "eventbus10"}]),
|
|
]
|
|
)
|