Refactor code structure for improved readability and maintainability

This commit is contained in:
2026-05-08 17:40:11 +08:00
parent 602c2bd71b
commit 0acee1ec6c
20 changed files with 5410 additions and 79 deletions

View File

@ -1,8 +1,10 @@
import asyncio
import sys
import types
import pytest
from fastapi import HTTPException
from fastapi.responses import StreamingResponse
from fastapi.testclient import TestClient
def install_test_stubs() -> None:
@ -59,8 +61,8 @@ def install_test_stubs() -> None:
install_test_stubs()
from memory_gateway.server import app
from memory_gateway.types import Config, ObsidianConfig, SearchResult, ServerConfig
import memory_gateway.server as server
from memory_gateway.types import CommitSummaryRequest, Config, ObsidianConfig, SearchRequest, SearchResult, ServerConfig
class FakeOVClient:
@ -117,9 +119,13 @@ async def fake_summarize_with_llm(content, **kwargs):
}
def build_headers(api_key: str | None):
return {"x-api-key": api_key} if api_key is not None else {}
class FakeUploadFile:
def __init__(self, filename: str, content: bytes) -> None:
self.filename = filename
self._content = content
async def read(self) -> bytes:
return self._content
def test_health_requires_api_key(monkeypatch):
monkeypatch.setattr(
@ -131,14 +137,15 @@ def test_health_requires_api_key(monkeypatch):
fake_get_openviking_client,
)
monkeypatch.setattr("memory_gateway.server.summarize_with_llm", fake_summarize_with_llm)
monkeypatch.setattr("memory_gateway.server.v1_service.evermemos_health", lambda: {"status": "disabled"})
with TestClient(app) as client:
response = client.get("/health")
assert response.status_code == 401
with pytest.raises(HTTPException) as exc_info:
server.verify_api_key()
assert exc_info.value.status_code == 401
response = client.get("/health", headers=build_headers("secret"))
assert response.status_code == 200
assert response.json()["openviking"]["status"] == "ok"
server.verify_api_key("secret")
payload = asyncio.run(server.health_check())
assert payload["openviking"]["status"] == "ok"
def test_mcp_rpc_lists_tools_with_api_key(monkeypatch):
@ -151,18 +158,11 @@ def test_mcp_rpc_lists_tools_with_api_key(monkeypatch):
fake_get_openviking_client,
)
with TestClient(app) as client:
response = client.post(
"/mcp/rpc",
json={"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}},
headers=build_headers("secret"),
)
assert response.status_code == 200
payload = response.json()
assert payload["jsonrpc"] == "2.0"
assert len(payload["result"]["tools"]) >= 7
assert any(tool["name"] == "commit_summary" for tool in payload["result"]["tools"])
assert any(tool["name"] == "memory_search" for tool in payload["result"]["tools"])
server.verify_api_key("secret")
tools = asyncio.run(server.list_tools())
assert len(tools) >= 7
assert any(tool.name == "commit_summary" for tool in tools)
assert any(tool.name == "memory_search" for tool in tools)
def test_search_passes_through_gateway(monkeypatch):
@ -175,12 +175,9 @@ def test_search_passes_through_gateway(monkeypatch):
fake_get_openviking_client,
)
with TestClient(app) as client:
response = client.post("/api/search", json={"query": "phishing"})
assert response.status_code == 200
payload = response.json()
assert payload["total"] == 1
assert payload["results"][0]["abstract"] == "phishing"
payload = asyncio.run(server.api_search(SearchRequest(query="phishing")))
assert payload["total"] == 1
assert payload["results"][0]["abstract"] == "phishing"
def test_summary_endpoint_builds_generic_artifact(monkeypatch):
@ -194,28 +191,26 @@ def test_summary_endpoint_builds_generic_artifact(monkeypatch):
)
monkeypatch.setattr("memory_gateway.server.summarize_with_llm", fake_summarize_with_llm)
with TestClient(app) as client:
response = client.post(
"/api/summary",
json={
"title": "Demo investigation summary",
"content": "结论:这是一次高价值沉淀。\n- 证据:命中历史 case。\n- 建议:后续复用该处置路径。",
"namespace": "demo",
"memory_type": "knowledge",
"tags": ["demo", "summary"],
"persist_as": "none",
},
payload = asyncio.run(
server.api_commit_summary(
CommitSummaryRequest(
title="Demo investigation summary",
content="结论:这是一次高价值沉淀。\n- 证据:命中历史 case。\n- 建议:后续复用该处置路径。",
namespace="demo",
memory_type="knowledge",
tags=["demo", "summary"],
persist_as="none",
)
)
assert response.status_code == 200
payload = response.json()
assert payload["status"] == "ok"
assert payload["artifact"]["title"] == "Demo investigation summary"
assert payload["artifact"]["namespace"] == "demo"
assert payload["artifact"]["memory_type"] == "knowledge"
assert payload["artifact"]["summary"].startswith("LLM summary:")
assert payload["artifact"]["llm"]["provider"] == "fake"
assert payload["memory_result"] is None
assert payload["resource_result"] is None
)
assert payload["status"] == "ok"
assert payload["artifact"]["title"] == "Demo investigation summary"
assert payload["artifact"]["namespace"] == "demo"
assert payload["artifact"]["memory_type"] == "knowledge"
assert payload["artifact"]["summary"].startswith("LLM summary:")
assert payload["artifact"]["llm"]["provider"] == "fake"
assert payload["memory_result"] is None
assert payload["resource_result"] is None
def test_knowledge_upload_converts_saves_and_commits(monkeypatch, tmp_path):
@ -230,21 +225,27 @@ def test_knowledge_upload_converts_saves_and_commits(monkeypatch, tmp_path):
monkeypatch.setattr("memory_gateway.server.summarize_with_llm", fake_summarize_with_llm)
monkeypatch.setattr("memory_gateway.server.convert_file_to_markdown", lambda path: "# Uploaded Doc\n\nImportant uploaded knowledge.")
with TestClient(app) as client:
response = client.post(
"/api/knowledge/upload",
data={
"title": "Uploaded Knowledge",
"namespace": "demo",
"knowledge_type": "playbook",
"tags": "demo,upload",
"persist_as": "resource",
},
files={"file": ("sample.txt", b"hello", "text/plain")},
)
async def fake_to_thread(func, *args, **kwargs):
return func(*args, **kwargs)
monkeypatch.setattr("memory_gateway.server.asyncio.to_thread", fake_to_thread)
upload = FakeUploadFile(filename="sample.txt", content=b"hello")
payload = asyncio.run(
server.api_upload_knowledge(
file=upload,
title="Uploaded Knowledge",
namespace="demo",
knowledge_type="playbook",
tags="demo,upload",
source=None,
obsidian_dir=None,
resource_uri=None,
persist_as="resource",
max_summary_chars=1000,
)
)
assert response.status_code == 200
payload = response.json()
assert payload["status"] == "ok"
assert payload["artifact"]["schema_version"] == "memory-gateway.knowledge_upload.v1"
assert payload["artifact"]["knowledge_type"] == "playbook"