mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-15 14:03:02 +00:00
exercise start/stop race conditions
this doesn’t cover all the edge cases of each possible stage for the races, but it gets the basics covered.
This commit is contained in:
@@ -231,7 +231,10 @@ class UserServerAPIHandler(APIHandler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not spawner.ready:
|
if not spawner.ready:
|
||||||
raise web.HTTPError(400, "%s is not running" % spawner._log_name)
|
raise web.HTTPError(
|
||||||
|
400, "%s is not running %s" %
|
||||||
|
(spawner._log_name, '(pending: %s)' % spawner.pending if spawner.pending else '')
|
||||||
|
)
|
||||||
# include notify, so that a server that died is noticed immediately
|
# include notify, so that a server that died is noticed immediately
|
||||||
status = yield spawner.poll_and_notify()
|
status = yield spawner.poll_and_notify()
|
||||||
if status is not None:
|
if status is not None:
|
||||||
|
@@ -514,7 +514,7 @@ class BaseHandler(RequestHandler):
|
|||||||
raise KeyError("User %s has no such spawner %r", user.name, name)
|
raise KeyError("User %s has no such spawner %r", user.name, name)
|
||||||
spawner = user.spawners[name]
|
spawner = user.spawners[name]
|
||||||
if spawner.pending:
|
if spawner.pending:
|
||||||
raise RuntimeError("%s pending %s" % (user_server_name, spawner.pending))
|
raise RuntimeError("%s pending %s" % (spawner._log_name, spawner.pending))
|
||||||
# set user._stop_pending before doing anything async
|
# set user._stop_pending before doing anything async
|
||||||
# to avoid races
|
# to avoid races
|
||||||
spawner._stop_pending = True
|
spawner._stop_pending = True
|
||||||
|
@@ -654,6 +654,50 @@ def test_active_server_limit(app, request):
|
|||||||
assert counts['pending'] == 0
|
assert counts['pending'] == 0
|
||||||
|
|
||||||
|
|
||||||
|
@mark.gen_test
|
||||||
|
def test_start_stop_race(app, no_patience, slow_spawn):
|
||||||
|
user = add_user(app.db, app, name='panda')
|
||||||
|
spawner = user.spawner
|
||||||
|
# start the server
|
||||||
|
r = yield api_request(app, 'users', user.name, 'server', method='post')
|
||||||
|
assert r.status_code == 202
|
||||||
|
assert spawner.pending == 'spawn'
|
||||||
|
# additional spawns while spawning shouldn't trigger a new spawn
|
||||||
|
with mock.patch.object(spawner, 'start') as m:
|
||||||
|
r = yield api_request(app, 'users', user.name, 'server', method='post')
|
||||||
|
assert r.status_code == 202
|
||||||
|
assert m.call_count == 0
|
||||||
|
|
||||||
|
# stop while spawning is not okay
|
||||||
|
r = yield api_request(app, 'users', user.name, 'server', method='delete')
|
||||||
|
assert r.status_code == 400
|
||||||
|
while not spawner.ready:
|
||||||
|
yield gen.sleep(0.1)
|
||||||
|
|
||||||
|
spawner.delay = 3
|
||||||
|
# stop the spawner
|
||||||
|
r = yield api_request(app, 'users', user.name, 'server', method='delete')
|
||||||
|
assert r.status_code == 202
|
||||||
|
assert spawner.pending == 'stop'
|
||||||
|
# make sure we get past deleting from the proxy
|
||||||
|
yield gen.sleep(1)
|
||||||
|
# additional stops while stopping shouldn't trigger a new stop
|
||||||
|
with mock.patch.object(spawner, 'stop') as m:
|
||||||
|
r = yield api_request(app, 'users', user.name, 'server', method='delete')
|
||||||
|
assert r.status_code == 202
|
||||||
|
assert m.call_count == 0
|
||||||
|
# start while stopping is not allowed
|
||||||
|
with mock.patch.object(spawner, 'start') as m:
|
||||||
|
r = yield api_request(app, 'users', user.name, 'server', method='post')
|
||||||
|
assert r.status_code == 400
|
||||||
|
|
||||||
|
while spawner.active:
|
||||||
|
yield gen.sleep(0.1)
|
||||||
|
# start after stop is okay
|
||||||
|
r = yield api_request(app, 'users', user.name, 'server', method='post')
|
||||||
|
assert r.status_code == 202
|
||||||
|
|
||||||
|
|
||||||
@mark.gen_test
|
@mark.gen_test
|
||||||
def test_get_proxy(app):
|
def test_get_proxy(app):
|
||||||
r = yield api_request(app, 'proxy')
|
r = yield api_request(app, 'proxy')
|
||||||
|
Reference in New Issue
Block a user