#4830·jupyterhub

test_share_codes_api_revoke flaky

Author: minrkCreated May 31, 2024Updated Dec 14, 2025
Labelsbug

The test test_share_codes_api_revoke[shares!server=SERVER-code=CODE-204] has been flaky, sometimes returning a 404 status for the deleted code instead of 204 (DELETED).

I've tried to debug this a few times, but it's very hard to reproduce reliably.

Possible issues:

  • failure to commit share code to database in the first place, e.g. via rollback
  • escaping problem where transmitted code gets mangled somehow, in one direction or the other, or in the lookup code
  • code gets expired/deleted somehow

None of these seem particularly likely. Escaping seems the most likely, but that should be reproducible by hardcoding the code value to the one from the failed test.

Captured output from this run for log retention purposes:

=================================== FAILURES ===================================
_______ test_share_codes_api_revoke[shares!server=SERVER-code=CODE-204] ________

app = <jupyterhub.tests.mocking.MockHub object at 0x7f76bac0ebd0>
user = <User(testuser-597 0/1 running)>, group = <Group testgroup-184>
share_user = <User(share_with-598 0/0 running)>
create_user_with_scopes = <function create_user_with_scopes.<locals>.temp_user_creator at 0x7f76e9685580>
have_scopes = 'shares!server=SERVER', delete_by = 'code=CODE', status = 204

    @pytest.mark.parametrize(
        "have_scopes, delete_by, status",
        [
            (None, None, 204),
            ("shares", "id=ID", 204),
            (
                "shares!server=SERVER",
                "code=CODE",
                204,
            ),
            ("shares!user=other", None, 404),
            ("read:shares", "code=CODE", 403),
            ("shares", "id=invalid", 404),
            ("shares", "id=sc_9999", 404),
            ("shares", "code=nomatch", 404),
        ],
    )
    async def test_share_codes_api_revoke(
        app,
        user,
        group,
        share_user,
        create_user_with_scopes,
        have_scopes,
        delete_by,
        status,
    ):
        db = app.db
        spawner = user.spawner.orm_spawner
    
        _expand_scopes = partial(expand_scopes, user=user, share_with=share_user)
        # make sure default spawner exists
        spawner = user.spawner.orm_spawner
        share_code, code = orm.ShareCode.new(
            db, spawner, scopes=list(scopes.access_scopes(spawner=spawner))
        )
    
        assert orm.ShareCode.find(db, code=code)
        other_share_code, other_code = orm.ShareCode.new(
            db, spawner, scopes=list(scopes.access_scopes(spawner=spawner))
        )
    
        if have_scopes is None:
            # default: needed permissions
            have_scopes = "shares"
    
        requester = create_user_with_scopes(*_expand_scopes(have_scopes))
    
        url = f"/share-codes/{user.name}/"
        if delete_by:
            query = delete_by.replace("CODE", code).replace("ID", f"sc_{share_code.id}")
            url = f"{url}?{query}"
    
        r = await api_request(
            app,
            url,
            method="delete",
            name=requester.name,
        )
>       assert r.status_code == status
E       assert 404 == 204
E        +  where 404 = <Response [404]>.status_code


