Browse Source

added command line parameters --mqtt-username and --mqtt-password

Fabian Peter Hammerle 4 years ago
parent
commit
396e3423ec
4 changed files with 105 additions and 7 deletions
  1. 3 0
      CHANGELOG.md
  2. 18 2
      switchbot_mqtt/__init__.py
  3. 45 4
      tests/test_cli.py
  4. 39 1
      tests/test_mqtt.py

+ 3 - 0
CHANGELOG.md

@@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
+### Added
+- Added command line parameters `--mqtt-username` and `--mqtt-password`
+
 ### Fixed
 - Fixed executable name in command line help
 - Docker: no longer require build arg `SWITCHBOT_MQTT_VERSION`

+ 18 - 2
switchbot_mqtt/__init__.py

@@ -117,7 +117,12 @@ def _mqtt_on_message(
     _send_command(switchbot_mac_address=switchbot_mac_address, action=action)
 
 
-def _run(mqtt_host: str, mqtt_port: int) -> None:
+def _run(
+    mqtt_host: str,
+    mqtt_port: int,
+    mqtt_username: typing.Optional[str],
+    mqtt_password: typing.Optional[str],
+) -> None:
     # https://pypi.org/project/paho-mqtt/
     mqtt_client = paho.mqtt.client.Client()
     mqtt_client.on_connect = _mqtt_on_connect
@@ -125,6 +130,10 @@ def _run(mqtt_host: str, mqtt_port: int) -> None:
     _LOGGER.info(
         "connecting to MQTT broker %s:%d", mqtt_host, mqtt_port,
     )
+    if mqtt_username:
+        mqtt_client.username_pw_set(username=mqtt_username, password=mqtt_password)
+    elif mqtt_password:
+        raise ValueError("Missing MQTT username")
     mqtt_client.connect(host=mqtt_host, port=mqtt_port)
     mqtt_client.loop_forever()
 
@@ -141,5 +150,12 @@ def _main() -> None:
     )
     argparser.add_argument("--mqtt-host", type=str, required=True)
     argparser.add_argument("--mqtt-port", type=int, default=1883)
+    argparser.add_argument("--mqtt-username", type=str)
+    argparser.add_argument("--mqtt-password", type=str)
     args = argparser.parse_args()
-    _run(mqtt_host=args.mqtt_host, mqtt_port=args.mqtt_port)
+    _run(
+        mqtt_host=args.mqtt_host,
+        mqtt_port=args.mqtt_port,
+        mqtt_username=args.mqtt_username,
+        mqtt_password=args.mqtt_password,
+    )

+ 45 - 4
tests/test_cli.py

@@ -6,22 +6,63 @@ import switchbot_mqtt
 
 
 @pytest.mark.parametrize(
-    ("argv", "expected_mqtt_host", "expected_mqtt_port"),
+    (
+        "argv",
+        "expected_mqtt_host",
+        "expected_mqtt_port",
+        "expected_username",
+        "expected_password",
+    ),
     [
-        (["", "--mqtt-host", "mqtt-broker.local"], "mqtt-broker.local", 1883),
+        (
+            ["", "--mqtt-host", "mqtt-broker.local"],
+            "mqtt-broker.local",
+            1883,
+            None,
+            None,
+        ),
         (
             ["", "--mqtt-host", "mqtt-broker.local", "--mqtt-port", "8883"],
             "mqtt-broker.local",
             8883,
+            None,
+            None,
+        ),
+        (
+            ["", "--mqtt-host", "mqtt-broker.local", "--mqtt-username", "me"],
+            "mqtt-broker.local",
+            1883,
+            "me",
+            None,
+        ),
+        (
+            [
+                "",
+                "--mqtt-host",
+                "mqtt-broker.local",
+                "--mqtt-username",
+                "me",
+                "--mqtt-password",
+                "secret",
+            ],
+            "mqtt-broker.local",
+            1883,
+            "me",
+            "secret",
         ),
     ],
 )
-def test__main(argv, expected_mqtt_host, expected_mqtt_port):
+def test__main(
+    argv, expected_mqtt_host, expected_mqtt_port, expected_username, expected_password
+):
     with unittest.mock.patch("switchbot_mqtt._run") as run_mock, unittest.mock.patch(
         "sys.argv", argv
     ):
         # pylint: disable=protected-access
         switchbot_mqtt._main()
     run_mock.assert_called_once_with(
-        mqtt_host=expected_mqtt_host, mqtt_port=expected_mqtt_port,
+        mqtt_host=expected_mqtt_host,
+        mqtt_port=expected_mqtt_port,
+        mqtt_username=expected_username,
+        mqtt_password=expected_password,
     )

+ 39 - 1
tests/test_mqtt.py

@@ -16,8 +16,14 @@ def test__run(mqtt_host, mqtt_port):
     ) as mqtt_client_mock, unittest.mock.patch(
         "switchbot_mqtt._mqtt_on_message"
     ) as message_handler_mock:
-        switchbot_mqtt._run(mqtt_host=mqtt_host, mqtt_port=mqtt_port)
+        switchbot_mqtt._run(
+            mqtt_host=mqtt_host,
+            mqtt_port=mqtt_port,
+            mqtt_username=None,
+            mqtt_password=None,
+        )
     mqtt_client_mock.assert_called_once_with()
+    assert not mqtt_client_mock().username_pw_set.called
     mqtt_client_mock().connect.assert_called_once_with(host=mqtt_host, port=mqtt_port)
     mqtt_client_mock().socket().getpeername.return_value = (mqtt_host, mqtt_port)
     mqtt_client_mock().on_connect(mqtt_client_mock(), None, {}, 0)
@@ -29,6 +35,38 @@ def test__run(mqtt_host, mqtt_port):
     mqtt_client_mock().loop_forever.assert_called_once_with()
 
 
+@pytest.mark.parametrize("mqtt_host", ["mqtt-broker.local"])
+@pytest.mark.parametrize("mqtt_port", [1833])
+@pytest.mark.parametrize("mqtt_username", ["me"])
+@pytest.mark.parametrize("mqtt_password", [None, "secret"])
+def test__run_authentication(mqtt_host, mqtt_port, mqtt_username, mqtt_password):
+    with unittest.mock.patch("paho.mqtt.client.Client") as mqtt_client_mock:
+        switchbot_mqtt._run(
+            mqtt_host=mqtt_host,
+            mqtt_port=mqtt_port,
+            mqtt_username=mqtt_username,
+            mqtt_password=mqtt_password,
+        )
+    mqtt_client_mock.assert_called_once_with()
+    mqtt_client_mock().username_pw_set.assert_called_once_with(
+        username=mqtt_username, password=mqtt_password,
+    )
+
+
+@pytest.mark.parametrize("mqtt_host", ["mqtt-broker.local"])
+@pytest.mark.parametrize("mqtt_port", [1833])
+@pytest.mark.parametrize("mqtt_password", ["secret"])
+def test__run_authentication_missing_username(mqtt_host, mqtt_port, mqtt_password):
+    with unittest.mock.patch("paho.mqtt.client.Client"):
+        with pytest.raises(ValueError):
+            switchbot_mqtt._run(
+                mqtt_host=mqtt_host,
+                mqtt_port=mqtt_port,
+                mqtt_username=None,
+                mqtt_password=mqtt_password,
+            )
+
+
 @pytest.mark.parametrize(
     ("topic", "payload", "expected_mac_address", "expected_action"),
     [