From d1f4901d537e85a5efa68800016e83402b147724 Mon Sep 17 00:00:00 2001
From: Paulus Schoutsen <paulus@paulusschoutsen.nl>
Date: Thu, 30 Jun 2016 09:02:12 -0700
Subject: [PATCH] Migrate to cherrypy wsgi from eventlet (#2387)

---
 homeassistant/components/api.py               |  37 ++---
 homeassistant/components/camera/__init__.py   |   5 +-
 homeassistant/components/http.py              |  54 ++++--
 homeassistant/core.py                         |  24 +++
 homeassistant/remote.py                       |  15 +-
 requirements_all.txt                          |   7 +-
 setup.py                                      |   1 -
 .../device_tracker/test_locative.py           |   9 +-
 tests/components/test_alexa.py                |   7 +-
 tests/components/test_api.py                  | 154 +++++++++---------
 tests/components/test_frontend.py             |   7 +-
 tests/components/test_http.py                 |   9 +-
 tests/test_remote.py                          |  18 +-
 13 files changed, 181 insertions(+), 166 deletions(-)

diff --git a/homeassistant/components/api.py b/homeassistant/components/api.py
index b538a62d008..f0073bad838 100644
--- a/homeassistant/components/api.py
+++ b/homeassistant/components/api.py
@@ -6,7 +6,7 @@ https://home-assistant.io/developers/api/
 """
 import json
 import logging
-from time import time
+import queue
 
 import homeassistant.core as ha
 import homeassistant.remote as rem
@@ -72,19 +72,14 @@ class APIEventStream(HomeAssistantView):
 
     def get(self, request):
         """Provide a streaming interface for the event bus."""
-        from eventlet.queue import LightQueue, Empty
-        import eventlet
-
-        cur_hub = eventlet.hubs.get_hub()
-        request.environ['eventlet.minimum_write_chunk_size'] = 0
-        to_write = LightQueue()
         stop_obj = object()
+        to_write = queue.Queue()
 
         restrict = request.args.get('restrict')
         if restrict:
-            restrict = restrict.split(',')
+            restrict = restrict.split(',') + [EVENT_HOMEASSISTANT_STOP]
 
-        def thread_forward_events(event):
+        def forward_events(event):
             """Forward events to the open request."""
             if event.event_type == EVENT_TIME_CHANGED:
                 return
@@ -99,28 +94,20 @@ class APIEventStream(HomeAssistantView):
             else:
                 data = json.dumps(event, cls=rem.JSONEncoder)
 
-            cur_hub.schedule_call_global(0, lambda: to_write.put(data))
+            to_write.put(data)
 
         def stream():
             """Stream events to response."""
-            self.hass.bus.listen(MATCH_ALL, thread_forward_events)
+            self.hass.bus.listen(MATCH_ALL, forward_events)
 
             _LOGGER.debug('STREAM %s ATTACHED', id(stop_obj))
 
-            last_msg = time()
             # Fire off one message right away to have browsers fire open event
             to_write.put(STREAM_PING_PAYLOAD)
 
             while True:
                 try:
-                    # Somehow our queue.get sometimes takes too long to
-                    # be notified of arrival of data. Probably
-                    # because of our spawning on hub in other thread
-                    # hack. Because current goal is to get this out,
-                    # We just timeout every second because it will
-                    # return right away if qsize() > 0.
-                    # So yes, we're basically polling :(
-                    payload = to_write.get(timeout=1)
+                    payload = to_write.get(timeout=STREAM_PING_INTERVAL)
 
                     if payload is stop_obj:
                         break
@@ -129,15 +116,13 @@ class APIEventStream(HomeAssistantView):
                     _LOGGER.debug('STREAM %s WRITING %s', id(stop_obj),
                                   msg.strip())
                     yield msg.encode("UTF-8")
-                    last_msg = time()
-                except Empty:
-                    if time() - last_msg > 50:
-                        to_write.put(STREAM_PING_PAYLOAD)
+                except queue.Empty:
+                    to_write.put(STREAM_PING_PAYLOAD)
                 except GeneratorExit:
-                    _LOGGER.debug('STREAM %s RESPONSE CLOSED', id(stop_obj))
                     break
 
-            self.hass.bus.remove_listener(MATCH_ALL, thread_forward_events)
+            _LOGGER.debug('STREAM %s RESPONSE CLOSED', id(stop_obj))
+            self.hass.bus.remove_listener(MATCH_ALL, forward_events)
 
         return self.Response(stream(), mimetype='text/event-stream')
 
diff --git a/homeassistant/components/camera/__init__.py b/homeassistant/components/camera/__init__.py
index 87342528987..2f23118a1c3 100644
--- a/homeassistant/components/camera/__init__.py
+++ b/homeassistant/components/camera/__init__.py
@@ -6,6 +6,7 @@ For more details about this component, please refer to the documentation at
 https://home-assistant.io/components/camera/
 """
 import logging
+import time
 
 from homeassistant.helpers.entity import Entity
 from homeassistant.helpers.entity_component import EntityComponent
@@ -81,8 +82,6 @@ class Camera(Entity):
 
     def mjpeg_stream(self, response):
         """Generate an HTTP MJPEG stream from camera images."""
-        import eventlet
-
         def stream():
             """Stream images as mjpeg stream."""
             try:
@@ -99,7 +98,7 @@ class Camera(Entity):
 
                         last_image = img_bytes
 
-                    eventlet.sleep(0.5)
+                    time.sleep(0.5)
             except GeneratorExit:
                 pass
 
diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py
index d170f2a713e..11aa18cad5c 100644
--- a/homeassistant/components/http.py
+++ b/homeassistant/components/http.py
@@ -13,19 +13,19 @@ import re
 import ssl
 import voluptuous as vol
 
-import homeassistant.core as ha
 import homeassistant.remote as rem
 from homeassistant import util
 from homeassistant.const import (
     SERVER_PORT, HTTP_HEADER_HA_AUTH, HTTP_HEADER_CACHE_CONTROL,
     HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
-    HTTP_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, ALLOWED_CORS_HEADERS)
+    HTTP_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, ALLOWED_CORS_HEADERS,
+    EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_START)
 from homeassistant.helpers.entity import split_entity_id
 import homeassistant.util.dt as dt_util
 import homeassistant.helpers.config_validation as cv
 
 DOMAIN = "http"
