jetforce/tests/test_jetforce.py

102 lines
3.2 KiB
Python
Raw Normal View History

import os
import ssl
import socket
import unittest
from threading import Thread
from twisted.internet import reactor
from jetforce import StaticDirectoryApplication, GeminiServer
ROOT_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data")
class GeminiTestServer(GeminiServer):
real_port: int
def on_bind_interface(self, port):
"""
Capture the port number that the test server actually binds to.
"""
sock_ip, sock_port, *_ = port.socket.getsockname()
self.real_port = sock_port
def log_access(self, message: str) -> None:
"""Suppress logging"""
def log_message(self, message: str) -> None:
"""Suppress logging"""
class FunctionalTestCase(unittest.TestCase):
"""
This class will spin up a complete test jetforce server and serve it
on a local TCP port in a new thread. The tests will send real gemini
connection strings to the server and check the validity of the response
body from end-to-end.
"""
server: GeminiTestServer
thread: Thread
@classmethod
def setUpClass(cls):
app = StaticDirectoryApplication(root_directory=ROOT_DIR)
cls.server = GeminiTestServer(app=app, port=0)
cls.server.initialize()
cls.thread = Thread(target=reactor.run, args=(False,))
cls.thread.start()
@classmethod
def tearDownClass(cls):
reactor.callFromThread(reactor.stop)
cls.thread.join(timeout=5)
@classmethod
def request(cls, data):
"""
Send bytes to the server using a TCP/IP socket.
"""
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
with socket.create_connection((cls.server.host, cls.server.real_port)) as sock:
with context.wrap_socket(sock) as ssock:
ssock.sendall(data)
fp = ssock.makefile("rb")
return fp.read()
def test_index(self):
resp = self.request(b"gemini://localhost\r\n")
self.assertEqual(resp, b"20 text/gemini\r\nJetforce rules!\n")
def test_invalid_path(self):
resp = self.request(b"gemini://localhost/invalid\r\n")
self.assertEqual(resp, b"51 Not Found\r\n")
def test_invalid_hostname(self):
resp = self.request(b"gemini://example.com\r\n")
self.assertEqual(resp, b"53 This server does not allow proxy requests\r\n")
def test_invalid_port(self):
resp = self.request(b"gemini://localhost:1111\r\n")
self.assertEqual(resp, b"53 This server does not allow proxy requests\r\n")
def test_directory_redirect(self):
resp = self.request(b"gemini://localhost/cgi-bin\r\n")
self.assertEqual(resp, b"31 gemini://localhost/cgi-bin/\r\n")
def test_directory(self):
resp = self.request(b"gemini://localhost/cgi-bin/\r\n")
self.assertEqual(resp.splitlines(keepends=True)[0], b"20 text/gemini\r\n")
def test_cgi_script(self):
resp = self.request(b"gemini://localhost/cgi-bin/echo.cgi?hello%20world\r\n")
self.assertEqual(resp, b"20 text/plain\r\nhello%20world\n")
if __name__ == "__main__":
unittest.main()