diff --git a/tests/integration/test_deck_vector_search.py b/tests/integration/test_deck_vector_search.py index 3f6433bc..7524816f 100644 --- a/tests/integration/test_deck_vector_search.py +++ b/tests/integration/test_deck_vector_search.py @@ -207,10 +207,13 @@ async def test_deck_card_chunk_context(nc_client): # Fetch chunk context (simulates viz UI request) # The chunk spans the title, so start=0 and end=len(card_title) + # doc_id is str — keyword-indexed in Qdrant payload; the real + # callers (viz_routes.py from URL path; server/semantic.py from + # str(result.id)) all stringify before reaching this entry point. context = await get_chunk_with_context( nc_client=nc_client, user_id=nc_client.username, - doc_id=card.id, + doc_id=str(card.id), doc_type="deck_card", chunk_start=0, chunk_end=len(card_title), diff --git a/tests/server/login_flow/test_login_flow_integration.py b/tests/server/login_flow/test_login_flow_integration.py index f2db50ba..262be92d 100644 --- a/tests/server/login_flow/test_login_flow_integration.py +++ b/tests/server/login_flow/test_login_flow_integration.py @@ -43,7 +43,13 @@ class TestLoginFlowAuthTools: data = json.loads(result.content[0].text) assert data["status"] == "provisioned" assert data["username"] is not None - assert data["scopes"] is not None + # ``scopes`` may legitimately be ``None`` — per ProvisionStatusResponse + # in models/auth.py, ``None`` is the documented sentinel for "all + # scopes granted" and is what the web provisioning path + # (``provision_routes.py``, used by Astrolabe's "Enable Semantic + # Search" flow) stores. So accept either a non-empty list or None; + # the field's *presence* in the payload is what we care about here. + assert data["scopes"] is None or len(data["scopes"]) > 0 logger.info(f"Provisioned as: {data['username']}, scopes: {data['scopes']}") async def test_provision_access_already_provisioned( diff --git a/tests/unit/vector/test_qdrant_client.py b/tests/unit/vector/test_qdrant_client.py index 146b1f89..9479acdc 100644 --- a/tests/unit/vector/test_qdrant_client.py +++ b/tests/unit/vector/test_qdrant_client.py @@ -237,7 +237,7 @@ async def test_ensure_payload_indexes_logs_and_returns_when_get_collection_raise async def _get_collection_raises(*args, **kwargs): # See _scroll_raises in the backfill section for why this is async. - await anyio.sleep(0) + await anyio.lowlevel.checkpoint() raise RuntimeError("connection refused") client.get_collection.side_effect = _get_collection_raises @@ -494,11 +494,11 @@ async def test_backfill_logs_and_returns_when_scroll_raises(mocker, caplog): # An async-callable side_effect lets AsyncMock await the coroutine # before the exception propagates; assigning a bare exception class # leaks an un-awaited coroutine and trips RuntimeWarning at gc time. - # The `await anyio.sleep(0)` is a no-op event-loop yield that + # The `await anyio.lowlevel.checkpoint()` is a no-op event-loop yield that # satisfies static analysis ("async function uses no async features") # without changing observable behavior. async def _scroll_raises(*args, **kwargs): - await anyio.sleep(0) + await anyio.lowlevel.checkpoint() raise RuntimeError("boom") client.scroll.side_effect = _scroll_raises @@ -538,7 +538,7 @@ async def test_backfill_logs_warning_when_sentinel_upsert_fails(mocker, caplog): async def _upsert_raises(*args, **kwargs): # See _scroll_raises above for why this is async + sleep(0). - await anyio.sleep(0) + await anyio.lowlevel.checkpoint() raise RuntimeError("sentinel write blip") client.upsert.side_effect = _upsert_raises @@ -615,7 +615,7 @@ async def test_ensure_payload_indexes_summarises_failed_fields(mocker, caplog): async def _create_index(*args, **kwargs): # See _scroll_raises above for why this is async + sleep(0). - await anyio.sleep(0) + await anyio.lowlevel.checkpoint() call_count["n"] += 1 if call_count["n"] != 2: raise _make_unexpected(500, b'{"status":{"error":"boom"}}')