Upgrade to aiohttp 1.2 (#4964)

* Upgrade to aiohttp 1.2

* Clean up emulated_hue tests
This commit is contained in:
Paulus Schoutsen 2017-01-11 21:25:02 +01:00 committed by GitHub
parent 1cf9ae5a01
commit e68e29e03e
6 changed files with 316 additions and 330 deletions

View File

@ -91,7 +91,7 @@ class HueOneLightStateView(HomeAssistantView):
self.config = config self.config = config
@core.callback @core.callback
def get(self, request, username, entity_id=None): def get(self, request, username, entity_id):
"""Process a request to get the state of an individual light.""" """Process a request to get the state of an individual light."""
hass = request.app['hass'] hass = request.app['hass']
entity_id = self.config.number_to_entity_id(entity_id) entity_id = self.config.number_to_entity_id(entity_id)

View File

@ -32,7 +32,7 @@ from .const import (
KEY_USE_X_FORWARDED_FOR, KEY_TRUSTED_NETWORKS, KEY_USE_X_FORWARDED_FOR, KEY_TRUSTED_NETWORKS,
KEY_BANS_ENABLED, KEY_LOGIN_THRESHOLD, KEY_BANS_ENABLED, KEY_LOGIN_THRESHOLD,
KEY_DEVELOPMENT, KEY_AUTHENTICATED) KEY_DEVELOPMENT, KEY_AUTHENTICATED)
from .static import FILE_SENDER, GZIP_FILE_SENDER, staticresource_middleware from .static import FILE_SENDER, CACHING_FILE_SENDER, staticresource_middleware
from .util import get_real_ip from .util import get_real_ip
DOMAIN = 'http' DOMAIN = 'http'
@ -272,7 +272,7 @@ class HomeAssistantWSGI(object):
@asyncio.coroutine @asyncio.coroutine
def serve_file(request): def serve_file(request):
"""Serve file from disk.""" """Serve file from disk."""
res = yield from GZIP_FILE_SENDER.send(request, filepath) res = yield from CACHING_FILE_SENDER.send(request, filepath)
return res return res
# aiohttp supports regex matching for variables. Using that as temp # aiohttp supports regex matching for variables. Using that as temp

View File

@ -1,69 +1,40 @@
"""Static file handling for HTTP component.""" """Static file handling for HTTP component."""
import asyncio import asyncio
import mimetypes
import re import re
from aiohttp import hdrs from aiohttp import hdrs
from aiohttp.file_sender import FileSender from aiohttp.file_sender import FileSender
from aiohttp.web_urldispatcher import StaticResource from aiohttp.web_urldispatcher import StaticResource
from aiohttp.web_exceptions import HTTPNotModified
from .const import KEY_DEVELOPMENT from .const import KEY_DEVELOPMENT
_FINGERPRINT = re.compile(r'^(.+)-[a-z0-9]{32}\.(\w+)$', re.IGNORECASE) _FINGERPRINT = re.compile(r'^(.+)-[a-z0-9]{32}\.(\w+)$', re.IGNORECASE)
class GzipFileSender(FileSender): class CachingFileSender(FileSender):
"""FileSender class capable of sending gzip version if available.""" """FileSender class that caches output if not in dev mode."""
# pylint: disable=invalid-name def __init__(self, *args, **kwargs):
"""Initialize the hass file sender."""
super().__init__(*args, **kwargs)
@asyncio.coroutine orig_sendfile = self._sendfile
def send(self, request, filepath):
"""Send filepath to client using request."""
gzip = False
if 'gzip' in request.headers[hdrs.ACCEPT_ENCODING]:
gzip_path = filepath.with_name(filepath.name + '.gz')
if gzip_path.is_file(): @asyncio.coroutine
filepath = gzip_path def sendfile(request, resp, fobj, count):
gzip = True """Sendfile that includes a cache header."""
if not request.app[KEY_DEVELOPMENT]:
cache_time = 31 * 86400 # = 1 month
resp.headers[hdrs.CACHE_CONTROL] = "public, max-age={}".format(
cache_time)
st = filepath.stat() yield from orig_sendfile(request, resp, fobj, count)
modsince = request.if_modified_since # Overwriting like this because __init__ can change implementation.
if modsince is not None and st.st_mtime <= modsince.timestamp(): self._sendfile = sendfile
raise HTTPNotModified()
ct, encoding = mimetypes.guess_type(str(filepath))
if not ct:
ct = 'application/octet-stream'
resp = self._response_factory()
resp.content_type = ct
if encoding:
resp.headers[hdrs.CONTENT_ENCODING] = encoding
if gzip:
resp.headers[hdrs.VARY] = hdrs.ACCEPT_ENCODING
resp.last_modified = st.st_mtime
# CACHE HACK
if not request.app[KEY_DEVELOPMENT]:
cache_time = 31 * 86400 # = 1 month
resp.headers[hdrs.CACHE_CONTROL] = "public, max-age={}".format(
cache_time)
file_size = st.st_size
resp.content_length = file_size
with filepath.open('rb') as f:
yield from self._sendfile(request, resp, f, file_size)
return resp
GZIP_FILE_SENDER = GzipFileSender()
FILE_SENDER = FileSender() FILE_SENDER = FileSender()
CACHING_FILE_SENDER = CachingFileSender()
@asyncio.coroutine @asyncio.coroutine
@ -77,7 +48,7 @@ def staticresource_middleware(app, handler):
return handler return handler
# pylint: disable=protected-access # pylint: disable=protected-access
inst._file_sender = GZIP_FILE_SENDER inst._file_sender = CACHING_FILE_SENDER
@asyncio.coroutine @asyncio.coroutine
def static_middleware_handler(request): def static_middleware_handler(request):

