test_mqtt_message.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import logging
  2. import unittest.mock
  3. import pytest
  4. from paho.mqtt.client import MQTTMessage
  5. import intertechno_cc1101_mqtt
  6. # pylint: disable=protected-access
  7. @pytest.mark.parametrize(
  8. ("topic", "address"),
  9. (
  10. (b"intertechno-cc1101/12345678/0/set", 12345678),
  11. (b"intertechno-cc1101/1234/0/set", 1234),
  12. ),
  13. )
  14. def test__mqtt_on_message_address(topic, address):
  15. message = MQTTMessage(topic=topic)
  16. message.payload = b"ON"
  17. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  18. intertechno_cc1101_mqtt._mqtt_on_message("dummy", {}, message)
  19. remote_control_mock.assert_called_once_with(address=address)
  20. @pytest.mark.parametrize(
  21. ("topic", "address_str"),
  22. (
  23. (b"intertechno-cc1101/abcdef/0/set", "abcdef"),
  24. (b"intertechno-cc1101//0/set", ""),
  25. ),
  26. )
  27. def test__mqtt_on_message_invalid_address(caplog, topic, address_str):
  28. message = MQTTMessage(topic=topic)
  29. message.payload = b"ON"
  30. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  31. with caplog.at_level(logging.WARNING):
  32. intertechno_cc1101_mqtt._mqtt_on_message("dummy", {}, message)
  33. remote_control_mock.assert_not_called()
  34. assert caplog.record_tuples == [
  35. (
  36. "intertechno_cc1101_mqtt",
  37. logging.WARNING,
  38. "failed to parse address {!r}, expected integer; ignoring message".format(
  39. address_str
  40. ),
  41. )
  42. ]
  43. @pytest.mark.parametrize(
  44. ("topic", "button_index"),
  45. ((b"intertechno-cc1101/12345678/0/set", 0), (b"intertechno-cc1101/1234/7/set", 7)),
  46. )
  47. @pytest.mark.parametrize(
  48. ("payload", "turn_on"),
  49. ((b"ON", True), (b"On", True), (b"on", True), (b"OFF", False), (b"off", False)),
  50. )
  51. @pytest.mark.parametrize("retain", [True, False])
  52. def test__mqtt_on_message_button_index_action(
  53. topic, button_index, payload, turn_on, retain
  54. ):
  55. message = MQTTMessage(topic=topic)
  56. message.payload = payload
  57. message.retain = retain
  58. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  59. intertechno_cc1101_mqtt._mqtt_on_message("dummy", {}, message)
  60. if turn_on:
  61. remote_control_mock().turn_on.assert_called_once_with(button_index=button_index)
  62. remote_control_mock().turn_off.assert_not_called()
  63. else:
  64. remote_control_mock().turn_off.assert_called_once_with(
  65. button_index=button_index
  66. )
  67. remote_control_mock().turn_on.assert_not_called()
  68. @pytest.mark.parametrize(
  69. ("topic", "button_index_str"),
  70. (
  71. (b"intertechno-cc1101/12345678/abc/set", "abc"),
  72. (b"intertechno-cc1101/12345678//set", ""),
  73. ),
  74. )
  75. def test__mqtt_on_message_invalid_button_index(caplog, topic, button_index_str):
  76. message = MQTTMessage(topic=topic)
  77. message.payload = b"ON"
  78. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  79. with caplog.at_level(logging.WARNING):
  80. intertechno_cc1101_mqtt._mqtt_on_message("dummy", {}, message)
  81. remote_control_mock().turn_on.assert_not_called()
  82. remote_control_mock().turn_off.assert_not_called()
  83. assert caplog.record_tuples == [
  84. (
  85. "intertechno_cc1101_mqtt",
  86. logging.WARNING,
  87. "failed to parse button index {!r}, expected integer; ignoring message".format(
  88. button_index_str
  89. ),
  90. )
  91. ]
  92. @pytest.mark.parametrize(
  93. ("topic", "address", "button_index"),
  94. (
  95. (b"intertechno-cc1101/some-name/set", 21, 0),
  96. (b"intertechno-cc1101/another-name/set", 42, 7),
  97. ),
  98. )
  99. def test__mqtt_on_message_alias(topic, address, button_index):
  100. message = MQTTMessage(topic=topic)
  101. message.payload = b"ON"
  102. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  103. intertechno_cc1101_mqtt._mqtt_on_message(
  104. "dummy",
  105. {
  106. "some-name": {"address": 21, "button-index": 0},
  107. "another-name": {"address": "42", "button-index": "7"}, # :O
  108. },
  109. message,
  110. )
  111. remote_control_mock.assert_called_once_with(address=address)
  112. remote_control_mock().turn_on.assert_called_once_with(button_index=button_index)
  113. @pytest.mark.parametrize(
  114. ("topic", "alias"),
  115. (
  116. (b"intertechno-cc1101//set", ""),
  117. (b"intertechno-cc1101/unknown-name/set", "unknown-name"),
  118. ),
  119. )
  120. def test__mqtt_on_message_undefined_alias(caplog, topic, alias):
  121. message = MQTTMessage(topic=topic)
  122. message.payload = b"ON"
  123. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  124. with caplog.at_level(logging.WARNING):
  125. intertechno_cc1101_mqtt._mqtt_on_message(
  126. "dummy", {"some-name": {"address": 21, "button-index": 0}}, message
  127. )
  128. remote_control_mock.assert_not_called()
  129. assert caplog.record_tuples == [
  130. (
  131. "intertechno_cc1101_mqtt",
  132. logging.WARNING,
  133. "unknown alias {!r}; ignoring message".format(alias),
  134. )
  135. ]
  136. @pytest.mark.parametrize(
  137. "aliases",
  138. (
  139. {"some-name": {"address": 21}},
  140. {"some-name": {"button-index": 0}},
  141. {"some-name": {"adresse": 21, "button-index": 0}},
  142. ),
  143. )
  144. def test__mqtt_on_message_alias_missing_attrs(caplog, aliases):
  145. message = MQTTMessage(topic=b"intertechno-cc1101/some-name/set")
  146. message.payload = b"ON"
  147. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  148. with caplog.at_level(logging.WARNING):
  149. intertechno_cc1101_mqtt._mqtt_on_message("dummy", aliases, message)
  150. remote_control_mock.assert_not_called()
  151. assert caplog.record_tuples == [
  152. (
  153. "intertechno_cc1101_mqtt",
  154. logging.ERROR,
  155. "alias file must provide fields 'address' and 'button-index' for each alias",
  156. )
  157. ]
  158. @pytest.mark.parametrize(
  159. "topic", (b"intertechno-cc1101/123456789/0/set", b"intertechno-cc1101/-21/0/set")
  160. )
  161. def test__mqtt_on_message_remote_init_failed(caplog, topic):
  162. message = MQTTMessage(topic=topic)
  163. message.payload = b"ON"
  164. with caplog.at_level(logging.WARNING):
  165. intertechno_cc1101_mqtt._mqtt_on_message("dummy", {}, message)
  166. assert len(caplog.records) == 1
  167. assert caplog.records[0].levelno == logging.WARNING
  168. assert (
  169. caplog.records[0].message
  170. == "failed to initialize remote control, invalid address? ignoring message"
  171. )
  172. assert isinstance(caplog.records[0].exc_info[1], AssertionError)
  173. def test__mqtt_on_message_transmission_failed(caplog):
  174. message = MQTTMessage(topic=b"intertechno-cc1101/12345678/3/set")
  175. message.payload = b"ON"
  176. with unittest.mock.patch(
  177. "cc1101.CC1101.__enter__",
  178. side_effect=FileNotFoundError("[Errno 2] No such file or directory"),
  179. ), caplog.at_level(logging.ERROR):
  180. intertechno_cc1101_mqtt._mqtt_on_message("dummy", {}, message)
  181. assert len(caplog.records) == 1
  182. assert caplog.records[0].levelno == logging.ERROR
  183. assert caplog.records[0].message == "failed to send signal"
  184. assert isinstance(caplog.records[0].exc_info[1], FileNotFoundError)
  185. @pytest.mark.parametrize("payload", (b"EIN", b"aus", b""))
  186. def test__mqtt_on_message_invalid_payload(caplog, payload):
  187. message = MQTTMessage(topic=b"intertechno-cc1101/1234/7/set")
  188. message.payload = payload
  189. with unittest.mock.patch("intertechno_cc1101.RemoteControl") as remote_control_mock:
  190. intertechno_cc1101_mqtt._mqtt_on_message("dummy", {}, message)
  191. remote_control_mock().turn_off.assert_not_called()
  192. remote_control_mock().turn_on.assert_not_called()
  193. assert caplog.record_tuples == [
  194. (
  195. "intertechno_cc1101_mqtt",
  196. 30,
  197. "unexpected payload {!r}; expected 'ON' or 'OFF'".format(payload),
  198. )
  199. ]