Example #1
0
async def _test_reconnect(hass, caplog, config):
    """Test that the error and reconnection attempts are logged correctly.

    "Handles device/service unavailable. Log a warning once when
    unavailable, log once when reconnected."

    https://developers.home-assistant.io/docs/en/integration_quality_scale_index.html
    """
    patch_key, entity_id, config_entry = _setup(config)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(
            True
    )[patch_key], patchers.patch_shell(
            SHELL_RESPONSE_OFF
    )[patch_key], patchers.PATCH_KEYGEN, patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        assert await hass.config_entries.async_setup(config_entry.entry_id)
        # assert await async_setup_component(hass, DOMAIN, config)
        await hass.async_block_till_done()

        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF

    caplog.clear()
    caplog.set_level(logging.WARNING)

    with patchers.patch_connect(False)[patch_key], patchers.patch_shell(
            error=True
    )[patch_key], patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        for _ in range(5):
            await hass.helpers.entity_component.async_update_entity(entity_id)
            state = hass.states.get(entity_id)
            assert state is not None
            assert state.state == STATE_UNAVAILABLE

    assert len(caplog.record_tuples) == 2
    assert caplog.record_tuples[0][1] == logging.ERROR
    assert caplog.record_tuples[1][1] == logging.WARNING

    caplog.set_level(logging.DEBUG)
    with patchers.patch_connect(True)[patch_key], patchers.patch_shell(
            SHELL_RESPONSE_STANDBY
    )[patch_key], patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        await hass.helpers.entity_component.async_update_entity(entity_id)

        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_STANDBY

    if patch_key == "python":
        assert ("ADB connection to 127.0.0.1:5555 successfully established"
                in caplog.record_tuples[2])
    else:
        assert (
            "ADB connection to 127.0.0.1:5555 via ADB server 127.0.0.1:5037 successfully established"
            in caplog.record_tuples[2])

    return True
async def test_adb_command_key(hass):
    """Test sending a key command via the `androidtv.adb_command` service."""
    patch_key = "server"
    entity_id = "media_player.android_tv"
    command = "HOME"
    response = None

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    with patch(
        "androidtv.basetv.basetv_async.BaseTVAsync.adb_shell", return_value=response
    ) as patch_shell:
        await hass.services.async_call(
            ANDROIDTV_DOMAIN,
            SERVICE_ADB_COMMAND,
            {ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
            blocking=True,
        )

        patch_shell.assert_called_with(f"input keyevent {KEYS[command]}")
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.attributes["adb_response"] is None
async def test_adb_command_get_properties(hass):
    """Test sending the "GET_PROPERTIES" command via the `androidtv.adb_command` service."""
    patch_key = "server"
    entity_id = "media_player.android_tv"
    command = "GET_PROPERTIES"
    response = {"test key": "test value"}

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    with patch(
        "androidtv.androidtv.androidtv_async.AndroidTVAsync.get_properties_dict",
        return_value=response,
    ) as patch_get_props:
        await hass.services.async_call(
            ANDROIDTV_DOMAIN,
            SERVICE_ADB_COMMAND,
            {ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
            blocking=True,
        )

        patch_get_props.assert_called()
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.attributes["adb_response"] == str(response)
Example #4
0
async def test_learn_sendevent(hass):
    """Test the `androidtv.learn_sendevent` service."""
    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    config_entry.add_to_hass(hass)
    response = "sendevent 1 2 3 4"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
            patch_key], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        with patchers.PATCH_DEVICE_PROPERTIES:
            assert await hass.config_entries.async_setup(config_entry.entry_id)
            await hass.async_block_till_done()

        with patch(
                "androidtv.basetv.basetv_async.BaseTVAsync.learn_sendevent",
                return_value=response,
        ) as patch_learn_sendevent:
            await hass.services.async_call(
                DOMAIN,
                SERVICE_LEARN_SENDEVENT,
                {ATTR_ENTITY_ID: entity_id},
                blocking=True,
            )

            patch_learn_sendevent.assert_called()
            state = hass.states.get(entity_id)
            assert state is not None
            assert state.attributes["adb_response"] == response
async def test_learn_sendevent(hass):
    """Test the `androidtv.learn_sendevent` service."""
    patch_key = "server"
    entity_id = "media_player.android_tv"
    response = "sendevent 1 2 3 4"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

        with patch(
            "androidtv.basetv.basetv_async.BaseTVAsync.learn_sendevent",
            return_value=response,
        ) as patch_learn_sendevent:
            await hass.services.async_call(
                ANDROIDTV_DOMAIN,
                SERVICE_LEARN_SENDEVENT,
                {ATTR_ENTITY_ID: entity_id},
                blocking=True,
            )

            patch_learn_sendevent.assert_called()
            state = hass.states.get(entity_id)
            assert state is not None
            assert state.attributes["adb_response"] == response
async def test_adb_command_unicode_decode_error(hass):
    """Test sending a command via the `androidtv.adb_command` service that raises a UnicodeDecodeError exception."""
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    command = "test command"
    response = b"test response"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    with patch(
        "androidtv.basetv.basetv_async.BaseTVAsync.adb_shell",
        side_effect=UnicodeDecodeError("utf-8", response, 0, len(response), "TEST"),
    ):
        await hass.services.async_call(
            ANDROIDTV_DOMAIN,
            SERVICE_ADB_COMMAND,
            {ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
            blocking=True,
        )

        # patch_shell.assert_called_with(command)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.attributes["adb_response"] is None
async def _test_select_source(hass, config0, source, expected_arg, method_patch):
    """Test that the methods for launching and stopping apps are called correctly when selecting a source."""
    config = config0.copy()
    config[DOMAIN][CONF_APPS] = {"com.app.test1": "TEST 1", "com.app.test3": None}
    patch_key, entity_id = _setup(config)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, config)
        await hass.async_block_till_done()
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF

    with method_patch as method_patch_:
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SELECT_SOURCE,
            {ATTR_ENTITY_ID: entity_id, ATTR_INPUT_SOURCE: source},
            blocking=True,
        )
        method_patch_.assert_called_with(expected_arg)

    return True
