mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-12-28 11:46:11 +00:00
194 lines
5.1 KiB
Python
194 lines
5.1 KiB
Python
|
"""Tests for the HTTP server."""
|
||
|
# -*- coding: utf-8 -*-
|
||
|
# vim: set fileencoding=utf-8 :
|
||
|
|
||
|
from __future__ import absolute_import, division, print_function
|
||
|
__metaclass__ = type
|
||
|
|
||
|
import os
|
||
|
import socket
|
||
|
import tempfile
|
||
|
import threading
|
||
|
import time
|
||
|
|
||
|
import pytest
|
||
|
|
||
|
from .._compat import bton
|
||
|
from ..server import Gateway, HTTPServer
|
||
|
from ..testing import (
|
||
|
ANY_INTERFACE_IPV4,
|
||
|
ANY_INTERFACE_IPV6,
|
||
|
EPHEMERAL_PORT,
|
||
|
get_server_client,
|
||
|
)
|
||
|
|
||
|
|
||
|
def make_http_server(bind_addr):
|
||
|
"""Create and start an HTTP server bound to bind_addr."""
|
||
|
httpserver = HTTPServer(
|
||
|
bind_addr=bind_addr,
|
||
|
gateway=Gateway,
|
||
|
)
|
||
|
|
||
|
threading.Thread(target=httpserver.safe_start).start()
|
||
|
|
||
|
while not httpserver.ready:
|
||
|
time.sleep(0.1)
|
||
|
|
||
|
return httpserver
|
||
|
|
||
|
|
||
|
non_windows_sock_test = pytest.mark.skipif(
|
||
|
not hasattr(socket, 'AF_UNIX'),
|
||
|
reason='UNIX domain sockets are only available under UNIX-based OS',
|
||
|
)
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def http_server():
|
||
|
"""Provision a server creator as a fixture."""
|
||
|
def start_srv():
|
||
|
bind_addr = yield
|
||
|
httpserver = make_http_server(bind_addr)
|
||
|
yield httpserver
|
||
|
yield httpserver
|
||
|
|
||
|
srv_creator = iter(start_srv())
|
||
|
next(srv_creator)
|
||
|
yield srv_creator
|
||
|
try:
|
||
|
while True:
|
||
|
httpserver = next(srv_creator)
|
||
|
if httpserver is not None:
|
||
|
httpserver.stop()
|
||
|
except StopIteration:
|
||
|
pass
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def unix_sock_file():
|
||
|
"""Check that bound UNIX socket address is stored in server."""
|
||
|
tmp_sock_fh, tmp_sock_fname = tempfile.mkstemp()
|
||
|
|
||
|
yield tmp_sock_fname
|
||
|
|
||
|
os.close(tmp_sock_fh)
|
||
|
os.unlink(tmp_sock_fname)
|
||
|
|
||
|
|
||
|
def test_prepare_makes_server_ready():
|
||
|
"""Check that prepare() makes the server ready, and stop() clears it."""
|
||
|
httpserver = HTTPServer(
|
||
|
bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT),
|
||
|
gateway=Gateway,
|
||
|
)
|
||
|
|
||
|
assert not httpserver.ready
|
||
|
assert not httpserver.requests._threads
|
||
|
|
||
|
httpserver.prepare()
|
||
|
|
||
|
assert httpserver.ready
|
||
|
assert httpserver.requests._threads
|
||
|
for thr in httpserver.requests._threads:
|
||
|
assert thr.ready
|
||
|
|
||
|
httpserver.stop()
|
||
|
|
||
|
assert not httpserver.requests._threads
|
||
|
assert not httpserver.ready
|
||
|
|
||
|
|
||
|
def test_stop_interrupts_serve():
|
||
|
"""Check that stop() interrupts running of serve()."""
|
||
|
httpserver = HTTPServer(
|
||
|
bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT),
|
||
|
gateway=Gateway,
|
||
|
)
|
||
|
|
||
|
httpserver.prepare()
|
||
|
serve_thread = threading.Thread(target=httpserver.serve)
|
||
|
serve_thread.start()
|
||
|
|
||
|
serve_thread.join(0.5)
|
||
|
assert serve_thread.is_alive()
|
||
|
|
||
|
httpserver.stop()
|
||
|
|
||
|
serve_thread.join(0.5)
|
||
|
assert not serve_thread.is_alive()
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize(
|
||
|
'ip_addr',
|
||
|
(
|
||
|
ANY_INTERFACE_IPV4,
|
||
|
ANY_INTERFACE_IPV6,
|
||
|
)
|
||
|
)
|
||
|
def test_bind_addr_inet(http_server, ip_addr):
|
||
|
"""Check that bound IP address is stored in server."""
|
||
|
httpserver = http_server.send((ip_addr, EPHEMERAL_PORT))
|
||
|
|
||
|
assert httpserver.bind_addr[0] == ip_addr
|
||
|
assert httpserver.bind_addr[1] != EPHEMERAL_PORT
|
||
|
|
||
|
|
||
|
@non_windows_sock_test
|
||
|
def test_bind_addr_unix(http_server, unix_sock_file):
|
||
|
"""Check that bound UNIX socket address is stored in server."""
|
||
|
httpserver = http_server.send(unix_sock_file)
|
||
|
|
||
|
assert httpserver.bind_addr == unix_sock_file
|
||
|
|
||
|
|
||
|
@pytest.mark.skip(reason="Abstract sockets don't work currently")
|
||
|
@non_windows_sock_test
|
||
|
def test_bind_addr_unix_abstract(http_server):
|
||
|
"""Check that bound UNIX socket address is stored in server."""
|
||
|
unix_abstract_sock = b'\x00cheroot/test/socket/here.sock'
|
||
|
httpserver = http_server.send(unix_abstract_sock)
|
||
|
|
||
|
assert httpserver.bind_addr == unix_abstract_sock
|
||
|
|
||
|
|
||
|
PEERCRED_IDS_URI = '/peer_creds/ids'
|
||
|
PEERCRED_TEXTS_URI = '/peer_creds/texts'
|
||
|
|
||
|
|
||
|
class _TestGateway(Gateway):
|
||
|
def respond(self):
|
||
|
req = self.req
|
||
|
conn = req.conn
|
||
|
req_uri = bton(req.uri)
|
||
|
if req_uri == PEERCRED_IDS_URI:
|
||
|
peer_creds = conn.peer_pid, conn.peer_uid, conn.peer_gid
|
||
|
return ['|'.join(map(str, peer_creds))]
|
||
|
elif req_uri == PEERCRED_TEXTS_URI:
|
||
|
return ['!'.join((conn.peer_user, conn.peer_group))]
|
||
|
return super(_TestGateway, self).respond()
|
||
|
|
||
|
|
||
|
@pytest.mark.skip(
|
||
|
reason='Test HTTP client is not able to work through UNIX socket currently'
|
||
|
)
|
||
|
@non_windows_sock_test
|
||
|
def test_peercreds_unix_sock(http_server, unix_sock_file):
|
||
|
"""Check that peercred lookup and resolution work when enabled."""
|
||
|
httpserver = http_server.send(unix_sock_file)
|
||
|
httpserver.gateway = _TestGateway
|
||
|
httpserver.peercreds_enabled = True
|
||
|
|
||
|
testclient = get_server_client(httpserver)
|
||
|
|
||
|
expected_peercreds = os.getpid(), os.getuid(), os.getgid()
|
||
|
expected_peercreds = '|'.join(map(str, expected_peercreds))
|
||
|
assert testclient.get(PEERCRED_IDS_URI) == expected_peercreds
|
||
|
assert 'RuntimeError' in testclient.get(PEERCRED_TEXTS_URI)
|
||
|
|
||
|
httpserver.peercreds_resolve_enabled = True
|
||
|
import grp
|
||
|
expected_textcreds = os.getlogin(), grp.getgrgid(os.getgid()).gr_name
|
||
|
expected_textcreds = '!'.join(map(str, expected_textcreds))
|
||
|
assert testclient.get(PEERCRED_TEXTS_URI) == expected_textcreds
|