2020-05-27 14:55:18 +00:00
|
|
|
from datetime import datetime
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
import pytest # type: ignore # https://github.com/pytest-dev/pytest/issues/3342
|
|
|
|
|
|
|
|
from kasa import SmartDeviceException
|
2021-09-23 22:24:44 +00:00
|
|
|
from kasa.smartstrip import SmartStripPlug
|
2020-05-27 14:55:18 +00:00
|
|
|
|
2022-11-13 22:34:47 +00:00
|
|
|
from .conftest import handle_turn_on, has_emeter, no_emeter, turn_on
|
2020-05-27 14:55:18 +00:00
|
|
|
from .newfakes import PLUG_SCHEMA, TZ_SCHEMA, FakeTransportProtocol
|
|
|
|
|
|
|
|
|
|
|
|
async def test_state_info(dev):
|
|
|
|
assert isinstance(dev.state_information, dict)
|
|
|
|
|
|
|
|
|
2021-09-19 21:45:48 +00:00
|
|
|
@pytest.mark.requires_dummy
|
2020-05-27 14:55:18 +00:00
|
|
|
async def test_invalid_connection(dev):
|
|
|
|
with patch.object(FakeTransportProtocol, "query", side_effect=SmartDeviceException):
|
|
|
|
with pytest.raises(SmartDeviceException):
|
|
|
|
await dev.update()
|
2021-09-19 21:43:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
@has_emeter
|
|
|
|
async def test_initial_update_emeter(dev, mocker):
|
|
|
|
"""Test that the initial update performs second query if emeter is available."""
|
|
|
|
dev._last_update = None
|
|
|
|
spy = mocker.spy(dev.protocol, "query")
|
|
|
|
await dev.update()
|
2021-09-23 22:24:44 +00:00
|
|
|
assert spy.call_count == 2 + len(dev.children)
|
2021-09-19 21:43:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
@no_emeter
|
|
|
|
async def test_initial_update_no_emeter(dev, mocker):
|
|
|
|
"""Test that the initial update performs second query if emeter is available."""
|
|
|
|
dev._last_update = None
|
|
|
|
spy = mocker.spy(dev.protocol, "query")
|
|
|
|
await dev.update()
|
2022-04-05 16:16:36 +00:00
|
|
|
# 2 calls are necessary as some devices crash on unexpected modules
|
|
|
|
# See #105, #120, #161
|
|
|
|
assert spy.call_count == 2
|
2020-05-27 14:55:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_query_helper(dev):
|
|
|
|
with pytest.raises(SmartDeviceException):
|
|
|
|
await dev._query_helper("test", "testcmd", {})
|
|
|
|
# TODO check for unwrapping?
|
|
|
|
|
|
|
|
|
|
|
|
@turn_on
|
|
|
|
async def test_state(dev, turn_on):
|
|
|
|
await handle_turn_on(dev, turn_on)
|
|
|
|
orig_state = dev.is_on
|
|
|
|
if orig_state:
|
|
|
|
await dev.turn_off()
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.update()
|
2020-05-27 14:55:18 +00:00
|
|
|
assert not dev.is_on
|
|
|
|
assert dev.is_off
|
|
|
|
|
|
|
|
await dev.turn_on()
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.update()
|
2020-05-27 14:55:18 +00:00
|
|
|
assert dev.is_on
|
|
|
|
assert not dev.is_off
|
|
|
|
else:
|
|
|
|
await dev.turn_on()
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.update()
|
2020-05-27 14:55:18 +00:00
|
|
|
assert dev.is_on
|
|
|
|
assert not dev.is_off
|
|
|
|
|
|
|
|
await dev.turn_off()
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.update()
|
2020-05-27 14:55:18 +00:00
|
|
|
assert not dev.is_on
|
|
|
|
assert dev.is_off
|
|
|
|
|
|
|
|
|
|
|
|
async def test_alias(dev):
|
|
|
|
test_alias = "TEST1234"
|
|
|
|
original = dev.alias
|
|
|
|
|
|
|
|
assert isinstance(original, str)
|
|
|
|
await dev.set_alias(test_alias)
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.update()
|
2020-05-27 14:55:18 +00:00
|
|
|
assert dev.alias == test_alias
|
|
|
|
|
|
|
|
await dev.set_alias(original)
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.update()
|
2020-05-27 14:55:18 +00:00
|
|
|
assert dev.alias == original
|
|
|
|
|
|
|
|
|
|
|
|
@turn_on
|
|
|
|
async def test_on_since(dev, turn_on):
|
|
|
|
await handle_turn_on(dev, turn_on)
|
|
|
|
orig_state = dev.is_on
|
|
|
|
if "on_time" not in dev.sys_info and not dev.is_strip:
|
|
|
|
assert dev.on_since is None
|
|
|
|
elif orig_state:
|
|
|
|
assert isinstance(dev.on_since, datetime)
|
|
|
|
else:
|
|
|
|
assert dev.on_since is None
|
|
|
|
|
|
|
|
|
|
|
|
async def test_time(dev):
|
|
|
|
assert isinstance(await dev.get_time(), datetime)
|
|
|
|
|
|
|
|
|
|
|
|
async def test_timezone(dev):
|
|
|
|
TZ_SCHEMA(await dev.get_timezone())
|
|
|
|
|
|
|
|
|
|
|
|
async def test_hw_info(dev):
|
|
|
|
PLUG_SCHEMA(dev.hw_info)
|
|
|
|
|
|
|
|
|
|
|
|
async def test_location(dev):
|
|
|
|
PLUG_SCHEMA(dev.location)
|
|
|
|
|
|
|
|
|
|
|
|
async def test_rssi(dev):
|
|
|
|
PLUG_SCHEMA({"rssi": dev.rssi}) # wrapping for vol
|
|
|
|
|
|
|
|
|
|
|
|
async def test_mac(dev):
|
|
|
|
PLUG_SCHEMA({"mac": dev.mac}) # wrapping for val
|
|
|
|
|
|
|
|
|
|
|
|
async def test_representation(dev):
|
|
|
|
import re
|
|
|
|
|
|
|
|
pattern = re.compile("<.* model .* at .* (.*), is_on: .* - dev specific: .*>")
|
|
|
|
assert pattern.match(str(dev))
|
|
|
|
|
|
|
|
|
|
|
|
async def test_childrens(dev):
|
|
|
|
"""Make sure that children property is exposed by every device."""
|
|
|
|
if dev.is_strip:
|
|
|
|
assert len(dev.children) > 0
|
|
|
|
else:
|
|
|
|
assert len(dev.children) == 0
|
2022-02-07 08:13:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_internal_state(dev):
|
|
|
|
"""Make sure the internal state returns the last update results."""
|
|
|
|
assert dev.internal_state == dev._last_update
|
2022-03-02 15:29:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_features(dev):
|
|
|
|
"""Make sure features is always accessible."""
|
|
|
|
sysinfo = dev._last_update["system"]["get_sysinfo"]
|
|
|
|
if "feature" in sysinfo:
|
|
|
|
assert dev.features == set(sysinfo["feature"].split(":"))
|
|
|
|
else:
|
|
|
|
assert dev.features == set()
|