Skip to content

Commit 2064957

Browse files
committed
Add basic terminal manager tests
1 parent cd9b1a8 commit 2064957

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

notebook/terminal/tests/__init__.py

Whitespace-only changes.
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
"""Test the terminal service API."""
2+
3+
import time
4+
5+
from requests import HTTPError
6+
from traitlets.config import Config
7+
8+
from notebook.utils import url_path_join
9+
from notebook.tests.launchnotebook import NotebookTestBase, assert_http_error
10+
11+
12+
class TerminalAPI(object):
13+
"""Wrapper for terminal REST API requests"""
14+
def __init__(self, request, base_url, headers):
15+
self.request = request
16+
self.base_url = base_url
17+
self.headers = headers
18+
19+
def _req(self, verb, path, body=None):
20+
response = self.request(verb, path, data=body)
21+
22+
if 400 <= response.status_code < 600:
23+
try:
24+
response.reason = response.json()['message']
25+
except:
26+
pass
27+
response.raise_for_status()
28+
29+
return response
30+
31+
def list(self):
32+
return self._req('GET', 'api/terminals')
33+
34+
def get(self, name):
35+
return self._req('GET', url_path_join('api/terminals', name))
36+
37+
def start(self):
38+
return self._req('POST', 'api/terminals')
39+
40+
def shutdown(self, name):
41+
return self._req('DELETE', url_path_join('api/terminals', name))
42+
43+
44+
class TerminalAPITest(NotebookTestBase):
45+
"""Test the terminals web service API"""
46+
def setUp(self):
47+
self.term_api = TerminalAPI(self.request,
48+
base_url=self.base_url(),
49+
headers=self.auth_headers(),
50+
)
51+
52+
def tearDown(self):
53+
for k in self.term_api.list().json():
54+
self.term_api.shutdown(k['name'])
55+
56+
def test_no_terminals(self):
57+
# Make sure there are no terminals running at the start
58+
terminals = self.term_api.list().json()
59+
self.assertEqual(terminals, [])
60+
61+
def test_create_terminal(self):
62+
# POST request
63+
r = self.term_api._req('POST', 'api/terminals')
64+
term1 = r.json()
65+
self.assertEqual(r.status_code, 200)
66+
self.assertIsInstance(term1, dict)
67+
68+
def test_terminal_root_handler(self):
69+
# POST request
70+
r = self.term_api.start()
71+
term1 = r.json()
72+
self.assertEqual(r.status_code, 200)
73+
self.assertIsInstance(term1, dict)
74+
75+
# GET request
76+
r = self.term_api.list()
77+
self.assertEqual(r.status_code, 200)
78+
assert isinstance(r.json(), list)
79+
self.assertEqual(r.json()[0]['name'], term1['name'])
80+
81+
# create another terminal and check that they both are added to the
82+
# list of terminals from a GET request
83+
term2 = self.term_api.start().json()
84+
assert isinstance(term2, dict)
85+
r = self.term_api.list()
86+
terminals = r.json()
87+
self.assertEqual(r.status_code, 200)
88+
assert isinstance(terminals, list)
89+
self.assertEqual(len(terminals), 2)
90+
91+
def test_terminal_handler(self):
92+
# GET terminal with given name
93+
term = self.term_api.start().json()['name']
94+
r = self.term_api.get(term)
95+
term1 = r.json()
96+
self.assertEqual(r.status_code, 200)
97+
assert isinstance(term1, dict)
98+
self.assertIn('name', term1)
99+
self.assertEqual(term1['name'], term)
100+
101+
# Request a bad terminal id and check that a JSON
102+
# message is returned!
103+
bad_term = 'nonExistentTerm'
104+
with assert_http_error(404, 'Terminal not found: ' + bad_term):
105+
self.term_api.get(bad_term)
106+
107+
# DELETE terminal with name
108+
r = self.term_api.shutdown(term)
109+
self.assertEqual(r.status_code, 204)
110+
terminals = self.term_api.list().json()
111+
self.assertEqual(terminals, [])
112+
113+
# Request to delete a non-existent terminal name
114+
bad_term = 'nonExistentTerm'
115+
with assert_http_error(404, 'Terminal not found: ' + bad_term):
116+
self.term_api.shutdown(bad_term)
117+
118+
119+
class TerminalCullingTest(NotebookTestBase):
120+
121+
# Configure culling
122+
config = Config({
123+
'NotebookApp': {
124+
'TerminalManager': {
125+
'cull_interval': 3,
126+
'cull_inactive_timeout': 2
127+
}
128+
}
129+
})
130+
131+
def setUp(self):
132+
self.term_api = TerminalAPI(self.request,
133+
base_url=self.base_url(),
134+
headers=self.auth_headers(),
135+
)
136+
137+
def tearDown(self):
138+
for k in self.term_api.list().json():
139+
self.term_api.shutdown(k['name'])
140+
141+
# Sanity check verifying that the configurable was properly set.
142+
def test_config(self):
143+
self.assertEqual(self.config.NotebookApp.TerminalManager.cull_inactive_timeout, 2)
144+
self.assertEqual(self.config.NotebookApp.TerminalManager.cull_interval, 3)
145+
terminal_mgr = self.notebook.web_app.settings['terminal_manager']
146+
self.assertEqual(terminal_mgr.cull_inactive_timeout, 2)
147+
self.assertEqual(terminal_mgr.cull_interval, 3)
148+
149+
def test_culling(self):
150+
# POST request
151+
r = self.term_api.start()
152+
self.assertEqual(r.status_code, 200)
153+
body = r.json()
154+
term1 = body['name']
155+
last_activity = body['last_activity']
156+
157+
culled = False
158+
for i in range(10): # Culling should occur in a few seconds
159+
try:
160+
r = self.term_api.get(term1)
161+
except HTTPError as e:
162+
self.assertEqual(e.response.status_code, 404)
163+
culled = True
164+
break
165+
else:
166+
self.assertEqual(r.status_code, 200)
167+
time.sleep(1)
168+
169+
self.assertTrue(culled)

0 commit comments

Comments
 (0)