-
Notifications
You must be signed in to change notification settings - Fork 313
/
test_auth.py
194 lines (149 loc) · 7.52 KB
/
test_auth.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import os
import pytest
import requests_mock
from traitlets.config import Config
from ..auth import Authenticator, JupyterHubAuthPlugin
from ..auth.jupyterhub import JupyterhubEnvironmentError, JupyterhubApiError
from _pytest.fixtures import SubRequest
@pytest.fixture
def env(request: SubRequest) -> dict:
old_env = os.environ.copy()
def fin() -> None:
os.environ = old_env
request.addfinalizer(fin)
return os.environ
@pytest.fixture
def jupyterhub_auth() -> Authenticator:
config = Config()
config.Authenticator.plugin_class = JupyterHubAuthPlugin
auth = Authenticator(config=config)
return auth
def _mock_api_call(method, path, status_code=None, json=None):
hub_api_url = 'http://127.0.0.1:8081/hub/api'
url = hub_api_url + path
def _set_json(request, context):
assert request.headers['Authorization'] == 'token abcd1234'
context.status_code = 200
return json or []
if status_code is None:
method(url, json=_set_json)
else:
method(url, status_code=status_code)
def test_default_authenticator():
auth = Authenticator()
assert auth.get_student_courses("foo") is None
assert auth.has_access("foo", "course123")
# smoke tests, these should just do nothing
auth.add_student_to_course("foo", "course123")
auth.remove_student_from_course("bar", "course123")
def test_jupyterhub_get_student_courses(env, jupyterhub_auth):
# this will fail, because the user hasn't been set
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = ''
with pytest.raises(JupyterhubEnvironmentError):
jupyterhub_auth.get_student_courses('foo')
# this will fail, because the api token hasn't been set
env['JUPYTERHUB_API_TOKEN'] = ''
env['JUPYTERHUB_USER'] = 'foo'
with pytest.raises(JupyterhubEnvironmentError):
jupyterhub_auth.get_student_courses('foo')
# should fail, because the server returns a forbidden response
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(m.get, '/users/foo', status_code=403)
with pytest.raises(JupyterhubApiError):
jupyterhub_auth.get_student_courses('foo')
# should succeed, but give no courses, because the group name is invalid
with requests_mock.Mocker() as m:
_mock_api_call(m.get, '/users/foo', json={'groups': ['nbgrader-']})
assert jupyterhub_auth.get_student_courses('foo') == []
_mock_api_call(m.get, '/users/foo', json={'groups': ['course101']})
assert jupyterhub_auth.get_student_courses('foo') == []
_mock_api_call(
m.get, '/users/foo', json={'groups': ['nbgrader-course123']})
assert jupyterhub_auth.get_student_courses('foo') == ['course123']
# should succeed
with requests_mock.Mocker() as m:
_mock_api_call(
m.get, '/users/foo', json={'groups': ['nbgrader-course123']})
assert jupyterhub_auth.get_student_courses('*') == ['course123']
def test_jupyterhub_has_access(env, jupyterhub_auth):
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(
m.get, '/users/foo', json={'groups': ['nbgrader-course123']})
assert jupyterhub_auth.has_access('foo', 'course123')
assert not jupyterhub_auth.has_access('foo', 'courseABC')
def test_jupyterhub_add_student_to_course_no_token(jupyterhub_auth):
# this will fail, because the api token hasn't been set
with pytest.raises(JupyterhubEnvironmentError):
jupyterhub_auth.add_student_to_course('foo', 'course123')
def test_jupyterhub_add_student_to_course_no_user(env: dict, jupyterhub_auth: Authenticator) -> None:
# should still fail, because the user hasn't been set
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
with pytest.raises(JupyterhubEnvironmentError):
jupyterhub_auth.add_student_to_course('foo', 'course123')
def test_jupyterhub_add_student_to_course_forbidden(env, jupyterhub_auth, caplog):
# test case where something goes wrong
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(m.get, '/groups', status_code=403)
jupyterhub_auth.add_student_to_course('foo', 'course123')
assert 'ERROR' in [rec.levelname for rec in caplog.records]
def test_jupyterhub_add_student_to_course_no_courseid(env, jupyterhub_auth, caplog):
# test case where something goes wrong
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(m.get, '/groups', status_code=403)
jupyterhub_auth.add_student_to_course('foo', None)
assert 'ERROR' in [rec.levelname for rec in caplog.records]
def test_jupyterhub_add_student_to_course_success(env, jupyterhub_auth, caplog):
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(m.get, '/groups', json=[])
_mock_api_call(m.post, '/groups/nbgrader-course123')
_mock_api_call(m.post, '/groups/nbgrader-course123/users')
jupyterhub_auth.add_student_to_course('foo', 'course123')
assert 'ERROR' not in [rec.levelname for rec in caplog.records]
# Check that it also works if the group already exists
_mock_api_call(m.get, '/groups', json=[{'name': 'nbgrader-course123'}])
_mock_api_call(m.post, '/groups/nbgrader-course123/users')
jupyterhub_auth.add_student_to_course('foo', 'course123')
assert 'ERROR' not in [rec.levelname for rec in caplog.records]
def test_jupyterhub_remove_student_from_course_no_token(jupyterhub_auth):
# this will fail, because the api token hasn't been set
with pytest.raises(JupyterhubEnvironmentError):
jupyterhub_auth.remove_student_from_course('foo', 'course123')
def test_jupyterhub_remove_student_from_course_no_user(env, jupyterhub_auth):
# should still fail, because the user hasn't been set
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
with pytest.raises(JupyterhubEnvironmentError):
jupyterhub_auth.remove_student_from_course('foo', 'course123')
def test_jupyterhub_remove_student_from_course_forbidden(env, jupyterhub_auth, caplog):
# test case where something goes wrong
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(m.delete, '/groups/nbgrader-course123/users', status_code=403)
jupyterhub_auth.remove_student_from_course('foo', 'course123')
assert 'ERROR' in [rec.levelname for rec in caplog.records]
def test_jupyterhub_remove_student_from_course_no_courseid(env, jupyterhub_auth, caplog):
# test case where something goes wrong
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(m.delete, '/groups/nbgrader-course123/users')
jupyterhub_auth.remove_student_from_course('foo', None)
assert 'ERROR' in [rec.levelname for rec in caplog.records]
def test_jupyterhub_remove_student_from_course_success(env, jupyterhub_auth, caplog):
env['JUPYTERHUB_API_TOKEN'] = 'abcd1234'
env['JUPYTERHUB_USER'] = 'foo'
with requests_mock.Mocker() as m:
_mock_api_call(m.delete, '/groups/nbgrader-course123/users')
jupyterhub_auth.remove_student_from_course('foo', 'course123')
assert 'ERROR' not in [rec.levelname for rec in caplog.records]