mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-20 02:16:39 +00:00
refactor: rename the application package to docsgpt
The backend import package is now docsgpt, the name it will carry on PyPI; application was far too generic to install into anyone's site-packages. git mv plus a mechanical rewrite of every import, dotted string and path reference: 734 Python files, the compose files, Dockerfile, workflows, docs, setup scripts, devcontainer, k8s manifests, vscode config, pytest and coverage config, .gitignore. Behaviour is unchanged. Kept for one release: - A top-level application package whose meta-path finder resolves application.x.y to the already-imported docsgpt.x.y object, so old imports and entry points (celery -A application.app.celery, uvicorn application.asgi:asgi_app) keep working with a FutureWarning. - Celery registers every application.* task name as an alias of its docsgpt.* task on start-up, so messages queued by the previous release still run. The redbeat key prefix moves to redbeat:docsgpt:v2: so schedule entries the previous release wrote are left unread instead of firing twice. The backend image builds from the repository root (docker build -f docsgpt/Dockerfile .) so it can ship the alias package; a root .dockerignore allow-lists docsgpt/ and application/ and keeps caches, local data, .env files, the sample index files and the Dockerfile out. Compose and the image workflows point at the new context.
This commit is contained in:
1 parent
3e7f1f91b4
commit
574f96341e
984 files changed
+9847
-9682
No files matched your search
@@ -9,11 +9,11 @@ from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from application.storage.db.repositories.admin_stats import AdminStatsRepository
|
||||
from application.storage.db.repositories.auth_events import AuthEventsRepository
|
||||
from application.storage.db.repositories.token_usage import TokenUsageRepository
|
||||
from application.storage.db.repositories.user_roles import UserRolesRepository
|
||||
from application.storage.db.repositories.users import UsersRepository
|
||||
from docsgpt.storage.db.repositories.admin_stats import AdminStatsRepository
|
||||
from docsgpt.storage.db.repositories.auth_events import AuthEventsRepository
|
||||
from docsgpt.storage.db.repositories.token_usage import TokenUsageRepository
|
||||
from docsgpt.storage.db.repositories.user_roles import UserRolesRepository
|
||||
from docsgpt.storage.db.repositories.users import UsersRepository
|
||||
|
||||
|
||||
class TestOverview:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
from docsgpt.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
|
||||
|
||||
def _repo(conn) -> AgentFoldersRepository:
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> AgentsRepository:
|
||||
@@ -183,7 +183,7 @@ class TestPart1bFields:
|
||||
assert agent["allow_system_prompt_override"] is False
|
||||
|
||||
def test_extra_source_ids_round_trip(self, pg_conn):
|
||||
from application.storage.db.repositories.sources import SourcesRepository
|
||||
from docsgpt.storage.db.repositories.sources import SourcesRepository
|
||||
|
||||
sources = SourcesRepository(pg_conn)
|
||||
s1 = sources.create("s1", user_id="u")
|
||||
@@ -199,7 +199,7 @@ class TestPart1bFields:
|
||||
assert str(agent["source_id"]) == str(s1["id"])
|
||||
|
||||
def test_workflow_id_fk(self, pg_conn):
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
wf = WorkflowsRepository(pg_conn).create("u", "wf")
|
||||
repo = _repo(pg_conn)
|
||||
@@ -212,7 +212,7 @@ class TestPart1bFields:
|
||||
|
||||
def test_workflow_id_set_null_on_workflow_delete(self, pg_conn):
|
||||
"""ON DELETE SET NULL on agents.workflow_id."""
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
wfr = WorkflowsRepository(pg_conn)
|
||||
wf = wfr.create("u", "wf")
|
||||
@@ -339,7 +339,7 @@ class TestDelete:
|
||||
|
||||
class TestSetFolder:
|
||||
def test_assigns_folder(self, pg_conn):
|
||||
from application.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
from docsgpt.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
|
||||
folder_repo = AgentFoldersRepository(pg_conn)
|
||||
folder = folder_repo.create("user-1", "f")
|
||||
@@ -350,7 +350,7 @@ class TestSetFolder:
|
||||
assert str(fetched["folder_id"]) == str(folder["id"])
|
||||
|
||||
def test_clear_folder(self, pg_conn):
|
||||
from application.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
from docsgpt.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
|
||||
folder_repo = AgentFoldersRepository(pg_conn)
|
||||
folder = folder_repo.create("user-1", "f")
|
||||
@@ -363,7 +363,7 @@ class TestSetFolder:
|
||||
|
||||
class TestClearFolderForAll:
|
||||
def test_clears_folder_from_all_agents(self, pg_conn):
|
||||
from application.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
from docsgpt.storage.db.repositories.agent_folders import AgentFoldersRepository
|
||||
|
||||
folder_repo = AgentFoldersRepository(pg_conn)
|
||||
folder = folder_repo.create("user-1", "f")
|
||||
|
||||
@@ -8,9 +8,9 @@ import pytest
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.artifacts import ArtifactsRepository
|
||||
from application.storage.db.repositories.conversations import ConversationsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.artifacts import ArtifactsRepository
|
||||
from docsgpt.storage.db.repositories.conversations import ConversationsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> ArtifactsRepository:
|
||||
@@ -366,7 +366,7 @@ class TestQuotaEnforcement:
|
||||
repo.create_artifact("alice", "document", conversation_id=_conversation_id(), size=size)
|
||||
|
||||
def test_under_quota_passes(self, pg_conn, monkeypatch):
|
||||
from application.sandbox import artifacts_capture as ac
|
||||
from docsgpt.sandbox import artifacts_capture as ac
|
||||
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_COUNT_PER_USER", 10, raising=False)
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_TOTAL_BYTES_PER_USER", 10_000, raising=False)
|
||||
@@ -376,7 +376,7 @@ class TestQuotaEnforcement:
|
||||
ac._enforce_user_quota(_repo(pg_conn), "alice", 100, new_artifact=True)
|
||||
|
||||
def test_over_count_quota_raises(self, pg_conn, monkeypatch):
|
||||
from application.sandbox import artifacts_capture as ac
|
||||
from docsgpt.sandbox import artifacts_capture as ac
|
||||
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_COUNT_PER_USER", 2, raising=False)
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_TOTAL_BYTES_PER_USER", 10_000_000, raising=False)
|
||||
@@ -386,7 +386,7 @@ class TestQuotaEnforcement:
|
||||
ac._enforce_user_quota(_repo(pg_conn), "alice", 10, new_artifact=True)
|
||||
|
||||
def test_count_quota_ignored_when_appending_version(self, pg_conn, monkeypatch):
|
||||
from application.sandbox import artifacts_capture as ac
|
||||
from docsgpt.sandbox import artifacts_capture as ac
|
||||
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_COUNT_PER_USER", 2, raising=False)
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_TOTAL_BYTES_PER_USER", 10_000_000, raising=False)
|
||||
@@ -396,7 +396,7 @@ class TestQuotaEnforcement:
|
||||
ac._enforce_user_quota(_repo(pg_conn), "alice", 10, new_artifact=False)
|
||||
|
||||
def test_over_total_bytes_quota_raises(self, pg_conn, monkeypatch):
|
||||
from application.sandbox import artifacts_capture as ac
|
||||
from docsgpt.sandbox import artifacts_capture as ac
|
||||
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_COUNT_PER_USER", 10_000, raising=False)
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_TOTAL_BYTES_PER_USER", 500, raising=False)
|
||||
@@ -406,7 +406,7 @@ class TestQuotaEnforcement:
|
||||
ac._enforce_user_quota(_repo(pg_conn), "alice", 100, new_artifact=True) # 450 + 100 > 500
|
||||
|
||||
def test_single_artifact_too_large_raises(self, pg_conn, monkeypatch):
|
||||
from application.sandbox import artifacts_capture as ac
|
||||
from docsgpt.sandbox import artifacts_capture as ac
|
||||
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_COUNT_PER_USER", 10_000, raising=False)
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_TOTAL_BYTES_PER_USER", 10_000_000, raising=False)
|
||||
@@ -415,7 +415,7 @@ class TestQuotaEnforcement:
|
||||
ac._enforce_user_quota(_repo(pg_conn), "alice", 1001, new_artifact=True)
|
||||
|
||||
def test_zero_settings_disable_enforcement(self, pg_conn, monkeypatch):
|
||||
from application.sandbox import artifacts_capture as ac
|
||||
from docsgpt.sandbox import artifacts_capture as ac
|
||||
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_COUNT_PER_USER", 0, raising=False)
|
||||
monkeypatch.setattr(ac.settings, "ARTIFACT_MAX_TOTAL_BYTES_PER_USER", 0, raising=False)
|
||||
@@ -574,7 +574,7 @@ class TestStableRefSeq:
|
||||
repo.resolve_id_by_ref_seq(1)
|
||||
|
||||
def test_resolver_resolves_a_n_by_stable_seq_after_delete(self, pg_conn):
|
||||
from application.agents.tools.artifact_ref import resolve_artifact_id
|
||||
from docsgpt.agents.tools.artifact_ref import resolve_artifact_id
|
||||
|
||||
repo = _repo(pg_conn)
|
||||
conv = _conversation_id()
|
||||
@@ -585,7 +585,7 @@ class TestStableRefSeq:
|
||||
assert resolve_artifact_id(repo, "A2", conversation_id=conv) == b["id"]
|
||||
|
||||
def test_legacy_row_without_ref_seq_falls_back_to_position(self, pg_conn):
|
||||
from application.agents.tools.artifact_ref import resolve_artifact_id
|
||||
from docsgpt.agents.tools.artifact_ref import resolve_artifact_id
|
||||
|
||||
repo = _repo(pg_conn)
|
||||
conv = _conversation_id()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.attachments import AttachmentsRepository
|
||||
from docsgpt.storage.db.repositories.attachments import AttachmentsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> AttachmentsRepository:
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
|
||||
class TestResolveIds:
|
||||
def test_empty_ids_returns_empty_dict(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
assert AttachmentsRepository(pg_conn).resolve_ids([]) == {}
|
||||
|
||||
def test_filters_none_values(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
assert AttachmentsRepository(pg_conn).resolve_ids([None]) == {}
|
||||
|
||||
def test_dedupes_ids(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
|
||||
@@ -28,7 +28,7 @@ class TestResolveIds:
|
||||
assert got[pk] == pk
|
||||
|
||||
def test_legacy_preferred_over_pk(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ class TestResolveIds:
|
||||
|
||||
class TestGetByLegacyId:
|
||||
def test_returns_none_when_not_found(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
assert (
|
||||
@@ -56,7 +56,7 @@ class TestGetByLegacyId:
|
||||
)
|
||||
|
||||
def test_with_user_scope(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -71,7 +71,7 @@ class TestGetByLegacyId:
|
||||
|
||||
class TestAttachmentsUpdate:
|
||||
def test_update_no_filtered_fields_returns_false(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
att = AttachmentsRepository(pg_conn).create("u", "f.txt", "/p")
|
||||
@@ -81,7 +81,7 @@ class TestAttachmentsUpdate:
|
||||
assert got is False
|
||||
|
||||
def test_update_sets_scalar_fields(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
att = AttachmentsRepository(pg_conn).create("u", "f.txt", "/p")
|
||||
@@ -92,7 +92,7 @@ class TestAttachmentsUpdate:
|
||||
assert got is True
|
||||
|
||||
def test_update_any_with_uuid(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -100,7 +100,7 @@ class TestAttachmentsUpdate:
|
||||
assert repo.update_any(str(att["id"]), "u", {"openai_file_id": "x"}) is True
|
||||
|
||||
def test_update_any_falls_back_to_legacy(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -114,7 +114,7 @@ class TestAttachmentsUpdate:
|
||||
)
|
||||
|
||||
def test_update_by_legacy_id_no_fields(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -123,7 +123,7 @@ class TestAttachmentsUpdate:
|
||||
assert got is False
|
||||
|
||||
def test_update_by_legacy_id_not_found(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
got = AttachmentsRepository(pg_conn).update_by_legacy_id(
|
||||
@@ -134,7 +134,7 @@ class TestAttachmentsUpdate:
|
||||
def test_update_by_legacy_id_wrong_user_leaves_row_untouched(self, pg_conn):
|
||||
"""IDOR regression: a caller with user B's id must not be able to
|
||||
mutate user A's attachment by guessing/reusing its legacy id."""
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -152,7 +152,7 @@ class TestAttachmentsUpdate:
|
||||
assert row["openai_file_id"] == "original"
|
||||
|
||||
def test_update_by_legacy_id_same_user_succeeds(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -170,7 +170,7 @@ class TestAttachmentsUpdate:
|
||||
assert row["openai_file_id"] == "updated"
|
||||
|
||||
def test_update_by_legacy_id_rejects_none_user(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -200,7 +200,7 @@ class TestAttachmentsShapeGate:
|
||||
assert conn.execute(_text("SELECT 1")).scalar() == 1
|
||||
|
||||
def test_get_any_legacy_shape_txn_survives(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
@@ -209,7 +209,7 @@ class TestAttachmentsShapeGate:
|
||||
self._assert_txn_alive(pg_conn)
|
||||
|
||||
def test_update_any_unknown_legacy_id_txn_survives(self, pg_conn):
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
repo = AttachmentsRepository(pg_conn)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.connector_sessions import ConnectorSessionsRepository
|
||||
from docsgpt.storage.db.repositories.connector_sessions import ConnectorSessionsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> ConnectorSessionsRepository:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
class TestGetByUserAndProvider:
|
||||
def test_not_found_returns_none(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
assert (
|
||||
@@ -15,7 +15,7 @@ class TestGetByUserAndProvider:
|
||||
)
|
||||
|
||||
def test_with_server_url_filter(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -30,7 +30,7 @@ class TestGetByUserAndProvider:
|
||||
assert str(got["id"]) == str(row["id"])
|
||||
|
||||
def test_with_mismatched_server_url(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -46,7 +46,7 @@ class TestGetByUserAndProvider:
|
||||
|
||||
class TestGetByUserAndServerUrl:
|
||||
def test_returns_row(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -59,7 +59,7 @@ class TestGetByUserAndServerUrl:
|
||||
assert str(got["id"]) == str(row["id"])
|
||||
|
||||
def test_not_found(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
got = ConnectorSessionsRepository(pg_conn).get_by_user_and_server_url(
|
||||
@@ -70,14 +70,14 @@ class TestGetByUserAndServerUrl:
|
||||
|
||||
class TestGetByLegacyId:
|
||||
def test_not_found(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
got = ConnectorSessionsRepository(pg_conn).get_by_legacy_id("x")
|
||||
assert got is None
|
||||
|
||||
def test_with_user_scope(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -96,7 +96,7 @@ class TestMergeSessionData:
|
||||
``get_by_user_and_server_url`` (``NULL = 'x'`` is UNKNOWN)."""
|
||||
|
||||
def test_insert_populates_scalar_server_url(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -117,7 +117,7 @@ class TestMergeSessionData:
|
||||
"""Legacy callers still embed ``server_url`` in the patch — the
|
||||
scalar column is authoritative so the key should be discarded
|
||||
rather than duplicated into the JSONB payload."""
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -133,7 +133,7 @@ class TestMergeSessionData:
|
||||
assert "server_url" not in (inserted["session_data"] or {})
|
||||
|
||||
def test_shallow_merge_preserves_other_keys(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -156,7 +156,7 @@ class TestMergeSessionData:
|
||||
}
|
||||
|
||||
def test_none_valued_keys_are_dropped(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -183,7 +183,7 @@ class TestMergeSessionData:
|
||||
|
||||
class TestConnectorSessionsUpdate:
|
||||
def test_no_filtered_fields_returns_false(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -192,7 +192,7 @@ class TestConnectorSessionsUpdate:
|
||||
assert got is False
|
||||
|
||||
def test_updates_status_and_token(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -204,7 +204,7 @@ class TestConnectorSessionsUpdate:
|
||||
assert got is True
|
||||
|
||||
def test_updates_token_info_jsonb(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
@@ -216,7 +216,7 @@ class TestConnectorSessionsUpdate:
|
||||
assert got is True
|
||||
|
||||
def test_update_by_legacy_no_fields(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
got = ConnectorSessionsRepository(pg_conn).update_by_legacy_id(
|
||||
@@ -225,7 +225,7 @@ class TestConnectorSessionsUpdate:
|
||||
assert got is False
|
||||
|
||||
def test_update_by_legacy_no_match(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
got = ConnectorSessionsRepository(pg_conn).update_by_legacy_id(
|
||||
@@ -235,7 +235,7 @@ class TestConnectorSessionsUpdate:
|
||||
assert got is False
|
||||
|
||||
def test_update_by_legacy_updates_match(self, pg_conn):
|
||||
from application.storage.db.repositories.connector_sessions import (
|
||||
from docsgpt.storage.db.repositories.connector_sessions import (
|
||||
ConnectorSessionsRepository,
|
||||
)
|
||||
repo = ConnectorSessionsRepository(pg_conn)
|
||||
|
||||
@@ -7,7 +7,7 @@ from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
MessageUpdateOutcome,
|
||||
)
|
||||
@@ -32,7 +32,7 @@ class TestCreate:
|
||||
assert doc["_id"] == doc["id"]
|
||||
|
||||
def test_create_with_agent(self, pg_conn):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
agent_repo = AgentsRepository(pg_conn)
|
||||
agent = agent_repo.create("user-1", "a", "active")
|
||||
@@ -440,7 +440,7 @@ class TestResolveAgentRef:
|
||||
ObjectId-era conversation service doesn't silently lose rows."""
|
||||
|
||||
def test_create_translates_objectid_agent_id(self, pg_conn):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
agent_repo = AgentsRepository(pg_conn)
|
||||
legacy_oid = "507f1f77bcf86cd799439099"
|
||||
@@ -452,7 +452,7 @@ class TestResolveAgentRef:
|
||||
assert str(conv["agent_id"]) == agent["id"]
|
||||
|
||||
def test_create_passes_through_uuid_agent_id(self, pg_conn):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
agent_repo = AgentsRepository(pg_conn)
|
||||
agent = agent_repo.create("user-1", "a", "active")
|
||||
@@ -477,7 +477,7 @@ class TestResolveAttachmentRefs:
|
||||
whole message."""
|
||||
|
||||
def _create_attachment(self, pg_conn, legacy: str) -> str:
|
||||
from application.storage.db.repositories.attachments import (
|
||||
from docsgpt.storage.db.repositories.attachments import (
|
||||
AttachmentsRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import uuid
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.idempotency import IdempotencyRepository
|
||||
from docsgpt.storage.db.repositories.idempotency import IdempotencyRepository
|
||||
|
||||
|
||||
def _repo(conn) -> IdempotencyRepository:
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.ingest_chunk_progress import (
|
||||
from docsgpt.storage.db.repositories.ingest_chunk_progress import (
|
||||
IngestChunkProgressRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.memories import MemoriesRepository
|
||||
from docsgpt.storage.db.repositories.memories import MemoriesRepository
|
||||
|
||||
|
||||
def _repo(conn) -> MemoriesRepository:
|
||||
@@ -133,7 +133,7 @@ class TestDefaultToolMemories:
|
||||
"""Synthetic-id memory writes work; real-tool delete still cascades via trigger."""
|
||||
|
||||
def test_synthetic_tool_id_memory_write_succeeds(self, pg_conn):
|
||||
from application.agents.default_tools import default_tool_id
|
||||
from docsgpt.agents.default_tools import default_tool_id
|
||||
|
||||
repo = _repo(pg_conn)
|
||||
synthetic_id = default_tool_id("memory")
|
||||
@@ -143,7 +143,7 @@ class TestDefaultToolMemories:
|
||||
assert got is not None and got["content"] == "built-in"
|
||||
|
||||
def test_built_in_and_explicit_memory_are_separate_stores(self, pg_conn):
|
||||
from application.agents.default_tools import default_tool_id
|
||||
from docsgpt.agents.default_tools import default_tool_id
|
||||
|
||||
repo = _repo(pg_conn)
|
||||
synthetic_id = default_tool_id("memory")
|
||||
@@ -193,7 +193,7 @@ class TestDeleteOrphans:
|
||||
assert repo.get_by_path("u-live", tool_id, "/keep.txt") is not None
|
||||
|
||||
def test_keeps_synthetic_default_tool_memory(self, pg_conn):
|
||||
from application.agents.default_tools import default_tool_id
|
||||
from docsgpt.agents.default_tools import default_tool_id
|
||||
|
||||
repo = _repo(pg_conn)
|
||||
synthetic_id = default_tool_id("memory")
|
||||
@@ -205,7 +205,7 @@ class TestDeleteOrphans:
|
||||
def test_sweeps_orphan_but_spares_synthetic_and_live(self, pg_conn):
|
||||
import uuid
|
||||
|
||||
from application.agents.default_tools import default_tool_id
|
||||
from docsgpt.agents.default_tools import default_tool_id
|
||||
|
||||
repo = _repo(pg_conn)
|
||||
synthetic_id = default_tool_id("memory")
|
||||
|
||||
@@ -14,7 +14,7 @@ import pytest
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from application.storage.db.repositories.message_events import (
|
||||
from docsgpt.storage.db.repositories.message_events import (
|
||||
MessageEventsRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.notes import NotesRepository
|
||||
from docsgpt.storage.db.repositories.notes import NotesRepository
|
||||
|
||||
|
||||
def _repo(conn) -> NotesRepository:
|
||||
|
||||
@@ -4,8 +4,8 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.conversations import ConversationsRepository
|
||||
from application.storage.db.repositories.pending_tool_state import PendingToolStateRepository
|
||||
from docsgpt.storage.db.repositories.conversations import ConversationsRepository
|
||||
from docsgpt.storage.db.repositories.pending_tool_state import PendingToolStateRepository
|
||||
|
||||
|
||||
def _conv(conn) -> dict:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.prompts import PromptsRepository
|
||||
from docsgpt.storage.db.repositories.prompts import PromptsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> PromptsRepository:
|
||||
|
||||
@@ -6,10 +6,10 @@ import json
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.reconciliation import (
|
||||
from docsgpt.storage.db.repositories.reconciliation import (
|
||||
ReconciliationRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ import json
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
MessageUpdateOutcome,
|
||||
)
|
||||
from application.storage.db.repositories.reconciliation import (
|
||||
from docsgpt.storage.db.repositories.reconciliation import (
|
||||
ReconciliationRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ from datetime import datetime, timedelta, timezone
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.schedule_runs import (
|
||||
from docsgpt.storage.db.repositories.schedule_runs import (
|
||||
ScheduleRunsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.schedules import SchedulesRepository
|
||||
from docsgpt.storage.db.repositories.schedules import SchedulesRepository
|
||||
|
||||
|
||||
def _now() -> datetime:
|
||||
|
||||
@@ -6,7 +6,7 @@ from datetime import datetime, timedelta, timezone
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.schedules import SchedulesRepository
|
||||
from docsgpt.storage.db.repositories.schedules import SchedulesRepository
|
||||
|
||||
|
||||
def _insert_agent(conn, user_id: str = "u1") -> str:
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.conversations import ConversationsRepository
|
||||
from application.storage.db.repositories.shared_conversations import SharedConversationsRepository
|
||||
from docsgpt.storage.db.repositories.conversations import ConversationsRepository
|
||||
from docsgpt.storage.db.repositories.shared_conversations import SharedConversationsRepository
|
||||
|
||||
|
||||
def _conv(conn) -> dict:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.sources import SourcesRepository
|
||||
from docsgpt.storage.db.repositories.sources import SourcesRepository
|
||||
|
||||
|
||||
def _repo(conn) -> SourcesRepository:
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.stack_logs import StackLogsRepository
|
||||
from docsgpt.storage.db.repositories.stack_logs import StackLogsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> StackLogsRepository:
|
||||
|
||||
@@ -8,20 +8,20 @@ from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from application.api.user.team_sharing import (
|
||||
from docsgpt.api.user.team_sharing import (
|
||||
can_access,
|
||||
effective_write_owner,
|
||||
owns_resource,
|
||||
team_access_for,
|
||||
visible_with_access,
|
||||
)
|
||||
from application.storage.db.repositories.team_scope import TeamScopeRepository
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.team_members import TeamMembersRepository
|
||||
from application.storage.db.repositories.team_resource_grants import (
|
||||
from docsgpt.storage.db.repositories.team_scope import TeamScopeRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.team_members import TeamMembersRepository
|
||||
from docsgpt.storage.db.repositories.team_resource_grants import (
|
||||
TeamResourceGrantsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.teams import TeamsRepository
|
||||
from docsgpt.storage.db.repositories.teams import TeamsRepository
|
||||
|
||||
|
||||
def _team(conn, owner="alice"):
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from application.storage.db.repositories.prompts import PromptsRepository
|
||||
from application.storage.db.repositories.sources import SourcesRepository
|
||||
from application.storage.db.repositories.user_tools import UserToolsRepository
|
||||
from docsgpt.storage.db.repositories.prompts import PromptsRepository
|
||||
from docsgpt.storage.db.repositories.sources import SourcesRepository
|
||||
from docsgpt.storage.db.repositories.user_tools import UserToolsRepository
|
||||
|
||||
|
||||
class TestPromptsSharing:
|
||||
|
||||
@@ -8,14 +8,14 @@ from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.team_members import TeamMembersRepository
|
||||
from application.storage.db.repositories.team_resource_grants import (
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.team_members import TeamMembersRepository
|
||||
from docsgpt.storage.db.repositories.team_resource_grants import (
|
||||
TeamResourceGrantsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.team_scope import TeamScopeRepository
|
||||
from application.storage.db.repositories.teams import TeamsRepository
|
||||
from application.storage.db.repositories.users import UsersRepository
|
||||
from docsgpt.storage.db.repositories.team_scope import TeamScopeRepository
|
||||
from docsgpt.storage.db.repositories.teams import TeamsRepository
|
||||
from docsgpt.storage.db.repositories.users import UsersRepository
|
||||
|
||||
|
||||
def _new_team(conn, name="Acme", slug=None, owner="alice"):
|
||||
|
||||
@@ -7,7 +7,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.todos import TodosRepository
|
||||
from docsgpt.storage.db.repositories.todos import TodosRepository
|
||||
|
||||
|
||||
def _repo(conn) -> TodosRepository:
|
||||
|
||||
@@ -7,7 +7,7 @@ from datetime import datetime, timedelta, timezone
|
||||
import pytest
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.token_usage import TokenUsageRepository
|
||||
from docsgpt.storage.db.repositories.token_usage import TokenUsageRepository
|
||||
|
||||
|
||||
def _repo(conn) -> TokenUsageRepository:
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.tool_call_attempts import (
|
||||
from docsgpt.storage.db.repositories.tool_call_attempts import (
|
||||
ToolCallAttemptsRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.conversations import (
|
||||
from docsgpt.storage.db.repositories.conversations import (
|
||||
ConversationsRepository,
|
||||
MessageUpdateOutcome,
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from application.storage.db.repositories.user_custom_models import (
|
||||
from docsgpt.storage.db.repositories.user_custom_models import (
|
||||
UserCustomModelsRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from application.storage.db.repositories.user_logs import UserLogsRepository
|
||||
from docsgpt.storage.db.repositories.user_logs import UserLogsRepository
|
||||
|
||||
|
||||
def _rows(conn, user_id):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from application.storage.db.repositories.user_roles import UserRolesRepository
|
||||
from docsgpt.storage.db.repositories.user_roles import UserRolesRepository
|
||||
|
||||
|
||||
def _repo(conn) -> UserRolesRepository:
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from application.storage.db.repositories.user_tools import UserToolsRepository
|
||||
from docsgpt.storage.db.repositories.user_tools import UserToolsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> UserToolsRepository:
|
||||
|
||||
@@ -7,7 +7,7 @@ in the parent conftest) so no data leaks between tests.
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.users import UsersRepository
|
||||
from docsgpt.storage.db.repositories.users import UsersRepository
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
@@ -371,7 +371,7 @@ class TestListPaginated:
|
||||
assert total >= 2
|
||||
assert {"page-a", "page-b"} <= {r["user_id"] for r in rows}
|
||||
sample = next(r for r in rows if r["user_id"] == "page-a")
|
||||
# the keys application/api/admin/routes.py projects must be real columns
|
||||
# the keys docsgpt/api/admin/routes.py projects must be real columns
|
||||
assert "active" in sample and "created_at" in sample
|
||||
|
||||
def test_first_positional_arg_is_the_filter(self, pg_conn):
|
||||
|
||||
@@ -8,8 +8,8 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from application.storage.db.repositories.sources import SourcesRepository
|
||||
from application.storage.db.repositories.wiki_pages import (
|
||||
from docsgpt.storage.db.repositories.sources import SourcesRepository
|
||||
from docsgpt.storage.db.repositories.wiki_pages import (
|
||||
WikiPageConflict,
|
||||
WikiPagesRepository,
|
||||
build_wiki_directory_structure,
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from application.storage.db.repositories.workflow_nodes import WorkflowNodesRepository
|
||||
from application.storage.db.repositories.workflow_edges import WorkflowEdgesRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflow_nodes import WorkflowNodesRepository
|
||||
from docsgpt.storage.db.repositories.workflow_edges import WorkflowEdgesRepository
|
||||
|
||||
|
||||
def _setup(conn) -> tuple[dict, dict, dict]:
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from application.storage.db.repositories.workflow_nodes import WorkflowNodesRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflow_nodes import WorkflowNodesRepository
|
||||
|
||||
|
||||
def _wf(conn) -> dict:
|
||||
|
||||
@@ -5,8 +5,8 @@ from __future__ import annotations
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from application.storage.db.repositories.workflow_runs import WorkflowRunsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflow_runs import WorkflowRunsRepository
|
||||
|
||||
|
||||
def _wf(conn) -> dict:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
from application.storage.db.repositories.workflows import WorkflowsRepository
|
||||
from docsgpt.storage.db.repositories.workflows import WorkflowsRepository
|
||||
|
||||
|
||||
def _repo(conn) -> WorkflowsRepository:
|
||||
@@ -113,9 +113,9 @@ class TestDelete:
|
||||
def test_delete_reaps_run_artifacts(self, pg_conn, monkeypatch):
|
||||
# Run artifacts have no FK cascade off the workflow, so deleting the
|
||||
# workflow must explicitly reclaim their rows (quota) and bytes.
|
||||
from application.storage.db.repositories.artifacts import ArtifactsRepository
|
||||
from application.storage.db.repositories.workflow_runs import WorkflowRunsRepository
|
||||
from application.storage.storage_creator import StorageCreator
|
||||
from docsgpt.storage.db.repositories.artifacts import ArtifactsRepository
|
||||
from docsgpt.storage.db.repositories.workflow_runs import WorkflowRunsRepository
|
||||
from docsgpt.storage.storage_creator import StorageCreator
|
||||
|
||||
deleted_paths: list[str] = []
|
||||
|
||||
@@ -148,8 +148,8 @@ class TestDelete:
|
||||
def test_delete_wrong_user_keeps_run_artifacts(self, pg_conn):
|
||||
# The ownership guard must run before any artifact cleanup, so a
|
||||
# non-owner delete can never reap another user's run artifacts.
|
||||
from application.storage.db.repositories.artifacts import ArtifactsRepository
|
||||
from application.storage.db.repositories.workflow_runs import WorkflowRunsRepository
|
||||
from docsgpt.storage.db.repositories.artifacts import ArtifactsRepository
|
||||
from docsgpt.storage.db.repositories.workflow_runs import WorkflowRunsRepository
|
||||
|
||||
repo = _repo(pg_conn)
|
||||
artifacts = ArtifactsRepository(pg_conn)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
class TestWorkflowsDeleteByLegacy:
|
||||
def test_delete_by_legacy_id_returns_true(self, pg_conn):
|
||||
from application.storage.db.repositories.workflows import (
|
||||
from docsgpt.storage.db.repositories.workflows import (
|
||||
WorkflowsRepository,
|
||||
)
|
||||
repo = WorkflowsRepository(pg_conn)
|
||||
@@ -14,7 +14,7 @@ class TestWorkflowsDeleteByLegacy:
|
||||
assert got is True
|
||||
|
||||
def test_delete_by_legacy_id_no_match(self, pg_conn):
|
||||
from application.storage.db.repositories.workflows import (
|
||||
from docsgpt.storage.db.repositories.workflows import (
|
||||
WorkflowsRepository,
|
||||
)
|
||||
got = WorkflowsRepository(pg_conn).delete_by_legacy_id(
|
||||
@@ -23,7 +23,7 @@ class TestWorkflowsDeleteByLegacy:
|
||||
assert got is False
|
||||
|
||||
def test_delete_by_legacy_id_wrong_user(self, pg_conn):
|
||||
from application.storage.db.repositories.workflows import (
|
||||
from docsgpt.storage.db.repositories.workflows import (
|
||||
WorkflowsRepository,
|
||||
)
|
||||
repo = WorkflowsRepository(pg_conn)
|
||||
|
||||
@@ -14,15 +14,15 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from application.storage.db.bootstrap import ensure_vector_schema
|
||||
from docsgpt.storage.db.bootstrap import ensure_vector_schema
|
||||
|
||||
_APP_PY = Path(__file__).resolve().parents[3] / "application" / "app.py"
|
||||
_APP_PY = Path(__file__).resolve().parents[3] / "docsgpt" / "app.py"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def vector_settings(monkeypatch):
|
||||
"""Settings configured for a pgvector deployment."""
|
||||
from application.core import settings as settings_module
|
||||
from docsgpt.core import settings as settings_module
|
||||
|
||||
settings = settings_module.settings
|
||||
monkeypatch.setattr(settings, "VECTOR_STORE", "pgvector", raising=False)
|
||||
@@ -74,17 +74,17 @@ class TestEnsureVectorSchemaCreates:
|
||||
cursor = MagicMock()
|
||||
conn.cursor.return_value = cursor
|
||||
with patch("psycopg.connect", return_value=conn) as connect, patch(
|
||||
"application.vectorstore.model_registry.dimension_for",
|
||||
"docsgpt.vectorstore.model_registry.dimension_for",
|
||||
return_value=dimension,
|
||||
), patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
) as vector_schema, patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
return_value=table_dimension,
|
||||
), patch(
|
||||
"application.graphrag.store.GraphStore.create_schema"
|
||||
"docsgpt.graphrag.store.GraphStore.create_schema"
|
||||
) as graph_schema, patch(
|
||||
"application.vectorstore.pgvector._pool_for"
|
||||
"docsgpt.vectorstore.pgvector._pool_for"
|
||||
) as pool_for:
|
||||
ensure_vector_schema()
|
||||
return connect, conn, cursor, vector_schema, graph_schema, pool_for
|
||||
@@ -130,10 +130,10 @@ class TestEnsureVectorSchemaDimensionCheck:
|
||||
):
|
||||
conn = MagicMock()
|
||||
with patch("psycopg.connect", return_value=conn), patch(
|
||||
"application.vectorstore.model_registry.dimension_for",
|
||||
"docsgpt.vectorstore.model_registry.dimension_for",
|
||||
return_value=1536,
|
||||
), patch("application.vectorstore.pgvector.PGVectorStore.create_schema"), patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
), patch("docsgpt.vectorstore.pgvector.PGVectorStore.create_schema"), patch(
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
return_value=768,
|
||||
):
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
@@ -151,11 +151,11 @@ class TestEnsureVectorSchemaDimensionCheck:
|
||||
stub = MagicMock()
|
||||
del stub.dimension
|
||||
with patch("psycopg.connect", return_value=conn), patch(
|
||||
"application.vectorstore.base.get_embeddings", return_value=stub
|
||||
"docsgpt.vectorstore.base.get_embeddings", return_value=stub
|
||||
), patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
) as vector_schema, patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
return_value=1536,
|
||||
):
|
||||
ensure_vector_schema() # must not raise
|
||||
@@ -165,12 +165,12 @@ class TestEnsureVectorSchemaDimensionCheck:
|
||||
def test_skips_the_check_when_the_model_cannot_be_loaded(self, vector_settings):
|
||||
conn = MagicMock()
|
||||
with patch("psycopg.connect", return_value=conn), patch(
|
||||
"application.vectorstore.base.get_embeddings",
|
||||
"docsgpt.vectorstore.base.get_embeddings",
|
||||
side_effect=RuntimeError("no model"),
|
||||
), patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
) as vector_schema, patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
return_value=1536,
|
||||
):
|
||||
ensure_vector_schema() # must not raise
|
||||
@@ -182,7 +182,7 @@ class TestEnsureVectorSchemaDimensionCheck:
|
||||
class TestBootGating:
|
||||
"""The boot hook must stay behind AUTO_VECTOR_SCHEMA.
|
||||
|
||||
Asserted on the source because importing ``application.app`` runs the hook,
|
||||
Asserted on the source because importing ``docsgpt.app`` runs the hook,
|
||||
and a test that imports it cannot observe the gate it just executed.
|
||||
"""
|
||||
|
||||
@@ -216,7 +216,7 @@ class TestBootGating:
|
||||
), "ensure_vector_schema() at import time must be wrapped in try/except"
|
||||
|
||||
def test_setting_defaults_on(self):
|
||||
from application.core.settings import Settings
|
||||
from docsgpt.core.settings import Settings
|
||||
|
||||
assert Settings.model_fields["AUTO_VECTOR_SCHEMA"].default is True
|
||||
|
||||
@@ -241,14 +241,14 @@ class TestBootDoesNotLoadTheModel:
|
||||
conn = MagicMock()
|
||||
conn.cursor.return_value = MagicMock()
|
||||
with patch("psycopg.connect", return_value=conn), patch(
|
||||
"application.vectorstore.model_registry.dimension_for",
|
||||
"docsgpt.vectorstore.model_registry.dimension_for",
|
||||
return_value=registry_dim,
|
||||
), patch(
|
||||
"application.vectorstore.base.build_local_embeddings", loader
|
||||
"docsgpt.vectorstore.base.build_local_embeddings", loader
|
||||
), patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
) as vector_schema, patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
return_value=None,
|
||||
):
|
||||
ensure_vector_schema()
|
||||
@@ -280,13 +280,13 @@ class TestUnknownWidthIsProbed:
|
||||
conn = MagicMock()
|
||||
conn.cursor.return_value = MagicMock()
|
||||
with patch("psycopg.connect", return_value=conn), patch(
|
||||
"application.vectorstore.model_registry.dimension_for", return_value=None
|
||||
"docsgpt.vectorstore.model_registry.dimension_for", return_value=None
|
||||
), patch(
|
||||
"application.vectorstore.base.build_local_embeddings", return_value=remote
|
||||
"docsgpt.vectorstore.base.build_local_embeddings", return_value=remote
|
||||
), patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
) as vector_schema, patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
return_value=table_dimension,
|
||||
):
|
||||
try:
|
||||
@@ -340,7 +340,7 @@ class TestBootLoadedModelIsReleased:
|
||||
"""
|
||||
|
||||
def _run(self, vector_settings, *, delegate, base_url=None):
|
||||
from application.vectorstore.base import EmbeddingsSingleton
|
||||
from docsgpt.vectorstore.base import EmbeddingsSingleton
|
||||
|
||||
monkeyed = _embeddings(1024)
|
||||
conn = MagicMock()
|
||||
@@ -356,13 +356,13 @@ class TestBootLoadedModelIsReleased:
|
||||
), patch.object(
|
||||
vector_settings, "EMBEDDINGS_BASE_URL", base_url
|
||||
), patch("psycopg.connect", return_value=conn), patch(
|
||||
"application.vectorstore.model_registry.dimension_for", return_value=None
|
||||
"docsgpt.vectorstore.model_registry.dimension_for", return_value=None
|
||||
), patch(
|
||||
"application.vectorstore.base.build_local_embeddings", side_effect=_build
|
||||
"docsgpt.vectorstore.base.build_local_embeddings", side_effect=_build
|
||||
), patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.create_schema"
|
||||
) as vector_schema, patch(
|
||||
"application.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
"docsgpt.vectorstore.pgvector.PGVectorStore.table_dimension",
|
||||
return_value=1024,
|
||||
):
|
||||
ensure_vector_schema()
|
||||
|
||||
@@ -4,13 +4,13 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from application.storage.db import embeddings_pin
|
||||
from application.storage.db.embeddings_pin import (
|
||||
from docsgpt.storage.db import embeddings_pin
|
||||
from docsgpt.storage.db.embeddings_pin import (
|
||||
NOTICE_KEY,
|
||||
PIN_KEY,
|
||||
resolve_embeddings_pin,
|
||||
)
|
||||
from application.vectorstore.model_registry import DEFAULT_LEGACY, DEFAULT_NEW_INSTALL
|
||||
from docsgpt.vectorstore.model_registry import DEFAULT_LEGACY, DEFAULT_NEW_INSTALL
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -62,7 +62,7 @@ class TestExistingInstall:
|
||||
def test_the_notice_names_the_migration_command(self, store, capsys):
|
||||
_run(store, has_sources=True)
|
||||
out = capsys.readouterr().out
|
||||
assert "application.scripts.reembed" in out
|
||||
assert "docsgpt.scripts.reembed" in out
|
||||
assert DEFAULT_NEW_INSTALL in out
|
||||
|
||||
def test_the_notice_is_shown_only_once(self, store, capsys):
|
||||
@@ -112,7 +112,7 @@ class TestSourceModelMismatch:
|
||||
self._run([(DEFAULT_LEGACY, 28)], DEFAULT_NEW_INSTALL, log)
|
||||
message = log.warning.call_args.args[0] % log.warning.call_args.args[1:]
|
||||
assert "28 built with" in message
|
||||
assert "application.scripts.reembed" in message
|
||||
assert "docsgpt.scripts.reembed" in message
|
||||
|
||||
def test_an_alias_is_not_a_mismatch(self):
|
||||
"""A stored alias and the canonical name are the same model."""
|
||||
|
||||
@@ -15,7 +15,7 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
@@ -123,7 +123,7 @@ class TestMigration0009RoundTrip:
|
||||
|
||||
def test_downgrade_purges_synthetic_id_memory_rows(self, pg_engine):
|
||||
"""Downgrade DELETEs synthetic-id memory rows so the FK can be restored."""
|
||||
from application.agents.default_tools import default_tool_id
|
||||
from docsgpt.agents.default_tools import default_tool_id
|
||||
|
||||
url = pg_engine.url.render_as_string(hide_password=False)
|
||||
# Land on 0009 so synthetic-id rows are insertable (no FK yet).
|
||||
|
||||
@@ -15,7 +15,7 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
|
||||
@@ -15,7 +15,7 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
|
||||
@@ -15,7 +15,7 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
|
||||
@@ -15,7 +15,7 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
|
||||
@@ -15,7 +15,7 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
|
||||
@@ -18,7 +18,7 @@ _0029 = "0029_agent_guardrails"
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
@@ -88,7 +88,7 @@ class TestMigration0029RoundTrip:
|
||||
|
||||
def test_existing_agents_default_to_empty_config(self, pg_engine):
|
||||
"""The server default must backfill, so old agents parse as disabled."""
|
||||
from application.guardrails.config import AgentConfig
|
||||
from docsgpt.guardrails.config import AgentConfig
|
||||
|
||||
with pg_engine.begin() as conn:
|
||||
conn.execute(
|
||||
@@ -158,7 +158,7 @@ class TestMigration0029RoundTrip:
|
||||
|
||||
class TestAgentConfigPersistence:
|
||||
def test_config_round_trips_through_the_repository(self, pg_engine):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
config = {
|
||||
"guardrails": {
|
||||
@@ -188,8 +188,8 @@ class TestAgentConfigPersistence:
|
||||
assert reread["config"] == {"guardrails": {}}
|
||||
|
||||
def test_config_survives_a_parse_round_trip(self, pg_engine):
|
||||
from application.guardrails.config import AgentConfig
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.guardrails.config import AgentConfig
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
raw = AgentConfig.model_validate(
|
||||
{
|
||||
@@ -211,10 +211,10 @@ class TestAgentConfigPersistence:
|
||||
|
||||
class TestGuardrailEventsRepository:
|
||||
def test_record_and_read_back(self, pg_engine):
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
|
||||
with pg_engine.begin() as conn:
|
||||
agent = AgentsRepository(conn).create("u-ev", "a", "published")
|
||||
@@ -256,7 +256,7 @@ class TestGuardrailEventsRepository:
|
||||
assert summary["totals"]["flagged"] == 0
|
||||
|
||||
def test_empty_batch_is_a_noop(self, pg_engine):
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
|
||||
@@ -264,8 +264,8 @@ class TestGuardrailEventsRepository:
|
||||
assert GuardrailEventsRepository(conn).record_many([]) == 0
|
||||
|
||||
def test_events_are_scoped_to_the_requesting_user(self, pg_engine):
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
|
||||
@@ -290,8 +290,8 @@ class TestGuardrailEventsRepository:
|
||||
|
||||
def test_listing_never_exposes_the_key_or_scanned_text(self, pg_engine):
|
||||
"""``api_key`` is the agent's raw key and ``matched_value`` is raw PII."""
|
||||
from application.storage.db.repositories.agents import AgentsRepository
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.agents import AgentsRepository
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
|
||||
@@ -314,7 +314,7 @@ class TestGuardrailEventsRepository:
|
||||
assert "ada@example.com" not in str(rows[0])
|
||||
|
||||
def test_purge_respects_the_window(self, pg_engine):
|
||||
from application.storage.db.repositories.guardrail_events import (
|
||||
from docsgpt.storage.db.repositories.guardrail_events import (
|
||||
GuardrailEventsRepository,
|
||||
)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ pytestmark = pytest.mark.integration
|
||||
|
||||
|
||||
def _alembic_ini() -> Path:
|
||||
return Path(__file__).resolve().parents[3] / "application" / "alembic.ini"
|
||||
return Path(__file__).resolve().parents[3] / "docsgpt" / "alembic.ini"
|
||||
|
||||
|
||||
def _run_alembic(url: str, *args: str) -> None:
|
||||
|
||||
@@ -7,7 +7,7 @@ from uuid import UUID, uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from application.storage.db.serialization import (
|
||||
from docsgpt.storage.db.serialization import (
|
||||
PGNativeJSONEncoder,
|
||||
coerce_pg_native,
|
||||
decode_base64_bytes,
|
||||
@@ -132,7 +132,7 @@ class TestPGNativeJSONEncoder:
|
||||
class TestDecodeBase64Bytes:
|
||||
def test_roundtrip(self):
|
||||
b = b"\x00\x10\x20\xff"
|
||||
from application.storage.db.serialization import _coerce_scalar
|
||||
from docsgpt.storage.db.serialization import _coerce_scalar
|
||||
encoded = _coerce_scalar(b)
|
||||
assert decode_base64_bytes(encoded) == b
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Guardrail tests for :mod:`application.storage.db.session`.
|
||||
"""Guardrail tests for :mod:`docsgpt.storage.db.session`.
|
||||
|
||||
Two invariants are covered here:
|
||||
|
||||
@@ -19,9 +19,9 @@ import pytest
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.exc import DBAPIError, InternalError, OperationalError
|
||||
|
||||
from application.storage.db import engine as engine_module
|
||||
from application.storage.db.engine import STATEMENT_TIMEOUT_MS
|
||||
from application.storage.db.session import db_readonly, db_session
|
||||
from docsgpt.storage.db import engine as engine_module
|
||||
from docsgpt.storage.db.engine import STATEMENT_TIMEOUT_MS
|
||||
from docsgpt.storage.db.session import db_readonly, db_session
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from application.storage.db.source_config import (
|
||||
from docsgpt.storage.db.source_config import (
|
||||
ChunkingConfig,
|
||||
GraphConfig,
|
||||
PreScreenConfig,
|
||||
|
||||
@@ -3,7 +3,7 @@ import os
|
||||
from unittest.mock import MagicMock, mock_open, patch
|
||||
|
||||
import pytest
|
||||
from application.storage.local import LocalStorage
|
||||
from docsgpt.storage.local import LocalStorage
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -5,7 +5,7 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from application.storage.s3 import S3Storage
|
||||
from docsgpt.storage.s3 import S3Storage
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class TestS3StorageInitialization:
|
||||
def test_init_creates_boto3_client_with_s3_credentials(self):
|
||||
"""Should create boto3 S3 client with dedicated S3_* credentials."""
|
||||
with patch("boto3.client") as mock_client, patch(
|
||||
"application.storage.s3.settings"
|
||||
"docsgpt.storage.s3.settings"
|
||||
) as mock_settings:
|
||||
|
||||
mock_settings.S3_BUCKET_NAME = "docsgpt-test-bucket"
|
||||
@@ -71,8 +71,8 @@ class TestS3StorageInitialization:
|
||||
def test_init_falls_back_to_sagemaker_credentials(self):
|
||||
"""Should fall back to deprecated SAGEMAKER_* credentials when S3_* unset."""
|
||||
with patch("boto3.client") as mock_client, patch(
|
||||
"application.storage.s3.settings"
|
||||
) as mock_settings, patch("application.storage.s3.logger") as mock_logger:
|
||||
"docsgpt.storage.s3.settings"
|
||||
) as mock_settings, patch("docsgpt.storage.s3.logger") as mock_logger:
|
||||
|
||||
mock_settings.S3_BUCKET_NAME = "docsgpt-test-bucket"
|
||||
mock_settings.S3_ACCESS_KEY_ID = None
|
||||
@@ -98,7 +98,7 @@ class TestS3StorageInitialization:
|
||||
def test_init_with_custom_endpoint_and_path_style(self):
|
||||
"""Should pass endpoint_url and path-style config for S3-compatible services."""
|
||||
with patch("boto3.client") as mock_client, patch(
|
||||
"application.storage.s3.settings"
|
||||
"docsgpt.storage.s3.settings"
|
||||
) as mock_settings:
|
||||
|
||||
mock_settings.S3_BUCKET_NAME = "my-bucket"
|
||||
@@ -149,7 +149,7 @@ class TestS3StorageSaveFile:
|
||||
file_data = io.BytesIO(b"test content")
|
||||
path = "documents/test.txt"
|
||||
|
||||
with patch("application.storage.s3.settings") as mock_settings:
|
||||
with patch("docsgpt.storage.s3.settings") as mock_settings:
|
||||
mock_settings.SAGEMAKER_REGION = "us-east-1"
|
||||
s3_storage.save_file(file_data, path, storage_class="STANDARD")
|
||||
mock_boto3_client.upload_fileobj.assert_called_once_with(
|
||||
|
||||
Reference in new issue
Block a user