Convert Alexa tests to use aiohttp test utils (#6839)

This commit is contained in:
Paulus Schoutsen 2017-03-29 22:21:39 -07:00 committed by GitHub
parent bfe0aee468
commit 556dba4020

View File

@ -1,33 +1,20 @@
"""The tests for the Alexa component.""" """The tests for the Alexa component."""
# pylint: disable=protected-access # pylint: disable=protected-access
import asyncio
import json import json
import datetime import datetime
import unittest
import requests import pytest
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant import setup, const from homeassistant.setup import async_setup_component
from homeassistant.components import alexa, http from homeassistant.components import alexa
from tests.common import get_test_instance_port, get_test_home_assistant
API_PASSWORD = "test1234"
SERVER_PORT = get_test_instance_port()
BASE_API_URL = "http://127.0.0.1:{}".format(SERVER_PORT)
INTENTS_API_URL = "{}{}".format(BASE_API_URL, alexa.INTENTS_API_ENDPOINT)
HA_HEADERS = {
const.HTTP_HEADER_HA_AUTH: API_PASSWORD,
const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON,
}
SESSION_ID = "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000" SESSION_ID = "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000"
APPLICATION_ID = "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe" APPLICATION_ID = "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
REQUEST_ID = "amzn1.echo-api.request.0000000-0000-0000-0000-00000000000" REQUEST_ID = "amzn1.echo-api.request.0000000-0000-0000-0000-00000000000"
# pylint: disable=invalid-name # pylint: disable=invalid-name
hass = None
calls = [] calls = []
NPR_NEWS_MP3_URL = "https://pd.npr.org/anon.npr-mp3/npr/news/newscast.mp3" NPR_NEWS_MP3_URL = "https://pd.npr.org/anon.npr-mp3/npr/news/newscast.mp3"
@ -36,25 +23,16 @@ NPR_NEWS_MP3_URL = "https://pd.npr.org/anon.npr-mp3/npr/news/newscast.mp3"
STATIC_TIME = datetime.datetime.utcfromtimestamp(1476129102) STATIC_TIME = datetime.datetime.utcfromtimestamp(1476129102)
# pylint: disable=invalid-name @pytest.fixture
def setUpModule(): def alexa_client(loop, hass, test_client):
"""Initialize a Home Assistant server for testing this module.""" """Initialize a Home Assistant server for testing this module."""
global hass
hass = get_test_home_assistant()
setup.setup_component(
hass, http.DOMAIN,
{http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD,
http.CONF_SERVER_PORT: SERVER_PORT}})
@callback @callback
def mock_service(call): def mock_service(call):
calls.append(call) calls.append(call)
hass.services.register("test", "alexa", mock_service) hass.services.async_register("test", "alexa", mock_service)
setup.setup_component(hass, alexa.DOMAIN, { assert loop.run_until_complete(async_setup_component(hass, alexa.DOMAIN, {
# Key is here to verify we allow other keys in config too # Key is here to verify we allow other keys in config too
"homeassistant": {}, "homeassistant": {},
"alexa": { "alexa": {
@ -122,38 +100,22 @@ def setUpModule():
} }
} }
} }
}) }))
return loop.run_until_complete(test_client(hass.http.app))
hass.start()
# pylint: disable=invalid-name def _intent_req(client, data={}):
def tearDownModule(): return client.post(alexa.INTENTS_API_ENDPOINT, data=json.dumps(data),
"""Stop the Home Assistant server.""" headers={'content-type': 'application/json'})
hass.stop()
def _intent_req(data={}): def _flash_briefing_req(client, briefing_id):
return requests.post(INTENTS_API_URL, data=json.dumps(data), timeout=5, return client.get(
headers=HA_HEADERS) "/api/alexa/flash_briefings/{}".format(briefing_id))
def _flash_briefing_req(briefing_id=None): @asyncio.coroutine
url_format = "{}/api/alexa/flash_briefings/{}" def test_intent_launch_request(alexa_client):
FLASH_BRIEFING_API_URL = url_format.format(BASE_API_URL,
briefing_id)
return requests.get(FLASH_BRIEFING_API_URL, timeout=5,
headers=HA_HEADERS)
class TestAlexa(unittest.TestCase):
"""Test Alexa."""
def tearDown(self):
"""Stop everything that was started."""
hass.block_till_done()
def test_intent_launch_request(self):
"""Test the launch of a request.""" """Test the launch of a request."""
data = { data = {
"version": "1.0", "version": "1.0",
@ -174,12 +136,14 @@ class TestAlexa(unittest.TestCase):
"timestamp": "2015-05-13T12:34:56Z" "timestamp": "2015-05-13T12:34:56Z"
} }
} }
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
resp = req.json() resp = yield from req.json()
self.assertIn("outputSpeech", resp["response"]) assert "outputSpeech" in resp["response"]
def test_intent_request_with_slots(self):
@asyncio.coroutine
def test_intent_request_with_slots(alexa_client):
"""Test a request with slots.""" """Test a request with slots."""
data = { data = {
"version": "1.0", "version": "1.0",
@ -215,13 +179,16 @@ class TestAlexa(unittest.TestCase):
} }
} }
} }
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
text = req.json().get("response", {}).get("outputSpeech", data = yield from req.json()
text = data.get("response", {}).get("outputSpeech",
{}).get("text") {}).get("text")
self.assertEqual("You told us your sign is virgo.", text) assert text == "You told us your sign is virgo."
def test_intent_request_with_slots_but_no_value(self):
@asyncio.coroutine
def test_intent_request_with_slots_but_no_value(alexa_client):
"""Test a request with slots but no value.""" """Test a request with slots but no value."""
data = { data = {
"version": "1.0", "version": "1.0",
@ -256,13 +223,16 @@ class TestAlexa(unittest.TestCase):
} }
} }
} }
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
text = req.json().get("response", {}).get("outputSpeech", data = yield from req.json()
text = data.get("response", {}).get("outputSpeech",
{}).get("text") {}).get("text")
self.assertEqual("You told us your sign is .", text) assert text == "You told us your sign is ."
def test_intent_request_without_slots(self):
@asyncio.coroutine
def test_intent_request_without_slots(hass, alexa_client):
"""Test a request without slots.""" """Test a request without slots."""
data = { data = {
"version": "1.0", "version": "1.0",
@ -292,24 +262,27 @@ class TestAlexa(unittest.TestCase):
} }
} }
} }
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
text = req.json().get("response", {}).get("outputSpeech", json = yield from req.json()
text = json.get("response", {}).get("outputSpeech",
{}).get("text") {}).get("text")
self.assertEqual("Anne Therese is at unknown and Paulus is at unknown", assert text == "Anne Therese is at unknown and Paulus is at unknown"
text)
hass.states.set("device_tracker.paulus", "home") hass.states.async_set("device_tracker.paulus", "home")
hass.states.set("device_tracker.anne_therese", "home") hass.states.async_set("device_tracker.anne_therese", "home")
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
text = req.json().get("response", {}).get("outputSpeech", json = yield from req.json()
text = json.get("response", {}).get("outputSpeech",
{}).get("text") {}).get("text")
self.assertEqual("You are both home, you silly", text) assert text == "You are both home, you silly"
def test_intent_request_calling_service(self):
@asyncio.coroutine
def test_intent_request_calling_service(alexa_client):
"""Test a request for calling a service.""" """Test a request for calling a service."""
data = { data = {
"version": "1.0", "version": "1.0",
@ -340,16 +313,18 @@ class TestAlexa(unittest.TestCase):
} }
} }
call_count = len(calls) call_count = len(calls)
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
self.assertEqual(call_count + 1, len(calls)) assert call_count + 1 == len(calls)
call = calls[-1] call = calls[-1]
self.assertEqual("test", call.domain) assert call.domain == "test"
self.assertEqual("alexa", call.service) assert call.service == "alexa"
self.assertEqual(["switch.test"], call.data.get("entity_id")) assert call.data.get("entity_id") == ["switch.test"]
self.assertEqual("virgo", call.data.get("hello")) assert call.data.get("hello") == "virgo"
def test_intent_session_ended_request(self):
@asyncio.coroutine
def test_intent_session_ended_request(alexa_client):
"""Test the request for ending the session.""" """Test the request for ending the session."""
data = { data = {
"version": "1.0", "version": "1.0",
@ -378,11 +353,14 @@ class TestAlexa(unittest.TestCase):
} }
} }
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
self.assertEqual("", req.text) text = yield from req.text()
assert text == ''
def test_intent_from_built_in_intent_library(self):
@asyncio.coroutine
def test_intent_from_built_in_intent_library(alexa_client):
"""Test intents from the Built-in Intent Library.""" """Test intents from the Built-in Intent Library."""
data = { data = {
'request': { 'request': {
@ -435,33 +413,43 @@ class TestAlexa(unittest.TestCase):
} }
} }
} }
req = _intent_req(data) req = yield from _intent_req(alexa_client, data)
self.assertEqual(200, req.status_code) assert req.status == 200
text = req.json().get("response", {}).get("outputSpeech", data = yield from req.json()
text = data.get("response", {}).get("outputSpeech",
{}).get("text") {}).get("text")
self.assertEqual("Playing the shins.", text) assert text == "Playing the shins."
def test_flash_briefing_invalid_id(self):
@asyncio.coroutine
def test_flash_briefing_invalid_id(alexa_client):
"""Test an invalid Flash Briefing ID.""" """Test an invalid Flash Briefing ID."""
req = _flash_briefing_req() req = yield from _flash_briefing_req(alexa_client, 10000)
self.assertEqual(404, req.status_code) assert req.status == 404
self.assertEqual("", req.text) text = yield from req.text()
assert text == ''
def test_flash_briefing_date_from_str(self):
@asyncio.coroutine
def test_flash_briefing_date_from_str(alexa_client):
"""Test the response has a valid date parsed from string.""" """Test the response has a valid date parsed from string."""
req = _flash_briefing_req("weather") req = yield from _flash_briefing_req(alexa_client, "weather")
self.assertEqual(200, req.status_code) assert req.status == 200
self.assertEqual(req.json()[0].get(alexa.ATTR_UPDATE_DATE), data = yield from req.json()
"2016-10-09T19:51:42.0Z") assert data[0].get(alexa.ATTR_UPDATE_DATE) == "2016-10-09T19:51:42.0Z"
def test_flash_briefing_date_from_datetime(self):
@asyncio.coroutine
def test_flash_briefing_date_from_datetime(alexa_client):
"""Test the response has a valid date from a datetime object.""" """Test the response has a valid date from a datetime object."""
req = _flash_briefing_req("weather") req = yield from _flash_briefing_req(alexa_client, "weather")
self.assertEqual(200, req.status_code) assert req.status == 200
self.assertEqual(req.json()[1].get(alexa.ATTR_UPDATE_DATE), data = yield from req.json()
'2016-10-10T19:51:42.0Z') assert data[1].get(alexa.ATTR_UPDATE_DATE) == '2016-10-10T19:51:42.0Z'
def test_flash_briefing_valid(self):
@asyncio.coroutine
def test_flash_briefing_valid(alexa_client):
"""Test the response is valid.""" """Test the response is valid."""
data = [{ data = [{
"titleText": "NPR", "titleText": "NPR",
@ -472,7 +460,7 @@ class TestAlexa(unittest.TestCase):
"updateDate": '2016-10-10T19:51:42.0Z' "updateDate": '2016-10-10T19:51:42.0Z'
}] }]
req = _flash_briefing_req("news_audio") req = yield from _flash_briefing_req(alexa_client, "news_audio")
self.assertEqual(200, req.status_code) assert req.status == 200
response = req.json() json = yield from req.json()
self.assertEqual(response, data) assert json == data