async def test_disconnected(hass, caplog):
    """Test disconnected behavior."""
    mocked_device = _create_mocked_device()
    entry = MockConfigEntry(domain=songpal.DOMAIN, data=CONF_DATA)
    entry.add_to_hass(hass)

    with _patch_media_player_device(mocked_device):
        await hass.config_entries.async_setup(entry.entry_id)
        await hass.async_block_till_done()

    async def _assert_state():
        state = hass.states.get(ENTITY_ID)
        assert state.state == STATE_UNAVAILABLE

    connect_change = MagicMock()
    connect_change.exception = "disconnected"
    type(mocked_device).get_supported_methods = AsyncMock(side_effect=[
        SongpalException(""),
        SongpalException(""), _assert_state
    ])
    notification_callbacks = mocked_device.notification_callbacks
    with patch(
            "homeassistant.components.songpal.media_player.INITIAL_RETRY_DELAY",
            0):
        await notification_callbacks[ConnectChange](connect_change)
    warning_records = [
        x for x in caplog.records if x.levelno == logging.WARNING
    ]
    assert len(warning_records) == 2
    assert warning_records[0].message.endswith(
        "Got disconnected, trying to reconnect")
    assert warning_records[1].message.endswith("Connection reestablished")
    assert not any(x.levelno == logging.ERROR for x in caplog.records)
Пример #2
0
    async def __call__(self, *args, **kwargs):
        """Call the method with given parameters.

        On error this call will raise a :class:SongpalException:. If the error is
        reported by the device (e.g. not a problem doing the request), the exception
        will contain `error` attribute containing the device-reported error message.
        """
        try:
            res = await self.service.call_method(self, *args, **kwargs)
        except Exception as ex:
            raise SongpalException("Unable to make a request: %s" % ex) from ex

        if self.debug > 1:
            _LOGGER.debug("got payload: %s" % res)

        if "error" in res:
            _LOGGER.debug(self)
            raise SongpalException(
                "Got an error for %s: %s" % (self.name, res["error"]),
                error=res["error"],
            )

        if self.debug > 0:
            _LOGGER.debug("got res: %s" % pf(res))

        if "result" not in res:
            _LOGGER.error("No result in response, how to handle? %s" % res)
            return

        res = res["result"]
        if len(res) > 1:
            _LOGGER.warning("Got a response with len >  1: %s" % res)
            return res
        elif len(res) < 1:
            _LOGGER.debug("Got no response, assuming success")
            return True

        return res[0]
Пример #3
0
    def parse_json_types(x) -> Union[type, str, Dict[str, type]]:
        """Parse JSON signature. Used to parse input and output parameters."""
        try:
            if x.endswith("*"):  # TODO handle arrays properly
                # _LOGGER.debug("got an array %s: %s" % (self.name, x))
                x = x.rstrip("*")

            obj = json.loads(x)
            obj = {x: MethodSignature.return_type(obj[x]) for x in obj}
        except json.JSONDecodeError as ex:
            try:
                return MethodSignature.return_type(x)
            except Exception:
                raise SongpalException("Unknown return type: %s" % x) from ex

        return obj
Пример #4
0
def _create_mocked_device(throw_exception=False):
    mocked_device = MagicMock()

    type(mocked_device).get_supported_methods = AsyncMock(
        side_effect=SongpalException("Unable to do POST request: "
                                     ) if throw_exception else None)

    interface_info = MagicMock()
    interface_info.modelName = MODEL
    type(mocked_device).get_interface_information = AsyncMock(
        return_value=interface_info)

    sys_info = MagicMock()
    sys_info.macAddr = MAC
    sys_info.version = SW_VERSION
    type(mocked_device).get_system_info = AsyncMock(return_value=sys_info)

    volume1 = MagicMock()
    volume1.maxVolume = 100
    volume1.minVolume = 0
    volume1.volume = 50
    volume1.is_muted = False
    volume1.set_volume = AsyncMock()
    volume1.set_mute = AsyncMock()
    volume2 = MagicMock()
    volume2.maxVolume = 100
    volume2.minVolume = 0
    volume2.volume = 20
    volume2.is_muted = True
    mocked_device.volume1 = volume1
    type(mocked_device).get_volume_information = AsyncMock(
        return_value=[volume1, volume2])

    power = MagicMock()
    power.status = True
    type(mocked_device).get_power = AsyncMock(return_value=power)

    input1 = MagicMock()
    input1.title = "title1"
    input1.uri = "uri1"
    input1.active = False
    input1.activate = AsyncMock()
    mocked_device.input1 = input1
    input2 = MagicMock()
    input2.title = "title2"
    input2.uri = "uri2"
    input2.active = True
    type(mocked_device).get_inputs = AsyncMock(return_value=[input1, input2])

    type(mocked_device).set_power = AsyncMock()
    type(mocked_device).set_sound_settings = AsyncMock()
    type(mocked_device).listen_notifications = AsyncMock()
    type(mocked_device).stop_listen_notifications = AsyncMock()

    notification_callbacks = {}
    mocked_device.notification_callbacks = notification_callbacks

    def _on_notification(name, callback):
        notification_callbacks[name] = callback

    type(mocked_device).on_notification = MagicMock(
        side_effect=_on_notification)
    type(mocked_device).clear_notification_callbacks = MagicMock()

    return mocked_device