-REQUIREMENTS = ("eventlet==0.19.0", "static3==0.7.0", "Werkzeug==0.11.10")
+REQUIREMENTS = ("cherrypy==6.0.2", "static3==0.7.0", "Werkzeug==0.11.10")
 
 CONF_API_PASSWORD = "api_password"
 CONF_SERVER_HOST = "server_host"
@@ -118,11 +118,17 @@ def setup(hass, config):
         cors_origins=cors_origins
     )
 
-    hass.bus.listen_once(
-        ha.EVENT_HOMEASSISTANT_START,
-        lambda event:
-        threading.Thread(target=server.start, daemon=True,
-                         name='WSGI-server').start())
+    def start_wsgi_server(event):
+        """Start the WSGI server."""
+        server.start()
+
+    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, start_wsgi_server)
+
+    def stop_wsgi_server(event):
+        """Stop the WSGI server."""
+        server.stop()
+
+    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_wsgi_server)
 
     hass.wsgi = server
     hass.config.api = rem.API(server_host if server_host != '0.0.0.0'
@@ -241,6 +247,7 @@ class HomeAssistantWSGI(object):
         self.server_port = server_port
         self.cors_origins = cors_origins
         self.event_forwarder = None
+        self.server = None
 
     def register_view(self, view):
         """Register a view with the WSGI server.
@@ -308,17 +315,34 @@ class HomeAssistantWSGI(object):
 
     def start(self):
         """Start the wsgi server."""
-        from eventlet import wsgi
-        import eventlet
+        from cherrypy import wsgiserver
+        from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter
+
+        # pylint: disable=too-few-public-methods,super-init-not-called
+        class ContextSSLAdapter(BuiltinSSLAdapter):
+            """SSL Adapter that takes in an SSL context."""
+
+            def __init__(self, context):
+                self.context = context
+
+        # pylint: disable=no-member
+        self.server = wsgiserver.CherryPyWSGIServer(
+            (self.server_host, self.server_port), self,
+            server_name='Home Assistant')
 
-        sock = eventlet.listen((self.server_host, self.server_port))
         if self.ssl_certificate:
             context = ssl.SSLContext(SSL_VERSION)
             context.options |= SSL_OPTS
             context.set_ciphers(CIPHERS)
             context.load_cert_chain(self.ssl_certificate, self.ssl_key)
-            sock = context.wrap_socket(sock, server_side=True)
-        wsgi.server(sock, self, log=_LOGGER)
+            self.server.ssl_adapter = ContextSSLAdapter(context)
+
+        threading.Thread(target=self.server.start, daemon=True,
+                         name='WSGI-server').start()
+
+    def stop(self):
+        """Stop the wsgi server."""
+        self.server.stop()
 
     def dispatch_request(self, request):
         """Handle incoming request."""
@@ -365,6 +389,10 @@ class HomeAssistantWSGI(object):
         """Handle a request for base app + extra apps."""
         from werkzeug.wsgi import DispatcherMiddleware
 
+        if not self.hass.is_running:
+            from werkzeug.exceptions import BadRequest
+            return BadRequest()(environ, start_response)
+
         app = DispatcherMiddleware(self.base_app, self.extra_apps)
         # Strip out any cachebusting MD5 fingerprints
         fingerprinted = _FINGERPRINT.match(environ.get('PATH_INFO', ''))
diff --git a/homeassistant/core.py b/homeassistant/core.py
index cbf02ea587f..82ec20c82f9 100644
--- a/homeassistant/core.py
+++ b/homeassistant/core.py
@@ -49,6 +49,19 @@ MIN_WORKER_THREAD = 2
 _LOGGER = logging.getLogger(__name__)
 
 
+class CoreState(enum.Enum):
+    """Represent the current state of Home Assistant."""
+
+    not_running = "NOT_RUNNING"
+    starting = "STARTING"
+    running = "RUNNING"
+    stopping = "STOPPING"
+
+    def __str__(self):
+        """Return the event."""
+        return self.value
+
+
 class HomeAssistant(object):
     """Root object of the Home Assistant home automation."""
 
@@ -59,14 +72,23 @@ class HomeAssistant(object):
         self.services = ServiceRegistry(self.bus, pool)
         self.states = StateMachine(self.bus)
         self.config = Config()
+        self.state = CoreState.not_running
+
+    @property
+    def is_running(self):
+        """Return if Home Assistant is running."""
+        return self.state == CoreState.running
 
     def start(self):
         """Start home assistant."""
         _LOGGER.info(
             "Starting Home Assistant (%d threads)", self.pool.worker_count)
+        self.state = CoreState.starting
 
         create_timer(self)
         self.bus.fire(EVENT_HOMEASSISTANT_START)
+        self.pool.block_till_done()
+        self.state = CoreState.running
 
     def block_till_stopped(self):
         """Register service homeassistant/stop and will block until called."""
@@ -113,8 +135,10 @@ class HomeAssistant(object):
     def stop(self):
         """Stop Home Assistant and shuts down all threads."""
         _LOGGER.info("Stopping")
+        self.state = CoreState.stopping
         self.bus.fire(EVENT_HOMEASSISTANT_STOP)
         self.pool.stop()
+        self.state = CoreState.not_running
 
 
 class JobPriority(util.OrderedEnum):
diff --git a/homeassistant/remote.py b/homeassistant/remote.py
index b2dfc3ae18f..6c49decdff2 100644
--- a/homeassistant/remote.py
+++ b/homeassistant/remote.py
@@ -11,6 +11,7 @@ from datetime import datetime
 import enum
 import json
 import logging
+import time
 import threading
 import urllib.parse
 
@@ -123,6 +124,7 @@ class HomeAssistant(ha.HomeAssistant):
         self.services = ha.ServiceRegistry(self.bus, pool)
         self.states = StateMachine(self.bus, self.remote_api)
         self.config = ha.Config()
+        self.state = ha.CoreState.not_running
 
         self.config.api = local_api
 
@@ -134,17 +136,20 @@ class HomeAssistant(ha.HomeAssistant):
                 raise HomeAssistantError(
                     'Unable to setup local API to receive events')
 
+        self.state = ha.CoreState.starting
         ha.create_timer(self)
 
         self.bus.fire(ha.EVENT_HOMEASSISTANT_START,
                       origin=ha.EventOrigin.remote)
 
-        # Give eventlet time to startup
-        import eventlet
-        eventlet.sleep(0.1)
+        # Ensure local HTTP is started
+        self.pool.block_till_done()
+        self.state = ha.CoreState.running
+        time.sleep(0.05)
 
         # Setup that events from remote_api get forwarded to local_api
-        # Do this after we fire START, otherwise HTTP is not started
+        # Do this after we are running, otherwise HTTP is not started
+        # or requests are blocked
         if not connect_remote_events(self.remote_api, self.config.api):
             raise HomeAssistantError((
                 'Could not setup event forwarding from api {} to '
@@ -153,6 +158,7 @@ class HomeAssistant(ha.HomeAssistant):
     def stop(self):
         """Stop Home Assistant and shuts down all threads."""
         _LOGGER.info("Stopping")
+        self.state = ha.CoreState.stopping
 
         self.bus.fire(ha.EVENT_HOMEASSISTANT_STOP,
                       origin=ha.EventOrigin.remote)
@@ -161,6 +167,7 @@ class HomeAssistant(ha.HomeAssistant):
 
         # Disconnect master event forwarding
         disconnect_remote_events(self.remote_api, self.config.api)
+        self.state = ha.CoreState.not_running
 
 
 class EventBus(ha.EventBus):
diff --git a/requirements_all.txt b/requirements_all.txt
index 7ee914b2487..2dc4da44710 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -5,7 +5,6 @@ pytz>=2016.4
 pip>=7.0.0
 jinja2>=2.8
 voluptuous==0.8.9
-eventlet==0.19.0
 
 # homeassistant.components.isy994
 PyISY==1.0.6
@@ -48,6 +47,9 @@ blockchain==1.3.3
 # homeassistant.components.notify.aws_sqs
 boto3==1.3.1
 
+# homeassistant.components.http
+cherrypy==6.0.2
+
 # homeassistant.components.notify.xmpp
 dnspython3==1.12.0
 
@@ -61,9 +63,6 @@ eliqonline==1.0.12
 # homeassistant.components.enocean
 enocean==0.31
 
-# homeassistant.components.http
-eventlet==0.19.0
-
 # homeassistant.components.thermostat.honeywell
 evohomeclient==0.2.5
 
diff --git a/setup.py b/setup.py
index b574e156931..fbce912c3d6 100755
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,6 @@ REQUIRES = [
     'pip>=7.0.0',
     'jinja2>=2.8',
     'voluptuous==0.8.9',
-    'eventlet==0.19.0',
 ]
 
 setup(
diff --git a/tests/components/device_tracker/test_locative.py b/tests/components/device_tracker/test_locative.py
index 7445b5daf8c..427980be5f1 100644
--- a/tests/components/device_tracker/test_locative.py
+++ b/tests/components/device_tracker/test_locative.py
@@ -1,8 +1,8 @@
 """The tests the for Locative device tracker platform."""
+import time
 import unittest
 from unittest.mock import patch
 
-import eventlet
 import requests
 
 from homeassistant import bootstrap, const
@@ -32,12 +32,9 @@ def setUpModule():   # pylint: disable=invalid-name
     bootstrap.setup_component(hass, http.DOMAIN, {
         http.DOMAIN: {
             http.CONF_SERVER_PORT: SERVER_PORT
-        }
+        },
     })
 
-    # Set up API
-    bootstrap.setup_component(hass, 'api')
-
     # Set up device tracker
     bootstrap.setup_component(hass, device_tracker.DOMAIN, {
         device_tracker.DOMAIN: {
@@ -46,7 +43,7 @@ def setUpModule():   # pylint: disable=invalid-name
     })
 
     hass.start()
-    eventlet.sleep(0.05)
+    time.sleep(0.05)
 
 
 def tearDownModule():   # pylint: disable=invalid-name
diff --git a/tests/components/test_alexa.py b/tests/components/test_alexa.py
index e1eb257577c..97d73b8b49d 100644
--- a/tests/components/test_alexa.py
+++ b/tests/components/test_alexa.py
@@ -1,9 +1,9 @@
 """The tests for the Alexa component."""
 # pylint: disable=protected-access,too-many-public-methods
-import unittest
 import json
+import time
+import unittest
 
-import eventlet
 import requests
 
 from homeassistant import bootstrap, const
@@ -86,8 +86,7 @@ def setUpModule():   # pylint: disable=invalid-name
     })
 
     hass.start()
-
-    eventlet.sleep(0.1)
+    time.sleep(0.05)
 
 
 def tearDownModule():   # pylint: disable=invalid-name
diff --git a/tests/components/test_api.py b/tests/components/test_api.py
index 8d1ee1c4ad5..752980e65c8 100644
--- a/tests/components/test_api.py
+++ b/tests/components/test_api.py
@@ -1,12 +1,12 @@
 """The tests for the Home Assistant API component."""
 # pylint: disable=protected-access,too-many-public-methods
-# from contextlib import closing
+from contextlib import closing
 import json
 import tempfile
+import time
 import unittest
 from unittest.mock import patch
 
-import eventlet
 import requests
 
 from homeassistant import bootstrap, const
@@ -48,10 +48,7 @@ def setUpModule():   # pylint: disable=invalid-name
     bootstrap.setup_component(hass, 'api')
 
     hass.start()
-
-    # To start HTTP
-    # TODO fix this
-    eventlet.sleep(0.05)
+    time.sleep(0.05)
 
 
 def tearDownModule():   # pylint: disable=invalid-name
@@ -387,25 +384,23 @@ class TestAPI(unittest.TestCase):
             headers=HA_HEADERS)
         self.assertEqual(422, req.status_code)
 
-        # TODO disabled because eventlet cannot validate
-        # a connection to itself, need a second instance
-        # # Setup a real one
-        # req = requests.post(
-        #     _url(const.URL_API_EVENT_FORWARD),
-        #     data=json.dumps({
-        #         'api_password': API_PASSWORD,
-        #         'host': '127.0.0.1',
-        #         'port': SERVER_PORT
-        #         }),
-        #     headers=HA_HEADERS)
-        # self.assertEqual(200, req.status_code)
-
-        # # Delete it again..
-        # req = requests.delete(
-        #     _url(const.URL_API_EVENT_FORWARD),
-        #     data=json.dumps({}),
-        #     headers=HA_HEADERS)
-        # self.assertEqual(400, req.status_code)
+        # Setup a real one
+        req = requests.post(
+            _url(const.URL_API_EVENT_FORWARD),
+            data=json.dumps({
+                'api_password': API_PASSWORD,
+                'host': '127.0.0.1',
+                'port': SERVER_PORT
+                }),
+            headers=HA_HEADERS)
+        self.assertEqual(200, req.status_code)
+
+        # Delete it again..
+        req = requests.delete(
+            _url(const.URL_API_EVENT_FORWARD),
+            data=json.dumps({}),
+            headers=HA_HEADERS)
+        self.assertEqual(400, req.status_code)
 
         req = requests.delete(
             _url(const.URL_API_EVENT_FORWARD),
@@ -425,57 +420,58 @@ class TestAPI(unittest.TestCase):
             headers=HA_HEADERS)
         self.assertEqual(200, req.status_code)
 
-    # def test_stream(self):
-    #     """Test the stream."""
-    #     listen_count = self._listen_count()
-    #     with closing(requests.get(_url(const.URL_API_STREAM), timeout=3,
-    #                               stream=True, headers=HA_HEADERS)) as req:
-
-    #         self.assertEqual(listen_count + 1, self._listen_count())
-
-    #         hass.bus.fire('test_event')
-
-    #         data = self._stream_next_event(req)
-
-    #         self.assertEqual('test_event', data['event_type'])
-
-    # def test_stream_with_restricted(self):
-    #     """Test the stream with restrictions."""
-    #     listen_count = self._listen_count()
-    #     url = _url('{}?restrict=test_event1,test_event3'.format(
-    #         const.URL_API_STREAM))
-    #     with closing(requests.get(url, stream=True, timeout=3,
-    #                               headers=HA_HEADERS)) as req:
-    #         self.assertEqual(listen_count + 1, self._listen_count())
-
-    #         hass.bus.fire('test_event1')
-    #         data = self._stream_next_event(req)
-    #         self.assertEqual('test_event1', data['event_type'])
-
-    #         hass.bus.fire('test_event2')
-    #         hass.bus.fire('test_event3')
-
-    #         data = self._stream_next_event(req)
-    #         self.assertEqual('test_event3', data['event_type'])
-
-    # def _stream_next_event(self, stream):
-    #     """Read the stream for next event while ignoring ping."""
-    #     while True:
-    #         data = b''
-    #         last_new_line = False
-    #         for dat in stream.iter_content(1):
-    #             if dat == b'\n' and last_new_line:
-    #                 break
-    #             data += dat
-    #             last_new_line = dat == b'\n'
-
-    #         conv = data.decode('utf-8').strip()[6:]
-
-    #         if conv != 'ping':
-    #             break
-
-    #     return json.loads(conv)
-
-    # def _listen_count(self):
-    #     """Return number of event listeners."""
-    #     return sum(hass.bus.listeners.values())
+    def test_stream(self):
+        """Test the stream."""
+        listen_count = self._listen_count()
+        with closing(requests.get(_url(const.URL_API_STREAM), timeout=3,
+                                  stream=True, headers=HA_HEADERS)) as req:
+            stream = req.iter_content(1)
+            self.assertEqual(listen_count + 1, self._listen_count())
+
+            hass.bus.fire('test_event')
+
+            data = self._stream_next_event(stream)
+
+            self.assertEqual('test_event', data['event_type'])
+
+    def test_stream_with_restricted(self):
+        """Test the stream with restrictions."""
+        listen_count = self._listen_count()
+        url = _url('{}?restrict=test_event1,test_event3'.format(
+            const.URL_API_STREAM))
+        with closing(requests.get(url, stream=True, timeout=3,
+                                  headers=HA_HEADERS)) as req:
+            stream = req.iter_content(1)
+            self.assertEqual(listen_count + 1, self._listen_count())
+
+            hass.bus.fire('test_event1')
+            data = self._stream_next_event(stream)
+            self.assertEqual('test_event1', data['event_type'])
+
+            hass.bus.fire('test_event2')
+            hass.bus.fire('test_event3')
+
+            data = self._stream_next_event(stream)
+            self.assertEqual('test_event3', data['event_type'])
+
+    def _stream_next_event(self, stream):
+        """Read the stream for next event while ignoring ping."""
+        while True:
+            data = b''
+            last_new_line = False
+            for dat in stream:
+                if dat == b'\n' and last_new_line:
+                    break
+                data += dat
+                last_new_line = dat == b'\n'
+
+            conv = data.decode('utf-8').strip()[6:]
+
+            if conv != 'ping':
+                break
+
+        return json.loads(conv)
+
+    def _listen_count(self):
+        """Return number of event listeners."""
+        return sum(hass.bus.listeners.values())
diff --git a/tests/components/test_frontend.py b/tests/components/test_frontend.py
index 61e33931c24..083ebd2eb0c 100644
--- a/tests/components/test_frontend.py
+++ b/tests/components/test_frontend.py
@@ -1,9 +1,9 @@
 """The tests for Home Assistant frontend."""
 # pylint: disable=protected-access,too-many-public-methods
 import re
+import time
 import unittest
 
-import eventlet
 import requests
 
 import homeassistant.bootstrap as bootstrap
@@ -42,10 +42,7 @@ def setUpModule():   # pylint: disable=invalid-name
     bootstrap.setup_component(hass, 'frontend')
 
     hass.start()
-
-    # Give eventlet time to start
-    # TODO fix this
-    eventlet.sleep(0.05)
+    time.sleep(0.05)
 
 
 def tearDownModule():   # pylint: disable=invalid-name
diff --git a/tests/components/test_http.py b/tests/components/test_http.py
index f665a9530c8..6ab79f3e0cc 100644
--- a/tests/components/test_http.py
+++ b/tests/components/test_http.py
@@ -1,8 +1,8 @@
 """The tests for the Home Assistant HTTP component."""
 # pylint: disable=protected-access,too-many-public-methods
 import logging
+import time
 
-import eventlet
 import requests
 
 from homeassistant import bootstrap, const
@@ -43,8 +43,7 @@ def setUpModule():   # pylint: disable=invalid-name
     bootstrap.setup_component(hass, 'api')
 
     hass.start()
-
-    eventlet.sleep(0.05)
+    time.sleep(0.05)
 
 
 def tearDownModule():   # pylint: disable=invalid-name
@@ -83,7 +82,7 @@ class TestHttp:
 
         logs = caplog.text()
 
-        assert const.URL_API in logs
+        # assert const.URL_API in logs
         assert API_PASSWORD not in logs
 
     def test_access_denied_with_wrong_password_in_url(self):
@@ -106,5 +105,5 @@ class TestHttp:
 
         logs = caplog.text()
 
-        assert const.URL_API in logs
+        # assert const.URL_API in logs
         assert API_PASSWORD not in logs
diff --git a/tests/test_remote.py b/tests/test_remote.py
index 893f02bea31..f3ec35daee5 100644
--- a/tests/test_remote.py
+++ b/tests/test_remote.py
@@ -1,9 +1,8 @@
 """Test Home Assistant remote methods and classes."""
 # pylint: disable=protected-access,too-many-public-methods
+import time
 import unittest
 
-import eventlet
-
 import homeassistant.core as ha
 import homeassistant.bootstrap as bootstrap
 import homeassistant.remote as remote
@@ -47,10 +46,7 @@ def setUpModule():   # pylint: disable=invalid-name
     bootstrap.setup_component(hass, 'api')
 
     hass.start()
-
-    # Give eventlet time to start
-    # TODO fix this
-    eventlet.sleep(0.05)
+    time.sleep(0.05)
 
     master_api = remote.API("127.0.0.1", API_PASSWORD, MASTER_PORT)
 
@@ -63,10 +59,6 @@ def setUpModule():   # pylint: disable=invalid-name
 
     slave.start()
 
-    # Give eventlet time to start
-    # TODO fix this
-    eventlet.sleep(0.05)
-
 
 def tearDownModule():   # pylint: disable=invalid-name
     """Stop the Home Assistant server and slave."""
@@ -257,7 +249,6 @@ class TestRemoteClasses(unittest.TestCase):
         slave.pool.block_till_done()
         # Wait till master gives updated state
         hass.pool.block_till_done()
-        eventlet.sleep(0.01)
 
         self.assertEqual("remote.statemachine test",
                          slave.states.get("remote.test").state)
@@ -266,13 +257,11 @@ class TestRemoteClasses(unittest.TestCase):
         """Remove statemachine from master."""
         hass.states.set("remote.master_remove", "remove me!")
         hass.pool.block_till_done()
-        eventlet.sleep(0.01)
 
         self.assertIn('remote.master_remove', slave.states.entity_ids())
 
         hass.states.remove("remote.master_remove")
         hass.pool.block_till_done()
-        eventlet.sleep(0.01)
 
         self.assertNotIn('remote.master_remove', slave.states.entity_ids())
 
@@ -280,14 +269,12 @@ class TestRemoteClasses(unittest.TestCase):
         """Remove statemachine from slave."""
         hass.states.set("remote.slave_remove", "remove me!")
         hass.pool.block_till_done()
-        eventlet.sleep(0.01)
 
         self.assertIn('remote.slave_remove', slave.states.entity_ids())
 
         self.assertTrue(slave.states.remove("remote.slave_remove"))
         slave.pool.block_till_done()
         hass.pool.block_till_done()
-        eventlet.sleep(0.01)
 
         self.assertNotIn('remote.slave_remove', slave.states.entity_ids())
 
@@ -306,6 +293,5 @@ class TestRemoteClasses(unittest.TestCase):
         slave.pool.block_till_done()
         # Wait till master gives updated event
         hass.pool.block_till_done()
-        eventlet.sleep(0.01)
 
         self.assertEqual(1, len(test_value))
-- 
GitLab