Fix non-thread-safe operations in html5 (#116068)

Fix non thread-safe calls in html5

https://github.com/home-assistant/core/actions/runs/8808425552/job/24177668764?pr=116055
This commit is contained in:
J. Nick Koston 2024-04-24 03:33:19 +02:00 committed by GitHub
parent b1b8b8ba00
commit 9d54aa205b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 122 additions and 114 deletions

View file

@ -165,7 +165,7 @@ HTML5_SHOWNOTIFICATION_PARAMETERS = (
)
def get_service(
async def async_get_service(
hass: HomeAssistant,
config: ConfigType,
discovery_info: DiscoveryInfoType | None = None,
@ -173,7 +173,7 @@ def get_service(
"""Get the HTML5 push notification service."""
json_path = hass.config.path(REGISTRATIONS_FILE)
registrations = _load_config(json_path)
registrations = await hass.async_add_executor_job(_load_config, json_path)
vapid_pub_key = config[ATTR_VAPID_PUB_KEY]
vapid_prv_key = config[ATTR_VAPID_PRV_KEY]

View file

@ -2,7 +2,7 @@
from http import HTTPStatus
import json
from unittest.mock import MagicMock, mock_open, patch
from unittest.mock import mock_open, patch
from aiohttp.hdrs import AUTHORIZATION
@ -83,166 +83,174 @@ async def mock_client(hass, hass_client, registrations=None):
return await hass_client()
class TestHtml5Notify:
"""Tests for HTML5 notify platform."""
async def test_get_service_with_no_json(hass: HomeAssistant):
"""Test empty json file."""
await async_setup_component(hass, "http", {})
m = mock_open()
with patch("homeassistant.util.json.open", m, create=True):
service = await html5.async_get_service(hass, VAPID_CONF)
def test_get_service_with_no_json(self):
"""Test empty json file."""
hass = MagicMock()
assert service is not None
m = mock_open()
with patch("homeassistant.util.json.open", m, create=True):
service = html5.get_service(hass, VAPID_CONF)
assert service is not None
@patch("homeassistant.components.html5.notify.WebPusher")
async def test_dismissing_message(mock_wp, hass: HomeAssistant):
"""Test dismissing message."""
await async_setup_component(hass, "http", {})
mock_wp().send().status_code = 201
@patch("homeassistant.components.html5.notify.WebPusher")
def test_dismissing_message(self, mock_wp):
"""Test dismissing message."""
hass = MagicMock()
mock_wp().send().status_code = 201
data = {"device": SUBSCRIPTION_1}
data = {"device": SUBSCRIPTION_1}
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = await html5.async_get_service(hass, VAPID_CONF)
service.hass = hass
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = html5.get_service(hass, VAPID_CONF)
assert service is not None
assert service is not None
await service.async_dismiss(target=["device", "non_existing"], data={"tag": "test"})
service.dismiss(target=["device", "non_existing"], data={"tag": "test"})
assert len(mock_wp.mock_calls) == 4
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_1["subscription"]
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_1["subscription"]
# Call to send
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
# Call to send
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
assert payload["dismiss"] is True
assert payload["tag"] == "test"
assert payload["dismiss"] is True
assert payload["tag"] == "test"
@patch("homeassistant.components.html5.notify.WebPusher")
def test_sending_message(self, mock_wp):
"""Test sending message."""
hass = MagicMock()
mock_wp().send().status_code = 201
@patch("homeassistant.components.html5.notify.WebPusher")
async def test_sending_message(mock_wp, hass: HomeAssistant):
"""Test sending message."""
await async_setup_component(hass, "http", {})
mock_wp().send().status_code = 201
data = {"device": SUBSCRIPTION_1}
data = {"device": SUBSCRIPTION_1}
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = html5.get_service(hass, VAPID_CONF)
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = await html5.async_get_service(hass, VAPID_CONF)
service.hass = hass
assert service is not None
assert service is not None
service.send_message(
"Hello", target=["device", "non_existing"], data={"icon": "beer.png"}
)
await service.async_send_message(
"Hello", target=["device", "non_existing"], data={"icon": "beer.png"}
)
assert len(mock_wp.mock_calls) == 4
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_1["subscription"]
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_1["subscription"]
# Call to send
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
# Call to send
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
assert payload["body"] == "Hello"
assert payload["icon"] == "beer.png"
assert payload["body"] == "Hello"
assert payload["icon"] == "beer.png"
@patch("homeassistant.components.html5.notify.WebPusher")
def test_fcm_key_include(self, mock_wp):
"""Test if the FCM header is included."""
hass = MagicMock()
mock_wp().send().status_code = 201
data = {"chrome": SUBSCRIPTION_5}
@patch("homeassistant.components.html5.notify.WebPusher")
async def test_fcm_key_include(mock_wp, hass: HomeAssistant):
"""Test if the FCM header is included."""
await async_setup_component(hass, "http", {})
mock_wp().send().status_code = 201
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = html5.get_service(hass, VAPID_CONF)
data = {"chrome": SUBSCRIPTION_5}
assert service is not None
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = await html5.async_get_service(hass, VAPID_CONF)
service.hass = hass
service.send_message("Hello", target=["chrome"])
assert service is not None
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
await service.async_send_message("Hello", target=["chrome"])
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["Authorization"] is not None
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
@patch("homeassistant.components.html5.notify.WebPusher")
def test_fcm_send_with_unknown_priority(self, mock_wp):
"""Test if the gcm_key is only included for GCM endpoints."""
hass = MagicMock()
mock_wp().send().status_code = 201
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["Authorization"] is not None
data = {"chrome": SUBSCRIPTION_5}
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = html5.get_service(hass, VAPID_CONF)
@patch("homeassistant.components.html5.notify.WebPusher")
async def test_fcm_send_with_unknown_priority(mock_wp, hass: HomeAssistant):
"""Test if the gcm_key is only included for GCM endpoints."""
await async_setup_component(hass, "http", {})
mock_wp().send().status_code = 201
assert service is not None
data = {"chrome": SUBSCRIPTION_5}
service.send_message("Hello", target=["chrome"], priority="undefined")
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = await html5.async_get_service(hass, VAPID_CONF)
service.hass = hass
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
assert service is not None
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
await service.async_send_message("Hello", target=["chrome"], priority="undefined")
@patch("homeassistant.components.html5.notify.WebPusher")
def test_fcm_no_targets(self, mock_wp):
"""Test if the gcm_key is only included for GCM endpoints."""
hass = MagicMock()
mock_wp().send().status_code = 201
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
data = {"chrome": SUBSCRIPTION_5}
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = html5.get_service(hass, VAPID_CONF)
assert service is not None
@patch("homeassistant.components.html5.notify.WebPusher")
async def test_fcm_no_targets(mock_wp, hass: HomeAssistant):
"""Test if the gcm_key is only included for GCM endpoints."""
await async_setup_component(hass, "http", {})
mock_wp().send().status_code = 201
service.send_message("Hello")
data = {"chrome": SUBSCRIPTION_5}
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = await html5.async_get_service(hass, VAPID_CONF)
service.hass = hass
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
assert service is not None
@patch("homeassistant.components.html5.notify.WebPusher")
def test_fcm_additional_data(self, mock_wp):
"""Test if the gcm_key is only included for GCM endpoints."""
hass = MagicMock()
mock_wp().send().status_code = 201
await service.async_send_message("Hello")
data = {"chrome": SUBSCRIPTION_5}
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = html5.get_service(hass, VAPID_CONF)
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
assert service is not None
service.send_message("Hello", data={"mykey": "myvalue"})
@patch("homeassistant.components.html5.notify.WebPusher")
async def test_fcm_additional_data(mock_wp, hass: HomeAssistant):
"""Test if the gcm_key is only included for GCM endpoints."""
await async_setup_component(hass, "http", {})
mock_wp().send().status_code = 201
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
data = {"chrome": SUBSCRIPTION_5}
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
m = mock_open(read_data=json.dumps(data))
with patch("homeassistant.util.json.open", m, create=True):
service = await html5.async_get_service(hass, VAPID_CONF)
service.hass = hass
assert service is not None
await service.async_send_message("Hello", data={"mykey": "myvalue"})
assert len(mock_wp.mock_calls) == 4
# WebPusher constructor
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
# Get the keys passed to the WebPusher's send method
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
async def test_registering_new_device_view(