async def test_update_lock_not_acquired(hass):
    """Test that the state does not get updated when a `LockNotAcquiredException` is raised."""
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    with patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF

    with patch(
        "androidtv.androidtv.androidtv_async.AndroidTVAsync.update",
        side_effect=LockNotAcquiredException,
    ):
        with patchers.patch_shell(SHELL_RESPONSE_STANDBY)[patch_key]:
            await hass.helpers.entity_component.async_update_entity(entity_id)
            state = hass.states.get(entity_id)
            assert state is not None
            assert state.state == STATE_OFF

    with patchers.patch_shell(SHELL_RESPONSE_STANDBY)[patch_key]:
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_STANDBY
async def _test_adb_shell_returns_none(hass, config):
    """Test the case that the ADB shell command returns `None`.

    The state should be `None` and the device should be unavailable.
    """
    patch_key, entity_id = _setup(config)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[
        patch_key
    ], patchers.PATCH_KEYGEN, patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        assert await async_setup_component(hass, DOMAIN, config)
        await hass.async_block_till_done()
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state != STATE_UNAVAILABLE

    with patchers.patch_shell(None)[patch_key], patchers.patch_shell(error=True)[
        patch_key
    ], patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_UNAVAILABLE

    return True
Example #10
0
async def test_get_image(hass, hass_ws_client):
    """Test taking a screen capture.

    This is based on `test_get_image` in tests/components/media_player/test_init.py.
    """
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    with patchers.patch_shell("11")[patch_key]:
        await hass.helpers.entity_component.async_update_entity(entity_id)

    client = await hass_ws_client(hass)

    with patch(
        "androidtv.basetv.basetv_async.BaseTVAsync.adb_screencap", return_value=b"image"
    ):
        await client.send_json(
            {"id": 5, "type": "media_player_thumbnail", "entity_id": entity_id}
        )

        msg = await client.receive_json()

    assert msg["id"] == 5
    assert msg["type"] == TYPE_RESULT
    assert msg["success"]
    assert msg["result"]["content_type"] == "image/png"
    assert msg["result"]["content"] == base64.b64encode(b"image").decode("utf-8")
