2023-02-18 20:41:08 +00:00
|
|
|
import json
|
2024-01-10 19:37:43 +00:00
|
|
|
import re
|
2022-10-03 18:28:05 +00:00
|
|
|
|
2023-09-13 13:46:38 +00:00
|
|
|
import asyncclick as click
|
2021-12-13 19:17:54 +00:00
|
|
|
import pytest
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
from asyncclick.testing import CliRunner
|
2020-05-12 10:11:47 +00:00
|
|
|
|
2023-12-29 19:17:15 +00:00
|
|
|
from kasa import (
|
|
|
|
AuthenticationException,
|
2024-02-04 15:20:08 +00:00
|
|
|
Device,
|
2024-01-05 01:25:24 +00:00
|
|
|
EmeterStatus,
|
2024-01-10 19:37:43 +00:00
|
|
|
SmartDeviceException,
|
2023-12-29 19:17:15 +00:00
|
|
|
UnsupportedDeviceException,
|
|
|
|
)
|
|
|
|
from kasa.cli import (
|
|
|
|
TYPE_TO_CLASS,
|
|
|
|
alias,
|
|
|
|
brightness,
|
|
|
|
cli,
|
|
|
|
emeter,
|
|
|
|
raw_command,
|
2024-01-23 13:26:47 +00:00
|
|
|
reboot,
|
2023-12-29 19:17:15 +00:00
|
|
|
state,
|
|
|
|
sysinfo,
|
|
|
|
toggle,
|
2024-01-10 19:37:43 +00:00
|
|
|
update_credentials,
|
|
|
|
wifi,
|
2023-12-29 19:17:15 +00:00
|
|
|
)
|
|
|
|
from kasa.discover import Discover, DiscoveryResult
|
2024-02-04 15:20:08 +00:00
|
|
|
from kasa.iot import IotDevice
|
2020-04-20 17:26:20 +00:00
|
|
|
|
2024-01-10 19:37:43 +00:00
|
|
|
from .conftest import device_iot, device_smart, handle_turn_on, new_discovery, turn_on
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
|
2020-04-20 17:26:20 +00:00
|
|
|
|
2024-01-23 21:58:57 +00:00
|
|
|
async def test_update_called_by_cli(dev, mocker):
|
|
|
|
"""Test that device update is called on main."""
|
|
|
|
runner = CliRunner()
|
|
|
|
update = mocker.patch.object(dev, "update")
|
|
|
|
mocker.patch("kasa.discover.Discover.discover_single", return_value=dev)
|
|
|
|
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--host",
|
|
|
|
"127.0.0.1",
|
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
assert res.exit_code == 0
|
|
|
|
update.assert_called()
|
|
|
|
|
|
|
|
|
2023-12-04 18:50:05 +00:00
|
|
|
@device_iot
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
async def test_sysinfo(dev):
|
2020-04-20 17:26:20 +00:00
|
|
|
runner = CliRunner()
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(sysinfo, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
assert "System info" in res.output
|
|
|
|
assert dev.alias in res.output
|
|
|
|
|
|
|
|
|
|
|
|
@turn_on
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
async def test_state(dev, turn_on):
|
|
|
|
await handle_turn_on(dev, turn_on)
|
2020-04-20 17:26:20 +00:00
|
|
|
runner = CliRunner()
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(state, obj=dev)
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.update()
|
2020-04-20 17:26:20 +00:00
|
|
|
|
|
|
|
if dev.is_on:
|
2023-02-18 16:31:06 +00:00
|
|
|
assert "Device state: True" in res.output
|
2020-04-20 17:26:20 +00:00
|
|
|
else:
|
2023-02-18 16:31:06 +00:00
|
|
|
assert "Device state: False" in res.output
|
2020-04-20 17:26:20 +00:00
|
|
|
|
|
|
|
|
2023-08-26 12:21:38 +00:00
|
|
|
@turn_on
|
|
|
|
async def test_toggle(dev, turn_on, mocker):
|
|
|
|
await handle_turn_on(dev, turn_on)
|
|
|
|
runner = CliRunner()
|
|
|
|
await runner.invoke(toggle, obj=dev)
|
|
|
|
|
|
|
|
if turn_on:
|
|
|
|
assert not dev.is_on
|
|
|
|
else:
|
|
|
|
assert dev.is_on
|
|
|
|
|
|
|
|
|
2023-12-04 18:50:05 +00:00
|
|
|
@device_iot
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
async def test_alias(dev):
|
2020-04-20 17:26:20 +00:00
|
|
|
runner = CliRunner()
|
|
|
|
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(alias, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
assert f"Alias: {dev.alias}" in res.output
|
|
|
|
|
2021-09-19 21:45:48 +00:00
|
|
|
old_alias = dev.alias
|
|
|
|
|
2020-04-20 17:26:20 +00:00
|
|
|
new_alias = "new alias"
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(alias, [new_alias], obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
assert f"Setting alias to {new_alias}" in res.output
|
|
|
|
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(alias, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
assert f"Alias: {new_alias}" in res.output
|
|
|
|
|
2021-09-19 21:45:48 +00:00
|
|
|
await dev.set_alias(old_alias)
|
|
|
|
|
2020-04-20 17:26:20 +00:00
|
|
|
|
2024-01-23 21:58:57 +00:00
|
|
|
async def test_raw_command(dev, mocker):
|
2020-04-20 17:26:20 +00:00
|
|
|
runner = CliRunner()
|
2024-01-23 21:58:57 +00:00
|
|
|
update = mocker.patch.object(dev, "update")
|
2024-02-04 15:20:08 +00:00
|
|
|
from kasa.smart import SmartDevice
|
2024-01-10 19:37:43 +00:00
|
|
|
|
2024-02-04 15:20:08 +00:00
|
|
|
if isinstance(dev, SmartDevice):
|
2024-01-10 19:37:43 +00:00
|
|
|
params = ["na", "get_device_info"]
|
|
|
|
else:
|
|
|
|
params = ["system", "get_sysinfo"]
|
|
|
|
res = await runner.invoke(raw_command, params, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
|
2024-01-23 21:58:57 +00:00
|
|
|
# Make sure that update was not called for wifi
|
|
|
|
with pytest.raises(AssertionError):
|
|
|
|
update.assert_called()
|
|
|
|
|
2020-04-20 17:26:20 +00:00
|
|
|
assert res.exit_code == 0
|
2024-01-10 19:37:43 +00:00
|
|
|
assert dev.model in res.output
|
2020-04-20 17:26:20 +00:00
|
|
|
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(raw_command, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
assert res.exit_code != 0
|
|
|
|
assert "Usage" in res.output
|
|
|
|
|
|
|
|
|
2024-01-23 13:26:47 +00:00
|
|
|
@device_smart
|
|
|
|
async def test_reboot(dev, mocker):
|
|
|
|
"""Test that reboot works on SMART devices."""
|
|
|
|
runner = CliRunner()
|
|
|
|
query_mock = mocker.patch.object(dev.protocol, "query")
|
|
|
|
|
|
|
|
res = await runner.invoke(
|
|
|
|
reboot,
|
|
|
|
obj=dev,
|
|
|
|
)
|
|
|
|
|
|
|
|
query_mock.assert_called()
|
|
|
|
assert res.exit_code == 0
|
|
|
|
|
|
|
|
|
2024-01-10 19:37:43 +00:00
|
|
|
@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
|
2024-01-23 21:58:57 +00:00
|
|
|
async def test_wifi_join(dev, mocker):
|
2024-01-10 19:37:43 +00:00
|
|
|
runner = CliRunner()
|
2024-01-23 21:58:57 +00:00
|
|
|
update = mocker.patch.object(dev, "update")
|
2024-01-10 19:37:43 +00:00
|
|
|
res = await runner.invoke(
|
|
|
|
wifi,
|
|
|
|
["join", "FOOBAR", "--keytype", "wpa_psk", "--password", "foobar"],
|
|
|
|
obj=dev,
|
|
|
|
)
|
|
|
|
|
2024-01-23 21:58:57 +00:00
|
|
|
# Make sure that update was not called for wifi
|
|
|
|
with pytest.raises(AssertionError):
|
|
|
|
update.assert_called()
|
|
|
|
|
2024-01-10 19:37:43 +00:00
|
|
|
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
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-02-04 15:20:08 +00:00
|
|
|
async def test_emeter(dev: Device, mocker):
|
2020-04-20 17:26:20 +00:00
|
|
|
runner = CliRunner()
|
|
|
|
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(emeter, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
if not dev.has_emeter:
|
|
|
|
assert "Device has no emeter" in res.output
|
|
|
|
return
|
|
|
|
|
2020-05-24 15:57:54 +00:00
|
|
|
assert "== Emeter ==" in res.output
|
2020-04-20 17:26:20 +00:00
|
|
|
|
2024-01-05 01:25:24 +00:00
|
|
|
if not dev.is_strip:
|
|
|
|
res = await runner.invoke(emeter, ["--index", "0"], obj=dev)
|
|
|
|
assert "Index and name are only for power strips!" in res.output
|
|
|
|
res = await runner.invoke(emeter, ["--name", "mock"], obj=dev)
|
|
|
|
assert "Index and name are only for power strips!" in res.output
|
|
|
|
|
|
|
|
if dev.is_strip and len(dev.children) > 0:
|
|
|
|
realtime_emeter = mocker.patch.object(dev.children[0], "get_emeter_realtime")
|
|
|
|
realtime_emeter.return_value = EmeterStatus({"voltage_mv": 122066})
|
|
|
|
|
|
|
|
res = await runner.invoke(emeter, ["--index", "0"], obj=dev)
|
|
|
|
assert "Voltage: 122.066 V" in res.output
|
|
|
|
realtime_emeter.assert_called()
|
|
|
|
assert realtime_emeter.call_count == 1
|
|
|
|
|
|
|
|
res = await runner.invoke(emeter, ["--name", dev.children[0].alias], obj=dev)
|
|
|
|
assert "Voltage: 122.066 V" in res.output
|
|
|
|
assert realtime_emeter.call_count == 2
|
|
|
|
|
2024-02-04 15:20:08 +00:00
|
|
|
if isinstance(dev, IotDevice):
|
|
|
|
monthly = mocker.patch.object(dev, "get_emeter_monthly")
|
|
|
|
monthly.return_value = {1: 1234}
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(emeter, ["--year", "1900"], obj=dev)
|
2024-02-04 15:20:08 +00:00
|
|
|
if not isinstance(dev, IotDevice):
|
|
|
|
assert "Device has no historical statistics" in res.output
|
|
|
|
return
|
2020-04-20 17:26:20 +00:00
|
|
|
assert "For year" in res.output
|
2022-10-03 18:28:05 +00:00
|
|
|
assert "1, 1234" in res.output
|
|
|
|
monthly.assert_called_with(year=1900)
|
2020-04-20 17:26:20 +00:00
|
|
|
|
2024-02-04 15:20:08 +00:00
|
|
|
if isinstance(dev, IotDevice):
|
|
|
|
daily = mocker.patch.object(dev, "get_emeter_daily")
|
|
|
|
daily.return_value = {1: 1234}
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(emeter, ["--month", "1900-12"], obj=dev)
|
2024-02-04 15:20:08 +00:00
|
|
|
if not isinstance(dev, IotDevice):
|
|
|
|
assert "Device has no historical statistics" in res.output
|
|
|
|
return
|
2020-04-20 17:26:20 +00:00
|
|
|
assert "For month" in res.output
|
2022-10-03 18:28:05 +00:00
|
|
|
assert "1, 1234" in res.output
|
|
|
|
daily.assert_called_with(year=1900, month=12)
|
2020-04-20 17:26:20 +00:00
|
|
|
|
|
|
|
|
2023-12-04 18:50:05 +00:00
|
|
|
@device_iot
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
async def test_brightness(dev):
|
2020-04-20 17:26:20 +00:00
|
|
|
runner = CliRunner()
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(brightness, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
if not dev.is_dimmable:
|
|
|
|
assert "This device does not support brightness." in res.output
|
|
|
|
return
|
|
|
|
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(brightness, obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
assert f"Brightness: {dev.brightness}" in res.output
|
|
|
|
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(brightness, ["12"], obj=dev)
|
2020-04-20 17:26:20 +00:00
|
|
|
assert "Setting brightness" in res.output
|
|
|
|
|
async++, small powerstrip improvements (#46)
* async++, small powerstrip improvements
* use asyncclick instead of click, allows defining the commands with async def to avoid manual eventloop/asyncio.run handling
* improve powerstrip support:
* new powerstrip api: turn_{on,off}_by_{name,index} methods
* cli: fix on/off for powerstrip using the new apis
* add missing update()s for cli's hsv, led, temperature (fixes #43)
* prettyprint the received payloads when debug mode in use
* cli: debug mode can be activated now with '-d'
* update requirements_test.txt
* remove outdated click-datetime, replace click with asyncclick
* debug is a flag
* make smartstripplug to inherit the sysinfo from its parent, allows for simple access of general plug properties
* proper bound checking for index accesses, allow controlling the plug at index 0
* remove the mess of turn_{on,off}_by_{name,index}, get_plug_by_{name,index} are enough.
* adapt cli to use that
* allow changing the alias per index
* use f-strings consistently everywhere in the cli
* add tests for get_plug_by_{index,name}
2020-04-21 18:46:13 +00:00
|
|
|
res = await runner.invoke(brightness, obj=dev)
|
2020-05-13 12:50:45 +00:00
|
|
|
assert "Brightness: 12" in res.output
|
2020-04-20 17:26:20 +00:00
|
|
|
|
|
|
|
|
2023-12-04 18:50:05 +00:00
|
|
|
@device_iot
|
2024-02-04 15:20:08 +00:00
|
|
|
async def test_json_output(dev: Device, mocker):
|
2023-02-18 20:41:08 +00:00
|
|
|
"""Test that the json output produces correct output."""
|
|
|
|
mocker.patch("kasa.Discover.discover", return_value=[dev])
|
|
|
|
runner = CliRunner()
|
|
|
|
res = await runner.invoke(cli, ["--json", "state"], obj=dev)
|
|
|
|
assert res.exit_code == 0
|
|
|
|
assert json.loads(res.output) == dev.internal_state
|
2023-09-13 13:46:38 +00:00
|
|
|
|
|
|
|
|
2023-12-04 18:50:05 +00:00
|
|
|
@new_discovery
|
|
|
|
async def test_credentials(discovery_mock, mocker):
|
2023-09-13 13:46:38 +00:00
|
|
|
"""Test credentials are passed correctly from cli to device."""
|
|
|
|
# Patch state to echo username and password
|
2024-02-04 15:20:08 +00:00
|
|
|
pass_dev = click.make_pass_decorator(Device)
|
2023-09-13 13:46:38 +00:00
|
|
|
|
|
|
|
@pass_dev
|
2024-02-04 15:20:08 +00:00
|
|
|
async def _state(dev: Device):
|
2023-09-13 13:46:38 +00:00
|
|
|
if dev.credentials:
|
|
|
|
click.echo(
|
|
|
|
f"Username:{dev.credentials.username} Password:{dev.credentials.password}"
|
|
|
|
)
|
|
|
|
|
|
|
|
mocker.patch("kasa.cli.state", new=_state)
|
|
|
|
|
2023-12-29 19:17:15 +00:00
|
|
|
mocker.patch("kasa.IotProtocol.query", return_value=discovery_mock.query_data)
|
|
|
|
mocker.patch("kasa.SmartProtocol.query", return_value=discovery_mock.query_data)
|
|
|
|
|
|
|
|
dr = DiscoveryResult(**discovery_mock.discovery_data["result"])
|
2023-09-13 13:46:38 +00:00
|
|
|
runner = CliRunner()
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--host",
|
2023-12-04 18:50:05 +00:00
|
|
|
"127.0.0.123",
|
2023-09-13 13:46:38 +00:00
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
2023-12-29 19:17:15 +00:00
|
|
|
"--device-family",
|
|
|
|
dr.device_type,
|
|
|
|
"--encrypt-type",
|
|
|
|
dr.mgt_encrypt_schm.encrypt_type,
|
2023-09-13 13:46:38 +00:00
|
|
|
],
|
|
|
|
)
|
|
|
|
assert res.exit_code == 0
|
2023-12-04 18:50:05 +00:00
|
|
|
|
|
|
|
assert "Username:foo Password:bar\n" in res.output
|
2023-09-13 13:46:38 +00:00
|
|
|
|
|
|
|
|
2023-12-04 18:50:05 +00:00
|
|
|
@device_iot
|
2023-12-29 19:17:15 +00:00
|
|
|
async def test_without_device_type(dev, mocker):
|
2023-11-21 22:48:53 +00:00
|
|
|
"""Test connecting without the device type."""
|
|
|
|
runner = CliRunner()
|
|
|
|
mocker.patch("kasa.discover.Discover.discover_single", return_value=dev)
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--host",
|
|
|
|
"127.0.0.1",
|
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
assert res.exit_code == 0
|
|
|
|
|
|
|
|
|
2023-09-13 13:46:38 +00:00
|
|
|
@pytest.mark.parametrize("auth_param", ["--username", "--password"])
|
|
|
|
async def test_invalid_credential_params(auth_param):
|
2023-10-04 21:35:26 +00:00
|
|
|
"""Test for handling only one of username or password supplied."""
|
2023-09-13 13:46:38 +00:00
|
|
|
runner = CliRunner()
|
|
|
|
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--host",
|
|
|
|
"127.0.0.1",
|
|
|
|
"--type",
|
|
|
|
"plug",
|
|
|
|
auth_param,
|
|
|
|
"foo",
|
|
|
|
],
|
|
|
|
)
|
2023-10-04 21:35:26 +00:00
|
|
|
assert res.exit_code == 2
|
2023-09-13 13:46:38 +00:00
|
|
|
assert (
|
2023-10-04 21:35:26 +00:00
|
|
|
"Error: Using authentication requires both --username and --password"
|
|
|
|
in res.output
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def test_duplicate_target_device():
|
|
|
|
"""Test that defining both --host or --alias gives an error."""
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--host",
|
|
|
|
"127.0.0.1",
|
|
|
|
"--alias",
|
|
|
|
"foo",
|
|
|
|
],
|
2023-09-13 13:46:38 +00:00
|
|
|
)
|
2023-10-04 21:35:26 +00:00
|
|
|
assert res.exit_code == 2
|
|
|
|
assert "Error: Use either --alias or --host, not both." in res.output
|
2023-12-19 12:50:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_discover(discovery_mock, mocker):
|
|
|
|
"""Test discovery output."""
|
|
|
|
runner = CliRunner()
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--discovery-timeout",
|
|
|
|
0,
|
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
|
|
|
"--verbose",
|
2023-12-29 15:04:41 +00:00
|
|
|
"discover",
|
2023-12-19 12:50:33 +00:00
|
|
|
],
|
|
|
|
)
|
|
|
|
assert res.exit_code == 0
|
|
|
|
|
|
|
|
|
|
|
|
async def test_discover_unsupported(unsupported_device_info):
|
|
|
|
"""Test discovery output."""
|
|
|
|
runner = CliRunner()
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--discovery-timeout",
|
|
|
|
0,
|
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
|
|
|
"--verbose",
|
2023-12-29 15:04:41 +00:00
|
|
|
"discover",
|
2023-12-19 12:50:33 +00:00
|
|
|
],
|
|
|
|
)
|
|
|
|
assert res.exit_code == 0
|
|
|
|
assert "== Unsupported device ==" in res.output
|
|
|
|
assert "== Discovery Result ==" in res.output
|
|
|
|
|
|
|
|
|
|
|
|
async def test_host_unsupported(unsupported_device_info):
|
|
|
|
"""Test discovery output."""
|
|
|
|
runner = CliRunner()
|
|
|
|
host = "127.0.0.1"
|
|
|
|
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--host",
|
|
|
|
host,
|
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
assert res.exit_code != 0
|
|
|
|
assert isinstance(res.exception, UnsupportedDeviceException)
|
|
|
|
|
|
|
|
|
|
|
|
@new_discovery
|
|
|
|
async def test_discover_auth_failed(discovery_mock, mocker):
|
|
|
|
"""Test discovery output."""
|
|
|
|
runner = CliRunner()
|
|
|
|
host = "127.0.0.1"
|
|
|
|
discovery_mock.ip = host
|
|
|
|
device_class = Discover._get_device_class(discovery_mock.discovery_data)
|
|
|
|
mocker.patch.object(
|
|
|
|
device_class,
|
|
|
|
"update",
|
|
|
|
side_effect=AuthenticationException("Failed to authenticate"),
|
|
|
|
)
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--discovery-timeout",
|
|
|
|
0,
|
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
|
|
|
"--verbose",
|
2023-12-29 15:04:41 +00:00
|
|
|
"discover",
|
2023-12-19 12:50:33 +00:00
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
assert res.exit_code == 0
|
|
|
|
assert "== Authentication failed for device ==" in res.output
|
|
|
|
assert "== Discovery Result ==" in res.output
|
|
|
|
|
|
|
|
|
|
|
|
@new_discovery
|
|
|
|
async def test_host_auth_failed(discovery_mock, mocker):
|
|
|
|
"""Test discovery output."""
|
|
|
|
runner = CliRunner()
|
|
|
|
host = "127.0.0.1"
|
|
|
|
discovery_mock.ip = host
|
|
|
|
device_class = Discover._get_device_class(discovery_mock.discovery_data)
|
|
|
|
mocker.patch.object(
|
|
|
|
device_class,
|
|
|
|
"update",
|
|
|
|
side_effect=AuthenticationException("Failed to authenticate"),
|
|
|
|
)
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
[
|
|
|
|
"--host",
|
|
|
|
host,
|
|
|
|
"--username",
|
|
|
|
"foo",
|
|
|
|
"--password",
|
|
|
|
"bar",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
assert res.exit_code != 0
|
|
|
|
assert isinstance(res.exception, AuthenticationException)
|
2023-12-29 19:17:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("device_type", list(TYPE_TO_CLASS))
|
|
|
|
async def test_type_param(device_type, mocker):
|
|
|
|
"""Test for handling only one of username or password supplied."""
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
|
|
result_device = FileNotFoundError
|
2024-02-04 15:20:08 +00:00
|
|
|
pass_dev = click.make_pass_decorator(Device)
|
2023-12-29 19:17:15 +00:00
|
|
|
|
|
|
|
@pass_dev
|
2024-02-04 15:20:08 +00:00
|
|
|
async def _state(dev: Device):
|
2023-12-29 19:17:15 +00:00
|
|
|
nonlocal result_device
|
|
|
|
result_device = dev
|
|
|
|
|
|
|
|
mocker.patch("kasa.cli.state", new=_state)
|
|
|
|
expected_type = TYPE_TO_CLASS[device_type]
|
|
|
|
mocker.patch.object(expected_type, "update")
|
|
|
|
res = await runner.invoke(
|
|
|
|
cli,
|
|
|
|
["--type", device_type, "--host", "127.0.0.1"],
|
|
|
|
)
|
|
|
|
assert res.exit_code == 0
|
|
|
|
assert isinstance(result_device, expected_type)
|