From 45c548ae47ab9cfedb060e9bb1a7f8b01fbea1bc Mon Sep 17 00:00:00 2001 From: Jeff Irion Date: Thu, 26 Sep 2019 22:53:26 -0700 Subject: [PATCH] Bump androidtv to 0.0.28 (#26906) * Bump androidtv to 0.0.28 * Address reviewer comments * Remove adb-shell from requirements_test_all.txt * Use a one-liner to avoid a coverage failure --- .../components/androidtv/manifest.json | 3 +- .../components/androidtv/media_player.py | 32 +++++----- requirements_all.txt | 5 +- requirements_test_all.txt | 2 +- tests/components/androidtv/patchers.py | 63 ++++++++++--------- .../components/androidtv/test_media_player.py | 8 ++- 6 files changed, 61 insertions(+), 52 deletions(-) diff --git a/homeassistant/components/androidtv/manifest.json b/homeassistant/components/androidtv/manifest.json index 6643faa85bd..c085addad4d 100644 --- a/homeassistant/components/androidtv/manifest.json +++ b/homeassistant/components/androidtv/manifest.json @@ -3,7 +3,8 @@ "name": "Androidtv", "documentation": "https://www.home-assistant.io/components/androidtv", "requirements": [ - "androidtv==0.0.27" + "adb-shell==0.0.2", + "androidtv==0.0.28" ], "dependencies": [], "codeowners": ["@JeffLIrion"] diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index d68f47b1b0a..fcf4950f5e2 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -3,6 +3,12 @@ import functools import logging import voluptuous as vol +from adb_shell.exceptions import ( + InvalidChecksumError, + InvalidCommandError, + InvalidResponseError, + TcpTimeoutException, +) from androidtv import setup, ha_state_detection_rules_validator from androidtv.constants import APPS, KEYS @@ -123,11 +129,15 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Android TV / Fire TV platform.""" hass.data.setdefault(ANDROIDTV_DOMAIN, {}) - host = "{0}:{1}".format(config[CONF_HOST], config[CONF_PORT]) + host = f"{config[CONF_HOST]}:{config[CONF_PORT]}" if CONF_ADB_SERVER_IP not in config: - # Use "python-adb" (Python ADB implementation) - adb_log = "using Python ADB implementation " + # Use "adb_shell" (Python ADB implementation) + adb_log = "using Python ADB implementation " + ( + f"with adbkey='{config[CONF_ADBKEY]}'" + if CONF_ADBKEY in config + else "without adbkey authentication" + ) if CONF_ADBKEY in config: aftv = setup( host, @@ -135,7 +145,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None): device_class=config[CONF_DEVICE_CLASS], state_detection_rules=config[CONF_STATE_DETECTION_RULES], ) - adb_log += "with adbkey='{0}'".format(config[CONF_ADBKEY]) else: aftv = setup( @@ -143,7 +152,6 @@ def setup_platform(hass, config, add_entities, discovery_info=None): device_class=config[CONF_DEVICE_CLASS], state_detection_rules=config[CONF_STATE_DETECTION_RULES], ) - adb_log += "without adbkey authentication" else: # Use "pure-python-adb" (communicate with ADB server) aftv = setup( @@ -153,9 +161,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): device_class=config[CONF_DEVICE_CLASS], state_detection_rules=config[CONF_STATE_DETECTION_RULES], ) - adb_log = "using ADB server at {0}:{1}".format( - config[CONF_ADB_SERVER_IP], config[CONF_ADB_SERVER_PORT] - ) + adb_log = f"using ADB server at {config[CONF_ADB_SERVER_IP]}:{config[CONF_ADB_SERVER_PORT]}" if not aftv.available: # Determine the name that will be used for the device in the log @@ -251,6 +257,7 @@ def adb_decorator(override_available=False): "establishing attempt in the next update. Error: %s", err, ) + self.aftv.adb.close() self._available = False # pylint: disable=protected-access return None @@ -278,14 +285,7 @@ class ADBDevice(MediaPlayerDevice): # ADB exceptions to catch if not self.aftv.adb_server_ip: - # Using "python-adb" (Python ADB implementation) - from adb.adb_protocol import ( - InvalidChecksumError, - InvalidCommandError, - InvalidResponseError, - ) - from adb.usb_exceptions import TcpTimeoutException - + # Using "adb_shell" (Python ADB implementation) self.exceptions = ( AttributeError, BrokenPipeError, diff --git a/requirements_all.txt b/requirements_all.txt index 19bdc4efd83..a9ec02ffcc6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -111,6 +111,9 @@ adafruit-blinka==1.2.1 # homeassistant.components.mcp23017 adafruit-circuitpython-mcp230xx==1.1.2 +# homeassistant.components.androidtv +adb-shell==0.0.2 + # homeassistant.components.adguard adguardhome==0.2.1 @@ -197,7 +200,7 @@ ambiclimate==0.2.1 amcrest==1.5.3 # homeassistant.components.androidtv -androidtv==0.0.27 +androidtv==0.0.28 # homeassistant.components.anel_pwrctrl anel_pwrctrl-homeassistant==0.0.1.dev2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3a4fa60f15e..c3f40e16349 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -80,7 +80,7 @@ aiowwlln==2.0.2 ambiclimate==0.2.1 # homeassistant.components.androidtv -androidtv==0.0.27 +androidtv==0.0.28 # homeassistant.components.apns apns2==0.3.0 diff --git a/tests/components/androidtv/patchers.py b/tests/components/androidtv/patchers.py index 86d1c1c15bd..73aa5225989 100644 --- a/tests/components/androidtv/patchers.py +++ b/tests/components/androidtv/patchers.py @@ -4,34 +4,24 @@ from socket import error as socket_error from unittest.mock import patch -class AdbCommandsFake: - """A fake of the `adb.adb_commands.AdbCommands` class.""" +class AdbDeviceFake: + """A fake of the `adb_shell.adb_device.AdbDevice` class.""" - def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name + def __init__(self, *args, **kwargs): + """Initialize a fake `adb_shell.adb_device.AdbDevice` instance.""" + self.available = False + + def close(self): + """Close the socket connection.""" + self.available = False + + def connect(self, *args, **kwargs): """Try to connect to a device.""" raise NotImplementedError - def Shell(self, cmd): # pylint: disable=invalid-name + def shell(self, cmd): """Send an ADB shell command.""" - raise NotImplementedError - - -class AdbCommandsFakeSuccess(AdbCommandsFake): - """A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt succeeds.""" - - def ConnectDevice(self, *args, **kwargs): # pylint: disable=invalid-name - """Successfully connect to a device.""" - return self - - -class AdbCommandsFakeFail(AdbCommandsFake): - """A fake of the `adb.adb_commands.AdbCommands` class when the connection attempt fails.""" - - def ConnectDevice( - self, *args, **kwargs - ): # pylint: disable=invalid-name, no-self-use - """Fail to connect to a device.""" - raise socket_error + return None class ClientFakeSuccess: @@ -85,31 +75,39 @@ class DeviceFake: def patch_connect(success): - """Mock the `adb.adb_commands.AdbCommands` and `adb_messenger.client.Client` classes.""" + """Mock the `adb_shell.adb_device.AdbDevice` and `adb_messenger.client.Client` classes.""" + + def connect_success_python(self, *args, **kwargs): + """Mock the `AdbDeviceFake.connect` method when it succeeds.""" + self.available = True + + def connect_fail_python(self, *args, **kwargs): + """Mock the `AdbDeviceFake.connect` method when it fails.""" + raise socket_error if success: return { "python": patch( - "androidtv.adb_manager.AdbCommands", AdbCommandsFakeSuccess + f"{__name__}.AdbDeviceFake.connect", connect_success_python ), "server": patch("androidtv.adb_manager.Client", ClientFakeSuccess), } return { - "python": patch("androidtv.adb_manager.AdbCommands", AdbCommandsFakeFail), + "python": patch(f"{__name__}.AdbDeviceFake.connect", connect_fail_python), "server": patch("androidtv.adb_manager.Client", ClientFakeFail), } def patch_shell(response=None, error=False): - """Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods.""" + """Mock the `AdbDeviceFake.shell` and `DeviceFake.shell` methods.""" def shell_success(self, cmd): - """Mock the `AdbCommandsFake.Shell` and `DeviceFake.shell` methods when they are successful.""" + """Mock the `AdbDeviceFake.shell` and `DeviceFake.shell` methods when they are successful.""" self.shell_cmd = cmd return response def shell_fail_python(self, cmd): - """Mock the `AdbCommandsFake.Shell` method when it fails.""" + """Mock the `AdbDeviceFake.shell` method when it fails.""" self.shell_cmd = cmd raise AttributeError @@ -120,10 +118,13 @@ def patch_shell(response=None, error=False): if not error: return { - "python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_success), + "python": patch(f"{__name__}.AdbDeviceFake.shell", shell_success), "server": patch(f"{__name__}.DeviceFake.shell", shell_success), } return { - "python": patch(f"{__name__}.AdbCommandsFake.Shell", shell_fail_python), + "python": patch(f"{__name__}.AdbDeviceFake.shell", shell_fail_python), "server": patch(f"{__name__}.DeviceFake.shell", shell_fail_server), } + + +PATCH_ADB_DEVICE = patch("androidtv.adb_manager.AdbDevice", AdbDeviceFake) diff --git a/tests/components/androidtv/test_media_player.py b/tests/components/androidtv/test_media_player.py index 39b392c97ee..feffc70d841 100644 --- a/tests/components/androidtv/test_media_player.py +++ b/tests/components/androidtv/test_media_player.py @@ -79,7 +79,9 @@ async def _test_reconnect(hass, caplog, config): else: entity_id = "media_player.fire_tv" - with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]: + with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[ + patch_key + ], patchers.patch_shell("")[patch_key]: assert await async_setup_component(hass, DOMAIN, config) await hass.helpers.entity_component.async_update_entity(entity_id) state = hass.states.get(entity_id) @@ -151,7 +153,9 @@ async def _test_adb_shell_returns_none(hass, config): else: entity_id = "media_player.fire_tv" - with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]: + with patchers.PATCH_ADB_DEVICE, patchers.patch_connect(True)[ + patch_key + ], patchers.patch_shell("")[patch_key]: assert await async_setup_component(hass, DOMAIN, config) await hass.helpers.entity_component.async_update_entity(entity_id) state = hass.states.get(entity_id)