Files
wehub-resource-sync fed8b2eed7
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Backend release / release (push) Has been cancelled
Bandit Security Scan / bandit_scan (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / manifest (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / manifest (push) Has been cancelled
Python linting / ruff (push) Has been cancelled
Run python tests with pytest / Run tests and count coverage (3.12) (push) Has been cancelled
React Widget Build / build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:28:29 +08:00

160 lines
5.7 KiB
Python

"""Tests for NotesRepository against a real Postgres instance.
Notes have a FK to user_tools, so each test creates a tool row first.
"""
from __future__ import annotations
from sqlalchemy import text
from application.storage.db.repositories.notes import NotesRepository
def _repo(conn) -> NotesRepository:
return NotesRepository(conn)
def _make_tool(conn, user_id: str = "test-user", name: str = "notes-tool") -> str:
"""Insert a user_tools row and return its UUID as a string."""
return str(
conn.execute(
text("INSERT INTO user_tools (user_id, name) VALUES (:uid, :name) RETURNING id"),
{"uid": user_id, "name": name},
).scalar()
)
class TestUpsert:
def test_creates_note(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
doc = repo.upsert("test-user", tool_id, "My Note", "Some content")
assert doc["title"] == "My Note"
assert doc["content"] == "Some content"
assert doc["id"] is not None
def test_second_upsert_also_returns_content(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
first = repo.upsert("test-user", tool_id, "title", "v1")
assert first["content"] == "v1"
# A second upsert for the same (user, tool) creates a new note
# (no unique constraint on (user_id, tool_id) exists).
second = repo.upsert("test-user", tool_id, "title2", "v2")
assert second["content"] == "v2"
class TestGetForUserTool:
def test_returns_note(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
repo.upsert("u", tool_id, "t", "c")
fetched = repo.get_for_user_tool("u", tool_id)
assert fetched is not None
assert fetched["content"] == "c"
def test_returns_none_when_missing(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
assert repo.get_for_user_tool("u", tool_id) is None
class TestGetById:
def test_get_existing(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
created = repo.upsert("u", tool_id, "t", "c")
fetched = repo.get(created["id"], "u")
assert fetched["id"] == created["id"]
def test_get_nonexistent_returns_none(self, pg_conn):
repo = _repo(pg_conn)
assert repo.get("00000000-0000-0000-0000-000000000000", "u") is None
def test_get_wrong_user_returns_none(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
created = repo.upsert("u", tool_id, "t", "c")
assert repo.get(created["id"], "other") is None
class TestDelete:
def test_deletes_note(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
repo.upsert("u", tool_id, "t", "c")
deleted = repo.delete("u", tool_id)
assert deleted is True
assert repo.get_for_user_tool("u", tool_id) is None
def test_delete_nonexistent_returns_false(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
deleted = repo.delete("u", tool_id)
assert deleted is False
class TestLegacyMongoIdLookup:
"""Legacy-id resolution for pre-cutover note artifact ids.
``NotesRepository.upsert`` doesn't accept ``legacy_mongo_id`` — only
the Mongo→PG backfill writes it — so tests seed it via raw SQL to
mirror the backfill shape.
"""
def _upsert_with_legacy_id(self, conn, user_id: str, tool_id: str, legacy_id: str) -> str:
return str(
conn.execute(
text(
"""
INSERT INTO notes (user_id, tool_id, title, content, legacy_mongo_id)
VALUES (:user_id, CAST(:tool_id AS uuid), 'note', 'body', :legacy)
RETURNING id
"""
),
{"user_id": user_id, "tool_id": tool_id, "legacy": legacy_id},
).scalar()
)
def test_get_by_legacy_id(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
pg_id = self._upsert_with_legacy_id(pg_conn, "u", tool_id, "abc123")
fetched = repo.get_by_legacy_id("abc123")
assert fetched is not None
assert fetched["id"] == pg_id
def test_get_by_legacy_id_missing(self, pg_conn):
repo = _repo(pg_conn)
assert repo.get_by_legacy_id("nope") is None
def test_get_any_resolves_uuid(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
created = repo.upsert("u", tool_id, "t", "c")
fetched = repo.get_any(created["id"], "u")
assert fetched["id"] == created["id"]
def test_get_any_resolves_legacy_id(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn)
pg_id = self._upsert_with_legacy_id(pg_conn, "u", tool_id, "legacy-obj-1")
fetched = repo.get_any("legacy-obj-1", "u")
assert fetched is not None
assert fetched["id"] == pg_id
def test_get_any_wrong_user_returns_none(self, pg_conn):
repo = _repo(pg_conn)
tool_id = _make_tool(pg_conn, user_id="owner")
self._upsert_with_legacy_id(pg_conn, "owner", tool_id, "legacy-obj-2")
assert repo.get_any("legacy-obj-2", "intruder") is None
def test_get_any_non_uuid_non_legacy_returns_none(self, pg_conn):
"""Non-UUID ids skip the UUID cast and fall through to the
legacy lookup; unknown ids must return None without poisoning
the transaction."""
repo = _repo(pg_conn)
assert repo.get_any("not_a_uuid_or_legacy_id", "u") is None
# Connection is still usable after the failed lookup.
assert repo.get_by_legacy_id("still-works") is None