1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 21:06:19 +00:00
Files
core/tests/components/buienradar/test_camera.py
Ties de Kock 0eb387916f Camera platform for buienradar imagery (#23358)
* Add camera for buienradar radar

* Use asyncio.Conditions instead of asyncio.Lock

* Add test and fix python 3.5 compatibility

* rename interval to delta for consistency with BOM integration

* fix linting error introduced during rebase

* Improved buienradar.camera documentation and tests

  * Incorporated one comment on a redundant/cargo cult function
  * Improved documentation
  * Increase test coverage by fixing one test by making it a coroutine
    (to make it actually run), adding another test case, and changing
    the flow in the implementation.

* style changes after review, additional test case

* Use python 3.5 style mypy type annotations in __init__

* Remove explicit passing of event loop

* Adopt buienradar camera as codeowner

* Update manifest.json

* Update CODEOWNERS through hassfest

Updated CODEOWNERS through hassfest (instead of manually), thanks to
@balloob for the hint.
2019-06-11 15:26:04 -07:00

203 lines
6.2 KiB
Python

"""The tests for generic camera component."""
import asyncio
from aiohttp.client_exceptions import ClientResponseError
from homeassistant.util import dt as dt_util
from homeassistant.setup import async_setup_component
# An infinitesimally small time-delta.
EPSILON_DELTA = 0.0000000001
def radar_map_url(dim: int = 512) -> str:
"""Build map url, defaulting to 512 wide (as in component)."""
return ("https://api.buienradar.nl/"
"image/1.0/RadarMapNL?w={dim}&h={dim}").format(dim=dim)
async def test_fetching_url_and_caching(aioclient_mock, hass, hass_client):
"""Test that it fetches the given url."""
aioclient_mock.get(radar_map_url(), text='hello world')
await async_setup_component(hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'buienradar',
}})
client = await hass_client()
resp = await client.get('/api/camera_proxy/camera.config_test')
assert resp.status == 200
assert aioclient_mock.call_count == 1
body = await resp.text()
assert body == 'hello world'
# default delta is 600s -> should be the same when calling immediately
# afterwards.
resp = await client.get('/api/camera_proxy/camera.config_test')
assert aioclient_mock.call_count == 1
async def test_expire_delta(aioclient_mock, hass, hass_client):
"""Test that the cache expires after delta."""
aioclient_mock.get(radar_map_url(), text='hello world')
await async_setup_component(hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'buienradar',
'delta': EPSILON_DELTA,
}})
client = await hass_client()
resp = await client.get('/api/camera_proxy/camera.config_test')
assert resp.status == 200
assert aioclient_mock.call_count == 1
body = await resp.text()
assert body == 'hello world'
await asyncio.sleep(EPSILON_DELTA)
# tiny delta has passed -> should immediately call again
resp = await client.get('/api/camera_proxy/camera.config_test')
assert aioclient_mock.call_count == 2
async def test_only_one_fetch_at_a_time(aioclient_mock, hass, hass_client):
"""Test that it fetches with only one request at the same time."""
aioclient_mock.get(radar_map_url(), text='hello world')
await async_setup_component(hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'buienradar',
}})
client = await hass_client()
resp_1 = client.get('/api/camera_proxy/camera.config_test')
resp_2 = client.get('/api/camera_proxy/camera.config_test')
resp = await resp_1
resp_2 = await resp_2
assert (await resp.text()) == (await resp_2.text())
assert aioclient_mock.call_count == 1
async def test_dimension(aioclient_mock, hass, hass_client):
"""Test that it actually adheres to the dimension."""
aioclient_mock.get(radar_map_url(700), text='hello world')
await async_setup_component(hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'buienradar',
'dimension': 700,
}})
client = await hass_client()
await client.get('/api/camera_proxy/camera.config_test')
assert aioclient_mock.call_count == 1
async def test_failure_response_not_cached(aioclient_mock, hass, hass_client):
"""Test that it does not cache a failure response."""
aioclient_mock.get(radar_map_url(), text='hello world', status=401)
await async_setup_component(hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'buienradar',
}})
client = await hass_client()
await client.get('/api/camera_proxy/camera.config_test')
await client.get('/api/camera_proxy/camera.config_test')
assert aioclient_mock.call_count == 2
async def test_last_modified_updates(aioclient_mock, hass, hass_client):
"""Test that it does respect HTTP not modified."""
# Build Last-Modified header value
now = dt_util.utcnow()
last_modified = now.strftime("%a, %d %m %Y %H:%M:%S GMT")
aioclient_mock.get(radar_map_url(), text='hello world', status=200,
headers={
'Last-Modified': last_modified,
})
await async_setup_component(hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'buienradar',
'delta': EPSILON_DELTA,
}})
client = await hass_client()
resp_1 = await client.get('/api/camera_proxy/camera.config_test')
# It is not possible to check if header was sent.
assert aioclient_mock.call_count == 1
await asyncio.sleep(EPSILON_DELTA)
# Content has expired, change response to a 304 NOT MODIFIED, which has no
# text, i.e. old value should be kept
aioclient_mock.clear_requests()
# mock call count is now reset as well:
assert aioclient_mock.call_count == 0
aioclient_mock.get(radar_map_url(), text=None, status=304)
resp_2 = await client.get('/api/camera_proxy/camera.config_test')
assert aioclient_mock.call_count == 1
assert (await resp_1.read()) == (await resp_2.read())
async def test_retries_after_error(aioclient_mock, hass, hass_client):
"""Test that it does retry after an error instead of caching."""
await async_setup_component(hass, 'camera', {
'camera': {
'name': 'config_test',
'platform': 'buienradar',
}})
client = await hass_client()
aioclient_mock.get(radar_map_url(), text=None, status=500)
# A 404 should not return data and throw:
try:
await client.get('/api/camera_proxy/camera.config_test')
except ClientResponseError:
pass
assert aioclient_mock.call_count == 1
# Change the response to a 200
aioclient_mock.clear_requests()
aioclient_mock.get(radar_map_url(), text="DEADBEEF")
assert aioclient_mock.call_count == 0
# http error should not be cached, immediate retry.
resp_2 = await client.get('/api/camera_proxy/camera.config_test')
assert aioclient_mock.call_count == 1
# Binary text can not be added as body to `aioclient_mock.get(text=...)`,
# while `resp.read()` returns bytes, encode the value.
assert (await resp_2.read()) == b"DEADBEEF"