From bd9328c215db873ce2eff056c6bd6230d63e963e Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Thu, 9 May 2024 17:56:34 +0200 Subject: [PATCH 1/9] Bump pysignalclirestapi to 0.3.24 --- homeassistant/components/signal_messenger/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/signal_messenger/manifest.json b/homeassistant/components/signal_messenger/manifest.json index 058b01535ea16..217109bfa2ca4 100644 --- a/homeassistant/components/signal_messenger/manifest.json +++ b/homeassistant/components/signal_messenger/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/signal_messenger", "iot_class": "cloud_push", "loggers": ["pysignalclirestapi"], - "requirements": ["pysignalclirestapi==0.3.23"] + "requirements": ["pysignalclirestapi==0.3.24"] } diff --git a/requirements_all.txt b/requirements_all.txt index 4821ca831cd99..b4e0cad491e37 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2143,7 +2143,7 @@ pysesame2==1.0.1 pysiaalarm==3.1.1 # homeassistant.components.signal_messenger -pysignalclirestapi==0.3.23 +pysignalclirestapi==0.3.24 # homeassistant.components.sky_hub pyskyqhub==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 99f90017aba70..5d4bd9a8c61dc 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1679,7 +1679,7 @@ pyserial==3.5 pysiaalarm==3.1.1 # homeassistant.components.signal_messenger -pysignalclirestapi==0.3.23 +pysignalclirestapi==0.3.24 # homeassistant.components.sma pysma==0.7.3 From 20bab810ab6d8bcbf10798cf63c73ffdefa7269b Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Sun, 19 May 2024 22:28:56 +0200 Subject: [PATCH 2/9] pysignalclirestapi: add `text_mode` parameter. --- .../components/signal_messenger/notify.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/signal_messenger/notify.py b/homeassistant/components/signal_messenger/notify.py index 9c8846b27671a..1da12c01383b9 100644 --- a/homeassistant/components/signal_messenger/notify.py +++ b/homeassistant/components/signal_messenger/notify.py @@ -27,6 +27,7 @@ ATTR_FILENAMES = "attachments" ATTR_URLS = "urls" ATTR_VERIFY_SSL = "verify_ssl" +ATTR_TEXTMODE = "text_mode" DATA_FILENAMES_SCHEMA = vol.Schema({vol.Required(ATTR_FILENAMES): [cv.string]}) @@ -37,10 +38,15 @@ } ) +DATA_TEXTMODE_SCHEMA = vol.Schema( + {vol.Optional(ATTR_TEXTMODE, default="normal"): [cv.string]} +) + DATA_SCHEMA = vol.Any( None, DATA_FILENAMES_SCHEMA, DATA_URLS_SCHEMA, + DATA_TEXTMODE_SCHEMA, ) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( @@ -100,10 +106,15 @@ def send_message(self, message: str = "", **kwargs: Any) -> None: attachments_as_bytes = self.get_attachments_as_bytes( data, CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES, self._hass ) + text_mode = self.get_text_mode(data) try: self._signal_cli_rest_api.send_message( - message, self._recp_nrs, filenames, attachments_as_bytes + message, + self._recp_nrs, + filenames, + attachments_as_bytes, + text_mode=text_mode, ) except SignalCliRestApiError as ex: _LOGGER.error("%s", ex) @@ -180,3 +191,12 @@ def get_attachments_as_bytes( return None return attachments_as_bytes + + @staticmethod + def get_text_mode(data: Any) -> str: + """Extract text mode parameter from data.""" + try: + data = DATA_TEXTMODE_SCHEMA(data) + except vol.Invalid: + return "normal" + return data[ATTR_TEXTMODE] From 1e8c8162823369bbe282da477907725f89106c6c Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Mon, 10 Jun 2024 17:16:31 +0000 Subject: [PATCH 3/9] Signal Messenger: updated data schema to implement text_mode. --- .../components/signal_messenger/notify.py | 45 +++++++++++-------- .../signal_messenger/test_notify.py | 20 ++++----- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/homeassistant/components/signal_messenger/notify.py b/homeassistant/components/signal_messenger/notify.py index 1da12c01383b9..488cacdb56020 100644 --- a/homeassistant/components/signal_messenger/notify.py +++ b/homeassistant/components/signal_messenger/notify.py @@ -29,7 +29,7 @@ ATTR_VERIFY_SSL = "verify_ssl" ATTR_TEXTMODE = "text_mode" -DATA_FILENAMES_SCHEMA = vol.Schema({vol.Required(ATTR_FILENAMES): [cv.string]}) +DATA_FILENAMES_SCHEMA = vol.Schema([cv.string]) DATA_URLS_SCHEMA = vol.Schema( { @@ -38,15 +38,15 @@ } ) -DATA_TEXTMODE_SCHEMA = vol.Schema( - {vol.Optional(ATTR_TEXTMODE, default="normal"): [cv.string]} -) - DATA_SCHEMA = vol.Any( None, - DATA_FILENAMES_SCHEMA, - DATA_URLS_SCHEMA, - DATA_TEXTMODE_SCHEMA, + vol.Schema( + { + vol.Optional(ATTR_TEXTMODE, default="normal"): cv.string, + vol.Exclusive(ATTR_FILENAMES, "attachments"): [cv.string], + vol.Exclusive(ATTR_URLS, "attachments"): DATA_URLS_SCHEMA, + } + ), ) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( @@ -106,15 +106,13 @@ def send_message(self, message: str = "", **kwargs: Any) -> None: attachments_as_bytes = self.get_attachments_as_bytes( data, CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES, self._hass ) - text_mode = self.get_text_mode(data) - try: self._signal_cli_rest_api.send_message( message, self._recp_nrs, filenames, attachments_as_bytes, - text_mode=text_mode, + text_mode=self.get_text_mode(data), ) except SignalCliRestApiError as ex: _LOGGER.error("%s", ex) @@ -124,11 +122,15 @@ def send_message(self, message: str = "", **kwargs: Any) -> None: def get_filenames(data: Any) -> list[str] | None: """Extract attachment filenames from data.""" try: - data = DATA_FILENAMES_SCHEMA(data) + data = DATA_FILENAMES_SCHEMA(data[ATTR_FILENAMES]) except vol.Invalid: return None + except KeyError: + return None + except TypeError: + return None - return data[ATTR_FILENAMES] + return data @staticmethod def get_attachments_as_bytes( @@ -138,10 +140,13 @@ def get_attachments_as_bytes( ) -> list[bytearray] | None: """Retrieve attachments from URLs defined in data.""" try: - data = DATA_URLS_SCHEMA(data) + data = DATA_URLS_SCHEMA(data[ATTR_URLS]) except vol.Invalid: return None - + except KeyError: + return None + except TypeError: + return None urls = data[ATTR_URLS] attachments_as_bytes: list[bytearray] = [] @@ -193,10 +198,12 @@ def get_attachments_as_bytes( return attachments_as_bytes @staticmethod - def get_text_mode(data: Any) -> str: + def get_text_mode(data) -> str: """Extract text mode parameter from data.""" try: - data = DATA_TEXTMODE_SCHEMA(data) - except vol.Invalid: + text_mode = data.get(ATTR_TEXTMODE) + if text_mode in ["normal", "styled"]: + return text_mode + except AttributeError: return "normal" - return data[ATTR_TEXTMODE] + return "normal" diff --git a/tests/components/signal_messenger/test_notify.py b/tests/components/signal_messenger/test_notify.py index e2f76d54c87fe..2260a5a40a0ff 100644 --- a/tests/components/signal_messenger/test_notify.py +++ b/tests/components/signal_messenger/test_notify.py @@ -139,7 +139,7 @@ def test_send_message_with_attachment_as_url( with caplog.at_level( logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" ): - data = {"urls": [URL_ATTACHMENT]} + data = {"urls": {"urls": [URL_ATTACHMENT]}} signal_notification_service.send_message(MESSAGE, data=data) assert "Sending signal message" in caplog.text @@ -155,7 +155,7 @@ def test_get_attachments( ) -> None: """Test getting attachments as URL.""" signal_requests_mock = signal_requests_mock_factory(True, str(len(CONTENT))) - data = {"urls": [URL_ATTACHMENT]} + data = {"urls": {"urls": [URL_ATTACHMENT]}} result = signal_notification_service.get_attachments_as_bytes( data, len(CONTENT), hass ) @@ -172,7 +172,7 @@ def test_get_attachments_not_on_allowlist( ) -> None: """Test getting attachments as URL that aren't on the allowlist.""" url = "http://dodgyurl.com" - data = {"urls": [url]} + data = {"urls": {"urls": [url]}} with caplog.at_level( logging.ERROR, logger="homeassistant.components.signal_messenger.notify" ): @@ -192,7 +192,7 @@ def test_get_attachments_with_large_attachment( """Test getting attachments as URL with large attachment (per Content-Length header) throws error.""" signal_requests_mock = signal_requests_mock_factory(True, str(len(CONTENT) + 1)) with pytest.raises(ValueError) as exc: - data = {"urls": [URL_ATTACHMENT]} + data = {"urls": {"urls": [URL_ATTACHMENT]}} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -208,7 +208,7 @@ def test_get_attachments_with_large_attachment_no_header( """Test getting attachments as URL with large attachment (per content length) throws error.""" signal_requests_mock = signal_requests_mock_factory() with pytest.raises(ValueError) as exc: - data = {"urls": [URL_ATTACHMENT]} + data = {"urls": {"urls": [URL_ATTACHMENT]}} signal_notification_service.get_attachments_as_bytes( data, len(CONTENT) - 1, hass ) @@ -263,7 +263,7 @@ def test_get_attachments_with_non_list_returns_none( hass: HomeAssistant, ) -> None: """Test getting attachments with non list data.""" - data = {"urls": URL_ATTACHMENT} + data = {"urls": {"urls": URL_ATTACHMENT}} result = signal_notification_service.get_attachments_as_bytes( data, len(CONTENT), hass ) @@ -278,7 +278,7 @@ def test_get_attachments_with_verify_unset( ) -> None: """Test getting attachments as URL with verify_ssl unset results in verify=true.""" signal_requests_mock = signal_requests_mock_factory() - data = {"urls": [URL_ATTACHMENT]} + data = {"urls": {"urls": [URL_ATTACHMENT]}} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -293,7 +293,7 @@ def test_get_attachments_with_verify_set_true( ) -> None: """Test getting attachments as URL with verify_ssl set to true results in verify=true.""" signal_requests_mock = signal_requests_mock_factory() - data = {"verify_ssl": True, "urls": [URL_ATTACHMENT]} + data = {"urls": {"verify_ssl": True, "urls": [URL_ATTACHMENT]}} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -308,7 +308,7 @@ def test_get_attachments_with_verify_set_false( ) -> None: """Test getting attachments as URL with verify_ssl set to false results in verify=false.""" signal_requests_mock = signal_requests_mock_factory() - data = {"verify_ssl": False, "urls": [URL_ATTACHMENT]} + data = {"urls": {"verify_ssl": False, "urls": [URL_ATTACHMENT]}} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -321,7 +321,7 @@ def test_get_attachments_with_verify_set_garbage( hass: HomeAssistant, ) -> None: """Test getting attachments as URL with verify_ssl set to garbage results in None.""" - data = {"verify_ssl": "test", "urls": [URL_ATTACHMENT]} + data = {"urls": {"verify_ssl": "test", "urls": [URL_ATTACHMENT]}} result = signal_notification_service.get_attachments_as_bytes( data, len(CONTENT), hass ) From e9b2a94f0cdb30238a439e3206a2b53d4841d079 Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Mon, 10 Jun 2024 22:35:23 +0000 Subject: [PATCH 4/9] Signal Messenger: fixed data schema to avoid breaking changes. --- .../components/signal_messenger/notify.py | 27 +++++++++---------- .../signal_messenger/test_notify.py | 20 +++++++------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/signal_messenger/notify.py b/homeassistant/components/signal_messenger/notify.py index 488cacdb56020..1de58f5fd6c14 100644 --- a/homeassistant/components/signal_messenger/notify.py +++ b/homeassistant/components/signal_messenger/notify.py @@ -29,12 +29,18 @@ ATTR_VERIFY_SSL = "verify_ssl" ATTR_TEXTMODE = "text_mode" -DATA_FILENAMES_SCHEMA = vol.Schema([cv.string]) +DATA_FILENAMES_SCHEMA = vol.Schema( + { + vol.Required(ATTR_FILENAMES): [cv.string], + vol.Optional(ATTR_TEXTMODE, default="normal"): cv.string, + } +) DATA_URLS_SCHEMA = vol.Schema( { vol.Required(ATTR_URLS): [cv.url], vol.Optional(ATTR_VERIFY_SSL, default=True): cv.boolean, + vol.Optional(ATTR_TEXTMODE, default="normal"): cv.string, } ) @@ -43,10 +49,10 @@ vol.Schema( { vol.Optional(ATTR_TEXTMODE, default="normal"): cv.string, - vol.Exclusive(ATTR_FILENAMES, "attachments"): [cv.string], - vol.Exclusive(ATTR_URLS, "attachments"): DATA_URLS_SCHEMA, } ), + DATA_FILENAMES_SCHEMA, + DATA_URLS_SCHEMA, ) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( @@ -122,15 +128,10 @@ def send_message(self, message: str = "", **kwargs: Any) -> None: def get_filenames(data: Any) -> list[str] | None: """Extract attachment filenames from data.""" try: - data = DATA_FILENAMES_SCHEMA(data[ATTR_FILENAMES]) + data = DATA_FILENAMES_SCHEMA(data) except vol.Invalid: return None - except KeyError: - return None - except TypeError: - return None - - return data + return data[ATTR_FILENAMES] @staticmethod def get_attachments_as_bytes( @@ -140,13 +141,9 @@ def get_attachments_as_bytes( ) -> list[bytearray] | None: """Retrieve attachments from URLs defined in data.""" try: - data = DATA_URLS_SCHEMA(data[ATTR_URLS]) + data = DATA_URLS_SCHEMA(data) except vol.Invalid: return None - except KeyError: - return None - except TypeError: - return None urls = data[ATTR_URLS] attachments_as_bytes: list[bytearray] = [] diff --git a/tests/components/signal_messenger/test_notify.py b/tests/components/signal_messenger/test_notify.py index 2260a5a40a0ff..e2f76d54c87fe 100644 --- a/tests/components/signal_messenger/test_notify.py +++ b/tests/components/signal_messenger/test_notify.py @@ -139,7 +139,7 @@ def test_send_message_with_attachment_as_url( with caplog.at_level( logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" ): - data = {"urls": {"urls": [URL_ATTACHMENT]}} + data = {"urls": [URL_ATTACHMENT]} signal_notification_service.send_message(MESSAGE, data=data) assert "Sending signal message" in caplog.text @@ -155,7 +155,7 @@ def test_get_attachments( ) -> None: """Test getting attachments as URL.""" signal_requests_mock = signal_requests_mock_factory(True, str(len(CONTENT))) - data = {"urls": {"urls": [URL_ATTACHMENT]}} + data = {"urls": [URL_ATTACHMENT]} result = signal_notification_service.get_attachments_as_bytes( data, len(CONTENT), hass ) @@ -172,7 +172,7 @@ def test_get_attachments_not_on_allowlist( ) -> None: """Test getting attachments as URL that aren't on the allowlist.""" url = "http://dodgyurl.com" - data = {"urls": {"urls": [url]}} + data = {"urls": [url]} with caplog.at_level( logging.ERROR, logger="homeassistant.components.signal_messenger.notify" ): @@ -192,7 +192,7 @@ def test_get_attachments_with_large_attachment( """Test getting attachments as URL with large attachment (per Content-Length header) throws error.""" signal_requests_mock = signal_requests_mock_factory(True, str(len(CONTENT) + 1)) with pytest.raises(ValueError) as exc: - data = {"urls": {"urls": [URL_ATTACHMENT]}} + data = {"urls": [URL_ATTACHMENT]} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -208,7 +208,7 @@ def test_get_attachments_with_large_attachment_no_header( """Test getting attachments as URL with large attachment (per content length) throws error.""" signal_requests_mock = signal_requests_mock_factory() with pytest.raises(ValueError) as exc: - data = {"urls": {"urls": [URL_ATTACHMENT]}} + data = {"urls": [URL_ATTACHMENT]} signal_notification_service.get_attachments_as_bytes( data, len(CONTENT) - 1, hass ) @@ -263,7 +263,7 @@ def test_get_attachments_with_non_list_returns_none( hass: HomeAssistant, ) -> None: """Test getting attachments with non list data.""" - data = {"urls": {"urls": URL_ATTACHMENT}} + data = {"urls": URL_ATTACHMENT} result = signal_notification_service.get_attachments_as_bytes( data, len(CONTENT), hass ) @@ -278,7 +278,7 @@ def test_get_attachments_with_verify_unset( ) -> None: """Test getting attachments as URL with verify_ssl unset results in verify=true.""" signal_requests_mock = signal_requests_mock_factory() - data = {"urls": {"urls": [URL_ATTACHMENT]}} + data = {"urls": [URL_ATTACHMENT]} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -293,7 +293,7 @@ def test_get_attachments_with_verify_set_true( ) -> None: """Test getting attachments as URL with verify_ssl set to true results in verify=true.""" signal_requests_mock = signal_requests_mock_factory() - data = {"urls": {"verify_ssl": True, "urls": [URL_ATTACHMENT]}} + data = {"verify_ssl": True, "urls": [URL_ATTACHMENT]} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -308,7 +308,7 @@ def test_get_attachments_with_verify_set_false( ) -> None: """Test getting attachments as URL with verify_ssl set to false results in verify=false.""" signal_requests_mock = signal_requests_mock_factory() - data = {"urls": {"verify_ssl": False, "urls": [URL_ATTACHMENT]}} + data = {"verify_ssl": False, "urls": [URL_ATTACHMENT]} signal_notification_service.get_attachments_as_bytes(data, len(CONTENT), hass) assert signal_requests_mock.called @@ -321,7 +321,7 @@ def test_get_attachments_with_verify_set_garbage( hass: HomeAssistant, ) -> None: """Test getting attachments as URL with verify_ssl set to garbage results in None.""" - data = {"urls": {"verify_ssl": "test", "urls": [URL_ATTACHMENT]}} + data = {"verify_ssl": "test", "urls": [URL_ATTACHMENT]} result = signal_notification_service.get_attachments_as_bytes( data, len(CONTENT), hass ) From 6a68fe66d1f17a63639ec855f7cfa17fc3dd330c Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:23:44 +0000 Subject: [PATCH 5/9] Signal Messenger: Fixed unreachable return. Signed-off-by: r-xyz <100710244+r-xyz@users.noreply.github.com> --- homeassistant/components/signal_messenger/notify.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/signal_messenger/notify.py b/homeassistant/components/signal_messenger/notify.py index 1de58f5fd6c14..59b532e033a61 100644 --- a/homeassistant/components/signal_messenger/notify.py +++ b/homeassistant/components/signal_messenger/notify.py @@ -198,9 +198,8 @@ def get_attachments_as_bytes( def get_text_mode(data) -> str: """Extract text mode parameter from data.""" try: - text_mode = data.get(ATTR_TEXTMODE) - if text_mode in ["normal", "styled"]: - return text_mode + return vol.In(["normal", "styled"])(data.get(ATTR_TEXTMODE)) except AttributeError: return "normal" - return "normal" + except vol.Invalid: + return "normal" From 9d7c0a17d14d5b7630c16e39e07c6a78059de884 Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:41:31 +0000 Subject: [PATCH 6/9] Signal Messenger: adding base test for styled text_mode. Signed-off-by: r-xyz <100710244+r-xyz@users.noreply.github.com> --- .../signal_messenger/test_notify.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/components/signal_messenger/test_notify.py b/tests/components/signal_messenger/test_notify.py index 012de07df0e05..bc8418c889b09 100644 --- a/tests/components/signal_messenger/test_notify.py +++ b/tests/components/signal_messenger/test_notify.py @@ -64,6 +64,26 @@ def test_send_message( assert_sending_requests(signal_requests_mock) +def test_send_message_styled( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test send message.""" + signal_requests_mock = signal_requests_mock_factory() + with caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ): + data = {"text_mode": "styled"} + signal_notification_service.send_message(MESSAGE, data=data) + post_data = json.loads(signal_requests_mock.request_history[-1].text) + assert "Sending signal message" in caplog.text + assert signal_requests_mock.called + assert signal_requests_mock.call_count == 2 + assert post_data["text_mode"] == "styled" + assert_sending_requests(signal_requests_mock) + + def test_send_message_to_api_with_bad_data_throws_error( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker, From 4429c9289eff3b19d9fc5b9173c0ee8b926f620c Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:42:39 +0000 Subject: [PATCH 7/9] Signal Messenger: Adding additional tests for text_mode. --- .../signal_messenger/test_notify.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/components/signal_messenger/test_notify.py b/tests/components/signal_messenger/test_notify.py index bc8418c889b09..98090dc6e187f 100644 --- a/tests/components/signal_messenger/test_notify.py +++ b/tests/components/signal_messenger/test_notify.py @@ -148,6 +148,32 @@ def test_send_message_with_attachment( assert_sending_requests(signal_requests_mock, 1) +def test_send_message_styled_with_attachment( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test send message with attachment.""" + signal_requests_mock = signal_requests_mock_factory() + with ( + caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ), + tempfile.NamedTemporaryFile( + mode="w", suffix=".png", prefix=os.path.basename(__file__) + ) as temp_file, + ): + temp_file.write("attachment_data") + data = {"attachments": [temp_file.name], "text_mode": "styled"} + signal_notification_service.send_message(MESSAGE, data=data) + post_data = json.loads(signal_requests_mock.request_history[-1].text) + assert "Sending signal message" in caplog.text + assert signal_requests_mock.called + assert signal_requests_mock.call_count == 2 + assert_sending_requests(signal_requests_mock, 1) + assert post_data["text_mode"] == "styled" + + def test_send_message_with_attachment_as_url( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker, @@ -167,6 +193,26 @@ def test_send_message_with_attachment_as_url( assert_sending_requests(signal_requests_mock, 1) +def test_send_message_styled_with_attachment_as_url( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test send message with attachment as URL.""" + signal_requests_mock = signal_requests_mock_factory(True, str(len(CONTENT))) + with caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ): + data = {"urls": [URL_ATTACHMENT], "text_mode": "styled"} + signal_notification_service.send_message(MESSAGE, data=data) + post_data = json.loads(signal_requests_mock.request_history[-1].text) + assert "Sending signal message" in caplog.text + assert signal_requests_mock.called + assert signal_requests_mock.call_count == 3 + assert_sending_requests(signal_requests_mock, 1) + assert post_data["text_mode"] == "styled" + + def test_get_attachments( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker, From 4f40c1767ee91afb5d67248686a21ac1719910ff Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Mon, 17 Jun 2024 23:33:41 +0000 Subject: [PATCH 8/9] Signal Messenger styled messages: improved testing and exception handling. --- .../components/signal_messenger/notify.py | 11 +++++++-- .../signal_messenger/test_notify.py | 23 ++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/signal_messenger/notify.py b/homeassistant/components/signal_messenger/notify.py index 59b532e033a61..4e5fdc25db95b 100644 --- a/homeassistant/components/signal_messenger/notify.py +++ b/homeassistant/components/signal_messenger/notify.py @@ -29,6 +29,8 @@ ATTR_VERIFY_SSL = "verify_ssl" ATTR_TEXTMODE = "text_mode" +TEXTMODE_OPTIONS = ["normal", "styled"] + DATA_FILENAMES_SCHEMA = vol.Schema( { vol.Required(ATTR_FILENAMES): [cv.string], @@ -112,13 +114,14 @@ def send_message(self, message: str = "", **kwargs: Any) -> None: attachments_as_bytes = self.get_attachments_as_bytes( data, CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES, self._hass ) + text_mode = self.get_text_mode(data) try: self._signal_cli_rest_api.send_message( message, self._recp_nrs, filenames, attachments_as_bytes, - text_mode=self.get_text_mode(data), + text_mode=text_mode, ) except SignalCliRestApiError as ex: _LOGGER.error("%s", ex) @@ -198,8 +201,12 @@ def get_attachments_as_bytes( def get_text_mode(data) -> str: """Extract text mode parameter from data.""" try: - return vol.In(["normal", "styled"])(data.get(ATTR_TEXTMODE)) + return vol.In(TEXTMODE_OPTIONS)(data.get(ATTR_TEXTMODE)) except AttributeError: return "normal" except vol.Invalid: + _LOGGER.warning( + "'text_mode' is invalid: found '%s', defaulting to normal", + data.get(ATTR_TEXTMODE), + ) return "normal" diff --git a/tests/components/signal_messenger/test_notify.py b/tests/components/signal_messenger/test_notify.py index 98090dc6e187f..e00c8f76148ab 100644 --- a/tests/components/signal_messenger/test_notify.py +++ b/tests/components/signal_messenger/test_notify.py @@ -69,7 +69,7 @@ def test_send_message_styled( signal_requests_mock_factory: Mocker, caplog: pytest.LogCaptureFixture, ) -> None: - """Test send message.""" + """Test send styled message.""" signal_requests_mock = signal_requests_mock_factory() with caplog.at_level( logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" @@ -123,6 +123,27 @@ def test_send_message_with_bad_data_throws_vol_error( assert "extra keys not allowed" in str(exc.value) +def test_send_message_styled_with_bad_data_throws_vol_error( + signal_notification_service: SignalNotificationService, + signal_requests_mock_factory: Mocker, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test sending a styled message with bad data throws an error.""" + signal_requests_mock = signal_requests_mock_factory() + with caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ): + signal_notification_service.send_message(MESSAGE, data={"text_mode": "test"}) + post_data = json.loads(signal_requests_mock.request_history[-1].text) + + assert "Sending signal message" in caplog.text + assert "'text_mode' is invalid: found 'test', defaulting to normal" in caplog.text + assert signal_requests_mock.called + assert signal_requests_mock.call_count == 2 + assert post_data["text_mode"] == "normal" + assert_sending_requests(signal_requests_mock) + + def test_send_message_with_attachment( signal_notification_service: SignalNotificationService, signal_requests_mock_factory: Mocker, From 6ba61298f9aafce743a446c2e0723bd8f40a6d26 Mon Sep 17 00:00:00 2001 From: r-xyz <100710244+r-xyz@users.noreply.github.com> Date: Sat, 22 Jun 2024 15:00:27 +0000 Subject: [PATCH 9/9] Signal Messenger styled messages: improved data validation --- .../components/signal_messenger/notify.py | 23 ++++--------------- .../signal_messenger/test_notify.py | 18 +++++++-------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/signal_messenger/notify.py b/homeassistant/components/signal_messenger/notify.py index 4e5fdc25db95b..b93e5bb43e24f 100644 --- a/homeassistant/components/signal_messenger/notify.py +++ b/homeassistant/components/signal_messenger/notify.py @@ -34,7 +34,7 @@ DATA_FILENAMES_SCHEMA = vol.Schema( { vol.Required(ATTR_FILENAMES): [cv.string], - vol.Optional(ATTR_TEXTMODE, default="normal"): cv.string, + vol.Optional(ATTR_TEXTMODE, default="normal"): vol.In(TEXTMODE_OPTIONS), } ) @@ -42,7 +42,7 @@ { vol.Required(ATTR_URLS): [cv.url], vol.Optional(ATTR_VERIFY_SSL, default=True): cv.boolean, - vol.Optional(ATTR_TEXTMODE, default="normal"): cv.string, + vol.Optional(ATTR_TEXTMODE, default="normal"): vol.In(TEXTMODE_OPTIONS), } ) @@ -50,7 +50,7 @@ None, vol.Schema( { - vol.Optional(ATTR_TEXTMODE, default="normal"): cv.string, + vol.Optional(ATTR_TEXTMODE, default="normal"): vol.In(TEXTMODE_OPTIONS), } ), DATA_FILENAMES_SCHEMA, @@ -114,14 +114,13 @@ def send_message(self, message: str = "", **kwargs: Any) -> None: attachments_as_bytes = self.get_attachments_as_bytes( data, CONF_MAX_ALLOWED_DOWNLOAD_SIZE_BYTES, self._hass ) - text_mode = self.get_text_mode(data) try: self._signal_cli_rest_api.send_message( message, self._recp_nrs, filenames, attachments_as_bytes, - text_mode=text_mode, + text_mode="normal" if data is None else data.get(ATTR_TEXTMODE), ) except SignalCliRestApiError as ex: _LOGGER.error("%s", ex) @@ -196,17 +195,3 @@ def get_attachments_as_bytes( return None return attachments_as_bytes - - @staticmethod - def get_text_mode(data) -> str: - """Extract text mode parameter from data.""" - try: - return vol.In(TEXTMODE_OPTIONS)(data.get(ATTR_TEXTMODE)) - except AttributeError: - return "normal" - except vol.Invalid: - _LOGGER.warning( - "'text_mode' is invalid: found '%s', defaulting to normal", - data.get(ATTR_TEXTMODE), - ) - return "normal" diff --git a/tests/components/signal_messenger/test_notify.py b/tests/components/signal_messenger/test_notify.py index e00c8f76148ab..d0085fd6e21c3 100644 --- a/tests/components/signal_messenger/test_notify.py +++ b/tests/components/signal_messenger/test_notify.py @@ -129,19 +129,19 @@ def test_send_message_styled_with_bad_data_throws_vol_error( caplog: pytest.LogCaptureFixture, ) -> None: """Test sending a styled message with bad data throws an error.""" - signal_requests_mock = signal_requests_mock_factory() - with caplog.at_level( - logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + with ( + caplog.at_level( + logging.DEBUG, logger="homeassistant.components.signal_messenger.notify" + ), + pytest.raises(vol.Invalid) as exc, ): signal_notification_service.send_message(MESSAGE, data={"text_mode": "test"}) - post_data = json.loads(signal_requests_mock.request_history[-1].text) assert "Sending signal message" in caplog.text - assert "'text_mode' is invalid: found 'test', defaulting to normal" in caplog.text - assert signal_requests_mock.called - assert signal_requests_mock.call_count == 2 - assert post_data["text_mode"] == "normal" - assert_sending_requests(signal_requests_mock) + assert ( + "value must be one of ['normal', 'styled'] for dictionary value @ data['text_mode']" + in str(exc.value) + ) def test_send_message_with_attachment(