python-tuf/tests/utils.py
Jussi Kukkonen 740be9cdb6 tests: Avoid sleep(): make sure servers really start
* Add utility function to wait on a socket until it responds
* Use the function instead of sleeping in tests that need to wait for
  the server to start
* Increase the max timeout to 5 seconds by default (as appveyor builds
  still seem to hit the 3 second mark sometimes)

wait_for_server() functions quite differently depending on OS: Windows
can take 2 seconds to respond with ECONNREFUSED whereas Linux is almost
instant. There might be tricks to be faster on Windows (like setting
a shorter socket timeout) but this was not done here.

This makes a full Linux test run almost 40% faster and should be more
reproducible on every platform.

Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
2020-08-10 16:11:33 +03:00

76 lines
1.8 KiB
Python

#!/usr/bin/env python
# Copyright 2020, TUF contributors
# SPDX-License-Identifier: MIT OR Apache-2.0
"""
<Program Name>
utils.py
<Started>
August 3, 2020.
<Author>
Jussi Kukkonen
<Copyright>
See LICENSE-MIT OR LICENSE for licensing information.
<Purpose>
Provide common utilities for TUF tests
"""
import errno
import logging
import socket
import time
logger = logging.getLogger(__name__)
try:
# is defined in Python 3
TimeoutError
except NameError:
# Define for Python 2
class TimeoutError(Exception):
def __init__(self, value="Timeout"):
self.value = value
def __str__(self):
return repr(self.value)
# Wait until host:port accepts connections.
# Raises TimeoutError if this does not happen within timeout seconds
# There are major differences between operating systems on how this works
# but the current blocking connect() seems to work fast on Linux and seems
# to at least work on Windows (ECONNREFUSED unfortunately has a 2 second
# timeout on Windows)
def wait_for_server(host, port, timeout=5):
start = time.time()
remaining_timeout = timeout
succeeded = False
while not succeeded and remaining_timeout > 0:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(remaining_timeout)
sock.connect((host, port))
succeeded = True
except socket.timeout as e:
pass
except IOError as e:
# ECONNREFUSED is expected while the server is not started
if e.errno not in [errno.ECONNREFUSED]:
logger.warning("Unexpected error while waiting for server: " + str(e))
# Avoid pegging a core just for this
time.sleep(0.01)
finally:
if sock:
sock.close()
sock = None
remaining_timeout = timeout - (time.time() - start)
if not succeeded:
raise TimeoutError