Files
arc53--docsgpt/tests/api/test_internal_routes.py
wehub-resource-sync fed8b2eed7
Backend release / release (push) Waiting to run
Bandit Security Scan / bandit_scan (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push multi-arch DocsGPT Docker image / manifest (push) Blocked by required conditions
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Waiting to run
Build and push DocsGPT FE Docker image for development / manifest (push) Blocked by required conditions
Python linting / ruff (push) Waiting to run
Run python tests with pytest / Run tests and count coverage (3.12) (push) Waiting to run
React Widget Build / build (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:28:29 +08:00

321 lines
11 KiB
Python

"""Tests for application/api/internal/routes.py.
Uses the ephemeral ``pg_conn`` fixture so the sources repository writes
happen against a real Postgres schema.
"""
import io
from contextlib import contextmanager
from unittest.mock import MagicMock, patch
from flask import Flask
_TEST_KEY = "test-internal-key"
_AUTH = {"X-Internal-Key": _TEST_KEY}
@contextmanager
def _patch_db(conn):
@contextmanager
def _yield():
yield conn
with patch(
"application.api.internal.routes.db_session", _yield
):
yield
def _make_app():
from application.api.internal.routes import internal
app = Flask(__name__)
app.register_blueprint(internal)
app.config["TESTING"] = True
return app
class TestVerifyInternalKey:
def test_rejects_when_internal_key_not_configured(self):
app = _make_app()
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", ""
):
with app.test_client() as c:
r = c.get("/api/download")
assert r.status_code == 401
def test_rejects_when_key_missing(self):
app = _make_app()
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
):
with app.test_client() as c:
r = c.get("/api/download")
assert r.status_code == 401
def test_rejects_when_key_mismatch(self):
app = _make_app()
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
):
with app.test_client() as c:
r = c.get("/api/download", headers={"X-Internal-Key": "wrong"})
assert r.status_code == 401
class TestDownloadFile:
def test_returns_404_for_missing_file(self, tmp_path):
app = _make_app()
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.UPLOAD_FOLDER",
str(tmp_path),
), patch(
"application.api.internal.routes.current_dir", ""
):
with app.test_client() as c:
r = c.get(
"/api/download?user=alice&name=job1&file=missing.txt",
headers=_AUTH,
)
assert r.status_code == 404
def test_returns_file_when_present(self, tmp_path):
app = _make_app()
user_dir = tmp_path / "bob" / "job1"
user_dir.mkdir(parents=True)
(user_dir / "hello.txt").write_text("hi there")
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.UPLOAD_FOLDER",
str(tmp_path),
), patch(
"application.api.internal.routes.current_dir", ""
):
with app.test_client() as c:
r = c.get(
"/api/download?user=bob&name=job1&file=hello.txt",
headers=_AUTH,
)
assert r.status_code == 200
assert r.data == b"hi there"
class TestUploadIndex:
def _base_form(self, *, source_id="source-1"):
return {
"user": "alice",
"name": "Job A",
"tokens": "100",
"retriever": "classic",
"id": source_id,
"type": "file",
}
def test_rejects_without_auth(self):
app = _make_app()
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
):
with app.test_client() as c:
r = c.post("/api/upload_index")
assert r.status_code == 401
def test_rejects_missing_user(self):
app = _make_app()
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
):
with app.test_client() as c:
r = c.post("/api/upload_index", headers=_AUTH, data={})
assert r.status_code == 200
assert r.json == {"status": "no user"}
def test_rejects_missing_name(self):
app = _make_app()
form = {"user": "alice"}
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
):
with app.test_client() as c:
r = c.post("/api/upload_index", headers=_AUTH, data=form)
assert r.status_code == 200
assert r.json == {"status": "no name"}
def test_creates_new_source_for_non_faiss_store(self, pg_conn):
"""For non-faiss VECTOR_STORE the route skips file uploads entirely."""
from application.storage.db.repositories.sources import SourcesRepository
app = _make_app()
form = {**self._base_form(source_id="legacy-source-1")}
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.VECTOR_STORE", "milvus"
), patch(
"application.api.internal.routes.settings.EMBEDDINGS_NAME", "emb"
), patch(
"application.api.internal.routes.StorageCreator.get_storage",
return_value=MagicMock(),
), _patch_db(pg_conn):
with app.test_client() as c:
r = c.post("/api/upload_index", headers=_AUTH, data=form)
assert r.status_code == 200
assert r.json == {"status": "ok"}
repo = SourcesRepository(pg_conn)
found = repo.get_by_legacy_id("legacy-source-1", "alice")
assert found is not None
def test_updates_existing_source(self, pg_conn):
from application.storage.db.repositories.sources import SourcesRepository
repo = SourcesRepository(pg_conn)
created = repo.create(
"initial",
user_id="alice",
legacy_mongo_id="legacy-src-2",
tokens="0",
)
app = _make_app()
form = {**self._base_form(source_id="legacy-src-2"), "tokens": "999"}
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.VECTOR_STORE", "milvus"
), patch(
"application.api.internal.routes.settings.EMBEDDINGS_NAME", "emb"
), patch(
"application.api.internal.routes.StorageCreator.get_storage",
return_value=MagicMock(),
), _patch_db(pg_conn):
with app.test_client() as c:
r = c.post("/api/upload_index", headers=_AUTH, data=form)
assert r.status_code == 200
updated = repo.get(str(created["id"]), "alice")
assert updated["tokens"] == "999"
def test_handles_directory_structure_and_file_name_map(self, pg_conn):
import json
app = _make_app()
form = {
**self._base_form(source_id="legacy-src-3"),
"directory_structure": json.dumps({"root": {"a.txt": None}}),
"file_name_map": json.dumps({"a.txt": "Original A.txt"}),
}
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.VECTOR_STORE", "milvus"
), patch(
"application.api.internal.routes.settings.EMBEDDINGS_NAME", "emb"
), patch(
"application.api.internal.routes.StorageCreator.get_storage",
return_value=MagicMock(),
), _patch_db(pg_conn):
with app.test_client() as c:
r = c.post("/api/upload_index", headers=_AUTH, data=form)
assert r.status_code == 200
def test_invalid_json_falls_back_to_empty(self, pg_conn):
app = _make_app()
form = {
**self._base_form(source_id="legacy-src-4"),
"directory_structure": "not-json",
"file_name_map": "also-not-json",
}
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.VECTOR_STORE", "milvus"
), patch(
"application.api.internal.routes.settings.EMBEDDINGS_NAME", "emb"
), patch(
"application.api.internal.routes.StorageCreator.get_storage",
return_value=MagicMock(),
), _patch_db(pg_conn):
with app.test_client() as c:
r = c.post("/api/upload_index", headers=_AUTH, data=form)
assert r.status_code == 200
def test_faiss_missing_file_faiss(self, pg_conn):
app = _make_app()
form = self._base_form(source_id="legacy-src-5")
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.VECTOR_STORE", "faiss"
), patch(
"application.api.internal.routes.StorageCreator.get_storage",
return_value=MagicMock(),
):
with app.test_client() as c:
r = c.post(
"/api/upload_index",
headers=_AUTH,
data=form,
content_type="multipart/form-data",
)
assert r.status_code == 200
assert r.json == {"status": "no file"}
def test_faiss_missing_file_pkl(self, pg_conn):
app = _make_app()
data = {
**self._base_form(source_id="legacy-src-6"),
"file_faiss": (io.BytesIO(b"faiss-data"), "index.faiss"),
}
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.VECTOR_STORE", "faiss"
), patch(
"application.api.internal.routes.StorageCreator.get_storage",
return_value=MagicMock(),
):
with app.test_client() as c:
r = c.post(
"/api/upload_index",
headers=_AUTH,
data=data,
content_type="multipart/form-data",
)
assert r.status_code == 200
assert r.json == {"status": "no file"}
def test_faiss_saves_both_files(self, pg_conn):
app = _make_app()
fake_storage = MagicMock()
data = {
**self._base_form(source_id="legacy-src-7"),
"file_faiss": (io.BytesIO(b"faiss-data"), "index.faiss"),
"file_pkl": (io.BytesIO(b"pkl-data"), "index.pkl"),
}
with patch(
"application.api.internal.routes.settings.INTERNAL_KEY", _TEST_KEY
), patch(
"application.api.internal.routes.settings.VECTOR_STORE", "faiss"
), patch(
"application.api.internal.routes.settings.EMBEDDINGS_NAME", "emb"
), patch(
"application.api.internal.routes.StorageCreator.get_storage",
return_value=fake_storage,
), _patch_db(pg_conn):
with app.test_client() as c:
r = c.post(
"/api/upload_index",
headers=_AUTH,
data=data,
content_type="multipart/form-data",
)
assert r.status_code == 200
assert r.json == {"status": "ok"}
assert fake_storage.save_file.call_count == 2