test spawn-pending page

This commit is contained in:
Min RK
2019-02-27 11:14:03 +01:00
parent 81a43a588b
commit 8d01b0356b
3 changed files with 71 additions and 14 deletions

View File

@@ -131,21 +131,24 @@ class SpawnHandler(BaseHandler):
# must not be /user/server for named servers,
# which may get handled by the default server if they aren't ready yet
next_url = self.get_next_url(
user,
default=url_path_join(
pending_url = url_path_join(
self.hub.base_url, "spawn-pending", user.name, server_name
),
)
if self.get_argument('next', None):
# preserve `?next=...` through spawn-pending
pending_url = url_concat(pending_url, {'next': self.get_argument('next')})
# spawner is active, redirect back to get progress, etc.
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))
self.redirect(next_url)
return
elif spawner.active:
self.log.info("Server %s is already active", spawner._log_name)
self.redirect(next_url)
self.redirect(pending_url)
return
# Add handler to spawner here so you can access query params in form rendering.
@@ -169,7 +172,7 @@ class SpawnHandler(BaseHandler):
# not running, no form. Trigger spawn and redirect back to /user/:name
f = asyncio.ensure_future(self.spawn_single_user(user, server_name))
await asyncio.wait([f], timeout=1)
self.redirect(next_url)
self.redirect(pending_url)
@web.authenticated
async def post(self, for_user=None, server_name=''):
@@ -317,10 +320,7 @@ class SpawnPendingHandler(BaseHandler):
# further, set status to 404 because this is not
# serving the expected page
if status is not None:
spawn_url = url_concat(
url_path_join(self.hub.base_url, "spawn", user.escaped_name),
{"next": self.request.uri},
)
spawn_url = url_path_join(self.hub.base_url, "spawn", user.escaped_name)
html = self.render_template(
"not_running.html",
user=user,

View File

@@ -2,6 +2,7 @@
import asyncio
import sys
from unittest import mock
from urllib.parse import parse_qs
from urllib.parse import urlencode
from urllib.parse import urlparse
@@ -16,6 +17,7 @@ from ..handlers import BaseHandler
from ..utils import url_path_join as ujoin
from .mocking import FalsyCallableFormSpawner
from .mocking import FormSpawner
from .test_api import next_event
from .utils import add_user
from .utils import api_request
from .utils import async_requests
@@ -310,6 +312,61 @@ async def test_spawn_form_with_file(app):
}
async def test_spawn_pending(app, username, slow_spawn):
cookies = await app.login_user(username)
# first request, no spawn is pending
# spawn-pending shows button linking to spawn
r = await get_page('/spawn-pending/' + username, app, cookies=cookies)
r.raise_for_status()
page = BeautifulSoup(r.text, "html.parser")
assert "is not running" in page.body.text
link = page.find("a", id="start")
assert link
assert link['href'] == ujoin(app.base_url, '/hub/spawn/', username)
# request spawn
next_url = ujoin(app.base_url, 'user', username, 'tree/foo')
spawn_url = url_concat('/spawn/' + username, dict(next=next_url))
r = await get_page(spawn_url, app, cookies=cookies)
r.raise_for_status()
url = urlparse(r.url)
# spawn redirects to spawn-pending
assert url.path == ujoin(app.base_url, 'hub/spawn-pending', username)
# ?next query arg is preserved
assert parse_qs(url.query).get('next') == [next_url]
# check spawn-pending html
page = BeautifulSoup(r.text, "html.parser")
assert page.find('div', {'class': 'progress'})
# validate event source url by consuming it
script = page.body.find('script').text
assert 'EventSource' in script
# find EventSource url in javascript
# maybe not the most robust way to check this?
eventsource = script.find('new EventSource')
start = script.find('(', eventsource)
end = script.find(')', start)
# strip quotes
progress_url = script[start + 2 : end - 1]
# verify that it works by watching progress events
# (double-duty because we also want to wait for the spawn to finish)
progress = await api_request(app, 'users', username, 'server/progress', stream=True)
ex = async_requests.executor
line_iter = iter(progress.iter_lines(decode_unicode=True))
evt = True
while evt is not None:
evt = await ex.submit(next_event, line_iter)
if evt:
print(evt)
# refresh page after progress is complete
r = await async_requests.get(r.url, cookies=cookies)
r.raise_for_status()
# should have redirected to the now-running server
assert urlparse(r.url).path == urlparse(next_url).path
async def test_user_redirect(app, username):
name = username
cookies = await app.login_user(name)
@@ -650,7 +707,7 @@ async def test_token_page(app):
assert urlparse(r.url).path.endswith('/hub/token')
def extract_body(r):
soup = BeautifulSoup(r.text, "html5lib")
soup = BeautifulSoup(r.text, "html.parser")
import re
# trim empty lines

View File

@@ -35,7 +35,7 @@
require(["jquery"], function ($) {
$("#refresh").click(function () {
window.location.reload();
})
});
// hook up event-stream for progress
var evtSource = new EventSource("{{ progress_url }}");
@@ -85,7 +85,7 @@ require(["jquery"], function ($) {
// open event log for debugging
$('#progress-details').prop('open', true);
}
}
};
});
</script>