View File

@ -6,7 +6,7 @@ pip>=7.0.0
jinja2>=2.8 jinja2>=2.8
voluptuous==0.9.2 voluptuous==0.9.2
typing>=3,<4 typing>=3,<4
aiohttp==1.1.6 aiohttp==1.2
async_timeout==1.1.0 async_timeout==1.1.0
# homeassistant.components.nuimo_controller # homeassistant.components.nuimo_controller

View File

@ -22,7 +22,7 @@ REQUIRES = [
'jinja2>=2.8', 'jinja2>=2.8',
'voluptuous==0.9.2', 'voluptuous==0.9.2',
'typing>=3,<4', 'typing>=3,<4',
'aiohttp==1.1.6', 'aiohttp==1.2',
'async_timeout==1.1.0', 'async_timeout==1.1.0',
] ]

View File

@ -1,9 +1,9 @@
"""The tests for the emulated Hue component.""" """The tests for the emulated Hue component."""
import asyncio
import json import json
import unittest
from unittest.mock import patch from unittest.mock import patch
import requests import pytest
from homeassistant import bootstrap, const, core from homeassistant import bootstrap, const, core
import homeassistant.components as core_components import homeassistant.components as core_components
@ -12,10 +12,12 @@ from homeassistant.components import (
) )
from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.components.emulated_hue.hue_api import ( from homeassistant.components.emulated_hue.hue_api import (
HUE_API_STATE_ON, HUE_API_STATE_BRI) HUE_API_STATE_ON, HUE_API_STATE_BRI, HueUsernameView,
from homeassistant.util.async import run_coroutine_threadsafe HueAllLightsStateView, HueOneLightStateView, HueOneLightChangeView)
from homeassistant.components.emulated_hue import Config
from tests.common import get_test_instance_port, get_test_home_assistant from tests.common import (
get_test_instance_port, mock_http_component_app)
HTTP_SERVER_PORT = get_test_instance_port() HTTP_SERVER_PORT = get_test_instance_port()
BRIDGE_SERVER_PORT = get_test_instance_port() BRIDGE_SERVER_PORT = get_test_instance_port()
@ -24,41 +26,38 @@ BRIDGE_URL_BASE = 'http://127.0.0.1:{}'.format(BRIDGE_SERVER_PORT) + '{}'
JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON} JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON}
class TestEmulatedHueExposedByDefault(unittest.TestCase): @pytest.fixture
"""Test class for emulated hue component.""" def hass_hue(loop, hass):
"""Setup a hass instance for these tests."""
# We need to do this to get access to homeassistant/turn_(on,off)
loop.run_until_complete(
core_components.async_setup(hass, {core.DOMAIN: {}}))
@classmethod loop.run_until_complete(bootstrap.async_setup_component(
def setUpClass(cls): hass, http.DOMAIN,
"""Setup the class.""" {http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}}))
cls.hass = hass = get_test_home_assistant()
# We need to do this to get access to homeassistant/turn_(on,off) with patch('homeassistant.components'
run_coroutine_threadsafe( '.emulated_hue.UPNPResponderThread'):
core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop loop.run_until_complete(
).result() bootstrap.async_setup_component(hass, emulated_hue.DOMAIN, {
bootstrap.setup_component(
hass, http.DOMAIN,
{http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}})
with patch('homeassistant.components'
'.emulated_hue.UPNPResponderThread'):
bootstrap.setup_component(hass, emulated_hue.DOMAIN, {
emulated_hue.DOMAIN: { emulated_hue.DOMAIN: {
emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT, emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT,
emulated_hue.CONF_EXPOSE_BY_DEFAULT: True emulated_hue.CONF_EXPOSE_BY_DEFAULT: True
} }
}) }))
bootstrap.setup_component(cls.hass, light.DOMAIN, { loop.run_until_complete(
bootstrap.async_setup_component(hass, light.DOMAIN, {
'light': [ 'light': [
{ {
'platform': 'demo', 'platform': 'demo',
} }
] ]
}) }))
bootstrap.setup_component(cls.hass, script.DOMAIN, { loop.run_until_complete(
bootstrap.async_setup_component(hass, script.DOMAIN, {
'script': { 'script': {
'set_kitchen_light': { 'set_kitchen_light': {
'sequence': [ 'sequence': [
@ -73,338 +72,354 @@ class TestEmulatedHueExposedByDefault(unittest.TestCase):
] ]
} }
} }
}) }))
bootstrap.setup_component(cls.hass, media_player.DOMAIN, { loop.run_until_complete(
bootstrap.async_setup_component(hass, media_player.DOMAIN, {
'media_player': [ 'media_player': [
{ {
'platform': 'demo', 'platform': 'demo',
} }
] ]
}) }))
cls.hass.start() # Kitchen light is explicitly excluded from being exposed
kitchen_light_entity = hass.states.get('light.kitchen_lights')
attrs = dict(kitchen_light_entity.attributes)
attrs[emulated_hue.ATTR_EMULATED_HUE] = False
hass.states.async_set(
kitchen_light_entity.entity_id, kitchen_light_entity.state,
attributes=attrs)
# Kitchen light is explicitly excluded from being exposed # Expose the script
kitchen_light_entity = cls.hass.states.get('light.kitchen_lights') script_entity = hass.states.get('script.set_kitchen_light')
attrs = dict(kitchen_light_entity.attributes) attrs = dict(script_entity.attributes)
attrs[emulated_hue.ATTR_EMULATED_HUE] = False attrs[emulated_hue.ATTR_EMULATED_HUE] = True
cls.hass.states.set( hass.states.async_set(
kitchen_light_entity.entity_id, kitchen_light_entity.state, script_entity.entity_id, script_entity.state, attributes=attrs
attributes=attrs) )
# Expose the script return hass
script_entity = cls.hass.states.get('script.set_kitchen_light')
attrs = dict(script_entity.attributes)
attrs[emulated_hue.ATTR_EMULATED_HUE] = True
cls.hass.states.set(
script_entity.entity_id, script_entity.state, attributes=attrs
)
@classmethod
def tearDownClass(cls):
"""Stop the class."""
cls.hass.stop()
def test_discover_lights(self): @pytest.fixture
"""Test the discovery of lights.""" def hue_client(loop, hass_hue, test_client):
result = requests.get( """Create web client for emulated hue api."""
BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5) web_app = mock_http_component_app(hass_hue)
config = Config({'type': 'alexa'})
self.assertEqual(result.status_code, 200) HueUsernameView().register(web_app.router)
self.assertTrue('application/json' in result.headers['content-type']) HueAllLightsStateView(config).register(web_app.router)
HueOneLightStateView(config).register(web_app.router)
HueOneLightChangeView(config).register(web_app.router)
result_json = result.json() return loop.run_until_complete(test_client(web_app))
# Make sure the lights we added to the config are there
self.assertTrue('light.ceiling_lights' in result_json)
self.assertTrue('light.bed_light' in result_json)
self.assertTrue('script.set_kitchen_light' in result_json)
self.assertTrue('light.kitchen_lights' not in result_json)
self.assertTrue('media_player.living_room' in result_json)
self.assertTrue('media_player.bedroom' in result_json)
self.assertTrue('media_player.walkman' in result_json)
self.assertTrue('media_player.lounge_room' in result_json)
def test_get_light_state(self): @asyncio.coroutine
"""Test the getting of light state.""" def test_discover_lights(hue_client):
# Turn office light on and set to 127 brightness """Test the discovery of lights."""
self.hass.services.call( result = yield from hue_client.get('/api/username/lights')
light.DOMAIN, const.SERVICE_TURN_ON,
{
const.ATTR_ENTITY_ID: 'light.ceiling_lights',
light.ATTR_BRIGHTNESS: 127
},
blocking=True)
office_json = self.perform_get_light_state('light.ceiling_lights', 200) assert result.status == 200
assert 'application/json' in result.headers['content-type']
self.assertEqual(office_json['state'][HUE_API_STATE_ON], True) result_json = yield from result.json()
self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127)
# Check all lights view devices = set(val['uniqueid'] for val in result_json.values())
result = requests.get(
BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5)
self.assertEqual(result.status_code, 200) # Make sure the lights we added to the config are there
self.assertTrue('application/json' in result.headers['content-type']) assert 'light.ceiling_lights' in devices
assert 'light.bed_light' in devices
assert 'script.set_kitchen_light' in devices
assert 'light.kitchen_lights' not in devices
assert 'media_player.living_room' in devices
assert 'media_player.bedroom' in devices
assert 'media_player.walkman' in devices
assert 'media_player.lounge_room' in devices
result_json = result.json()
self.assertTrue('light.ceiling_lights' in result_json) @asyncio.coroutine
self.assertEqual( def test_get_light_state(hass_hue, hue_client):
result_json['light.ceiling_lights']['state'][HUE_API_STATE_BRI], """Test the getting of light state."""
127, # Turn office light on and set to 127 brightness
) yield from hass_hue.services.async_call(
light.DOMAIN, const.SERVICE_TURN_ON,
{
const.ATTR_ENTITY_ID: 'light.ceiling_lights',
light.ATTR_BRIGHTNESS: 127
},
blocking=True)
# Turn bedroom light off office_json = yield from perform_get_light_state(
self.hass.services.call( hue_client, 'light.ceiling_lights', 200)
light.DOMAIN, const.SERVICE_TURN_OFF,
{
const.ATTR_ENTITY_ID: 'light.bed_light'
},
blocking=True)
bedroom_json = self.perform_get_light_state('light.bed_light', 200) assert office_json['state'][HUE_API_STATE_ON] is True
assert office_json['state'][HUE_API_STATE_BRI] == 127
self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False) # Check all lights view
self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0) result = yield from hue_client.get('/api/username/lights')
# Make sure kitchen light isn't accessible assert result.status == 200
kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights') assert 'application/json' in result.headers['content-type']
kitchen_result = requests.get(
BRIDGE_URL_BASE.format(kitchen_url), timeout=5)
self.assertEqual(kitchen_result.status_code, 404) result_json = yield from result.json()
def test_put_light_state(self): assert 'light.ceiling_lights' in result_json
"""Test the seeting of light states.""" assert result_json['light.ceiling_lights']['state'][HUE_API_STATE_BRI] == \
self.perform_put_test_on_ceiling_lights() 127
# Turn the bedroom light on first # Turn bedroom light off
self.hass.services.call( yield from hass_hue.services.async_call(
light.DOMAIN, const.SERVICE_TURN_ON, light.DOMAIN, const.SERVICE_TURN_OFF,
{const.ATTR_ENTITY_ID: 'light.bed_light', {
light.ATTR_BRIGHTNESS: 153}, const.ATTR_ENTITY_ID: 'light.bed_light'
blocking=True) },
blocking=True)
bed_light = self.hass.states.get('light.bed_light') bedroom_json = yield from perform_get_light_state(
self.assertEqual(bed_light.state, STATE_ON) hue_client, 'light.bed_light', 200)
self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153)
# Go through the API to turn it off assert bedroom_json['state'][HUE_API_STATE_ON] is False
bedroom_result = self.perform_put_light_state( assert bedroom_json['state'][HUE_API_STATE_BRI] == 0
'light.bed_light', False)
bedroom_result_json = bedroom_result.json() # Make sure kitchen light isn't accessible
yield from perform_get_light_state(
hue_client, 'light.kitchen_lights', 404)
self.assertEqual(bedroom_result.status_code, 200)
self.assertTrue(
'application/json' in bedroom_result.headers['content-type'])
self.assertEqual(len(bedroom_result_json), 1) @asyncio.coroutine
def test_put_light_state(hass_hue, hue_client):
"""Test the seeting of light states."""
yield from perform_put_test_on_ceiling_lights(hass_hue, hue_client)
# Check to make sure the state changed # Turn the bedroom light on first
bed_light = self.hass.states.get('light.bed_light') yield from hass_hue.services.async_call(
self.assertEqual(bed_light.state, STATE_OFF) light.DOMAIN, const.SERVICE_TURN_ON,
{const.ATTR_ENTITY_ID: 'light.bed_light',
light.ATTR_BRIGHTNESS: 153},
blocking=True)
# Make sure we can't change the kitchen light state bed_light = hass_hue.states.get('light.bed_light')
kitchen_result = self.perform_put_light_state( assert bed_light.state == STATE_ON
'light.kitchen_light', True) assert bed_light.attributes[light.ATTR_BRIGHTNESS] == 153
self.assertEqual(kitchen_result.status_code, 404)
def test_put_light_state_script(self): # Go through the API to turn it off
"""Test the setting of script variables.""" bedroom_result = yield from perform_put_light_state(
# Turn the kitchen light off first hass_hue, hue_client,
self.hass.services.call( 'light.bed_light', False)
light.DOMAIN, const.SERVICE_TURN_OFF,
{const.ATTR_ENTITY_ID: 'light.kitchen_lights'},
blocking=True)
# Emulated hue converts 0-100% to 0-255. bedroom_result_json = yield from bedroom_result.json()
level = 23
brightness = round(level * 255 / 100)
script_result = self.perform_put_light_state( assert bedroom_result.status == 200
'script.set_kitchen_light', True, brightness) assert 'application/json' in bedroom_result.headers['content-type']
script_result_json = script_result.json() assert len(bedroom_result_json) == 1
self.assertEqual(script_result.status_code, 200) # Check to make sure the state changed
self.assertEqual(len(script_result_json), 2) bed_light = hass_hue.states.get('light.bed_light')
assert bed_light.state == STATE_OFF
kitchen_light = self.hass.states.get('light.kitchen_lights') # Make sure we can't change the kitchen light state
self.assertEqual(kitchen_light.state, 'on') kitchen_result = yield from perform_put_light_state(
self.assertEqual( hass_hue, hue_client,
kitchen_light.attributes[light.ATTR_BRIGHTNESS], 'light.kitchen_light', True)
level) assert kitchen_result.status == 404
def test_put_light_state_media_player(self):
"""Test turning on media player and setting volume."""
# Turn the music player off first
self.hass.services.call(
media_player.DOMAIN, const.SERVICE_TURN_OFF,
{const.ATTR_ENTITY_ID: 'media_player.walkman'},
blocking=True)
# Emulated hue converts 0.0-1.0 to 0-255. @asyncio.coroutine
level = 0.25 def test_put_light_state_script(hass_hue, hue_client):
brightness = round(level * 255) """Test the setting of script variables."""
# Turn the kitchen light off first
yield from hass_hue.services.async_call(
light.DOMAIN, const.SERVICE_TURN_OFF,
{const.ATTR_ENTITY_ID: 'light.kitchen_lights'},
blocking=True)
mp_result = self.perform_put_light_state( # Emulated hue converts 0-100% to 0-255.
'media_player.walkman', True, brightness) level = 23
brightness = round(level * 255 / 100)
mp_result_json = mp_result.json() script_result = yield from perform_put_light_state(
hass_hue, hue_client,
'script.set_kitchen_light', True, brightness)
self.assertEqual(mp_result.status_code, 200) script_result_json = yield from script_result.json()
self.assertEqual(len(mp_result_json), 2)
walkman = self.hass.states.get('media_player.walkman') assert script_result.status == 200
self.assertEqual(walkman.state, 'playing') assert len(script_result_json) == 2
self.assertEqual(
walkman.attributes[media_player.ATTR_MEDIA_VOLUME_LEVEL],
level)
# pylint: disable=invalid-name kitchen_light = hass_hue.states.get('light.kitchen_lights')
def test_put_with_form_urlencoded_content_type(self): assert kitchen_light.state == 'on'
"""Test the form with urlencoded content.""" assert kitchen_light.attributes[light.ATTR_BRIGHTNESS] == level
# Needed for Alexa
self.perform_put_test_on_ceiling_lights(
'application/x-www-form-urlencoded')
# Make sure we fail gracefully when we can't parse the data
data = {'key1': 'value1', 'key2': 'value2'}
result = requests.put(
BRIDGE_URL_BASE.format(
'/api/username/lights/{}/state'.format(
'light.ceiling_lights')), data=data)
self.assertEqual(result.status_code, 400) @asyncio.coroutine
def test_put_light_state_media_player(hass_hue, hue_client):
"""Test turning on media player and setting volume."""
# Turn the music player off first
yield from hass_hue.services.async_call(
media_player.DOMAIN, const.SERVICE_TURN_OFF,
{const.ATTR_ENTITY_ID: 'media_player.walkman'},
blocking=True)
def test_entity_not_found(self): # Emulated hue converts 0.0-1.0 to 0-255.
"""Test for entity which are not found.""" level = 0.25
result = requests.get( brightness = round(level * 255)
BRIDGE_URL_BASE.format(
'/api/username/lights/{}'.format("not.existant_entity")),
timeout=5)
self.assertEqual(result.status_code, 404) mp_result = yield from perform_put_light_state(
hass_hue, hue_client,
'media_player.walkman', True, brightness)
result = requests.put( mp_result_json = yield from mp_result.json()
BRIDGE_URL_BASE.format(
'/api/username/lights/{}/state'.format("non.existant_entity")),
timeout=5)
self.assertEqual(result.status_code, 404) assert mp_result.status == 200
assert len(mp_result_json) == 2
def test_allowed_methods(self): walkman = hass_hue.states.get('media_player.walkman')
"""Test the allowed methods.""" assert walkman.state == 'playing'
result = requests.get( assert walkman.attributes[media_player.ATTR_MEDIA_VOLUME_LEVEL] == level
BRIDGE_URL_BASE.format(
'/api/username/lights/{}/state'.format(
"light.ceiling_lights")))
self.assertEqual(result.status_code, 405)
result = requests.put( # pylint: disable=invalid-name
BRIDGE_URL_BASE.format( @asyncio.coroutine
'/api/username/lights/{}'.format("light.ceiling_lights")), def test_put_with_form_urlencoded_content_type(hass_hue, hue_client):
data={'key1': 'value1'}) """Test the form with urlencoded content."""
# Needed for Alexa
yield from perform_put_test_on_ceiling_lights(
hass_hue, hue_client, 'application/x-www-form-urlencoded')
self.assertEqual(result.status_code, 405) # Make sure we fail gracefully when we can't parse the data
data = {'key1': 'value1', 'key2': 'value2'}
result = yield from hue_client.put(
'/api/username/lights/light.ceiling_lights/state',
headers={
'content-type': 'application/x-www-form-urlencoded'
},
data=data,
)
result = requests.put( assert result.status == 400
BRIDGE_URL_BASE.format('/api/username/lights'),
data={'key1': 'value1'})
self.assertEqual(result.status_code, 405)
def test_proper_put_state_request(self): @asyncio.coroutine
"""Test the request to set the state.""" def test_entity_not_found(hue_client):
# Test proper on value parsing """Test for entity which are not found."""
result = requests.put( result = yield from hue_client.get(
BRIDGE_URL_BASE.format( '/api/username/lights/not.existant_entity')
'/api/username/lights/{}/state'.format(
'light.ceiling_lights')), assert result.status == 404
result = yield from hue_client.put(
'/api/username/lights/not.existant_entity/state')
assert result.status == 404
@asyncio.coroutine
def test_allowed_methods(hue_client):
"""Test the allowed methods."""
result = yield from hue_client.get(
'/api/username/lights/light.ceiling_lights/state')
assert result.status == 405
result = yield from hue_client.put(
'/api/username/lights/light.ceiling_lights')
assert result.status == 405
result = yield from hue_client.put(
'/api/username/lights')
assert result.status == 405
@asyncio.coroutine
def test_proper_put_state_request(hue_client):
"""Test the request to set the state."""
# Test proper on value parsing
result = yield from hue_client.put(
'/api/username/lights/{}/state'.format(
'light.ceiling_lights'),
data=json.dumps({HUE_API_STATE_ON: 1234})) data=json.dumps({HUE_API_STATE_ON: 1234}))
self.assertEqual(result.status_code, 400) assert result.status == 400
# Test proper brightness value parsing # Test proper brightness value parsing
result = requests.put( result = yield from hue_client.put(
BRIDGE_URL_BASE.format( '/api/username/lights/{}/state'.format(
'/api/username/lights/{}/state'.format( 'light.ceiling_lights'),
'light.ceiling_lights')), data=json.dumps({ data=json.dumps({
HUE_API_STATE_ON: True, HUE_API_STATE_ON: True,
HUE_API_STATE_BRI: 'Hello world!' HUE_API_STATE_BRI: 'Hello world!'
})) }))
self.assertEqual(result.status_code, 400) assert result.status == 400
# pylint: disable=invalid-name
def perform_put_test_on_ceiling_lights(self,
content_type='application/json'):
"""Test the setting of a light."""
# Turn the office light off first
self.hass.services.call(
light.DOMAIN, const.SERVICE_TURN_OFF,
{const.ATTR_ENTITY_ID: 'light.ceiling_lights'},
blocking=True)
ceiling_lights = self.hass.states.get('light.ceiling_lights') # pylint: disable=invalid-name
self.assertEqual(ceiling_lights.state, STATE_OFF) def perform_put_test_on_ceiling_lights(hass_hue, hue_client,
content_type='application/json'):
"""Test the setting of a light."""
# Turn the office light off first
yield from hass_hue.services.async_call(
light.DOMAIN, const.SERVICE_TURN_OFF,
{const.ATTR_ENTITY_ID: 'light.ceiling_lights'},
blocking=True)
# Go through the API to turn it on ceiling_lights = hass_hue.states.get('light.ceiling_lights')
office_result = self.perform_put_light_state( assert ceiling_lights.state == STATE_OFF
'light.ceiling_lights', True, 56, content_type)
office_result_json = office_result.json() # Go through the API to turn it on
office_result = yield from perform_put_light_state(
hass_hue, hue_client,
'light.ceiling_lights', True, 56, content_type)
self.assertEqual(office_result.status_code, 200) assert office_result.status == 200
self.assertTrue( assert 'application/json' in office_result.headers['content-type']
'application/json' in office_result.headers['content-type'])
self.assertEqual(len(office_result_json), 2) office_result_json = yield from office_result.json()
# Check to make sure the state changed assert len(office_result_json) == 2
ceiling_lights = self.hass.states.get('light.ceiling_lights')
self.assertEqual(ceiling_lights.state, STATE_ON)
self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56)
def perform_get_light_state(self, entity_id, expected_status): # Check to make sure the state changed
"""Test the gettting of a light state.""" ceiling_lights = hass_hue.states.get('light.ceiling_lights')
result = requests.get( assert ceiling_lights.state == STATE_ON
BRIDGE_URL_BASE.format( assert ceiling_lights.attributes[light.ATTR_BRIGHTNESS] == 56
'/api/username/lights/{}'.format(entity_id)), timeout=5)
self.assertEqual(result.status_code, expected_status)
if expected_status == 200: @asyncio.coroutine
self.assertTrue( def perform_get_light_state(client, entity_id, expected_status):
'application/json' in result.headers['content-type']) """Test the gettting of a light state."""
result = yield from client.get('/api/username/lights/{}'.format(entity_id))
return result.json() assert result.status == expected_status
return None if expected_status == 200:
assert 'application/json' in result.headers['content-type']
# pylint: disable=no-self-use return (yield from result.json())
def perform_put_light_state(self, entity_id, is_on, brightness=None,
content_type='application/json'):
"""Test the setting of a light state."""
url = BRIDGE_URL_BASE.format(
'/api/username/lights/{}/state'.format(entity_id))
req_headers = {'Content-Type': content_type} return None
data = {HUE_API_STATE_ON: is_on}
if brightness is not None: @asyncio.coroutine
data[HUE_API_STATE_BRI] = brightness def perform_put_light_state(hass_hue, client, entity_id, is_on,
brightness=None, content_type='application/json'):
"""Test the setting of a light state."""
req_headers = {'Content-Type': content_type}
result = requests.put( data = {HUE_API_STATE_ON: is_on}
url, data=json.dumps(data), timeout=5, headers=req_headers)
# Wait until state change is complete before continuing if brightness is not None:
self.hass.block_till_done() data[HUE_API_STATE_BRI] = brightness
return result result = yield from client.put(
'/api/username/lights/{}/state'.format(entity_id), headers=req_headers,
data=json.dumps(data).encode())
# Wait until state change is complete before continuing
yield from hass_hue.async_block_till_done()
return result