Skip to content

Commit bd966ca

Browse files
Add frontend and backend tests for manager
1 parent 86d0ad9 commit bd966ca

File tree

2 files changed

+179
-1
lines changed

2 files changed

+179
-1
lines changed

tests/acceptance/Lab.robot

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ Launch Browser Tab
1717
Location Should Contain foo
1818
Page Should Contain Hello World
1919
Close Window
20-
[Teardown] Switch Window title:JupyterLab
20+
Switch Window title:JupyterLab
21+
Click RunningSessions
22+
Click RefreshSessions
23+
Capture Page Screenshot 01-running.png
24+
Click Shutdown
25+
Capture Page Screenshot 02-shutdown.png
26+
[Teardown]
2127

2228
Launch Lab Tab
2329
Click Launcher bar
@@ -34,3 +40,13 @@ Start Lab Tests
3440
Click Launcher
3541
[Arguments] ${title}
3642
Click Element css:.jp-LauncherCard-label[title^\="${title}"]
43+
44+
Click RunningSessions
45+
Click Element css:#tab-key-1-0
46+
47+
Click RefreshSessions
48+
Click Element css:.jp-Button.jp-ToolbarButtonComponent[title^\="Refresh List"]
49+
50+
Click ShutDown
51+
Mouse Over css:.jp-RunningSessions-itemShutdown[title^\="Shut Down"]
52+
Click Element css:.jp-RunningSessions-itemShutdown[title^\="Shut Down"]

