mirror of
https://github.com/langgenius/dify.git
synced 2026-11-12 06:11:12 +08:00
232 lines
6.7 KiB
Python
232 lines
6.7 KiB
Python
"""
|
|
Shared fixtures for Service API controller tests.
|
|
|
|
This module provides reusable fixtures for mocking authentication,
|
|
database interactions, and common test data patterns used across
|
|
Service API controller tests.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from collections.abc import Iterator
|
|
from dataclasses import dataclass
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
from flask import Flask
|
|
from sqlalchemy import Engine
|
|
from sqlalchemy.orm import Session
|
|
|
|
from core.rag.index_processor.constant.index_type import IndexStructureType
|
|
from models.account import Account, Tenant, TenantAccountJoin, TenantAccountRole, TenantStatus
|
|
from models.base import TypeBase
|
|
from models.enums import ApiTokenType, AppStatus, DataSourceType, DocumentCreatedFrom, IndexingStatus, SegmentStatus
|
|
from models.model import ApiToken, App, AppMode, EndUser, EndUserType
|
|
|
|
if TYPE_CHECKING:
|
|
from models.dataset import ChildChunk, Dataset, Document, DocumentSegment
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ServiceApiIdentity:
|
|
"""Persisted owner identity for service-API authentication tests."""
|
|
|
|
session: Session
|
|
tenant: Tenant
|
|
account: Account
|
|
membership: TenantAccountJoin
|
|
|
|
|
|
@pytest.fixture
|
|
def service_api_identity(sqlite_engine: Engine) -> Iterator[ServiceApiIdentity]:
|
|
"""Given an isolated SQLite engine, yield a persisted tenant owner and close its session afterward."""
|
|
TypeBase.metadata.create_all(
|
|
sqlite_engine,
|
|
tables=[TypeBase.metadata.tables[model.__tablename__] for model in (Account, Tenant, TenantAccountJoin)],
|
|
)
|
|
with Session(sqlite_engine, expire_on_commit=False) as session:
|
|
tenant = Tenant(name="Service API Workspace")
|
|
tenant.id = str(uuid.uuid4())
|
|
account = Account(name="Service API Owner", email=f"owner-{tenant.id}@example.com")
|
|
account.id = str(uuid.uuid4())
|
|
membership = TenantAccountJoin(
|
|
tenant_id=tenant.id,
|
|
account_id=account.id,
|
|
role=TenantAccountRole.OWNER,
|
|
)
|
|
account._current_tenant = tenant
|
|
session.add_all([tenant, account, membership])
|
|
session.commit()
|
|
yield ServiceApiIdentity(
|
|
session=session,
|
|
tenant=tenant,
|
|
account=account,
|
|
membership=membership,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def app() -> Flask:
|
|
"""Create Flask test application with proper configuration."""
|
|
flask_app = Flask(__name__)
|
|
flask_app.config["TESTING"] = True
|
|
return flask_app
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_tenant_id() -> str:
|
|
"""Return a fresh UUID string for an isolated test tenant."""
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_app_id() -> str:
|
|
"""Return a fresh UUID string for an isolated test app."""
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_end_user(mock_tenant_id: str) -> EndUser:
|
|
"""Create a real EndUser model with required attributes."""
|
|
user = EndUser(
|
|
id=str(uuid.uuid4()),
|
|
external_user_id=f"external_{uuid.uuid4().hex[:8]}",
|
|
tenant_id=mock_tenant_id,
|
|
app_id=None,
|
|
type=EndUserType.SERVICE_API,
|
|
name="Service API User",
|
|
session_id=str(uuid.uuid4()),
|
|
)
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_app_model(mock_app_id: str, mock_tenant_id: str) -> App:
|
|
"""Create an App model with all required attributes for API testing."""
|
|
app = App(
|
|
id=mock_app_id,
|
|
tenant_id=mock_tenant_id,
|
|
name="Test App",
|
|
description="A test application",
|
|
mode=AppMode.CHAT,
|
|
status=AppStatus.NORMAL,
|
|
enable_api=True,
|
|
)
|
|
return app
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_tenant(mock_tenant_id: str) -> Tenant:
|
|
"""Create a Tenant model."""
|
|
tenant = Tenant(name="Service API Tenant", status=TenantStatus.NORMAL)
|
|
tenant.id = mock_tenant_id
|
|
return tenant
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_account() -> Account:
|
|
"""Create an Account model."""
|
|
account = Account(name="Service API Account", email=f"service-{uuid.uuid4()}@example.com")
|
|
account.id = str(uuid.uuid4())
|
|
return account
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_api_token(mock_app_id: str, mock_tenant_id: str) -> ApiToken:
|
|
"""Create a real API token for authentication tests."""
|
|
return ApiToken(
|
|
app_id=mock_app_id,
|
|
tenant_id=mock_tenant_id,
|
|
token=f"test_token_{uuid.uuid4().hex[:8]}",
|
|
type=ApiTokenType.APP,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_dataset_api_token(mock_tenant_id: str) -> ApiToken:
|
|
"""Create a real API token for dataset endpoints."""
|
|
return ApiToken(
|
|
tenant_id=mock_tenant_id,
|
|
token=f"dataset_token_{uuid.uuid4().hex[:8]}",
|
|
type=ApiTokenType.DATASET,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_dataset() -> Dataset:
|
|
"""Create a Dataset model."""
|
|
from models.dataset import Dataset
|
|
|
|
dataset = Dataset(
|
|
id=str(uuid.uuid4()),
|
|
tenant_id=str(uuid.uuid4()),
|
|
name="Test Dataset",
|
|
indexing_technique="economy",
|
|
embedding_model=None,
|
|
embedding_model_provider=None,
|
|
)
|
|
return dataset
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_document() -> Document:
|
|
"""Return an unpersisted completed Document with its required source and creator fields."""
|
|
from models.dataset import Document
|
|
|
|
document = Document(
|
|
id=str(uuid.uuid4()),
|
|
dataset_id=str(uuid.uuid4()),
|
|
tenant_id=str(uuid.uuid4()),
|
|
name="test_document.txt",
|
|
position=1,
|
|
data_source_type=DataSourceType.UPLOAD_FILE,
|
|
batch="test-batch",
|
|
created_from=DocumentCreatedFrom.API,
|
|
created_by=str(uuid.uuid4()),
|
|
indexing_status=IndexingStatus.COMPLETED,
|
|
enabled=True,
|
|
doc_form=IndexStructureType.PARAGRAPH_INDEX,
|
|
)
|
|
return document
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_segment() -> DocumentSegment:
|
|
"""Create a DocumentSegment model."""
|
|
from models.dataset import DocumentSegment
|
|
|
|
segment = DocumentSegment(
|
|
tenant_id=str(uuid.uuid4()),
|
|
dataset_id=str(uuid.uuid4()),
|
|
document_id=str(uuid.uuid4()),
|
|
position=1,
|
|
content="Test segment content",
|
|
word_count=3,
|
|
tokens=0,
|
|
created_by="account-id",
|
|
enabled=True,
|
|
status=SegmentStatus.COMPLETED,
|
|
)
|
|
segment.id = str(uuid.uuid4())
|
|
return segment
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_child_chunk() -> ChildChunk:
|
|
"""Return an unpersisted ChildChunk with valid required fields."""
|
|
from models.dataset import ChildChunk
|
|
|
|
child_chunk = ChildChunk(
|
|
tenant_id=str(uuid.uuid4()),
|
|
dataset_id="dataset-id",
|
|
document_id="document-id",
|
|
segment_id=str(uuid.uuid4()),
|
|
position=1,
|
|
content="Test child chunk content",
|
|
word_count=0,
|
|
created_by="account-id",
|
|
)
|
|
child_chunk.id = str(uuid.uuid4())
|
|
return child_chunk
|