* {switch,light}.tplink: use deviceid as unique id, fetch name from the device during initialization * raise PlatformNotReady when no device is available * Use mac instead of deviceid * remove name option as obsolete * Add support for configuration flow / integration Allows activating automatic discovery of supported devices from the configuration * Fix linting, update requirements_all.txt * start cleaning up tplink component based on feedback * add device info, improve config handling * Allow overriding detected devices via configuration file * Update requirements.txt * Remove debug logging * make hound happy * Avoid I/O during init and simplify the code, remove remains of leds_on * Fix issues based on feedback, use consistent quotation marks for device info * add async_setup_platform emiting a deprecation warning * Avoid blocking the I/O, check for None on features * handle some Martin's comments, schema-validation is still missing * use async_create_task instead of async_add_job, let core validate the schema * simplify configuration handling by storing the configuration data separately from initialized instances * add default values to schema, make hound happy * with defaults set by schema, simplify the checks. add async_unload_entry * Use constant for data structure access * REWORD add a short note about async_unload_entry * handle feedback from Martin, config_data is checked against Noneness * use pop to remove the domain on unload * First steps to add tests for the new tplink component * embed platforms under the component directory * Fix tests by mocking the pyhs100 internals * Fix linting * Test against multiple instances of devices, tidy up * (hopefully) final linting round * Add pyHS100 to test requirements * log always the warnings occured during an update to make them easy to see * revert back the warning behavior (requirement for silver level in IQS) * Unload only when an entry is being loaded and add tests for that Thanks @MartinHjelmare for pointing this out! * Fix linting * Bump the upstream lib, fixes most prominently the HSV setting on bulbs * Test unloading for all platforms, clear the data storage instead of popping it out, making it possible to reconfigure after removal without restarting hass first * Use class variables instead of instance variables for bulb states, required for HS220 * Use new-style format string * Fix indenting, uppercase the mock constant * Run black on test_init, hopefully that will finally fix the weird formatting (pycharm, pylint and hound seems to have different opinions...)
181 lines
6.3 KiB
Python
181 lines
6.3 KiB
Python
"""Tests for the TP-Link component."""
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from homeassistant import config_entries, data_entry_flow
|
|
from homeassistant.components import tplink
|
|
from homeassistant.setup import async_setup_component
|
|
from pyHS100 import SmartPlug, SmartBulb
|
|
from tests.common import MockDependency, MockConfigEntry, mock_coro
|
|
|
|
MOCK_PYHS100 = MockDependency("pyHS100")
|
|
|
|
|
|
async def test_creating_entry_tries_discover(hass):
|
|
"""Test setting up does discovery."""
|
|
with MOCK_PYHS100, patch(
|
|
"homeassistant.components.tplink.async_setup_entry",
|
|
return_value=mock_coro(True),
|
|
) as mock_setup, patch(
|
|
"pyHS100.Discover.discover", return_value={"host": 1234}
|
|
):
|
|
result = await hass.config_entries.flow.async_init(
|
|
tplink.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
|
|
# Confirmation form
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"], {}
|
|
)
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(mock_setup.mock_calls) == 1
|
|
|
|
|
|
async def test_configuring_tplink_causes_discovery(hass):
|
|
"""Test that specifying empty config does discovery."""
|
|
with MOCK_PYHS100, patch("pyHS100.Discover.discover") as discover:
|
|
discover.return_value = {"host": 1234}
|
|
await async_setup_component(hass, tplink.DOMAIN, {"tplink": {}})
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(discover.mock_calls) == 1
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"name,cls,platform",
|
|
[
|
|
("pyHS100.SmartPlug", SmartPlug, "switch"),
|
|
("pyHS100.SmartBulb", SmartBulb, "light"),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize("count", [1, 2, 3])
|
|
async def test_configuring_device_types(hass, name, cls, platform, count):
|
|
"""Test that light or switch platform list is filled correctly."""
|
|
with patch("pyHS100.Discover.discover") as discover, patch(
|
|
"pyHS100.SmartDevice._query_helper"
|
|
):
|
|
discovery_data = {
|
|
"123.123.123.{}".format(c): cls("123.123.123.123")
|
|
for c in range(count)
|
|
}
|
|
discover.return_value = discovery_data
|
|
await async_setup_component(hass, tplink.DOMAIN, {"tplink": {}})
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(discover.mock_calls) == 1
|
|
assert len(hass.data[tplink.DOMAIN][platform]) == count
|
|
|
|
|
|
async def test_is_dimmable(hass):
|
|
"""Test that is_dimmable switches are correctly added as lights."""
|
|
with patch("pyHS100.Discover.discover") as discover, patch(
|
|
"homeassistant.components.tplink.light.async_setup_entry",
|
|
return_value=mock_coro(True),
|
|
) as setup, patch("pyHS100.SmartDevice._query_helper"), patch(
|
|
"pyHS100.SmartPlug.is_dimmable", True
|
|
):
|
|
dimmable_switch = SmartPlug("123.123.123.123")
|
|
discover.return_value = {"host": dimmable_switch}
|
|
|
|
await async_setup_component(hass, tplink.DOMAIN, {"tplink": {}})
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(discover.mock_calls) == 1
|
|
assert len(setup.mock_calls) == 1
|
|
assert len(hass.data[tplink.DOMAIN]["light"]) == 1
|
|
assert len(hass.data[tplink.DOMAIN]["switch"]) == 0
|
|
|
|
|
|
async def test_configuring_discovery_disabled(hass):
|
|
"""Test that discover does not get called when disabled."""
|
|
with MOCK_PYHS100, patch(
|
|
"homeassistant.components.tplink.async_setup_entry",
|
|
return_value=mock_coro(True),
|
|
) as mock_setup, patch(
|
|
"pyHS100.Discover.discover", return_value=[]
|
|
) as discover:
|
|
await async_setup_component(
|
|
hass,
|
|
tplink.DOMAIN,
|
|
{tplink.DOMAIN: {tplink.CONF_DISCOVERY: False}},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(discover.mock_calls) == 0
|
|
assert len(mock_setup.mock_calls) == 1
|
|
|
|
|
|
async def test_platforms_are_initialized(hass):
|
|
"""Test that platforms are initialized per configuration array."""
|
|
config = {
|
|
"tplink": {
|
|
"discovery": False,
|
|
"light": [{"host": "123.123.123.123"}],
|
|
"switch": [{"host": "321.321.321.321"}],
|
|
}
|
|
}
|
|
|
|
with patch("pyHS100.Discover.discover") as discover, patch(
|
|
"pyHS100.SmartDevice._query_helper"
|
|
), patch(
|
|
"homeassistant.components.tplink.light.async_setup_entry",
|
|
return_value=mock_coro(True),
|
|
) as light_setup, patch(
|
|
"homeassistant.components.tplink.switch.async_setup_entry",
|
|
return_value=mock_coro(True),
|
|
) as switch_setup, patch(
|
|
"pyHS100.SmartPlug.is_dimmable", False
|
|
):
|
|
# patching is_dimmable is necessray to avoid misdetection as light.
|
|
await async_setup_component(hass, tplink.DOMAIN, config)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(discover.mock_calls) == 0
|
|
assert len(light_setup.mock_calls) == 1
|
|
assert len(switch_setup.mock_calls) == 1
|
|
|
|
|
|
async def test_no_config_creates_no_entry(hass):
|
|
"""Test for when there is no tplink in config."""
|
|
with MOCK_PYHS100, patch(
|
|
"homeassistant.components.tplink.async_setup_entry",
|
|
return_value=mock_coro(True),
|
|
) as mock_setup:
|
|
await async_setup_component(hass, tplink.DOMAIN, {})
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(mock_setup.mock_calls) == 0
|
|
|
|
|
|
@pytest.mark.parametrize("platform", ["switch", "light"])
|
|
async def test_unload(hass, platform):
|
|
"""Test that the async_unload_entry works."""
|
|
# As we have currently no configuration, we just to pass the domain here.
|
|
entry = MockConfigEntry(domain=tplink.DOMAIN)
|
|
entry.add_to_hass(hass)
|
|
|
|
with patch("pyHS100.SmartDevice._query_helper"), patch(
|
|
"homeassistant.components.tplink.{}"
|
|
".async_setup_entry".format(platform),
|
|
return_value=mock_coro(True),
|
|
) as light_setup:
|
|
config = {
|
|
"tplink": {
|
|
platform: [{"host": "123.123.123.123"}],
|
|
"discovery": False,
|
|
}
|
|
}
|
|
assert await async_setup_component(hass, tplink.DOMAIN, config)
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(light_setup.mock_calls) == 1
|
|
assert tplink.DOMAIN in hass.data
|
|
|
|
assert await tplink.async_unload_entry(hass, entry)
|
|
assert not hass.data[tplink.DOMAIN]
|