mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
test: compose real datasource credential repositories (#43216)
This commit is contained in:
1 parent
ba28e3ad82
commit
a54589a672
5 files changed
+27
-21
No files matched your search
+4
-4
@@ -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",
|
||||
|
||||
+6
-5
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user