diff --git a/ai-hub/integration_tests/API_COVERAGE.md b/ai-hub/integration_tests/API_COVERAGE.md index 5ce45d4..61938df 100644 --- a/ai-hub/integration_tests/API_COVERAGE.md +++ b/ai-hub/integration_tests/API_COVERAGE.md @@ -4,9 +4,9 @@ ## Todo Works - [ ] Parse mapping of remaining APIs from all markdown files in `docs/api_reference/` to complete the checklist. -- [ ] Build a generic `test_stt_tts.py` integration spec (Targeting `/audio` transcode routing or native gemini). +- [x] Build a generic `test_audio.py` integration spec (Targeting STT and TTS routing). - [ ] Build a `test_agent_nodes_sandbox.py` spec for deep sandbox edge cases to ensure `workspace` restrictions work. -- [ ] Fully map coverage for the `/models` endpoints to `test_provider_config.py`. +- [x] Fully map coverage for the `/models` endpoints to `test_provider_config.py`. - [ ] Write missing tests for `/users/me/profile` endpoints. - [ ] Review `/skills` and `/knowledge` mapping against `test_browser_llm.py` which only touches standard capability mapping. @@ -58,4 +58,11 @@ Covered roughly by `integration_tests/test_provider_config.py` - [x] `POST /users/me/config/verify_llm` (Config validation proxy ping before save) - [x] `PUT /users/me/config` (Apply Provider Key Update) -- [ ] Check full coverage against `api_reference/models.md` +- [x] `GET /users/me/config` (Get Personal Setting Mapping) +- [x] `GET /users/me/config/models` (Get Models for Provider) + +### Audio Pipeline (STT & TTS) +Covered by `integration_tests/test_audio.py` +- [x] `GET /speech/voices` (List available TTS voices) +- [x] `POST /speech` (Generate speech from text) +- [x] `POST /stt/transcribe` (Transcribe audio to text) diff --git a/ai-hub/integration_tests/test_audio.py b/ai-hub/integration_tests/test_audio.py new file mode 100644 index 0000000..68474ff --- /dev/null +++ b/ai-hub/integration_tests/test_audio.py @@ -0,0 +1,64 @@ +import os +import httpx +import pytest + +BASE_URL = os.getenv("SYNC_TEST_BASE_URL", "http://127.0.0.1:8002/api/v1") + +def _headers(): + return { + "X-User-ID": os.environ.get("SYNC_TEST_USER_ID", "") + } + +def test_tts_voices(): + """Test retrieving available TTS voices.""" + with httpx.Client(timeout=10.0) as client: + r = client.get(f"{BASE_URL}/speech/voices", headers=_headers()) + assert r.status_code == 200, f"Failed to get voices: {r.text}" + voices = r.json() + assert isinstance(voices, list), "Voices should be a list" + +def test_tts_to_stt_lifecycle(): + """ + Test generating speech from text (TTS), then transcribing that audio + back to text (STT) to verify the full audio processing pipeline. + """ + user_id = os.environ.get("SYNC_TEST_USER_ID", "") + assert user_id, "User ID not found in environment from conftest." + + test_phrase = "Hello from integration test audio pipeline." + + with httpx.Client(timeout=30.0) as client: + # Step 1: Generate speech (TTS) + tts_payload = { + "text": test_phrase + } + r_tts = client.post( + f"{BASE_URL}/speech", + params={"stream": False}, + headers=_headers(), + json=tts_payload + ) + assert r_tts.status_code == 200, f"TTS failed: {r_tts.text}" + + # Ensure we got audio bytes back + audio_content = r_tts.content + assert len(audio_content) > 1000, "TTS audio content seems too small" + + # Step 2: Transcribe the generated audio (STT) + files = { + "audio_file": ("test_audio_pipeline.wav", audio_content, "audio/wav") + } + r_stt = client.post( + f"{BASE_URL}/stt/transcribe", + headers=_headers(), + files=files + ) + assert r_stt.status_code == 200, f"STT failed: {r_stt.text}" + + stt_result = r_stt.json() + transcript = stt_result.get("transcript", "").lower() + + # Assert the transcript contains our original phrase (or at least parts of it) + # Using a looser verification because STT models might slightly rephrase or omit punctuation + assert "hello" in transcript, f"Expected 'hello' in transcript: {transcript}" + assert "integration" in transcript, f"Expected 'integration' in transcript: {transcript}" diff --git a/ai-hub/integration_tests/test_provider_config.py b/ai-hub/integration_tests/test_provider_config.py index bc54cff..5c84d6e 100644 --- a/ai-hub/integration_tests/test_provider_config.py +++ b/ai-hub/integration_tests/test_provider_config.py @@ -124,3 +124,21 @@ data = r.json() # Should gracefully fail assert data["success"] is False + +def test_get_provider_models(): + """ + Test 6: Check retrieving the list of models for a provider via GET /users/me/config/models + """ + with httpx.Client(timeout=10.0) as client: + r = client.get(f"{BASE_URL}/users/me/config/models", params={"provider_name": "gemini"}, headers=_headers()) + assert r.status_code == 200, f"Expected 200 OK: {r.text}" + + models = r.json() + assert isinstance(models, list), "Response should be a list" + + # We expect at least some gemini models to be returned + # (e.g. gemini-3-flash-preview, gemini-2.5-flash, etc.) + assert len(models) > 0, "No models returned for provider 'gemini'" + + # Verify the structure of the returned objects + assert "model_name" in models[0], "Missing 'model_name' key in model object"