/home/runner/work/jupyterhub/jupyterhub/jupyterhub/tests/test_shares.py:1345: AssertionError
---------------------------- Captured stderr setup -----------------------------
[D 2024-05-30 14:31:01.065 MockHub roles:326] Assigning default role to User testuser-597
[I 2024-05-30 14:31:01.067 MockHub roles:281] Adding role user for User: testuser-597
[D 2024-05-30 14:31:01.084 MockHub roles:326] Assigning default role to User share_with-598
[I 2024-05-30 14:31:01.086 MockHub roles:281] Adding role user for User: share_with-598
------------------------------ Captured log setup ------------------------------
DEBUG    MockHub:roles.py:326 Assigning default role to User testuser-597
INFO     MockHub:roles.py:281 Adding role user for User: testuser-597
DEBUG    MockHub:roles.py:326 Assigning default role to User share_with-598
INFO     MockHub:roles.py:281 Adding role user for User: share_with-598
----------------------------- Captured stderr call -----------------------------
[D 2024-05-30 14:31:01.090 MockHub user:496] Creating <class 'jupyterhub.tests.mocking.MockSpawner'> for testuser-597:
[I 2024-05-30 14:31:01.091 MockHub orm:961] Creating share code for testuser-597/
[I 2024-05-30 14:31:01.102 MockHub orm:961] Creating share code for testuser-597/
[I 2024-05-30 14:31:01.114 MockHub roles:281] Adding role temp_role_1 for User: temp_user_1
[D 2024-05-30 14:31:01.137 MockHub base:366] Recording first activity for <APIToken('858a...', user='temp_user_1', client_id='jupyterhub')>
[D 2024-05-30 14:31:01.137 MockHub base:366] Recording first activity for <User(temp_user_1 0/1 running)>
[D 2024-05-30 14:31:01.140 MockHub base:411] Refreshing auth for temp_user_1
[D 2024-05-30 14:31:01.141 MockHub scopes:1010] Checking access to /@/space%20word/hub/api/share-codes/testuser-597/ via scope shares!server=testuser-597/
[W 2024-05-30 14:31:01.152 MockHub web:1873] 404 DELETE /@/space%20word/hub/api/share-codes/testuser-597/?code=jP4YqMfM9fXklsc_1ypLOIpe2EXCwCAoW7KBKzV8VXgH0 (127.0.0.1): No matching code found
[W 2024-05-30 14:31:01.152 MockHub log:192] 404 DELETE /@/space%20word/hub/api/share-codes/testuser-597/?code=[secret] ([email protected]) 17.08ms
------------------------------ Captured log call -------------------------------
DEBUG    MockHub:user.py:496 Creating <class 'jupyterhub.tests.mocking.MockSpawner'> for testuser-597:
INFO     MockHub:orm.py:961 Creating share code for testuser-597/
INFO     MockHub:orm.py:961 Creating share code for testuser-597/
INFO     MockHub:roles.py:281 Adding role temp_role_1 for User: temp_user_1
DEBUG    MockHub:base.py:366 Recording first activity for <APIToken('858a...', user='temp_user_1', client_id='jupyterhub')>
DEBUG    MockHub:base.py:366 Recording first activity for <User(temp_user_1 0/1 running)>
DEBUG    MockHub:base.py:411 Refreshing auth for temp_user_1
DEBUG    MockHub:scopes.py:1010 Checking access to /@/space%20word/hub/api/share-codes/testuser-597/ via scope shares!server=testuser-597/
WARNING  MockHub:web.py:1873 404 DELETE /@/space%20word/hub/api/share-codes/testuser-597/?code=jP4YqMfM9fXklsc_1ypLOIpe2EXCwCAoW7KBKzV8VXgH0 (127.0.0.1): No matching code found
WARNING  MockHub:log.py:192 404 DELETE /@/space%20word/hub/api/share-codes/testuser-597/?code=[secret] ([email protected]) 17.08ms
--------------------------- Captured stderr teardown ---------------------------
[D 2024-05-30 14:31:01.273 MockHub conftest:189] Deleting test user testuser-597
[D 2024-05-30 14:31:01.289 MockHub conftest:189] Deleting test user share_with-598
[D 2024-05-30 14:31:01.298 MockHub conftest:189] Deleting test user temp_user_1
[D 2024-05-30 14:31:01.312 MockHub conftest:193] Deleting test group testgroup-184
[D 2024-05-30 14:31:01.316 MockHub proxy:925] Proxy: Fetching GET http://127.0.0.1:8001/api/routes
---------------------------- Captured log teardown -----------------------------
DEBUG    MockHub:conftest.py:189 Deleting test user testuser-597
DEBUG    MockHub:conftest.py:189 Deleting test user share_with-598
DEBUG    MockHub:conftest.py:189 Deleting test user temp_user_1
DEBUG    MockHub:conftest.py:193 Deleting test group testgroup-184
DEBUG    MockHub:proxy.py:925 Proxy: Fetching GET http://127.0.0.1:8001/api/routes