update tests for changed redirects

- handle 503 on not running /hub/user/:name
- handle new spawn-redirect page
This commit is contained in:
Min RK
2019-02-25 15:43:50 +01:00
parent 4b1d80203e
commit 1185619bf6
3 changed files with 65 additions and 35 deletions

View File

@@ -1220,7 +1220,7 @@ class UserUrlHandler(BaseHandler):
self.log.warning( self.log.warning(
"User %s requested server for %s, which they don't own", "User %s requested server for %s, which they don't own",
current_user.name, current_user.name,
user.name, user_name,
) )
target = url_path_join(current_user.url, user_path or '') target = url_path_join(current_user.url, user_path or '')
if self.request.query: if self.request.query:
@@ -1270,13 +1270,10 @@ class UserUrlHandler(BaseHandler):
# if request is expecting JSON, assume it's an API request and fail with 503 # if request is expecting JSON, assume it's an API request and fail with 503
# because it won't like the redirect to the pending page # because it won't like the redirect to the pending page
if ( if get_accepted_mimetype(
get_accepted_mimetype(
self.request.headers.get('Accept', ''), self.request.headers.get('Accept', ''),
choices=['application/json', 'text/html'], choices=['application/json', 'text/html'],
) ) == 'application/json' or 'api' in user_path.split('/'):
== 'application/json'
):
self._fail_api_request() self._fail_api_request()
return return
@@ -1376,9 +1373,14 @@ class UserRedirectHandler(BaseHandler):
@web.authenticated @web.authenticated
def get(self, path): def get(self, path):
user = self.current_user user = self.current_user
url = url_path_join(user.url, path) user_url = url_path_join(user.url, path)
if self.request.query: if self.request.query:
url = url_concat(url, parse_qsl(self.request.query)) user_url = url_concat(user_url, parse_qsl(self.request.query))
url = url_concat(
url_path_join(self.hub.base_url, "spawn", user.name), {"next": user_url}
)
self.redirect(url) self.redirect(url)

View File

@@ -118,8 +118,8 @@ class SpawnHandler(BaseHandler):
raise web.HTTPError(404, "No such user: %s" % for_user) raise web.HTTPError(404, "No such user: %s" % for_user)
if not self.allow_named_servers and user.running: if not self.allow_named_servers and user.running:
url = user.server_url(server_name) url = self.get_next_url(user, default=user.server_url(server_name))
self.log.debug("User is running: %s", url) self.log.info("User is running: %s", user.name)
self.redirect(url) self.redirect(url)
return return
@@ -127,10 +127,10 @@ class SpawnHandler(BaseHandler):
server_name = '' server_name = ''
spawner = user.spawners[server_name] spawner = user.spawners[server_name]
# resolve `?next=...`, falling back on the /hub/user/server url # resolve `?next=...`, falling back on the spawn-pending url
# instead of /hub/home
# must not be /user/server for named servers, # must not be /user/server for named servers,
# which may get handled by the default server if they aren't ready yet # which may get handled by the default server if they aren't ready yet
next_url = self.get_next_url( next_url = self.get_next_url(
user, user,
default=url_path_join( default=url_path_join(
@@ -139,19 +139,28 @@ class SpawnHandler(BaseHandler):
) )
# spawner is active, redirect back to get progress, etc. # spawner is active, redirect back to get progress, etc.
if spawner.active: if spawner.ready:
self.log.info("Server %s is already running", spawner._log_name)
next_url = self.get_next_url(user, default=user.server_url(server_name))
elif spawner.active:
self.log.info("Server %s is already active", spawner._log_name)
self.redirect(next_url) self.redirect(next_url)
return return
spawner_options_form = await spawner.get_options_form()
if spawner_options_form:
# Add handler to spawner here so you can access query params in form rendering. # Add handler to spawner here so you can access query params in form rendering.
spawner.handler = self spawner.handler = self
spawner_options_form = await spawner.get_options_form()
if spawner_options_form:
self.log.debug("Serving options form for %s", spawner._log_name)
form = self._render_form( form = self._render_form(
for_user=user, spawner_options_form=spawner_options_form for_user=user, spawner_options_form=spawner_options_form
) )
self.finish(form) self.finish(form)
else: else:
self.log.debug(
"Triggering spawn with default options for %s", spawner._log_name
)
# Explicit spawn request: clear _spawn_future # Explicit spawn request: clear _spawn_future
# which may have been saved to prevent implicit spawns # which may have been saved to prevent implicit spawns
# after a failure. # after a failure.
@@ -210,11 +219,6 @@ class SpawnHandler(BaseHandler):
self.hub.base_url, "spawn-pending", user.name, server_name self.hub.base_url, "spawn-pending", user.name, server_name
), ),
) )
# request spawn and redirect immediately
# this will send folks to the
f = asyncio.ensure_future(self.spawn_single_user(user, server_name))
await asyncio.wait([f], timeout=1)
self.redirect(next_url) self.redirect(next_url)

View File

