Return emulated hue id for update requests (#35139)

* Return emulated hue id for update requests

* Emulated Hue: Rename function argument to match its content

* Use HTTP status consts throughout the test

* Use HTTP status consts in UPnP test
This commit is contained in:
Thomas Hollstegge 2020-05-04 02:27:19 +02:00 committed by GitHub
parent 7e36699aac
commit e4e89becc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 98 additions and 57 deletions

View file

@ -506,7 +506,9 @@ class HueOneLightChangeView(HomeAssistantView):
# Create success responses for all received keys
json_response = [
create_hue_success_response(entity_id, HUE_API_STATE_ON, parsed[STATE_ON])
create_hue_success_response(
entity_number, HUE_API_STATE_ON, parsed[STATE_ON]
)
]
for (key, val) in (
@ -517,7 +519,7 @@ class HueOneLightChangeView(HomeAssistantView):
):
if parsed[key] is not None:
json_response.append(
create_hue_success_response(entity_id, val, parsed[key])
create_hue_success_response(entity_number, val, parsed[key])
)
return self.json(json_response)
@ -710,9 +712,9 @@ def entity_to_json(config, entity):
return retval
def create_hue_success_response(entity_id, attr, value):
def create_hue_success_response(entity_number, attr, value):
"""Create a success response for an attribute set on a light."""
success_key = f"/lights/{entity_id}/state/{attr}"
success_key = f"/lights/{entity_number}/state/{attr}"
return {"success": {success_key: value}}

View file

@ -34,6 +34,8 @@ from homeassistant.components.emulated_hue.hue_api import (
from homeassistant.const import (
ATTR_ENTITY_ID,
HTTP_NOT_FOUND,
HTTP_OK,
HTTP_UNAUTHORIZED,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
@ -54,6 +56,26 @@ BRIDGE_SERVER_PORT = get_test_instance_port()
BRIDGE_URL_BASE = f"http://127.0.0.1:{BRIDGE_SERVER_PORT}" + "{}"
JSON_HEADERS = {CONTENT_TYPE: const.CONTENT_TYPE_JSON}
ENTITY_IDS_BY_NUMBER = {
"1": "light.ceiling_lights",
"2": "light.bed_light",
"3": "script.set_kitchen_light",
"4": "light.kitchen_lights",
"5": "media_player.living_room",
"6": "media_player.bedroom",
"7": "media_player.walkman",
"8": "media_player.lounge_room",
"9": "fan.living_room_fan",
"10": "fan.ceiling_fan",
"11": "cover.living_room_window",
"12": "climate.hvac",
"13": "climate.heatpump",
"14": "climate.ecobee",
"15": "light.no_brightness",
}
ENTITY_NUMBERS_BY_ID = {v: k for k, v in ENTITY_IDS_BY_NUMBER.items()}
@pytest.fixture
def hass_hue(loop, hass):
@ -144,7 +166,6 @@ def hue_client(loop, hass_hue, aiohttp_client):
config = Config(
None,
{
emulated_hue.CONF_TYPE: emulated_hue.TYPE_ALEXA,
emulated_hue.CONF_ENTITIES: {
"light.bed_light": {emulated_hue.CONF_ENTITY_HIDDEN: True},
# Kitchen light is explicitly excluded from being exposed
@ -162,6 +183,7 @@ def hue_client(loop, hass_hue, aiohttp_client):
},
},
)
config.numbers = ENTITY_IDS_BY_NUMBER
HueUsernameView().register(web_app, web_app.router)
HueAllLightsStateView(config).register(web_app, web_app.router)
@ -177,7 +199,7 @@ async def test_discover_lights(hue_client):
"""Test the discovery of lights."""
result = await hue_client.get("/api/username/lights")
assert result.status == 200
assert result.status == HTTP_OK
assert "application/json" in result.headers["content-type"]
result_json = await result.json()
@ -204,7 +226,7 @@ async def test_discover_lights(hue_client):
async def test_light_without_brightness_supported(hass_hue, hue_client):
"""Test that light without brightness is supported."""
light_without_brightness_json = await perform_get_light_state(
hue_client, "light.no_brightness", 200
hue_client, "light.no_brightness", HTTP_OK
)
assert light_without_brightness_json["state"][HUE_API_STATE_ON] is True
@ -223,7 +245,7 @@ async def test_light_without_brightness_can_be_turned_off(hass_hue, hue_client):
)
no_brightness_result_json = await no_brightness_result.json()
assert no_brightness_result.status == 200
assert no_brightness_result.status == HTTP_OK
assert "application/json" in no_brightness_result.headers["content-type"]
assert len(no_brightness_result_json) == 1
@ -255,7 +277,7 @@ async def test_light_without_brightness_can_be_turned_on(hass_hue, hue_client):
no_brightness_result_json = await no_brightness_result.json()
assert no_brightness_result.status == 200
assert no_brightness_result.status == HTTP_OK
assert "application/json" in no_brightness_result.headers["content-type"]
assert len(no_brightness_result_json) == 1
@ -283,7 +305,7 @@ async def test_reachable_for_state(hass_hue, hue_client, state, is_reachable):
hass_hue.states.async_set(entity_id, state)
state_json = await perform_get_light_state(hue_client, entity_id, 200)
state_json = await perform_get_light_state(hue_client, entity_id, HTTP_OK)
assert state_json["state"]["reachable"] == is_reachable, state_json
@ -292,7 +314,7 @@ async def test_discover_full_state(hue_client):
"""Test the discovery of full state."""
result = await hue_client.get(f"/api/{HUE_API_USERNAME}")
assert result.status == 200
assert result.status == HTTP_OK
assert "application/json" in result.headers["content-type"]
result_json = await result.json()
@ -344,7 +366,9 @@ async def test_get_light_state(hass_hue, hue_client):
blocking=True,
)
office_json = await perform_get_light_state(hue_client, "light.ceiling_lights", 200)
office_json = await perform_get_light_state(
hue_client, "light.ceiling_lights", HTTP_OK
)
assert office_json["state"][HUE_API_STATE_ON] is True
assert office_json["state"][HUE_API_STATE_BRI] == 127
@ -354,13 +378,18 @@ async def test_get_light_state(hass_hue, hue_client):
# Check all lights view
result = await hue_client.get("/api/username/lights")
assert result.status == 200
assert result.status == HTTP_OK
assert "application/json" in result.headers["content-type"]
result_json = await result.json()
assert "light.ceiling_lights" in result_json
assert result_json["light.ceiling_lights"]["state"][HUE_API_STATE_BRI] == 127
assert ENTITY_NUMBERS_BY_ID["light.ceiling_lights"] in result_json
assert (
result_json[ENTITY_NUMBERS_BY_ID["light.ceiling_lights"]]["state"][
HUE_API_STATE_BRI
]
== 127
)
# Turn office light off
await hass_hue.services.async_call(
@ -370,7 +399,9 @@ async def test_get_light_state(hass_hue, hue_client):
blocking=True,
)
office_json = await perform_get_light_state(hue_client, "light.ceiling_lights", 200)
office_json = await perform_get_light_state(
hue_client, "light.ceiling_lights", HTTP_OK
)
assert office_json["state"][HUE_API_STATE_ON] is False
# Removed assert HUE_API_STATE_BRI == 0 as Hue API states bri must be 1..254
@ -378,10 +409,10 @@ async def test_get_light_state(hass_hue, hue_client):
assert office_json["state"][HUE_API_STATE_SAT] == 0
# Make sure bedroom light isn't accessible
await perform_get_light_state(hue_client, "light.bed_light", 401)
await perform_get_light_state(hue_client, "light.bed_light", HTTP_UNAUTHORIZED)
# Make sure kitchen light isn't accessible
await perform_get_light_state(hue_client, "light.kitchen_lights", 401)
await perform_get_light_state(hue_client, "light.kitchen_lights", HTTP_UNAUTHORIZED)
async def test_put_light_state(hass, hass_hue, hue_client):
@ -432,7 +463,7 @@ async def test_put_light_state(hass, hass_hue, hue_client):
# go through api to get the state back
ceiling_json = await perform_get_light_state(
hue_client, "light.ceiling_lights", 200
hue_client, "light.ceiling_lights", HTTP_OK
)
assert ceiling_json["state"][HUE_API_STATE_BRI] == 123
assert ceiling_json["state"][HUE_API_STATE_HUE] == 4369
@ -451,7 +482,7 @@ async def test_put_light_state(hass, hass_hue, hue_client):
# go through api to get the state back
ceiling_json = await perform_get_light_state(
hue_client, "light.ceiling_lights", 200
hue_client, "light.ceiling_lights", HTTP_OK
)
assert ceiling_json["state"][HUE_API_STATE_BRI] == 254
assert ceiling_json["state"][HUE_API_STATE_HUE] == 4369
@ -464,7 +495,7 @@ async def test_put_light_state(hass, hass_hue, hue_client):
ceiling_result_json = await ceiling_result.json()
assert ceiling_result.status == 200
assert ceiling_result.status == HTTP_OK
assert "application/json" in ceiling_result.headers["content-type"]
assert len(ceiling_result_json) == 1
@ -473,7 +504,7 @@ async def test_put_light_state(hass, hass_hue, hue_client):
ceiling_lights = hass_hue.states.get("light.ceiling_lights")
assert ceiling_lights.state == STATE_OFF
ceiling_json = await perform_get_light_state(
hue_client, "light.ceiling_lights", 200
hue_client, "light.ceiling_lights", HTTP_OK
)
# Removed assert HUE_API_STATE_BRI == 0 as Hue API states bri must be 1..254
assert ceiling_json["state"][HUE_API_STATE_HUE] == 0
@ -483,13 +514,13 @@ async def test_put_light_state(hass, hass_hue, hue_client):
bedroom_result = await perform_put_light_state(
hass_hue, hue_client, "light.bed_light", True
)
assert bedroom_result.status == 401
assert bedroom_result.status == HTTP_UNAUTHORIZED
# Make sure we can't change the kitchen light state
kitchen_result = await perform_put_light_state(
hass_hue, hue_client, "light.kitchen_light", True
hass_hue, hue_client, "light.kitchen_lights", True
)
assert kitchen_result.status == HTTP_NOT_FOUND
assert kitchen_result.status == HTTP_UNAUTHORIZED
async def test_put_light_state_script(hass, hass_hue, hue_client):
@ -512,7 +543,7 @@ async def test_put_light_state_script(hass, hass_hue, hue_client):
script_result_json = await script_result.json()
assert script_result.status == 200
assert script_result.status == HTTP_OK
assert len(script_result_json) == 2
kitchen_light = hass_hue.states.get("light.kitchen_lights")
@ -535,7 +566,7 @@ async def test_put_light_state_climate_set_temperature(hass_hue, hue_client):
hvac_result_json = await hvac_result.json()
assert hvac_result.status == 200
assert hvac_result.status == HTTP_OK
assert len(hvac_result_json) == 2
hvac = hass_hue.states.get("climate.hvac")
@ -546,7 +577,7 @@ async def test_put_light_state_climate_set_temperature(hass_hue, hue_client):
ecobee_result = await perform_put_light_state(
hass_hue, hue_client, "climate.ecobee", True
)
assert ecobee_result.status == 401
assert ecobee_result.status == HTTP_UNAUTHORIZED
async def test_put_light_state_media_player(hass_hue, hue_client):
@ -569,7 +600,7 @@ async def test_put_light_state_media_player(hass_hue, hue_client):
mp_result_json = await mp_result.json()
assert mp_result.status == 200
assert mp_result.status == HTTP_OK
assert len(mp_result_json) == 2
walkman = hass_hue.states.get("media_player.walkman")
@ -604,7 +635,7 @@ async def test_close_cover(hass_hue, hue_client):
hass_hue, hue_client, cover_id, True, 100
)
assert cover_result.status == 200
assert cover_result.status == HTTP_OK
assert "application/json" in cover_result.headers["content-type"]
for _ in range(7):
@ -624,6 +655,7 @@ async def test_close_cover(hass_hue, hue_client):
async def test_set_position_cover(hass_hue, hue_client):
"""Test setting position cover ."""
cover_id = "cover.living_room_window"
cover_number = ENTITY_NUMBERS_BY_ID[cover_id]
# Turn the office light off first
await hass_hue.services.async_call(
cover.DOMAIN,
@ -651,19 +683,14 @@ async def test_set_position_cover(hass_hue, hue_client):
hass_hue, hue_client, cover_id, False, brightness
)
assert cover_result.status == 200
assert cover_result.status == HTTP_OK
assert "application/json" in cover_result.headers["content-type"]
cover_result_json = await cover_result.json()
assert len(cover_result_json) == 2
assert True, cover_result_json[0]["success"][
"/lights/cover.living_room_window/state/on"
]
assert (
cover_result_json[1]["success"]["/lights/cover.living_room_window/state/bri"]
== level
)
assert True, cover_result_json[0]["success"][f"/lights/{cover_number}/state/on"]
assert cover_result_json[1]["success"][f"/lights/{cover_number}/state/bri"] == level
for _ in range(100):
future = dt_util.utcnow() + timedelta(seconds=1)
@ -696,7 +723,7 @@ async def test_put_light_state_fan(hass_hue, hue_client):
fan_result_json = await fan_result.json()
assert fan_result.status == 200
assert fan_result.status == HTTP_OK
assert len(fan_result_json) == 2
living_room_fan = hass_hue.states.get("fan.living_room_fan")
@ -707,6 +734,7 @@ async def test_put_light_state_fan(hass_hue, hue_client):
# pylint: disable=invalid-name
async def test_put_with_form_urlencoded_content_type(hass_hue, hue_client):
"""Test the form with urlencoded content."""
entity_number = ENTITY_NUMBERS_BY_ID["light.ceiling_lights"]
# Needed for Alexa
await perform_put_test_on_ceiling_lights(
hass_hue, hue_client, "application/x-www-form-urlencoded"
@ -715,7 +743,7 @@ async def test_put_with_form_urlencoded_content_type(hass_hue, hue_client):
# Make sure we fail gracefully when we can't parse the data
data = {"key1": "value1", "key2": "value2"}
result = await hue_client.put(
"/api/username/lights/light.ceiling_lights/state",
f"/api/username/lights/{entity_number}/state",
headers={"content-type": "application/x-www-form-urlencoded"},
data=data,
)
@ -725,22 +753,26 @@ async def test_put_with_form_urlencoded_content_type(hass_hue, hue_client):
async def test_entity_not_found(hue_client):
"""Test for entity which are not found."""
result = await hue_client.get("/api/username/lights/not.existant_entity")
result = await hue_client.get("/api/username/lights/98")
assert result.status == HTTP_NOT_FOUND
result = await hue_client.put("/api/username/lights/not.existant_entity/state")
result = await hue_client.put("/api/username/lights/98/state")
assert result.status == HTTP_NOT_FOUND
async def test_allowed_methods(hue_client):
"""Test the allowed methods."""
result = await hue_client.get("/api/username/lights/light.ceiling_lights/state")
result = await hue_client.get(
"/api/username/lights/ENTITY_NUMBERS_BY_ID[light.ceiling_lights]/state"
)
assert result.status == 405
result = await hue_client.put("/api/username/lights/light.ceiling_lights")
result = await hue_client.put(
"/api/username/lights/ENTITY_NUMBERS_BY_ID[light.ceiling_lights]"
)
assert result.status == 405
@ -753,7 +785,9 @@ async def test_proper_put_state_request(hue_client):
"""Test the request to set the state."""
# Test proper on value parsing
result = await hue_client.put(
"/api/username/lights/{}/state".format("light.ceiling_lights"),
"/api/username/lights/{}/state".format(
ENTITY_NUMBERS_BY_ID["light.ceiling_lights"]
),
data=json.dumps({HUE_API_STATE_ON: 1234}),
)
@ -761,7 +795,9 @@ async def test_proper_put_state_request(hue_client):
# Test proper brightness value parsing
result = await hue_client.put(
"/api/username/lights/{}/state".format("light.ceiling_lights"),
"/api/username/lights/{}/state".format(
ENTITY_NUMBERS_BY_ID["light.ceiling_lights"]
),
data=json.dumps({HUE_API_STATE_ON: True, HUE_API_STATE_BRI: "Hello world!"}),
)
@ -773,7 +809,7 @@ async def test_get_empty_groups_state(hue_client):
# Test proper on value parsing
result = await hue_client.get("/api/username/groups")
assert result.status == 200
assert result.status == HTTP_OK
result_json = await result.json()
@ -801,7 +837,7 @@ async def perform_put_test_on_ceiling_lights(
hass_hue, hue_client, "light.ceiling_lights", True, 56, content_type
)
assert office_result.status == 200
assert office_result.status == HTTP_OK
assert "application/json" in office_result.headers["content-type"]
office_result_json = await office_result.json()
@ -816,11 +852,12 @@ async def perform_put_test_on_ceiling_lights(
async def perform_get_light_state(client, entity_id, expected_status):
"""Test the getting of a light state."""
result = await client.get(f"/api/username/lights/{entity_id}")
entity_number = ENTITY_NUMBERS_BY_ID[entity_id]
result = await client.get(f"/api/username/lights/{entity_number}")
assert result.status == expected_status
if expected_status == 200:
if expected_status == HTTP_OK:
assert "application/json" in result.headers["content-type"]
return await result.json()
@ -850,8 +887,9 @@ async def perform_put_light_state(
if saturation is not None:
data[HUE_API_STATE_SAT] = saturation
entity_number = ENTITY_NUMBERS_BY_ID[entity_id]
result = await client.put(
f"/api/username/lights/{entity_id}/state",
f"/api/username/lights/{entity_number}/state",
headers=req_headers,
data=json.dumps(data).encode(),
)
@ -878,12 +916,12 @@ async def test_external_ip_blocked(hue_client):
):
for getUrl in getUrls:
result = await hue_client.get(getUrl)
assert result.status == 401
assert result.status == HTTP_UNAUTHORIZED
for postUrl in postUrls:
result = await hue_client.post(postUrl)
assert result.status == 401
assert result.status == HTTP_UNAUTHORIZED
for putUrl in putUrls:
result = await hue_client.put(putUrl)
assert result.status == 401
assert result.status == HTTP_UNAUTHORIZED

View file

@ -8,6 +8,7 @@ import requests
from homeassistant import const, setup
from homeassistant.components import emulated_hue
from homeassistant.const import HTTP_OK
from tests.async_mock import patch
from tests.common import get_test_home_assistant, get_test_instance_port
@ -51,7 +52,7 @@ class TestEmulatedHue(unittest.TestCase):
"""Test the description."""
result = requests.get(BRIDGE_URL_BASE.format("/description.xml"), timeout=5)
assert result.status_code == 200
assert result.status_code == HTTP_OK
assert "text/xml" in result.headers["content-type"]
# Make sure the XML is parsable
@ -68,7 +69,7 @@ class TestEmulatedHue(unittest.TestCase):
BRIDGE_URL_BASE.format("/api"), data=json.dumps(request_json), timeout=5
)
assert result.status_code == 200
assert result.status_code == HTTP_OK
assert "application/json" in result.headers["content-type"]
resp_json = result.json()
@ -87,7 +88,7 @@ class TestEmulatedHue(unittest.TestCase):
timeout=5,
)
assert result.status_code == 200
assert result.status_code == HTTP_OK
assert "application/json" in result.headers["content-type"]
resp_json = result.json()