Example #11
0
async def test_adb_command(hass):
    """Test sending a command via the `androidtv.adb_command` service."""
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    command = "test command"
    response = "test response"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    with patch(
        "androidtv.basetv.basetv_async.BaseTVAsync.adb_shell", return_value=response
    ) as patch_shell:
        await hass.services.async_call(
            ANDROIDTV_DOMAIN,
            SERVICE_ADB_COMMAND,
            {ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
            blocking=True,
        )

        patch_shell.assert_called_with(command)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.attributes["adb_response"] == response
Example #12
0
async def test_exception(hass):
    """Test that the ADB connection gets closed when there is an unforeseen exception.

    HA will attempt to reconnect on the next update.
    """
    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_PYTHON_ADB)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(
            True
    )[patch_key], patchers.patch_shell(
            SHELL_RESPONSE_OFF
    )[patch_key], patchers.PATCH_KEYGEN, patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        assert await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF

        # When an unforeseen exception occurs, we close the ADB connection and raise the exception
        with patchers.PATCH_ANDROIDTV_UPDATE_EXCEPTION, pytest.raises(
                Exception):
            await hass.helpers.entity_component.async_update_entity(entity_id)
            state = hass.states.get(entity_id)
            assert state is not None
            assert state.state == STATE_UNAVAILABLE

        # On the next update, HA will reconnect to the device
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF
Example #13
0
async def _test_exclude_sources(opp, config0, expected_sources):
    """Test that sources (i.e., apps) are handled correctly when the `exclude_unnamed_apps` config parameter is provided."""
    config = copy.deepcopy(config0)
    config[DOMAIN][CONF_APPS] = {
        "com.app.test1": "TEST 1",
        "com.app.test3": None,
        "com.app.test4": SHELL_RESPONSE_OFF,
    }
    patch_key, entity_id = _setup(config)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(opp, DOMAIN, config)
        await opp.async_block_till_done()
        await opp.helpers.entity_component.async_update_entity(entity_id)
        state = opp.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF

    if config[DOMAIN].get(CONF_DEVICE_CLASS) != "firetv":
        patch_update = patchers.patch_androidtv_update(
            "playing",
            "com.app.test1",
            [
                "com.app.test1",
                "com.app.test2",
                "com.app.test3",
                "com.app.test4",
                "com.app.test5",
            ],
            "hdmi",
            False,
            1,
            "HW5",
        )
    else:
        patch_update = patchers.patch_firetv_update(
            "playing",
            "com.app.test1",
            [
                "com.app.test1",
                "com.app.test2",
                "com.app.test3",
                "com.app.test4",
                "com.app.test5",
            ],
            "HW5",
        )

    with patch_update:
        await opp.helpers.entity_component.async_update_entity(entity_id)
        state = opp.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_PLAYING
        assert state.attributes["source"] == "TEST 1"
        assert sorted(state.attributes["source_list"]) == expected_sources

    return True
Example #14
0
async def test_setup_same_device_twice(hass):
    """Test that setup succeeds with a duplicated config entry."""
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()
        state = hass.states.get(entity_id)
        assert state is not None

    assert hass.services.has_service(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()
Example #15
0
async def test_get_image(hass, hass_ws_client):
    """Test taking a screen capture.

    This is based on `test_get_image` in tests/components/media_player/test_init.py.
    """
    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
            patch_key], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        with patchers.PATCH_DEVICE_PROPERTIES:
            assert await hass.config_entries.async_setup(config_entry.entry_id)
            await hass.async_block_till_done()

    with patchers.patch_shell("11")[patch_key]:
        await hass.helpers.entity_component.async_update_entity(entity_id)

    client = await hass_ws_client(hass)

    with patch("androidtv.basetv.basetv_async.BaseTVAsync.adb_screencap",
               return_value=b"image"):
        await client.send_json({
            "id": 5,
            "type": "media_player_thumbnail",
            "entity_id": entity_id
        })

        msg = await client.receive_json()

    assert msg["id"] == 5
    assert msg["type"] == TYPE_RESULT
    assert msg["success"]
    assert msg["result"]["content_type"] == "image/png"
    assert msg["result"]["content"] == base64.b64encode(b"image").decode(
        "utf-8")

    with patch(
            "androidtv.basetv.basetv_async.BaseTVAsync.adb_screencap",
            side_effect=RuntimeError,
    ):
        await client.send_json({
            "id": 6,
            "type": "media_player_thumbnail",
            "entity_id": entity_id
        })

        msg = await client.receive_json()

        # The device is unavailable, but getting the media image did not cause an exception
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_UNAVAILABLE
Example #16
0
async def test_services_androidtv(hass):
    """Test media player services for an Android TV device."""
    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(
            True)[patch_key]:
        with patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
            assert await hass.config_entries.async_setup(config_entry.entry_id)
            await hass.async_block_till_done()

        with patchers.patch_shell(SHELL_RESPONSE_STANDBY)[patch_key]:
            await _test_service(hass, entity_id, SERVICE_MEDIA_NEXT_TRACK,
                                "media_next_track")
            await _test_service(hass, entity_id, SERVICE_MEDIA_PAUSE,
                                "media_pause")
            await _test_service(hass, entity_id, SERVICE_MEDIA_PLAY,
                                "media_play")
            await _test_service(hass, entity_id, SERVICE_MEDIA_PLAY_PAUSE,
                                "media_play_pause")
            await _test_service(hass, entity_id, SERVICE_MEDIA_PREVIOUS_TRACK,
                                "media_previous_track")
            await _test_service(hass, entity_id, SERVICE_MEDIA_STOP,
                                "media_stop")
            await _test_service(hass, entity_id, SERVICE_TURN_OFF, "turn_off")
            await _test_service(hass, entity_id, SERVICE_TURN_ON, "turn_on")
            await _test_service(hass,
                                entity_id,
                                SERVICE_VOLUME_DOWN,
                                "volume_down",
                                return_value=0.1)
            await _test_service(
                hass,
                entity_id,
                SERVICE_VOLUME_MUTE,
                "mute_volume",
                {ATTR_MEDIA_VOLUME_MUTED: False},
            )
            await _test_service(
                hass,
                entity_id,
                SERVICE_VOLUME_SET,
                "set_volume_level",
                {ATTR_MEDIA_VOLUME_LEVEL: 0.5},
                0.5,
            )
            await _test_service(hass,
                                entity_id,
                                SERVICE_VOLUME_UP,
                                "volume_up",
                                return_value=0.2)
