mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
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:
parent
b1b8b8ba00
commit
9d54aa205b
@ -165,7 +165,7 @@ HTML5_SHOWNOTIFICATION_PARAMETERS = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_service(
|
async def async_get_service(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config: ConfigType,
|
config: ConfigType,
|
||||||
discovery_info: DiscoveryInfoType | None = None,
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
@ -173,7 +173,7 @@ def get_service(
|
|||||||
"""Get the HTML5 push notification service."""
|
"""Get the HTML5 push notification service."""
|
||||||
json_path = hass.config.path(REGISTRATIONS_FILE)
|
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_pub_key = config[ATTR_VAPID_PUB_KEY]
|
||||||
vapid_prv_key = config[ATTR_VAPID_PRV_KEY]
|
vapid_prv_key = config[ATTR_VAPID_PRV_KEY]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
import json
|
import json
|
||||||
from unittest.mock import MagicMock, mock_open, patch
|
from unittest.mock import mock_open, patch
|
||||||
|
|
||||||
from aiohttp.hdrs import AUTHORIZATION
|
from aiohttp.hdrs import AUTHORIZATION
|
||||||
|
|
||||||
@ -83,166 +83,174 @@ async def mock_client(hass, hass_client, registrations=None):
|
|||||||
return await hass_client()
|
return await hass_client()
|
||||||
|
|
||||||
|
|
||||||
class TestHtml5Notify:
|
async def test_get_service_with_no_json(hass: HomeAssistant):
|
||||||
"""Tests for HTML5 notify platform."""
|
"""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):
|
assert service is not None
|
||||||
"""Test empty json file."""
|
|
||||||
hass = MagicMock()
|
|
||||||
|
|
||||||
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")
|
data = {"device": SUBSCRIPTION_1}
|
||||||
def test_dismissing_message(self, mock_wp):
|
|
||||||
"""Test dismissing message."""
|
|
||||||
hass = MagicMock()
|
|
||||||
mock_wp().send().status_code = 201
|
|
||||||
|
|
||||||
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))
|
assert service is not None
|
||||||
with patch("homeassistant.util.json.open", m, create=True):
|
|
||||||
service = html5.get_service(hass, VAPID_CONF)
|
|
||||||
|
|
||||||
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
|
# Call to send
|
||||||
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_1["subscription"]
|
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
|
||||||
|
|
||||||
# Call to send
|
assert payload["dismiss"] is True
|
||||||
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
|
assert payload["tag"] == "test"
|
||||||
|
|
||||||
assert payload["dismiss"] is True
|
|
||||||
assert payload["tag"] == "test"
|
|
||||||
|
|
||||||
@patch("homeassistant.components.html5.notify.WebPusher")
|
@patch("homeassistant.components.html5.notify.WebPusher")
|
||||||
def test_sending_message(self, mock_wp):
|
async def test_sending_message(mock_wp, hass: HomeAssistant):
|
||||||
"""Test sending message."""
|
"""Test sending message."""
|
||||||
hass = MagicMock()
|
await async_setup_component(hass, "http", {})
|
||||||
mock_wp().send().status_code = 201
|
mock_wp().send().status_code = 201
|
||||||
|
|
||||||
data = {"device": SUBSCRIPTION_1}
|
data = {"device": SUBSCRIPTION_1}
|
||||||
|
|
||||||
m = mock_open(read_data=json.dumps(data))
|
m = mock_open(read_data=json.dumps(data))
|
||||||
with patch("homeassistant.util.json.open", m, create=True):
|
with patch("homeassistant.util.json.open", m, create=True):
|
||||||
service = html5.get_service(hass, VAPID_CONF)
|
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(
|
await service.async_send_message(
|
||||||
"Hello", target=["device", "non_existing"], data={"icon": "beer.png"}
|
"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
|
# WebPusher constructor
|
||||||
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_1["subscription"]
|
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_1["subscription"]
|
||||||
|
|
||||||
# Call to send
|
# Call to send
|
||||||
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
|
payload = json.loads(mock_wp.mock_calls[3][2]["data"])
|
||||||
|
|
||||||
assert payload["body"] == "Hello"
|
assert payload["body"] == "Hello"
|
||||||
assert payload["icon"] == "beer.png"
|
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))
|
data = {"chrome": SUBSCRIPTION_5}
|
||||||
with patch("homeassistant.util.json.open", m, create=True):
|
|
||||||
service = html5.get_service(hass, VAPID_CONF)
|
|
||||||
|
|
||||||
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
|
await service.async_send_message("Hello", target=["chrome"])
|
||||||
# WebPusher constructor
|
|
||||||
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
|
|
||||||
|
|
||||||
# Get the keys passed to the WebPusher's send method
|
assert len(mock_wp.mock_calls) == 4
|
||||||
assert mock_wp.mock_calls[3][2]["headers"]["Authorization"] is not None
|
# WebPusher constructor
|
||||||
|
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
|
||||||
|
|
||||||
@patch("homeassistant.components.html5.notify.WebPusher")
|
# Get the keys passed to the WebPusher's send method
|
||||||
def test_fcm_send_with_unknown_priority(self, mock_wp):
|
assert mock_wp.mock_calls[3][2]["headers"]["Authorization"] is not None
|
||||||
"""Test if the gcm_key is only included for GCM endpoints."""
|
|
||||||
hass = MagicMock()
|
|
||||||
mock_wp().send().status_code = 201
|
|
||||||
|
|
||||||
data = {"chrome": SUBSCRIPTION_5}
|
|
||||||
|
|
||||||
m = mock_open(read_data=json.dumps(data))
|
@patch("homeassistant.components.html5.notify.WebPusher")
|
||||||
with patch("homeassistant.util.json.open", m, create=True):
|
async def test_fcm_send_with_unknown_priority(mock_wp, hass: HomeAssistant):
|
||||||
service = html5.get_service(hass, VAPID_CONF)
|
"""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
|
assert service is not None
|
||||||
# WebPusher constructor
|
|
||||||
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
|
|
||||||
|
|
||||||
# Get the keys passed to the WebPusher's send method
|
await service.async_send_message("Hello", target=["chrome"], priority="undefined")
|
||||||
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
|
|
||||||
|
|
||||||
@patch("homeassistant.components.html5.notify.WebPusher")
|
assert len(mock_wp.mock_calls) == 4
|
||||||
def test_fcm_no_targets(self, mock_wp):
|
# WebPusher constructor
|
||||||
"""Test if the gcm_key is only included for GCM endpoints."""
|
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
|
||||||
hass = MagicMock()
|
|
||||||
mock_wp().send().status_code = 201
|
|
||||||
|
|
||||||
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
|
m = mock_open(read_data=json.dumps(data))
|
||||||
# WebPusher constructor
|
with patch("homeassistant.util.json.open", m, create=True):
|
||||||
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
|
service = await html5.async_get_service(hass, VAPID_CONF)
|
||||||
|
service.hass = hass
|
||||||
|
|
||||||
# Get the keys passed to the WebPusher's send method
|
assert service is not None
|
||||||
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
|
|
||||||
|
|
||||||
@patch("homeassistant.components.html5.notify.WebPusher")
|
await service.async_send_message("Hello")
|
||||||
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
|
|
||||||
|
|
||||||
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))
|
# Get the keys passed to the WebPusher's send method
|
||||||
with patch("homeassistant.util.json.open", m, create=True):
|
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
|
||||||
service = html5.get_service(hass, VAPID_CONF)
|
|
||||||
|
|
||||||
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
|
data = {"chrome": SUBSCRIPTION_5}
|
||||||
# WebPusher constructor
|
|
||||||
assert mock_wp.mock_calls[2][1][0] == SUBSCRIPTION_5["subscription"]
|
|
||||||
|
|
||||||
# Get the keys passed to the WebPusher's send method
|
m = mock_open(read_data=json.dumps(data))
|
||||||
assert mock_wp.mock_calls[3][2]["headers"]["priority"] == "normal"
|
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(
|
async def test_registering_new_device_view(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user