Files
english/.opencode/skills/ai-multimodal/scripts/tests/test_minimax_api_client.py
2026-04-12 01:06:31 +07:00

233 lines
8.1 KiB
Python

"""
Tests for minimax_api_client.py - HTTP utilities, auth, polling, downloads.
"""
import json
import pytest
import sys
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
sys.path.insert(0, str(Path(__file__).parent.parent))
import minimax_api_client as mac
class TestFindMinimaxApiKey:
"""Test API key discovery."""
def test_find_key_from_env(self, monkeypatch):
monkeypatch.setenv('MINIMAX_API_KEY', 'test-minimax-key')
with patch.object(mac, 'CENTRALIZED_RESOLVER_AVAILABLE', False):
assert mac.find_minimax_api_key() == 'test-minimax-key'
def test_find_key_not_found(self, monkeypatch):
monkeypatch.delenv('MINIMAX_API_KEY', raising=False)
with patch.object(mac, 'CENTRALIZED_RESOLVER_AVAILABLE', False):
result = mac.find_minimax_api_key()
assert result is None
def test_find_key_via_centralized_resolver(self, monkeypatch):
mock_resolve = Mock(return_value='resolved-key')
with patch.object(mac, 'CENTRALIZED_RESOLVER_AVAILABLE', True), \
patch.object(mac, 'resolve_env', mock_resolve, create=True):
result = mac.find_minimax_api_key()
assert result == 'resolved-key'
mock_resolve.assert_called_once_with(
'MINIMAX_API_KEY', skill='ai-multimodal'
)
class TestGetHeaders:
"""Test header generation."""
def test_headers_contain_bearer_token(self):
headers = mac.get_headers('my-api-key')
assert headers['Authorization'] == 'Bearer my-api-key'
assert headers['Content-Type'] == 'application/json'
def test_headers_with_different_key(self):
headers = mac.get_headers('another-key-123')
assert 'another-key-123' in headers['Authorization']
class TestApiPost:
"""Test POST request handling."""
@patch('minimax_api_client.requests.post')
def test_successful_post(self, mock_post):
mock_resp = Mock()
mock_resp.status_code = 200
mock_resp.json.return_value = {
"base_resp": {"status_code": 0},
"data": {"result": "ok"}
}
mock_post.return_value = mock_resp
result = mac.api_post("test_endpoint", {"key": "val"}, "api-key")
assert result["data"]["result"] == "ok"
mock_post.assert_called_once()
@patch('minimax_api_client.requests.post')
def test_http_error_raises(self, mock_post):
mock_resp = Mock()
mock_resp.status_code = 401
mock_resp.text = "Unauthorized"
mock_post.return_value = mock_resp
with pytest.raises(Exception, match="HTTP 401"):
mac.api_post("endpoint", {}, "bad-key")
@patch('minimax_api_client.requests.post')
def test_minimax_error_code_raises(self, mock_post):
mock_resp = Mock()
mock_resp.status_code = 200
mock_resp.json.return_value = {
"base_resp": {"status_code": 1002, "status_msg": "Rate limit"}
}
mock_post.return_value = mock_resp
with pytest.raises(Exception, match="code 1002.*Rate limit"):
mac.api_post("endpoint", {}, "api-key")
@patch('minimax_api_client.requests.post')
def test_custom_timeout(self, mock_post):
mock_resp = Mock()
mock_resp.status_code = 200
mock_resp.json.return_value = {"base_resp": {"status_code": 0}}
mock_post.return_value = mock_resp
mac.api_post("endpoint", {}, "key", timeout=300)
_, kwargs = mock_post.call_args
assert kwargs['timeout'] == 300
@patch('minimax_api_client.requests.post')
def test_default_timeout_is_120(self, mock_post):
mock_resp = Mock()
mock_resp.status_code = 200
mock_resp.json.return_value = {"base_resp": {"status_code": 0}}
mock_post.return_value = mock_resp
mac.api_post("endpoint", {}, "key")
_, kwargs = mock_post.call_args
assert kwargs['timeout'] == 120
@patch('minimax_api_client.requests.post')
def test_verbose_prints_url(self, mock_post, capsys):
mock_resp = Mock()
mock_resp.status_code = 200
mock_resp.json.return_value = {"base_resp": {"status_code": 0}}
mock_post.return_value = mock_resp
mac.api_post("image_generation", {}, "key", verbose=True)
captured = capsys.readouterr()
assert "image_generation" in captured.err
class TestApiGet:
"""Test GET request handling."""
@patch('minimax_api_client.requests.get')
def test_successful_get(self, mock_get):
mock_resp = Mock()
mock_resp.status_code = 200
mock_resp.json.return_value = {"status": "Success", "file_id": "abc"}
mock_get.return_value = mock_resp
result = mac.api_get("query/video_generation", {"task_id": "t1"}, "key")
assert result["status"] == "Success"
@patch('minimax_api_client.requests.get')
def test_get_http_error(self, mock_get):
mock_resp = Mock()
mock_resp.status_code = 500
mock_resp.text = "Server Error"
mock_get.return_value = mock_resp
with pytest.raises(Exception, match="HTTP 500"):
mac.api_get("endpoint", {}, "key")
class TestPollAsyncTask:
"""Test async task polling."""
@patch('minimax_api_client.time.sleep')
@patch('minimax_api_client.api_get')
def test_poll_success_first_try(self, mock_get, mock_sleep):
mock_get.return_value = {"status": "Success", "file_id": "f123"}
result = mac.poll_async_task("task1", "video_generation", "key")
assert result["file_id"] == "f123"
mock_sleep.assert_not_called()
@patch('minimax_api_client.time.sleep')
@patch('minimax_api_client.api_get')
def test_poll_success_after_processing(self, mock_get, mock_sleep):
mock_get.side_effect = [
{"status": "Processing"},
{"status": "Processing"},
{"status": "Success", "file_id": "f456"}
]
result = mac.poll_async_task("task2", "video_generation", "key",
poll_interval=1)
assert result["file_id"] == "f456"
assert mock_sleep.call_count == 2
@patch('minimax_api_client.time.sleep')
@patch('minimax_api_client.api_get')
def test_poll_task_failed(self, mock_get, mock_sleep):
mock_get.return_value = {"status": "Failed", "error": "bad input"}
with pytest.raises(Exception, match="Task failed"):
mac.poll_async_task("task3", "video_generation", "key")
@patch('minimax_api_client.time.sleep')
@patch('minimax_api_client.api_get')
def test_poll_timeout(self, mock_get, mock_sleep):
mock_get.return_value = {"status": "Processing"}
with pytest.raises(TimeoutError, match="timed out"):
mac.poll_async_task("task4", "video_generation", "key",
poll_interval=1, max_wait=3)
class TestDownloadFile:
"""Test file download."""
@patch('minimax_api_client.requests.get')
@patch('minimax_api_client.api_get')
def test_download_success(self, mock_api_get, mock_req_get, tmp_path):
mock_api_get.return_value = {
"file": {"download_url": "https://cdn.minimax.io/video.mp4"}
}
mock_resp = Mock()
mock_resp.raise_for_status = Mock()
mock_resp.iter_content.return_value = [b"video_data"]
mock_req_get.return_value = mock_resp
output = str(tmp_path / "test.mp4")
result = mac.download_file("file123", "key", output)
assert result == output
assert Path(output).exists()
@patch('minimax_api_client.api_get')
def test_download_no_url_raises(self, mock_api_get):
mock_api_get.return_value = {"file": {}}
with pytest.raises(Exception, match="No download URL"):
mac.download_file("file123", "key", "/tmp/test.mp4")
class TestGetOutputDir:
"""Test output directory resolution."""
def test_returns_path_object(self):
result = mac.get_output_dir()
assert isinstance(result, Path)
def test_directory_exists(self):
result = mac.get_output_dir()
assert result.exists()
assert result.is_dir()