chore: add type to test (#36324)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Asuka Minato 2026-05-18 17:47:47 +09:00 committed by GitHub
parent 59e96fbb2a
commit 76bba64b79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 464 additions and 385 deletions

View File

@ -5,6 +5,7 @@ from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from flask.testing import FlaskClient
from sqlalchemy import delete
from sqlalchemy.orm import Session
@ -126,7 +127,7 @@ class TestAppApiKeyResource:
def test_delete_forbidden_for_non_admin(
self,
flask_app_with_containers,
flask_app_with_containers: Flask,
) -> None:
"""A non-admin member cannot delete API keys via the controller permission check."""
from werkzeug.exceptions import Forbidden

View File

@ -575,7 +575,7 @@ class TestTriggerSubscriptionVerifyApi:
assert method(api, "github", "s1") == {"ok": True}
@pytest.mark.parametrize("raised_exception", [ValueError("bad"), Exception("boom")])
def test_verify_errors(self, app, raised_exception):
def test_verify_errors(self, app: Flask, raised_exception):
api = TriggerSubscriptionVerifyApi()
method = unwrap(api.post)

View File

@ -277,7 +277,7 @@ class TestDecodeJwtToken:
mock_extract: MagicMock,
mock_passport_cls: MagicMock,
mock_features: MagicMock,
app,
app: Flask,
) -> None:
non_existent_id = str(uuid4())
mock_extract.return_value = "jwt-token"

View File

