df7653dcba
The light's TCP stack resets HTTP/1.1 GET connections but requires HTTP/1.1 for PUT requests. Switch from requests to raw http.client with HTTP/1.0 for GETs and HTTP/1.1 + Connection: close for PUTs. Add retry logic (5 attempts, 1s delay) for intermittent resets.
120 lines
4.1 KiB
Python
120 lines
4.1 KiB
Python
"""Tests for elgato_cli.api."""
|
|
|
|
import json
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
import requests
|
|
|
|
from elgato_cli.api import ElgatoLight, LightState, mired_to_kelvin, kelvin_to_mired
|
|
|
|
|
|
LIGHT_RESPONSE = {
|
|
"numberOfLights": 1,
|
|
"lights": [{"on": 1, "brightness": 50, "temperature": 200}],
|
|
}
|
|
|
|
|
|
def _make_mock_conn(response_data, status=200):
|
|
"""Create a mock HTTPConnection that returns the given response."""
|
|
mock_conn = MagicMock()
|
|
mock_resp = MagicMock()
|
|
mock_resp.status = status
|
|
mock_resp.reason = "OK" if status == 200 else "Error"
|
|
mock_resp.read.return_value = json.dumps(response_data).encode()
|
|
mock_conn.getresponse.return_value = mock_resp
|
|
return mock_conn
|
|
|
|
|
|
class TestMiredKelvin:
|
|
def test_mired_to_kelvin(self):
|
|
assert mired_to_kelvin(143) == 6993
|
|
assert mired_to_kelvin(344) == 2907
|
|
assert mired_to_kelvin(200) == 5000
|
|
|
|
def test_kelvin_to_mired(self):
|
|
assert kelvin_to_mired(5000) == 200
|
|
assert kelvin_to_mired(7000) == 143
|
|
assert kelvin_to_mired(2900) == 345
|
|
|
|
def test_roundtrip(self):
|
|
for mired in [143, 200, 250, 300, 344]:
|
|
assert abs(kelvin_to_mired(mired_to_kelvin(mired)) - mired) <= 1
|
|
|
|
|
|
class TestElgatoLight:
|
|
@patch("elgato_cli.api.http.client.HTTPConnection")
|
|
def test_get_state(self, mock_http_cls):
|
|
mock_http_cls.return_value = _make_mock_conn(LIGHT_RESPONSE)
|
|
light = ElgatoLight("192.168.1.100")
|
|
state = light.get_state()
|
|
assert state == LightState(on=True, brightness=50, temperature=200)
|
|
mock_http_cls.assert_called_with("192.168.1.100", 9123, timeout=5)
|
|
|
|
@patch("elgato_cli.api.http.client.HTTPConnection")
|
|
def test_set_state_partial(self, mock_http_cls):
|
|
updated = {
|
|
"numberOfLights": 1,
|
|
"lights": [{"on": 1, "brightness": 80, "temperature": 200}],
|
|
}
|
|
# First call: get_state (GET), second call: put (PUT)
|
|
mock_http_cls.side_effect = [
|
|
_make_mock_conn(LIGHT_RESPONSE),
|
|
_make_mock_conn(updated),
|
|
]
|
|
|
|
light = ElgatoLight("192.168.1.100")
|
|
state = light.set_state(brightness=80)
|
|
|
|
assert state.brightness == 80
|
|
assert mock_http_cls.call_count == 2
|
|
|
|
@patch("elgato_cli.api.http.client.HTTPConnection")
|
|
def test_toggle(self, mock_http_cls):
|
|
toggled = {
|
|
"numberOfLights": 1,
|
|
"lights": [{"on": 0, "brightness": 50, "temperature": 200}],
|
|
}
|
|
# toggle calls: get_state, then set_state(get_state + put)
|
|
mock_http_cls.side_effect = [
|
|
_make_mock_conn(LIGHT_RESPONSE), # toggle -> get_state
|
|
_make_mock_conn(LIGHT_RESPONSE), # set_state -> get_state
|
|
_make_mock_conn(toggled), # set_state -> put
|
|
]
|
|
|
|
light = ElgatoLight("192.168.1.100")
|
|
state = light.toggle()
|
|
assert state.on is False
|
|
|
|
@patch("elgato_cli.api.http.client.HTTPConnection")
|
|
def test_get_info(self, mock_http_cls):
|
|
info_resp = {
|
|
"productName": "Elgato Key Light",
|
|
"serialNumber": "AB12CD34",
|
|
"firmwareVersion": "1.0.3",
|
|
}
|
|
mock_http_cls.return_value = _make_mock_conn(info_resp)
|
|
|
|
light = ElgatoLight("192.168.1.100")
|
|
info = light.get_info()
|
|
assert info["productName"] == "Elgato Key Light"
|
|
|
|
@patch("elgato_cli.api.time.sleep")
|
|
@patch("elgato_cli.api.http.client.HTTPConnection")
|
|
def test_retry_on_connection_error(self, mock_http_cls, mock_sleep):
|
|
fail_conn = MagicMock()
|
|
fail_conn.request.side_effect = ConnectionError("reset")
|
|
|
|
ok_conn = _make_mock_conn(LIGHT_RESPONSE)
|
|
|
|
mock_http_cls.side_effect = [fail_conn, ok_conn]
|
|
|
|
light = ElgatoLight("192.168.1.100")
|
|
state = light.get_state()
|
|
assert state == LightState(on=True, brightness=50, temperature=200)
|
|
assert mock_http_cls.call_count == 2
|
|
mock_sleep.assert_called_once_with(1.0)
|
|
|
|
def test_custom_port(self):
|
|
light = ElgatoLight("10.0.0.5", port=8080)
|
|
assert light.base_url == "http://10.0.0.5:8080/elgato"
|