From a54589a6725e2ca76864cd7764293ac036de642b Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Fri, 2 Oct 2026 13:53:36 +0000 Subject: [PATCH] test: compose real datasource credential repositories (#43216) --- .../console/datasets/test_data_source.py | 8 ++++---- .../datasets/rag_pipeline/test_datasource_auth.py | 11 ++++++----- .../console/workspace/test_tool_providers.py | 7 ++++--- .../core/datasource/test_notion_provider.py | 15 +++++++++------ .../knowledge/test_indexing_source_adapters.py | 7 ++++--- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py b/api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py index fcd34cb6d6d..c871edaafc0 100644 --- a/api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py +++ b/api/tests/test_containers_integration_tests/controllers/console/datasets/test_data_source.py @@ -9,6 +9,7 @@ from flask import Flask from sqlalchemy.orm import Session, sessionmaker from controllers.console.datasets.data_source import DataSourceNotionListApi, DataSourceNotionListQuery +from extensions.application_services.data_sources import build_data_source_credentials from machinery.context import RequestContext from models import Account, Tenant, TenantAccountJoin, TenantAccountRole from models.dataset import Dataset, Document @@ -16,7 +17,6 @@ from models.enums import DataSourceType, DocumentCreatedFrom, IndexingStatus from repositories.knowledge.dataset_repository import SQLAlchemyDatasetRepository from repositories.knowledge.document_repository import SQLAlchemyDocumentRepository from repositories.workspace.workspace_repository import WorkspaceRepository -from services.data_source.credential_gateway import ActorDatasourceCredentialResolver from services.data_source.notion_import_adapters import PluginNotionSourceGateway from services.data_source.notion_import_application_service import NotionImportApplicationService from services.knowledge.dataset_access import DatasetAccessService @@ -89,8 +89,7 @@ def test_notion_page_is_marked_bound_from_persisted_document( sessions = sessionmaker(bind=db_session_with_containers.get_bind(), expire_on_commit=False) datasets = SQLAlchemyDatasetRepository(session_factory=sessions) - credentials = MagicMock(spec=ActorDatasourceCredentialResolver) - credentials.resolve.return_value = {"token": "token"} + credentials = build_data_source_credentials(database_client=sessions).actor notion_imports = NotionImportApplicationService( dataset_access=DatasetAccessService( datasets=datasets, @@ -106,6 +105,7 @@ def test_notion_page_is_marked_bound_from_persisted_document( ) with ( + patch.object(credentials, "resolve", return_value={"token": "token"}) as resolve_credentials, flask_app_with_containers.test_request_context(f"/?credential_id=c1&dataset_id={dataset_id}"), patch( "controllers.console.datasets.data_source.application_services", @@ -120,7 +120,7 @@ def test_notion_page_is_marked_bound_from_persisted_document( assert status == 200 assert response["notion_info"][0]["pages"][0]["is_bound"] is True - credentials.resolve.assert_called_once_with( + resolve_credentials.assert_called_once_with( workspace_id=tenant_id, actor_id=account.id, credential_id="c1", diff --git a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_datasource_auth.py b/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_datasource_auth.py index 4874145451d..a57f5e8338a 100644 --- a/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_datasource_auth.py +++ b/api/tests/unit_tests/controllers/console/datasets/rag_pipeline/test_datasource_auth.py @@ -6,6 +6,7 @@ from unittest.mock import ANY, MagicMock, patch import pytest from flask import Flask +from sqlalchemy.orm import Session, sessionmaker from werkzeug.exceptions import Forbidden, NotFound from controllers.console import console_ns @@ -28,10 +29,10 @@ from controllers.console.datasets.rag_pipeline.datasource_auth import ( DatasourceUpdateProviderNameApi, ) from core.plugin.impl.oauth import OAuthHandler +from extensions.application_services.data_sources import build_data_source_credentials from graphon.model_runtime.errors.validate import CredentialsValidateFailedError from models.account import Account -from services.credentials.query import CredentialQuery -from services.data_source.credential_gateway import DatasourceProviderCredentialStore +from repositories.credentials.query_repository import CredentialQueryRepository from services.data_source.provider_service import DatasourceProviderService from services.plugin.oauth_service import OAuthProxyService from tests.unit_tests.model_factories import make_account @@ -40,9 +41,9 @@ _PROVIDER_ID = "langgenius/notion_datasource/notion" @pytest.fixture(autouse=True) -def credential_query_dependency(monkeypatch: pytest.MonkeyPatch) -> None: - query = MagicMock(spec=CredentialQuery) - providers = DatasourceProviderService(credentials=MagicMock(spec=DatasourceProviderCredentialStore)) +def credential_query_dependency(monkeypatch: pytest.MonkeyPatch, sqlite_session_factory: sessionmaker[Session]) -> None: + query = CredentialQueryRepository(session_factory=sqlite_session_factory) + providers = build_data_source_credentials(database_client=sqlite_session_factory).providers monkeypatch.setattr( import_module("controllers.console.datasets.rag_pipeline.datasource_auth"), "application_services", diff --git a/api/tests/unit_tests/controllers/console/workspace/test_tool_providers.py b/api/tests/unit_tests/controllers/console/workspace/test_tool_providers.py index cb61284cd35..e2e4412f2a9 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_tool_providers.py +++ b/api/tests/unit_tests/controllers/console/workspace/test_tool_providers.py @@ -25,7 +25,6 @@ from models.account import TenantAccountRole from models.credential_permission import CredentialPermission from models.enums import PermissionEnum from repositories.credentials.query_repository import CredentialQueryRepository -from services.credentials.query import CredentialQuery if not hasattr(builtins, "MethodView"): builtins.MethodView = MethodView # type: ignore[attr-defined] @@ -43,7 +42,7 @@ def app() -> Flask: @pytest.fixture -def controller_module(monkeypatch: pytest.MonkeyPatch, config_overrides: Callable[..., None]): +def controller_module(monkeypatch: pytest.MonkeyPatch, config_overrides: Callable[..., None], sqlite_session_factory): """ Import the controller with auth decorators neutralized only during import. @@ -82,7 +81,9 @@ def controller_module(monkeypatch: pytest.MonkeyPatch, config_overrides: Callabl login_module = importlib.import_module("libs.login") monkeypatch.setattr(login_module, "check_csrf_token", lambda *args, **kwargs: None) monkeypatch.setattr( - module, "application_services", lambda: SimpleNamespace(credential_queries=MagicMock(spec=CredentialQuery)) + module, + "application_services", + lambda: SimpleNamespace(credential_queries=CredentialQueryRepository(session_factory=sqlite_session_factory)), ) return module diff --git a/api/tests/unit_tests/core/datasource/test_notion_provider.py b/api/tests/unit_tests/core/datasource/test_notion_provider.py index d1e232f8f57..c140825037c 100644 --- a/api/tests/unit_tests/core/datasource/test_notion_provider.py +++ b/api/tests/unit_tests/core/datasource/test_notion_provider.py @@ -32,11 +32,10 @@ from core.datasource.online_document.online_document_provider import ( from core.rag.extractor import notion_extractor as notion_extractor_module from core.rag.extractor.notion_extractor import NotionExtractor from core.rag.models.document import Document +from extensions.application_services.data_sources import build_data_source_credentials from models.base import TypeBase from models.dataset import Document as DocumentModel from models.enums import DataSourceType, DocumentCreatedFrom -from services.data_source.credential_gateway import DatasourceProviderCredentialStore -from services.data_source.provider_service import DatasourceProviderService @dataclass(frozen=True) @@ -140,12 +139,14 @@ class TestNotionExtractorAuthentication: ) @patch("services.data_source.provider_service.DatasourceProviderService.get_datasource_credentials") - def test_init_with_integration_token_fallback(self, mock_get_token, mock_document_model, config_overrides): + def test_init_with_integration_token_fallback( + self, mock_get_token, mock_document_model, config_overrides, sqlite_session_factory + ): """Test NotionExtractor falls back to integration token when credential not found.""" # Arrange mock_get_token.side_effect = Exception("No credential id found") config_overrides(NOTION_INTEGRATION_TOKEN="integration-token-fallback") - providers = DatasourceProviderService(credentials=Mock(spec=DatasourceProviderCredentialStore)) + providers = build_data_source_credentials(database_client=sqlite_session_factory).providers # Act extractor = NotionExtractor( @@ -164,12 +165,14 @@ class TestNotionExtractorAuthentication: assert extractor._notion_access_token == "integration-token-fallback" @patch("services.data_source.provider_service.DatasourceProviderService.get_datasource_credentials") - def test_init_missing_credentials_raises_error(self, mock_get_token, mock_document_model, config_overrides): + def test_init_missing_credentials_raises_error( + self, mock_get_token, mock_document_model, config_overrides, sqlite_session_factory + ): """Test NotionExtractor raises error when no credentials available.""" # Arrange mock_get_token.side_effect = Exception("No credential id found") config_overrides(NOTION_INTEGRATION_TOKEN=None) - providers = DatasourceProviderService(credentials=Mock(spec=DatasourceProviderCredentialStore)) + providers = build_data_source_credentials(database_client=sqlite_session_factory).providers # Act & Assert with pytest.raises(ValueError) as exc_info: diff --git a/api/tests/unit_tests/services/knowledge/test_indexing_source_adapters.py b/api/tests/unit_tests/services/knowledge/test_indexing_source_adapters.py index 8037a4d037d..be642c3d6a9 100644 --- a/api/tests/unit_tests/services/knowledge/test_indexing_source_adapters.py +++ b/api/tests/unit_tests/services/knowledge/test_indexing_source_adapters.py @@ -3,17 +3,17 @@ from dataclasses import dataclass, field from unittest.mock import Mock import pytest +from sqlalchemy.orm import Session, sessionmaker from core.rag.extractor.entity.datasource_type import DatasourceType from core.rag.extractor.entity.extract_setting import UploadFileExtractionInput from core.rag.extractor.notion_extractor import NotionExtractor +from extensions.application_services.data_sources import build_data_source_credentials from services.data_source.credential_gateway import ( DatasourceCredentialNotFoundError, DatasourceCredentialRefreshError, - DatasourceProviderCredentialStore, ) from services.data_source.entities.notion_import import NotionPageType -from services.data_source.provider_service import DatasourceProviderService from services.knowledge.indexing.adapters.sources import ( CompositeStoredSourceResolver, FileSourceAdapter, @@ -194,6 +194,7 @@ def test_stored_notion_resolution_uses_trusted_document_owner_chain() -> None: ) @pytest.mark.parametrize("integration_token", ["environment-secret", None, ""]) def test_stored_notion_preview_and_indexing_use_same_integration( + sqlite_session_factory: sessionmaker[Session], monkeypatch: pytest.MonkeyPatch, credential_id: str | None, credentials: dict[str, object], @@ -205,7 +206,7 @@ def test_stored_notion_preview_and_indexing_use_same_integration( stored = RecordingStoredCredentials(credentials, error=error) resolver = _notion_resolver(stored=stored) indexing_credentials = Mock(return_value=credentials, side_effect=error) - providers = DatasourceProviderService(credentials=Mock(spec=DatasourceProviderCredentialStore)) + providers = build_data_source_credentials(database_client=sqlite_session_factory).providers monkeypatch.setattr( providers, "get_datasource_credentials",