tests/test_api.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
"""Tests for API endpoints"""
2+
3+
import os
4+
import pytest
5+
import time
6+
import json
7+
8+
from typing import Tuple
9+
10+
from traitlets.config.loader import PyFileConfigLoader
11+
12+
from http.client import HTTPConnection
13+
14+
# use ipv4 for CI, etc.
15+
LOCALHOST = "127.0.0.1"
16+
17+
18+
def request_get(port, path, token, host=LOCALHOST):
19+
h = HTTPConnection(host, port, 10)
20+
if "?" in path:
21+
url = f"{path}&token={token}"
22+
else:
23+
url = f"{path}?token={token}"
24+
h.request("GET", url)
25+
return h.getresponse()
26+
27+
28+
def request_delete(port, path, token, host=LOCALHOST):
29+
h = HTTPConnection(host, port, 10)
30+
if "?" in path:
31+
url = f"{path}&token={token}"
32+
else:
33+
url = f"{path}?token={token}"
34+
h.request("DELETE", url)
35+
return h.getresponse()
36+
37+
38+
def load_config():
39+
"""Load config file"""
40+
config_file_path = os.path.join(
41+
os.path.dirname(os.path.abspath(__file__)),
42+
'resources', 'jupyter_server_config.py'
43+
)
44+
cl = PyFileConfigLoader(config_file_path)
45+
return cl.load_config()
46+
47+
48+
def start_proxies(PORT, TOKEN):
49+
"""Start proxy servers for testing API handlers"""
50+
selected_servers = [
51+
"python-http",
52+
"python-unix-socket-true",
53+
"python-websocket"
54+
]
55+
for url in selected_servers:
56+
_ = request_get(PORT, f"/{url}/", TOKEN)
57+
return selected_servers
58+
59+
60+
def test_server_proxy_info(
61+
a_server_port_and_token: Tuple[int, str]
62+
) -> None:
63+
"""Test API endpoint of /server-proxy/api/servers-info."""
64+
PORT, TOKEN = a_server_port_and_token
65+
config = load_config()
66+
test_url = '/server-proxy/api/servers-info'
67+
expected_servers = list(config['ServerProxy']['servers'].keys())
68+
r = request_get(PORT, test_url, TOKEN)
69+
data = json.loads(r.read().decode())
70+
found_servers = [sp["name"] for sp in data['server_processes']]
71+
assert r.code == 200
72+
assert found_servers == expected_servers
73+
74+
75+
def test_get_all_server_proxy(
76+
a_server_port_and_token: Tuple[int, str]
77+
) -> None:
78+
"""Test API endpoint of /server-proxy/api/servers."""
79+
PORT, TOKEN = a_server_port_and_token
80+
expected_servers = start_proxies(PORT, TOKEN)
81+
test_url = '/server-proxy/api/servers/'
82+
r = request_get(PORT, test_url, TOKEN)
83+
data = json.loads(r.read().decode())
84+
found_servers = [sp["name"] for sp in data]
85+
assert r.code == 200
86+
assert found_servers == expected_servers
87+
88+
89+
@pytest.mark.parametrize(
90+
"server_process_path",
91+
[
92+
"python-http",
93+
"python-unix-socket-true",
94+
"python-websocket",
95+
],
96+
)
97+
def test_get_given_server_proxy(
98+
server_process_path: str, a_server_port_and_token: Tuple[int, str]
99+
) -> None:
100+
"""Test API GET endpoint of /server-proxy/api/servers/{name}."""
101+
PORT, TOKEN = a_server_port_and_token
102+
# config = load_config()
103+
# expected_data = config['ServerProxy']['servers'][server_process_path]
104+
_ = request_get(PORT, f"/{server_process_path}/", TOKEN)
105+
test_url = f'/server-proxy/api/servers/{server_process_path}'
106+
r = request_get(PORT, test_url, TOKEN)
107+
data = json.loads(r.read().decode())
108+
assert r.code == 200
109+
assert data['name'] == server_process_path
110+
if server_process_path in ['python-http', 'python-websocket']:
111+
assert isinstance(int(data['port']), int)
112+
assert data['managed'] == True
113+
assert data['unix_socket'] == ''
114+
elif server_process_path == 'python-unix-socket-true':
115+
assert int(data['port']) == 0
116+
assert 'jupyter-server-proxy' in data['unix_socket']
117+
assert data['managed'] == True
118+
119+
120+
def test_get_nonexisting_server_proxy(
121+
a_server_port_and_token: Tuple[int, str]
122+
) -> None:
123+
"""Test API non existing GET endpoint of /server-proxy/api/servers/{name}."""
124+
PORT, TOKEN = a_server_port_and_token
125+
test_url = '/server-proxy/api/servers/doesnotexist'
126+
r = request_get(PORT, test_url, TOKEN)
127+
assert r.code == 404
128+
129+
130+
@pytest.mark.parametrize(
131+
"server_process_path",
132+
[
133+
"python-http",
134+
"python-unix-socket-true",
135+
"python-websocket",
136+
],
137+
)
138+
def test_delete_given_server_proxy(
139+
server_process_path: str, a_server_port_and_token: Tuple[int, str]
140+
) -> None:
141+
"""Test API DELETE endpoint of /server-proxy/api/servers/{name}."""
142+
PORT, TOKEN = a_server_port_and_token
143+
_ = request_get(PORT, f"/{server_process_path}/", TOKEN)
144+
# Just give enough time for it to be added in manager if it does not exist already
145+
time.sleep(1)
146+
test_url = f'/server-proxy/api/servers/{server_process_path}'
147+
r = request_delete(PORT, test_url, TOKEN)
148+
assert r.code == 204
149+
150+
151+
def test_delete_nonexisting_server_proxy(
152+
a_server_port_and_token: Tuple[int, str]
153+
) -> None:
154+
"""Test API DELETE non existing endpoint of /server-proxy/api/servers/{name}."""
155+
PORT, TOKEN = a_server_port_and_token
156+
test_url = '/server-proxy/api/servers/doesnotexist'
157+
r = request_delete(PORT, test_url, TOKEN)
158+
assert r.code == 404
159+
# When no server name is supplied
160+
test_url = '/server-proxy/api/servers/'
161+
r = request_delete(PORT, test_url, TOKEN)
162+
assert r.code == 403

0 commit comments

Comments
 (0)