Files
startrail-org--leann/tests/test_minimax_provider.py
wehub-resource-sync 15dadb5432
CI / build (push) Has been cancelled
Link Check / link-check (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:38:09 +08:00

232 lines
8.3 KiB
Python

"""
Tests for MiniMax provider integration.
These tests validate MiniMax provider settings, chat class, and factory integration.
We import from leann.settings and leann.chat directly to avoid triggering
the full leann.__init__ import chain which requires C++ backend builds.
"""
import os
import sys
from unittest.mock import MagicMock, patch
import pytest
# Add the leann-core source to sys.path so we can import submodules
# without triggering __init__.py's backend imports.
_LEANN_SRC = os.path.join(os.path.dirname(__file__), "..", "packages", "leann-core", "src")
if _LEANN_SRC not in sys.path:
sys.path.insert(0, os.path.abspath(_LEANN_SRC))
# Prevent leann.__init__ from running its heavy imports by pre-registering
# a lightweight stub in sys.modules (if not already present).
if "leann" not in sys.modules:
import types
_stub = types.ModuleType("leann")
_stub.__path__ = [os.path.join(os.path.abspath(_LEANN_SRC), "leann")]
sys.modules["leann"] = _stub
# Now we can safely import the modules we actually test.
from leann.settings import ( # noqa: E402
resolve_minimax_api_key,
resolve_minimax_base_url,
)
class TestMiniMaxSettings:
"""Test MiniMax settings resolver functions."""
def test_resolve_minimax_api_key_explicit(self):
assert resolve_minimax_api_key("test-key") == "test-key"
def test_resolve_minimax_api_key_from_env(self):
with patch.dict(os.environ, {"MINIMAX_API_KEY": "env-key"}):
assert resolve_minimax_api_key() == "env-key"
def test_resolve_minimax_api_key_none(self):
with patch.dict(os.environ, {}, clear=True):
assert resolve_minimax_api_key() is None
def test_resolve_minimax_base_url_default(self):
with patch.dict(os.environ, {}, clear=True):
assert resolve_minimax_base_url() == "https://api.minimax.io/v1"
def test_resolve_minimax_base_url_explicit(self):
assert resolve_minimax_base_url("https://custom.url/v1") == "https://custom.url/v1"
def test_resolve_minimax_base_url_from_env(self):
with patch.dict(os.environ, {"MINIMAX_BASE_URL": "https://env.url/v1"}):
assert resolve_minimax_base_url() == "https://env.url/v1"
def test_resolve_minimax_base_url_leann_env(self):
with patch.dict(os.environ, {"LEANN_MINIMAX_BASE_URL": "https://leann.url/v1"}):
assert resolve_minimax_base_url() == "https://leann.url/v1"
def test_resolve_minimax_base_url_strips_trailing_slash(self):
assert resolve_minimax_base_url("https://api.minimax.io/v1/") == "https://api.minimax.io/v1"
class TestMiniMaxChat:
"""Test MiniMaxChat class."""
def test_init_requires_api_key(self):
from leann.chat import MiniMaxChat
with patch.dict(os.environ, {}, clear=True):
with pytest.raises(ValueError, match="MiniMax API key is required"):
MiniMaxChat(api_key=None)
@patch("openai.OpenAI")
def test_init_with_api_key(self, mock_openai_cls):
from leann.chat import MiniMaxChat
chat = MiniMaxChat(api_key="test-key")
assert chat.model == "MiniMax-M2.5"
assert chat.api_key == "test-key"
assert chat.base_url == "https://api.minimax.io/v1"
mock_openai_cls.assert_called_once_with(
api_key="test-key", base_url="https://api.minimax.io/v1"
)
@patch("openai.OpenAI")
def test_init_custom_model(self, mock_openai_cls):
from leann.chat import MiniMaxChat
chat = MiniMaxChat(model="MiniMax-M2.5-highspeed", api_key="test-key")
assert chat.model == "MiniMax-M2.5-highspeed"
@patch("openai.OpenAI")
def test_init_custom_base_url(self, mock_openai_cls):
from leann.chat import MiniMaxChat
chat = MiniMaxChat(api_key="test-key", base_url="https://api.minimaxi.com/v1")
assert chat.base_url == "https://api.minimaxi.com/v1"
@patch("openai.OpenAI")
def test_ask_returns_response(self, mock_openai_cls):
from leann.chat import MiniMaxChat
# Mock the response chain
mock_client = MagicMock()
mock_openai_cls.return_value = mock_client
mock_response = MagicMock()
mock_response.choices = [MagicMock()]
mock_response.choices[0].message.content = "Hello from MiniMax!"
mock_response.choices[0].finish_reason = "stop"
mock_response.usage.total_tokens = 100
mock_response.usage.prompt_tokens = 50
mock_response.usage.completion_tokens = 50
mock_client.chat.completions.create.return_value = mock_response
chat = MiniMaxChat(api_key="test-key")
result = chat.ask("Hello")
assert result == "Hello from MiniMax!"
mock_client.chat.completions.create.assert_called_once()
@patch("openai.OpenAI")
def test_ask_with_kwargs(self, mock_openai_cls):
from leann.chat import MiniMaxChat
mock_client = MagicMock()
mock_openai_cls.return_value = mock_client
mock_response = MagicMock()
mock_response.choices = [MagicMock()]
mock_response.choices[0].message.content = "Response"
mock_response.choices[0].finish_reason = "stop"
mock_response.usage.total_tokens = 50
mock_response.usage.prompt_tokens = 25
mock_response.usage.completion_tokens = 25
mock_client.chat.completions.create.return_value = mock_response
chat = MiniMaxChat(api_key="test-key")
chat.ask("Hello", temperature=0.5, max_tokens=500, top_p=0.9)
call_kwargs = mock_client.chat.completions.create.call_args[1]
assert call_kwargs["temperature"] == 0.5
assert call_kwargs["max_tokens"] == 500
assert call_kwargs["top_p"] == 0.9
@patch("openai.OpenAI")
def test_ask_handles_error(self, mock_openai_cls):
from leann.chat import MiniMaxChat
mock_client = MagicMock()
mock_openai_cls.return_value = mock_client
mock_client.chat.completions.create.side_effect = Exception("API error")
chat = MiniMaxChat(api_key="test-key")
result = chat.ask("Hello")
assert "Error" in result
assert "MiniMax" in result
class TestGetLLMFactory:
"""Test get_llm factory function with minimax type."""
@patch("openai.OpenAI")
def test_get_llm_minimax(self, mock_openai_cls):
from leann.chat import MiniMaxChat, get_llm
llm = get_llm({"type": "minimax", "api_key": "test-key"})
assert isinstance(llm, MiniMaxChat)
assert llm.model == "MiniMax-M2.5"
@patch("openai.OpenAI")
def test_get_llm_minimax_custom_model(self, mock_openai_cls):
from leann.chat import MiniMaxChat, get_llm
llm = get_llm({"type": "minimax", "model": "MiniMax-M2.5-highspeed", "api_key": "test-key"})
assert isinstance(llm, MiniMaxChat)
assert llm.model == "MiniMax-M2.5-highspeed"
@patch("openai.OpenAI")
def test_get_llm_minimax_custom_base_url(self, mock_openai_cls):
from leann.chat import MiniMaxChat, get_llm
llm = get_llm(
{
"type": "minimax",
"api_key": "test-key",
"base_url": "https://api.minimaxi.com/v1",
}
)
assert isinstance(llm, MiniMaxChat)
assert llm.base_url == "https://api.minimaxi.com/v1"
@pytest.mark.skipif(
not os.getenv("MINIMAX_API_KEY"),
reason="MINIMAX_API_KEY not set; skipping live API test",
)
class TestMiniMaxLiveAPI:
"""Live API tests for MiniMax provider (requires MINIMAX_API_KEY)."""
def test_minimax_m25_live(self):
from leann.chat import MiniMaxChat
chat = MiniMaxChat(model="MiniMax-M2.5")
response = chat.ask("Say hello in one word.", max_tokens=10)
assert isinstance(response, str)
assert len(response) > 0
def test_minimax_m25_highspeed_live(self):
from leann.chat import MiniMaxChat
chat = MiniMaxChat(model="MiniMax-M2.5-highspeed")
response = chat.ask("Say hello in one word.", max_tokens=10)
assert isinstance(response, str)
assert len(response) > 0
def test_minimax_via_get_llm_live(self):
from leann.chat import get_llm
llm = get_llm({"type": "minimax"})
response = llm.ask("What is 1+1? Reply with just the number.", max_tokens=10)
assert isinstance(response, str)
assert len(response) > 0