Improve seventeentrack (#25454)

* Code improvement + tests

* review

* review + moving to pytest test function

* move test to async

* remove code comment
This commit is contained in:
Thomas Germain 2019-07-28 19:55:46 +02:00 committed by Martin Hjelmare
parent da53e0a836
commit 4936e55979
5 changed files with 382 additions and 78 deletions

View file

@ -0,0 +1,311 @@
"""Tests for the seventeentrack sensor."""
import datetime
from typing import Union
import pytest
import mock
from py17track.package import Package
from homeassistant.components.seventeentrack.sensor \
import CONF_SHOW_ARCHIVED, CONF_SHOW_DELIVERED
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD
from homeassistant.setup import async_setup_component
from homeassistant.util import utcnow
from tests.common import MockDependency, async_fire_time_changed
VALID_CONFIG_MINIMAL = {
'sensor': {
'platform': 'seventeentrack',
CONF_USERNAME: 'test',
CONF_PASSWORD: 'test'
}
}
INVALID_CONFIG = {
'sensor': {
'platform': 'seventeentrack',
'boom': 'test',
}
}
VALID_CONFIG_FULL = {
'sensor': {
'platform': 'seventeentrack',
CONF_USERNAME: 'test',
CONF_PASSWORD: 'test',
CONF_SHOW_ARCHIVED: True,
CONF_SHOW_DELIVERED: True
}
}
VALID_CONFIG_FULL_NO_DELIVERED = {
'sensor': {
'platform': 'seventeentrack',
CONF_USERNAME: 'test',
CONF_PASSWORD: 'test',
CONF_SHOW_ARCHIVED: False,
CONF_SHOW_DELIVERED: False
}
}
DEFAULT_SUMMARY = {
"Not Found": 0,
"In Transit": 0,
"Expired": 0,
"Ready to be Picked Up": 0,
"Undelivered": 0,
"Delivered": 0,
"Returned": 0
}
NEW_SUMMARY_DATA = {
"Not Found": 1,
"In Transit": 1,
"Expired": 1,
"Ready to be Picked Up": 1,
"Undelivered": 1,
"Delivered": 1,
"Returned": 1
}
class ClientMock:
"""Mock the py17track client to inject the ProfileMock."""
def __init__(self, websession) -> None:
"""Mock the profile."""
self.profile = ProfileMock()
class ProfileMock:
"""ProfileMock will mock data coming from 17track."""
package_list = []
login_result = True
summary_data = DEFAULT_SUMMARY
account_id = '123'
@classmethod
def reset(cls):
"""Reset data to defaults."""
cls.package_list = []
cls.login_result = True
cls.summary_data = DEFAULT_SUMMARY
cls.account_id = '123'
def __init__(self) -> None:
"""Override Account id."""
self.account_id = self.__class__.account_id
async def login(self, email: str, password: str) -> bool:
"""Login mock."""
return self.__class__.login_result
async def packages(self, package_state: Union[int, str] = '',
show_archived: bool = False) -> list:
"""Packages mock."""
return self.__class__.package_list[:]
async def summary(self, show_archived: bool = False) -> dict:
"""Summary mock."""
return self.__class__.summary_data
@pytest.fixture(autouse=True, name="mock_py17track")
def fixture_mock_py17track():
"""Mock py17track dependency."""
with MockDependency('py17track'):
yield
@pytest.fixture(autouse=True, name="mock_client")
def fixture_mock_client(mock_py17track):
"""Mock py17track client."""
with mock.patch('py17track.Client', new=ClientMock):
yield
ProfileMock.reset()
async def _setup_seventeentrack(hass, config=None, summary_data=None):
"""Set up component using config."""
if not config:
config = VALID_CONFIG_MINIMAL
if not summary_data:
summary_data = {}
ProfileMock.summary_data = summary_data
assert await async_setup_component(hass, 'sensor', config)
async def _goto_future(hass, future=None):
"""Move to future."""
if not future:
future = utcnow() + datetime.timedelta(minutes=10)
with mock.patch('homeassistant.util.utcnow', return_value=future):
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
async def test_full_valid_config(hass):
"""Ensure everything starts correctly."""
assert await async_setup_component(hass, 'sensor', VALID_CONFIG_FULL)
assert len(hass.states.async_entity_ids()) == len(
ProfileMock.summary_data.keys())
async def test_valid_config(hass):
"""Ensure everything starts correctly."""
assert await async_setup_component(hass, 'sensor', VALID_CONFIG_MINIMAL)
assert len(hass.states.async_entity_ids()) == len(
ProfileMock.summary_data.keys())
async def test_invalid_config(hass):
"""Ensure nothing is created when config is wrong."""
assert await async_setup_component(hass, 'sensor', INVALID_CONFIG)
assert not hass.states.async_entity_ids()
async def test_add_package(hass):
"""Ensure package is added correctly when user add a new package."""
package = Package('456', 206, 'friendly name 1', 'info text 1',
'location 1', 206, 2)
ProfileMock.package_list = [package]
await _setup_seventeentrack(hass)
assert hass.states.get(
'sensor.seventeentrack_package_456') is not None
assert len(hass.states.async_entity_ids()) == 1
package2 = Package('789', 206, 'friendly name 2', 'info text 2',
'location 2', 206, 2)
ProfileMock.package_list = [package, package2]
await _goto_future(hass)
assert hass.states.get(
'sensor.seventeentrack_package_789') is not None
assert len(hass.states.async_entity_ids()) == 2
async def test_remove_package(hass):
"""Ensure entity is not there anymore if package is not there."""
package1 = Package('456', 206, 'friendly name 1', 'info text 1',
'location 1', 206, 2)
package2 = Package('789', 206, 'friendly name 2', 'info text 2',
'location 2', 206, 2)
ProfileMock.package_list = [package1, package2]
await _setup_seventeentrack(hass)
assert hass.states.get(
'sensor.seventeentrack_package_456') is not None
assert hass.states.get(
'sensor.seventeentrack_package_789') is not None
assert len(hass.states.async_entity_ids()) == 2
ProfileMock.package_list = [package2]
await _goto_future(hass)
assert hass.states.get(
'sensor.seventeentrack_package_456') is None
assert hass.states.get(
'sensor.seventeentrack_package_789') is not None
assert len(hass.states.async_entity_ids()) == 1
async def test_friendly_name_changed(hass):
"""Test friendly name change."""
package = Package('456', 206, 'friendly name 1', 'info text 1',
'location 1', 206, 2)
ProfileMock.package_list = [package]
await _setup_seventeentrack(hass)
assert hass.states.get(
'sensor.seventeentrack_package_456') is not None
assert len(hass.states.async_entity_ids()) == 1
package = Package('456', 206, 'friendly name 2', 'info text 1',
'location 1', 206, 2)
ProfileMock.package_list = [package]
await _goto_future(hass)
assert hass.states.get(
'sensor.seventeentrack_package_456') is not None
entity = hass.data['entity_components']['sensor'].get_entity(
'sensor.seventeentrack_package_456')
assert entity.name == 'Seventeentrack Package: friendly name 2'
assert len(hass.states.async_entity_ids()) == 1
async def test_delivered_not_shown(hass):
"""Ensure delivered packages are not shown."""
package = Package('456', 206, 'friendly name 1', 'info text 1',
'location 1', 206, 2, 40)
ProfileMock.package_list = [package]
hass.components.persistent_notification = mock.MagicMock()
await _setup_seventeentrack(hass, VALID_CONFIG_FULL_NO_DELIVERED)
assert not hass.states.async_entity_ids()
hass.components.persistent_notification.create.assert_called()
async def test_delivered_shown(hass):
"""Ensure delivered packages are show when user choose to show them."""
package = Package('456', 206, 'friendly name 1', 'info text 1',
'location 1', 206, 2, 40)
ProfileMock.package_list = [package]
hass.components.persistent_notification = mock.MagicMock()
await _setup_seventeentrack(hass, VALID_CONFIG_FULL)
assert hass.states.get(
'sensor.seventeentrack_package_456') is not None
assert len(hass.states.async_entity_ids()) == 1
hass.components.persistent_notification.create.assert_not_called()
async def test_becomes_delivered_not_shown_notification(hass):
"""Ensure notification is triggered when package becomes delivered."""
package = Package('456', 206, 'friendly name 1', 'info text 1',
'location 1', 206, 2)
ProfileMock.package_list = [package]
await _setup_seventeentrack(hass, VALID_CONFIG_FULL_NO_DELIVERED)
assert hass.states.get(
'sensor.seventeentrack_package_456') is not None
assert len(hass.states.async_entity_ids()) == 1
package_delivered = Package('456', 206, 'friendly name 1',
'info text 1', 'location 1', 206, 2, 40)
ProfileMock.package_list = [package_delivered]
hass.components.persistent_notification = mock.MagicMock()
await _goto_future(hass)
hass.components.persistent_notification.create.assert_called()
assert not hass.states.async_entity_ids()
async def test_summary_correctly_updated(hass):
"""Ensure summary entities are not duplicated."""
await _setup_seventeentrack(hass, summary_data=DEFAULT_SUMMARY)
assert len(hass.states.async_entity_ids()) == 7
for state in hass.states.async_all():
assert state.state == '0'
ProfileMock.summary_data = NEW_SUMMARY_DATA
await _goto_future(hass)
assert len(hass.states.async_entity_ids()) == 7
for state in hass.states.async_all():
assert state.state == '1'