@ -5,6 +5,7 @@ from unittest.mock import Mock, patch
from uuid import uuid4
import pytest
from flask import Flask
from sqlalchemy.orm import Session
from models.source import DataSourceApiKeyAuthBinding
@ -45,7 +46,7 @@ class TestApiKeyAuthService:
return binding
def test_get_provider_auth_list_success(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, category, provider
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id, category, provider
):
self._create_binding(db_session_with_containers, tenant_id=tenant_id, category=category, provider=provider)
db_session_with_containers.expire_all()
@ -58,7 +59,7 @@ class TestApiKeyAuthService:
assert tenant_results[0].provider == provider
def test_get_provider_auth_list_empty(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id
):
result = ApiKeyAuthService.get_provider_auth_list(tenant_id)
@ -66,7 +67,7 @@ class TestApiKeyAuthService:
assert tenant_results == []
def test_get_provider_auth_list_filters_disabled(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, category, provider
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id, category, provider
):
self._create_binding(
db_session_with_containers, tenant_id=tenant_id, category=category, provider=provider, disabled=True
@ -84,7 +85,7 @@ class TestApiKeyAuthService:
self,
mock_encrypter,
mock_factory,
flask_app_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id,
mock_args,
@ -106,7 +107,7 @@ class TestApiKeyAuthService:
@patch("services.auth.api_key_auth_service.ApiKeyAuthFactory")
def test_create_provider_auth_validation_failed(
self, mock_factory, flask_app_with_containers, db_session_with_containers: Session, tenant_id, mock_args
self, mock_factory, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id, mock_args
):
mock_auth_instance = Mock()
mock_auth_instance.validate_credentials.return_value = False
@ -124,7 +125,7 @@ class TestApiKeyAuthService:
self,
mock_encrypter,
mock_factory,
flask_app_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id,
mock_args,
@ -144,7 +145,7 @@ class TestApiKeyAuthService:
def test_get_auth_credentials_success(
self,
flask_app_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id,
category,
@ -165,14 +166,14 @@ class TestApiKeyAuthService:
assert result == mock_credentials
def test_get_auth_credentials_not_found(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, category, provider
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id, category, provider
):
result = ApiKeyAuthService.get_auth_credentials(tenant_id, category, provider)
assert result is None
def test_get_auth_credentials_json_parsing(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, category, provider
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id, category, provider
):
special_credentials = {"auth_type": "api_key", "config": {"api_key": "key_with_中文_and_special_chars_!@#$%"}}
self._create_binding(
@ -190,7 +191,7 @@ class TestApiKeyAuthService:
assert result["config"]["api_key"] == "key_with_中文_and_special_chars_!@#$%"
def test_delete_provider_auth_success(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, category, provider
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id, category, provider
):
binding = self._create_binding(
db_session_with_containers, tenant_id=tenant_id, category=category, provider=provider
@ -205,7 +206,7 @@ class TestApiKeyAuthService:
assert remaining is None
def test_delete_provider_auth_not_found(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id
):
# Should not raise when binding not found
ApiKeyAuthService.delete_provider_auth(tenant_id, str(uuid4()))
@ -275,7 +276,7 @@ class TestApiKeyAuthService:
@patch("services.auth.api_key_auth_service.ApiKeyAuthFactory")
@patch("services.auth.api_key_auth_service.encrypter")
def test_create_provider_auth_database_error_handling(
self, mock_encrypter, mock_factory, flask_app_with_containers, tenant_id, mock_args
self, mock_encrypter, mock_factory, flask_app_with_containers: Flask, tenant_id, mock_args
):
mock_auth_instance = Mock()
mock_auth_instance.validate_credentials.return_value = True

View File

@ -10,6 +10,7 @@ from uuid import uuid4
import httpx
import pytest
from flask import Flask
from sqlalchemy.orm import Session
from models.source import DataSourceApiKeyAuthBinding
@ -45,8 +46,8 @@ class TestAuthIntegration:
self,
mock_encrypt,
mock_http,
flask_app_with_containers,
db_session_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id_1,
category,
firecrawl_credentials,
@ -86,8 +87,8 @@ class TestAuthIntegration:
mock_jina_http,
mock_fc_http,
mock_encrypt,
flask_app_with_containers,
db_session_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id_1,
tenant_id_2,
category,
@ -115,7 +116,7 @@ class TestAuthIntegration:
assert result2[0].tenant_id == tenant_id_2
def test_cross_tenant_access_prevention(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id_2, category
self, flask_app_with_containers: Flask, db_session_with_containers: Session, tenant_id_2, category
):
result = ApiKeyAuthService.get_auth_credentials(tenant_id_2, category, AuthType.FIRECRAWL)
@ -139,8 +140,8 @@ class TestAuthIntegration:
self,
mock_encrypt,
mock_http,
flask_app_with_containers,
db_session_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id_1,
category,
firecrawl_credentials,
@ -201,8 +202,8 @@ class TestAuthIntegration:
def test_network_failure_recovery(
self,
mock_http,
flask_app_with_containers,
db_session_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id_1,
category,
firecrawl_credentials,
@ -239,8 +240,8 @@ class TestAuthIntegration:
self,
mock_http,
mock_encrypt,
flask_app_with_containers,
db_session_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id_1,
category,
firecrawl_credentials,

View File

@ -14,7 +14,7 @@ from sqlalchemy.orm import Session
from werkzeug.exceptions import NotFound
from core.rag.index_processor.constant.index_type import IndexTechniqueType
from models import Account, Tenant, TenantAccountJoin, TenantAccountRole
from models import Account, AccountStatus, Tenant, TenantAccountJoin, TenantAccountRole, TenantStatus
from models.dataset import AppDatasetJoin, Dataset, DatasetPermissionEnum
from models.enums import DataSourceType
from models.model import App
@ -38,13 +38,13 @@ class DatasetUpdateDeleteTestDataFactory:
email=f"{uuid4()}@example.com",
name=f"user-{uuid4()}",
interface_language="en-US",
status="active",
status=AccountStatus.ACTIVE,
)
db_session_with_containers.add(account)
db_session_with_containers.commit()
if tenant is None:
tenant = Tenant(name=f"tenant-{uuid4()}", status="normal")
tenant = Tenant(name=f"tenant-{uuid4()}", status=TenantStatus.NORMAL)
db_session_with_containers.add(tenant)
db_session_with_containers.commit()

View File

@ -10,6 +10,7 @@ from unittest.mock import patch
from uuid import uuid4
import pytest
from flask import Flask
from redis import RedisError
from sqlalchemy.orm import Session
@ -123,7 +124,7 @@ class TestSyncAccountDeletion:
mock_queue_task.assert_not_called()
def test_sync_account_deletion_multiple_workspaces(
self, flask_app_with_containers, db_session_with_containers: Session, mock_queue_task
self, flask_app_with_containers: Flask, db_session_with_containers: Session, mock_queue_task
):
account_id = str(uuid4())
tenant_ids = [str(uuid4()) for _ in range(3)]
@ -145,7 +146,7 @@ class TestSyncAccountDeletion:
assert queued_workspace_ids == set(tenant_ids)
def test_sync_account_deletion_no_workspaces(
self, flask_app_with_containers, db_session_with_containers: Session, mock_queue_task
self, flask_app_with_containers: Flask, db_session_with_containers: Session, mock_queue_task
):
with patch("services.enterprise.account_deletion_sync.dify_config") as mock_config:
mock_config.ENTERPRISE_ENABLED = True
@ -156,7 +157,7 @@ class TestSyncAccountDeletion:
mock_queue_task.assert_not_called()
def test_sync_account_deletion_partial_failure(
self, flask_app_with_containers, db_session_with_containers: Session, mock_queue_task
self, flask_app_with_containers: Flask, db_session_with_containers: Session, mock_queue_task
):
account_id = str(uuid4())
tenant_ids = [str(uuid4()) for _ in range(3)]
@ -181,7 +182,7 @@ class TestSyncAccountDeletion:
assert mock_queue_task.call_count == 3
def test_sync_account_deletion_all_failures(
self, flask_app_with_containers, db_session_with_containers: Session, mock_queue_task
self, flask_app_with_containers: Flask, db_session_with_containers: Session, mock_queue_task
):
account_id = str(uuid4())
tenant_id = str(uuid4())

View File

@ -11,6 +11,7 @@ from unittest.mock import MagicMock, patch
from uuid import uuid4
import pytest
from flask import Flask
from core.plugin.entities.plugin_daemon import CredentialType
from models.tools import BuiltinToolProvider
@ -49,8 +50,8 @@ class TestGetDynamicSelectOptionsTool:
mock_tool_mgr,
mock_encrypter_fn,
mock_client_cls,
flask_app_with_containers,
db_session_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
):
tenant_id = str(uuid4())
provider_ctrl = MagicMock()
@ -91,8 +92,8 @@ class TestGetDynamicSelectOptionsTool:
self,
mock_tool_mgr,
mock_encrypter_fn,
flask_app_with_containers,
db_session_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
):
provider_ctrl = MagicMock()
provider_ctrl.need_credentials = True

View File

@ -11,10 +11,13 @@ from unittest.mock import MagicMock, patch
from uuid import uuid4
import pytest
from flask import Flask
from sqlalchemy import select
from sqlalchemy.orm import Session
from core.plugin.entities.plugin import PluginInstallationSource
from core.plugin.entities.plugin_daemon import PluginVerification
from models import ProviderType
from models.provider import Provider, ProviderCredential, TenantPreferredModelProvider
from services.errors.plugin import PluginInstallationForbiddenError
from services.feature_service import PluginInstallationScope
@ -346,7 +349,7 @@ class TestUninstall:
@patch("services.plugin.plugin_service.PluginInstaller")
def test_cleans_credentials_when_plugin_found(
self, mock_installer_cls, flask_app_with_containers, db_session_with_containers
self, mock_installer_cls, flask_app_with_containers: Flask, db_session_with_containers: Session
):
tenant_id = str(uuid4())
plugin_id = "org/myplugin"
@ -374,7 +377,7 @@ class TestUninstall:
pref = TenantPreferredModelProvider(
tenant_id=tenant_id,
provider_name=provider_name,
preferred_provider_type="custom",
preferred_provider_type=ProviderType.CUSTOM,
)
db_session_with_containers.add(pref)
db_session_with_containers.commit()

View File

@ -3,6 +3,7 @@ from __future__ import annotations
from unittest.mock import patch
from uuid import uuid4
from flask import Flask
from sqlalchemy.orm import Session
from models.model import App, RecommendedApp, Site
@ -10,7 +11,7 @@ from services.recommend_app.database.database_retrieval import DatabaseRecommend
from services.recommend_app.recommend_app_type import RecommendAppType
def _create_app(db_session, *, tenant_id: str, is_public: bool = True) -> App:
def _create_app(db_session: Session, *, tenant_id: str, is_public: bool = True) -> App:
app = App(
tenant_id=tenant_id,
name=f"app-{uuid4()}",
@ -25,7 +26,7 @@ def _create_app(db_session, *, tenant_id: str, is_public: bool = True) -> App:
return app
def _create_site(db_session, *, app_id: str) -> Site:
def _create_site(db_session: Session, *, app_id: str) -> Site:
site = Site(
app_id=app_id,
title=f"site-{uuid4()}",
@ -95,7 +96,9 @@ class TestDatabaseRecommendAppRetrieval:
class TestFetchRecommendedAppsFromDb:
def test_returns_apps_and_sorted_categories(self, flask_app_with_containers, db_session_with_containers: Session):
def test_returns_apps_and_sorted_categories(
self, flask_app_with_containers: Flask, db_session_with_containers: Session
):
tenant_id = str(uuid4())
app1 = _create_app(db_session_with_containers, tenant_id=tenant_id)
_create_site(db_session_with_containers, app_id=app1.id)
@ -116,7 +119,7 @@ class TestFetchRecommendedAppsFromDb:
assert "writing" in result["categories"]
def test_returns_multiple_categories_for_one_app(
self, flask_app_with_containers, db_session_with_containers: Session
self, flask_app_with_containers: Flask, db_session_with_containers: Session
):
tenant_id = str(uuid4())
created_app = _create_app(db_session_with_containers, tenant_id=tenant_id)
@ -139,7 +142,7 @@ class TestFetchRecommendedAppsFromDb:
def test_ignores_legacy_category_when_categories_are_empty(
self,
flask_app_with_containers,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
):
legacy_category = f"legacy-empty-{uuid4()}"
@ -163,7 +166,7 @@ class TestFetchRecommendedAppsFromDb:
assert legacy_category not in result["categories"]
def test_falls_back_to_default_language_when_empty(
self, flask_app_with_containers, db_session_with_containers: Session
self, flask_app_with_containers: Flask, db_session_with_containers: Session
):
tenant_id = str(uuid4())
app1 = _create_app(db_session_with_containers, tenant_id=tenant_id)
@ -177,7 +180,7 @@ class TestFetchRecommendedAppsFromDb:
app_ids = {r["app_id"] for r in result["recommended_apps"]}
assert app1.id in app_ids
def test_skips_non_public_apps(self, flask_app_with_containers, db_session_with_containers: Session):
def test_skips_non_public_apps(self, flask_app_with_containers: Flask, db_session_with_containers: Session):
tenant_id = str(uuid4())
app1 = _create_app(db_session_with_containers, tenant_id=tenant_id, is_public=False)
_create_site(db_session_with_containers, app_id=app1.id)
@ -190,7 +193,7 @@ class TestFetchRecommendedAppsFromDb:
app_ids = {r["app_id"] for r in result["recommended_apps"]}
assert app1.id not in app_ids
def test_skips_apps_without_site(self, flask_app_with_containers, db_session_with_containers: Session):
def test_skips_apps_without_site(self, flask_app_with_containers: Flask, db_session_with_containers: Session):
tenant_id = str(uuid4())
app1 = _create_app(db_session_with_containers, tenant_id=tenant_id)
_create_recommended_app(db_session_with_containers, app_id=app1.id)
@ -204,12 +207,14 @@ class TestFetchRecommendedAppsFromDb:
class TestFetchRecommendedAppDetailFromDb:
def test_returns_none_when_not_listed(self, flask_app_with_containers, db_session_with_containers: Session):
def test_returns_none_when_not_listed(self, flask_app_with_containers: Flask, db_session_with_containers: Session):
result = DatabaseRecommendAppRetrieval.fetch_recommended_app_detail_from_db(str(uuid4()))
assert result is None
def test_returns_none_when_app_not_public(self, flask_app_with_containers, db_session_with_containers: Session):
def test_returns_none_when_app_not_public(
self, flask_app_with_containers: Flask, db_session_with_containers: Session
):
tenant_id = str(uuid4())
app1 = _create_app(db_session_with_containers, tenant_id=tenant_id, is_public=False)
_create_recommended_app(db_session_with_containers, app_id=app1.id)
@ -221,7 +226,9 @@ class TestFetchRecommendedAppDetailFromDb:
assert result is None
@patch("services.recommend_app.database.database_retrieval.AppDslService")
def test_returns_detail_on_success(self, mock_dsl, flask_app_with_containers, db_session_with_containers: Session):
def test_returns_detail_on_success(
self, mock_dsl, flask_app_with_containers: Flask, db_session_with_containers: Session
):
tenant_id = str(uuid4())
app1 = _create_app(db_session_with_containers, tenant_id=tenant_id)
_create_site(db_session_with_containers, app_id=app1.id)

View File

@ -6,7 +6,7 @@ from faker import Faker
from sqlalchemy.orm import Session
from core.plugin.impl.exc import PluginDaemonClientSideError
from models import Account, CreatorUserRole
from models import Account, AppMode, CreatorUserRole
from models.enums import ConversationFromSource, MessageFileBelongsTo
from models.model import AppModelConfig, Conversation, EndUser, Message, MessageAgentThought
from services.account_service import AccountService, TenantService
@ -134,7 +134,7 @@ class TestAgentService:
app = app_service.create_app(tenant.id, app_args, account)
# Update the app model config to set agent_mode for agent-chat mode
if app.mode == "agent-chat" and app.app_model_config:
if app.mode == AppMode.AGENT_CHAT and app.app_model_config:
app.app_model_config.agent_mode = json.dumps({"enabled": True, "strategy": "react", "tools": []})
db_session_with_containers.commit()
@ -272,7 +272,7 @@ class TestAgentService:
tool_input=json.dumps({"dataset_tool": {"query": "test_query"}}),
observation=json.dumps({"dataset_tool": {"results": "test_results"}}),
tokens=30,
created_by_role="account",
created_by_role=CreatorUserRole.ACCOUNT,
created_by=message.from_account_id,
)
db_session_with_containers.add(thought2)

View File

@ -5,6 +5,7 @@ from unittest.mock import MagicMock, patch
from uuid import uuid4
import pytest
from flask import Flask
from werkzeug.exceptions import Unauthorized
import services.api_token_service as api_token_service_module
@ -14,7 +15,7 @@ from services.api_token_service import ApiTokenCache, CachedApiToken
class TestQueryTokenFromDb:
def test_should_return_api_token_and_cache_when_token_exists(
self, flask_app_with_containers, db_session_with_containers
self, flask_app_with_containers: Flask, db_session_with_containers
):
tenant_id = str(uuid4())
app_id = str(uuid4())
@ -41,7 +42,7 @@ class TestQueryTokenFromDb:
mock_record_usage.assert_called_once_with(token_value, "app")
def test_should_cache_null_and_raise_unauthorized_when_token_not_found(
self, flask_app_with_containers, db_session_with_containers
self, flask_app_with_containers: Flask, db_session_with_containers
):
with (
patch.object(api_token_service_module.ApiTokenCache, "set") as mock_cache_set,

View File

@ -15,6 +15,7 @@ from uuid import uuid4
from zipfile import ZipFile
import pytest
from sqlalchemy.orm import Session
import services.file_service as file_service_module
from extensions.storage.storage_type import StorageType
@ -23,7 +24,7 @@ from models.model import UploadFile
from services.file_service import FileService
def _create_upload_file(db_session, *, tenant_id: str, key: str, name: str) -> UploadFile:
def _create_upload_file(db_session: Session, *, tenant_id: str, key: str, name: str) -> UploadFile:
upload_file = UploadFile(
tenant_id=tenant_id,
storage_type=StorageType.OPENDAL,
@ -66,12 +67,12 @@ def test_build_upload_files_zip_tempfile_sanitizes_and_dedupes_names(monkeypatch
assert zf.read("b (2).txt") == b"three"
def test_get_upload_files_by_ids_returns_empty_when_no_ids(db_session_with_containers) -> None:
def test_get_upload_files_by_ids_returns_empty_when_no_ids(db_session_with_containers: Session) -> None:
"""Ensure empty input returns an empty mapping without hitting the database."""
assert FileService.get_upload_files_by_ids(str(uuid4()), []) == {}
def test_get_upload_files_by_ids_returns_id_keyed_mapping(db_session_with_containers) -> None:
def test_get_upload_files_by_ids_returns_id_keyed_mapping(db_session_with_containers: Session) -> None:
"""Ensure batch lookup returns a dict keyed by stringified UploadFile ids."""
tenant_id = str(uuid4())
file1 = _create_upload_file(db_session_with_containers, tenant_id=tenant_id, key="k1", name="file1.txt")
@ -84,7 +85,7 @@ def test_get_upload_files_by_ids_returns_id_keyed_mapping(db_session_with_contai
assert result[file2.id].id == file2.id
def test_get_upload_files_by_ids_filters_by_tenant(db_session_with_containers) -> None:
def test_get_upload_files_by_ids_filters_by_tenant(db_session_with_containers: Session) -> None:
"""Ensure files from other tenants are not returned."""
tenant_a = str(uuid4())
tenant_b = str(uuid4())

View File

@ -5,6 +5,7 @@ from unittest.mock import MagicMock, patch
from uuid import uuid4
import pytest
from flask import Flask
from sqlalchemy.engine import Engine
from sqlalchemy.orm import Session
@ -89,7 +90,7 @@ class TestDeliveryTestRegistry:
with pytest.raises(DeliveryTestUnsupportedError, match="Delivery method does not support test send."):
registry.dispatch(context=context, method=method)
def test_default(self, flask_app_with_containers, db_session_with_containers: Session):
def test_default(self, flask_app_with_containers: Flask, db_session_with_containers: Session):
registry = DeliveryTestRegistry.default()
assert len(registry._handlers) == 1
assert isinstance(registry._handlers[0], EmailDeliveryTestHandler)
@ -261,7 +262,7 @@ class TestEmailDeliveryTestHandler:
)
assert handler._resolve_recipients(tenant_id="t1", method=method) == ["ext@example.com"]
def test_resolve_recipients_member(self, flask_app_with_containers, db_session_with_containers: Session):
def test_resolve_recipients_member(self, flask_app_with_containers: Flask, db_session_with_containers: Session):
tenant_id = str(uuid4())
account = Account(name="Test User", email="member@example.com")
db_session_with_containers.add(account)
@ -283,7 +284,9 @@ class TestEmailDeliveryTestHandler:
)
assert handler._resolve_recipients(tenant_id=tenant_id, method=method) == ["member@example.com"]
def test_resolve_recipients_whole_workspace(self, flask_app_with_containers, db_session_with_containers: Session):
def test_resolve_recipients_whole_workspace(
self, flask_app_with_containers: Flask, db_session_with_containers: Session
):
tenant_id = str(uuid4())
account1 = Account(name="User 1", email=f"u1-{uuid4()}@example.com")
account2 = Account(name="User 2", email=f"u2-{uuid4()}@example.com")

View File

@ -4,6 +4,7 @@ from unittest.mock import Mock, patch
from uuid import uuid4
import pytest
from flask import Flask
from sqlalchemy import select
from sqlalchemy.orm import Session
@ -17,7 +18,7 @@ from services.entities.knowledge_entities.knowledge_entities import (
from services.metadata_service import MetadataService
def _create_dataset(db_session, *, tenant_id: str, built_in_field_enabled: bool = False) -> Dataset:
def _create_dataset(db_session: Session, *, tenant_id: str, built_in_field_enabled: bool = False) -> Dataset:
dataset = Dataset(
tenant_id=tenant_id,
name=f"dataset-{uuid4()}",
@ -31,7 +32,9 @@ def _create_dataset(db_session, *, tenant_id: str, built_in_field_enabled: bool
return dataset
def _create_document(db_session, *, dataset_id: str, tenant_id: str, doc_metadata: dict | None = None) -> Document:
def _create_document(
db_session: Session, *, dataset_id: str, tenant_id: str, doc_metadata: dict | None = None
) -> Document:
document = Document(
tenant_id=tenant_id,
dataset_id=dataset_id,
@ -66,7 +69,11 @@ class TestMetadataPartialUpdate:
yield account
def test_partial_update_merges_metadata(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, mock_current_account
self,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id: str,
mock_current_account,
):
dataset = _create_dataset(db_session_with_containers, tenant_id=tenant_id)
document = _create_document(
@ -93,7 +100,11 @@ class TestMetadataPartialUpdate:
assert updated_doc.doc_metadata["new_key"] == "new_value"
def test_full_update_replaces_metadata(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, mock_current_account
self,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id: str,
mock_current_account,
):
dataset = _create_dataset(db_session_with_containers, tenant_id=tenant_id)
document = _create_document(
@ -120,7 +131,12 @@ class TestMetadataPartialUpdate:
assert "existing_key" not in updated_doc.doc_metadata
def test_partial_update_skips_existing_binding(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, user_id, mock_current_account
self,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id,
user_id,
mock_current_account,
):
dataset = _create_dataset(db_session_with_containers, tenant_id=tenant_id)
document = _create_document(
@ -160,7 +176,11 @@ class TestMetadataPartialUpdate:
assert len(bindings) == 1
def test_rollback_called_on_commit_failure(
self, flask_app_with_containers, db_session_with_containers: Session, tenant_id, mock_current_account
self,
flask_app_with_containers: Flask,
db_session_with_containers: Session,
tenant_id: str,
mock_current_account,
):
dataset = _create_dataset(db_session_with_containers, tenant_id=tenant_id)
document = _create_document(

View File

@ -6,6 +6,7 @@ from types import SimpleNamespace
from unittest.mock import MagicMock
import pytest
from flask import Flask
from controllers.console.app import app_import as app_import_module
from services.app_dsl_service import ImportStatus
@ -48,7 +49,9 @@ class TestAppImportApi:
def api(self):
return app_import_module.AppImportApi()
def test_import_post_returns_failed_status_and_rolls_back(self, api, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_import_post_returns_failed_status_and_rolls_back(
self, api, app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
method = _unwrap(api.post)
_install_features(monkeypatch, enabled=False)
@ -68,7 +71,9 @@ class TestAppImportApi:
assert status == 400
assert response["status"] == ImportStatus.FAILED
def test_import_post_returns_pending_status_and_commits(self, api, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_import_post_returns_pending_status_and_commits(
self, api, app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
method = _unwrap(api.post)
_install_features(monkeypatch, enabled=False)
@ -88,7 +93,9 @@ class TestAppImportApi:
assert status == 202
assert response["status"] == ImportStatus.PENDING
def test_import_post_updates_webapp_auth_when_enabled(self, api, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_import_post_updates_webapp_auth_when_enabled(
self, api, app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
method = _unwrap(api.post)
_install_features(monkeypatch, enabled=True)
@ -118,7 +125,7 @@ class TestAppImportConfirmApi:
return app_import_module.AppImportConfirmApi()
def test_import_confirm_returns_failed_status_and_rolls_back(
self, api, app, monkeypatch: pytest.MonkeyPatch
self, api, app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
method = _unwrap(api.post)

View File

@ -5,6 +5,7 @@ from datetime import UTC, datetime
from types import SimpleNamespace
import pytest
from flask import Flask
from pydantic import ValidationError
from controllers.console.app import conversation_variables as conversation_variables_module
@ -20,7 +21,7 @@ def _unwrap(func):
return func
def test_get_conversation_variables_returns_paginated_response(app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_get_conversation_variables_returns_paginated_response(app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
api = conversation_variables_module.ConversationVariablesApi()
method = _unwrap(api.get)
@ -63,7 +64,9 @@ def test_get_conversation_variables_returns_paginated_response(app, monkeypatch:
assert response["data"][0]["updated_at"] == int(updated_at.timestamp())
def test_get_conversation_variables_normalizes_value_type_and_value(app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_get_conversation_variables_normalizes_value_type_and_value(
app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
api = conversation_variables_module.ConversationVariablesApi()
method = _unwrap(api.get)

View File

@ -20,8 +20,11 @@ from models.workflow import WorkflowRun
def _make_account() -> Account:
account = Account(name="tester", email="tester@example.com")
account.status = AccountStatus.ACTIVE
account = Account(
name="tester",
email="tester@example.com",
status=AccountStatus.ACTIVE,
)
account.role = TenantAccountRole.OWNER
account.id = "account-123" # type: ignore[assignment]
account._current_tenant = SimpleNamespace(id="tenant-123") # type: ignore[attr-defined]

View File

@ -1,7 +1,7 @@
from unittest.mock import MagicMock, patch
import pytest
from flask import Response
from flask import Flask, Response
from controllers.console import console_ns
from controllers.console.app.error import DraftWorkflowNotExist
@ -46,7 +46,7 @@ def restx_config(app):
class TestRagPipelineVariableCollectionApi:
def test_get_variables_success(self, app, fake_db, editor_user, restx_config):
def test_get_variables_success(self, app: Flask, fake_db, editor_user, restx_config):
api = RagPipelineVariableCollectionApi()
method = unwrap(api.get)
@ -80,7 +80,7 @@ class TestRagPipelineVariableCollectionApi:
assert result["items"] == []
def test_get_variables_workflow_not_exist(self, app, fake_db, editor_user):
def test_get_variables_workflow_not_exist(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableCollectionApi()
method = unwrap(api.get)
@ -101,7 +101,7 @@ class TestRagPipelineVariableCollectionApi:
with pytest.raises(DraftWorkflowNotExist):
method(api, pipeline)
def test_delete_variables_success(self, app, fake_db, editor_user):
def test_delete_variables_success(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableCollectionApi()
method = unwrap(api.delete)
@ -120,7 +120,7 @@ class TestRagPipelineVariableCollectionApi:
class TestRagPipelineNodeVariableCollectionApi:
def test_get_node_variables_success(self, app, fake_db, editor_user, restx_config):
def test_get_node_variables_success(self, app: Flask, fake_db, editor_user, restx_config):
api = RagPipelineNodeVariableCollectionApi()
method = unwrap(api.get)
@ -146,7 +146,7 @@ class TestRagPipelineNodeVariableCollectionApi:
assert result["items"] == []
def test_get_node_variables_invalid_node(self, app, editor_user):
def test_get_node_variables_invalid_node(self, app: Flask, editor_user):
api = RagPipelineNodeVariableCollectionApi()
method = unwrap(api.get)
@ -159,7 +159,7 @@ class TestRagPipelineNodeVariableCollectionApi:
class TestRagPipelineVariableApi:
def test_get_variable_not_found(self, app, fake_db, editor_user):
def test_get_variable_not_found(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableApi()
method = unwrap(api.get)
@ -178,7 +178,7 @@ class TestRagPipelineVariableApi:
with pytest.raises(NotFoundError):
method(api, MagicMock(), "v1")
def test_patch_variable_invalid_file_payload(self, app, fake_db, editor_user):
def test_patch_variable_invalid_file_payload(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableApi()
method = unwrap(api.patch)
@ -203,7 +203,7 @@ class TestRagPipelineVariableApi:
with pytest.raises(InvalidArgumentError):
method(api, pipeline, "v1")
def test_delete_variable_success(self, app, fake_db, editor_user):
def test_delete_variable_success(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableApi()
method = unwrap(api.delete)
@ -228,7 +228,7 @@ class TestRagPipelineVariableApi:
class TestRagPipelineVariableResetApi:
def test_reset_variable_success(self, app, fake_db, editor_user):
def test_reset_variable_success(self, app: Flask, fake_db, editor_user):
api = RagPipelineVariableResetApi()
method = unwrap(api.put)
@ -266,7 +266,7 @@ class TestRagPipelineVariableResetApi:
class TestSystemAndEnvironmentVariablesApi:
def test_system_variables_success(self, app, fake_db, editor_user, restx_config):
def test_system_variables_success(self, app: Flask, fake_db, editor_user, restx_config):
api = RagPipelineSystemVariableCollectionApi()
method = unwrap(api.get)
@ -292,7 +292,7 @@ class TestSystemAndEnvironmentVariablesApi:
assert result["items"] == []
def test_environment_variables_success(self, app, editor_user):
def test_environment_variables_success(self, app: Flask, editor_user):
api = RagPipelineEnvironmentVariableCollectionApi()
method = unwrap(api.get)

View File

@ -95,7 +95,7 @@ def patch_permission():
class TestGetProcessRuleApi:
def test_get_default_success(self, app, patch_tenant):
def test_get_default_success(self, app: Flask, patch_tenant):
api = GetProcessRuleApi()
method = unwrap(api.get)
@ -104,7 +104,7 @@ class TestGetProcessRuleApi:
assert "rules" in response
def test_get_with_document_dataset_not_found(self, app, patch_tenant):
def test_get_with_document_dataset_not_found(self, app: Flask, patch_tenant):
api = GetProcessRuleApi()
method = unwrap(api.get)
@ -126,7 +126,7 @@ class TestGetProcessRuleApi:
class TestDatasetDocumentListApi:
def test_get_with_fetch_true_counts_segments(self, app, patch_tenant, patch_dataset, patch_permission):
def test_get_with_fetch_true_counts_segments(self, app: Flask, patch_tenant, patch_dataset, patch_permission):
api = DatasetDocumentListApi()
method = unwrap(api.get)
@ -158,7 +158,9 @@ class TestDatasetDocumentListApi:
assert resp["data"]
def test_get_with_search_status_and_created_at_sort(self, app, patch_tenant, patch_dataset, patch_permission):
def test_get_with_search_status_and_created_at_sort(
self, app: Flask, patch_tenant, patch_dataset, patch_permission
):
api = DatasetDocumentListApi()
method = unwrap(api.get)
@ -187,7 +189,7 @@ class TestDatasetDocumentListApi:
assert resp["total"] == 1
def test_get_success(self, app, patch_tenant, patch_dataset, patch_permission):
def test_get_success(self, app: Flask, patch_tenant, patch_dataset, patch_permission):
api = DatasetDocumentListApi()
method = unwrap(api.get)
@ -212,7 +214,7 @@ class TestDatasetDocumentListApi:
assert response["total"] == 1
def test_post_success(self, app, patch_tenant, patch_dataset, patch_permission):
def test_post_success(self, app: Flask, patch_tenant, patch_dataset, patch_permission):
api = DatasetDocumentListApi()
method = unwrap(api.post)
@ -261,7 +263,7 @@ class TestDatasetDocumentListApi:
with pytest.raises(Forbidden):
method(api, "ds-1")
def test_get_with_fetch_true_and_invalid_fetch(self, app, patch_tenant, patch_dataset, patch_permission):
def test_get_with_fetch_true_and_invalid_fetch(self, app: Flask, patch_tenant, patch_dataset, patch_permission):
api = DatasetDocumentListApi()
method = unwrap(api.get)
@ -286,7 +288,7 @@ class TestDatasetDocumentListApi:
assert response["total"] == 1
def test_get_sort_hit_count(self, app, patch_tenant, patch_dataset, patch_permission):
def test_get_sort_hit_count(self, app: Flask, patch_tenant, patch_dataset, patch_permission):
api = DatasetDocumentListApi()
method = unwrap(api.get)
@ -309,7 +311,7 @@ class TestDatasetDocumentListApi:
class TestDocumentApi:
def test_get_success(self, app, patch_tenant):
def test_get_success(self, app: Flask, patch_tenant):
api = DocumentApi()
method = unwrap(api.get)
@ -327,7 +329,7 @@ class TestDocumentApi:
assert status == 200
def test_get_invalid_metadata(self, app, patch_tenant):
def test_get_invalid_metadata(self, app: Flask, patch_tenant):
api = DocumentApi()
method = unwrap(api.get)
@ -335,7 +337,7 @@ class TestDocumentApi:
with pytest.raises(InvalidMetadataError):
method(api, "ds-1", "doc-1")
def test_delete_success(self, app, patch_tenant, patch_dataset):
def test_delete_success(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentApi()
method = unwrap(api.delete)
@ -355,7 +357,7 @@ class TestDocumentApi:
assert status == 204
def test_delete_indexing_error(self, app, patch_tenant, patch_dataset):
def test_delete_indexing_error(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentApi()
method = unwrap(api.delete)
@ -376,7 +378,7 @@ class TestDocumentApi:
class TestDocumentDownloadApi:
def test_download_success(self, app, patch_tenant):
def test_download_success(self, app: Flask, patch_tenant):
api = DocumentDownloadApi()
method = unwrap(api.get)
@ -413,7 +415,7 @@ class TestDocumentProcessingApi:
with pytest.raises(Forbidden):
method(api, "ds-1", "doc-1", "pause")
def test_resume_from_error_state(self, app, patch_tenant):
def test_resume_from_error_state(self, app: Flask, patch_tenant):
api = DocumentProcessingApi()
method = unwrap(api.patch)
@ -431,7 +433,7 @@ class TestDocumentProcessingApi:
assert status == 200
def test_resume_success(self, app, patch_tenant):
def test_resume_success(self, app: Flask, patch_tenant):
api = DocumentProcessingApi()
method = unwrap(api.patch)
@ -449,7 +451,7 @@ class TestDocumentProcessingApi:
assert status == 200
def test_pause_success(self, app, patch_tenant):
def test_pause_success(self, app: Flask, patch_tenant):
api = DocumentProcessingApi()
method = unwrap(api.patch)
@ -467,7 +469,7 @@ class TestDocumentProcessingApi:
assert status == 200
def test_pause_invalid(self, app, patch_tenant):
def test_pause_invalid(self, app: Flask, patch_tenant):
api = DocumentProcessingApi()
method = unwrap(api.patch)
@ -479,7 +481,7 @@ class TestDocumentProcessingApi:
class TestDocumentMetadataApi:
def test_put_metadata_schema_filtering(self, app, patch_tenant):
def test_put_metadata_schema_filtering(self, app: Flask, patch_tenant):
api = DocumentMetadataApi()
method = unwrap(api.put)
@ -508,7 +510,7 @@ class TestDocumentMetadataApi:
assert doc.doc_metadata == {"amount": 10}
def test_put_success(self, app, patch_tenant):
def test_put_success(self, app: Flask, patch_tenant):
api = DocumentMetadataApi()
method = unwrap(api.put)
@ -532,7 +534,7 @@ class TestDocumentMetadataApi:
assert status == 200
def test_put_invalid_payload(self, app, patch_tenant):
def test_put_invalid_payload(self, app: Flask, patch_tenant):
api = DocumentMetadataApi()
method = unwrap(api.put)
@ -540,7 +542,7 @@ class TestDocumentMetadataApi:
with pytest.raises(ValueError):
method(api, "ds-1", "doc-1")
def test_put_invalid_doc_type(self, app, patch_tenant):
def test_put_invalid_doc_type(self, app: Flask, patch_tenant):
api = DocumentMetadataApi()
method = unwrap(api.put)
@ -559,7 +561,7 @@ class TestDocumentMetadataApi:
class TestDocumentStatusApi:
def test_patch_success(self, app, patch_tenant, patch_dataset):
def test_patch_success(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentStatusApi()
method = unwrap(api.patch)
@ -582,7 +584,7 @@ class TestDocumentStatusApi:
assert status == 200
def test_patch_invalid_action(self, app, patch_tenant, patch_dataset):
def test_patch_invalid_action(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentStatusApi()
method = unwrap(api.patch)
@ -606,7 +608,7 @@ class TestDocumentStatusApi:
class TestDocumentRetryApi:
def test_retry_archived_document_skipped(self, app, patch_tenant, patch_dataset):
def test_retry_archived_document_skipped(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentRetryApi()
method = unwrap(api.post)
@ -634,7 +636,7 @@ class TestDocumentRetryApi:
assert status == 204
retry_mock.assert_called_once_with("ds-1", [])
def test_retry_success(self, app, patch_tenant, patch_dataset):
def test_retry_success(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentRetryApi()
method = unwrap(api.post)
@ -663,7 +665,7 @@ class TestDocumentRetryApi:
assert status == 204
retry_mock.assert_called_once_with("ds-1", [document])
def test_retry_skips_completed_document(self, app, patch_tenant, patch_dataset):
def test_retry_skips_completed_document(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentRetryApi()
method = unwrap(api.post)
@ -690,7 +692,7 @@ class TestDocumentRetryApi:
class TestDocumentPipelineExecutionLogApi:
def test_get_log_success(self, app, patch_tenant, patch_dataset):
def test_get_log_success(self, app: Flask, patch_tenant, patch_dataset):
api = DocumentPipelineExecutionLogApi()
method = unwrap(api.get)
@ -718,7 +720,7 @@ class TestDocumentPipelineExecutionLogApi:
class TestDocumentGenerateSummaryApi:
def test_generate_summary_missing_documents(self, app, patch_tenant, patch_permission):
def test_generate_summary_missing_documents(self, app: Flask, patch_tenant, patch_permission):
api = DocumentGenerateSummaryApi()
method = unwrap(api.post)
@ -744,7 +746,7 @@ class TestDocumentGenerateSummaryApi:
with pytest.raises(NotFound):
method(api, "ds-1")
def test_generate_not_enabled(self, app, patch_tenant, patch_permission):
def test_generate_not_enabled(self, app: Flask, patch_tenant, patch_permission):
api = DocumentGenerateSummaryApi()
method = unwrap(api.post)
@ -763,7 +765,7 @@ class TestDocumentGenerateSummaryApi:
with pytest.raises(ValueError):
method(api, "ds-1")
def test_generate_summary_success_with_qa_skip(self, app, patch_tenant, patch_permission):
def test_generate_summary_success_with_qa_skip(self, app: Flask, patch_tenant, patch_permission):
api = DocumentGenerateSummaryApi()
method = unwrap(api.post)
@ -799,7 +801,7 @@ class TestDocumentGenerateSummaryApi:
class TestDocumentSummaryStatusApi:
def test_get_success(self, app, patch_tenant, patch_permission):
def test_get_success(self, app: Flask, patch_tenant, patch_permission):
api = DocumentSummaryStatusApi()
method = unwrap(api.get)
@ -820,7 +822,7 @@ class TestDocumentSummaryStatusApi:
class TestDocumentIndexingEstimateApi:
def test_indexing_estimate_file_not_found(self, app, patch_tenant):
def test_indexing_estimate_file_not_found(self, app: Flask, patch_tenant):
api = DocumentIndexingEstimateApi()
method = unwrap(api.get)
@ -844,7 +846,7 @@ class TestDocumentIndexingEstimateApi:
with pytest.raises(NotFound):
method(api, "ds-1", "doc-1")
def test_indexing_estimate_generic_exception(self, app, patch_tenant):
def test_indexing_estimate_generic_exception(self, app: Flask, patch_tenant):
api = DocumentIndexingEstimateApi()
method = unwrap(api.get)
@ -881,7 +883,7 @@ class TestDocumentIndexingEstimateApi:
with pytest.raises(IndexingEstimateError):
method(api, "ds-1", "doc-1")
def test_get_finished(self, app, patch_tenant):
def test_get_finished(self, app: Flask, patch_tenant):
api = DocumentIndexingEstimateApi()
method = unwrap(api.get)
@ -893,7 +895,7 @@ class TestDocumentIndexingEstimateApi:
class TestDocumentBatchDownloadZipApi:
def test_post_no_documents(self, app, patch_tenant):
def test_post_no_documents(self, app: Flask, patch_tenant):
api = DocumentBatchDownloadZipApi()
method = unwrap(api.post)
@ -905,7 +907,7 @@ class TestDocumentBatchDownloadZipApi:
class TestDatasetDocumentListApiDelete:
def test_delete_success(self, app, patch_tenant, patch_dataset):
def test_delete_success(self, app: Flask, patch_tenant, patch_dataset):
"""Test successful deletion of documents"""
api = DatasetDocumentListApi()
method = unwrap(api.delete)
@ -925,7 +927,7 @@ class TestDatasetDocumentListApiDelete:
assert status == 204
def test_delete_indexing_error(self, app, patch_tenant, patch_dataset):
def test_delete_indexing_error(self, app: Flask, patch_tenant, patch_dataset):
"""Test deletion with indexing error"""
api = DatasetDocumentListApi()
method = unwrap(api.delete)
@ -944,7 +946,7 @@ class TestDatasetDocumentListApiDelete:
with pytest.raises(DocumentIndexingError):
method(api, "ds-1")
def test_delete_dataset_not_found(self, app, patch_tenant):
def test_delete_dataset_not_found(self, app: Flask, patch_tenant):
"""Test deletion when dataset not found"""
api = DatasetDocumentListApi()
method = unwrap(api.delete)
@ -961,7 +963,7 @@ class TestDatasetDocumentListApiDelete:
class TestDocumentBatchIndexingEstimateApi:
def test_batch_indexing_estimate_website(self, app, patch_tenant):
def test_batch_indexing_estimate_website(self, app: Flask, patch_tenant):
api = DocumentBatchIndexingEstimateApi()
method = unwrap(api.get)
@ -990,7 +992,7 @@ class TestDocumentBatchIndexingEstimateApi:
assert status == 200
def test_batch_indexing_estimate_notion(self, app, patch_tenant):
def test_batch_indexing_estimate_notion(self, app: Flask, patch_tenant):
api = DocumentBatchIndexingEstimateApi()
method = unwrap(api.get)
@ -1018,7 +1020,7 @@ class TestDocumentBatchIndexingEstimateApi:
assert status == 200
def test_batch_estimate_unsupported_datasource(self, app, patch_tenant):
def test_batch_estimate_unsupported_datasource(self, app: Flask, patch_tenant):
api = DocumentBatchIndexingEstimateApi()
method = unwrap(api.get)
@ -1033,7 +1035,7 @@ class TestDocumentBatchIndexingEstimateApi:
with pytest.raises(ValueError):
method(api, "ds-1", "batch-1")
def test_get_batch_estimate_invalid_batch(self, app, patch_tenant):
def test_get_batch_estimate_invalid_batch(self, app: Flask, patch_tenant):
"""Test batch estimation with invalid batch"""
api = DocumentBatchIndexingEstimateApi()
method = unwrap(api.get)
@ -1044,7 +1046,7 @@ class TestDocumentBatchIndexingEstimateApi:
class TestDocumentBatchIndexingStatusApi:
def test_get_batch_status_invalid_batch(self, app, patch_tenant):
def test_get_batch_status_invalid_batch(self, app: Flask, patch_tenant):
"""Test batch status with invalid batch"""
api = DocumentBatchIndexingStatusApi()
method = unwrap(api.get)
@ -1055,7 +1057,7 @@ class TestDocumentBatchIndexingStatusApi:
class TestDocumentIndexingStatusApi:
def test_get_status_document_not_found(self, app, patch_tenant):
def test_get_status_document_not_found(self, app: Flask, patch_tenant):
"""Test getting status for non-existent document"""
api = DocumentIndexingStatusApi()
method = unwrap(api.get)
@ -1066,7 +1068,7 @@ class TestDocumentIndexingStatusApi:
class TestDocumentApiMetadata:
def test_get_with_only_option(self, app, patch_tenant):
def test_get_with_only_option(self, app: Flask, patch_tenant):
"""Test get with 'only' metadata option"""
api = DocumentApi()
method = unwrap(api.get)
@ -1085,7 +1087,7 @@ class TestDocumentApiMetadata:
assert status == 200
def test_get_with_without_option(self, app, patch_tenant):
def test_get_with_without_option(self, app: Flask, patch_tenant):
"""Test get with 'without' metadata option"""
api = DocumentApi()
method = unwrap(api.get)
@ -1106,7 +1108,7 @@ class TestDocumentApiMetadata:
class TestDocumentGenerateSummaryApiSuccess:
def test_generate_not_enabled_high_quality(self, app, patch_tenant, patch_permission):
def test_generate_not_enabled_high_quality(self, app: Flask, patch_tenant, patch_permission):
"""Test summary generation on non-high-quality dataset"""
api = DocumentGenerateSummaryApi()
method = unwrap(api.post)
@ -1128,7 +1130,7 @@ class TestDocumentGenerateSummaryApiSuccess:
class TestDocumentProcessingApiResume:
def test_resume_invalid_status(self, app, patch_tenant):
def test_resume_invalid_status(self, app: Flask, patch_tenant):
"""Test resume on non-paused document"""
api = DocumentProcessingApi()
method = unwrap(api.patch)
@ -1141,7 +1143,7 @@ class TestDocumentProcessingApiResume:
class TestDocumentPermissionCases:
def test_document_batch_get_permission_denied(self, app, patch_tenant):
def test_document_batch_get_permission_denied(self, app: Flask, patch_tenant):
api = DocumentBatchIndexingEstimateApi()
method = unwrap(api.get)
@ -1159,7 +1161,7 @@ class TestDocumentPermissionCases:
with pytest.raises(Forbidden):
method(api, "ds-1", "batch-1")
def test_document_batch_get_documents_not_found(self, app, patch_tenant):
def test_document_batch_get_documents_not_found(self, app: Flask, patch_tenant):
api = DocumentBatchIndexingEstimateApi()
method = unwrap(api.get)
@ -1218,7 +1220,7 @@ class TestDocumentPermissionCases:
with pytest.raises(Forbidden):
method(api, "ds-1", "doc-1")
def test_process_rule_get_by_document_success(self, app, patch_tenant):
def test_process_rule_get_by_document_success(self, app: Flask, patch_tenant):
api = GetProcessRuleApi()
method = unwrap(api.get)
@ -1284,7 +1286,7 @@ class TestDocumentPermissionCases:
class TestDocumentListAdvancedCases:
def test_document_list_with_multiple_sort_options(self, app, patch_tenant, patch_dataset, patch_permission):
def test_document_list_with_multiple_sort_options(self, app: Flask, patch_tenant, patch_dataset, patch_permission):
"""Test document list with different sort options"""
api = DatasetDocumentListApi()
method = unwrap(api.get)
@ -1310,7 +1312,7 @@ class TestDocumentListAdvancedCases:
assert response["total"] == 1
def test_document_metadata_with_schema_validation(self, app, patch_tenant):
def test_document_metadata_with_schema_validation(self, app: Flask, patch_tenant):
"""Test document metadata update with schema validation"""
api = DocumentMetadataApi()
method = unwrap(api.put)
@ -1342,7 +1344,7 @@ class TestDocumentListAdvancedCases:
class TestDocumentIndexingEdgeCases:
def test_document_indexing_with_extraction_setting(self, app, patch_tenant):
def test_document_indexing_with_extraction_setting(self, app: Flask, patch_tenant):
api = DocumentIndexingEstimateApi()
method = unwrap(api.get)

View File

@ -292,7 +292,7 @@ class TestBedrockRetrievalApi:
class TestExternalApiTemplateListApiAdvanced:
def test_post_duplicate_name_error(self, app, mock_auth, current_user):
def test_post_duplicate_name_error(self, app: Flask, mock_auth, current_user):
api = ExternalApiTemplateListApi()
method = unwrap(api.post)
@ -310,7 +310,7 @@ class TestExternalApiTemplateListApiAdvanced:
with pytest.raises(DatasetNameDuplicateError):
method(api)
def test_get_with_pagination(self, app, mock_auth, current_user):
def test_get_with_pagination(self, app: Flask, mock_auth, current_user):
api = ExternalApiTemplateListApi()
method = unwrap(api.get)
@ -331,7 +331,7 @@ class TestExternalApiTemplateListApiAdvanced:
class TestExternalDatasetCreateApiAdvanced:
def test_create_forbidden(self, app, mock_auth, current_user):
def test_create_forbidden(self, app: Flask, mock_auth, current_user):
"""Test creating external dataset without permission"""
api = ExternalDatasetCreateApi()
method = unwrap(api.post)
@ -351,7 +351,7 @@ class TestExternalDatasetCreateApiAdvanced:
class TestExternalKnowledgeHitTestingApiAdvanced:
def test_hit_testing_dataset_not_found(self, app, mock_auth, current_user):
def test_hit_testing_dataset_not_found(self, app: Flask, mock_auth, current_user):
"""Test hit testing on non-existent dataset"""
api = ExternalKnowledgeHitTestingApi()
method = unwrap(api.post)
@ -372,7 +372,7 @@ class TestExternalKnowledgeHitTestingApiAdvanced:
with pytest.raises(NotFound):
method(api, "ds-1")
def test_hit_testing_with_custom_retrieval_model(self, app, mock_auth, current_user):
def test_hit_testing_with_custom_retrieval_model(self, app: Flask, mock_auth, current_user):
api = ExternalKnowledgeHitTestingApi()
method = unwrap(api.post)
@ -402,7 +402,7 @@ class TestExternalKnowledgeHitTestingApiAdvanced:
class TestBedrockRetrievalApiAdvanced:
def test_bedrock_retrieval_with_invalid_setting(self, app, mock_auth, current_user):
def test_bedrock_retrieval_with_invalid_setting(self, app: Flask, mock_auth, current_user):
api = BedrockRetrievalApi()
method = unwrap(api.post)

View File

@ -82,7 +82,7 @@ def bypass_decorators(mocker: MockerFixture):
class TestDatasetMetadataCreateApi:
def test_create_metadata_success(self, app, current_user, dataset, dataset_id):
def test_create_metadata_success(self, app: Flask, current_user, dataset, dataset_id):
api = DatasetMetadataCreateApi()
method = unwrap(api.post)
@ -125,7 +125,7 @@ class TestDatasetMetadataCreateApi:
assert status == 201
assert result["name"] == "author"
def test_create_metadata_dataset_not_found(self, app, current_user, dataset_id):
def test_create_metadata_dataset_not_found(self, app: Flask, current_user, dataset_id):
api = DatasetMetadataCreateApi()
method = unwrap(api.post)
@ -162,7 +162,7 @@ class TestDatasetMetadataCreateApi:
class TestDatasetMetadataGetApi:
def test_get_metadata_success(self, app, dataset, dataset_id):
def test_get_metadata_success(self, app: Flask, dataset, dataset_id):
api = DatasetMetadataCreateApi()
method = unwrap(api.get)
@ -184,7 +184,7 @@ class TestDatasetMetadataGetApi:
assert status == 200
assert isinstance(result, list)
def test_get_metadata_dataset_not_found(self, app, dataset_id):
def test_get_metadata_dataset_not_found(self, app: Flask, dataset_id):
api = DatasetMetadataCreateApi()
method = unwrap(api.get)
@ -201,7 +201,7 @@ class TestDatasetMetadataGetApi:
class TestDatasetMetadataApi:
def test_update_metadata_success(self, app, current_user, dataset, dataset_id, metadata_id):
def test_update_metadata_success(self, app: Flask, current_user, dataset, dataset_id, metadata_id):
api = DatasetMetadataApi()
method = unwrap(api.patch)
@ -239,7 +239,7 @@ class TestDatasetMetadataApi:
assert status == 200
assert result["name"] == "updated-name"
def test_delete_metadata_success(self, app, current_user, dataset, dataset_id, metadata_id):
def test_delete_metadata_success(self, app: Flask, current_user, dataset, dataset_id, metadata_id):
api = DatasetMetadataApi()
method = unwrap(api.delete)
@ -289,7 +289,7 @@ class TestDatasetMetadataBuiltInFieldApi:
class TestDatasetMetadataBuiltInFieldActionApi:
def test_enable_built_in_field(self, app, current_user, dataset, dataset_id):
def test_enable_built_in_field(self, app: Flask, current_user, dataset, dataset_id):
api = DatasetMetadataBuiltInFieldActionApi()
method = unwrap(api.post)
@ -320,7 +320,7 @@ class TestDatasetMetadataBuiltInFieldActionApi:
class TestDocumentMetadataEditApi:
def test_update_document_metadata_success(self, app, current_user, dataset, dataset_id):
def test_update_document_metadata_success(self, app: Flask, current_user, dataset, dataset_id):
api = DocumentMetadataEditApi()
method = unwrap(api.post)

View File

@ -49,7 +49,7 @@ def bypass_auth_and_setup(mocker: MockerFixture):
class TestWebsiteCrawlApi:
def test_crawl_success(self, app, mocker: MockerFixture):
def test_crawl_success(self, app: Flask, mocker: MockerFixture):
api = WebsiteCrawlApi()
method = unwrap(api.post)
@ -86,7 +86,7 @@ class TestWebsiteCrawlApi:
assert status == 200
assert result["job_id"] == "job-1"
def test_crawl_invalid_payload(self, app, mocker: MockerFixture):
def test_crawl_invalid_payload(self, app: Flask, mocker: MockerFixture):
api = WebsiteCrawlApi()
method = unwrap(api.post)
@ -114,7 +114,7 @@ class TestWebsiteCrawlApi:
with pytest.raises(WebsiteCrawlError, match="invalid payload"):
method(api)
def test_crawl_service_error(self, app, mocker: MockerFixture):
def test_crawl_service_error(self, app: Flask, mocker: MockerFixture):
api = WebsiteCrawlApi()
method = unwrap(api.post)
@ -151,7 +151,7 @@ class TestWebsiteCrawlApi:
class TestWebsiteCrawlStatusApi:
def test_get_status_success(self, app, mocker: MockerFixture):
def test_get_status_success(self, app: Flask, mocker: MockerFixture):
api = WebsiteCrawlStatusApi()
method = unwrap(api.get)
@ -182,7 +182,7 @@ class TestWebsiteCrawlStatusApi:
assert status == 200
assert result["status"] == "completed"
def test_get_status_invalid_provider(self, app, mocker: MockerFixture):
def test_get_status_invalid_provider(self, app: Flask, mocker: MockerFixture):
api = WebsiteCrawlStatusApi()
method = unwrap(api.get)
@ -204,7 +204,7 @@ class TestWebsiteCrawlStatusApi:
with pytest.raises(WebsiteCrawlError, match="invalid provider"):
method(api, job_id)
def test_get_status_service_error(self, app, mocker: MockerFixture):
def test_get_status_service_error(self, app: Flask, mocker: MockerFixture):
api = WebsiteCrawlStatusApi()
method = unwrap(api.get)

View File

@ -2,6 +2,7 @@ from io import BytesIO
from unittest.mock import MagicMock, patch
import pytest
from flask import Flask
from werkzeug.exceptions import InternalServerError
import controllers.console.explore.audio as audio_module
@ -52,7 +53,7 @@ class TestChatAudioApi:
self.api = audio_module.ChatAudioApi()
self.method = unwrap(self.api.post)
def test_post_success(self, app, installed_app, audio_file):
def test_post_success(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -69,7 +70,7 @@ class TestChatAudioApi:
assert resp == {"text": "ok"}
def test_app_unavailable(self, app, installed_app, audio_file):
def test_app_unavailable(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -85,7 +86,7 @@ class TestChatAudioApi:
with pytest.raises(AppUnavailableError):
self.method(installed_app)
def test_no_audio_uploaded(self, app, installed_app, audio_file):
def test_no_audio_uploaded(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -101,7 +102,7 @@ class TestChatAudioApi:
with pytest.raises(NoAudioUploadedError):
self.method(installed_app)
def test_audio_too_large(self, app, installed_app, audio_file):
def test_audio_too_large(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -117,7 +118,7 @@ class TestChatAudioApi:
with pytest.raises(AudioTooLargeError):
self.method(installed_app)
def test_provider_quota_exceeded(self, app, installed_app, audio_file):
def test_provider_quota_exceeded(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -133,7 +134,7 @@ class TestChatAudioApi:
with pytest.raises(ProviderQuotaExceededError):
self.method(installed_app)
def test_unknown_exception(self, app, installed_app, audio_file):
def test_unknown_exception(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -149,7 +150,7 @@ class TestChatAudioApi:
with pytest.raises(InternalServerError):
self.method(installed_app)
def test_unsupported_audio_type(self, app, installed_app, audio_file):
def test_unsupported_audio_type(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -165,7 +166,7 @@ class TestChatAudioApi:
with pytest.raises(audio_module.UnsupportedAudioTypeError):
self.method(installed_app)
def test_provider_not_support_speech_to_text(self, app, installed_app, audio_file):
def test_provider_not_support_speech_to_text(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -181,7 +182,7 @@ class TestChatAudioApi:
with pytest.raises(audio_module.ProviderNotSupportSpeechToTextError):
self.method(installed_app)
def test_provider_not_initialized(self, app, installed_app, audio_file):
def test_provider_not_initialized(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -197,7 +198,7 @@ class TestChatAudioApi:
with pytest.raises(ProviderNotInitializeError):
self.method(installed_app)
def test_model_currently_not_supported(self, app, installed_app, audio_file):
def test_model_currently_not_supported(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -213,7 +214,7 @@ class TestChatAudioApi:
with pytest.raises(ProviderModelCurrentlyNotSupportError):
self.method(installed_app)
def test_invoke_error_asr(self, app, installed_app, audio_file):
def test_invoke_error_asr(self, app: Flask, installed_app, audio_file):
with (
app.test_request_context(
"/",
@ -235,7 +236,7 @@ class TestChatTextApi:
self.api = audio_module.ChatTextApi()
self.method = unwrap(self.api.post)
def test_post_success(self, app, installed_app):
def test_post_success(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -251,7 +252,7 @@ class TestChatTextApi:
assert resp == {"audio": "ok"}
def test_provider_not_initialized(self, app, installed_app):
def test_provider_not_initialized(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -266,7 +267,7 @@ class TestChatTextApi:
with pytest.raises(ProviderNotInitializeError):
self.method(installed_app)
def test_model_not_supported(self, app, installed_app):
def test_model_not_supported(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -281,7 +282,7 @@ class TestChatTextApi:
with pytest.raises(ProviderModelCurrentlyNotSupportError):
self.method(installed_app)
def test_invoke_error(self, app, installed_app):
def test_invoke_error(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -296,7 +297,7 @@ class TestChatTextApi:
with pytest.raises(CompletionRequestError):
self.method(installed_app)
def test_unknown_exception(self, app, installed_app):
def test_unknown_exception(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -311,7 +312,7 @@ class TestChatTextApi:
with pytest.raises(InternalServerError):
self.method(installed_app)
def test_app_unavailable_tts(self, app, installed_app):
def test_app_unavailable_tts(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -326,7 +327,7 @@ class TestChatTextApi:
with pytest.raises(AppUnavailableError):
self.method(installed_app)
def test_no_audio_uploaded_tts(self, app, installed_app):
def test_no_audio_uploaded_tts(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -341,7 +342,7 @@ class TestChatTextApi:
with pytest.raises(NoAudioUploadedError):
self.method(installed_app)
def test_audio_too_large_tts(self, app, installed_app):
def test_audio_too_large_tts(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -356,7 +357,7 @@ class TestChatTextApi:
with pytest.raises(AudioTooLargeError):
self.method(installed_app)
def test_unsupported_audio_type_tts(self, app, installed_app):
def test_unsupported_audio_type_tts(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -371,7 +372,7 @@ class TestChatTextApi:
with pytest.raises(audio_module.UnsupportedAudioTypeError):
self.method(installed_app)
def test_provider_not_support_speech_to_text_tts(self, app, installed_app):
def test_provider_not_support_speech_to_text_tts(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",
@ -386,7 +387,7 @@ class TestChatTextApi:
with pytest.raises(audio_module.ProviderNotSupportSpeechToTextError):
self.method(installed_app)
def test_quota_exceeded_tts(self, app, installed_app):
def test_quota_exceeded_tts(self, app: Flask, installed_app):
with (
app.test_request_context(
"/",

View File

@ -1,6 +1,7 @@
from unittest.mock import MagicMock, PropertyMock, patch
import pytest
from flask import Flask
from werkzeug.exceptions import InternalServerError
import controllers.console.explore.completion as completion_module
@ -51,7 +52,7 @@ def payload_patch(payload_data):
class TestCompletionApi:
def test_post_success(self, app, completion_app, user, payload_patch):
def test_post_success(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -83,7 +84,7 @@ class TestCompletionApi:
with pytest.raises(NotCompletionAppError):
method(installed_app)
def test_conversation_completed(self, app, completion_app, user, payload_patch):
def test_conversation_completed(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -100,7 +101,7 @@ class TestCompletionApi:
with pytest.raises(ConversationCompletedError):
method(completion_app)
def test_internal_error(self, app, completion_app, user, payload_patch):
def test_internal_error(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -117,7 +118,7 @@ class TestCompletionApi:
with pytest.raises(InternalServerError):
method(completion_app)
def test_conversation_not_exists(self, app, completion_app, user, payload_patch):
def test_conversation_not_exists(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -134,7 +135,7 @@ class TestCompletionApi:
with pytest.raises(completion_module.NotFound):
method(completion_app)
def test_app_unavailable(self, app, completion_app, user, payload_patch):
def test_app_unavailable(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -151,7 +152,7 @@ class TestCompletionApi:
with pytest.raises(completion_module.AppUnavailableError):
method(completion_app)
def test_provider_not_initialized(self, app, completion_app, user, payload_patch):
def test_provider_not_initialized(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -168,7 +169,7 @@ class TestCompletionApi:
with pytest.raises(completion_module.ProviderNotInitializeError):
method(completion_app)
def test_quota_exceeded(self, app, completion_app, user, payload_patch):
def test_quota_exceeded(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -185,7 +186,7 @@ class TestCompletionApi:
with pytest.raises(completion_module.ProviderQuotaExceededError):
method(completion_app)
def test_model_not_supported(self, app, completion_app, user, payload_patch):
def test_model_not_supported(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -202,7 +203,7 @@ class TestCompletionApi:
with pytest.raises(completion_module.ProviderModelCurrentlyNotSupportError):
method(completion_app)
def test_invoke_error(self, app, completion_app, user, payload_patch):
def test_invoke_error(self, app: Flask, completion_app, user, payload_patch):
api = completion_module.CompletionApi()
method = unwrap(api.post)
@ -247,7 +248,7 @@ class TestCompletionStopApi:
class TestChatApi:
def test_post_success(self, app, chat_app, user, payload_patch):
def test_post_success(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -279,7 +280,7 @@ class TestChatApi:
with pytest.raises(NotChatAppError):
method(installed_app)
def test_rate_limit_error(self, app, chat_app, user, payload_patch):
def test_rate_limit_error(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -296,7 +297,7 @@ class TestChatApi:
with pytest.raises(InvokeRateLimitHttpError):
method(chat_app)
def test_conversation_completed_chat(self, app, chat_app, user, payload_patch):
def test_conversation_completed_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -313,7 +314,7 @@ class TestChatApi:
with pytest.raises(ConversationCompletedError):
method(chat_app)
def test_conversation_not_exists_chat(self, app, chat_app, user, payload_patch):
def test_conversation_not_exists_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -330,7 +331,7 @@ class TestChatApi:
with pytest.raises(completion_module.NotFound):
method(chat_app)
def test_app_unavailable_chat(self, app, chat_app, user, payload_patch):
def test_app_unavailable_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -347,7 +348,7 @@ class TestChatApi:
with pytest.raises(completion_module.AppUnavailableError):
method(chat_app)
def test_provider_not_initialized_chat(self, app, chat_app, user, payload_patch):
def test_provider_not_initialized_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -364,7 +365,7 @@ class TestChatApi:
with pytest.raises(completion_module.ProviderNotInitializeError):
method(chat_app)
def test_quota_exceeded_chat(self, app, chat_app, user, payload_patch):
def test_quota_exceeded_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -381,7 +382,7 @@ class TestChatApi:
with pytest.raises(completion_module.ProviderQuotaExceededError):
method(chat_app)
def test_model_not_supported_chat(self, app, chat_app, user, payload_patch):
def test_model_not_supported_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -398,7 +399,7 @@ class TestChatApi:
with pytest.raises(completion_module.ProviderModelCurrentlyNotSupportError):
method(chat_app)
def test_invoke_error_chat(self, app, chat_app, user, payload_patch):
def test_invoke_error_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)
@ -415,7 +416,7 @@ class TestChatApi:
with pytest.raises(completion_module.CompletionRequestError):
method(chat_app)
def test_internal_error_chat(self, app, chat_app, user, payload_patch):
def test_internal_error_chat(self, app: Flask, chat_app, user, payload_patch):
api = completion_module.ChatApi()
method = unwrap(api.post)

View File

@ -2,6 +2,7 @@ from datetime import datetime
from unittest.mock import MagicMock, PropertyMock, patch
import pytest
from flask import Flask
from werkzeug.exceptions import BadRequest, Forbidden, NotFound
import controllers.console.explore.installed_app as module
@ -51,7 +52,7 @@ def payload_patch():
class TestInstalledAppsListApi:
def test_get_installed_apps(self, app, current_user, tenant_id, installed_app):
def test_get_installed_apps(self, app: Flask, current_user, tenant_id, installed_app):
api = module.InstalledAppsListApi()
method = unwrap(api.get)
@ -75,7 +76,7 @@ class TestInstalledAppsListApi:
assert result["installed_apps"][0]["editable"] is True
assert result["installed_apps"][0]["uninstallable"] is False
def test_get_installed_apps_with_app_id_filter(self, app, current_user, tenant_id):
def test_get_installed_apps_with_app_id_filter(self, app: Flask, current_user, tenant_id):
api = module.InstalledAppsListApi()
method = unwrap(api.get)
@ -97,7 +98,7 @@ class TestInstalledAppsListApi:
assert result == {"installed_apps": []}
def test_get_installed_apps_with_webapp_auth_enabled(self, app, current_user, tenant_id, installed_app):
def test_get_installed_apps_with_webapp_auth_enabled(self, app: Flask, current_user, tenant_id, installed_app):
"""Test filtering when webapp_auth is enabled."""
api = module.InstalledAppsListApi()
method = unwrap(api.get)
@ -133,7 +134,7 @@ class TestInstalledAppsListApi:
assert len(result["installed_apps"]) == 1
def test_get_installed_apps_with_webapp_auth_user_denied(self, app, current_user, tenant_id, installed_app):
def test_get_installed_apps_with_webapp_auth_user_denied(self, app: Flask, current_user, tenant_id, installed_app):
"""Test filtering when user doesn't have access."""
api = module.InstalledAppsListApi()
method = unwrap(api.get)
@ -169,7 +170,7 @@ class TestInstalledAppsListApi:
assert result["installed_apps"] == []
def test_get_installed_apps_with_sso_verified_access(self, app, current_user, tenant_id, installed_app):
def test_get_installed_apps_with_sso_verified_access(self, app: Flask, current_user, tenant_id, installed_app):
"""Test that sso_verified access mode apps are skipped in filtering."""
api = module.InstalledAppsListApi()
method = unwrap(api.get)
@ -200,7 +201,7 @@ class TestInstalledAppsListApi:
assert len(result["installed_apps"]) == 0
def test_get_installed_apps_filters_null_apps(self, app, current_user, tenant_id):
def test_get_installed_apps_filters_null_apps(self, app: Flask, current_user, tenant_id):
"""Test that installed apps with null app are filtered out."""
api = module.InstalledAppsListApi()
method = unwrap(api.get)
@ -226,7 +227,7 @@ class TestInstalledAppsListApi:
assert result["installed_apps"] == []
def test_get_installed_apps_current_tenant_none(self, app, tenant_id, installed_app):
def test_get_installed_apps_current_tenant_none(self, app: Flask, tenant_id, installed_app):
"""Test error when current_user.current_tenant is None."""
api = module.InstalledAppsListApi()
method = unwrap(api.get)
@ -247,7 +248,7 @@ class TestInstalledAppsListApi:
class TestInstalledAppsCreateApi:
def test_post_success(self, app, tenant_id, payload_patch):
def test_post_success(self, app: Flask, tenant_id, payload_patch):
api = module.InstalledAppsListApi()
method = unwrap(api.post)
@ -276,7 +277,7 @@ class TestInstalledAppsCreateApi:
assert result == {"message": "App installed successfully"}
assert recommended.install_count == 1
def test_post_recommended_not_found(self, app, payload_patch):
def test_post_recommended_not_found(self, app: Flask, payload_patch):
api = module.InstalledAppsListApi()
method = unwrap(api.post)
@ -291,7 +292,7 @@ class TestInstalledAppsCreateApi:
with pytest.raises(NotFound):
method(api)
def test_post_app_not_public(self, app, tenant_id, payload_patch):
def test_post_app_not_public(self, app: Flask, tenant_id, payload_patch):
api = module.InstalledAppsListApi()
method = unwrap(api.post)
@ -315,7 +316,7 @@ class TestInstalledAppsCreateApi:
class TestInstalledAppApi:
def test_delete_success(self, tenant_id, installed_app):
def test_delete_success(self, tenant_id: str, installed_app):
api = module.InstalledAppApi()
method = unwrap(api.delete)
@ -328,7 +329,7 @@ class TestInstalledAppApi:
assert status == 204
assert resp["result"] == "success"
def test_delete_owned_by_current_tenant(self, tenant_id):
def test_delete_owned_by_current_tenant(self, tenant_id: str):
api = module.InstalledAppApi()
method = unwrap(api.delete)
@ -338,7 +339,7 @@ class TestInstalledAppApi:
with pytest.raises(BadRequest):
method(installed_app)
def test_patch_update_pin(self, app, payload_patch, installed_app):
def test_patch_update_pin(self, app: Flask, payload_patch, installed_app):
api = module.InstalledAppApi()
method = unwrap(api.patch)
@ -352,7 +353,7 @@ class TestInstalledAppApi:
assert installed_app.is_pinned is True
assert result["result"] == "success"
def test_patch_no_change(self, app, payload_patch, installed_app):
def test_patch_no_change(self, app: Flask, payload_patch, installed_app):
api = module.InstalledAppApi()
method = unwrap(api.patch)

View File

@ -82,7 +82,7 @@ class TestSavedMessageListApi:
with pytest.raises(NotCompletionAppError):
method(installed_app)
def test_post_success(self, app, payload_patch):
def test_post_success(self, app: Flask, payload_patch):
api = module.SavedMessageListApi()
method = unwrap(api.post)
@ -102,7 +102,7 @@ class TestSavedMessageListApi:
save_mock.assert_called_once()
assert result == {"result": "success"}
def test_post_message_not_exists(self, app, payload_patch):
def test_post_message_not_exists(self, app: Flask, payload_patch):
api = module.SavedMessageListApi()
method = unwrap(api.post)

View File

@ -102,7 +102,7 @@ class TestTrialAppWorkflowRunApi:
with pytest.raises(NotWorkflowAppError):
method(api, MagicMock(mode=AppMode.CHAT))
def test_success(self, app, trial_app_workflow, account):
def test_success(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -116,7 +116,7 @@ class TestTrialAppWorkflowRunApi:
assert result is not None
def test_workflow_provider_not_init(self, app, trial_app_workflow, account):
def test_workflow_provider_not_init(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -132,7 +132,7 @@ class TestTrialAppWorkflowRunApi:
with pytest.raises(ProviderNotInitializeError):
method(api, trial_app_workflow)
def test_workflow_quota_exceeded(self, app, trial_app_workflow, account):
def test_workflow_quota_exceeded(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -148,7 +148,7 @@ class TestTrialAppWorkflowRunApi:
with pytest.raises(ProviderQuotaExceededError):
method(api, trial_app_workflow)
def test_workflow_model_not_support(self, app, trial_app_workflow, account):
def test_workflow_model_not_support(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -164,7 +164,7 @@ class TestTrialAppWorkflowRunApi:
with pytest.raises(ProviderModelCurrentlyNotSupportError):
method(api, trial_app_workflow)
def test_workflow_invoke_error(self, app, trial_app_workflow, account):
def test_workflow_invoke_error(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -180,7 +180,7 @@ class TestTrialAppWorkflowRunApi:
with pytest.raises(CompletionRequestError):
method(api, trial_app_workflow)
def test_workflow_rate_limit_error(self, app, trial_app_workflow, account):
def test_workflow_rate_limit_error(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -196,7 +196,7 @@ class TestTrialAppWorkflowRunApi:
with pytest.raises(InvokeRateLimitHttpError):
method(api, trial_app_workflow)
def test_workflow_value_error(self, app, trial_app_workflow, account):
def test_workflow_value_error(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -212,7 +212,7 @@ class TestTrialAppWorkflowRunApi:
with pytest.raises(ValueError):
method(api, trial_app_workflow)
def test_workflow_generic_exception(self, app, trial_app_workflow, account):
def test_workflow_generic_exception(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowRunApi()
method = unwrap(api.post)
@ -238,7 +238,7 @@ class TestTrialChatApi:
with pytest.raises(NotChatAppError):
method(api, MagicMock(mode="completion"))
def test_success(self, app, trial_app_chat, account):
def test_success(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -252,7 +252,7 @@ class TestTrialChatApi:
assert result is not None
def test_chat_conversation_not_exists(self, app, trial_app_chat, account):
def test_chat_conversation_not_exists(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -268,7 +268,7 @@ class TestTrialChatApi:
with pytest.raises(NotFound):
method(api, trial_app_chat)
def test_chat_conversation_completed(self, app, trial_app_chat, account):
def test_chat_conversation_completed(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -284,7 +284,7 @@ class TestTrialChatApi:
with pytest.raises(ConversationCompletedError):
method(api, trial_app_chat)
def test_chat_app_config_broken(self, app, trial_app_chat, account):
def test_chat_app_config_broken(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -300,7 +300,7 @@ class TestTrialChatApi:
with pytest.raises(AppUnavailableError):
method(api, trial_app_chat)
def test_chat_provider_not_init(self, app, trial_app_chat, account):
def test_chat_provider_not_init(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -316,7 +316,7 @@ class TestTrialChatApi:
with pytest.raises(ProviderNotInitializeError):
method(api, trial_app_chat)
def test_chat_quota_exceeded(self, app, trial_app_chat, account):
def test_chat_quota_exceeded(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -332,7 +332,7 @@ class TestTrialChatApi:
with pytest.raises(ProviderQuotaExceededError):
method(api, trial_app_chat)
def test_chat_model_not_support(self, app, trial_app_chat, account):
def test_chat_model_not_support(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -348,7 +348,7 @@ class TestTrialChatApi:
with pytest.raises(ProviderModelCurrentlyNotSupportError):
method(api, trial_app_chat)
def test_chat_invoke_error(self, app, trial_app_chat, account):
def test_chat_invoke_error(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -364,7 +364,7 @@ class TestTrialChatApi:
with pytest.raises(CompletionRequestError):
method(api, trial_app_chat)
def test_chat_rate_limit_error(self, app, trial_app_chat, account):
def test_chat_rate_limit_error(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -380,7 +380,7 @@ class TestTrialChatApi:
with pytest.raises(InvokeRateLimitHttpError):
method(api, trial_app_chat)
def test_chat_value_error(self, app, trial_app_chat, account):
def test_chat_value_error(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -396,7 +396,7 @@ class TestTrialChatApi:
with pytest.raises(ValueError):
method(api, trial_app_chat)
def test_chat_generic_exception(self, app, trial_app_chat, account):
def test_chat_generic_exception(self, app: Flask, trial_app_chat, account):
api = module.TrialChatApi()
method = unwrap(api.post)
@ -422,7 +422,7 @@ class TestTrialCompletionApi:
with pytest.raises(NotCompletionAppError):
method(api, MagicMock(mode=AppMode.CHAT))
def test_success(self, app, trial_app_completion, account):
def test_success(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -436,7 +436,7 @@ class TestTrialCompletionApi:
assert result is not None
def test_completion_app_config_broken(self, app, trial_app_completion, account):
def test_completion_app_config_broken(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -452,7 +452,7 @@ class TestTrialCompletionApi:
with pytest.raises(AppUnavailableError):
method(api, trial_app_completion)
def test_completion_provider_not_init(self, app, trial_app_completion, account):
def test_completion_provider_not_init(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -468,7 +468,7 @@ class TestTrialCompletionApi:
with pytest.raises(ProviderNotInitializeError):
method(api, trial_app_completion)
def test_completion_quota_exceeded(self, app, trial_app_completion, account):
def test_completion_quota_exceeded(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -484,7 +484,7 @@ class TestTrialCompletionApi:
with pytest.raises(ProviderQuotaExceededError):
method(api, trial_app_completion)
def test_completion_model_not_support(self, app, trial_app_completion, account):
def test_completion_model_not_support(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -500,7 +500,7 @@ class TestTrialCompletionApi:
with pytest.raises(ProviderModelCurrentlyNotSupportError):
method(api, trial_app_completion)
def test_completion_invoke_error(self, app, trial_app_completion, account):
def test_completion_invoke_error(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -516,7 +516,7 @@ class TestTrialCompletionApi:
with pytest.raises(CompletionRequestError):
method(api, trial_app_completion)
def test_completion_rate_limit_error(self, app, trial_app_completion, account):
def test_completion_rate_limit_error(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -532,7 +532,7 @@ class TestTrialCompletionApi:
with pytest.raises(InternalServerError):
method(api, trial_app_completion)
def test_completion_value_error(self, app, trial_app_completion, account):
def test_completion_value_error(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -548,7 +548,7 @@ class TestTrialCompletionApi:
with pytest.raises(ValueError):
method(api, trial_app_completion)
def test_completion_generic_exception(self, app, trial_app_completion, account):
def test_completion_generic_exception(self, app: Flask, trial_app_completion, account):
api = module.TrialCompletionApi()
method = unwrap(api.post)
@ -574,7 +574,7 @@ class TestTrialMessageSuggestedQuestionApi:
with pytest.raises(NotChatAppError):
method(MagicMock(mode="completion"), str(uuid4()))
def test_success(self, app, trial_app_chat, account):
def test_success(self, app: Flask, trial_app_chat, account):
api = module.TrialMessageSuggestedQuestionApi()
method = unwrap(api.get)
@ -591,7 +591,7 @@ class TestTrialMessageSuggestedQuestionApi:
assert result == {"data": ["q1", "q2"]}
def test_conversation_not_exists(self, app, trial_app_chat, account):
def test_conversation_not_exists(self, app: Flask, trial_app_chat, account):
api = module.TrialMessageSuggestedQuestionApi()
method = unwrap(api.get)
@ -643,7 +643,7 @@ class TestTrialAppParameterApi:
class TestTrialChatAudioApi:
def test_success(self, app, trial_app_chat, account):
def test_success(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -662,7 +662,7 @@ class TestTrialChatAudioApi:
assert result == {"text": "hello"}
def test_app_config_broken(self, app, trial_app_chat, account):
def test_app_config_broken(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -683,7 +683,7 @@ class TestTrialChatAudioApi:
with pytest.raises(module.AppUnavailableError):
method(api, trial_app_chat)
def test_no_audio_uploaded(self, app, trial_app_chat, account):
def test_no_audio_uploaded(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -704,7 +704,7 @@ class TestTrialChatAudioApi:
with pytest.raises(module.NoAudioUploadedError):
method(api, trial_app_chat)
def test_audio_too_large(self, app, trial_app_chat, account):
def test_audio_too_large(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -725,7 +725,7 @@ class TestTrialChatAudioApi:
with pytest.raises(module.AudioTooLargeError):
method(api, trial_app_chat)
def test_unsupported_audio_type(self, app, trial_app_chat, account):
def test_unsupported_audio_type(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -746,7 +746,7 @@ class TestTrialChatAudioApi:
with pytest.raises(module.UnsupportedAudioTypeError):
method(api, trial_app_chat)
def test_provider_not_support_tts(self, app, trial_app_chat, account):
def test_provider_not_support_tts(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -767,7 +767,7 @@ class TestTrialChatAudioApi:
with pytest.raises(module.ProviderNotSupportSpeechToTextError):
method(api, trial_app_chat)
def test_provider_not_init(self, app, trial_app_chat, account):
def test_provider_not_init(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -784,7 +784,7 @@ class TestTrialChatAudioApi:
with pytest.raises(ProviderNotInitializeError):
method(api, trial_app_chat)
def test_quota_exceeded(self, app, trial_app_chat, account):
def test_quota_exceeded(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -803,7 +803,7 @@ class TestTrialChatAudioApi:
class TestTrialChatTextApi:
def test_success(self, app, trial_app_chat, account):
def test_success(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -817,7 +817,7 @@ class TestTrialChatTextApi:
assert result == {"audio": "base64_data"}
def test_app_config_broken(self, app, trial_app_chat, account):
def test_app_config_broken(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -833,7 +833,7 @@ class TestTrialChatTextApi:
with pytest.raises(module.AppUnavailableError):
method(api, trial_app_chat)
def test_provider_not_support(self, app, trial_app_chat, account):
def test_provider_not_support(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -849,7 +849,7 @@ class TestTrialChatTextApi:
with pytest.raises(module.ProviderNotSupportSpeechToTextError):
method(api, trial_app_chat)
def test_audio_too_large(self, app, trial_app_chat, account):
def test_audio_too_large(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -865,7 +865,7 @@ class TestTrialChatTextApi:
with pytest.raises(module.AudioTooLargeError):
method(api, trial_app_chat)
def test_no_audio_uploaded(self, app, trial_app_chat, account):
def test_no_audio_uploaded(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -881,7 +881,7 @@ class TestTrialChatTextApi:
with pytest.raises(module.NoAudioUploadedError):
method(api, trial_app_chat)
def test_provider_not_init(self, app, trial_app_chat, account):
def test_provider_not_init(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -893,7 +893,7 @@ class TestTrialChatTextApi:
with pytest.raises(ProviderNotInitializeError):
method(api, trial_app_chat)
def test_quota_exceeded(self, app, trial_app_chat, account):
def test_quota_exceeded(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -905,7 +905,7 @@ class TestTrialChatTextApi:
with pytest.raises(ProviderQuotaExceededError):
method(api, trial_app_chat)
def test_model_not_support(self, app, trial_app_chat, account):
def test_model_not_support(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -917,7 +917,7 @@ class TestTrialChatTextApi:
with pytest.raises(ProviderModelCurrentlyNotSupportError):
method(api, trial_app_chat)
def test_invoke_error(self, app, trial_app_chat, account):
def test_invoke_error(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -931,7 +931,7 @@ class TestTrialChatTextApi:
class TestTrialAppWorkflowTaskStopApi:
def test_not_workflow_app(self, app, trial_app_chat):
def test_not_workflow_app(self, app: Flask, trial_app_chat):
api = module.TrialAppWorkflowTaskStopApi()
method = unwrap(api.post)
@ -939,7 +939,7 @@ class TestTrialAppWorkflowTaskStopApi:
with pytest.raises(NotWorkflowAppError):
method(api, trial_app_chat, str(uuid4()))
def test_success(self, app, trial_app_workflow, account):
def test_success(self, app: Flask, trial_app_workflow, account):
api = module.TrialAppWorkflowTaskStopApi()
method = unwrap(api.post)
@ -1009,7 +1009,7 @@ class TestTrialSitApi:
class TestTrialChatAudioApiExceptionHandlers:
def test_provider_not_init(self, app, trial_app_chat, account):
def test_provider_not_init(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -1030,7 +1030,7 @@ class TestTrialChatAudioApiExceptionHandlers:
with pytest.raises(ProviderNotInitializeError):
method(api, trial_app_chat)
def test_quota_exceeded(self, app, trial_app_chat, account):
def test_quota_exceeded(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -1051,7 +1051,7 @@ class TestTrialChatAudioApiExceptionHandlers:
with pytest.raises(ProviderQuotaExceededError):
method(api, trial_app_chat)
def test_invoke_error(self, app, trial_app_chat, account):
def test_invoke_error(self, app: Flask, trial_app_chat, account):
api = module.TrialChatAudioApi()
method = unwrap(api.post)
@ -1074,7 +1074,7 @@ class TestTrialChatAudioApiExceptionHandlers:
class TestTrialChatTextApiExceptionHandlers:
def test_app_config_broken(self, app, trial_app_chat, account):
def test_app_config_broken(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)
@ -1090,7 +1090,7 @@ class TestTrialChatTextApiExceptionHandlers:
with pytest.raises(module.AppUnavailableError):
method(api, trial_app_chat)
def test_unsupported_audio_type(self, app, trial_app_chat, account):
def test_unsupported_audio_type(self, app: Flask, trial_app_chat, account):
api = module.TrialChatTextApi()
method = unwrap(api.post)

View File

@ -57,7 +57,7 @@ def payload():
class TestInstalledAppWorkflowRunApi:
def test_not_workflow_app(self, app, non_workflow_installed_app):
def test_not_workflow_app(self, app: Flask, non_workflow_installed_app):
api = InstalledAppWorkflowRunApi()
method = unwrap(api.post)
@ -71,7 +71,7 @@ class TestInstalledAppWorkflowRunApi:
with pytest.raises(NotWorkflowAppError):
method(non_workflow_installed_app)
def test_success(self, app, installed_workflow_app, user, payload):
def test_success(self, app: Flask, installed_workflow_app, user, payload):
api = InstalledAppWorkflowRunApi()
method = unwrap(api.post)
@ -91,7 +91,7 @@ class TestInstalledAppWorkflowRunApi:
generate_mock.assert_called_once()
assert result is not None
def test_rate_limit_error(self, app, installed_workflow_app, user, payload):
def test_rate_limit_error(self, app: Flask, installed_workflow_app, user, payload):
api = InstalledAppWorkflowRunApi()
method = unwrap(api.post)
@ -109,7 +109,7 @@ class TestInstalledAppWorkflowRunApi:
with pytest.raises(InvokeRateLimitHttpError):
method(installed_workflow_app)
def test_unexpected_exception(self, app, installed_workflow_app, user, payload):
def test_unexpected_exception(self, app: Flask, installed_workflow_app, user, payload):
api = InstalledAppWorkflowRunApi()
method = unwrap(api.post)

View File

@ -101,7 +101,7 @@ class TestTagListApi:
assert status == 200
assert result == [{"id": "1", "name": "tag", "type": "knowledge", "binding_count": "1"}]
def test_post_success(self, app, admin_user, tag, payload_patch):
def test_post_success(self, app: Flask, admin_user, tag, payload_patch):
api = TagListApi()
method = unwrap(api.post)
@ -144,7 +144,7 @@ class TestTagListApi:
class TestTagUpdateDeleteApi:
def test_patch_success(self, app, admin_user, tag, payload_patch):
def test_patch_success(self, app: Flask, admin_user, tag, payload_patch):
api = TagUpdateDeleteApi()
method = unwrap(api.patch)
@ -191,7 +191,7 @@ class TestTagUpdateDeleteApi:
with pytest.raises(Forbidden):
method(api, "tag-1")
def test_delete_success(self, app, admin_user):
def test_delete_success(self, app: Flask, admin_user):
api = TagUpdateDeleteApi()
method = unwrap(api.delete)
@ -210,7 +210,7 @@ class TestTagUpdateDeleteApi:
class TestTagBindingCollectionApi:
def test_create_success(self, app, admin_user, payload_patch):
def test_create_success(self, app: Flask, admin_user, payload_patch):
api = TagBindingCollectionApi()
method = unwrap(api.post)
@ -252,7 +252,7 @@ class TestTagBindingCollectionApi:
class TestTagBindingRemoveApi:
def test_remove_success(self, app, admin_user, payload_patch):
def test_remove_success(self, app: Flask, admin_user, payload_patch):
api = TagBindingRemoveApi()
method = unwrap(api.post)

View File

@ -95,7 +95,7 @@ class TestFileApiGet:
class TestFileApiPost:
def test_no_file_uploaded(self, app, mock_account_context):
def test_no_file_uploaded(self, app: Flask, mock_account_context):
api = FileApi()
post_method = unwrap(api.post)
@ -103,7 +103,7 @@ class TestFileApiPost:
with pytest.raises(NoFileUploadedError):
post_method(api)
def test_too_many_files(self, app, mock_account_context):
def test_too_many_files(self, app: Flask, mock_account_context):
api = FileApi()
post_method = unwrap(api.post)
@ -120,7 +120,7 @@ class TestFileApiPost:
with pytest.raises(TooManyFilesError):
post_method(api)
def test_filename_missing(self, app, mock_account_context):
def test_filename_missing(self, app: Flask, mock_account_context):
api = FileApi()
post_method = unwrap(api.post)
@ -132,7 +132,7 @@ class TestFileApiPost:
with pytest.raises(FilenameNotExistsError):
post_method(api)
def test_dataset_upload_without_permission(self, app, mock_current_user):
def test_dataset_upload_without_permission(self, app: Flask, mock_current_user):
mock_current_user.is_dataset_editor = False
with patch(
@ -151,7 +151,7 @@ class TestFileApiPost:
with pytest.raises(Forbidden):
post_method(api)
def test_successful_upload(self, app, mock_account_context, mock_file_service):
def test_successful_upload(self, app: Flask, mock_account_context, mock_file_service):
api = FileApi()
post_method = unwrap(api.post)
@ -185,7 +185,7 @@ class TestFileApiPost:
assert response["id"] == "file-id-123"
assert response["name"] == "test.txt"
def test_upload_with_invalid_source(self, app, mock_account_context, mock_file_service):
def test_upload_with_invalid_source(self, app: Flask, mock_account_context, mock_file_service):
"""Test that invalid source parameter gets normalized to None"""
api = FileApi()
post_method = unwrap(api.post)
@ -225,7 +225,7 @@ class TestFileApiPost:
call_kwargs = mock_file_service.upload_file.call_args[1]
assert call_kwargs["source"] is None
def test_file_too_large_error(self, app, mock_account_context, mock_file_service):
def test_file_too_large_error(self, app: Flask, mock_account_context, mock_file_service):
api = FileApi()
post_method = unwrap(api.post)
@ -242,7 +242,7 @@ class TestFileApiPost:
with pytest.raises(FileTooLargeError):
post_method(api)
def test_unsupported_file_type(self, app, mock_account_context, mock_file_service):
def test_unsupported_file_type(self, app: Flask, mock_account_context, mock_file_service):
api = FileApi()
post_method = unwrap(api.post)
@ -259,7 +259,7 @@ class TestFileApiPost:
with pytest.raises(UnsupportedFileTypeError):
post_method(api)
def test_blocked_extension(self, app, mock_account_context, mock_file_service):
def test_blocked_extension(self, app: Flask, mock_account_context, mock_file_service):
api = FileApi()
post_method = unwrap(api.post)
@ -278,7 +278,7 @@ class TestFileApiPost:
class TestFilePreviewApi:
def test_get_preview(self, app, mock_account_context, mock_file_service):
def test_get_preview(self, app: Flask, mock_account_context, mock_file_service):
api = FilePreviewApi()
get_method = unwrap(api.get)
mock_file_service.get_file_preview.return_value = "preview text"

View File

@ -114,7 +114,7 @@ class TestAccountUpdateApis:
(AccountTimezoneApi, {"timezone": "UTC"}),
],
)
def test_update_success(self, app, api_cls, payload):
def test_update_success(self, app: Flask, api_cls, payload):
api = api_cls()
method = unwrap(api.post)

View File

@ -302,7 +302,7 @@ class TestPluginFetchPermissionApi:
class TestPluginFetchDynamicSelectOptionsApi:
def test_fetch_dynamic_options(self, app, user):
def test_fetch_dynamic_options(self, app: Flask, user):
api = PluginFetchDynamicSelectOptionsApi()
method = unwrap(api.get)

View File

@ -17,6 +17,7 @@ from types import SimpleNamespace
from unittest.mock import Mock
import pytest
from flask import Flask
from flask_restx.api import HTTPStatus
from controllers.service_api.app.annotation import (
@ -163,7 +164,7 @@ class TestAnnotationErrorPatterns:
class TestAnnotationReplyActionApi:
def test_enable(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_enable(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
enable_mock = Mock()
monkeypatch.setattr(AppAnnotationService, "enable_app_annotation", enable_mock)
@ -181,7 +182,7 @@ class TestAnnotationReplyActionApi:
assert status == 200
enable_mock.assert_called_once()
def test_disable(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_disable(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
disable_mock = Mock()
monkeypatch.setattr(AppAnnotationService, "disable_app_annotation", disable_mock)
@ -231,7 +232,7 @@ class TestAnnotationReplyActionStatusApi:
class TestAnnotationListApi:
def test_get(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_get(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
annotation = SimpleNamespace(id="a1", question="q", content="a", created_at=0)
monkeypatch.setattr(
AppAnnotationService,
@ -248,7 +249,7 @@ class TestAnnotationListApi:
assert response["total"] == 1
def test_create(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_create(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
annotation = SimpleNamespace(id="a1", question="q", content="a", created_at=0)
monkeypatch.setattr(
AppAnnotationService,
@ -268,7 +269,7 @@ class TestAnnotationListApi:
class TestAnnotationUpdateDeleteApi:
def test_update_delete(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_update_delete(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
annotation = SimpleNamespace(id="a1", question="q", content="a", created_at=0)
monkeypatch.setattr(
AppAnnotationService,

View File

@ -415,7 +415,7 @@ class TestChatRequestPayloadController:
class TestCompletionApiController:
def test_wrong_mode(self, app) -> None:
def test_wrong_mode(self, app: Flask) -> None:
api = CompletionApi()
handler = _unwrap(api.post)
app_model = SimpleNamespace(mode=AppMode.CHAT.value)
@ -425,7 +425,7 @@ class TestCompletionApiController:
with pytest.raises(AppUnavailableError):
handler(api, app_model=app_model, end_user=end_user)
def test_conversation_not_found(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_conversation_not_found(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
AppGenerateService,
"generate",
@ -443,7 +443,7 @@ class TestCompletionApiController:
class TestCompletionStopApiController:
def test_wrong_mode(self, app) -> None:
def test_wrong_mode(self, app: Flask) -> None:
api = CompletionStopApi()
handler = _unwrap(api.post)
app_model = SimpleNamespace(mode=AppMode.CHAT.value)
@ -453,7 +453,7 @@ class TestCompletionStopApiController:
with pytest.raises(AppUnavailableError):
handler(api, app_model=app_model, end_user=end_user, task_id="t1")
def test_success(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_success(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
stop_mock = Mock()
monkeypatch.setattr(AppTaskService, "stop_task", stop_mock)
@ -470,7 +470,7 @@ class TestCompletionStopApiController:
class TestChatApiController:
def test_wrong_mode(self, app) -> None:
def test_wrong_mode(self, app: Flask) -> None:
api = ChatApi()
handler = _unwrap(api.post)
app_model = SimpleNamespace(mode=AppMode.COMPLETION.value)
@ -480,7 +480,7 @@ class TestChatApiController:
with pytest.raises(NotChatAppError):
handler(api, app_model=app_model, end_user=end_user)
def test_workflow_not_found(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_workflow_not_found(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
AppGenerateService,
"generate",
@ -496,7 +496,7 @@ class TestChatApiController:
with pytest.raises(NotFound):
handler(api, app_model=app_model, end_user=end_user)
def test_draft_workflow(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_draft_workflow(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
AppGenerateService,
"generate",
@ -514,10 +514,10 @@ class TestChatApiController:
class TestChatStopApiController:
def test_wrong_mode(self, app) -> None:
def test_wrong_mode(self, app: Flask) -> None:
api = ChatStopApi()
handler = _unwrap(api.post)
app_model = SimpleNamespace(mode=AppMode.COMPLETION.value)
app_model = SimpleNamespace(mode=AppMode.COMPLETION)
end_user = SimpleNamespace(id="u1")
with app.test_request_context("/chat-messages/1/stop", method="POST"):

View File

@ -495,7 +495,7 @@ class TestConversationPayloadsController:
class TestConversationApiController:
def test_list_not_chat(self, app) -> None:
def test_list_not_chat(self, app: Flask) -> None:
api = ConversationApi()
handler = _unwrap(api.get)
app_model = SimpleNamespace(mode=AppMode.COMPLETION)
@ -543,7 +543,7 @@ class TestConversationApiController:
class TestConversationDetailApiController:
def test_delete_not_chat(self, app) -> None:
def test_delete_not_chat(self, app: Flask) -> None:
api = ConversationDetailApi()
handler = _unwrap(api.delete)
app_model = SimpleNamespace(mode=AppMode.COMPLETION)
@ -593,7 +593,7 @@ class TestConversationRenameApiController:
class TestConversationVariablesApiController:
def test_not_chat(self, app) -> None:
def test_not_chat(self, app: Flask) -> None:
api = ConversationVariablesApi()
handler = _unwrap(api.get)
app_model = SimpleNamespace(mode=AppMode.COMPLETION)

View File

@ -238,7 +238,7 @@ class TestFileApiPost:
self,
mock_db,
mock_file_svc_cls,
app,
app: Flask,
mock_app_model,
mock_end_user,
):
@ -342,7 +342,7 @@ class TestFileApiPost:
self,
mock_db,
mock_file_svc_cls,
app,
app: Flask,
mock_app_model,
mock_end_user,
):
@ -374,7 +374,7 @@ class TestFileApiPost:
self,
mock_db,
mock_file_svc_cls,
app,
app: Flask,
mock_app_model,
mock_end_user,
):

View File

@ -66,7 +66,7 @@ class TestFilePreviewApi:
return message
def test_validate_file_ownership_success(
self, file_preview_api, mock_app, mock_upload_file, mock_message_file, mock_message
self, file_preview_api: FilePreviewApi, mock_app, mock_upload_file, mock_message_file, mock_message
):
"""Test successful file ownership validation"""
file_id = str(uuid.uuid4())
@ -97,7 +97,7 @@ class TestFilePreviewApi:
assert result_message_file == mock_message_file
assert result_upload_file == mock_upload_file
def test_validate_file_ownership_file_not_found(self, file_preview_api):
def test_validate_file_ownership_file_not_found(self, file_preview_api: FilePreviewApi):
"""Test file ownership validation when MessageFile not found"""
file_id = str(uuid.uuid4())
app_id = str(uuid.uuid4())
@ -112,7 +112,7 @@ class TestFilePreviewApi:
assert "File not found in message context" in str(exc_info.value)
def test_validate_file_ownership_access_denied(self, file_preview_api, mock_message_file):
def test_validate_file_ownership_access_denied(self, file_preview_api: FilePreviewApi, mock_message_file):
"""Test file ownership validation when Message not owned by app"""
file_id = str(uuid.uuid4())
app_id = str(uuid.uuid4())
@ -130,7 +130,9 @@ class TestFilePreviewApi:
assert "not owned by requesting app" in str(exc_info.value)
def test_validate_file_ownership_upload_file_not_found(self, file_preview_api, mock_message_file, mock_message):
def test_validate_file_ownership_upload_file_not_found(
self, file_preview_api: FilePreviewApi, mock_message_file, mock_message
):
"""Test file ownership validation when UploadFile not found"""
file_id = str(uuid.uuid4())
app_id = str(uuid.uuid4())
@ -151,7 +153,7 @@ class TestFilePreviewApi:
assert "Upload file record not found" in str(exc_info.value)
def test_validate_file_ownership_tenant_mismatch(
self, file_preview_api, mock_app, mock_upload_file, mock_message_file, mock_message
self, file_preview_api: FilePreviewApi, mock_app, mock_upload_file, mock_message_file, mock_message
):
"""Test file ownership validation with tenant mismatch"""
file_id = str(uuid.uuid4())
@ -182,7 +184,7 @@ class TestFilePreviewApi:
assert "tenant mismatch" in str(exc_info.value)
def test_validate_file_ownership_invalid_input(self, file_preview_api):
def test_validate_file_ownership_invalid_input(self, file_preview_api: FilePreviewApi):
"""Test file ownership validation with invalid input"""
# Test with empty file_id
@ -195,7 +197,7 @@ class TestFilePreviewApi:
file_preview_api._validate_file_ownership("file_id", "")
assert "Invalid file or app identifier" in str(exc_info.value)
def test_build_file_response_basic(self, file_preview_api, mock_upload_file):
def test_build_file_response_basic(self, file_preview_api: FilePreviewApi, mock_upload_file):
"""Test basic file response building"""
mock_generator = Mock()
@ -207,7 +209,7 @@ class TestFilePreviewApi:
assert response.headers["Content-Length"] == str(mock_upload_file.size)
assert "Cache-Control" in response.headers
def test_build_file_response_as_attachment(self, file_preview_api, mock_upload_file):
def test_build_file_response_as_attachment(self, file_preview_api: FilePreviewApi, mock_upload_file):
"""Test file response building with attachment flag"""
mock_generator = Mock()
@ -218,7 +220,7 @@ class TestFilePreviewApi:
assert mock_upload_file.name in response.headers["Content-Disposition"]
assert response.headers["Content-Type"] == "application/octet-stream"
def test_build_file_response_html_forces_attachment(self, file_preview_api, mock_upload_file):
def test_build_file_response_html_forces_attachment(self, file_preview_api: FilePreviewApi, mock_upload_file):
"""Test HTML files are forced to download"""
mock_generator = Mock()
mock_upload_file.mime_type = "text/html"
@ -231,7 +233,7 @@ class TestFilePreviewApi:
assert response.headers["Content-Type"] == "application/octet-stream"
assert response.headers["X-Content-Type-Options"] == "nosniff"
def test_build_file_response_audio_video(self, file_preview_api, mock_upload_file):
def test_build_file_response_audio_video(self, file_preview_api: FilePreviewApi, mock_upload_file):
"""Test file response building for audio/video files"""
mock_generator = Mock()
mock_upload_file.mime_type = "video/mp4"
@ -241,7 +243,7 @@ class TestFilePreviewApi:
# Check Range support for media files
assert response.headers["Accept-Ranges"] == "bytes"
def test_build_file_response_no_size(self, file_preview_api, mock_upload_file):
def test_build_file_response_no_size(self, file_preview_api: FilePreviewApi, mock_upload_file):
"""Test file response building when size is unknown"""
mock_generator = Mock()
mock_upload_file.size = 0 # Unknown size
@ -253,7 +255,14 @@ class TestFilePreviewApi:
@patch("controllers.service_api.app.file_preview.storage")
def test_get_method_integration(
self, mock_storage, file_preview_api, mock_app, mock_end_user, mock_upload_file, mock_message_file, mock_message
self,
mock_storage,
file_preview_api: FilePreviewApi,
mock_app,
mock_end_user,
mock_upload_file,
mock_message_file,
mock_message,
):
"""Test the full GET method integration (without decorator)"""
file_id = str(uuid.uuid4())
@ -295,7 +304,13 @@ class TestFilePreviewApi:
@patch("controllers.service_api.app.file_preview.storage")
def test_storage_error_handling(
self, mock_storage, file_preview_api, mock_app, mock_upload_file, mock_message_file, mock_message
self,
mock_storage,
file_preview_api: FilePreviewApi,
mock_app,
mock_upload_file,
mock_message_file,
mock_message,
):
"""Test storage error handling in the core logic"""
file_id = str(uuid.uuid4())
@ -334,7 +349,7 @@ class TestFilePreviewApi:
assert "Storage error" in str(exc_info.value)
@patch("controllers.service_api.app.file_preview.logger")
def test_validate_file_ownership_unexpected_error_logging(self, mock_logger, file_preview_api):
def test_validate_file_ownership_unexpected_error_logging(self, mock_logger, file_preview_api: FilePreviewApi):
"""Test that unexpected errors are logged properly"""
file_id = str(uuid.uuid4())
app_id = str(uuid.uuid4())

View File

@ -249,7 +249,9 @@ def _build_resumption_context(task_id: str) -> WorkflowResumptionContext:
class TestHitlServiceApi:
# Service API event-stream continuation
def test_workflow_events_continue_on_pause_keeps_stream_open(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_workflow_events_continue_on_pause_keeps_stream_open(
self, app: Flask, monkeypatch: pytest.MonkeyPatch
) -> None:
workflow_run = SimpleNamespace(
id="run-1",
app_id="app-1",

View File

@ -9,6 +9,7 @@ from types import SimpleNamespace
from unittest.mock import Mock
import pytest
from flask import Flask
from werkzeug.exceptions import NotFound
from controllers.service_api.app.human_input_form import WorkflowHumanInputFormApi
@ -17,7 +18,7 @@ from tests.unit_tests.controllers.service_api.conftest import _unwrap
class TestWorkflowHumanInputFormApi:
def test_get_success(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_get_success(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
definition = SimpleNamespace(
model_dump=lambda: {
"rendered_content": "Rendered form content",
@ -57,7 +58,7 @@ class TestWorkflowHumanInputFormApi:
service_mock.get_form_by_token.assert_called_once_with("token-1")
service_mock.ensure_form_active.assert_called_once_with(form)
def test_get_form_not_in_app(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_get_form_not_in_app(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
form = SimpleNamespace(
app_id="another-app",
tenant_id="tenant-1",
@ -87,7 +88,7 @@ class TestWorkflowHumanInputFormApi:
],
)
def test_get_rejects_non_service_api_recipient_types(
self, app, monkeypatch: pytest.MonkeyPatch, recipient_type: RecipientType
self, app: Flask, monkeypatch: pytest.MonkeyPatch, recipient_type: RecipientType
) -> None:
form = SimpleNamespace(
app_id="app-1",
@ -111,7 +112,7 @@ class TestWorkflowHumanInputFormApi:
service_mock.ensure_form_active.assert_not_called()
def test_post_success(self, app, monkeypatch: pytest.MonkeyPatch) -> None:
def test_post_success(self, app: Flask, monkeypatch: pytest.MonkeyPatch) -> None:
form = SimpleNamespace(
app_id="app-1",
tenant_id="tenant-1",
@ -155,7 +156,7 @@ class TestWorkflowHumanInputFormApi:
],
)
def test_post_rejects_non_service_api_recipient_types(
self, app, monkeypatch: pytest.MonkeyPatch, recipient_type: RecipientType
self, app: Flask, monkeypatch: pytest.MonkeyPatch, recipient_type: RecipientType
) -> None:
form = SimpleNamespace(
app_id="app-1",

View File

@ -381,7 +381,7 @@ class TestMessageService:
class TestMessageListApi:
def test_not_chat_app(self, app) -> None:
def test_not_chat_app(self, app: Flask) -> None:
api = MessageListApi()
handler = _unwrap(api.get)
app_model = SimpleNamespace(mode=AppMode.COMPLETION.value)
@ -467,7 +467,7 @@ class TestAppGetFeedbacksApi:
class TestMessageSuggestedApi:
def test_not_chat(self, app) -> None:
def test_not_chat(self, app: Flask) -> None:
api = MessageSuggestedApi()
handler = _unwrap(api.get)
app_model = SimpleNamespace(mode=AppMode.COMPLETION.value)

View File

@ -32,7 +32,7 @@ def _mock_repo_for_run(monkeypatch: pytest.MonkeyPatch, workflow_run):
class TestWorkflowEventsApi:
def test_wrong_app_mode(self, app) -> None:
def test_wrong_app_mode(self, app: Flask) -> None:
api = WorkflowEventsApi()
handler = _unwrap(api.get)
app_model = SimpleNamespace(mode=AppMode.CHAT.value)

View File

@ -19,6 +19,7 @@ import uuid
from unittest.mock import Mock, patch
import pytest
from flask import Flask
from werkzeug.exceptions import Forbidden, NotFound
from controllers.service_api.dataset.document import (
@ -550,7 +551,7 @@ class TestDocumentApiGet:
@patch("controllers.service_api.dataset.document.DatasetService")
@patch("controllers.service_api.dataset.document.DocumentService")
def test_get_document_success_with_all_metadata(
self, mock_doc_svc, mock_dataset_svc, app, mock_tenant, mock_doc_detail
self, mock_doc_svc, mock_dataset_svc, app: Flask, mock_tenant, mock_doc_detail
):
"""Test successful document retrieval with metadata='all'."""
# Arrange
@ -579,7 +580,7 @@ class TestDocumentApiGet:
assert "doc_metadata" in response
@patch("controllers.service_api.dataset.document.DocumentService")
def test_get_document_not_found(self, mock_doc_svc, app, mock_tenant):
def test_get_document_not_found(self, mock_doc_svc, app: Flask, mock_tenant):
"""Test 404 when document is not found."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -599,7 +600,7 @@ class TestDocumentApiGet:
api.get(tenant_id=mock_tenant.id, dataset_id=dataset_id, document_id="nonexistent")
@patch("controllers.service_api.dataset.document.DocumentService")
def test_get_document_forbidden_wrong_tenant(self, mock_doc_svc, app, mock_tenant, mock_doc_detail):
def test_get_document_forbidden_wrong_tenant(self, mock_doc_svc, app: Flask, mock_tenant, mock_doc_detail):
"""Test 403 when document tenant doesn't match request tenant."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -620,7 +621,7 @@ class TestDocumentApiGet:
api.get(tenant_id=mock_tenant.id, dataset_id=dataset_id, document_id=mock_doc_detail.id)
@patch("controllers.service_api.dataset.document.DocumentService")
def test_get_document_metadata_only(self, mock_doc_svc, app, mock_tenant, mock_doc_detail):
def test_get_document_metadata_only(self, mock_doc_svc, app: Flask, mock_tenant, mock_doc_detail):
"""Test document retrieval with metadata='only'."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -647,7 +648,9 @@ class TestDocumentApiGet:
@patch("controllers.service_api.dataset.document.DatasetService")
@patch("controllers.service_api.dataset.document.DocumentService")
def test_get_document_metadata_without(self, mock_doc_svc, mock_dataset_svc, app, mock_tenant, mock_doc_detail):
def test_get_document_metadata_without(
self, mock_doc_svc, mock_dataset_svc, app: Flask, mock_tenant, mock_doc_detail
):
"""Test document retrieval with metadata='without'."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -674,7 +677,7 @@ class TestDocumentApiGet:
assert "name" in response
@patch("controllers.service_api.dataset.document.DocumentService")
def test_get_document_invalid_metadata_value(self, mock_doc_svc, app, mock_tenant, mock_doc_detail):
def test_get_document_invalid_metadata_value(self, mock_doc_svc, app: Flask, mock_tenant, mock_doc_detail):
"""Test error when metadata parameter has invalid value."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -713,7 +716,7 @@ class TestDocumentApiDelete:
@patch("controllers.service_api.dataset.document.DocumentService")
@patch("controllers.service_api.dataset.document.db")
def test_delete_document_success(self, mock_db, mock_doc_svc, app, mock_tenant, mock_document):
def test_delete_document_success(self, mock_db, mock_doc_svc, app: Flask, mock_tenant, mock_document):
"""Test successful document deletion."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -741,7 +744,7 @@ class TestDocumentApiDelete:
@patch("controllers.service_api.dataset.document.DocumentService")
@patch("controllers.service_api.dataset.document.db")
def test_delete_document_not_found(self, mock_db, mock_doc_svc, app, mock_tenant):
def test_delete_document_not_found(self, mock_db, mock_doc_svc, app: Flask, mock_tenant):
"""Test 404 when document not found."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -763,7 +766,7 @@ class TestDocumentApiDelete:
@patch("controllers.service_api.dataset.document.DocumentService")
@patch("controllers.service_api.dataset.document.db")
def test_delete_document_archived_forbidden(self, mock_db, mock_doc_svc, app, mock_tenant, mock_document):
def test_delete_document_archived_forbidden(self, mock_db, mock_doc_svc, app: Flask, mock_tenant, mock_document):
"""Test ArchivedDocumentImmutableError when deleting archived document."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -785,7 +788,7 @@ class TestDocumentApiDelete:
@patch("controllers.service_api.dataset.document.DocumentService")
@patch("controllers.service_api.dataset.document.db")
def test_delete_document_dataset_not_found(self, mock_db, mock_doc_svc, app, mock_tenant):
def test_delete_document_dataset_not_found(self, mock_db, mock_doc_svc, app: Flask, mock_tenant):
"""Test ValueError when dataset not found."""
# Arrange
dataset_id = str(uuid.uuid4())
@ -808,7 +811,7 @@ class TestDocumentListApi:
@patch("controllers.service_api.dataset.document.marshal")
@patch("controllers.service_api.dataset.document.DocumentService")
@patch("controllers.service_api.dataset.document.db")
def test_list_documents_success(self, mock_db, mock_doc_svc, mock_marshal, app, mock_tenant, mock_dataset):
def test_list_documents_success(self, mock_db, mock_doc_svc, mock_marshal, app: Flask, mock_tenant, mock_dataset):
"""Test successful document list retrieval."""
# Arrange
mock_db.session.scalar.return_value = mock_dataset
@ -837,7 +840,7 @@ class TestDocumentListApi:
assert response["total"] == 2
@patch("controllers.service_api.dataset.document.db")
def test_list_documents_dataset_not_found(self, mock_db, app, mock_tenant, mock_dataset):
def test_list_documents_dataset_not_found(self, mock_db, app: Flask, mock_tenant, mock_dataset):
"""Test 404 when dataset not found."""
# Arrange
mock_db.session.scalar.return_value = None
@ -858,7 +861,9 @@ class TestDocumentIndexingStatusApi:
@patch("controllers.service_api.dataset.document.marshal")
@patch("controllers.service_api.dataset.document.DocumentService")
@patch("controllers.service_api.dataset.document.db")
def test_get_indexing_status_success(self, mock_db, mock_doc_svc, mock_marshal, app, mock_tenant, mock_dataset):
def test_get_indexing_status_success(
self, mock_db, mock_doc_svc, mock_marshal, app: Flask, mock_tenant, mock_dataset
):
"""Test successful indexing status retrieval."""
# Arrange
batch_id = "batch_123"
@ -894,7 +899,7 @@ class TestDocumentIndexingStatusApi:
assert len(response["data"]) == 1
@patch("controllers.service_api.dataset.document.db")
def test_get_indexing_status_dataset_not_found(self, mock_db, app, mock_tenant, mock_dataset):
def test_get_indexing_status_dataset_not_found(self, mock_db, app: Flask, mock_tenant, mock_dataset):
"""Test 404 when dataset not found."""
# Arrange
batch_id = "batch_123"
@ -911,7 +916,9 @@ class TestDocumentIndexingStatusApi:
@patch("controllers.service_api.dataset.document.DocumentService")
@patch("controllers.service_api.dataset.document.db")
def test_get_indexing_status_documents_not_found(self, mock_db, mock_doc_svc, app, mock_tenant, mock_dataset):
def test_get_indexing_status_documents_not_found(
self, mock_db, mock_doc_svc, app: Flask, mock_tenant, mock_dataset
):
"""Test 404 when no documents found for batch."""
# Arrange
batch_id = "batch_empty"
@ -978,7 +985,7 @@ class TestDocumentAddByTextApi:
mock_knowledge_config,
mock_doc_svc,
mock_marshal,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1029,7 +1036,7 @@ class TestDocumentAddByTextApi:
@patch("controllers.service_api.wraps.validate_and_get_api_token")
@patch("controllers.service_api.dataset.document.db")
def test_create_document_dataset_not_found(
self, mock_db, mock_validate_token, mock_feature_svc, app, mock_tenant, mock_dataset
self, mock_db, mock_validate_token, mock_feature_svc, app: Flask, mock_tenant, mock_dataset
):
"""Test ValueError when dataset not found."""
# Arrange — neutralise billing decorators
@ -1052,7 +1059,7 @@ class TestDocumentAddByTextApi:
@patch("controllers.service_api.wraps.validate_and_get_api_token")
@patch("controllers.service_api.dataset.document.db")
def test_create_document_missing_indexing_technique(
self, mock_db, mock_validate_token, mock_feature_svc, app, mock_tenant, mock_dataset
self, mock_db, mock_validate_token, mock_feature_svc, app: Flask, mock_tenant, mock_dataset
):
"""Test error when both dataset and payload lack indexing_technique.
@ -1161,7 +1168,7 @@ class TestDocumentUpdateByTextApiPost:
mock_file_svc_cls,
mock_doc_svc,
mock_marshal,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1206,7 +1213,7 @@ class TestDocumentUpdateByTextApiPost:
mock_validate_token,
mock_feature_svc,
mock_db,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1245,7 +1252,7 @@ class TestDocumentAddByFileApiPost:
mock_validate_token,
mock_feature_svc,
mock_db,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1275,7 +1282,7 @@ class TestDocumentAddByFileApiPost:
mock_validate_token,
mock_feature_svc,
mock_db,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1306,7 +1313,7 @@ class TestDocumentAddByFileApiPost:
mock_validate_token,
mock_feature_svc,
mock_db,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1338,7 +1345,7 @@ class TestDocumentAddByFileApiPost:
mock_validate_token,
mock_feature_svc,
mock_db,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1381,7 +1388,7 @@ class TestDocumentUpdateByFileApiPatch:
mock_feature_svc,
mock_update_document_by_file,
route_name,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1418,7 +1425,7 @@ class TestDocumentUpdateByFileApiPatch:
mock_validate_token,
mock_feature_svc,
mock_db,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1453,7 +1460,7 @@ class TestDocumentUpdateByFileApiPatch:
mock_validate_token,
mock_feature_svc,
mock_db,
app,
app: Flask,
mock_tenant,
mock_dataset,
):
@ -1497,7 +1504,7 @@ class TestDocumentUpdateByFileApiPatch:
mock_file_svc_cls,
mock_doc_svc,
mock_marshal,
app,
app: Flask,
mock_tenant,
mock_dataset,
):

View File

@ -18,6 +18,7 @@ import uuid
from unittest.mock import Mock, patch
import pytest
from flask import Flask
from werkzeug.exceptions import Forbidden, NotFound
import services
@ -91,7 +92,7 @@ class TestHitTestingApiPost:
mock_hit_svc,
mock_marshal,
mock_ns,
app,
app: Flask,
):
"""Test successful hit testing request."""
dataset_id = str(uuid.uuid4())
@ -129,7 +130,7 @@ class TestHitTestingApiPost:
mock_hit_svc,
mock_marshal,
mock_ns,
app,
app: Flask,
):
"""Test hit testing with custom retrieval model."""
dataset_id = str(uuid.uuid4())
@ -183,7 +184,7 @@ class TestHitTestingApiPost:
mock_hit_svc,
mock_marshal,
mock_ns,
app,
app: Flask,
):
"""Service API retrieval payload should not drop metadata filters."""
dataset_id = str(uuid.uuid4())
@ -239,7 +240,7 @@ class TestHitTestingApiPost:
mock_hit_svc,
mock_marshal,
mock_ns,
app,
app: Flask,
):
"""Test service API prepares nullable list fields from marshalled records."""
dataset_id = str(uuid.uuid4())
@ -286,7 +287,7 @@ class TestHitTestingApiPost:
mock_current_user,
mock_dataset_svc,
mock_ns,
app,
app: Flask,
):
"""Test hit testing with non-existent dataset."""
dataset_id = str(uuid.uuid4())
@ -308,7 +309,7 @@ class TestHitTestingApiPost:
mock_current_user,
mock_dataset_svc,
mock_ns,
app,
app: Flask,
):
"""Test hit testing when user lacks dataset permission."""
dataset_id = str(uuid.uuid4())

View File

@ -54,7 +54,7 @@ class TestIndexApi:
assert isinstance(response["server_version"], str)
@pytest.mark.parametrize("version", ["0.0.1", "1.0.0", "2.0.0-beta", "1.11.4"])
def test_get_returns_correct_version(self, app, version):
def test_get_returns_correct_version(self, app: Flask, version):
"""Test that server_version matches config version."""
# Arrange
mock_config = MagicMock()

View File

@ -44,7 +44,7 @@ class TestEmailCodeLoginSendEmailApi:
self,
mock_get_user,
mock_send_email,
app,
app: Flask,
):
mock_account = MagicMock()
mock_get_user.return_value = mock_account
@ -75,7 +75,7 @@ class TestEmailCodeLoginApi:
mock_get_user,
mock_login,
mock_reset_login_rate,
app,
app: Flask,
):
mock_get_token_data.return_value = {"email": "User@Example.com", "code": "123456"}
mock_get_user.return_value = MagicMock()

View File

@ -8,14 +8,14 @@
Snapshot generated from `packages/contracts/generated/api/readiness.json` after running `pnpm -C packages/contracts gen-api-contract-from-openapi`.
Are we OpenAPI ready? **No.** Current generated API contracts are **16.6% ready**.
Are we OpenAPI ready? **No.** Current generated API contracts are **16.7% ready**.
| Surface | Ready | Not ready | Total | Ready % |
| --------- | ------: | --------: | ------: | --------: |
| console | 95 | 475 | 570 | 16.7% |
| console | 96 | 474 | 570 | 16.8% |
| service | 16 | 72 | 88 | 18.2% |
| web | 5 | 36 | 41 | 12.2% |
| **total** | **116** | **583** | **699** | **16.6%** |
| **total** | **117** | **582** | **699** | **16.7%** |
Readiness here means the generated contract operation is not marked with:

View File

@ -426,16 +426,10 @@ export const imports = {
/**
* Get workflow online users
*
* Generated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.
*
* @deprecated
*/
export const post3 = oc
.route({
deprecated: true,
description:
'Get workflow online users\n\nGenerated contract types may be inaccurate because backend OpenAPI annotations are incomplete. Do not migrate callers until the generated contract is accurate.',
description: 'Get workflow online users',
inputStructure: 'detailed',
method: 'POST',
operationId: 'postAppsWorkflowsOnlineUsers',

View File

@ -1,7 +1,7 @@
{
"surfaces": {
"console": {
"notReady": 475,
"notReady": 474,
"total": 570
},
"service": {