From 50a30d4dc91ed2a044499de0504573c0ec200ac6 Mon Sep 17 00:00:00 2001 From: Adam Mills Date: Sat, 24 Nov 2018 15:10:57 -0500 Subject: [PATCH] Async tests for remaining device trackers (#18682) --- .../components/device_tracker/test_tplink.py | 32 +-- .../device_tracker/test_unifi_direct.py | 216 +++++++++--------- .../components/device_tracker/test_xiaomi.py | 202 ++++++++-------- 3 files changed, 213 insertions(+), 237 deletions(-) diff --git a/tests/components/device_tracker/test_tplink.py b/tests/components/device_tracker/test_tplink.py index b50d1c67511..8f226f449b0 100644 --- a/tests/components/device_tracker/test_tplink.py +++ b/tests/components/device_tracker/test_tplink.py @@ -1,7 +1,7 @@ """The tests for the tplink device tracker platform.""" import os -import unittest +import pytest from homeassistant.components import device_tracker from homeassistant.components.device_tracker.tplink import Tplink4DeviceScanner @@ -9,27 +9,19 @@ from homeassistant.const import (CONF_PLATFORM, CONF_PASSWORD, CONF_USERNAME, CONF_HOST) import requests_mock -from tests.common import get_test_home_assistant + +@pytest.fixture(autouse=True) +def setup_comp(hass): + """Initialize components.""" + yaml_devices = hass.config.path(device_tracker.YAML_DEVICES) + yield + if os.path.isfile(yaml_devices): + os.remove(yaml_devices) -class TestTplink4DeviceScanner(unittest.TestCase): - """Tests for the Tplink4DeviceScanner class.""" - - def setUp(self): # pylint: disable=invalid-name - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - - def tearDown(self): # pylint: disable=invalid-name - """Stop everything that was started.""" - self.hass.stop() - try: - os.remove(self.hass.config.path(device_tracker.YAML_DEVICES)) - except FileNotFoundError: - pass - - @requests_mock.mock() - def test_get_mac_addresses_from_both_bands(self, m): - """Test grabbing the mac addresses from 2.4 and 5 GHz clients pages.""" +async def test_get_mac_addresses_from_both_bands(hass): + """Test grabbing the mac addresses from 2.4 and 5 GHz clients pages.""" + with requests_mock.Mocker() as m: conf_dict = { CONF_PLATFORM: 'tplink', CONF_HOST: 'fake-host', diff --git a/tests/components/device_tracker/test_unifi_direct.py b/tests/components/device_tracker/test_unifi_direct.py index 6e2830eee52..1b1dc1a7cb5 100644 --- a/tests/components/device_tracker/test_unifi_direct.py +++ b/tests/components/device_tracker/test_unifi_direct.py @@ -1,14 +1,12 @@ """The tests for the Unifi direct device tracker platform.""" import os from datetime import timedelta -import unittest -from unittest import mock -from unittest.mock import patch +from asynctest import mock, patch import pytest import voluptuous as vol -from homeassistant.setup import setup_component +from homeassistant.setup import async_setup_component from homeassistant.components import device_tracker from homeassistant.components.device_tracker import ( CONF_CONSIDER_HOME, CONF_TRACK_NEW, CONF_AWAY_HIDE, @@ -19,133 +17,129 @@ from homeassistant.const import (CONF_PLATFORM, CONF_PASSWORD, CONF_USERNAME, CONF_HOST) from tests.common import ( - get_test_home_assistant, assert_setup_component, - mock_component, load_fixture) + assert_setup_component, mock_component, load_fixture) + +scanner_path = 'homeassistant.components.device_tracker.' + \ + 'unifi_direct.UnifiDeviceScanner' -class TestComponentsDeviceTrackerUnifiDirect(unittest.TestCase): - """Tests for the Unifi direct device tracker platform.""" +@pytest.fixture(autouse=True) +def setup_comp(hass): + """Initialize components.""" + mock_component(hass, 'zone') + yaml_devices = hass.config.path(device_tracker.YAML_DEVICES) + yield + if os.path.isfile(yaml_devices): + os.remove(yaml_devices) - hass = None - scanner_path = 'homeassistant.components.device_tracker.' + \ - 'unifi_direct.UnifiDeviceScanner' - def setup_method(self, _): - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - mock_component(self.hass, 'zone') - - def teardown_method(self, _): - """Stop everything that was started.""" - self.hass.stop() - try: - os.remove(self.hass.config.path(device_tracker.YAML_DEVICES)) - except FileNotFoundError: - pass - - @mock.patch(scanner_path, - return_value=mock.MagicMock()) - def test_get_scanner(self, unifi_mock): - """Test creating an Unifi direct scanner with a password.""" - conf_dict = { - DOMAIN: { - CONF_PLATFORM: 'unifi_direct', - CONF_HOST: 'fake_host', - CONF_USERNAME: 'fake_user', - CONF_PASSWORD: 'fake_pass', +@patch(scanner_path, return_value=mock.MagicMock()) +async def test_get_scanner(unifi_mock, hass): + """Test creating an Unifi direct scanner with a password.""" + conf_dict = { + DOMAIN: { + CONF_PLATFORM: 'unifi_direct', + CONF_HOST: 'fake_host', + CONF_USERNAME: 'fake_user', + CONF_PASSWORD: 'fake_pass', + CONF_TRACK_NEW: True, + CONF_CONSIDER_HOME: timedelta(seconds=180), + CONF_NEW_DEVICE_DEFAULTS: { CONF_TRACK_NEW: True, - CONF_CONSIDER_HOME: timedelta(seconds=180), - CONF_NEW_DEVICE_DEFAULTS: { - CONF_TRACK_NEW: True, - CONF_AWAY_HIDE: False - } + CONF_AWAY_HIDE: False } } + } - with assert_setup_component(1, DOMAIN): - assert setup_component(self.hass, DOMAIN, conf_dict) + with assert_setup_component(1, DOMAIN): + assert await async_setup_component(hass, DOMAIN, conf_dict) - conf_dict[DOMAIN][CONF_PORT] = 22 - assert unifi_mock.call_args == mock.call(conf_dict[DOMAIN]) + conf_dict[DOMAIN][CONF_PORT] = 22 + assert unifi_mock.call_args == mock.call(conf_dict[DOMAIN]) - @patch('pexpect.pxssh.pxssh') - def test_get_device_name(self, mock_ssh): - """Testing MAC matching.""" - conf_dict = { - DOMAIN: { - CONF_PLATFORM: 'unifi_direct', - CONF_HOST: 'fake_host', - CONF_USERNAME: 'fake_user', - CONF_PASSWORD: 'fake_pass', - CONF_PORT: 22, - CONF_TRACK_NEW: True, - CONF_CONSIDER_HOME: timedelta(seconds=180) - } + +@patch('pexpect.pxssh.pxssh') +async def test_get_device_name(mock_ssh, hass): + """Testing MAC matching.""" + conf_dict = { + DOMAIN: { + CONF_PLATFORM: 'unifi_direct', + CONF_HOST: 'fake_host', + CONF_USERNAME: 'fake_user', + CONF_PASSWORD: 'fake_pass', + CONF_PORT: 22, + CONF_TRACK_NEW: True, + CONF_CONSIDER_HOME: timedelta(seconds=180) } - mock_ssh.return_value.before = load_fixture('unifi_direct.txt') - scanner = get_scanner(self.hass, conf_dict) - devices = scanner.scan_devices() - assert 23 == len(devices) - assert "iPhone" == \ - scanner.get_device_name("98:00:c6:56:34:12") - assert "iPhone" == \ - scanner.get_device_name("98:00:C6:56:34:12") + } + mock_ssh.return_value.before = load_fixture('unifi_direct.txt') + scanner = get_scanner(hass, conf_dict) + devices = scanner.scan_devices() + assert 23 == len(devices) + assert "iPhone" == \ + scanner.get_device_name("98:00:c6:56:34:12") + assert "iPhone" == \ + scanner.get_device_name("98:00:C6:56:34:12") - @patch('pexpect.pxssh.pxssh.logout') - @patch('pexpect.pxssh.pxssh.login') - def test_failed_to_log_in(self, mock_login, mock_logout): - """Testing exception at login results in False.""" - from pexpect import exceptions - conf_dict = { - DOMAIN: { - CONF_PLATFORM: 'unifi_direct', - CONF_HOST: 'fake_host', - CONF_USERNAME: 'fake_user', - CONF_PASSWORD: 'fake_pass', - CONF_PORT: 22, - CONF_TRACK_NEW: True, - CONF_CONSIDER_HOME: timedelta(seconds=180) - } +@patch('pexpect.pxssh.pxssh.logout') +@patch('pexpect.pxssh.pxssh.login') +async def test_failed_to_log_in(mock_login, mock_logout, hass): + """Testing exception at login results in False.""" + from pexpect import exceptions + + conf_dict = { + DOMAIN: { + CONF_PLATFORM: 'unifi_direct', + CONF_HOST: 'fake_host', + CONF_USERNAME: 'fake_user', + CONF_PASSWORD: 'fake_pass', + CONF_PORT: 22, + CONF_TRACK_NEW: True, + CONF_CONSIDER_HOME: timedelta(seconds=180) } + } - mock_login.side_effect = exceptions.EOF("Test") - scanner = get_scanner(self.hass, conf_dict) - assert not scanner + mock_login.side_effect = exceptions.EOF("Test") + scanner = get_scanner(hass, conf_dict) + assert not scanner - @patch('pexpect.pxssh.pxssh.logout') - @patch('pexpect.pxssh.pxssh.login', autospec=True) - @patch('pexpect.pxssh.pxssh.prompt') - @patch('pexpect.pxssh.pxssh.sendline') - def test_to_get_update(self, mock_sendline, mock_prompt, mock_login, - mock_logout): - """Testing exception in get_update matching.""" - conf_dict = { - DOMAIN: { - CONF_PLATFORM: 'unifi_direct', - CONF_HOST: 'fake_host', - CONF_USERNAME: 'fake_user', - CONF_PASSWORD: 'fake_pass', - CONF_PORT: 22, - CONF_TRACK_NEW: True, - CONF_CONSIDER_HOME: timedelta(seconds=180) - } + +@patch('pexpect.pxssh.pxssh.logout') +@patch('pexpect.pxssh.pxssh.login', autospec=True) +@patch('pexpect.pxssh.pxssh.prompt') +@patch('pexpect.pxssh.pxssh.sendline') +async def test_to_get_update(mock_sendline, mock_prompt, mock_login, + mock_logout, hass): + """Testing exception in get_update matching.""" + conf_dict = { + DOMAIN: { + CONF_PLATFORM: 'unifi_direct', + CONF_HOST: 'fake_host', + CONF_USERNAME: 'fake_user', + CONF_PASSWORD: 'fake_pass', + CONF_PORT: 22, + CONF_TRACK_NEW: True, + CONF_CONSIDER_HOME: timedelta(seconds=180) } + } - scanner = get_scanner(self.hass, conf_dict) - # mock_sendline.side_effect = AssertionError("Test") - mock_prompt.side_effect = AssertionError("Test") - devices = scanner._get_update() # pylint: disable=protected-access - assert devices is None + scanner = get_scanner(hass, conf_dict) + # mock_sendline.side_effect = AssertionError("Test") + mock_prompt.side_effect = AssertionError("Test") + devices = scanner._get_update() # pylint: disable=protected-access + assert devices is None - def test_good_response_parses(self): - """Test that the response form the AP parses to JSON correctly.""" - response = _response_to_json(load_fixture('unifi_direct.txt')) - assert response != {} - def test_bad_response_returns_none(self): - """Test that a bad response form the AP parses to JSON correctly.""" - assert _response_to_json("{(}") == {} +def test_good_response_parses(hass): + """Test that the response form the AP parses to JSON correctly.""" + response = _response_to_json(load_fixture('unifi_direct.txt')) + assert response != {} + + +def test_bad_response_returns_none(hass): + """Test that a bad response form the AP parses to JSON correctly.""" + assert _response_to_json("{(}") == {} def test_config_error(): diff --git a/tests/components/device_tracker/test_xiaomi.py b/tests/components/device_tracker/test_xiaomi.py index 9c7c13ee741..7b141159256 100644 --- a/tests/components/device_tracker/test_xiaomi.py +++ b/tests/components/device_tracker/test_xiaomi.py @@ -1,8 +1,6 @@ """The tests for the Xiaomi router device tracker platform.""" import logging -import unittest -from unittest import mock -from unittest.mock import patch +from asynctest import mock, patch import requests @@ -10,7 +8,6 @@ from homeassistant.components.device_tracker import DOMAIN, xiaomi as xiaomi from homeassistant.components.device_tracker.xiaomi import get_scanner from homeassistant.const import (CONF_HOST, CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM) -from tests.common import get_test_home_assistant _LOGGER = logging.getLogger(__name__) @@ -152,113 +149,106 @@ def mocked_requests(*args, **kwargs): _LOGGER.debug('UNKNOWN ROUTE') -class TestXiaomiDeviceScanner(unittest.TestCase): - """Xiaomi device scanner test class.""" +@patch( + 'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner', + return_value=mock.MagicMock()) +async def test_config(xiaomi_mock, hass): + """Testing minimal configuration.""" + config = { + DOMAIN: xiaomi.PLATFORM_SCHEMA({ + CONF_PLATFORM: xiaomi.DOMAIN, + CONF_HOST: '192.168.0.1', + CONF_PASSWORD: 'passwordTest' + }) + } + xiaomi.get_scanner(hass, config) + assert xiaomi_mock.call_count == 1 + assert xiaomi_mock.call_args == mock.call(config[DOMAIN]) + call_arg = xiaomi_mock.call_args[0][0] + assert call_arg['username'] == 'admin' + assert call_arg['password'] == 'passwordTest' + assert call_arg['host'] == '192.168.0.1' + assert call_arg['platform'] == 'device_tracker' - def setUp(self): - """Initialize values for this testcase class.""" - self.hass = get_test_home_assistant() - def tearDown(self): - """Stop everything that was started.""" - self.hass.stop() +@patch( + 'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner', + return_value=mock.MagicMock()) +async def test_config_full(xiaomi_mock, hass): + """Testing full configuration.""" + config = { + DOMAIN: xiaomi.PLATFORM_SCHEMA({ + CONF_PLATFORM: xiaomi.DOMAIN, + CONF_HOST: '192.168.0.1', + CONF_USERNAME: 'alternativeAdminName', + CONF_PASSWORD: 'passwordTest' + }) + } + xiaomi.get_scanner(hass, config) + assert xiaomi_mock.call_count == 1 + assert xiaomi_mock.call_args == mock.call(config[DOMAIN]) + call_arg = xiaomi_mock.call_args[0][0] + assert call_arg['username'] == 'alternativeAdminName' + assert call_arg['password'] == 'passwordTest' + assert call_arg['host'] == '192.168.0.1' + assert call_arg['platform'] == 'device_tracker' - @mock.patch( - 'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner', - return_value=mock.MagicMock()) - def test_config(self, xiaomi_mock): - """Testing minimal configuration.""" - config = { - DOMAIN: xiaomi.PLATFORM_SCHEMA({ - CONF_PLATFORM: xiaomi.DOMAIN, - CONF_HOST: '192.168.0.1', - CONF_PASSWORD: 'passwordTest' - }) - } - xiaomi.get_scanner(self.hass, config) - assert xiaomi_mock.call_count == 1 - assert xiaomi_mock.call_args == mock.call(config[DOMAIN]) - call_arg = xiaomi_mock.call_args[0][0] - assert call_arg['username'] == 'admin' - assert call_arg['password'] == 'passwordTest' - assert call_arg['host'] == '192.168.0.1' - assert call_arg['platform'] == 'device_tracker' - @mock.patch( - 'homeassistant.components.device_tracker.xiaomi.XiaomiDeviceScanner', - return_value=mock.MagicMock()) - def test_config_full(self, xiaomi_mock): - """Testing full configuration.""" - config = { - DOMAIN: xiaomi.PLATFORM_SCHEMA({ - CONF_PLATFORM: xiaomi.DOMAIN, - CONF_HOST: '192.168.0.1', - CONF_USERNAME: 'alternativeAdminName', - CONF_PASSWORD: 'passwordTest' - }) - } - xiaomi.get_scanner(self.hass, config) - assert xiaomi_mock.call_count == 1 - assert xiaomi_mock.call_args == mock.call(config[DOMAIN]) - call_arg = xiaomi_mock.call_args[0][0] - assert call_arg['username'] == 'alternativeAdminName' - assert call_arg['password'] == 'passwordTest' - assert call_arg['host'] == '192.168.0.1' - assert call_arg['platform'] == 'device_tracker' +@patch('requests.get', side_effect=mocked_requests) +@patch('requests.post', side_effect=mocked_requests) +async def test_invalid_credential(mock_get, mock_post, hass): + """Testing invalid credential handling.""" + config = { + DOMAIN: xiaomi.PLATFORM_SCHEMA({ + CONF_PLATFORM: xiaomi.DOMAIN, + CONF_HOST: '192.168.0.1', + CONF_USERNAME: INVALID_USERNAME, + CONF_PASSWORD: 'passwordTest' + }) + } + assert get_scanner(hass, config) is None - @patch('requests.get', side_effect=mocked_requests) - @patch('requests.post', side_effect=mocked_requests) - def test_invalid_credential(self, mock_get, mock_post): - """Testing invalid credential handling.""" - config = { - DOMAIN: xiaomi.PLATFORM_SCHEMA({ - CONF_PLATFORM: xiaomi.DOMAIN, - CONF_HOST: '192.168.0.1', - CONF_USERNAME: INVALID_USERNAME, - CONF_PASSWORD: 'passwordTest' - }) - } - assert get_scanner(self.hass, config) is None - @patch('requests.get', side_effect=mocked_requests) - @patch('requests.post', side_effect=mocked_requests) - def test_valid_credential(self, mock_get, mock_post): - """Testing valid refresh.""" - config = { - DOMAIN: xiaomi.PLATFORM_SCHEMA({ - CONF_PLATFORM: xiaomi.DOMAIN, - CONF_HOST: '192.168.0.1', - CONF_USERNAME: 'admin', - CONF_PASSWORD: 'passwordTest' - }) - } - scanner = get_scanner(self.hass, config) - assert scanner is not None - assert 2 == len(scanner.scan_devices()) - assert "Device1" == \ - scanner.get_device_name("23:83:BF:F6:38:A0") - assert "Device2" == \ - scanner.get_device_name("1D:98:EC:5E:D5:A6") +@patch('requests.get', side_effect=mocked_requests) +@patch('requests.post', side_effect=mocked_requests) +async def test_valid_credential(mock_get, mock_post, hass): + """Testing valid refresh.""" + config = { + DOMAIN: xiaomi.PLATFORM_SCHEMA({ + CONF_PLATFORM: xiaomi.DOMAIN, + CONF_HOST: '192.168.0.1', + CONF_USERNAME: 'admin', + CONF_PASSWORD: 'passwordTest' + }) + } + scanner = get_scanner(hass, config) + assert scanner is not None + assert 2 == len(scanner.scan_devices()) + assert "Device1" == \ + scanner.get_device_name("23:83:BF:F6:38:A0") + assert "Device2" == \ + scanner.get_device_name("1D:98:EC:5E:D5:A6") - @patch('requests.get', side_effect=mocked_requests) - @patch('requests.post', side_effect=mocked_requests) - def test_token_timed_out(self, mock_get, mock_post): - """Testing refresh with a timed out token. - New token is requested and list is downloaded a second time. - """ - config = { - DOMAIN: xiaomi.PLATFORM_SCHEMA({ - CONF_PLATFORM: xiaomi.DOMAIN, - CONF_HOST: '192.168.0.1', - CONF_USERNAME: TOKEN_TIMEOUT_USERNAME, - CONF_PASSWORD: 'passwordTest' - }) - } - scanner = get_scanner(self.hass, config) - assert scanner is not None - assert 2 == len(scanner.scan_devices()) - assert "Device1" == \ - scanner.get_device_name("23:83:BF:F6:38:A0") - assert "Device2" == \ - scanner.get_device_name("1D:98:EC:5E:D5:A6") +@patch('requests.get', side_effect=mocked_requests) +@patch('requests.post', side_effect=mocked_requests) +async def test_token_timed_out(mock_get, mock_post, hass): + """Testing refresh with a timed out token. + + New token is requested and list is downloaded a second time. + """ + config = { + DOMAIN: xiaomi.PLATFORM_SCHEMA({ + CONF_PLATFORM: xiaomi.DOMAIN, + CONF_HOST: '192.168.0.1', + CONF_USERNAME: TOKEN_TIMEOUT_USERNAME, + CONF_PASSWORD: 'passwordTest' + }) + } + scanner = get_scanner(hass, config) + assert scanner is not None + assert 2 == len(scanner.scan_devices()) + assert "Device1" == \ + scanner.get_device_name("23:83:BF:F6:38:A0") + assert "Device2" == \ + scanner.get_device_name("1D:98:EC:5E:D5:A6")