mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-18 15:33:02 +00:00
test spawn-pending page
This commit is contained in:
@@ -131,21 +131,24 @@ class SpawnHandler(BaseHandler):
|
|||||||
# 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(
|
pending_url = url_path_join(
|
||||||
user,
|
self.hub.base_url, "spawn-pending", user.name, server_name
|
||||||
default=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.
|
# spawner is active, redirect back to get progress, etc.
|
||||||
if spawner.ready:
|
if spawner.ready:
|
||||||
self.log.info("Server %s is already running", spawner._log_name)
|
self.log.info("Server %s is already running", spawner._log_name)
|
||||||
next_url = self.get_next_url(user, default=user.server_url(server_name))
|
next_url = self.get_next_url(user, default=user.server_url(server_name))
|
||||||
|
self.redirect(next_url)
|
||||||
|
return
|
||||||
|
|
||||||
elif spawner.active:
|
elif spawner.active:
|
||||||
self.log.info("Server %s is already active", spawner._log_name)
|
self.log.info("Server %s is already active", spawner._log_name)
|
||||||
self.redirect(next_url)
|
self.redirect(pending_url)
|
||||||
return
|
return
|
||||||
|
|
||||||
# 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.
|
||||||
@@ -169,7 +172,7 @@ class SpawnHandler(BaseHandler):
|
|||||||
# not running, no form. Trigger spawn and redirect back to /user/:name
|
# not running, no form. Trigger spawn and redirect back to /user/:name
|
||||||
f = asyncio.ensure_future(self.spawn_single_user(user, server_name))
|
f = asyncio.ensure_future(self.spawn_single_user(user, server_name))
|
||||||
await asyncio.wait([f], timeout=1)
|
await asyncio.wait([f], timeout=1)
|
||||||
self.redirect(next_url)
|
self.redirect(pending_url)
|
||||||
|
|
||||||
@web.authenticated
|
@web.authenticated
|
||||||
async def post(self, for_user=None, server_name=''):
|
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
|
# further, set status to 404 because this is not
|
||||||
# serving the expected page
|
# serving the expected page
|
||||||
if status is not None:
|
if status is not None:
|
||||||
spawn_url = url_concat(
|
spawn_url = url_path_join(self.hub.base_url, "spawn", user.escaped_name)
|
||||||
url_path_join(self.hub.base_url, "spawn", user.escaped_name),
|
|
||||||
{"next": self.request.uri},
|
|
||||||
)
|
|
||||||
html = self.render_template(
|
html = self.render_template(
|
||||||
"not_running.html",
|
"not_running.html",
|
||||||
user=user,
|
user=user,
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
from urllib.parse import parse_qs
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ from ..handlers import BaseHandler
|
|||||||
from ..utils import url_path_join as ujoin
|
from ..utils import url_path_join as ujoin
|
||||||
from .mocking import FalsyCallableFormSpawner
|
from .mocking import FalsyCallableFormSpawner
|
||||||
from .mocking import FormSpawner
|
from .mocking import FormSpawner
|
||||||
|
from .test_api import next_event
|
||||||
from .utils import add_user
|
from .utils import add_user
|
||||||
from .utils import api_request
|
from .utils import api_request
|
||||||
from .utils import async_requests
|
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):
|
async def test_user_redirect(app, username):
|
||||||
name = username
|
name = username
|
||||||
cookies = await app.login_user(name)
|
cookies = await app.login_user(name)
|
||||||
@@ -650,7 +707,7 @@ async def test_token_page(app):
|
|||||||
assert urlparse(r.url).path.endswith('/hub/token')
|
assert urlparse(r.url).path.endswith('/hub/token')
|
||||||
|
|
||||||
def extract_body(r):
|
def extract_body(r):
|
||||||
soup = BeautifulSoup(r.text, "html5lib")
|
soup = BeautifulSoup(r.text, "html.parser")
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# trim empty lines
|
# trim empty lines
|
||||||
|
@@ -35,7 +35,7 @@
|
|||||||
require(["jquery"], function ($) {
|
require(["jquery"], function ($) {
|
||||||
$("#refresh").click(function () {
|
$("#refresh").click(function () {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
})
|
});
|
||||||
|
|
||||||
// hook up event-stream for progress
|
// hook up event-stream for progress
|
||||||
var evtSource = new EventSource("{{ progress_url }}");
|
var evtSource = new EventSource("{{ progress_url }}");
|
||||||
@@ -85,7 +85,7 @@ require(["jquery"], function ($) {
|
|||||||
// open event log for debugging
|
// open event log for debugging
|
||||||
$('#progress-details').prop('open', true);
|
$('#progress-details').prop('open', true);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
Reference in New Issue
Block a user