mirror of
https://github.com/langgenius/dify.git
synced 2026-11-11 22:02:23 +08:00
164 lines
6.0 KiB
Python
164 lines
6.0 KiB
Python
"""Application dependencies shared by controller tests."""
|
|
|
|
import sys
|
|
from collections.abc import Iterator
|
|
from dataclasses import dataclass
|
|
from functools import cache
|
|
from types import SimpleNamespace
|
|
from unittest.mock import create_autospec
|
|
|
|
import pytest
|
|
from flask import Flask, Response, request_finished
|
|
from sqlalchemy.orm import Session, sessionmaker
|
|
|
|
from core.app.apps.pipeline.pipeline_generator import PipelineGenerator
|
|
from extensions.application_services.app import AppServices
|
|
from extensions.ext_application_services import (
|
|
_batch_get_enterprise_webapp_access_modes,
|
|
_batch_get_enterprise_webapp_user_permissions,
|
|
)
|
|
from repositories.webapp_access_query_repository import WebAppAccessQueryRepository
|
|
from services.app.console_service import ConsoleAppService
|
|
from services.app.export_service import AppExportService
|
|
from services.app.import_service import AppImportService
|
|
from services.app.query_service import AppDiscoveryService
|
|
from services.credentials.query import CredentialQuery
|
|
from services.data_source.provider_service import DatasourceProviderService
|
|
from services.enterprise.enterprise_service import EnterpriseService
|
|
from services.tag_application_service import TagApplicationService
|
|
from services.webapp_access_adapters import EnterpriseWebAppAccessPolicyGateway
|
|
from services.webapp_access_query_service import WebAppAccessQueryService
|
|
from services.workflow.dsl_import import DslImportService
|
|
from tests.helpers.unit.controllers.error_contract import check_response, track_external_apis
|
|
|
|
track_external_apis()
|
|
|
|
|
|
def pytest_configure(config: pytest.Config) -> None:
|
|
config.addinivalue_line(
|
|
"markers",
|
|
"allow_error_contract_violations: the test serves contract-violating error responses on purpose",
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def error_response_contract(request: pytest.FixtureRequest) -> Iterator[None]:
|
|
"""Fail a test whose served error responses contradict the documented error contract."""
|
|
if request.node.get_closest_marker("allow_error_contract_violations"):
|
|
yield
|
|
return
|
|
violations: list[str] = []
|
|
|
|
def receiver(sender: Flask, response: Response, **_: object) -> None:
|
|
check_response(sender, response, violations)
|
|
|
|
request_finished.connect(receiver)
|
|
try:
|
|
yield
|
|
finally:
|
|
request_finished.disconnect(receiver)
|
|
if violations:
|
|
pytest.fail("error responses contradict the documented contract:\n" + "\n".join(violations))
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def datasource_application_dependencies(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
# Most controller tests never use these services. Build the mock on demand,
|
|
# with a fresh cache for each test to preserve mock isolation.
|
|
@cache
|
|
def application_services() -> SimpleNamespace:
|
|
return SimpleNamespace(
|
|
data_sources=SimpleNamespace(
|
|
providers=create_autospec(DatasourceProviderService, instance=True, spec_set=True)
|
|
)
|
|
)
|
|
|
|
for name in (
|
|
"controllers.console.datasets.rag_pipeline.rag_pipeline_workflow",
|
|
"controllers.console.datasets.rag_pipeline.datasource_content_preview",
|
|
"controllers.console.datasets.website",
|
|
):
|
|
module = sys.modules.get(name)
|
|
if module is not None:
|
|
monkeypatch.setattr(module, "application_services", application_services)
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PipelineKnowledgeStub:
|
|
pipeline_generator: PipelineGenerator
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PipelineDataSourceStub:
|
|
providers: DatasourceProviderService
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PipelineApplicationStub:
|
|
knowledge: PipelineKnowledgeStub
|
|
credential_queries: CredentialQuery
|
|
data_sources: PipelineDataSourceStub
|
|
|
|
|
|
@pytest.fixture
|
|
def pipeline_application(monkeypatch: pytest.MonkeyPatch) -> PipelineGenerator:
|
|
from controllers.console.datasets.rag_pipeline import rag_pipeline_workflow as console_workflow
|
|
from controllers.service_api.dataset.rag_pipeline import rag_pipeline_workflow as service_api_workflow
|
|
|
|
generator = create_autospec(PipelineGenerator, instance=True, spec_set=True)
|
|
registry = PipelineApplicationStub(
|
|
knowledge=PipelineKnowledgeStub(pipeline_generator=generator),
|
|
credential_queries=create_autospec(CredentialQuery, instance=True, spec_set=True),
|
|
data_sources=PipelineDataSourceStub(
|
|
providers=create_autospec(DatasourceProviderService, instance=True, spec_set=True)
|
|
),
|
|
)
|
|
monkeypatch.setattr(console_workflow, "application_services", lambda: registry)
|
|
monkeypatch.setattr(service_api_workflow, "application_services", lambda: registry)
|
|
return generator
|
|
|
|
|
|
@dataclass
|
|
class AppQueryTestServices:
|
|
console: ConsoleAppService
|
|
imports: AppImportService
|
|
exports: AppExportService
|
|
dsl_imports: DslImportService
|
|
discovery: AppDiscoveryService
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ControllerTestServices:
|
|
apps: AppQueryTestServices
|
|
tags: TagApplicationService
|
|
webapp_access: WebAppAccessQueryService
|
|
|
|
|
|
@pytest.fixture
|
|
def app_query_services(
|
|
app_services: AppServices,
|
|
application_tags: TagApplicationService,
|
|
app: Flask,
|
|
sqlite_session_factory: sessionmaker[Session],
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> ControllerTestServices:
|
|
services = ControllerTestServices(
|
|
tags=application_tags,
|
|
apps=AppQueryTestServices(
|
|
console=app_services.console,
|
|
imports=app_services.imports,
|
|
exports=app_services.exports,
|
|
dsl_imports=app_services.dsl_imports,
|
|
discovery=app_services.discovery,
|
|
),
|
|
webapp_access=WebAppAccessQueryService(
|
|
access=WebAppAccessQueryRepository(session_factory=sqlite_session_factory),
|
|
webapp_auth_enabled=True,
|
|
policy=EnterpriseWebAppAccessPolicyGateway(webapp_auth=EnterpriseService.WebAppAuth),
|
|
get_access_modes=_batch_get_enterprise_webapp_access_modes,
|
|
get_user_permissions=_batch_get_enterprise_webapp_user_permissions,
|
|
),
|
|
)
|
|
monkeypatch.setitem(app.extensions, "application_services", services)
|
|
return services
|