def stop(self):
        """Stop the current request and future ones.

        This avoids an exception if there is someone waiting when exiting test.
        """
        self.stopping = True
        self.queue_response(exc=ClientError())
Exemple #2
0
async def test_binary_sensor_device(hass, aioclient_mock):  # noqa
    """Test a binary sensor device."""
    config = {
        'qwikswitch': {
            'sensors': {
                'name': 's1',
                'id': '@a00001',
                'channel': 1,
                'type': 'imod',
            }
        }
    }
    await async_setup_component(hass, QWIKSWITCH, config)
    await hass.async_block_till_done()

    state_obj = hass.states.get('binary_sensor.s1')
    assert state_obj.state == 'off'

    hass.bus.async_fire(EVENT_HOMEASSISTANT_START)

    LISTEN.append('{"id":"@a00001","cmd":"","data":"4e0e1601","rssi":"61%"}')
    LISTEN.append(ClientError())  # Will cause a sleep

    await hass.async_block_till_done()
    state_obj = hass.states.get('binary_sensor.s1')
    assert state_obj.state == 'on'

    LISTEN.append('{"id":"@a00001","cmd":"","data":"4e0e1701","rssi":"61%"}')
    hass.data[QWIKSWITCH]._sleep_task.cancel()
    await LISTEN.wait_till_empty(hass)
    state_obj = hass.states.get('binary_sensor.s1')
    assert state_obj.state == 'off'
 async def __call__(self, method, url, data):
     """Fetch the next response from the queue or wait until the queue has items."""
     if self.stopping:
         raise ClientError()
     await self.semaphore.acquire()
     kwargs = self.response_list.pop(0)
     return AiohttpClientMockResponse(method=method, url=url, **kwargs)
Exemple #4
0
async def test_binary_sensor_device(hass, aioclient_mock):  # noqa: F811
    """Test a binary sensor device."""
    config = {
        "qwikswitch": {
            "sensors": {"name": "s1", "id": "@a00001", "channel": 1, "type": "imod"}
        }
    }
    await async_setup_component(hass, QWIKSWITCH, config)
    await hass.async_block_till_done()

    state_obj = hass.states.get("binary_sensor.s1")
    assert state_obj.state == "off"

    hass.bus.async_fire(EVENT_HOMEASSISTANT_START)

    LISTEN.append('{"id":"@a00001","cmd":"","data":"4e0e1601","rssi":"61%"}')
    LISTEN.append(ClientError())  # Will cause a sleep

    await hass.async_block_till_done()
    state_obj = hass.states.get("binary_sensor.s1")
    assert state_obj.state == "on"

    LISTEN.append('{"id":"@a00001","cmd":"","data":"4e0e1701","rssi":"61%"}')
    hass.data[QWIKSWITCH]._sleep_task.cancel()
    await LISTEN.wait_till_empty(hass)
    state_obj = hass.states.get("binary_sensor.s1")
    assert state_obj.state == "off"
Exemple #5
0
async def test_add_event_failure(
    hass: HomeAssistant,
    component_setup: ComponentSetup,
    mock_calendars_list: ApiResult,
    test_api_calendar: dict[str, Any],
    mock_events_list: ApiResult,
    mock_insert_event: Callable[[..., dict[str, Any]], None],
    setup_config_entry: MockConfigEntry,
    add_event_call_service: Callable[dict[str, Any], Awaitable[None]],
) -> None:
    """Test service calls with incorrect fields."""

    mock_calendars_list({"items": [test_api_calendar]})
    mock_events_list({})
    assert await component_setup()

    mock_insert_event(
        calendar_id=CALENDAR_ID,
        exc=ClientError(),
    )

    with pytest.raises(HomeAssistantError):
        await add_event_call_service(
            {"start_date": "2022-05-01", "end_date": "2022-05-01"}
        )
Exemple #6
0
async def fetch_url(session, url, timeout):
    with async_timeout.timeout(timeout):
        async with session.get(url) as response:
            if response.status == 200:
                log.debug("Got url {!r}".format(url))
                return await response.read()
            else:
                log.exception("Failed getting url {!r}".format(url))
                raise ClientError("Failed getting url {!r}".format(url))
Exemple #7
0
async def test_failed_update_devices(hass, aioclient_mock):
    """Test that code behaves correctly when unable to get the devices."""

    config = {"qwikswitch": {}}
    aioclient_mock.get("http://127.0.0.1:2020/&device", exc=ClientError())
    listen_mock = MockLongPollSideEffect()
    aioclient_mock.get("http://127.0.0.1:2020/&listen",
                       side_effect=listen_mock)
    assert not await async_setup_component(hass, QWIKSWITCH, config)
    await hass.async_start()
    await hass.async_block_till_done()
    listen_mock.stop()
