Skip to content

Commit e4741d0

Browse files
committed
Add Tests for the StandaloneProxy
1 parent 545a58d commit e4741d0

File tree

4 files changed

+131
-1
lines changed

4 files changed

+131
-1
lines changed

jupyter_server_proxy/standalone/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations # For Python 3.8 compatibility
2+
13
import argparse
24
import logging
35
import os

jupyter_server_proxy/standalone/proxy.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations # For Python 3.8 compatibility
2+
13
import os
24
import re
35
import ssl
@@ -157,7 +159,7 @@ def __init__(self, *args, **kwargs):
157159
app = Application(
158160
[
159161
# Redirects from the JupyterHub might not contain a slash
160-
(f"^{escaped_prefix}$", RedirectHandler, dict(url=f"^{escaped_prefix}/")),
162+
(f"^{escaped_prefix}$", RedirectHandler, dict(url=f"{escaped_prefix}/")),
161163
(f"^{escaped_prefix}/oauth_callback", HubOAuthCallbackHandler),
162164
(
163165
f"^{escaped_prefix}/(.*)",

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ dependencies = [
5252

5353
[project.optional-dependencies]
5454
test = [
55+
"jupyter-server-proxy[standalone]",
5556
"pytest",
5657
"pytest-asyncio",
5758
"pytest-cov",

tests/test_standalone.py

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import sys
2+
from pathlib import Path
3+
4+
import pytest
5+
from tornado import testing
6+
7+
from jupyter_server_proxy.standalone import _default_address_and_port, make_proxy_app
8+
9+
"""
10+
Test if address and port are identified correctly
11+
"""
12+
13+
14+
def test_address_and_port_with_http_address(monkeypatch):
15+
monkeypatch.setenv("JUPYTERHUB_SERVICE_URL", "http://localhost/")
16+
address, port = _default_address_and_port()
17+
18+
assert address == "localhost"
19+
assert port == 80
20+
21+
22+
def test_address_and_port_with_https_address(monkeypatch):
23+
monkeypatch.setenv("JUPYTERHUB_SERVICE_URL", "https://localhost/")
24+
address, port = _default_address_and_port()
25+
26+
assert address == "localhost"
27+
assert port == 443
28+
29+
30+
def test_address_and_port_with_address_and_port(monkeypatch):
31+
monkeypatch.setenv("JUPYTERHUB_SERVICE_URL", "http://localhost:7777/")
32+
address, port = _default_address_and_port()
33+
34+
assert address == "localhost"
35+
assert port == 7777
36+
37+
38+
def make_app(unix_socket: bool, skip_authentication: bool):
39+
command = [
40+
sys.executable,
41+
str(Path(__file__).parent / "resources" / "httpinfo.py"),
42+
"--port={port}",
43+
"--unix-socket={unix_socket}",
44+
]
45+
46+
return make_proxy_app(
47+
command=command,
48+
prefix="/some/prefix",
49+
port=0,
50+
unix_socket=unix_socket,
51+
environment={},
52+
mappath={},
53+
timeout=60,
54+
skip_authentication=skip_authentication,
55+
debug=True,
56+
websocket_max_message_size=0,
57+
)
58+
59+
60+
class TestStandaloneProxyRedirect(testing.AsyncHTTPTestCase):
61+
"""
62+
Ensure requests are proxied to the application. We need to disable authentication here,
63+
as we do not want to be redirected to the JupyterHub Login.
64+
"""
65+
66+
runTest = None # Required for Tornado 6.1
67+
68+
def get_app(self):
69+
return make_app(False, True)
70+
71+
def test_add_slash(self):
72+
response = self.fetch("/some/prefix", follow_redirects=False)
73+
74+
assert response.code == 301
75+
assert response.headers.get("Location") == "/some/prefix/"
76+
77+
def test_without_prefix(self):
78+
response = self.fetch("/some/other/prefix")
79+
80+
assert response.code == 404
81+
82+
def test_on_prefix(self):
83+
response = self.fetch("/some/prefix/")
84+
assert response.code == 200
85+
86+
body = response.body.decode()
87+
assert body.startswith("GET /")
88+
assert "X-Forwarded-Context: /some/prefix/" in body
89+
assert "X-Proxycontextpath: /some/prefix/" in body
90+
91+
92+
@pytest.mark.skipif(
93+
sys.platform == "win32", reason="Unix socket not supported on Windows"
94+
)
95+
class TestStandaloneProxyWithUnixSocket(testing.AsyncHTTPTestCase):
96+
runTest = None # Required for Tornado 6.1
97+
98+
def get_app(self):
99+
return make_app(True, True)
100+
101+
def test_with_unix_socket(self):
102+
response = self.fetch("/some/prefix/")
103+
assert response.code == 200
104+
105+
body = response.body.decode()
106+
assert body.startswith("GET /")
107+
assert "X-Forwarded-Context: /some/prefix/" in body
108+
assert "X-Proxycontextpath: /some/prefix/" in body
109+
110+
111+
class TestStandaloneProxyLogin(testing.AsyncHTTPTestCase):
112+
"""
113+
Ensure we redirect to JupyterHub login when authentication is enabled
114+
"""
115+
116+
runTest = None # Required for Tornado 6.1
117+
118+
def get_app(self):
119+
return make_app(False, False)
120+
121+
def test_redirect_to_login_url(self):
122+
response = self.fetch("/some/prefix/", follow_redirects=False)
123+
124+
assert response.code == 302
125+
assert "Location" in response.headers

0 commit comments

Comments
 (0)