test_mqtt.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import unittest.mock
  2. import pytest
  3. from paho.mqtt.client import MQTTMessage
  4. import switchbot_mqtt
  5. # pylint: disable=protected-access
  6. @pytest.mark.parametrize("mqtt_host", ["mqtt-broker.local"])
  7. @pytest.mark.parametrize("mqtt_port", [1833])
  8. def test__run(mqtt_host, mqtt_port):
  9. with unittest.mock.patch(
  10. "paho.mqtt.client.Client"
  11. ) as mqtt_client_mock, unittest.mock.patch(
  12. "switchbot_mqtt._mqtt_on_message"
  13. ) as message_handler_mock:
  14. switchbot_mqtt._run(
  15. mqtt_host=mqtt_host,
  16. mqtt_port=mqtt_port,
  17. mqtt_username=None,
  18. mqtt_password=None,
  19. )
  20. mqtt_client_mock.assert_called_once_with()
  21. assert not mqtt_client_mock().username_pw_set.called
  22. mqtt_client_mock().connect.assert_called_once_with(host=mqtt_host, port=mqtt_port)
  23. mqtt_client_mock().socket().getpeername.return_value = (mqtt_host, mqtt_port)
  24. mqtt_client_mock().on_connect(mqtt_client_mock(), None, {}, 0)
  25. mqtt_client_mock().subscribe.assert_called_once_with(
  26. "homeassistant/switch/switchbot/+/set"
  27. )
  28. mqtt_client_mock().on_message(mqtt_client_mock(), None, "message")
  29. message_handler_mock.assert_called_once()
  30. mqtt_client_mock().loop_forever.assert_called_once_with()
  31. @pytest.mark.parametrize("mqtt_host", ["mqtt-broker.local"])
  32. @pytest.mark.parametrize("mqtt_port", [1833])
  33. @pytest.mark.parametrize("mqtt_username", ["me"])
  34. @pytest.mark.parametrize("mqtt_password", [None, "secret"])
  35. def test__run_authentication(mqtt_host, mqtt_port, mqtt_username, mqtt_password):
  36. with unittest.mock.patch("paho.mqtt.client.Client") as mqtt_client_mock:
  37. switchbot_mqtt._run(
  38. mqtt_host=mqtt_host,
  39. mqtt_port=mqtt_port,
  40. mqtt_username=mqtt_username,
  41. mqtt_password=mqtt_password,
  42. )
  43. mqtt_client_mock.assert_called_once_with()
  44. mqtt_client_mock().username_pw_set.assert_called_once_with(
  45. username=mqtt_username, password=mqtt_password,
  46. )
  47. @pytest.mark.parametrize("mqtt_host", ["mqtt-broker.local"])
  48. @pytest.mark.parametrize("mqtt_port", [1833])
  49. @pytest.mark.parametrize("mqtt_password", ["secret"])
  50. def test__run_authentication_missing_username(mqtt_host, mqtt_port, mqtt_password):
  51. with unittest.mock.patch("paho.mqtt.client.Client"):
  52. with pytest.raises(ValueError):
  53. switchbot_mqtt._run(
  54. mqtt_host=mqtt_host,
  55. mqtt_port=mqtt_port,
  56. mqtt_username=None,
  57. mqtt_password=mqtt_password,
  58. )
  59. @pytest.mark.parametrize(
  60. ("topic", "payload", "expected_mac_address", "expected_action"),
  61. [
  62. (
  63. b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/set",
  64. b"ON",
  65. "aa:bb:cc:dd:ee:ff",
  66. switchbot_mqtt._SwitchbotAction.ON,
  67. ),
  68. (
  69. b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/set",
  70. b"OFF",
  71. "aa:bb:cc:dd:ee:ff",
  72. switchbot_mqtt._SwitchbotAction.OFF,
  73. ),
  74. (
  75. b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/set",
  76. b"on",
  77. "aa:bb:cc:dd:ee:ff",
  78. switchbot_mqtt._SwitchbotAction.ON,
  79. ),
  80. (
  81. b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/set",
  82. b"off",
  83. "aa:bb:cc:dd:ee:ff",
  84. switchbot_mqtt._SwitchbotAction.OFF,
  85. ),
  86. (
  87. b"homeassistant/switch/switchbot/aa:01:23:45:67:89/set",
  88. b"ON",
  89. "aa:01:23:45:67:89",
  90. switchbot_mqtt._SwitchbotAction.ON,
  91. ),
  92. ],
  93. )
  94. def test__mqtt_on_message(
  95. topic: bytes,
  96. payload: bytes,
  97. expected_mac_address: str,
  98. expected_action: switchbot_mqtt._SwitchbotAction,
  99. ):
  100. message = MQTTMessage(topic=topic)
  101. message.payload = payload
  102. with unittest.mock.patch("switchbot_mqtt._send_command") as send_command_mock:
  103. switchbot_mqtt._mqtt_on_message("client_dummy", None, message)
  104. send_command_mock.assert_called_once_with(
  105. mqtt_client="client_dummy",
  106. switchbot_mac_address=expected_mac_address,
  107. action=expected_action,
  108. )
  109. @pytest.mark.parametrize(
  110. ("topic", "payload"),
  111. [
  112. (b"homeassistant/switch/switchbot/aa:01:23:4E:RR:OR/set", b"ON"),
  113. (b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff", b"on"),
  114. (b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/change", b"ON"),
  115. (b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/set", b""),
  116. (b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/set", b"EIN"),
  117. ],
  118. )
  119. def test__mqtt_on_message_ignored(
  120. topic: bytes, payload: bytes,
  121. ):
  122. message = MQTTMessage(topic=topic)
  123. message.payload = payload
  124. with unittest.mock.patch("switchbot_mqtt._send_command") as send_command_mock:
  125. switchbot_mqtt._mqtt_on_message(None, None, message)
  126. assert not send_command_mock.called
  127. @pytest.mark.parametrize(
  128. ("topic", "payload"),
  129. [(b"homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/set", b"ON")],
  130. )
  131. def test__mqtt_on_message_ignored_retained(
  132. topic: bytes, payload: bytes,
  133. ):
  134. message = MQTTMessage(topic=topic)
  135. message.payload = payload
  136. message.retain = True
  137. with unittest.mock.patch("switchbot_mqtt._send_command") as send_command_mock:
  138. switchbot_mqtt._mqtt_on_message(None, None, message)
  139. assert not send_command_mock.called
  140. @pytest.mark.parametrize(
  141. ("switchbot_mac_address", "expected_topic"),
  142. # https://www.home-assistant.io/docs/mqtt/discovery/#switches
  143. [("aa:bb:cc:dd:ee:ff", "homeassistant/switch/switchbot/aa:bb:cc:dd:ee:ff/state")],
  144. )
  145. @pytest.mark.parametrize(
  146. ("state", "expected_payload"),
  147. [
  148. (switchbot_mqtt._SwitchbotState.ON, b"ON"),
  149. (switchbot_mqtt._SwitchbotState.OFF, b"OFF"),
  150. ],
  151. )
  152. def test__report_state(
  153. state: switchbot_mqtt._SwitchbotState,
  154. switchbot_mac_address: str,
  155. expected_topic: str,
  156. expected_payload: bytes,
  157. ):
  158. mqtt_client_mock = unittest.mock.MagicMock()
  159. switchbot_mqtt._report_state(
  160. mqtt_client=mqtt_client_mock,
  161. switchbot_mac_address=switchbot_mac_address,
  162. switchbot_state=state,
  163. )
  164. mqtt_client_mock.publish.assert_called_once_with(
  165. topic=expected_topic, payload=expected_payload, retain=True,
  166. )