@@ -44,9 +44,10 @@ async def test_root_redirect(app):
next_url = ujoin(app.base_url, 'user/other/test.ipynb') next_url = ujoin(app.base_url, 'user/other/test.ipynb')
url = '/?' + urlencode({'next': next_url}) url = '/?' + urlencode({'next': next_url})
r = await get_page(url, app, cookies=cookies) r = await get_page(url, app, cookies=cookies)
r.raise_for_status()
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, 'user/%s/test.ipynb' % name) assert path == ujoin(app.base_url, 'hub/user/%s/test.ipynb' % name)
# serve "server not running" page, which has status 503
assert r.status_code == 503
async def test_root_default_url_noauth(app): async def test_root_default_url_noauth(app):
@@ -122,11 +123,19 @@ async def test_spawn_redirect(app):
r.raise_for_status() r.raise_for_status()
print(urlparse(r.url)) print(urlparse(r.url))
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, 'user/%s/' % name) # make sure we visited hub/spawn-pending after spawn
# if spawn was really quick, we might get redirected all the way to the running server,
# so check history instead of r.url
history = [urlparse(_.url).path for _ in r.history]
history.append(path)
assert ujoin(app.base_url, 'hub/spawn-pending', name) in history
# should have started server # should have started server
status = await u.spawner.poll() status = await u.spawner.poll()
assert status is None assert status is None
# wait for ready signal before checking next redirect
while not u.spawner.ready:
await asyncio.sleep(0.1)
# test spawn page when server is already running (just redirect) # test spawn page when server is already running (just redirect)
r = await get_page('spawn', app, cookies=cookies) r = await get_page('spawn', app, cookies=cookies)
@@ -143,9 +152,9 @@ async def test_spawn_redirect(app):
# test handing of trailing slash on `/user/name` # test handing of trailing slash on `/user/name`
r = await get_page('user/' + name, app, hub=False, cookies=cookies) r = await get_page('user/' + name, app, hub=False, cookies=cookies)
r.raise_for_status()
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, '/user/%s/' % name) assert path == ujoin(app.base_url, 'hub/user/%s/' % name)
assert r.status_code == 503
async def test_spawn_handler_access(app): async def test_spawn_handler_access(app):
@@ -178,10 +187,11 @@ async def test_spawn_admin_access(app, admin_access):
name = 'mariel' name = 'mariel'
user = add_user(app.db, app=app, name=name) user = add_user(app.db, app=app, name=name)
app.db.commit() app.db.commit()
r = await get_page('user/' + name, app, cookies=cookies) r = await get_page('spawn/' + name, app, cookies=cookies)
r.raise_for_status() r.raise_for_status()
assert (r.url.split('?')[0] + '/').startswith(public_url(app, user)) assert (r.url.split('?')[0] + '/').startswith(public_url(app, user))
r = await get_page('user/{}/env'.format(name), app, hub=False, cookies=cookies) r = await get_page('user/{}/env'.format(name), app, hub=False, cookies=cookies)
r.raise_for_status() r.raise_for_status()
env = r.json() env = r.json()
assert env['JUPYTERHUB_USER'] == name assert env['JUPYTERHUB_USER'] == name
@@ -316,16 +326,16 @@ async def test_user_redirect_deprecated(app):
cookies = await app.login_user(name) cookies = await app.login_user(name)
r = await get_page('/user/baduser', app, cookies=cookies, hub=False) r = await get_page('/user/baduser', app, cookies=cookies, hub=False)
r.raise_for_status()
print(urlparse(r.url)) print(urlparse(r.url))
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, '/user/%s/' % name) assert path == ujoin(app.base_url, 'hub/user/%s/' % name)
assert r.status_code == 503
r = await get_page('/user/baduser/test.ipynb', app, cookies=cookies, hub=False) r = await get_page('/user/baduser/test.ipynb', app, cookies=cookies, hub=False)
r.raise_for_status()
print(urlparse(r.url)) print(urlparse(r.url))
path = urlparse(r.url).path path = urlparse(r.url).path
assert path == ujoin(app.base_url, '/user/%s/test.ipynb' % name) assert path == ujoin(app.base_url, 'hub/user/%s/test.ipynb' % name)
assert r.status_code == 503
r = await get_page('/user/baduser/test.ipynb', app, hub=False) r = await get_page('/user/baduser/test.ipynb', app, hub=False)
r.raise_for_status() r.raise_for_status()
@@ -389,9 +399,11 @@ async def test_login_redirect(app, running, next_url, location):
user = app.users['river'] user = app.users['river']
if location: if location:
location = ujoin(app.base_url, location) location = ujoin(app.base_url, location)
elif running:
location = ujoin(app.base_url, 'user/river/')
else: else:
# use default url # use default url
location = user.url location = ujoin(app.base_url, 'hub/spawn')
url = 'login' url = 'login'
if next_url: if next_url:
@@ -575,6 +587,10 @@ async def test_announcements(app, announcements):
assert ann01 in text assert ann01 in text
cookies = await app.login_user("jones") cookies = await app.login_user("jones")
# make sure spawner isn't running
# so we see the spawn form
user = app.users["jones"]
await user.stop()
with mock.patch.dict( with mock.patch.dict(
app.tornado_settings, app.tornado_settings,
@@ -650,6 +666,12 @@ async def test_token_page(app):
r = await get_page("spawn", app, cookies=cookies) r = await get_page("spawn", app, cookies=cookies)
r.raise_for_status() r.raise_for_status()
# wait for the server to be running and visit it
while not user.spawner.ready:
await asyncio.sleep(0.1)
r = await get_page("user/" + user.name, app, cookies=cookies)
r.raise_for_status()
r = await get_page("token", app, cookies=cookies) r = await get_page("token", app, cookies=cookies)
r.raise_for_status() r.raise_for_status()
body = extract_body(r) body = extract_body(r)
@@ -661,9 +683,11 @@ async def test_token_page(app):
async def test_server_not_running_api_request(app): async def test_server_not_running_api_request(app):
cookies = await app.login_user("bees") cookies = await app.login_user("bees")
r = await get_page("user/bees/api/status", app, hub=False, cookies=cookies) r = await get_page("user/bees/api/status", app, hub=False, cookies=cookies)
assert r.status_code == 404 assert r.status_code == 503
assert r.headers["content-type"] == "application/json" assert r.headers["content-type"] == "application/json"
assert r.json() == {"message": "bees is not running"} message = r.json()['message']
assert "Hub home page" in message
assert "/user/bees" in message
async def test_metrics_no_auth(app): async def test_metrics_no_auth(app):