2024-03-15 15:55:48 +00:00
|
|
|
"""Tests for all devices."""
|
2024-04-16 18:21:20 +00:00
|
|
|
|
2024-03-15 15:55:48 +00:00
|
|
|
import importlib
|
|
|
|
import inspect
|
|
|
|
import pkgutil
|
|
|
|
import sys
|
|
|
|
from unittest.mock import Mock, patch
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
import kasa
|
|
|
|
from kasa import Credentials, Device, DeviceConfig
|
|
|
|
from kasa.iot import IotDevice
|
|
|
|
from kasa.smart import SmartChildDevice, SmartDevice
|
|
|
|
|
|
|
|
|
|
|
|
def _get_subclasses(of_class):
|
|
|
|
package = sys.modules["kasa"]
|
|
|
|
subclasses = set()
|
|
|
|
for _, modname, _ in pkgutil.iter_modules(package.__path__):
|
|
|
|
importlib.import_module("." + modname, package="kasa")
|
|
|
|
module = sys.modules["kasa." + modname]
|
|
|
|
for name, obj in inspect.getmembers(module):
|
|
|
|
if (
|
|
|
|
inspect.isclass(obj)
|
|
|
|
and issubclass(obj, of_class)
|
|
|
|
and module.__package__ != "kasa"
|
|
|
|
):
|
|
|
|
subclasses.add((module.__package__ + "." + name, obj))
|
|
|
|
return subclasses
|
|
|
|
|
|
|
|
|
|
|
|
device_classes = pytest.mark.parametrize(
|
|
|
|
"device_class_name_obj", _get_subclasses(Device), ids=lambda t: t[0]
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def test_alias(dev):
|
|
|
|
test_alias = "TEST1234"
|
|
|
|
original = dev.alias
|
|
|
|
|
|
|
|
assert isinstance(original, str)
|
|
|
|
await dev.set_alias(test_alias)
|
|
|
|
await dev.update()
|
|
|
|
assert dev.alias == test_alias
|
|
|
|
|
|
|
|
await dev.set_alias(original)
|
|
|
|
await dev.update()
|
|
|
|
assert dev.alias == original
|
|
|
|
|
|
|
|
|
|
|
|
@device_classes
|
|
|
|
async def test_device_class_ctors(device_class_name_obj):
|
|
|
|
"""Make sure constructor api not broken for new and existing SmartDevices."""
|
|
|
|
host = "127.0.0.2"
|
|
|
|
port = 1234
|
|
|
|
credentials = Credentials("foo", "bar")
|
|
|
|
config = DeviceConfig(host, port_override=port, credentials=credentials)
|
|
|
|
klass = device_class_name_obj[1]
|
|
|
|
if issubclass(klass, SmartChildDevice):
|
|
|
|
parent = SmartDevice(host, config=config)
|
|
|
|
dev = klass(
|
|
|
|
parent, {"dummy": "info", "device_id": "dummy"}, {"dummy": "components"}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
dev = klass(host, config=config)
|
|
|
|
assert dev.host == host
|
|
|
|
assert dev.port == port
|
|
|
|
assert dev.credentials == credentials
|
|
|
|
|
|
|
|
|
|
|
|
async def test_create_device_with_timeout():
|
|
|
|
"""Make sure timeout is passed to the protocol."""
|
|
|
|
host = "127.0.0.1"
|
|
|
|
dev = IotDevice(host, config=DeviceConfig(host, timeout=100))
|
|
|
|
assert dev.protocol._transport._timeout == 100
|
|
|
|
dev = SmartDevice(host, config=DeviceConfig(host, timeout=100))
|
|
|
|
assert dev.protocol._transport._timeout == 100
|
|
|
|
|
|
|
|
|
|
|
|
async def test_create_thin_wrapper():
|
|
|
|
"""Make sure thin wrapper is created with the correct device type."""
|
|
|
|
mock = Mock()
|
|
|
|
config = DeviceConfig(
|
|
|
|
host="test_host",
|
|
|
|
port_override=1234,
|
|
|
|
timeout=100,
|
|
|
|
credentials=Credentials("username", "password"),
|
|
|
|
)
|
|
|
|
with patch("kasa.device_factory.connect", return_value=mock) as connect:
|
|
|
|
dev = await Device.connect(config=config)
|
|
|
|
assert dev is mock
|
|
|
|
|
|
|
|
connect.assert_called_once_with(
|
|
|
|
host=None,
|
|
|
|
config=config,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"device_class, use_class", kasa.deprecated_smart_devices.items()
|
|
|
|
)
|
|
|
|
def test_deprecated_devices(device_class, use_class):
|
|
|
|
package_name = ".".join(use_class.__module__.split(".")[:-1])
|
|
|
|
msg = f"{device_class} is deprecated, use {use_class.__name__} from package {package_name} instead"
|
|
|
|
with pytest.deprecated_call(match=msg):
|
|
|
|
getattr(kasa, device_class)
|
|
|
|
packages = package_name.split(".")
|
|
|
|
module = __import__(packages[0])
|
|
|
|
for _ in packages[1:]:
|
|
|
|
module = importlib.import_module(package_name, package=module.__name__)
|
|
|
|
getattr(module, use_class.__name__)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"exceptions_class, use_class", kasa.deprecated_exceptions.items()
|
|
|
|
)
|
|
|
|
def test_deprecated_exceptions(exceptions_class, use_class):
|
|
|
|
msg = f"{exceptions_class} is deprecated, use {use_class.__name__} instead"
|
|
|
|
with pytest.deprecated_call(match=msg):
|
|
|
|
getattr(kasa, exceptions_class)
|
|
|
|
getattr(kasa, use_class.__name__)
|