diff --git a/jupyterhub/tests/test_api.py b/jupyterhub/tests/test_api.py index 118dad7d..8b08fabf 100644 --- a/jupyterhub/tests/test_api.py +++ b/jupyterhub/tests/test_api.py @@ -347,6 +347,7 @@ def test_spawn(app, io_loop): 's': ['value'], 'i': 5, } + before_servers = sorted(db.query(orm.Server), key=lambda s: s.url) r = api_request(app, 'users', name, 'server', method='post', data=json.dumps(options)) assert r.status_code == 201 assert 'pid' in user.state @@ -379,6 +380,13 @@ def test_spawn(app, io_loop): status = io_loop.run_sync(app_user.spawner.poll) assert status == 0 + # check that we cleaned up after ourselves + assert user.server is None + after_servers = sorted(db.query(orm.Server), key=lambda s: s.url) + assert before_servers == after_servers + tokens = list(db.query(orm.APIToken).filter(orm.APIToken.user_id==user.id)) + assert tokens == [] + def test_slow_spawn(app, io_loop): # app.tornado_application.settings['spawner_class'] = mocking.SlowSpawner diff --git a/jupyterhub/user.py b/jupyterhub/user.py index c1e5dae9..c11b6cd6 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -291,12 +291,20 @@ class User(HasTraits): self.spawner.stop_polling() self.stop_pending = True try: + api_token = self.spawner.api_token status = yield spawner.poll() if status is None: yield self.spawner.stop() spawner.clear_state() self.state = spawner.get_state() self.last_activity = datetime.utcnow() + # cleanup server entry, API token from defunct server + if self.server: + # cleanup server entry from db + self.db.delete(self.server) + orm_token = orm.APIToken.find(self.db, api_token) + if orm_token: + self.db.delete(orm_token) self.server = None self.db.commit() finally: