123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- import logging
- import unittest.mock
- import pytest
- from paho.mqtt.client import MQTTMessage
- import intertechno_cc1101_mqtt
- # pylint: disable=protected-access
- @pytest.mark.parametrize(
- ("topic", "address"),
- (
- (b"intertechno-cc1101/12345678/0/set", 12345678),
- (b"intertechno-cc1101/1234/0/set", 1234),
- ),
- )
- def test__mqtt_on_message_address(topic, address):
- message = MQTTMessage(topic=topic)
- message.payload = b"ON"
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(aliases={}, power_setting=0xC6),
- message,
- )
- remote_control_mock.assert_called_once_with(address=address)
- @pytest.mark.parametrize(
- ("topic", "address_str"),
- (
- (b"intertechno-cc1101/abcdef/0/set", "abcdef"),
- (b"intertechno-cc1101//0/set", ""),
- ),
- )
- def test__mqtt_on_message_invalid_address(caplog, topic, address_str):
- message = MQTTMessage(topic=topic)
- message.payload = b"ON"
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- with caplog.at_level(logging.WARNING):
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(
- aliases={}, power_setting=0xC6
- ),
- message,
- )
- remote_control_mock.assert_not_called()
- assert caplog.record_tuples == [
- (
- "intertechno_cc1101_mqtt",
- logging.WARNING,
- "failed to parse address {!r}, expected integer; ignoring message".format(
- address_str
- ),
- )
- ]
- @pytest.mark.parametrize(
- ("topic", "button_index"),
- ((b"intertechno-cc1101/12345678/0/set", 0), (b"intertechno-cc1101/1234/7/set", 7)),
- )
- @pytest.mark.parametrize(
- ("payload", "turn_on"),
- ((b"ON", True), (b"On", True), (b"on", True), (b"OFF", False), (b"off", False)),
- )
- @pytest.mark.parametrize("retain", [True, False])
- @pytest.mark.parametrize("power_setting", [0xC6, 0xC0])
- def test__mqtt_on_message_button_index_action(
- topic, button_index, payload, turn_on, retain, power_setting
- ):
- # pylint: disable=too-many-arguments
- message = MQTTMessage(topic=topic)
- message.payload = payload
- message.retain = retain
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(
- aliases={}, power_setting=power_setting
- ),
- message,
- )
- if turn_on:
- remote_control_mock().turn_on.assert_called_once_with(
- button_index=button_index, power_setting=power_setting
- )
- remote_control_mock().turn_off.assert_not_called()
- else:
- remote_control_mock().turn_off.assert_called_once_with(
- button_index=button_index, power_setting=power_setting
- )
- remote_control_mock().turn_on.assert_not_called()
- @pytest.mark.parametrize(
- ("topic", "button_index_str"),
- (
- (b"intertechno-cc1101/12345678/abc/set", "abc"),
- (b"intertechno-cc1101/12345678//set", ""),
- ),
- )
- def test__mqtt_on_message_invalid_button_index(caplog, topic, button_index_str):
- message = MQTTMessage(topic=topic)
- message.payload = b"ON"
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- with caplog.at_level(logging.WARNING):
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(
- aliases={}, power_setting=0xC6
- ),
- message,
- )
- remote_control_mock().turn_on.assert_not_called()
- remote_control_mock().turn_off.assert_not_called()
- assert caplog.record_tuples == [
- (
- "intertechno_cc1101_mqtt",
- logging.WARNING,
- "failed to parse button index {!r}, expected integer; ignoring message".format(
- button_index_str
- ),
- )
- ]
- @pytest.mark.parametrize(
- ("topic", "address", "button_index"),
- (
- (b"intertechno-cc1101/some-name/set", 21, 0),
- (b"intertechno-cc1101/another-name/set", 42, 7),
- ),
- )
- def test__mqtt_on_message_alias(topic, address, button_index):
- message = MQTTMessage(topic=topic)
- message.payload = b"ON"
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(
- aliases={
- "some-name": {"address": 21, "button-index": 0},
- "another-name": {"address": "42", "button-index": "7"}, # :O
- },
- power_setting=0xC6,
- ),
- message,
- )
- remote_control_mock.assert_called_once_with(address=address)
- remote_control_mock().turn_on.assert_called_once_with(
- button_index=button_index, power_setting=0xC6
- )
- @pytest.mark.parametrize(
- ("topic", "alias"),
- (
- (b"intertechno-cc1101//set", ""),
- (b"intertechno-cc1101/unknown-name/set", "unknown-name"),
- ),
- )
- def test__mqtt_on_message_undefined_alias(caplog, topic, alias):
- message = MQTTMessage(topic=topic)
- message.payload = b"ON"
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- with caplog.at_level(logging.WARNING):
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(
- aliases={"some-name": {"address": 21, "button-index": 0}},
- power_setting=0xC6,
- ),
- message,
- )
- remote_control_mock.assert_not_called()
- assert caplog.record_tuples == [
- (
- "intertechno_cc1101_mqtt",
- logging.WARNING,
- "unknown alias {!r}; ignoring message".format(alias),
- )
- ]
- @pytest.mark.parametrize(
- "aliases",
- (
- {"some-name": {"address": 21}},
- {"some-name": {"button-index": 0}},
- {"some-name": {"adresse": 21, "button-index": 0}},
- ),
- )
- def test__mqtt_on_message_alias_missing_attrs(caplog, aliases):
- message = MQTTMessage(topic=b"intertechno-cc1101/some-name/set")
- message.payload = b"ON"
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- with caplog.at_level(logging.WARNING):
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(
- aliases=aliases, power_setting=0xC6
- ),
- message,
- )
- remote_control_mock.assert_not_called()
- assert caplog.record_tuples == [
- (
- "intertechno_cc1101_mqtt",
- logging.ERROR,
- "alias file must provide fields 'address' and 'button-index' for each alias",
- )
- ]
- @pytest.mark.parametrize(
- "topic", (b"intertechno-cc1101/123456789/0/set", b"intertechno-cc1101/-21/0/set")
- )
- def test__mqtt_on_message_remote_init_failed(caplog, topic):
- message = MQTTMessage(topic=topic)
- message.payload = b"ON"
- with caplog.at_level(logging.WARNING):
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(aliases={}, power_setting=0xC6),
- message,
- )
- assert len(caplog.records) == 1
- assert caplog.records[0].levelno == logging.WARNING
- assert (
- caplog.records[0].message
- == "failed to initialize remote control, invalid address? ignoring message"
- )
- assert isinstance(caplog.records[0].exc_info[1], ValueError)
- def test__mqtt_on_message_transmission_failed(caplog):
- message = MQTTMessage(topic=b"intertechno-cc1101/12345678/3/set")
- message.payload = b"ON"
- with unittest.mock.patch(
- "cc1101.CC1101.__enter__",
- side_effect=FileNotFoundError("[Errno 2] No such file or directory"),
- ), caplog.at_level(logging.ERROR):
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(aliases={}, power_setting=0xC6),
- message,
- )
- assert len(caplog.records) == 1
- assert caplog.records[0].levelno == logging.ERROR
- assert caplog.records[0].message == "failed to send signal"
- assert isinstance(caplog.records[0].exc_info[1], FileNotFoundError)
- @pytest.mark.parametrize("payload", (b"EIN", b"aus", b""))
- def test__mqtt_on_message_invalid_payload(caplog, payload):
- message = MQTTMessage(topic=b"intertechno-cc1101/1234/7/set")
- message.payload = payload
- with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
- intertechno_cc1101_mqtt._mqtt_on_message(
- "dummy",
- intertechno_cc1101_mqtt._MQTTEventUserData(aliases={}, power_setting=0xC6),
- message,
- )
- remote_control_mock().turn_off.assert_not_called()
- remote_control_mock().turn_on.assert_not_called()
- assert caplog.record_tuples == [
- (
- "intertechno_cc1101_mqtt",
- 30,
- "unexpected payload {!r}; expected 'ON' or 'OFF'".format(payload),
- )
- ]
|