diff --git a/homeassistant/components/cloud/cloudhooks.py b/homeassistant/components/cloud/cloudhooks.py index fdf7bb2a12e..3c638d29166 100644 --- a/homeassistant/components/cloud/cloudhooks.py +++ b/homeassistant/components/cloud/cloudhooks.py @@ -18,7 +18,7 @@ class Cloudhooks: await self.cloud.iot.async_send_message('webhook-register', { 'cloudhook_ids': [info['cloudhook_id'] for info in cloudhooks.values()] - }) + }, expect_answer=False) async def async_create(self, webhook_id): """Create a cloud webhook.""" diff --git a/homeassistant/components/cloud/iot.py b/homeassistant/components/cloud/iot.py index 3c7275afa7a..7d633a4b2ac 100644 --- a/homeassistant/components/cloud/iot.py +++ b/homeassistant/components/cloud/iot.py @@ -28,6 +28,10 @@ class UnknownHandler(Exception): """Exception raised when trying to handle unknown handler.""" +class NotConnected(Exception): + """Exception raised when trying to handle unknown handler.""" + + class ErrorMessage(Exception): """Exception raised when there was error handling message in the cloud.""" @@ -116,10 +120,17 @@ class CloudIoT: if remove_hass_stop_listener is not None: remove_hass_stop_listener() - async def async_send_message(self, handler, payload): + async def async_send_message(self, handler, payload, + expect_answer=True): """Send a message.""" + if self.state != STATE_CONNECTED: + raise NotConnected + msgid = uuid.uuid4().hex - self._response_handler[msgid] = asyncio.Future() + + if expect_answer: + fut = self._response_handler[msgid] = asyncio.Future() + message = { 'msgid': msgid, 'handler': handler, @@ -130,6 +141,9 @@ class CloudIoT: pprint.pformat(message)) await self.client.send_json(message) + if expect_answer: + return await fut + @asyncio.coroutine def _handle_connection(self): """Connect to the IoT broker.""" diff --git a/tests/components/cloud/test_iot.py b/tests/components/cloud/test_iot.py index 10488779dd8..b11de7da4e4 100644 --- a/tests/components/cloud/test_iot.py +++ b/tests/components/cloud/test_iot.py @@ -451,3 +451,51 @@ async def test_webhook_msg(hass): assert await received[0].json() == { 'hello': 'world' } + + +async def test_send_message_not_connected(mock_cloud): + """Test sending a message that expects no answer.""" + cloud_iot = iot.CloudIoT(mock_cloud) + + with pytest.raises(iot.NotConnected): + await cloud_iot.async_send_message('webhook', {'msg': 'yo'}) + + +async def test_send_message_no_answer(mock_cloud): + """Test sending a message that expects no answer.""" + cloud_iot = iot.CloudIoT(mock_cloud) + cloud_iot.state = iot.STATE_CONNECTED + cloud_iot.client = MagicMock(send_json=MagicMock(return_value=mock_coro())) + + await cloud_iot.async_send_message('webhook', {'msg': 'yo'}, + expect_answer=False) + assert not cloud_iot._response_handler + assert len(cloud_iot.client.send_json.mock_calls) == 1 + msg = cloud_iot.client.send_json.mock_calls[0][1][0] + assert msg['handler'] == 'webhook' + assert msg['payload'] == {'msg': 'yo'} + + +async def test_send_message_answer(loop, mock_cloud): + """Test sending a message that expects no answer.""" + cloud_iot = iot.CloudIoT(mock_cloud) + cloud_iot.state = iot.STATE_CONNECTED + cloud_iot.client = MagicMock(send_json=MagicMock(return_value=mock_coro())) + + uuid = 5 + + with patch('homeassistant.components.cloud.iot.uuid.uuid4', + return_value=MagicMock(hex=uuid)): + send_task = loop.create_task(cloud_iot.async_send_message( + 'webhook', {'msg': 'yo'})) + await asyncio.sleep(0) + + assert len(cloud_iot.client.send_json.mock_calls) == 1 + assert len(cloud_iot._response_handler) == 1 + msg = cloud_iot.client.send_json.mock_calls[0][1][0] + assert msg['handler'] == 'webhook' + assert msg['payload'] == {'msg': 'yo'} + + cloud_iot._response_handler[uuid].set_result({'response': True}) + response = await send_task + assert response == {'response': True}