mirror of
https://github.com/arc53/DocsGPT.git
synced 2026-05-07 06:30:03 +00:00
* feat: postgres tests * feat: mongo cutoff * feat: mongo cutoff * feat: adjust docs and compose files * fix: mini code mongo removals * fix: tests and k8s mongo stuff * feat: test fixes * fix: ruff * fix: vale * Potential fix for pull request finding 'CodeQL / Clear-text logging of sensitive information' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix: mini suggestions * vale lint fix 2 * fix: codeql columns thing * fix: test mongo * fix: tests coverage * feat: better tests 4 * feat: more tests * feat: decent coverage * fix: ruff fixes * fix: remove mongo mock * feat: enhance workflow engine and API routes; add document retrieval and source handling * feat: e2e tests * fix: mcp, mongo and more * fix: mini codeql warning * fix: agent chunk view * fix: mini issues * fix: more pg fixes * feat: postgres prep on start * feat: qa tests * fix: mini improvements * fix: tests --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Siddhant Rai <siddhant.rai.5686@gmail.com>
181 lines
5.6 KiB
Python
181 lines
5.6 KiB
Python
"""Unit tests for NotesTool.
|
|
|
|
Same approach as ``test_todo_tool.py``: patch ``NotesRepository`` with
|
|
an in-memory fake and replace ``db_session`` / ``db_readonly`` with a
|
|
no-op context manager.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from contextlib import contextmanager
|
|
|
|
import pytest
|
|
|
|
from application.agents.tools.notes import NotesTool
|
|
|
|
|
|
class _FakeNotesRepo:
|
|
_store: dict[tuple[str, str], dict] = {}
|
|
|
|
def __init__(self, conn=None) -> None:
|
|
self._conn = conn
|
|
|
|
@classmethod
|
|
def reset(cls) -> None:
|
|
cls._store = {}
|
|
|
|
def upsert(self, user_id, tool_id, title, content):
|
|
key = (user_id, tool_id)
|
|
if key in self._store:
|
|
self._store[key].update({"title": title, "content": content})
|
|
else:
|
|
self._store[key] = {
|
|
"id": str(uuid.uuid4()),
|
|
"user_id": user_id,
|
|
"tool_id": tool_id,
|
|
"title": title,
|
|
"content": content,
|
|
}
|
|
return self._store[key]
|
|
|
|
def get_for_user_tool(self, user_id, tool_id):
|
|
return self._store.get((user_id, tool_id))
|
|
|
|
def delete(self, user_id, tool_id):
|
|
return self._store.pop((user_id, tool_id), None) is not None
|
|
|
|
|
|
@contextmanager
|
|
def _noop_conn():
|
|
yield None
|
|
|
|
|
|
@pytest.fixture
|
|
def notes_tool(monkeypatch):
|
|
_FakeNotesRepo.reset()
|
|
monkeypatch.setattr(
|
|
"application.agents.tools.notes.NotesRepository", _FakeNotesRepo
|
|
)
|
|
monkeypatch.setattr(
|
|
"application.agents.tools.notes.db_session", _noop_conn
|
|
)
|
|
monkeypatch.setattr(
|
|
"application.agents.tools.notes.db_readonly", _noop_conn
|
|
)
|
|
return NotesTool({"tool_id": str(uuid.uuid4())}, user_id="test_user")
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_overwrite_and_view(notes_tool):
|
|
assert "saved" in notes_tool.execute_action("overwrite", text="first").lower()
|
|
assert "first" in notes_tool.execute_action("view")
|
|
|
|
assert "saved" in notes_tool.execute_action("overwrite", text="second").lower()
|
|
assert "second" in notes_tool.execute_action("view")
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_delete_note(notes_tool):
|
|
notes_tool.execute_action("overwrite", text="hello")
|
|
assert "deleted" in notes_tool.execute_action("delete").lower()
|
|
assert "no note" in notes_tool.execute_action("view").lower()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_view_not_found(notes_tool):
|
|
result = notes_tool.execute_action("view")
|
|
assert "no note found" in result.lower()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_str_replace(notes_tool):
|
|
notes_tool.execute_action("overwrite", text="Hello world, hello universe")
|
|
result = notes_tool.execute_action("str_replace", old_str="hello", new_str="hi")
|
|
assert "updated" in result.lower()
|
|
|
|
note = notes_tool.execute_action("view")
|
|
assert "hi world, hi universe" in note.lower()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_str_replace_not_found(notes_tool):
|
|
notes_tool.execute_action("overwrite", text="Hello world")
|
|
result = notes_tool.execute_action("str_replace", old_str="goodbye", new_str="hi")
|
|
assert "not found" in result.lower()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_insert_line(notes_tool):
|
|
notes_tool.execute_action("overwrite", text="Line 1\nLine 2\nLine 3")
|
|
result = notes_tool.execute_action("insert", line_number=2, text="Inserted line")
|
|
assert "inserted" in result.lower()
|
|
|
|
note = notes_tool.execute_action("view")
|
|
lines = note.split("\n")
|
|
assert lines[1] == "Inserted line"
|
|
assert lines[2] == "Line 2"
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_delete_nonexistent_note(notes_tool):
|
|
result = notes_tool.execute_action("delete")
|
|
assert "no note found" in result.lower()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_isolation_per_tool_id(monkeypatch):
|
|
_FakeNotesRepo.reset()
|
|
monkeypatch.setattr(
|
|
"application.agents.tools.notes.NotesRepository", _FakeNotesRepo
|
|
)
|
|
monkeypatch.setattr(
|
|
"application.agents.tools.notes.db_session", _noop_conn
|
|
)
|
|
monkeypatch.setattr(
|
|
"application.agents.tools.notes.db_readonly", _noop_conn
|
|
)
|
|
|
|
tool1 = NotesTool({"tool_id": str(uuid.uuid4())}, user_id="test_user")
|
|
tool2 = NotesTool({"tool_id": str(uuid.uuid4())}, user_id="test_user")
|
|
|
|
tool1.execute_action("overwrite", text="Content from tool 1")
|
|
tool2.execute_action("overwrite", text="Content from tool 2")
|
|
|
|
assert "Content from tool 1" in tool1.execute_action("view")
|
|
assert "Content from tool 2" not in tool1.execute_action("view")
|
|
|
|
assert "Content from tool 2" in tool2.execute_action("view")
|
|
assert "Content from tool 1" not in tool2.execute_action("view")
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_init_without_user_id():
|
|
"""Should fail gracefully if no user_id is provided."""
|
|
notes_tool = NotesTool(tool_config={})
|
|
result = notes_tool.execute_action("view")
|
|
assert "user_id" in str(result).lower()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_sentinel_tool_id_short_circuits():
|
|
"""A ``default_{user_id}`` tool_id must no-op with a polite error."""
|
|
tool = NotesTool({}, user_id="test_user")
|
|
assert tool.tool_id == "default_test_user"
|
|
result = tool.execute_action("view")
|
|
assert "Error" in result
|
|
assert "not configured" in result.lower() or "unavailable" in result.lower()
|
|
|
|
|
|
@pytest.mark.unit
|
|
def test_notes_tool_auto_generates_default_tool_id():
|
|
"""Without ``tool_id``, tool_id defaults to ``default_{user_id}``."""
|
|
tool1 = NotesTool({}, user_id="test_user")
|
|
tool2 = NotesTool({}, user_id="test_user")
|
|
assert tool1.tool_id == "default_test_user"
|
|
assert tool2.tool_id == "default_test_user"
|
|
|
|
tool3 = NotesTool({}, user_id="another_user")
|
|
assert tool3.tool_id == "default_another_user"
|
|
assert tool3.tool_id != tool1.tool_id
|