Files
topoteretes--cognee/cognee/tests/test_concurrent_cognify_e2e.py
wehub-resource-sync c889a57b6b
Test Suites / Build CI Environment (push) Has been cancelled
Test Suites / Basic Tests (push) Has been cancelled
Test Suites / End-to-End Tests (push) Has been cancelled
Test Suites / CLI Tests (push) Has been cancelled
Test Suites / Slow End-to-End Tests (push) Has been cancelled
Test Suites / Graph Database Tests (push) Has been cancelled
Test Suites / Vector DB Tests (push) Has been cancelled
Test Suites / Temporal Graph Test (push) Has been cancelled
Test Suites / Search Test on Different DBs (push) Has been cancelled
Test Suites / Example Tests (push) Has been cancelled
Test Suites / Notebook Tests (push) Has been cancelled
Test Suites / OS and Python Tests Ubuntu (push) Has been cancelled
Test Suites / OS and Python Tests Extended (push) Has been cancelled
Test Suites / LLM Test Suite (push) Has been cancelled
Test Suites / S3 File Storage Test (push) Has been cancelled
Test Suites / Run Integration Tests (push) Has been cancelled
Test Suites / MCP Tests (push) Has been cancelled
Test Suites / Docker Compose Test (push) Has been cancelled
Test Suites / Docker CI test (push) Has been cancelled
Test Suites / Relational DB Migration Tests (push) Has been cancelled
Test Suites / Distributed Cognee Test (push) Has been cancelled
Test Suites / DB Examples Tests (push) Has been cancelled
Test Suites / Test Completion Status (push) Has been cancelled
Test Suites / Claude Code Review (push) Has been cancelled
Test Suites / basic checks (push) Has been cancelled
build | Build and Push Cognee MCP Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
build | Build and Push Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.11) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.12) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (kuzu, kuzu) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (neo4j, neo4j) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Examples (push) Has been cancelled
Weighted Edges Tests / Code Quality for Weighted Edges (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:02:24 +08:00

134 lines
5.5 KiB
Python

"""End-to-end test: two background cognify runs on one dataset, each isolated to its own file.
Flow (exactly as a caller would do it):
add(file_one) -> cognify(run_in_background=True) # run #1 starts, returns immediately
add(file_two) -> cognify(run_in_background=True) # run #2 starts, returns immediately
gather both runs to completion
The per-dataset asyncio lock in `run_pipeline_per_dataset` serializes everything
touching the dataset, so the two runs cannot clobber each other. We assert, purely
from each run's return value (its PipelineRunCompleted.data_ingestion_info):
* both runs complete successfully (no errored run),
* they are two distinct pipeline runs, and
* run #1 cognified ONLY file_one and run #2 cognified ONLY file_two
(incremental loading skips file_one on the second run).
The two files are intentionally a bit larger than a single sentence so cognify #1
is still processing in the background when we add the second file and start
cognify #2 — i.e. we actually exercise the lock's contention window.
Uses the local default databases (SQLite / LanceDB / file-based graph) via
`config.*_root_directory` + prune, and a real LLM (the credentials CI provides
through secrets). No mocking.
"""
import asyncio
import pathlib
import pytest
import cognee
from cognee.modules.engine.operations.setup import setup as setup_databases
from cognee.modules.pipelines.models.PipelineRunInfo import (
PipelineRunCompleted,
PipelineRunErrored,
)
from cognee.modules.pipelines.queues.pipeline_run_info_queues import get_from_queue
POLL_INTERVAL_SECONDS = 1
def _make_document(subject: str, paragraphs: int = 40) -> str:
"""Build a distinct, multi-paragraph document so cognify produces several chunks."""
return "\n\n".join(
f"{subject} note {i + 1}: In context {i + 1}, {subject} is associated with a "
f"distinct development number {i + 1}. This particular detail about {subject} "
f"is documented as item {i + 1} and connects to topic {i + 1} in measurable ways."
for i in range(paragraphs)
)
async def _await_run_completion(pipeline_run_id) -> PipelineRunCompleted:
"""Drain a background run's info queue until it reaches a terminal status.
No timeout on purpose: real LLM calls are slow and not always stable, so a
deadline here would only produce flaky failures. We wait for the run.
"""
while True:
info = get_from_queue(pipeline_run_id)
if info is None:
await asyncio.sleep(POLL_INTERVAL_SECONDS)
continue
if isinstance(info, PipelineRunErrored):
raise AssertionError(f"Run {pipeline_run_id} errored: {info!r}.")
if isinstance(info, PipelineRunCompleted):
return info
# Non-terminal yields are ignored; keep draining.
def _started_run_id(started, label: str):
"""Extract the pipeline_run_id from a background cognify's return value."""
assert isinstance(started, dict) and started, (
f"{label}: background cognify must return a non-empty "
f"{{dataset_id: PipelineRunStarted}} map, got {started!r}."
)
return next(iter(started.values())).pipeline_run_id
def _processed_data_ids(completed: PipelineRunCompleted) -> set:
"""Data ids the run actually cognified (PipelineRunCompleted items, not skipped ones)."""
processed = set()
for item in completed.data_ingestion_info or []:
if isinstance(item.get("run_info"), PipelineRunCompleted):
processed.add(str(item["data_id"]))
return processed
@pytest.mark.asyncio
async def test_two_background_cognify_runs_are_isolated_per_file():
test_root = pathlib.Path(__file__).parent
cognee.config.data_root_directory(
str((test_root / ".data_storage" / "test_concurrent_cognify").resolve())
)
cognee.config.system_root_directory(
str((test_root / ".cognee_system" / "test_concurrent_cognify").resolve())
)
await cognee.prune.prune_data()
await cognee.prune.prune_system(metadata=True)
await setup_databases()
dataset_name = "concurrent_cognify_e2e"
# ---- First file: add, then cognify in the background -------------------
add_one = await cognee.add(_make_document("Alan Turing"), dataset_name)
data_id_one = str(add_one.data_ingestion_info[0]["data_id"])
started_one = await cognee.cognify([dataset_name], run_in_background=True)
run_id_one = _started_run_id(started_one, "cognify #1")
# ---- Second file: add NEW file, then a second background cognify -------
# (cognify #1 is still processing under the per-dataset lock here.)
add_two = await cognee.add(_make_document("Ada Lovelace"), dataset_name)
data_id_two = str(add_two.data_ingestion_info[0]["data_id"])
started_two = await cognee.cognify([dataset_name], run_in_background=True)
run_id_two = _started_run_id(started_two, "cognify #2")
assert data_id_one != data_id_two, "The two adds must produce two distinct files."
assert run_id_one != run_id_two, "Each cognify must be its own pipeline run."
# ---- Gather both background runs to completion -------------------------
completed_one, completed_two = await asyncio.gather(
_await_run_completion(run_id_one),
_await_run_completion(run_id_two),
)
# ---- Each run cognified exactly its own file --------------------------
assert _processed_data_ids(completed_one) == {data_id_one}, (
"cognify #1 must have processed only the first file."
)
assert _processed_data_ids(completed_two) == {data_id_two}, (
"cognify #2 must have processed only the second file."
)