mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-04-27 00:56:23 +00:00
Improve test coverage (#625)
This commit is contained in:
parent
3e0cd07b7c
commit
d5a6fd8e73
16
kasa/cli.py
16
kasa/cli.py
@ -427,8 +427,8 @@ async def discover(ctx):
|
|||||||
echo()
|
echo()
|
||||||
else:
|
else:
|
||||||
discovered[dev.host] = dev.internal_state
|
discovered[dev.host] = dev.internal_state
|
||||||
ctx.obj = dev
|
ctx.parent.obj = dev
|
||||||
await ctx.invoke(state)
|
await ctx.parent.invoke(state)
|
||||||
if verbose:
|
if verbose:
|
||||||
echo()
|
echo()
|
||||||
_echo_discovery_info(dev._discovery_info)
|
_echo_discovery_info(dev._discovery_info)
|
||||||
@ -513,12 +513,14 @@ async def sysinfo(dev):
|
|||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@pass_dev
|
@pass_dev
|
||||||
async def state(dev: SmartDevice):
|
@click.pass_context
|
||||||
|
async def state(ctx, dev: SmartDevice):
|
||||||
"""Print out device state and versions."""
|
"""Print out device state and versions."""
|
||||||
|
verbose = ctx.parent.params.get("verbose", False) if ctx.parent else False
|
||||||
|
|
||||||
echo(f"[bold]== {dev.alias} - {dev.model} ==[/bold]")
|
echo(f"[bold]== {dev.alias} - {dev.model} ==[/bold]")
|
||||||
echo(f"\tHost: {dev.host}")
|
echo(f"\tHost: {dev.host}")
|
||||||
echo(f"\tPort: {dev.port}")
|
echo(f"\tPort: {dev.port}")
|
||||||
echo(f"\tCredentials hash: {dev.credentials_hash}")
|
|
||||||
echo(f"\tDevice state: {dev.is_on}")
|
echo(f"\tDevice state: {dev.is_on}")
|
||||||
if dev.is_strip:
|
if dev.is_strip:
|
||||||
echo("\t[bold]== Plugs ==[/bold]")
|
echo("\t[bold]== Plugs ==[/bold]")
|
||||||
@ -554,6 +556,12 @@ async def state(dev: SmartDevice):
|
|||||||
else:
|
else:
|
||||||
echo(f"\t[red]- {module}[/red]")
|
echo(f"\t[red]- {module}[/red]")
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
echo("\n\t[bold]== Verbose information ==[/bold]")
|
||||||
|
echo(f"\tCredentials hash: {dev.credentials_hash}")
|
||||||
|
echo(f"\tDevice ID: {dev.device_id}")
|
||||||
|
for feature in dev.features:
|
||||||
|
echo(f"\tFeature: {feature}")
|
||||||
return dev.internal_state
|
return dev.internal_state
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ class TapoDevice(SmartDevice):
|
|||||||
]
|
]
|
||||||
networks.extend(network_list)
|
networks.extend(network_list)
|
||||||
|
|
||||||
if resp["get_wireless_scan_info"]["sum"] > start_index + 10:
|
if resp["get_wireless_scan_info"].get("sum", 0) > start_index + 10:
|
||||||
return await _query_networks(networks, start_index=start_index + 10)
|
return await _query_networks(networks, start_index=start_index + 10)
|
||||||
|
|
||||||
return networks
|
return networks
|
||||||
|
@ -18,6 +18,7 @@ from voluptuous import (
|
|||||||
|
|
||||||
from ..credentials import Credentials
|
from ..credentials import Credentials
|
||||||
from ..deviceconfig import DeviceConfig
|
from ..deviceconfig import DeviceConfig
|
||||||
|
from ..exceptions import SmartDeviceException
|
||||||
from ..protocol import BaseTransport, TPLinkSmartHomeProtocol, _XorTransport
|
from ..protocol import BaseTransport, TPLinkSmartHomeProtocol, _XorTransport
|
||||||
from ..smartprotocol import SmartProtocol
|
from ..smartprotocol import SmartProtocol
|
||||||
|
|
||||||
@ -315,6 +316,10 @@ class FakeSmartTransport(BaseTransport):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
self.info = info
|
self.info = info
|
||||||
|
self.components = {
|
||||||
|
comp["id"]: comp["ver_code"]
|
||||||
|
for comp in self.info["component_nego"]["component_list"]
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def default_port(self):
|
def default_port(self):
|
||||||
@ -326,6 +331,10 @@ class FakeSmartTransport(BaseTransport):
|
|||||||
"""The hashed credentials used by the transport."""
|
"""The hashed credentials used by the transport."""
|
||||||
return self._credentials.username + self._credentials.password + "hash"
|
return self._credentials.username + self._credentials.password + "hash"
|
||||||
|
|
||||||
|
FIXTURE_MISSING_MAP = {
|
||||||
|
"get_wireless_scan_info": ("wireless", {"ap_list": [], "wep_supported": False}),
|
||||||
|
}
|
||||||
|
|
||||||
async def send(self, request: str):
|
async def send(self, request: str):
|
||||||
request_dict = json_loads(request)
|
request_dict = json_loads(request)
|
||||||
method = request_dict["method"]
|
method = request_dict["method"]
|
||||||
@ -346,14 +355,20 @@ class FakeSmartTransport(BaseTransport):
|
|||||||
if method == "component_nego" or method[:4] == "get_":
|
if method == "component_nego" or method[:4] == "get_":
|
||||||
if method in self.info:
|
if method in self.info:
|
||||||
return {"result": self.info[method], "error_code": 0}
|
return {"result": self.info[method], "error_code": 0}
|
||||||
else:
|
elif (
|
||||||
|
missing_result := self.FIXTURE_MISSING_MAP.get(method)
|
||||||
|
) and missing_result[0] in self.components:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
UserWarning(
|
UserWarning(
|
||||||
f"Fixture missing expected method {method}, try to regenerate"
|
f"Fixture missing expected method {method}, try to regenerate"
|
||||||
),
|
),
|
||||||
stacklevel=1,
|
stacklevel=1,
|
||||||
)
|
)
|
||||||
return {"result": {}, "error_code": 0}
|
return {"result": missing_result[1], "error_code": 0}
|
||||||
|
else:
|
||||||
|
raise SmartDeviceException(f"Fixture doesn't support {method}")
|
||||||
|
elif method == "set_qs_info":
|
||||||
|
return {"error_code": 0}
|
||||||
elif method[:4] == "set_":
|
elif method[:4] == "set_":
|
||||||
target_method = f"get_{method[4:]}"
|
target_method = f"get_{method[4:]}"
|
||||||
self.info[target_method].update(params)
|
self.info[target_method].update(params)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
import asyncclick as click
|
import asyncclick as click
|
||||||
import pytest
|
import pytest
|
||||||
@ -9,6 +10,7 @@ from kasa import (
|
|||||||
Credentials,
|
Credentials,
|
||||||
EmeterStatus,
|
EmeterStatus,
|
||||||
SmartDevice,
|
SmartDevice,
|
||||||
|
SmartDeviceException,
|
||||||
TPLinkSmartHomeProtocol,
|
TPLinkSmartHomeProtocol,
|
||||||
UnsupportedDeviceException,
|
UnsupportedDeviceException,
|
||||||
)
|
)
|
||||||
@ -22,11 +24,13 @@ from kasa.cli import (
|
|||||||
state,
|
state,
|
||||||
sysinfo,
|
sysinfo,
|
||||||
toggle,
|
toggle,
|
||||||
|
update_credentials,
|
||||||
|
wifi,
|
||||||
)
|
)
|
||||||
from kasa.discover import Discover, DiscoveryResult
|
from kasa.discover import Discover, DiscoveryResult
|
||||||
from kasa.smartprotocol import SmartProtocol
|
from kasa.smartprotocol import SmartProtocol
|
||||||
|
|
||||||
from .conftest import device_iot, handle_turn_on, new_discovery, turn_on
|
from .conftest import device_iot, device_smart, handle_turn_on, new_discovery, turn_on
|
||||||
|
|
||||||
|
|
||||||
@device_iot
|
@device_iot
|
||||||
@ -81,20 +85,93 @@ async def test_alias(dev):
|
|||||||
await dev.set_alias(old_alias)
|
await dev.set_alias(old_alias)
|
||||||
|
|
||||||
|
|
||||||
@device_iot
|
|
||||||
async def test_raw_command(dev):
|
async def test_raw_command(dev):
|
||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
res = await runner.invoke(raw_command, ["system", "get_sysinfo"], obj=dev)
|
from kasa.tapo import TapoDevice
|
||||||
|
|
||||||
|
if isinstance(dev, TapoDevice):
|
||||||
|
params = ["na", "get_device_info"]
|
||||||
|
else:
|
||||||
|
params = ["system", "get_sysinfo"]
|
||||||
|
res = await runner.invoke(raw_command, params, obj=dev)
|
||||||
|
|
||||||
assert res.exit_code == 0
|
assert res.exit_code == 0
|
||||||
assert dev.alias in res.output
|
assert dev.model in res.output
|
||||||
|
|
||||||
res = await runner.invoke(raw_command, obj=dev)
|
res = await runner.invoke(raw_command, obj=dev)
|
||||||
assert res.exit_code != 0
|
assert res.exit_code != 0
|
||||||
assert "Usage" in res.output
|
assert "Usage" in res.output
|
||||||
|
|
||||||
|
|
||||||
@device_iot
|
@device_smart
|
||||||
|
async def test_wifi_scan(dev):
|
||||||
|
runner = CliRunner()
|
||||||
|
res = await runner.invoke(wifi, ["scan"], obj=dev)
|
||||||
|
|
||||||
|
assert res.exit_code == 0
|
||||||
|
assert re.search(r"Found \d wifi networks!", res.output)
|
||||||
|
|
||||||
|
|
||||||
|
@device_smart
|
||||||
|
async def test_wifi_join(dev):
|
||||||
|
runner = CliRunner()
|
||||||
|
res = await runner.invoke(
|
||||||
|
wifi,
|
||||||
|
["join", "FOOBAR", "--keytype", "wpa_psk", "--password", "foobar"],
|
||||||
|
obj=dev,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res.exit_code == 0
|
||||||
|
assert "Asking the device to connect to FOOBAR" in res.output
|
||||||
|
|
||||||
|
|
||||||
|
@device_smart
|
||||||
|
async def test_wifi_join_no_creds(dev):
|
||||||
|
runner = CliRunner()
|
||||||
|
dev.protocol._transport._credentials = None
|
||||||
|
res = await runner.invoke(
|
||||||
|
wifi,
|
||||||
|
["join", "FOOBAR", "--keytype", "wpa_psk", "--password", "foobar"],
|
||||||
|
obj=dev,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res.exit_code != 0
|
||||||
|
assert isinstance(res.exception, AuthenticationException)
|
||||||
|
|
||||||
|
|
||||||
|
@device_smart
|
||||||
|
async def test_wifi_join_exception(dev, mocker):
|
||||||
|
runner = CliRunner()
|
||||||
|
mocker.patch.object(
|
||||||
|
dev.protocol, "query", side_effect=SmartDeviceException(error_code=9999)
|
||||||
|
)
|
||||||
|
res = await runner.invoke(
|
||||||
|
wifi,
|
||||||
|
["join", "FOOBAR", "--keytype", "wpa_psk", "--password", "foobar"],
|
||||||
|
obj=dev,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res.exit_code != 0
|
||||||
|
assert isinstance(res.exception, SmartDeviceException)
|
||||||
|
|
||||||
|
|
||||||
|
@device_smart
|
||||||
|
async def test_update_credentials(dev):
|
||||||
|
runner = CliRunner()
|
||||||
|
res = await runner.invoke(
|
||||||
|
update_credentials,
|
||||||
|
["--username", "foo", "--password", "bar"],
|
||||||
|
input="y\n",
|
||||||
|
obj=dev,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res.exit_code == 0
|
||||||
|
assert (
|
||||||
|
"Do you really want to replace the existing credentials? [y/N]: y\n"
|
||||||
|
in res.output
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_emeter(dev: SmartDevice, mocker):
|
async def test_emeter(dev: SmartDevice, mocker):
|
||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ async def test_no_emeter(dev):
|
|||||||
await dev.erase_emeter_stats()
|
await dev.erase_emeter_stats()
|
||||||
|
|
||||||
|
|
||||||
@has_emeter_iot
|
@has_emeter
|
||||||
async def test_get_emeter_realtime(dev):
|
async def test_get_emeter_realtime(dev):
|
||||||
assert dev.has_emeter
|
assert dev.has_emeter
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user