mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-14 05:23:01 +00:00
test_api passes without threads
just put requests in a thread via `utils.async_requests` eliminates db threads issue
This commit is contained in:
@@ -2,12 +2,11 @@
|
||||
|
||||
import json
|
||||
import time
|
||||
from queue import Queue
|
||||
import sys
|
||||
from unittest import mock
|
||||
from urllib.parse import urlparse, quote
|
||||
|
||||
from pytest import mark, yield_fixture
|
||||
from pytest import mark
|
||||
import requests
|
||||
|
||||
from tornado import gen
|
||||
@@ -18,6 +17,7 @@ from ..user import User
|
||||
from ..utils import url_path_join as ujoin
|
||||
from . import mocking
|
||||
from .mocking import public_host, public_url
|
||||
from .utils import async_requests
|
||||
|
||||
|
||||
def check_db_locks(func):
|
||||
@@ -81,6 +81,7 @@ def auth_header(db, name):
|
||||
|
||||
|
||||
@check_db_locks
|
||||
@gen.coroutine
|
||||
def api_request(app, *api_path, **kwargs):
|
||||
"""Make an API request"""
|
||||
base_url = app.hub.url
|
||||
@@ -91,8 +92,8 @@ def api_request(app, *api_path, **kwargs):
|
||||
|
||||
url = ujoin(base_url, 'api', *api_path)
|
||||
method = kwargs.pop('method', 'get')
|
||||
f = getattr(requests, method)
|
||||
resp = f(url, **kwargs)
|
||||
f = getattr(async_requests, method)
|
||||
resp = yield f(url, **kwargs)
|
||||
assert "frame-ancestors 'self'" in resp.headers['Content-Security-Policy']
|
||||
assert ujoin(app.hub.base_url, "security/csp-report") in resp.headers['Content-Security-Policy']
|
||||
assert 'http' not in resp.headers['Content-Security-Policy']
|
||||
@@ -104,9 +105,10 @@ def api_request(app, *api_path, **kwargs):
|
||||
# --------------------
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_auth_api(app):
|
||||
db = app.db
|
||||
r = api_request(app, 'authorizations', 'gobbledygook')
|
||||
r = yield api_request(app, 'authorizations', 'gobbledygook')
|
||||
assert r.status_code == 404
|
||||
|
||||
# make a new cookie token
|
||||
@@ -114,36 +116,37 @@ def test_auth_api(app):
|
||||
api_token = user.new_api_token()
|
||||
|
||||
# check success:
|
||||
r = api_request(app, 'authorizations/token', api_token)
|
||||
r = yield api_request(app, 'authorizations/token', api_token)
|
||||
assert r.status_code == 200
|
||||
reply = r.json()
|
||||
assert reply['name'] == user.name
|
||||
|
||||
# check fail
|
||||
r = api_request(app, 'authorizations/token', api_token,
|
||||
r = yield api_request(app, 'authorizations/token', api_token,
|
||||
headers={'Authorization': 'no sir'},
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
r = api_request(app, 'authorizations/token', api_token,
|
||||
r = yield api_request(app, 'authorizations/token', api_token,
|
||||
headers={'Authorization': 'token: %s' % user.cookie_id},
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_referer_check(app, io_loop):
|
||||
url = ujoin(public_host(app), app.hub.base_url)
|
||||
host = urlparse(url).netloc
|
||||
user = find_user(app.db, 'admin')
|
||||
if user is None:
|
||||
user = add_user(app.db, name='admin', admin=True)
|
||||
cookies = app.login_user('admin')
|
||||
app_user = get_app_user(app, 'admin')
|
||||
cookies = yield app.login_user('admin')
|
||||
app_user = app.users[user]
|
||||
# stop the admin's server so we don't mess up future tests
|
||||
io_loop.run_sync(lambda: app.proxy.delete_user(app_user))
|
||||
io_loop.run_sync(app_user.stop)
|
||||
yield app.proxy.delete_user(app_user)
|
||||
yield app_user.stop()
|
||||
|
||||
r = api_request(app, 'users',
|
||||
r = yield api_request(app, 'users',
|
||||
headers={
|
||||
'Authorization': '',
|
||||
'Referer': 'null',
|
||||
@@ -151,7 +154,7 @@ def test_referer_check(app, io_loop):
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
r = api_request(app, 'users',
|
||||
r = yield api_request(app, 'users',
|
||||
headers={
|
||||
'Authorization': '',
|
||||
'Referer': 'http://attack.com/csrf/vulnerability',
|
||||
@@ -159,7 +162,7 @@ def test_referer_check(app, io_loop):
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
r = api_request(app, 'users',
|
||||
r = yield api_request(app, 'users',
|
||||
headers={
|
||||
'Authorization': '',
|
||||
'Referer': url,
|
||||
@@ -168,7 +171,7 @@ def test_referer_check(app, io_loop):
|
||||
)
|
||||
assert r.status_code == 200
|
||||
|
||||
r = api_request(app, 'users',
|
||||
r = yield api_request(app, 'users',
|
||||
headers={
|
||||
'Authorization': '',
|
||||
'Referer': ujoin(url, 'foo/bar/baz/bat'),
|
||||
@@ -184,9 +187,10 @@ def test_referer_check(app, io_loop):
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_get_users(app):
|
||||
db = app.db
|
||||
r = api_request(app, 'users')
|
||||
r = yield api_request(app, 'users')
|
||||
assert r.status_code == 200
|
||||
|
||||
users = sorted(r.json(), key=lambda d: d['name'])
|
||||
@@ -211,17 +215,18 @@ def test_get_users(app):
|
||||
}
|
||||
]
|
||||
|
||||
r = api_request(app, 'users',
|
||||
r = yield api_request(app, 'users',
|
||||
headers=auth_header(db, 'user'),
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_add_user(app):
|
||||
db = app.db
|
||||
name = 'newuser'
|
||||
r = api_request(app, 'users', name, method='post')
|
||||
r = yield api_request(app, 'users', name, method='post')
|
||||
assert r.status_code == 201
|
||||
user = find_user(db, name)
|
||||
assert user is not None
|
||||
@@ -230,9 +235,10 @@ def test_add_user(app):
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_get_user(app):
|
||||
name = 'user'
|
||||
r = api_request(app, 'users', name)
|
||||
r = yield api_request(app, 'users', name)
|
||||
assert r.status_code == 200
|
||||
user = r.json()
|
||||
user.pop('last_activity')
|
||||
@@ -247,19 +253,21 @@ def test_get_user(app):
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_add_multi_user_bad(app):
|
||||
r = api_request(app, 'users', method='post')
|
||||
r = yield api_request(app, 'users', method='post')
|
||||
assert r.status_code == 400
|
||||
r = api_request(app, 'users', method='post', data='{}')
|
||||
r = yield api_request(app, 'users', method='post', data='{}')
|
||||
assert r.status_code == 400
|
||||
r = api_request(app, 'users', method='post', data='[]')
|
||||
r = yield api_request(app, 'users', method='post', data='[]')
|
||||
assert r.status_code == 400
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_add_multi_user_invalid(app):
|
||||
app.authenticator.username_pattern = r'w.*'
|
||||
r = api_request(app, 'users', method='post',
|
||||
r = yield api_request(app, 'users', method='post',
|
||||
data=json.dumps({'usernames': ['Willow', 'Andrew', 'Tara']})
|
||||
)
|
||||
app.authenticator.username_pattern = ''
|
||||
@@ -268,10 +276,11 @@ def test_add_multi_user_invalid(app):
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_add_multi_user(app):
|
||||
db = app.db
|
||||
names = ['a', 'b']
|
||||
r = api_request(app, 'users', method='post',
|
||||
r = yield api_request(app, 'users', method='post',
|
||||
data=json.dumps({'usernames': names}),
|
||||
)
|
||||
assert r.status_code == 201
|
||||
@@ -286,7 +295,7 @@ def test_add_multi_user(app):
|
||||
assert not user.admin
|
||||
|
||||
# try to create the same users again
|
||||
r = api_request(app, 'users', method='post',
|
||||
r = yield api_request(app, 'users', method='post',
|
||||
data=json.dumps({'usernames': names}),
|
||||
)
|
||||
assert r.status_code == 400
|
||||
@@ -294,7 +303,7 @@ def test_add_multi_user(app):
|
||||
names = ['a', 'b', 'ab']
|
||||
|
||||
# try to create the same users again
|
||||
r = api_request(app, 'users', method='post',
|
||||
r = yield api_request(app, 'users', method='post',
|
||||
data=json.dumps({'usernames': names}),
|
||||
)
|
||||
assert r.status_code == 201
|
||||
@@ -304,10 +313,11 @@ def test_add_multi_user(app):
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_add_multi_user_admin(app):
|
||||
db = app.db
|
||||
names = ['c', 'd']
|
||||
r = api_request(app, 'users', method='post',
|
||||
r = yield api_request(app, 'users', method='post',
|
||||
data=json.dumps({'usernames': names, 'admin': True}),
|
||||
)
|
||||
assert r.status_code == 201
|
||||
@@ -323,20 +333,22 @@ def test_add_multi_user_admin(app):
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_add_user_bad(app):
|
||||
db = app.db
|
||||
name = 'dne_newuser'
|
||||
r = api_request(app, 'users', name, method='post')
|
||||
r = yield api_request(app, 'users', name, method='post')
|
||||
assert r.status_code == 400
|
||||
user = find_user(db, name)
|
||||
assert user is None
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_add_admin(app):
|
||||
db = app.db
|
||||
name = 'newadmin'
|
||||
r = api_request(app, 'users', name, method='post',
|
||||
r = yield api_request(app, 'users', name, method='post',
|
||||
data=json.dumps({'admin': True}),
|
||||
)
|
||||
assert r.status_code == 201
|
||||
@@ -347,25 +359,27 @@ def test_add_admin(app):
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_delete_user(app):
|
||||
db = app.db
|
||||
mal = add_user(db, name='mal')
|
||||
r = api_request(app, 'users', 'mal', method='delete')
|
||||
r = yield api_request(app, 'users', 'mal', method='delete')
|
||||
assert r.status_code == 204
|
||||
|
||||
|
||||
@mark.user
|
||||
@mark.gen_test
|
||||
def test_make_admin(app):
|
||||
db = app.db
|
||||
name = 'admin2'
|
||||
r = api_request(app, 'users', name, method='post')
|
||||
r = yield api_request(app, 'users', name, method='post')
|
||||
assert r.status_code == 201
|
||||
user = find_user(db, name)
|
||||
assert user is not None
|
||||
assert user.name == name
|
||||
assert not user.admin
|
||||
|
||||
r = api_request(app, 'users', name, method='patch',
|
||||
r = yield api_request(app, 'users', name, method='patch',
|
||||
data=json.dumps({'admin': True})
|
||||
)
|
||||
assert r.status_code == 200
|
||||
@@ -375,23 +389,7 @@ def test_make_admin(app):
|
||||
assert user.admin
|
||||
|
||||
|
||||
def get_app_user(app, name):
|
||||
"""Helper to get the User object from the main thread.
|
||||
|
||||
Needed for access to the Spawner during testing.
|
||||
|
||||
No ORM methods should be called on the result.
|
||||
"""
|
||||
q = Queue()
|
||||
|
||||
def get_user_id():
|
||||
user = find_user(app.db, name)
|
||||
q.put(user.id)
|
||||
app.io_loop.add_callback(get_user_id)
|
||||
user_id = q.get(timeout=2)
|
||||
return app.users[user_id]
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_spawn(app, io_loop):
|
||||
db = app.db
|
||||
name = 'wash'
|
||||
@@ -401,41 +399,41 @@ def test_spawn(app, io_loop):
|
||||
'i': 5,
|
||||
}
|
||||
before_servers = sorted(db.query(orm.Server), key=lambda s: s.url)
|
||||
r = api_request(app, 'users', name, 'server', method='post',
|
||||
r = yield api_request(app, 'users', name, 'server', method='post',
|
||||
data=json.dumps(options),
|
||||
)
|
||||
assert r.status_code == 201
|
||||
assert 'pid' in user.orm_spawners[''].state
|
||||
app_user = get_app_user(app, name)
|
||||
app_user = app.users[name]
|
||||
assert app_user.spawner is not None
|
||||
spawner = app_user.spawner
|
||||
assert app_user.spawner.user_options == options
|
||||
assert not app_user.spawner._spawn_pending
|
||||
status = io_loop.run_sync(app_user.spawner.poll)
|
||||
status = yield app_user.spawner.poll()
|
||||
assert status is None
|
||||
|
||||
assert spawner.server.base_url == ujoin(app.base_url, 'user/%s' % name) + '/'
|
||||
url = public_url(app, user)
|
||||
r = requests.get(url)
|
||||
r = yield async_requests.get(url)
|
||||
assert r.status_code == 200
|
||||
assert r.text == spawner.server.base_url
|
||||
|
||||
r = requests.get(ujoin(url, 'args'))
|
||||
r = yield async_requests.get(ujoin(url, 'args'))
|
||||
assert r.status_code == 200
|
||||
argv = r.json()
|
||||
assert '--port' in ' '.join(argv)
|
||||
r = requests.get(ujoin(url, 'env'))
|
||||
r = yield async_requests.get(ujoin(url, 'env'))
|
||||
env = r.json()
|
||||
for expected in ['JUPYTERHUB_USER', 'JUPYTERHUB_BASE_URL', 'JUPYTERHUB_API_TOKEN']:
|
||||
assert expected in env
|
||||
if app.subdomain_host:
|
||||
assert env['JUPYTERHUB_HOST'] == app.subdomain_host
|
||||
|
||||
r = api_request(app, 'users', name, 'server', method='delete')
|
||||
r = yield api_request(app, 'users', name, 'server', method='delete')
|
||||
assert r.status_code == 204
|
||||
|
||||
assert 'pid' not in user.orm_spawners[''].state
|
||||
status = io_loop.run_sync(app_user.spawner.poll)
|
||||
status = yield app_user.spawner.poll()
|
||||
assert status == 0
|
||||
|
||||
# check that we cleaned up after ourselves
|
||||
@@ -446,6 +444,7 @@ def test_spawn(app, io_loop):
|
||||
assert tokens == []
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_slow_spawn(app, io_loop, no_patience, request):
|
||||
patch = mock.patch.dict(app.tornado_settings, {'spawner_class': mocking.SlowSpawner})
|
||||
patch.start()
|
||||
@@ -453,10 +452,10 @@ def test_slow_spawn(app, io_loop, no_patience, request):
|
||||
db = app.db
|
||||
name = 'zoe'
|
||||
user = add_user(db, app=app, name=name)
|
||||
r = api_request(app, 'users', name, 'server', method='post')
|
||||
r = yield api_request(app, 'users', name, 'server', method='post')
|
||||
r.raise_for_status()
|
||||
assert r.status_code == 202
|
||||
app_user = get_app_user(app, name)
|
||||
app_user = app.users[name]
|
||||
assert app_user.spawner is not None
|
||||
assert app_user.spawner._spawn_pending
|
||||
assert not app_user.spawner._stop_pending
|
||||
@@ -466,9 +465,9 @@ def test_slow_spawn(app, io_loop, no_patience, request):
|
||||
while app_user.spawner._spawn_pending:
|
||||
yield gen.sleep(0.1)
|
||||
|
||||
io_loop.run_sync(wait_spawn)
|
||||
yield wait_spawn()
|
||||
assert not app_user.spawner._spawn_pending
|
||||
status = io_loop.run_sync(app_user.spawner.poll)
|
||||
status = yield app_user.spawner.poll()
|
||||
assert status is None
|
||||
|
||||
@gen.coroutine
|
||||
@@ -476,25 +475,26 @@ def test_slow_spawn(app, io_loop, no_patience, request):
|
||||
while app_user.spawner._stop_pending:
|
||||
yield gen.sleep(0.1)
|
||||
|
||||
r = api_request(app, 'users', name, 'server', method='delete')
|
||||
r = yield api_request(app, 'users', name, 'server', method='delete')
|
||||
r.raise_for_status()
|
||||
assert r.status_code == 202
|
||||
assert app_user.spawner is not None
|
||||
assert app_user.spawner._stop_pending
|
||||
|
||||
r = api_request(app, 'users', name, 'server', method='delete')
|
||||
r = yield api_request(app, 'users', name, 'server', method='delete')
|
||||
r.raise_for_status()
|
||||
assert r.status_code == 202
|
||||
assert app_user.spawner is not None
|
||||
assert app_user.spawner._stop_pending
|
||||
|
||||
io_loop.run_sync(wait_stop)
|
||||
yield wait_stop()
|
||||
assert not app_user.spawner._stop_pending
|
||||
assert app_user.spawner is not None
|
||||
r = api_request(app, 'users', name, 'server', method='delete')
|
||||
r = yield api_request(app, 'users', name, 'server', method='delete')
|
||||
assert r.status_code == 400
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_never_spawn(app, io_loop, no_patience, request):
|
||||
patch = mock.patch.dict(app.tornado_settings, {'spawner_class': mocking.NeverSpawner})
|
||||
patch.start()
|
||||
@@ -503,8 +503,8 @@ def test_never_spawn(app, io_loop, no_patience, request):
|
||||
db = app.db
|
||||
name = 'badger'
|
||||
user = add_user(db, app=app, name=name)
|
||||
r = api_request(app, 'users', name, 'server', method='post')
|
||||
app_user = get_app_user(app, name)
|
||||
r = yield api_request(app, 'users', name, 'server', method='post')
|
||||
app_user = app.users[name]
|
||||
assert app_user.spawner is not None
|
||||
assert app_user.spawner._spawn_pending
|
||||
|
||||
@@ -513,38 +513,40 @@ def test_never_spawn(app, io_loop, no_patience, request):
|
||||
while app_user.spawner._spawn_pending:
|
||||
yield gen.sleep(0.1)
|
||||
|
||||
io_loop.run_sync(wait_pending)
|
||||
yield wait_pending()
|
||||
assert not app_user.spawner._spawn_pending
|
||||
status = io_loop.run_sync(app_user.spawner.poll)
|
||||
status = yield app_user.spawner.poll()
|
||||
assert status is not None
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_get_proxy(app, io_loop):
|
||||
r = api_request(app, 'proxy')
|
||||
r = yield api_request(app, 'proxy')
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
assert list(reply.keys()) == ['/']
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_cookie(app):
|
||||
db = app.db
|
||||
name = 'patience'
|
||||
user = add_user(db, app=app, name=name)
|
||||
r = api_request(app, 'users', name, 'server', method='post')
|
||||
r = yield api_request(app, 'users', name, 'server', method='post')
|
||||
assert r.status_code == 201
|
||||
assert 'pid' in user.orm_spawners[''].state
|
||||
app_user = get_app_user(app, name)
|
||||
app_user = app.users[name]
|
||||
|
||||
cookies = app.login_user(name)
|
||||
cookies = yield app.login_user(name)
|
||||
cookie_name = app.hub.cookie_name
|
||||
# cookie jar gives '"cookie-value"', we want 'cookie-value'
|
||||
cookie = cookies[cookie_name][1:-1]
|
||||
r = api_request(app, 'authorizations/cookie',
|
||||
r = yield api_request(app, 'authorizations/cookie',
|
||||
cookie_name, "nothintoseehere",
|
||||
)
|
||||
assert r.status_code == 404
|
||||
|
||||
r = api_request(app, 'authorizations/cookie',
|
||||
r = yield api_request(app, 'authorizations/cookie',
|
||||
cookie_name, quote(cookie, safe=''),
|
||||
)
|
||||
r.raise_for_status()
|
||||
@@ -552,7 +554,7 @@ def test_cookie(app):
|
||||
assert reply['name'] == name
|
||||
|
||||
# deprecated cookie in body:
|
||||
r = api_request(app, 'authorizations/cookie',
|
||||
r = yield api_request(app, 'authorizations/cookie',
|
||||
cookie_name, data=cookie,
|
||||
)
|
||||
r.raise_for_status()
|
||||
@@ -560,18 +562,20 @@ def test_cookie(app):
|
||||
assert reply['name'] == name
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_token(app):
|
||||
name = 'book'
|
||||
user = add_user(app.db, app=app, name=name)
|
||||
token = user.new_api_token()
|
||||
r = api_request(app, 'authorizations/token', token)
|
||||
r = yield api_request(app, 'authorizations/token', token)
|
||||
r.raise_for_status()
|
||||
user_model = r.json()
|
||||
assert user_model['name'] == name
|
||||
r = api_request(app, 'authorizations/token', 'notauthorized')
|
||||
r = yield api_request(app, 'authorizations/token', 'notauthorized')
|
||||
assert r.status_code == 404
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
@mark.parametrize("headers, data, status", [
|
||||
({}, None, 200),
|
||||
({'Authorization': ''}, None, 403),
|
||||
@@ -581,13 +585,13 @@ def test_get_new_token(app, headers, data, status):
|
||||
if data:
|
||||
data = json.dumps(data)
|
||||
# request a new token
|
||||
r = api_request(app, 'authorizations', 'token', method='post', data=data, headers=headers)
|
||||
r = yield api_request(app, 'authorizations', 'token', method='post', data=data, headers=headers)
|
||||
assert r.status_code == status
|
||||
if status != 200:
|
||||
return
|
||||
reply = r.json()
|
||||
assert 'token' in reply
|
||||
r = api_request(app, 'authorizations', 'token', reply['token'])
|
||||
r = yield api_request(app, 'authorizations', 'token', reply['token'])
|
||||
r.raise_for_status()
|
||||
assert 'name' in r.json()
|
||||
|
||||
@@ -598,8 +602,9 @@ def test_get_new_token(app, headers, data, status):
|
||||
|
||||
|
||||
@mark.group
|
||||
@mark.gen_test
|
||||
def test_groups_list(app):
|
||||
r = api_request(app, 'groups')
|
||||
r = yield api_request(app, 'groups')
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
assert reply == []
|
||||
@@ -609,7 +614,7 @@ def test_groups_list(app):
|
||||
app.db.add(group)
|
||||
app.db.commit()
|
||||
|
||||
r = api_request(app, 'groups')
|
||||
r = yield api_request(app, 'groups')
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
assert reply == [{
|
||||
@@ -620,16 +625,17 @@ def test_groups_list(app):
|
||||
|
||||
|
||||
@mark.group
|
||||
@mark.gen_test
|
||||
def test_group_get(app):
|
||||
group = orm.Group.find(app.db, name='alphaflight')
|
||||
user = add_user(app.db, app=app, name='sasquatch')
|
||||
group.users.append(user)
|
||||
app.db.commit()
|
||||
|
||||
r = api_request(app, 'groups/runaways')
|
||||
r = yield api_request(app, 'groups/runaways')
|
||||
assert r.status_code == 404
|
||||
|
||||
r = api_request(app, 'groups/alphaflight')
|
||||
r = yield api_request(app, 'groups/alphaflight')
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
assert reply == {
|
||||
@@ -640,18 +646,19 @@ def test_group_get(app):
|
||||
|
||||
|
||||
@mark.group
|
||||
@mark.gen_test
|
||||
def test_group_create_delete(app):
|
||||
db = app.db
|
||||
r = api_request(app, 'groups/runaways', method='delete')
|
||||
r = yield api_request(app, 'groups/runaways', method='delete')
|
||||
assert r.status_code == 404
|
||||
|
||||
r = api_request(app, 'groups/new', method='post',
|
||||
r = yield api_request(app, 'groups/new', method='post',
|
||||
data=json.dumps({'users': ['doesntexist']}),
|
||||
)
|
||||
assert r.status_code == 400
|
||||
assert orm.Group.find(db, name='new') is None
|
||||
|
||||
r = api_request(app, 'groups/omegaflight', method='post',
|
||||
r = yield api_request(app, 'groups/omegaflight', method='post',
|
||||
data=json.dumps({'users': ['sasquatch']}),
|
||||
)
|
||||
r.raise_for_status()
|
||||
@@ -662,29 +669,30 @@ def test_group_create_delete(app):
|
||||
assert sasquatch in omegaflight.users
|
||||
|
||||
# create duplicate raises 400
|
||||
r = api_request(app, 'groups/omegaflight', method='post')
|
||||
r = yield api_request(app, 'groups/omegaflight', method='post')
|
||||
assert r.status_code == 400
|
||||
|
||||
r = api_request(app, 'groups/omegaflight', method='delete')
|
||||
r = yield api_request(app, 'groups/omegaflight', method='delete')
|
||||
assert r.status_code == 204
|
||||
assert omegaflight not in sasquatch.groups
|
||||
assert orm.Group.find(db, name='omegaflight') is None
|
||||
|
||||
# delete nonexistent gives 404
|
||||
r = api_request(app, 'groups/omegaflight', method='delete')
|
||||
r = yield api_request(app, 'groups/omegaflight', method='delete')
|
||||
assert r.status_code == 404
|
||||
|
||||
|
||||
@mark.group
|
||||
@mark.gen_test
|
||||
def test_group_add_users(app):
|
||||
db = app.db
|
||||
# must specify users
|
||||
r = api_request(app, 'groups/alphaflight/users', method='post', data='{}')
|
||||
r = yield api_request(app, 'groups/alphaflight/users', method='post', data='{}')
|
||||
assert r.status_code == 400
|
||||
|
||||
names = ['aurora', 'guardian', 'northstar', 'sasquatch', 'shaman', 'snowbird']
|
||||
users = [ find_user(db, name=name) or add_user(db, app=app, name=name) for name in names ]
|
||||
r = api_request(app, 'groups/alphaflight/users', method='post', data=json.dumps({
|
||||
r = yield api_request(app, 'groups/alphaflight/users', method='post', data=json.dumps({
|
||||
'users': names,
|
||||
}))
|
||||
r.raise_for_status()
|
||||
@@ -698,15 +706,16 @@ def test_group_add_users(app):
|
||||
|
||||
|
||||
@mark.group
|
||||
@mark.gen_test
|
||||
def test_group_delete_users(app):
|
||||
db = app.db
|
||||
# must specify users
|
||||
r = api_request(app, 'groups/alphaflight/users', method='delete', data='{}')
|
||||
r = yield api_request(app, 'groups/alphaflight/users', method='delete', data='{}')
|
||||
assert r.status_code == 400
|
||||
|
||||
names = ['aurora', 'guardian', 'northstar', 'sasquatch', 'shaman', 'snowbird']
|
||||
users = [ find_user(db, name=name) for name in names ]
|
||||
r = api_request(app, 'groups/alphaflight/users', method='delete', data=json.dumps({
|
||||
r = yield api_request(app, 'groups/alphaflight/users', method='delete', data=json.dumps({
|
||||
'users': names[:2],
|
||||
}))
|
||||
r.raise_for_status()
|
||||
@@ -726,10 +735,11 @@ def test_group_delete_users(app):
|
||||
|
||||
|
||||
@mark.services
|
||||
@mark.gen_test
|
||||
def test_get_services(app, mockservice_url):
|
||||
mockservice = mockservice_url
|
||||
db = app.db
|
||||
r = api_request(app, 'services')
|
||||
r = yield api_request(app, 'services')
|
||||
r.raise_for_status()
|
||||
assert r.status_code == 200
|
||||
|
||||
@@ -745,17 +755,18 @@ def test_get_services(app, mockservice_url):
|
||||
}
|
||||
}
|
||||
|
||||
r = api_request(app, 'services',
|
||||
r = yield api_request(app, 'services',
|
||||
headers=auth_header(db, 'user'),
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
|
||||
@mark.services
|
||||
@mark.gen_test
|
||||
def test_get_service(app, mockservice_url):
|
||||
mockservice = mockservice_url
|
||||
db = app.db
|
||||
r = api_request(app, 'services/%s' % mockservice.name)
|
||||
r = yield api_request(app, 'services/%s' % mockservice.name)
|
||||
r.raise_for_status()
|
||||
assert r.status_code == 200
|
||||
|
||||
@@ -769,22 +780,23 @@ def test_get_service(app, mockservice_url):
|
||||
'url': mockservice.url,
|
||||
}
|
||||
|
||||
r = api_request(app, 'services/%s' % mockservice.name,
|
||||
r = yield api_request(app, 'services/%s' % mockservice.name,
|
||||
headers={
|
||||
'Authorization': 'token %s' % mockservice.api_token
|
||||
}
|
||||
)
|
||||
r.raise_for_status()
|
||||
r = api_request(app, 'services/%s' % mockservice.name,
|
||||
r = yield api_request(app, 'services/%s' % mockservice.name,
|
||||
headers=auth_header(db, 'user'),
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_root_api(app):
|
||||
base_url = app.hub.url
|
||||
url = ujoin(base_url, 'api')
|
||||
r = requests.get(url)
|
||||
r = yield async_requests.get(url)
|
||||
r.raise_for_status()
|
||||
expected = {
|
||||
'version': jupyterhub.__version__
|
||||
@@ -792,8 +804,9 @@ def test_root_api(app):
|
||||
assert r.json() == expected
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_info(app):
|
||||
r = api_request(app, 'info')
|
||||
r = yield api_request(app, 'info')
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
assert data['version'] == jupyterhub.__version__
|
||||
@@ -821,14 +834,16 @@ def test_info(app):
|
||||
# -----------------
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_options(app):
|
||||
r = api_request(app, 'users', method='options')
|
||||
r = yield api_request(app, 'users', method='options')
|
||||
r.raise_for_status()
|
||||
assert 'Access-Control-Allow-Headers' in r.headers
|
||||
|
||||
|
||||
@mark.gen_test
|
||||
def test_bad_json_body(app):
|
||||
r = api_request(app, 'users', method='post', data='notjson')
|
||||
r = yield api_request(app, 'users', method='post', data='notjson')
|
||||
assert r.status_code == 400
|
||||
|
||||
|
||||
@@ -838,14 +853,24 @@ def test_bad_json_body(app):
|
||||
|
||||
|
||||
def test_shutdown(app):
|
||||
r = api_request(app, 'shutdown', method='post',
|
||||
data=json.dumps({'servers': True, 'proxy': True,}),
|
||||
)
|
||||
loop = app.io_loop
|
||||
|
||||
# have to do things a little funky since we are going to stop the loop,
|
||||
# which makes gen_test unhappy. So we run the loop ourselves.
|
||||
|
||||
@gen.coroutine
|
||||
def shutdown():
|
||||
r = yield api_request(app, 'shutdown', method='post',
|
||||
data=json.dumps({'servers': True, 'proxy': True,}),
|
||||
)
|
||||
return r
|
||||
|
||||
real_stop = loop.stop
|
||||
def stop():
|
||||
stop.called = True
|
||||
loop.call_later(1, real_stop)
|
||||
with mock.patch.object(loop, 'stop', stop):
|
||||
r = loop.run_sync(shutdown, timeout=5)
|
||||
r.raise_for_status()
|
||||
reply = r.json()
|
||||
for i in range(100):
|
||||
if app.io_loop._running:
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
break
|
||||
assert not app.io_loop._running
|
||||
assert stop.called
|
||||
|
Reference in New Issue
Block a user