Example #17
0
async def test_services_firetv(hass):
    """Test media player services for a Fire TV device."""
    patch_key, entity_id = _setup(CONFIG_FIRETV_ADB_SERVER)
    config = CONFIG_FIRETV_ADB_SERVER.copy()
    config[DOMAIN][CONF_TURN_OFF_COMMAND] = "test off"
    config[DOMAIN][CONF_TURN_ON_COMMAND] = "test on"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[patch_key]:
        with patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
            assert await async_setup_component(hass, DOMAIN, config)
            await hass.async_block_till_done()

        with patchers.patch_shell(SHELL_RESPONSE_STANDBY)[patch_key]:
            await _test_service(hass, entity_id, SERVICE_MEDIA_STOP, "back")
            await _test_service(hass, entity_id, SERVICE_TURN_OFF, "adb_shell")
            await _test_service(hass, entity_id, SERVICE_TURN_ON, "adb_shell")
Example #18
0
async def test_connection_closed_on_ha_stop(hass):
    """Test that the ADB socket connection is closed when HA stops."""
    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
            patch_key], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        with patch(
                "androidtv.androidtv.androidtv_async.AndroidTVAsync.adb_close"
        ) as adb_close:
            hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
            await hass.async_block_till_done()
            assert adb_close.called
Example #19
0
async def _test_setup_fail(hass, config):
    """Test that the entity is not created when the ADB connection is not established."""
    patch_key, entity_id = _setup(config)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(False)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[
        patch_key
    ], patchers.PATCH_KEYGEN, patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        assert await async_setup_component(hass, DOMAIN, config)
        await hass.async_block_till_done()
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is None

    return True