async def test_scan_calendar_error(
    hass,
    component_setup,
    test_api_calendar,
    mock_calendars_list,
):
    """Test that the calendar update handles a server error."""

    mock_calendars_list({}, exc=ClientError())
    assert await component_setup()

    assert not hass.states.get(TEST_ENTITY)
Exemple #9
0
    async def test_authenticate_on_network_error(self):
        self.authenticator._authenticate = mock.CoroutineMock(
            side_effect=ClientError())

        with self.assertRaisesRegex(AuthenticationError,
                                    "Network request failed"):
            await self.authenticator.authenticate()

        self.assertIsNone(self.authenticator.id)
        self.assertIsNone(self.authenticator.issued_at)
        self.assertIsNone(self.authenticator.instance_url)
        self.assertIsNone(self.authenticator.signature)
        self.assertIsNone(self.authenticator.access_token)
        self.assertIsNone(self.authenticator.token_type)
Exemple #10
0
async def test_http_event_api_failure(
    hass,
    hass_client,
    component_setup,
    mock_calendars_list,
    mock_events_list,
    aioclient_mock,
):
    """Test the Rest API response during a calendar failure."""
    mock_events_list({})
    assert await component_setup()

    client = await hass_client()

    aioclient_mock.clear_requests()
    mock_events_list({}, exc=ClientError())

    response = await client.get(upcoming_event_url())
    assert response.status == HTTPStatus.OK
    # A failure to talk to the server results in an empty list of events
    events = await response.json()
    assert events == []
Exemple #11
0
async def test_http_event_api_failure(
    hass,
    hass_client,
    component_setup,
    mock_calendars_list,
    mock_events_list,
    aioclient_mock,
):
    """Test the Rest API response during a calendar failure."""
    mock_events_list({})
    assert await component_setup()

    client = await hass_client()

    aioclient_mock.clear_requests()
    mock_events_list({}, exc=ClientError())

    response = await client.get(upcoming_event_url())
    assert response.status == HTTPStatus.INTERNAL_SERVER_ERROR

    state = hass.states.get(TEST_ENTITY)
    assert state.name == TEST_ENTITY_NAME
    assert state.state == "unavailable"
