From 5de823eab9b68400836e8d50a8b9c664e021edbd Mon Sep 17 00:00:00 2001 From: Lynn Date: Thu, 9 Jul 2026 17:48:02 +0800 Subject: [PATCH] Fix: delete unused tenant_llm testcase (#16786) --- .../restful_api/test_llm_routes_unit.py | 740 ------------------ 1 file changed, 740 deletions(-) delete mode 100644 test/testcases/restful_api/test_llm_routes_unit.py diff --git a/test/testcases/restful_api/test_llm_routes_unit.py b/test/testcases/restful_api/test_llm_routes_unit.py deleted file mode 100644 index fc4f91d54..000000000 --- a/test/testcases/restful_api/test_llm_routes_unit.py +++ /dev/null @@ -1,740 +0,0 @@ -# -# Copyright 2026 The InfiniFlow Authors. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import asyncio -import importlib.util -import json -import sys -from pathlib import Path -from types import ModuleType, SimpleNamespace - -import pytest -import requests - -from configs import HOST_ADDRESS, VERSION -from test.testcases.conftest import login -from test.testcases.libs.auth import RAGFlowWebApiAuth - - -class _DummyManager: - def route(self, *_args, **_kwargs): - def decorator(func): - return func - - return decorator - - -class _ExprField: - def __init__(self, name): - self.name = name - - def __eq__(self, other): - return (self.name, other) - - -class _StrEnum(str): - @property - def value(self): - return str(self) - - -class _DummyTenantLLMModel: - tenant_id = _ExprField("tenant_id") - llm_factory = _ExprField("llm_factory") - llm_name = _ExprField("llm_name") - - def __init__(self, id=None, **kwargs): - self.id = id - self.api_key = None - self.status = None - for key, value in kwargs.items(): - setattr(self, key, value) - - -class _TenantLLMRow: - def __init__( - self, - *, - id, - llm_name, - llm_factory, - model_type, - api_key="key", - status="1", - used_tokens=0, - api_base="", - max_tokens=8192, - ): - self.id = id - self.llm_name = llm_name - self.llm_factory = llm_factory - self.model_type = model_type - self.api_key = api_key - self.status = status - self.used_tokens = used_tokens - self.api_base = api_base - self.max_tokens = max_tokens - - def to_dict(self): - return { - "id": self.id, - "llm_name": self.llm_name, - "llm_factory": self.llm_factory, - "model_type": self.model_type, - "status": self.status, - "used_tokens": self.used_tokens, - "api_base": self.api_base, - "max_tokens": self.max_tokens, - } - - -class _LLMRow: - def __init__(self, *, llm_name, fid, model_type, status="1", max_tokens=2048): - self.llm_name = llm_name - self.fid = fid - self.model_type = model_type - self.status = status - self.max_tokens = max_tokens - - def to_dict(self): - return { - "llm_name": self.llm_name, - "fid": self.fid, - "model_type": self.model_type, - "status": self.status, - "max_tokens": self.max_tokens, - } - - -def _run(coro): - return asyncio.run(coro) - - -def _set_request_json(monkeypatch, module, payload): - async def _get_request_json(): - return dict(payload) - - monkeypatch.setattr(module, "get_request_json", _get_request_json) - - -def _load_llm_app(monkeypatch): - repo_root = Path(__file__).resolve().parents[3] - - quart_mod = ModuleType("quart") - quart_mod.request = SimpleNamespace(args={}) - monkeypatch.setitem(sys.modules, "quart", quart_mod) - - apps_mod = ModuleType("api.apps") - apps_mod.__path__ = [str(repo_root / "api" / "apps")] - apps_mod.login_required = lambda fn: fn - apps_mod.current_user = SimpleNamespace(id="tenant-1") - monkeypatch.setitem(sys.modules, "api.apps", apps_mod) - - tenant_llm_mod = ModuleType("api.db.services.tenant_llm_service") - - class _StubLLMFactoriesService: - @staticmethod - def query(**_kwargs): - return [] - - class _StubTenantLLMService: - @staticmethod - def ensure_mineru_from_env(_tenant_id): - return None - - @staticmethod - def ensure_opendataloader_from_env(_tenant_id): - return None - - @staticmethod - def query(**_kwargs): - return [] - - @staticmethod - def get_my_llms(_tenant_id): - return [] - - @staticmethod - def save(**_kwargs): - return True - - @staticmethod - def filter_delete(_filters): - return True - - @staticmethod - def filter_update(_filters, _payload): - return True - - tenant_llm_mod.LLMFactoriesService = _StubLLMFactoriesService - tenant_llm_mod.TenantLLMService = _StubTenantLLMService - monkeypatch.setitem(sys.modules, "api.db.services.tenant_llm_service", tenant_llm_mod) - - llm_service_mod = ModuleType("api.db.services.llm_service") - - class _StubLLMService: - @staticmethod - def get_all(): - return [] - - @staticmethod - def query(**_kwargs): - return [] - - llm_service_mod.LLMService = _StubLLMService - monkeypatch.setitem(sys.modules, "api.db.services.llm_service", llm_service_mod) - - api_utils_mod = ModuleType("api.utils.api_utils") - api_utils_mod.get_allowed_llm_factories = lambda: [] - api_utils_mod.get_data_error_result = lambda message="", code=400, data=None: { - "code": code, - "message": message, - "data": data, - } - api_utils_mod.get_json_result = lambda data=None, message="", code=0: { - "code": code, - "message": message, - "data": data, - } - - async def _get_request_json(): - return {} - - api_utils_mod.get_request_json = _get_request_json - api_utils_mod.server_error_response = lambda exc: {"code": 500, "message": str(exc), "data": None} - api_utils_mod.validate_request = lambda *_args, **_kwargs: lambda fn: fn - monkeypatch.setitem(sys.modules, "api.utils.api_utils", api_utils_mod) - - constants_mod = ModuleType("common.constants") - constants_mod.StatusEnum = SimpleNamespace(VALID=SimpleNamespace(value="1"), INVALID=SimpleNamespace(value="0")) - constants_mod.LLMType = SimpleNamespace( - CHAT=_StrEnum("chat"), - EMBEDDING=_StrEnum("embedding"), - SPEECH2TEXT=_StrEnum("speech2text"), - IMAGE2TEXT=_StrEnum("image2text"), - RERANK=_StrEnum("rerank"), - TTS=_StrEnum("tts"), - OCR=_StrEnum("ocr"), - ) - monkeypatch.setitem(sys.modules, "common.constants", constants_mod) - - db_models_mod = ModuleType("api.db.db_models") - db_models_mod.TenantLLM = _DummyTenantLLMModel - monkeypatch.setitem(sys.modules, "api.db.db_models", db_models_mod) - - base64_mod = ModuleType("rag.utils.base64_image") - base64_mod.test_image = b"image-bytes" - monkeypatch.setitem(sys.modules, "rag.utils.base64_image", base64_mod) - - rag_llm_mod = ModuleType("rag.llm") - rag_llm_mod.EmbeddingModel = {} - rag_llm_mod.ChatModel = {} - rag_llm_mod.RerankModel = {} - rag_llm_mod.CvModel = {} - rag_llm_mod.TTSModel = {} - rag_llm_mod.OcrModel = {} - rag_llm_mod.Seq2txtModel = {} - monkeypatch.setitem(sys.modules, "rag.llm", rag_llm_mod) - - module_path = repo_root / "api" / "apps" / "llm_app.py" - spec = importlib.util.spec_from_file_location("test_llm_routes_unit_module", module_path) - module = importlib.util.module_from_spec(spec) - module.manager = _DummyManager() - spec.loader.exec_module(module) - return module - - -def _rag_llm_module(): - return sys.modules["rag.llm"] - - -@pytest.mark.p2 -def test_llm_list_app_grouping_availability_and_merge(monkeypatch): - module = _load_llm_app(monkeypatch) - - ensure_calls = [] - monkeypatch.setattr(module.TenantLLMService, "ensure_mineru_from_env", lambda tenant_id: ensure_calls.append(tenant_id)) - - tenant_rows = [ - _TenantLLMRow(id=1, llm_name="fast-emb", llm_factory="FastEmbed", model_type="embedding", api_key="k1", status="1"), - _TenantLLMRow(id=2, llm_name="tenant-only", llm_factory="CustomFactory", model_type="chat", api_key="k2", status="1"), - _TenantLLMRow(id=3, llm_name="gpt-5.5", llm_factory="OpenAI", model_type="chat", api_key="k3", status="1"), - _TenantLLMRow(id=4, llm_name="gpt-5.4", llm_factory="OpenAI", model_type="chat", api_key="k4", status="1"), - ] - monkeypatch.setattr(module.TenantLLMService, "query", lambda **_kwargs: tenant_rows) - - all_llms = [ - _LLMRow(llm_name="tei-embed", fid="Builtin", model_type="embedding", status="1"), - _LLMRow(llm_name="fast-emb", fid="FastEmbed", model_type="embedding", status="1"), - _LLMRow(llm_name="gpt-5.5", fid="OpenAI", model_type="chat", status="1"), - _LLMRow(llm_name="gpt-5.4", fid="OpenAI", model_type="chat", status="1"), - _LLMRow(llm_name="not-in-status", fid="Other", model_type="chat", status="1"), - ] - monkeypatch.setattr(module.LLMService, "get_all", lambda: all_llms) - - monkeypatch.setattr(module, "request", SimpleNamespace(args={})) - monkeypatch.setenv("COMPOSE_PROFILES", "tei-cpu") - monkeypatch.setenv("TEI_MODEL", "tei-embed") - - res = _run(module.list_app()) - assert res["code"] == 0, res["message"] - assert ensure_calls == ["tenant-1"] - - data = res["data"] - assert {"Builtin", "FastEmbed", "CustomFactory", "OpenAI"}.issubset(set(data.keys())) - assert data["Builtin"][0]["llm_name"] == "tei-embed" - assert data["Builtin"][0]["available"] is True - assert data["FastEmbed"][0]["llm_name"] == "fast-emb" - assert data["FastEmbed"][0]["available"] is True - assert data["CustomFactory"][0]["llm_name"] == "tenant-only" - assert data["CustomFactory"][0]["available"] is True - openai_names = {item["llm_name"] for item in data["OpenAI"]} - assert {"gpt-5.5", "gpt-5.4"}.issubset(openai_names) - - -@pytest.mark.p2 -def test_llm_list_app_model_type_filter(monkeypatch): - module = _load_llm_app(monkeypatch) - - monkeypatch.setattr(module.TenantLLMService, "ensure_mineru_from_env", lambda _tenant_id: None) - monkeypatch.setattr( - module.TenantLLMService, - "query", - lambda **_kwargs: [ - _TenantLLMRow(id=1, llm_name="fast-emb", llm_factory="FastEmbed", model_type="embedding", api_key="k1", status="1"), - _TenantLLMRow(id=2, llm_name="tenant-only", llm_factory="CustomFactory", model_type="chat", api_key="k2", status="1"), - ], - ) - monkeypatch.setattr( - module.LLMService, - "get_all", - lambda: [ - _LLMRow(llm_name="tei-embed", fid="Builtin", model_type="embedding", status="1"), - _LLMRow(llm_name="fast-emb", fid="FastEmbed", model_type="embedding", status="1"), - ], - ) - - monkeypatch.setattr(module, "request", SimpleNamespace(args={"model_type": "chat"})) - res = _run(module.list_app()) - assert res["code"] == 0, res["message"] - assert list(res["data"].keys()) == ["CustomFactory"] - assert res["data"]["CustomFactory"][0]["model_type"] == "chat" - - -@pytest.mark.p2 -def test_llm_list_app_exception_path(monkeypatch): - module = _load_llm_app(monkeypatch) - - monkeypatch.setattr(module, "request", SimpleNamespace(args={})) - monkeypatch.setattr(module.TenantLLMService, "ensure_mineru_from_env", lambda _tenant_id: None) - monkeypatch.setattr( - module.TenantLLMService, - "query", - lambda **_kwargs: (_ for _ in ()).throw(RuntimeError("query boom")), - ) - - res = _run(module.list_app()) - assert res["code"] == 500 - assert "query boom" in res["message"] - - -@pytest.mark.p2 -def test_llm_factories_route_success_and_exception_unit(monkeypatch): - module = _load_llm_app(monkeypatch) - - def _factory(name): - return SimpleNamespace(name=name, to_dict=lambda n=name: {"name": n}) - - monkeypatch.setattr( - module, - "get_allowed_llm_factories", - lambda: [ - _factory("OpenAI"), - _factory("CustomFactory"), - _factory("FastEmbed"), - _factory("Builtin"), - ], - ) - monkeypatch.setattr( - module.LLMService, - "get_all", - lambda: [ - _LLMRow(llm_name="m1", fid="OpenAI", model_type="chat", status="1"), - _LLMRow(llm_name="m2", fid="OpenAI", model_type="embedding", status="1"), - _LLMRow(llm_name="m3", fid="OpenAI", model_type="rerank", status="0"), - ], - ) - res = module.factories() - assert res["code"] == 0 - names = [item["name"] for item in res["data"]] - assert "FastEmbed" not in names - assert "Builtin" not in names - assert {"OpenAI", "CustomFactory"} == set(names) - openai = next(item for item in res["data"] if item["name"] == "OpenAI") - assert {"chat", "embedding"} == set(openai["model_types"]) - - monkeypatch.setattr(module, "get_allowed_llm_factories", lambda: (_ for _ in ()).throw(RuntimeError("factories boom"))) - res = module.factories() - assert res["code"] == 500 - assert "factories boom" in res["message"] - - -@pytest.mark.p2 -def test_add_llm_factory_specific_key_assembly_unit(monkeypatch): - module = _load_llm_app(monkeypatch) - - async def _wait_for(coro, *_args, **_kwargs): - return await coro - - async def _to_thread(fn, *args, **kwargs): - return fn(*args, **kwargs) - - monkeypatch.setattr(module.asyncio, "wait_for", _wait_for) - monkeypatch.setattr(module.asyncio, "to_thread", _to_thread) - - allowed = [ - "VolcEngine", - "Tencent Cloud", - "Bedrock", - "LocalAI", - "HuggingFace", - "OpenAI-API-Compatible", - "VLLM", - "XunFei Spark", - "BaiduYiyan", - "Fish Audio", - "Google Cloud", - "Azure-OpenAI", - "OpenRouter", - "MinerU", - "PaddleOCR", - ] - monkeypatch.setattr(module, "get_allowed_llm_factories", lambda: [SimpleNamespace(name=name) for name in allowed]) - - captured = {"filter_payloads": []} - - class _ChatOK: - def __init__(self, *_args, **_kwargs): - pass - - async def async_chat(self, *_args, **_kwargs): - return "ok", 1 - - async def async_chat_streamly(self, *_args, **_kwargs): - yield "ok" - yield 1 - - class _TTSOK: - def __init__(self, *_args, **_kwargs): - pass - - def tts(self, _text): - yield b"ok" - - monkeypatch.setattr(_rag_llm_module(), "ChatModel", {name: _ChatOK for name in allowed}) - monkeypatch.setattr(_rag_llm_module(), "TTSModel", {"XunFei Spark": _TTSOK}) - monkeypatch.setattr(module.TenantLLMService, "filter_update", lambda _filters, payload: captured["filter_payloads"].append(dict(payload)) or True) - - reject_req = {"llm_factory": "NotAllowed", "llm_name": "x", "model_type": module.LLMType.CHAT.value} - _set_request_json(monkeypatch, module, reject_req) - res = _run(module.add_llm()) - assert res["code"] == 400 - assert "is not allowed" in res["message"] - - def _run_case(factory, *, model_type=module.LLMType.CHAT.value, extra=None): - req = {"llm_factory": factory, "llm_name": "model", "model_type": model_type, "api_key": "k", "api_base": "http://api"} - if extra: - req.update(extra) - _set_request_json(monkeypatch, module, req) - out = _run(module.add_llm()) - assert out["code"] == 0 - assert out["data"] is True - return captured["filter_payloads"][-1] - - volc = _run_case("VolcEngine", extra={"ark_api_key": "ak", "endpoint_id": "eid"}) - assert json.loads(volc["api_key"]) == {"ark_api_key": "ak", "endpoint_id": "eid"} - - bedrock = _run_case( - "Bedrock", - extra={"auth_mode": "iam", "bedrock_ak": "ak", "bedrock_sk": "sk", "bedrock_region": "r", "aws_role_arn": "arn"}, - ) - assert json.loads(bedrock["api_key"]) == { - "auth_mode": "iam", - "bedrock_ak": "ak", - "bedrock_sk": "sk", - "bedrock_region": "r", - "aws_role_arn": "arn", - } - - assert _run_case("LocalAI")["llm_name"] == "model___LocalAI" - assert _run_case("HuggingFace")["llm_name"] == "model___HuggingFace" - assert _run_case("OpenAI-API-Compatible")["llm_name"] == "model___OpenAI-API" - assert _run_case("VLLM")["llm_name"] == "model___VLLM" - - spark_chat = _run_case("XunFei Spark", extra={"spark_api_password": "spark-pass"}) - assert spark_chat["api_key"] == "spark-pass" - spark_tts = _run_case( - "XunFei Spark", - model_type=module.LLMType.TTS.value, - extra={"spark_app_id": "app", "spark_api_secret": "secret", "spark_api_key": "key"}, - ) - assert json.loads(spark_tts["api_key"]) == { - "spark_app_id": "app", - "spark_api_secret": "secret", - "spark_api_key": "key", - } - - assert json.loads(_run_case("BaiduYiyan", extra={"yiyan_ak": "ak", "yiyan_sk": "sk"})["api_key"]) == {"yiyan_ak": "ak", "yiyan_sk": "sk"} - assert json.loads(_run_case("Fish Audio", extra={"fish_audio_ak": "ak", "fish_audio_refid": "rid"})["api_key"]) == {"fish_audio_ak": "ak", "fish_audio_refid": "rid"} - assert json.loads(_run_case("Google Cloud", extra={"google_project_id": "pid", "google_region": "us", "google_service_account_key": "sak"})["api_key"]) == { - "google_project_id": "pid", - "google_region": "us", - "google_service_account_key": "sak", - } - assert json.loads(_run_case("Azure-OpenAI", extra={"api_key": "real-key", "api_version": "2024-01-01"})["api_key"]) == { - "api_key": "real-key", - "api_version": "2024-01-01", - } - assert json.loads(_run_case("OpenRouter", extra={"api_key": "or-key", "provider_order": "a,b"})["api_key"]) == { - "api_key": "or-key", - "provider_order": "a,b", - } - assert json.loads(_run_case("MinerU", extra={"api_key": "m-key", "provider_order": "p1"})["api_key"]) == { - "api_key": "m-key", - "provider_order": "p1", - } - assert json.loads(_run_case("PaddleOCR", extra={"api_key": "p-key", "provider_order": "p2"})["api_key"]) == { - "api_key": "p-key", - "provider_order": "p2", - } - - tencent_req = { - "llm_factory": "Tencent Cloud", - "llm_name": "model", - "model_type": module.LLMType.CHAT.value, - "tencent_cloud_sid": "sid", - "tencent_cloud_sk": "sk", - } - - async def _tencent_request_json(): - return tencent_req - - monkeypatch.setattr(module, "get_request_json", _tencent_request_json) - delegated = {} - - async def _fake_set_api_key(): - delegated["api_key"] = tencent_req.get("api_key") - return {"code": 0, "data": "delegated"} - - monkeypatch.setattr(module, "set_api_key", _fake_set_api_key) - res = _run(module.add_llm()) - assert res["code"] == 0 - assert res["data"] == "delegated" - assert json.loads(delegated["api_key"]) == {"tencent_cloud_sid": "sid", "tencent_cloud_sk": "sk"} - - -@pytest.mark.p2 -def test_add_llm_model_type_probe_and_persistence_matrix_unit(monkeypatch): - module = _load_llm_app(monkeypatch) - - async def _wait_for(coro, *_args, **_kwargs): - return await coro - - async def _to_thread(fn, *args, **kwargs): - return fn(*args, **kwargs) - - monkeypatch.setattr(module.asyncio, "wait_for", _wait_for) - monkeypatch.setattr(module.asyncio, "to_thread", _to_thread) - monkeypatch.setattr( - module, - "get_allowed_llm_factories", - lambda: [ - SimpleNamespace(name=name) - for name in [ - "FEmbFail", - "FEmbPass", - "FChatFail", - "FChatPass", - "FRKey", - "FRFail", - "FImgFail", - "FTTSFail", - "FOcrFail", - "FSttFail", - "FUnknown", - ] - ], - ) - - class _EmbeddingFail: - def __init__(self, *_args, **_kwargs): - pass - - def encode(self, _texts): - return [[]], 1 - - class _EmbeddingPass: - def __init__(self, *_args, **_kwargs): - pass - - def encode(self, _texts): - return [[0.5]], 1 - - class _ChatFail: - def __init__(self, *_args, **_kwargs): - pass - - async def async_chat(self, *_args, **_kwargs): - return "**ERROR**: chat failed", 0 - - async def async_chat_streamly(self, *_args, **_kwargs): - yield "**ERROR**: chat failed" - yield 0 - - class _ChatPass: - def __init__(self, *_args, **_kwargs): - pass - - async def async_chat(self, *_args, **_kwargs): - return "ok", 1 - - async def async_chat_streamly(self, *_args, **_kwargs): - yield "ok" - yield 1 - - class _RerankFail: - def __init__(self, *_args, **_kwargs): - pass - - def similarity(self, *_args, **_kwargs): - return [], 1 - - class _CvFail: - def __init__(self, *_args, **_kwargs): - pass - - def describe(self, _image_data): - return "**ERROR**: image failed", 0 - - class _TTSFail: - def __init__(self, *_args, **_kwargs): - pass - - def tts(self, _text): - raise RuntimeError("tts failed") - - class _OcrFail: - def __init__(self, *_args, **_kwargs): - pass - - def __call__(self, _img): - return None - - class _SttFail: - def __init__(self, *_args, **_kwargs): - pass - - def transcribe(self, _audio): - return "", 0 - - rag_llm_mod = _rag_llm_module() - monkeypatch.setattr(rag_llm_mod, "EmbeddingModel", {"FEmbFail": _EmbeddingFail, "FEmbPass": _EmbeddingPass}) - monkeypatch.setattr(rag_llm_mod, "ChatModel", {"FChatFail": _ChatFail, "FChatPass": _ChatPass}) - monkeypatch.setattr(rag_llm_mod, "RerankModel", {"FRFail": _RerankFail, "FRKey": _RerankFail}) - monkeypatch.setattr(rag_llm_mod, "CvModel", {"FImgFail": _CvFail}) - monkeypatch.setattr(rag_llm_mod, "TTSModel", {"FTTSFail": _TTSFail}) - monkeypatch.setattr(rag_llm_mod, "OcrModel", {"FOcrFail": _OcrFail}) - monkeypatch.setattr(rag_llm_mod, "Seq2txtModel", {"FSttFail": _SttFail}) - - saves = [] - monkeypatch.setattr(module.TenantLLMService, "filter_update", lambda _filters, _payload: False) - monkeypatch.setattr(module.TenantLLMService, "save", lambda **kwargs: saves.append(kwargs) or True) - - monkeypatch.setattr( - module.LLMService, - "query", - lambda **kwargs: ( - [] if kwargs.get("llm_factory") == "FUnknown" else [_LLMRow(llm_name="m", fid=kwargs.get("llm_factory"), model_type=kwargs.get("model_type", module.LLMType.CHAT.value), max_tokens=4096)] - ), - ) - - _set_request_json(monkeypatch, module, {"llm_factory": "FUnknown", "llm_name": "m", "model_type": "unknown"}) - with pytest.raises(RuntimeError, match="Unknown model type: unknown"): - _run(module.add_llm()) - - cases = [ - ("FEmbFail", module.LLMType.EMBEDDING.value, 400, None, "embedding model"), - ("FEmbPass", module.LLMType.EMBEDDING.value, 0, True, ""), - ("FChatFail", module.LLMType.CHAT.value, 400, None, "No valid response received"), - ("FChatPass", module.LLMType.CHAT.value, 0, True, ""), - ("FRFail", module.LLMType.RERANK.value, 400, None, "Not known"), - ("FImgFail", module.LLMType.IMAGE2TEXT.value, 400, None, "image failed"), - ("FTTSFail", module.LLMType.TTS.value, 400, None, "tts"), - ("FOcrFail", module.LLMType.OCR.value, 400, None, "ocr"), - ("FSttFail", module.LLMType.SPEECH2TEXT.value, 0, True, ""), - ] - for factory, model_type, expected_code, expected_data, expected_fragment in cases: - _set_request_json(monkeypatch, module, {"llm_factory": factory, "llm_name": "m", "model_type": model_type, "api_key": "key"}) - res = _run(module.add_llm()) - assert res["code"] == expected_code - if expected_data is not None: - assert res["data"] is expected_data - if expected_fragment: - assert expected_fragment.lower() in res["message"].lower() - - assert any(item["llm_factory"] == "FEmbPass" for item in saves) - - -@pytest.mark.p2 -def test_llm_factories_live_auth_contract(): - llm_url = f"{HOST_ADDRESS}/{VERSION}/llm/factories" - invalid_auth_cases = [ - (None, 401, ""), - (RAGFlowWebApiAuth("invalid-token"), 401, ""), - ] - for auth_obj, expected_code, expected_message in invalid_auth_cases: - res = requests.get(llm_url, auth=auth_obj, timeout=30) - assert res.status_code == 401 - payload = res.json() - assert payload["code"] == expected_code, payload - assert payload["message"] == expected_message, payload - - ok_res = requests.get(llm_url, auth=RAGFlowWebApiAuth(login()), timeout=30) - assert ok_res.status_code == 200 - ok_payload = ok_res.json() - assert ok_payload["code"] == 0, ok_payload - assert isinstance(ok_payload["data"], list), ok_payload - - -@pytest.mark.p2 -def test_llm_list_live_auth_contract(): - llm_url = f"{HOST_ADDRESS}/{VERSION}/llm/list" - invalid_auth_cases = [ - (None, 401, ""), - (RAGFlowWebApiAuth("invalid-token"), 401, ""), - ] - for auth_obj, expected_code, expected_message in invalid_auth_cases: - res = requests.get(llm_url, auth=auth_obj, timeout=30) - assert res.status_code == 401 - payload = res.json() - assert payload["code"] == expected_code, payload - assert payload["message"] == expected_message, payload - - ok_res = requests.get(llm_url, auth=RAGFlowWebApiAuth(login()), timeout=30) - assert ok_res.status_code == 200 - ok_payload = ok_res.json() - assert ok_payload["code"] == 0, ok_payload - assert isinstance(ok_payload["data"], dict), ok_payload