From ca284763bce55817c4c15260fdee29213d30f4e1 Mon Sep 17 00:00:00 2001 From: Jonathan Windgassen Date: Fri, 15 Nov 2024 13:37:01 +0100 Subject: [PATCH] Add Tests for the StandaloneProxy --- jupyter_server_proxy/standalone/proxy.py | 2 +- tests/test_standalone.py | 119 +++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 tests/test_standalone.py diff --git a/jupyter_server_proxy/standalone/proxy.py b/jupyter_server_proxy/standalone/proxy.py index a00181fd..4613cc68 100644 --- a/jupyter_server_proxy/standalone/proxy.py +++ b/jupyter_server_proxy/standalone/proxy.py @@ -157,7 +157,7 @@ def __init__(self, *args, **kwargs): app = Application( [ # Redirects from the JupyterHub might not contain a slash - (f"^{escaped_prefix}$", RedirectHandler, dict(url=f"^{escaped_prefix}/")), + (f"^{escaped_prefix}$", RedirectHandler, dict(url=f"{escaped_prefix}/")), (f"^{escaped_prefix}/oauth_callback", HubOAuthCallbackHandler), ( f"^{escaped_prefix}/(.*)", diff --git a/tests/test_standalone.py b/tests/test_standalone.py new file mode 100644 index 00000000..0137e8ca --- /dev/null +++ b/tests/test_standalone.py @@ -0,0 +1,119 @@ +import sys +from pathlib import Path + +import pytest +from tornado.testing import AsyncHTTPTestCase + +from jupyter_server_proxy.standalone import _default_address_and_port, make_proxy_app + +""" +Test if address and port are identified correctly +""" + + +def test_address_and_port_with_http_address(monkeypatch): + monkeypatch.setenv("JUPYTERHUB_SERVICE_URL", "http://localhost/") + address, port = _default_address_and_port() + + assert address == "localhost" + assert port == 80 + + +def test_address_and_port_with_https_address(monkeypatch): + monkeypatch.setenv("JUPYTERHUB_SERVICE_URL", "https://localhost/") + address, port = _default_address_and_port() + + assert address == "localhost" + assert port == 443 + + +def test_address_and_port_with_address_and_port(monkeypatch): + monkeypatch.setenv("JUPYTERHUB_SERVICE_URL", "http://localhost:7777/") + address, port = _default_address_and_port() + + assert address == "localhost" + assert port == 7777 + + +def make_app(unix_socket: bool, skip_authentication: bool): + command = [ + sys.executable, + str(Path(__file__).parent / "resources" / "httpinfo.py"), + "--port={port}", + "--unix-socket={unix_socket}", + ] + + return make_proxy_app( + command=command, + prefix="/some/prefix", + port=0, + unix_socket=unix_socket, + environment={}, + mappath={}, + timeout=60, + skip_authentication=skip_authentication, + debug=True, + websocket_max_message_size=0, + ) + + +class TestStandaloneProxyRedirect(AsyncHTTPTestCase): + """ + Ensure requests are proxied to the application. We need to disable authentication here, + as we do not want to be redirected to the JupyterHub Login. + """ + + def get_app(self): + return make_app(False, True) + + def test_add_slash(self): + response = self.fetch("/some/prefix", follow_redirects=False) + + assert response.code == 301 + assert response.headers.get("Location") == "/some/prefix/" + + def test_without_prefix(self): + response = self.fetch("/some/other/prefix") + + assert response.code == 404 + + def test_on_prefix(self): + response = self.fetch("/some/prefix/") + assert response.code == 200 + + body = response.body.decode() + assert body.startswith("GET /") + assert "X-Forwarded-Context: /some/prefix/" in body + assert "X-Proxycontextpath: /some/prefix/" in body + + +@pytest.mark.skipif( + sys.platform == "win32", reason="Unix socket not supported on Windows" +) +class TestStandaloneProxyWithUnixSocket(AsyncHTTPTestCase): + def get_app(self): + return make_app(True, True) + + def test_with_unix_socket(self): + response = self.fetch("/some/prefix/") + assert response.code == 200 + + body = response.body.decode() + assert body.startswith("GET /") + assert "X-Forwarded-Context: /some/prefix/" in body + assert "X-Proxycontextpath: /some/prefix/" in body + + +class TestStandaloneProxyLogin(AsyncHTTPTestCase): + """ + Ensure we redirect to JupyterHub login when authentication is enabled + """ + + def get_app(self): + return make_app(False, False) + + def test_redirect_to_login_url(self): + response = self.fetch("/some/prefix/", follow_redirects=False) + + assert response.code == 302 + assert "Location" in response.headers