Exemple #12
0
async def test_update_error(
    hass,
    component_setup,
    mock_calendars_list,
    mock_events_list,
    test_api_calendar,
    aioclient_mock,
):
    """Test that the calendar update handles a server error."""

    now = dt_util.now()
    mock_calendars_list({"items": [test_api_calendar]})
    mock_events_list({
        "items": [{
            **TEST_EVENT,
            "start": {
                "dateTime":
                (now + datetime.timedelta(minutes=-30)).isoformat()
            },
            "end": {
                "dateTime": (now + datetime.timedelta(minutes=30)).isoformat()
            },
        }]
    })
    assert await component_setup()

    state = hass.states.get(TEST_ENTITY)
    assert state.name == TEST_ENTITY_NAME
    assert state.state == "on"

    # Advance time to avoid throttling
    now += datetime.timedelta(minutes=30)

    aioclient_mock.clear_requests()
    mock_events_list({}, exc=ClientError())

    with patch("homeassistant.util.utcnow", return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()

    # No change
    state = hass.states.get(TEST_ENTITY)
    assert state.name == TEST_ENTITY_NAME
    assert state.state == "on"

    # Advance time beyond update/throttle point
    now += datetime.timedelta(minutes=30)

    aioclient_mock.clear_requests()
    mock_events_list({
        "items": [{
            **TEST_EVENT,
            "start": {
                "dateTime": (now + datetime.timedelta(minutes=30)).isoformat()
            },
            "end": {
                "dateTime": (now + datetime.timedelta(minutes=60)).isoformat()
            },
        }]
    })

    with patch("homeassistant.util.utcnow", return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()

    # State updated
    state = hass.states.get(TEST_ENTITY)
    assert state.name == TEST_ENTITY_NAME
    assert state.state == "off"
    def _build_digest_header(self, method, url):
        """
        :rtype: str
        """

        realm = self.challenge["realm"]
        nonce = self.challenge["nonce"]
        qop = self.challenge.get("qop")
        algorithm = self.challenge.get("algorithm", "MD5").upper()
        opaque = self.challenge.get("opaque")

        if qop and not (qop == "auth" or "auth" in qop.split(",")):
            raise ClientError("Unsupported qop value: %s" % qop)

        # lambdas assume digest modules are imported at the top level
        if algorithm == "MD5" or algorithm == "MD5-SESS":
            hash_fn = hashlib.md5
        elif algorithm == "SHA":
            hash_fn = hashlib.sha1
        else:
            return ""

        def H(x):
            return hash_fn(x.encode()).hexdigest()

        def KD(s, d):
            return H("%s:%s" % (s, d))

        path = URL(url).path_qs
        A1 = "%s:%s:%s" % (self.username, realm, self.password)
        A2 = "%s:%s" % (method, path)

        HA1 = H(A1)
        HA2 = H(A2)

        if nonce == self.last_nonce:
            self.nonce_count += 1
        else:
            self.nonce_count = 1

        self.last_nonce = nonce

        ncvalue = "%08x" % self.nonce_count

        # cnonce is just a random string generated by the client.
        cnonce_data = "".join(
            [
                str(self.nonce_count),
                nonce,
                time.ctime(),
                os.urandom(8).decode(errors="ignore"),
            ]
        ).encode()
        cnonce = hashlib.sha1(cnonce_data).hexdigest()[:16]

        if algorithm == "MD5-SESS":
            HA1 = H("%s:%s:%s" % (HA1, nonce, cnonce))

        # This assumes qop was validated to be 'auth' above. If 'auth-int'
        # support is added this will need to change.
        if qop:
            noncebit = ":".join([nonce, ncvalue, cnonce, "auth", HA2])
            response_digest = KD(HA1, noncebit)
        else:
            response_digest = KD(HA1, "%s:%s" % (nonce, HA2))

        base = ", ".join(
            [
                'username="******"' % self.username,
                'realm="%s"' % realm,
                'nonce="%s"' % nonce,
                'uri="%s"' % path,
                'response="%s"' % response_digest,
                'algorithm="%s"' % algorithm,
            ]
        )
        if opaque:
            base += ', opaque="%s"' % opaque
        if qop:
            base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce)

        return "Digest %s" % base
Exemple #14
0
    data["token"].pop("expires_at")
    data["token"].pop("expires_in")
    assert data == {
        "auth_implementation": "device_auth",
        "token": {
            "access_token": "ACCESS_TOKEN",
            "refresh_token": "REFRESH_TOKEN",
            "scope": "https://www.googleapis.com/auth/calendar",
            "token_type": "Bearer",
        },
    }

    assert len(mock_setup.mock_calls) == 1


@pytest.mark.parametrize("primary_calendar_error", [ClientError()])
async def test_calendar_lookup_failure(
    hass: HomeAssistant,
    mock_code_flow: Mock,
    mock_exchange: Mock,
    component_setup: ComponentSetup,
) -> None:
    """Test successful config flow and title fetch fails gracefully."""
    assert await component_setup()

    result = await hass.config_entries.flow.async_init(
        DOMAIN, context={"source": config_entries.SOURCE_USER})
    assert result.get("type") == "progress"
    assert result.get("step_id") == "auth"
    assert "description_placeholders" in result
    assert "url" in result["description_placeholders"]
Exemple #15
0
            async def post(self, *args: Any, **kwargs: Any):  # pylint: disable=W0613
                raise ClientError()

                # Need to yield to satisfy static analysis of @asynccontextmanager.
                yield  # noqa
Exemple #16
0
async def test_update_error(
    hass,
    component_setup,
    mock_calendars_list,
    mock_events_list,
    test_api_calendar,
    aioclient_mock,
):
    """Test that the calendar update handles a server error."""

    now = dt_util.now()
    mock_calendars_list({"items": [test_api_calendar]})
    mock_events_list({
        "items": [{
            **TEST_EVENT,
            "start": {
                "dateTime":
                (now + datetime.timedelta(minutes=-30)).isoformat()
            },
            "end": {
                "dateTime": (now + datetime.timedelta(minutes=30)).isoformat()
            },
        }]
    })
    assert await component_setup()

    state = hass.states.get(TEST_ENTITY)
    assert state.name == TEST_ENTITY_NAME
    assert state.state == "on"

    # Advance time to next data update interval
    now += datetime.timedelta(minutes=30)

    aioclient_mock.clear_requests()
    mock_events_list({}, exc=ClientError())

    with patch("homeassistant.util.utcnow", return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()

    # Entity is marked uanvailable due to API failure
    state = hass.states.get(TEST_ENTITY)
    assert state.name == TEST_ENTITY_NAME
    assert state.state == "unavailable"

    # Advance time past next coordinator update
    now += datetime.timedelta(minutes=30)

    aioclient_mock.clear_requests()
    mock_events_list({
        "items": [{
            **TEST_EVENT,
            "start": {
                "dateTime": (now + datetime.timedelta(minutes=30)).isoformat()
            },
            "end": {
                "dateTime": (now + datetime.timedelta(minutes=60)).isoformat()
            },
        }]
    })

    with patch("homeassistant.util.utcnow", return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()

    # State updated with new API response
    state = hass.states.get(TEST_ENTITY)
    assert state.name == TEST_ENTITY_NAME
    assert state.state == "off"