From fd1457ee201d59386fe54d6ee507dc87eb126791 Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Mon, 16 Dec 2019 09:18:52 +0100 Subject: [PATCH] Fix issue with ASR for weather & air quality, added tests --- nabairqualityd/nabairqualityd.py | 10 +-- nabairqualityd/tests.py | 3 - nabairqualityd/tests/aqicn_test.py | 19 +++++ nabairqualityd/tests/nabairqualityd_test.py | 87 +++++++++++++++++++++ nabcommon/nabservice.py | 9 ++- nabweatherd/nabweatherd.py | 26 +++--- nabweatherd/tests/nabweatherd_test.py | 30 ++++++- 7 files changed, 152 insertions(+), 32 deletions(-) delete mode 100644 nabairqualityd/tests.py create mode 100644 nabairqualityd/tests/aqicn_test.py create mode 100644 nabairqualityd/tests/nabairqualityd_test.py diff --git a/nabairqualityd/nabairqualityd.py b/nabairqualityd/nabairqualityd.py index f3ad6e4d..489adbd6 100644 --- a/nabairqualityd/nabairqualityd.py +++ b/nabairqualityd/nabairqualityd.py @@ -3,7 +3,6 @@ import dateutil.parser from asgiref.sync import sync_to_async from nabcommon.nabservice import NabInfoCachedService -import logging from . import aqicn @@ -120,13 +119,12 @@ async def process_nabd_packet(self, packet): packet["type"] == "asr_event" and packet["nlu"]["intent"] == "airquality_forecast" ): - next_date, next_args, config = self.get_config() + next_date, next_args, config_t = await sync_to_async( + self.get_config + )() now = datetime.datetime.now(datetime.timezone.utc) expiration = now + datetime.timedelta(minutes=1) - info_data = self.fetch_info_data(config) - await self.perform_additional( - expiration, "today", info_data, config - ) + await self.perform(expiration, "today", config_t) if __name__ == "__main__": diff --git a/nabairqualityd/tests.py b/nabairqualityd/tests.py deleted file mode 100644 index 7ce503c2..00000000 --- a/nabairqualityd/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/nabairqualityd/tests/aqicn_test.py b/nabairqualityd/tests/aqicn_test.py new file mode 100644 index 00000000..bf32fa30 --- /dev/null +++ b/nabairqualityd/tests/aqicn_test.py @@ -0,0 +1,19 @@ +import unittest + +from nabairqualityd import aqicn + + +class TestAQICN(unittest.TestCase): + def do_test_index(self, index): + client = aqicn.aqicnClient(index) + client.update() + airquality = client.get_data() + self.assertTrue(isinstance(airquality, int)) + self.assertTrue(airquality >= 0) + self.assertTrue(airquality <= 2) + city = client.get_city() + self.assertTrue(isinstance(city, str)) + + def test_indexes(self): + for index in range(0, 2): + self.do_test_index(index) diff --git a/nabairqualityd/tests/nabairqualityd_test.py b/nabairqualityd/tests/nabairqualityd_test.py new file mode 100644 index 00000000..aa35b248 --- /dev/null +++ b/nabairqualityd/tests/nabairqualityd_test.py @@ -0,0 +1,87 @@ +import unittest +import json +import django +import time +import datetime +import pytest +from asgiref.sync import async_to_sync +from nabairqualityd.nabairqualityd import NabAirqualityd +from nabairqualityd import models + + +class MockWriter(object): + def __init__(self): + self.written = [] + + def write(self, packet): + self.written.append(packet) + + async def drain(self): + pass + + +@pytest.mark.django_db(transaction=True) +class TestNabAirqualityd(unittest.TestCase): + def test_fetch_info_data(self): + config = models.Config.load() + config.index_airquality = "aqi" + config.localisation = None + config.save() + service = NabAirqualityd() + data = async_to_sync(service.fetch_info_data)("aqi") + config = models.Config.load() + self.assertIsNotNone(data) + self.assertTrue(data < 3) + self.assertTrue(data >= 0) + self.assertIsNotNone(config.localisation) + + def test_perform(self): + config = models.Config.load() + config.index_airquality = "aqi" + config.localisation = None + config.save() + service = NabAirqualityd() + writer = MockWriter() + service.writer = writer + config_t = "aqi" + expiration = datetime.datetime(2019, 4, 22, 0, 0, 0) + async_to_sync(service.perform)(expiration, "today", config_t) + self.assertEqual(len(writer.written), 2) + packet = writer.written[0] + packet_json = json.loads(packet.decode("utf8")) + self.assertEqual(packet_json["type"], "info") + self.assertEqual(packet_json["info_id"], "nabairqualityd") + self.assertTrue("animation" in packet_json) + packet = writer.written[1] + packet_json = json.loads(packet.decode("utf8")) + self.assertEqual(packet_json["type"], "message") + self.assertTrue("signature" in packet_json) + self.assertTrue("body" in packet_json) + + def test_asr(self): + config = models.Config.load() + config.index_airquality = "aqi" + config.localisation = None + config.save() + service = NabAirqualityd() + writer = MockWriter() + service.writer = writer + config_t = "aqi" + expiration = datetime.datetime(2019, 4, 22, 0, 0, 0) + packet = { + "type": "asr_event", + "nlu": {"intent": "airquality_forecast"}, + } + async_to_sync(service.process_nabd_packet)(packet) + print(writer.written) + self.assertEqual(len(writer.written), 2) + packet = writer.written[0] + packet_json = json.loads(packet.decode("utf8")) + self.assertEqual(packet_json["type"], "info") + self.assertEqual(packet_json["info_id"], "nabairqualityd") + self.assertTrue("animation" in packet_json) + packet = writer.written[1] + packet_json = json.loads(packet.decode("utf8")) + self.assertEqual(packet_json["type"], "message") + self.assertTrue("signature" in packet_json) + self.assertTrue("body" in packet_json) diff --git a/nabcommon/nabservice.py b/nabcommon/nabservice.py index 028c3ac5..3606cbfb 100644 --- a/nabcommon/nabservice.py +++ b/nabcommon/nabservice.py @@ -460,11 +460,12 @@ def compute_next(self, saved_date, saved_args, config, reason): next_date = self.next_info_update(config) return next_date, "info" - def _do_fetch_info_data(self, config): + async def _do_fetch_info_data(self, config): """ Invokes fetch_info_data, used by NabInfoCachedService subclass. """ - return self.fetch_info_data(config) + info_data = await self.fetch_info_data(config) + return info_data class NabInfoCachedService(NabInfoService, ABC): @@ -481,7 +482,7 @@ def __init__(self): self.cached_info_config = None self.cached_info_expdate = None - def _do_fetch_info_data(self, config): + async def _do_fetch_info_data(self, config): """ Fetch the info data from whatever source, using config, caching it locally. @@ -495,7 +496,7 @@ def _do_fetch_info_data(self, config): ): return self.cached_info next_hour = now + datetime.timedelta(seconds=3600) - new_info = self.fetch_info_data(config) + new_info = await self.fetch_info_data(config) self.cached_info = new_info self.cached_info_config = config self.cached_info_expdate = next_hour diff --git a/nabweatherd/nabweatherd.py b/nabweatherd/nabweatherd.py index 3a23f7d9..b7349759 100644 --- a/nabweatherd/nabweatherd.py +++ b/nabweatherd/nabweatherd.py @@ -429,16 +429,13 @@ async def perform_additional(self, expiration, type, info_data, config_t): location, unit = config_t if location is None: logging.debug(f"location is None (service is unconfigured)") - if type != "info": - packet = ( - '{"type":"message",' - '"signature":{"audio":[' - '"nabweatherd/signature.mp3"]},' - '"body":[{"audio":["nabweatherd/no-location-error.mp3"]}],' - '"expiration":"' + expiration.isoformat() + '"}\r\n' - ) - self.writer.write(packet.encode("utf8")) - packet = '{"type":"info","info_id":"weather"}\r\n' + packet = ( + '{"type":"message",' + '"signature":{"audio":[' + '"nabweatherd/signature.mp3"]},' + '"body":[{"audio":["nabweatherd/no-location-error.mp3"]}],' + '"expiration":"' + expiration.isoformat() + '"}\r\n' + ) self.writer.write(packet.encode("utf8")) else: if type == "today": @@ -471,14 +468,13 @@ async def process_nabd_packet(self, packet): packet["type"] == "asr_event" and packet["nlu"]["intent"] == "weather_forecast" ): - next_date, next_args, config = self.get_config() + next_date, next_args, config_t = await sync_to_async( + self.get_config + )() # todo : detect today/tomorrow now = datetime.datetime.now(datetime.timezone.utc) expiration = now + datetime.timedelta(minutes=1) - info_data = self.fetch_info_data(config) - await self.perform_additional( - expiration, "today", info_data, config - ) + await self.perform(expiration, "today", config_t) if __name__ == "__main__": diff --git a/nabweatherd/tests/nabweatherd_test.py b/nabweatherd/tests/nabweatherd_test.py index f8d0103b..ae79d6e9 100644 --- a/nabweatherd/tests/nabweatherd_test.py +++ b/nabweatherd/tests/nabweatherd_test.py @@ -1,14 +1,12 @@ import unittest -import asyncio -import threading import json import django import time import datetime -import signal import pytest from asgiref.sync import async_to_sync from nabweatherd.nabweatherd import NabWeatherd +from nabweatherd import models class MockWriter(object): @@ -22,7 +20,6 @@ async def drain(self): pass -@pytest.mark.django_db class TestNabWeatherd(unittest.TestCase): def test_fetch_info_data(self): service = NabWeatherd() @@ -62,3 +59,28 @@ def test_aliases(self): self.assertEqual(weather_class, "J_W1_0-N_1") weather_class = service.normalize_weather_class("J_W2_4-N_1") self.assertEqual(weather_class, "J_W1_3-N_0") + + +@pytest.mark.django_db(transaction=True) +class TestNabWeatherdDB(unittest.TestCase): + def test_asr(self): + config = models.Config.load() + config.location = "75005" + config.unit = NabWeatherd.UNIT_CELSIUS + config.save() + service = NabWeatherd() + writer = MockWriter() + service.writer = writer + packet = {"type": "asr_event", "nlu": {"intent": "weather_forecast"}} + async_to_sync(service.process_nabd_packet)(packet) + self.assertEqual(len(writer.written), 2) + packet = writer.written[0] + packet_json = json.loads(packet.decode("utf8")) + self.assertEqual(packet_json["type"], "info") + self.assertEqual(packet_json["info_id"], "nabweatherd") + self.assertTrue("animation" in packet_json) + packet = writer.written[1] + packet_json = json.loads(packet.decode("utf8")) + self.assertEqual(packet_json["type"], "message") + self.assertTrue("signature" in packet_json) + self.assertTrue("body" in packet_json)