mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-12 18:15:33 +00:00
Migration 0038 moves every stored secret (OAuth tokens, MCP OAuth tokens and client registrations, API keys) into the connection's encrypted envelope, links API-key tools to one connection per distinct credential, allows several accounts per provider, and adds credential_mode to sources and tools. OAuth MCP tools keep resolving each member's own token, as they did before. docsgpt.connectors.service is now the only reader of OAuth tokens: get_valid_token_info refreshes under a row lock and persists rotated refresh tokens, and a revoked grant flags the connection, pauses its sources and notifies the owner. Loaders build from a connection (BaseConnectorLoader.from_connection), so scheduled sync covers Drive, SharePoint and Confluence sources with no browser. S3 and Reddit keys stay on the connection instead of in remote_data. New endpoints: POST /api/connections, /setup, /reconnect, /picker-token, /claim, DELETE /api/connections/<id>, per-action permissions and MCP refresh-tools. Upload, file listing, sync and validate-session take a connection_id; session tokens keep working for this release. The tool executor reads credentials from the resolved connection (owner or member mode) and pauses on a Connect card when a connection needs signing in. docsgpt connectors reencrypt rewrites stored credentials after a key rotation.
106 lines
4.5 KiB
Python
106 lines
4.5 KiB
Python
"""Tests for ConnectorCreator factory class."""
|
|
|
|
from tests.parser.connectors.token_patch import patch_tokens
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
import pytest
|
|
|
|
|
|
class TestConnectorCreator:
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _patch_settings(self):
|
|
"""Patch settings so connector imports don't fail on missing credentials."""
|
|
mock_settings = MagicMock()
|
|
mock_settings.GOOGLE_CLIENT_ID = "gid"
|
|
mock_settings.GOOGLE_CLIENT_SECRET = "gsecret"
|
|
mock_settings.CONNECTOR_REDIRECT_BASE_URI = "https://redirect"
|
|
mock_settings.MICROSOFT_CLIENT_ID = "mid"
|
|
mock_settings.MICROSOFT_CLIENT_SECRET = "msecret"
|
|
mock_settings.MICROSOFT_TENANT_ID = "tid"
|
|
mock_settings.MONGO_DB_NAME = "test_db"
|
|
|
|
with patch("docsgpt.core.settings.settings", mock_settings), \
|
|
patch("docsgpt.parser.connectors.share_point.auth.settings", mock_settings), \
|
|
patch("docsgpt.parser.connectors.google_drive.auth.settings", mock_settings), \
|
|
patch("docsgpt.parser.connectors.share_point.auth.ConfidentialClientApplication"):
|
|
from docsgpt.parser.connectors.connector_creator import ConnectorCreator
|
|
self.ConnectorCreator = ConnectorCreator
|
|
yield
|
|
|
|
@pytest.mark.unit
|
|
def test_get_supported_connectors(self):
|
|
supported = self.ConnectorCreator.get_supported_connectors()
|
|
assert "google_drive" in supported
|
|
assert "share_point" in supported
|
|
|
|
@pytest.mark.unit
|
|
def test_is_supported_valid(self):
|
|
assert self.ConnectorCreator.is_supported("google_drive") is True
|
|
assert self.ConnectorCreator.is_supported("share_point") is True
|
|
|
|
@pytest.mark.unit
|
|
def test_is_supported_case_insensitive(self):
|
|
assert self.ConnectorCreator.is_supported("Google_Drive") is True
|
|
assert self.ConnectorCreator.is_supported("SHARE_POINT") is True
|
|
|
|
@pytest.mark.unit
|
|
def test_is_supported_invalid(self):
|
|
assert self.ConnectorCreator.is_supported("dropbox") is False
|
|
assert self.ConnectorCreator.is_supported("") is False
|
|
|
|
@pytest.mark.unit
|
|
def test_create_auth_google_drive(self):
|
|
auth = self.ConnectorCreator.create_auth("google_drive")
|
|
from docsgpt.parser.connectors.google_drive.auth import GoogleDriveAuth
|
|
assert isinstance(auth, GoogleDriveAuth)
|
|
|
|
@pytest.mark.unit
|
|
def test_create_auth_share_point(self):
|
|
auth = self.ConnectorCreator.create_auth("share_point")
|
|
from docsgpt.parser.connectors.share_point.auth import SharePointAuth
|
|
assert isinstance(auth, SharePointAuth)
|
|
|
|
@pytest.mark.unit
|
|
def test_create_auth_invalid_raises(self):
|
|
with pytest.raises(ValueError, match="No auth class found"):
|
|
self.ConnectorCreator.create_auth("invalid")
|
|
|
|
@pytest.mark.unit
|
|
def test_create_connector_invalid_raises(self):
|
|
with pytest.raises(ValueError, match="No connector class found"):
|
|
self.ConnectorCreator.create_connector("invalid", "session_tok")
|
|
|
|
@pytest.mark.unit
|
|
def test_create_connector_google_drive(self):
|
|
with patch("docsgpt.parser.connectors.google_drive.loader.GoogleDriveAuth") as MockAuth:
|
|
mock_auth_instance = MagicMock()
|
|
token_info = {
|
|
"access_token": "at", "refresh_token": "rt"
|
|
}
|
|
mock_creds = MagicMock()
|
|
mock_creds.token = "at"
|
|
mock_creds.expired = False
|
|
mock_auth_instance.create_credentials_from_token_info.return_value = mock_creds
|
|
mock_auth_instance.build_drive_service.return_value = MagicMock()
|
|
MockAuth.return_value = mock_auth_instance
|
|
|
|
with patch_tokens(token_info):
|
|
loader = self.ConnectorCreator.create_connector("google_drive", "session_tok")
|
|
from docsgpt.parser.connectors.google_drive.loader import GoogleDriveLoader
|
|
assert isinstance(loader, GoogleDriveLoader)
|
|
|
|
@pytest.mark.unit
|
|
def test_create_connector_share_point(self):
|
|
with patch("docsgpt.parser.connectors.share_point.loader.SharePointAuth") as MockAuth:
|
|
mock_auth_instance = MagicMock()
|
|
token_info = {
|
|
"access_token": "at", "refresh_token": "rt"
|
|
}
|
|
MockAuth.return_value = mock_auth_instance
|
|
|
|
with patch_tokens(token_info):
|
|
loader = self.ConnectorCreator.create_connector("share_point", "session_tok")
|
|
from docsgpt.parser.connectors.share_point.loader import SharePointLoader
|
|
assert isinstance(loader, SharePointLoader)
|