mirror of
https://github.com/python-kasa/python-kasa.git
synced 2025-10-17 21:08:03 +00:00
Rename tests/smartcamera to tests/smartcam (#1315)
This commit is contained in:
0
tests/smartcam/__init__.py
Normal file
0
tests/smartcam/__init__.py
Normal file
0
tests/smartcam/modules/__init__.py
Normal file
0
tests/smartcam/modules/__init__.py
Normal file
159
tests/smartcam/modules/test_alarm.py
Normal file
159
tests/smartcam/modules/test_alarm.py
Normal file
@@ -0,0 +1,159 @@
|
||||
"""Tests for smart camera devices."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from kasa import Device
|
||||
from kasa.smartcam.modules.alarm import (
|
||||
DURATION_MAX,
|
||||
DURATION_MIN,
|
||||
VOLUME_MAX,
|
||||
VOLUME_MIN,
|
||||
)
|
||||
from kasa.smartcam.smartcammodule import SmartCamModule
|
||||
|
||||
from ...conftest import hub_smartcam
|
||||
|
||||
|
||||
@hub_smartcam
|
||||
async def test_alarm(dev: Device):
|
||||
"""Test device alarm."""
|
||||
alarm = dev.modules.get(SmartCamModule.SmartCamAlarm)
|
||||
assert alarm
|
||||
|
||||
original_duration = alarm.alarm_duration
|
||||
assert original_duration is not None
|
||||
original_volume = alarm.alarm_volume
|
||||
assert original_volume is not None
|
||||
original_sound = alarm.alarm_sound
|
||||
|
||||
try:
|
||||
# test volume
|
||||
new_volume = original_volume - 1 if original_volume > 1 else original_volume + 1
|
||||
await alarm.set_alarm_volume(new_volume) # type: ignore[arg-type]
|
||||
await dev.update()
|
||||
assert alarm.alarm_volume == new_volume
|
||||
|
||||
# test duration
|
||||
new_duration = (
|
||||
original_duration - 1 if original_duration > 1 else original_duration + 1
|
||||
)
|
||||
await alarm.set_alarm_duration(new_duration)
|
||||
await dev.update()
|
||||
assert alarm.alarm_duration == new_duration
|
||||
|
||||
# test start
|
||||
await alarm.play()
|
||||
await dev.update()
|
||||
assert alarm.active
|
||||
|
||||
# test stop
|
||||
await alarm.stop()
|
||||
await dev.update()
|
||||
assert not alarm.active
|
||||
|
||||
# test set sound
|
||||
new_sound = (
|
||||
alarm.alarm_sounds[0]
|
||||
if alarm.alarm_sound != alarm.alarm_sounds[0]
|
||||
else alarm.alarm_sounds[1]
|
||||
)
|
||||
await alarm.set_alarm_sound(new_sound)
|
||||
await dev.update()
|
||||
assert alarm.alarm_sound == new_sound
|
||||
|
||||
finally:
|
||||
await alarm.set_alarm_volume(original_volume)
|
||||
await alarm.set_alarm_duration(original_duration)
|
||||
await alarm.set_alarm_sound(original_sound)
|
||||
await dev.update()
|
||||
|
||||
|
||||
@hub_smartcam
|
||||
async def test_alarm_invalid_setters(dev: Device):
|
||||
"""Test device alarm invalid setter values."""
|
||||
alarm = dev.modules.get(SmartCamModule.SmartCamAlarm)
|
||||
assert alarm
|
||||
|
||||
# test set sound invalid
|
||||
msg = f"sound must be one of {', '.join(alarm.alarm_sounds)}: foobar"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
await alarm.set_alarm_sound("foobar")
|
||||
|
||||
# test volume invalid
|
||||
msg = f"volume must be between {VOLUME_MIN} and {VOLUME_MAX}"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
await alarm.set_alarm_volume(-3)
|
||||
|
||||
# test duration invalid
|
||||
msg = f"duration must be between {DURATION_MIN} and {DURATION_MAX}"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
await alarm.set_alarm_duration(-3)
|
||||
|
||||
|
||||
@hub_smartcam
|
||||
async def test_alarm_features(dev: Device):
|
||||
"""Test device alarm features."""
|
||||
alarm = dev.modules.get(SmartCamModule.SmartCamAlarm)
|
||||
assert alarm
|
||||
|
||||
original_duration = alarm.alarm_duration
|
||||
assert original_duration is not None
|
||||
original_volume = alarm.alarm_volume
|
||||
assert original_volume is not None
|
||||
original_sound = alarm.alarm_sound
|
||||
|
||||
try:
|
||||
# test volume
|
||||
new_volume = original_volume - 1 if original_volume > 1 else original_volume + 1
|
||||
feature = dev.features.get("alarm_volume")
|
||||
assert feature
|
||||
await feature.set_value(new_volume) # type: ignore[arg-type]
|
||||
await dev.update()
|
||||
assert feature.value == new_volume
|
||||
|
||||
# test duration
|
||||
feature = dev.features.get("alarm_duration")
|
||||
assert feature
|
||||
new_duration = (
|
||||
original_duration - 1 if original_duration > 1 else original_duration + 1
|
||||
)
|
||||
await feature.set_value(new_duration)
|
||||
await dev.update()
|
||||
assert feature.value == new_duration
|
||||
|
||||
# test start
|
||||
feature = dev.features.get("test_alarm")
|
||||
assert feature
|
||||
await feature.set_value(None)
|
||||
await dev.update()
|
||||
feature = dev.features.get("alarm")
|
||||
assert feature
|
||||
assert feature.value is True
|
||||
|
||||
# test stop
|
||||
feature = dev.features.get("stop_alarm")
|
||||
assert feature
|
||||
await feature.set_value(None)
|
||||
await dev.update()
|
||||
assert dev.features["alarm"].value is False
|
||||
|
||||
# test set sound
|
||||
feature = dev.features.get("alarm_sound")
|
||||
assert feature
|
||||
new_sound = (
|
||||
alarm.alarm_sounds[0]
|
||||
if alarm.alarm_sound != alarm.alarm_sounds[0]
|
||||
else alarm.alarm_sounds[1]
|
||||
)
|
||||
await feature.set_value(new_sound)
|
||||
await alarm.set_alarm_sound(new_sound)
|
||||
await dev.update()
|
||||
assert feature.value == new_sound
|
||||
|
||||
finally:
|
||||
await alarm.set_alarm_volume(original_volume)
|
||||
await alarm.set_alarm_duration(original_duration)
|
||||
await alarm.set_alarm_sound(original_sound)
|
||||
await dev.update()
|
123
tests/smartcam/test_smartcamera.py
Normal file
123
tests/smartcam/test_smartcamera.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""Tests for smart camera devices."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import json
|
||||
from datetime import UTC, datetime
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
|
||||
from kasa import Credentials, Device, DeviceType, Module
|
||||
|
||||
from ..conftest import camera_smartcam, device_smartcam, hub_smartcam
|
||||
|
||||
|
||||
@device_smartcam
|
||||
async def test_state(dev: Device):
|
||||
if dev.device_type is DeviceType.Hub:
|
||||
pytest.skip("Hubs cannot be switched on and off")
|
||||
|
||||
state = dev.is_on
|
||||
await dev.set_state(not state)
|
||||
await dev.update()
|
||||
assert dev.is_on is not state
|
||||
|
||||
|
||||
@camera_smartcam
|
||||
async def test_stream_rtsp_url(dev: Device):
|
||||
camera_module = dev.modules.get(Module.Camera)
|
||||
assert camera_module
|
||||
|
||||
await camera_module.set_state(True)
|
||||
await dev.update()
|
||||
assert camera_module.is_on
|
||||
url = camera_module.stream_rtsp_url(Credentials("foo", "bar"))
|
||||
assert url == "rtsp://foo:bar@127.0.0.123:554/stream1"
|
||||
|
||||
with patch.object(dev.config, "credentials", Credentials("bar", "foo")):
|
||||
url = camera_module.stream_rtsp_url()
|
||||
assert url == "rtsp://bar:foo@127.0.0.123:554/stream1"
|
||||
|
||||
with patch.object(dev.config, "credentials", Credentials("bar", "")):
|
||||
url = camera_module.stream_rtsp_url()
|
||||
assert url is None
|
||||
|
||||
with patch.object(dev.config, "credentials", Credentials("", "Foo")):
|
||||
url = camera_module.stream_rtsp_url()
|
||||
assert url is None
|
||||
|
||||
# Test with credentials_hash
|
||||
cred = json.dumps({"un": "bar", "pwd": "foobar"})
|
||||
cred_hash = base64.b64encode(cred.encode()).decode()
|
||||
with (
|
||||
patch.object(dev.config, "credentials", None),
|
||||
patch.object(dev.config, "credentials_hash", cred_hash),
|
||||
):
|
||||
url = camera_module.stream_rtsp_url()
|
||||
assert url == "rtsp://bar:foobar@127.0.0.123:554/stream1"
|
||||
|
||||
# Test with invalid credentials_hash
|
||||
with (
|
||||
patch.object(dev.config, "credentials", None),
|
||||
patch.object(dev.config, "credentials_hash", b"238472871"),
|
||||
):
|
||||
url = camera_module.stream_rtsp_url()
|
||||
assert url is None
|
||||
|
||||
# Test with no credentials
|
||||
with (
|
||||
patch.object(dev.config, "credentials", None),
|
||||
patch.object(dev.config, "credentials_hash", None),
|
||||
):
|
||||
url = camera_module.stream_rtsp_url()
|
||||
assert url is None
|
||||
|
||||
# Test with camera off
|
||||
await camera_module.set_state(False)
|
||||
await dev.update()
|
||||
url = camera_module.stream_rtsp_url(Credentials("foo", "bar"))
|
||||
assert url is None
|
||||
with patch.object(dev.config, "credentials", Credentials("bar", "foo")):
|
||||
url = camera_module.stream_rtsp_url()
|
||||
assert url is None
|
||||
|
||||
|
||||
@device_smartcam
|
||||
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
|
||||
|
||||
|
||||
@hub_smartcam
|
||||
async def test_hub(dev):
|
||||
assert dev.children
|
||||
for child in dev.children:
|
||||
assert "Cloud" in child.modules
|
||||
assert child.modules["Cloud"].data
|
||||
assert child.alias
|
||||
await child.update()
|
||||
assert "Time" not in child.modules
|
||||
assert child.time
|
||||
|
||||
|
||||
@device_smartcam
|
||||
async def test_device_time(dev: Device, freezer: FrozenDateTimeFactory):
|
||||
"""Test a child device gets the time from it's parent module."""
|
||||
fallback_time = datetime.now(UTC).astimezone().replace(microsecond=0)
|
||||
assert dev.time != fallback_time
|
||||
module = dev.modules[Module.Time]
|
||||
await module.set_time(fallback_time)
|
||||
await dev.update()
|
||||
assert dev.time == fallback_time
|
Reference in New Issue
Block a user