Example #20
0
async def test_connection_closed_on_op_stop(opp):
    """Test that the ADB socket connection is closed when OPP stops."""
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(opp, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await opp.async_block_till_done()

        with patch(
            "androidtv.androidtv.androidtv_async.AndroidTVAsync.adb_close"
        ) as adb_close:
            opp.bus.async_fire(EVENT_OPENPEERPOWER_STOP)
            await opp.async_block_till_done()
            assert adb_close.called
Example #21
0
async def test_volume_mute(hass):
    """Test the volume mute service."""
    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(
            True)[patch_key]:
        with patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
            with patchers.PATCH_DEVICE_PROPERTIES:
                assert await hass.config_entries.async_setup(
                    config_entry.entry_id)
                await hass.async_block_till_done()

        with patchers.patch_shell(SHELL_RESPONSE_STANDBY)[patch_key]:
            service_data = {
                ATTR_ENTITY_ID: entity_id,
                ATTR_MEDIA_VOLUME_MUTED: True
            }
            with patch(
                    "androidtv.androidtv.androidtv_async.AndroidTVAsync.mute_volume",
                    return_value=None,
            ) as mute_volume:
                # Don't send the mute key if the volume is already muted
                with patch(
                        "androidtv.androidtv.androidtv_async.AndroidTVAsync.is_volume_muted",
                        return_value=True,
                ):
                    await hass.services.async_call(
                        MP_DOMAIN,
                        SERVICE_VOLUME_MUTE,
                        service_data=service_data,
                        blocking=True,
                    )
                    assert not mute_volume.called

                # Send the mute key because the volume is not already muted
                with patch(
                        "androidtv.androidtv.androidtv_async.AndroidTVAsync.is_volume_muted",
                        return_value=False,
                ):
                    await hass.services.async_call(
                        MP_DOMAIN,
                        SERVICE_VOLUME_MUTE,
                        service_data=service_data,
                        blocking=True,
                    )
                    assert mute_volume.called
Example #22
0
async def test_setup_with_adbkey(hass):
    """Test that setup succeeds when using an ADB key."""
    config = CONFIG_ANDROIDTV_PYTHON_ADB.copy()
    config[DOMAIN][CONF_ADBKEY] = hass.config.path("user_provided_adbkey")
    patch_key, entity_id = _setup(config)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[
        patch_key
    ], patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER, patchers.PATCH_ISFILE, patchers.PATCH_ACCESS:
        assert await async_setup_component(hass, DOMAIN, config)
        await hass.async_block_till_done()
        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF
Example #23
0
async def test_setup_fail(hass, config):
    """Test that the entity is not created when the ADB connection is not established."""
    patch_key, entity_id, config_entry = _setup(config)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(
            False
    )[patch_key], patchers.patch_shell(
            SHELL_RESPONSE_OFF
    )[patch_key], patchers.PATCH_KEYGEN, patchers.PATCH_ANDROIDTV_OPEN, patchers.PATCH_SIGNER:
        assert await hass.config_entries.async_setup(config_entry.entry_id
                                                     ) is False
        await hass.async_block_till_done()

        await async_update_entity(hass, entity_id)
        state = hass.states.get(entity_id)
        assert state is None
Example #24
0
async def test_setup_with_properties(hass):
    """Test that setup succeeds with device properties.

    the response must be a string with the following info separated with line break:
    "manufacturer, model, serialno, version, mac_wlan0_output, mac_eth0_output"

    """

    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    config_entry.add_to_hass(hass)
    response = "fake\nfake\n0123456\nfake\nether a1:b1:c1:d1:e1:f1 brd\nnone"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(
            True)[patch_key], patchers.patch_shell(response)[patch_key]:
        assert await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()
        state = hass.states.get(entity_id)
        assert state is not None
Example #25
0
async def test_upload(hass):
    """Test the `androidtv.upload` service."""
    patch_key, entity_id, config_entry = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    config_entry.add_to_hass(hass)
    device_path = "device/path"
    local_path = "local/path"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
            patch_key], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        with patchers.PATCH_DEVICE_PROPERTIES:
            assert await hass.config_entries.async_setup(config_entry.entry_id)
            await hass.async_block_till_done()

        # Failed upload because path is not whitelisted
        with patch("androidtv.basetv.basetv_async.BaseTVAsync.adb_push"
                   ) as patch_push:
            await hass.services.async_call(
                DOMAIN,
                SERVICE_UPLOAD,
                {
                    ATTR_ENTITY_ID: entity_id,
                    ATTR_DEVICE_PATH: device_path,
                    ATTR_LOCAL_PATH: local_path,
                },
                blocking=True,
            )
            patch_push.assert_not_called()

        # Successful upload
        with patch("androidtv.basetv.basetv_async.BaseTVAsync.adb_push"
                   ) as patch_push, patch.object(hass.config,
                                                 "is_allowed_path",
                                                 return_value=True):
            await hass.services.async_call(
                DOMAIN,
                SERVICE_UPLOAD,
                {
                    ATTR_ENTITY_ID: entity_id,
                    ATTR_DEVICE_PATH: device_path,
                    ATTR_LOCAL_PATH: local_path,
                },
                blocking=True,
            )
            patch_push.assert_called_with(local_path, device_path)
Example #26
0
async def test_download(hass):
    """Test the `androidtv.download` service."""
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)
    device_path = "device/path"
    local_path = "local/path"

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
            patch_key], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN,
                                           CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    # Failed download because path is not whitelisted
    with patch("androidtv.basetv.basetv_async.BaseTVAsync.adb_pull"
               ) as patch_pull:
        await hass.services.async_call(
            ANDROIDTV_DOMAIN,
            SERVICE_DOWNLOAD,
            {
                ATTR_ENTITY_ID: entity_id,
                ATTR_DEVICE_PATH: device_path,
                ATTR_LOCAL_PATH: local_path,
            },
            blocking=True,
        )
        patch_pull.assert_not_called()

    # Successful download
    with patch("androidtv.basetv.basetv_async.BaseTVAsync.adb_pull"
               ) as patch_pull, patch.object(hass.config,
                                             "is_allowed_path",
                                             return_value=True):
        await hass.services.async_call(
            ANDROIDTV_DOMAIN,
            SERVICE_DOWNLOAD,
            {
                ATTR_ENTITY_ID: entity_id,
                ATTR_DEVICE_PATH: device_path,
                ATTR_LOCAL_PATH: local_path,
            },
            blocking=True,
        )
        patch_pull.assert_called_with(local_path, device_path)
