mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-11-13 21:56:11 +00:00
158a736360
Fix playback issues that was causing Kodi to hang up
144 lines
3.9 KiB
Python
144 lines
3.9 KiB
Python
"""Pytest fixtures and other helpers for doing testing by end-users."""
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
__metaclass__ = type
|
|
|
|
from contextlib import closing
|
|
import errno
|
|
import socket
|
|
import threading
|
|
import time
|
|
|
|
import pytest
|
|
from six.moves import http_client
|
|
|
|
import cheroot.server
|
|
from cheroot.test import webtest
|
|
import cheroot.wsgi
|
|
|
|
EPHEMERAL_PORT = 0
|
|
NO_INTERFACE = None # Using this or '' will cause an exception
|
|
ANY_INTERFACE_IPV4 = '0.0.0.0'
|
|
ANY_INTERFACE_IPV6 = '::'
|
|
|
|
config = {
|
|
cheroot.wsgi.Server: {
|
|
'bind_addr': (NO_INTERFACE, EPHEMERAL_PORT),
|
|
'wsgi_app': None,
|
|
},
|
|
cheroot.server.HTTPServer: {
|
|
'bind_addr': (NO_INTERFACE, EPHEMERAL_PORT),
|
|
'gateway': cheroot.server.Gateway,
|
|
},
|
|
}
|
|
|
|
|
|
def cheroot_server(server_factory):
|
|
"""Set up and tear down a Cheroot server instance."""
|
|
conf = config[server_factory].copy()
|
|
bind_port = conf.pop('bind_addr')[-1]
|
|
|
|
for interface in ANY_INTERFACE_IPV6, ANY_INTERFACE_IPV4:
|
|
try:
|
|
actual_bind_addr = (interface, bind_port)
|
|
httpserver = server_factory( # create it
|
|
bind_addr=actual_bind_addr,
|
|
**conf
|
|
)
|
|
except OSError:
|
|
pass
|
|
else:
|
|
break
|
|
|
|
threading.Thread(target=httpserver.safe_start).start() # spawn it
|
|
while not httpserver.ready: # wait until fully initialized and bound
|
|
time.sleep(0.1)
|
|
|
|
yield httpserver
|
|
|
|
httpserver.stop() # destroy it
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def wsgi_server():
|
|
"""Set up and tear down a Cheroot WSGI server instance."""
|
|
for srv in cheroot_server(cheroot.wsgi.Server):
|
|
yield srv
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def native_server():
|
|
"""Set up and tear down a Cheroot HTTP server instance."""
|
|
for srv in cheroot_server(cheroot.server.HTTPServer):
|
|
yield srv
|
|
|
|
|
|
class _TestClient:
|
|
def __init__(self, server):
|
|
self._interface, self._host, self._port = _get_conn_data(server)
|
|
self._http_connection = self.get_connection()
|
|
self.server_instance = server
|
|
|
|
def get_connection(self):
|
|
name = '{interface}:{port}'.format(
|
|
interface=self._interface,
|
|
port=self._port,
|
|
)
|
|
return http_client.HTTPConnection(name)
|
|
|
|
def request(
|
|
self, uri, method='GET', headers=None, http_conn=None,
|
|
protocol='HTTP/1.1',
|
|
):
|
|
return webtest.openURL(
|
|
uri, method=method,
|
|
headers=headers,
|
|
host=self._host, port=self._port,
|
|
http_conn=http_conn or self._http_connection,
|
|
protocol=protocol,
|
|
)
|
|
|
|
def __getattr__(self, attr_name):
|
|
def _wrapper(uri, **kwargs):
|
|
http_method = attr_name.upper()
|
|
return self.request(uri, method=http_method, **kwargs)
|
|
|
|
return _wrapper
|
|
|
|
|
|
def _probe_ipv6_sock(interface):
|
|
# Alternate way is to check IPs on interfaces using glibc, like:
|
|
# github.com/Gautier/minifail/blob/master/minifail/getifaddrs.py
|
|
try:
|
|
with closing(socket.socket(family=socket.AF_INET6)) as sock:
|
|
sock.bind((interface, 0))
|
|
except (OSError, socket.error) as sock_err:
|
|
# In Python 3 socket.error is an alias for OSError
|
|
# In Python 2 socket.error is a subclass of IOError
|
|
if sock_err.errno != errno.EADDRNOTAVAIL:
|
|
raise
|
|
else:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def _get_conn_data(server):
|
|
if isinstance(server.bind_addr, tuple):
|
|
host, port = server.bind_addr
|
|
else:
|
|
host, port = server.bind_addr, 0
|
|
|
|
interface = webtest.interface(host)
|
|
|
|
if ':' in interface and not _probe_ipv6_sock(interface):
|
|
interface = '127.0.0.1'
|
|
if ':' in host:
|
|
host = interface
|
|
|
|
return interface, host, port
|
|
|
|
|
|
def get_server_client(server):
|
|
"""Create and return a test client for the given server."""
|
|
return _TestClient(server)
|