diff --git a/homeassistant/components/notify/html5.py b/homeassistant/components/notify/html5.py index a05c061c515..2314722a2ab 100644 --- a/homeassistant/components/notify/html5.py +++ b/homeassistant/components/notify/html5.py @@ -8,7 +8,6 @@ import asyncio import datetime import json import logging -import os import time import uuid @@ -16,6 +15,8 @@ from aiohttp.hdrs import AUTHORIZATION import voluptuous as vol from voluptuous.humanize import humanize_error +from homeassistant.util.json import load_json, save_json +from homeassistant.exceptions import HomeAssistantError from homeassistant.components.frontend import add_manifest_json_key from homeassistant.components.http import HomeAssistantView from homeassistant.components.notify import ( @@ -125,21 +126,11 @@ def get_service(hass, config, discovery_info=None): def _load_config(filename): """Load configuration.""" - if not os.path.isfile(filename): - return {} - try: - with open(filename, 'r') as fdesc: - inp = fdesc.read() - - # In case empty file - if not inp: - return {} - - return json.loads(inp) - except (IOError, ValueError) as error: - _LOGGER.error("Reading config file %s failed: %s", filename, error) - return None + return load_json(filename) + except HomeAssistantError: + pass + return {} class JSONBytesDecoder(json.JSONEncoder): @@ -153,18 +144,6 @@ class JSONBytesDecoder(json.JSONEncoder): return json.JSONEncoder.default(self, obj) -def _save_config(filename, config): - """Save configuration.""" - try: - with open(filename, 'w') as fdesc: - fdesc.write(json.dumps( - config, cls=JSONBytesDecoder, indent=4, sort_keys=True)) - except (IOError, TypeError) as error: - _LOGGER.error("Saving configuration file failed: %s", error) - return False - return True - - class HTML5PushRegistrationView(HomeAssistantView): """Accepts push registrations from a browser.""" @@ -194,7 +173,7 @@ class HTML5PushRegistrationView(HomeAssistantView): self.registrations[name] = data - if not _save_config(self.json_path, self.registrations): + if not save_json(self.json_path, self.registrations): return self.json_message( 'Error saving registration.', HTTP_INTERNAL_SERVER_ERROR) @@ -223,7 +202,7 @@ class HTML5PushRegistrationView(HomeAssistantView): reg = self.registrations.pop(found) - if not _save_config(self.json_path, self.registrations): + if not save_json(self.json_path, self.registrations): self.registrations[found] = reg return self.json_message( 'Error saving registration.', HTTP_INTERNAL_SERVER_ERROR) @@ -411,8 +390,8 @@ class HTML5NotificationService(BaseNotificationService): if response.status_code == 410: _LOGGER.info("Notification channel has expired") reg = self.registrations.pop(target) - if not _save_config(self.registrations_json_path, - self.registrations): + if not save_json(self.registrations_json_path, + self.registrations): self.registrations[target] = reg _LOGGER.error("Error saving registration") else: diff --git a/tests/components/notify/test_html5.py b/tests/components/notify/test_html5.py index 2c39cc5dbd7..c3998b6db64 100644 --- a/tests/components/notify/test_html5.py +++ b/tests/components/notify/test_html5.py @@ -57,24 +57,13 @@ class TestHtml5Notify(object): m = mock_open() with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): service = html5.get_service(hass, {}) assert service is not None - def test_get_service_with_bad_json(self): - """Test .""" - hass = MagicMock() - - m = mock_open(read_data='I am not JSON') - with patch( - 'homeassistant.components.notify.html5.open', m, create=True - ): - service = html5.get_service(hass, {}) - - assert service is None - @patch('pywebpush.WebPusher') def test_sending_message(self, mock_wp): """Test sending message.""" @@ -86,7 +75,8 @@ class TestHtml5Notify(object): m = mock_open(read_data=json.dumps(data)) with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): service = html5.get_service(hass, {'gcm_sender_id': '100'}) @@ -120,7 +110,8 @@ class TestHtml5Notify(object): m = mock_open() with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): hass.config.path.return_value = 'file.conf' service = html5.get_service(hass, {}) @@ -158,7 +149,8 @@ class TestHtml5Notify(object): m = mock_open() with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): hass.config.path.return_value = 'file.conf' service = html5.get_service(hass, {}) @@ -193,7 +185,8 @@ class TestHtml5Notify(object): m = mock_open() with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): hass.config.path.return_value = 'file.conf' service = html5.get_service(hass, {}) @@ -222,7 +215,7 @@ class TestHtml5Notify(object): })) assert resp.status == 400 - with patch('homeassistant.components.notify.html5._save_config', + with patch('homeassistant.components.notify.html5.save_json', return_value=False): # resp = view.post(Request(builder.get_environ())) resp = yield from client.post(REGISTER_URL, data=json.dumps({ @@ -243,14 +236,12 @@ class TestHtml5Notify(object): } m = mock_open(read_data=json.dumps(config)) - - with patch('homeassistant.components.notify.html5.open', m, - create=True): + with patch( + 'homeassistant.util.json.open', + m, create=True + ): hass.config.path.return_value = 'file.conf' - - with patch('homeassistant.components.notify.html5.os.path.isfile', - return_value=True): - service = html5.get_service(hass, {}) + service = html5.get_service(hass, {}) assert service is not None @@ -291,12 +282,11 @@ class TestHtml5Notify(object): m = mock_open(read_data=json.dumps(config)) with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): hass.config.path.return_value = 'file.conf' - with patch('homeassistant.components.notify.html5.os.path.isfile', - return_value=True): - service = html5.get_service(hass, {}) + service = html5.get_service(hass, {}) assert service is not None @@ -324,7 +314,7 @@ class TestHtml5Notify(object): @asyncio.coroutine def test_unregistering_device_view_handles_json_safe_error( - self, loop, test_client): + self, loop, test_client): """Test that the HTML unregister view handles JSON write errors.""" hass = MagicMock() @@ -335,12 +325,11 @@ class TestHtml5Notify(object): m = mock_open(read_data=json.dumps(config)) with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): hass.config.path.return_value = 'file.conf' - with patch('homeassistant.components.notify.html5.os.path.isfile', - return_value=True): - service = html5.get_service(hass, {}) + service = html5.get_service(hass, {}) assert service is not None @@ -357,7 +346,7 @@ class TestHtml5Notify(object): client = yield from test_client(app) hass.http.is_banned_ip.return_value = False - with patch('homeassistant.components.notify.html5._save_config', + with patch('homeassistant.components.notify.html5.save_json', return_value=False): resp = yield from client.delete(REGISTER_URL, data=json.dumps({ 'subscription': SUBSCRIPTION_1['subscription'], @@ -375,7 +364,8 @@ class TestHtml5Notify(object): m = mock_open() with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): hass.config.path.return_value = 'file.conf' service = html5.get_service(hass, {}) @@ -406,17 +396,16 @@ class TestHtml5Notify(object): hass = MagicMock() data = { - 'device': SUBSCRIPTION_1, + 'device': SUBSCRIPTION_1 } m = mock_open(read_data=json.dumps(data)) with patch( - 'homeassistant.components.notify.html5.open', m, create=True + 'homeassistant.util.json.open', + m, create=True ): hass.config.path.return_value = 'file.conf' - with patch('homeassistant.components.notify.html5.os.path.isfile', - return_value=True): - service = html5.get_service(hass, {'gcm_sender_id': '100'}) + service = html5.get_service(hass, {'gcm_sender_id': '100'}) assert service is not None