Example #27
0
async def test_services_firetv(hass):
    """Test media player services for a Fire TV device."""
    config = copy.deepcopy(CONFIG_FIRETV_ADB_SERVER)
    config[DOMAIN][CONF_OPTIONS] = {
        CONF_TURN_OFF_COMMAND: "test off",
        CONF_TURN_ON_COMMAND: "test on",
    }
    patch_key, entity_id, config_entry = _setup(config)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(
            True)[patch_key]:
        with patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
            assert await hass.config_entries.async_setup(config_entry.entry_id)
            await hass.async_block_till_done()

        with patchers.patch_shell(SHELL_RESPONSE_STANDBY)[patch_key]:
            await _test_service(hass, entity_id, SERVICE_MEDIA_STOP, "back")
            await _test_service(hass, entity_id, SERVICE_TURN_OFF, "adb_shell")
            await _test_service(hass, entity_id, SERVICE_TURN_ON, "adb_shell")
Example #28
0
async def test_setup_two_devices(hass):
    """Test that two devices can be set up."""
    config = {
        DOMAIN: [
            CONFIG_ANDROIDTV_ADB_SERVER[DOMAIN],
            copy.deepcopy(CONFIG_FIRETV_ADB_SERVER[DOMAIN]),
        ]
    }
    config[DOMAIN][1][CONF_HOST] = "127.0.0.2"

    patch_key = "server"
    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
            patch_key], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, config)
        await hass.async_block_till_done()

        for entity_id in ["media_player.android_tv", "media_player.fire_tv"]:
            await hass.helpers.entity_component.async_update_entity(entity_id)
            state = hass.states.get(entity_id)
            assert state is not None
            assert state.state == STATE_OFF
Example #29
0
async def test_androidtv_volume_set(hass):
    """Test setting the volume for an Android TV device."""
    patch_key, entity_id = _setup(CONFIG_ANDROIDTV_ADB_SERVER)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
        patch_key
    ], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        assert await async_setup_component(hass, DOMAIN, CONFIG_ANDROIDTV_ADB_SERVER)
        await hass.async_block_till_done()

    with patch(
        "androidtv.basetv.basetv_async.BaseTVAsync.set_volume_level", return_value=0.5
    ) as patch_set_volume_level:
        await hass.services.async_call(
            DOMAIN,
            SERVICE_VOLUME_SET,
            {ATTR_ENTITY_ID: entity_id, ATTR_MEDIA_VOLUME_LEVEL: 0.5},
            blocking=True,
        )

        patch_set_volume_level.assert_called_with(0.5)
Example #30
0
async def _test_select_source(hass, config0, source, expected_arg,
                              method_patch):
    """Test that the methods for launching and stopping apps are called correctly when selecting a source."""
    config = copy.deepcopy(config0)
    config[DOMAIN].setdefault(CONF_OPTIONS, {}).update({
        CONF_APPS: {
            "com.app.test1": "TEST 1",
            "com.app.test3": None,
            "com.youtube.test": "YouTube",
        }
    })
    patch_key, entity_id, config_entry = _setup(config)
    config_entry.add_to_hass(hass)

    with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
            patch_key], patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key]:
        with patchers.PATCH_DEVICE_PROPERTIES:
            assert await hass.config_entries.async_setup(config_entry.entry_id)
            await hass.async_block_till_done()

        await hass.helpers.entity_component.async_update_entity(entity_id)
        state = hass.states.get(entity_id)
        assert state is not None
        assert state.state == STATE_OFF

    with method_patch as method_patch_:
        await hass.services.async_call(
            MP_DOMAIN,
            SERVICE_SELECT_SOURCE,
            {
                ATTR_ENTITY_ID: entity_id,
                ATTR_INPUT_SOURCE: source
            },
            blocking=True,
        )
        method_patch_.assert_called_with(expected_arg)

    return True