mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-17 06:14:25 +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
@@ -1,4 +1,4 @@
|
||||
"""Tests for application/api/user/tools/mcp.py using real PG."""
|
||||
"""Tests for docsgpt/api/user/tools/mcp.py using real PG."""
|
||||
|
||||
from contextlib import contextmanager
|
||||
from unittest.mock import MagicMock, patch
|
||||
@@ -19,43 +19,43 @@ def _patch_db(conn):
|
||||
yield conn
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.db_session", _yield
|
||||
"docsgpt.api.user.tools.mcp.db_session", _yield
|
||||
), patch(
|
||||
"application.api.user.tools.mcp.db_readonly", _yield
|
||||
"docsgpt.api.user.tools.mcp.db_readonly", _yield
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
class TestSanitizeMcpTransport:
|
||||
def test_defaults_to_auto(self):
|
||||
from application.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
from docsgpt.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
cfg = {}
|
||||
got = _sanitize_mcp_transport(cfg)
|
||||
assert got == "auto"
|
||||
assert cfg["transport_type"] == "auto"
|
||||
|
||||
def test_accepts_supported_transports(self):
|
||||
from application.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
from docsgpt.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
for t in ("auto", "sse", "http"):
|
||||
cfg = {"transport_type": t}
|
||||
assert _sanitize_mcp_transport(cfg) == t
|
||||
|
||||
def test_strips_command_and_args(self):
|
||||
from application.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
from docsgpt.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
cfg = {"transport_type": "http", "command": "/bin/x", "args": ["a"]}
|
||||
_sanitize_mcp_transport(cfg)
|
||||
assert "command" not in cfg
|
||||
assert "args" not in cfg
|
||||
|
||||
def test_unsupported_transport_raises(self):
|
||||
from application.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
from docsgpt.api.user.tools.mcp import _sanitize_mcp_transport
|
||||
with pytest.raises(ValueError):
|
||||
_sanitize_mcp_transport({"transport_type": "websocket"})
|
||||
|
||||
|
||||
class TestExtractAuthCredentials:
|
||||
def test_api_key_auth(self):
|
||||
from application.api.user.tools.mcp import _extract_auth_credentials
|
||||
from docsgpt.api.user.tools.mcp import _extract_auth_credentials
|
||||
got = _extract_auth_credentials({
|
||||
"auth_type": "api_key",
|
||||
"api_key": "secret",
|
||||
@@ -64,7 +64,7 @@ class TestExtractAuthCredentials:
|
||||
assert got == {"api_key": "secret", "api_key_header": "X-API-Key"}
|
||||
|
||||
def test_bearer_auth(self):
|
||||
from application.api.user.tools.mcp import _extract_auth_credentials
|
||||
from docsgpt.api.user.tools.mcp import _extract_auth_credentials
|
||||
got = _extract_auth_credentials({
|
||||
"auth_type": "bearer",
|
||||
"bearer_token": "my-token",
|
||||
@@ -72,7 +72,7 @@ class TestExtractAuthCredentials:
|
||||
assert got == {"bearer_token": "my-token"}
|
||||
|
||||
def test_basic_auth(self):
|
||||
from application.api.user.tools.mcp import _extract_auth_credentials
|
||||
from docsgpt.api.user.tools.mcp import _extract_auth_credentials
|
||||
got = _extract_auth_credentials({
|
||||
"auth_type": "basic",
|
||||
"username": "u", "password": "p",
|
||||
@@ -80,28 +80,28 @@ class TestExtractAuthCredentials:
|
||||
assert got == {"username": "u", "password": "p"}
|
||||
|
||||
def test_none_auth_empty_creds(self):
|
||||
from application.api.user.tools.mcp import _extract_auth_credentials
|
||||
from docsgpt.api.user.tools.mcp import _extract_auth_credentials
|
||||
assert _extract_auth_credentials({"auth_type": "none"}) == {}
|
||||
|
||||
|
||||
class TestValidateMcpServerUrl:
|
||||
def test_empty_url_raises(self):
|
||||
from application.api.user.tools.mcp import _validate_mcp_server_url
|
||||
from docsgpt.api.user.tools.mcp import _validate_mcp_server_url
|
||||
with pytest.raises(ValueError):
|
||||
_validate_mcp_server_url({})
|
||||
|
||||
def test_missing_server_url(self):
|
||||
from application.api.user.tools.mcp import _validate_mcp_server_url
|
||||
from docsgpt.api.user.tools.mcp import _validate_mcp_server_url
|
||||
with pytest.raises(ValueError):
|
||||
_validate_mcp_server_url({"server_url": ""})
|
||||
|
||||
def test_ssrf_url_raises(self):
|
||||
from application.api.user.tools.mcp import _validate_mcp_server_url
|
||||
from docsgpt.api.user.tools.mcp import _validate_mcp_server_url
|
||||
with pytest.raises(ValueError):
|
||||
_validate_mcp_server_url({"server_url": "http://127.0.0.1"})
|
||||
|
||||
def test_valid_public_url_passes(self):
|
||||
from application.api.user.tools.mcp import _validate_mcp_server_url
|
||||
from docsgpt.api.user.tools.mcp import _validate_mcp_server_url
|
||||
# Should not raise for a public-ish URL
|
||||
try:
|
||||
_validate_mcp_server_url({"server_url": "https://example.com/mcp"})
|
||||
@@ -113,7 +113,7 @@ class TestValidateMcpServerUrl:
|
||||
|
||||
class TestTestMCPServerConfig:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST",
|
||||
@@ -125,7 +125,7 @@ class TestTestMCPServerConfig:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_config(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST", json={},
|
||||
@@ -136,7 +136,7 @@ class TestTestMCPServerConfig:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_unsupported_transport_returns_400(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST",
|
||||
@@ -148,7 +148,7 @@ class TestTestMCPServerConfig:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_missing_url_returns_400(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST",
|
||||
@@ -160,7 +160,7 @@ class TestTestMCPServerConfig:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_connection_success(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
fake_tool = MagicMock()
|
||||
fake_tool.test_connection.return_value = {
|
||||
@@ -169,7 +169,7 @@ class TestTestMCPServerConfig:
|
||||
}
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.MCPTool",
|
||||
"docsgpt.api.user.tools.mcp.MCPTool",
|
||||
return_value=fake_tool,
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST",
|
||||
@@ -189,7 +189,7 @@ class TestTestMCPServerConfig:
|
||||
assert response.json["tools_count"] == 3
|
||||
|
||||
def test_connection_failure_returns_200_with_failure_message(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
fake_tool = MagicMock()
|
||||
fake_tool.test_connection.return_value = {
|
||||
@@ -197,7 +197,7 @@ class TestTestMCPServerConfig:
|
||||
}
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.MCPTool",
|
||||
"docsgpt.api.user.tools.mcp.MCPTool",
|
||||
return_value=fake_tool,
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST",
|
||||
@@ -215,7 +215,7 @@ class TestTestMCPServerConfig:
|
||||
assert response.json["success"] is False
|
||||
|
||||
def test_oauth_required_returns_200(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
fake_tool = MagicMock()
|
||||
fake_tool.test_connection.return_value = {
|
||||
@@ -225,7 +225,7 @@ class TestTestMCPServerConfig:
|
||||
}
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.MCPTool",
|
||||
"docsgpt.api.user.tools.mcp.MCPTool",
|
||||
return_value=fake_tool,
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST",
|
||||
@@ -244,10 +244,10 @@ class TestTestMCPServerConfig:
|
||||
assert response.json["requires_oauth"] is True
|
||||
|
||||
def test_unexpected_exception_returns_500(self, app):
|
||||
from application.api.user.tools.mcp import TestMCPServerConfig
|
||||
from docsgpt.api.user.tools.mcp import TestMCPServerConfig
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.MCPTool",
|
||||
"docsgpt.api.user.tools.mcp.MCPTool",
|
||||
side_effect=RuntimeError("boom"),
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/test", method="POST",
|
||||
@@ -266,7 +266,7 @@ class TestTestMCPServerConfig:
|
||||
|
||||
class TestMCPServerSave:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.tools.mcp import MCPServerSave
|
||||
from docsgpt.api.user.tools.mcp import MCPServerSave
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/save", method="POST",
|
||||
@@ -278,7 +278,7 @@ class TestMCPServerSave:
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_returns_400_missing_fields(self, app):
|
||||
from application.api.user.tools.mcp import MCPServerSave
|
||||
from docsgpt.api.user.tools.mcp import MCPServerSave
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/save", method="POST", json={},
|
||||
@@ -289,7 +289,7 @@ class TestMCPServerSave:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_unsupported_transport_returns_400(self, app):
|
||||
from application.api.user.tools.mcp import MCPServerSave
|
||||
from docsgpt.api.user.tools.mcp import MCPServerSave
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/save", method="POST",
|
||||
@@ -304,7 +304,7 @@ class TestMCPServerSave:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_missing_server_url_returns_400(self, app):
|
||||
from application.api.user.tools.mcp import MCPServerSave
|
||||
from docsgpt.api.user.tools.mcp import MCPServerSave
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/save", method="POST",
|
||||
@@ -316,7 +316,7 @@ class TestMCPServerSave:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_oauth_missing_task_id_returns_400(self, app):
|
||||
from application.api.user.tools.mcp import MCPServerSave
|
||||
from docsgpt.api.user.tools.mcp import MCPServerSave
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/save", method="POST",
|
||||
@@ -335,7 +335,7 @@ class TestMCPServerSave:
|
||||
assert response.status_code == 400
|
||||
|
||||
def test_creates_mcp_tool_successfully(self, app, pg_conn):
|
||||
from application.api.user.tools.mcp import MCPServerSave
|
||||
from docsgpt.api.user.tools.mcp import MCPServerSave
|
||||
|
||||
user = "u-mcp-save"
|
||||
fake_tool = MagicMock()
|
||||
@@ -343,7 +343,7 @@ class TestMCPServerSave:
|
||||
fake_tool.get_actions_metadata.return_value = [{"name": "t1"}]
|
||||
|
||||
with _patch_db(pg_conn), patch(
|
||||
"application.api.user.tools.mcp.MCPTool",
|
||||
"docsgpt.api.user.tools.mcp.MCPTool",
|
||||
return_value=fake_tool,
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/save", method="POST",
|
||||
@@ -365,7 +365,7 @@ class TestMCPServerSave:
|
||||
|
||||
class TestMCPOAuthCallback:
|
||||
def test_error_param_redirects_error(self, app):
|
||||
from application.api.user.tools.mcp import MCPOAuthCallback
|
||||
from docsgpt.api.user.tools.mcp import MCPOAuthCallback
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/oauth_callback?error=access_denied"
|
||||
@@ -375,7 +375,7 @@ class TestMCPOAuthCallback:
|
||||
assert "status=error" in response.location
|
||||
|
||||
def test_missing_code_or_state_redirects_error(self, app):
|
||||
from application.api.user.tools.mcp import MCPOAuthCallback
|
||||
from docsgpt.api.user.tools.mcp import MCPOAuthCallback
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/oauth_callback"
|
||||
@@ -384,17 +384,17 @@ class TestMCPOAuthCallback:
|
||||
assert response.status_code == 302
|
||||
|
||||
def test_success_redirects_success(self, app):
|
||||
from application.api.user.tools.mcp import MCPOAuthCallback
|
||||
from docsgpt.api.user.tools.mcp import MCPOAuthCallback
|
||||
|
||||
fake_redis = MagicMock()
|
||||
fake_manager = MagicMock()
|
||||
fake_manager.handle_oauth_callback.return_value = True
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.get_redis_instance",
|
||||
"docsgpt.api.user.tools.mcp.get_redis_instance",
|
||||
return_value=fake_redis,
|
||||
), patch(
|
||||
"application.api.user.tools.mcp.MCPOAuthManager",
|
||||
"docsgpt.api.user.tools.mcp.MCPOAuthManager",
|
||||
return_value=fake_manager,
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/oauth_callback?code=c1&state=s1"
|
||||
@@ -404,17 +404,17 @@ class TestMCPOAuthCallback:
|
||||
assert "status=success" in response.location
|
||||
|
||||
def test_manager_failure_redirects_error(self, app):
|
||||
from application.api.user.tools.mcp import MCPOAuthCallback
|
||||
from docsgpt.api.user.tools.mcp import MCPOAuthCallback
|
||||
|
||||
fake_redis = MagicMock()
|
||||
fake_manager = MagicMock()
|
||||
fake_manager.handle_oauth_callback.return_value = False
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.get_redis_instance",
|
||||
"docsgpt.api.user.tools.mcp.get_redis_instance",
|
||||
return_value=fake_redis,
|
||||
), patch(
|
||||
"application.api.user.tools.mcp.MCPOAuthManager",
|
||||
"docsgpt.api.user.tools.mcp.MCPOAuthManager",
|
||||
return_value=fake_manager,
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/oauth_callback?code=c1&state=s1"
|
||||
@@ -424,10 +424,10 @@ class TestMCPOAuthCallback:
|
||||
assert "status=error" in response.location
|
||||
|
||||
def test_no_redis_redirects_error(self, app):
|
||||
from application.api.user.tools.mcp import MCPOAuthCallback
|
||||
from docsgpt.api.user.tools.mcp import MCPOAuthCallback
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.get_redis_instance",
|
||||
"docsgpt.api.user.tools.mcp.get_redis_instance",
|
||||
return_value=None,
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/oauth_callback?code=c&state=s"
|
||||
@@ -437,10 +437,10 @@ class TestMCPOAuthCallback:
|
||||
assert "Redis" in response.location or "status=error" in response.location
|
||||
|
||||
def test_exception_redirects_error(self, app):
|
||||
from application.api.user.tools.mcp import MCPOAuthCallback
|
||||
from docsgpt.api.user.tools.mcp import MCPOAuthCallback
|
||||
|
||||
with patch(
|
||||
"application.api.user.tools.mcp.get_redis_instance",
|
||||
"docsgpt.api.user.tools.mcp.get_redis_instance",
|
||||
side_effect=RuntimeError("boom"),
|
||||
), app.test_request_context(
|
||||
"/api/mcp_server/oauth_callback?code=c&state=s"
|
||||
@@ -451,7 +451,7 @@ class TestMCPOAuthCallback:
|
||||
|
||||
class TestMCPAuthStatus:
|
||||
def test_returns_401_unauthenticated(self, app):
|
||||
from application.api.user.tools.mcp import MCPAuthStatus
|
||||
from docsgpt.api.user.tools.mcp import MCPAuthStatus
|
||||
|
||||
with app.test_request_context(
|
||||
"/api/mcp_server/auth_status"
|
||||
|
||||
Reference in new issue
Block a user