Spaces:
Sleeping
Sleeping
Download dataFusion/tests/test_fallback.py from shak3008/cdss-backend: direct link, hf CLI and curl.
- Browser
- Download file 5.37 kB
-
https://huggingface.co/spaces/shak3008/cdss-backend/resolve/main/dataFusion/tests/test_fallback.py
- Command line
-
hf download hf://spaces/shak3008/cdss-backend/dataFusion/tests/test_fallback.py
-
curl -L -o test_fallback.py https://huggingface.co/spaces/shak3008/cdss-backend/resolve/main/dataFusion/tests/test_fallback.py
5.37 kB
| """Dedicated unit tests for automatic rule-based fallback behavior under all LLM failure modes.""" | |
| from unittest.mock import MagicMock, patch | |
| import httpx | |
| import pytest | |
| from app.config import settings | |
| from app.fusion import fuse_clinical_data, preprocess_fusion_request | |
| from app.schemas import FusionRequest | |
| from tests.test_data import VALID_FUSION_REQUEST_DICT | |
| def _run_fusion_with_mock_llm(mock_post): | |
| request = FusionRequest.model_validate(VALID_FUSION_REQUEST_DICT) | |
| preprocessed = preprocess_fusion_request(request) | |
| context, conflicts, trace_origins, mode, stats, fallback_reason = fuse_clinical_data(preprocessed, correlation_id="test-fallback-suite") | |
| return context, conflicts, trace_origins, mode, stats, fallback_reason | |
| def test_fallback_on_api_timeout(): | |
| """Verify that network timeout during LLM call falls back automatically to rule-based fusion.""" | |
| with patch.object(settings, "llm_api_key", "valid_key_123"), \ | |
| patch("httpx.Client.post", side_effect=httpx.TimeoutException("Connection timed out")): | |
| context, conflicts, origins, mode, stats, reason = _run_fusion_with_mock_llm(None) | |
| assert mode == "rule_based_fallback" | |
| assert reason is not None | |
| assert "Acute Myocardial Infarction" in context.normalized_medical_terms | |
| assert len(conflicts) > 0 | |
| def test_fallback_on_network_error(): | |
| """Verify that network failure during LLM call falls back automatically to rule-based fusion.""" | |
| with patch.object(settings, "llm_api_key", "valid_key_123"), \ | |
| patch("httpx.Client.post", side_effect=httpx.RequestError("DNS Resolution Error")): | |
| context, conflicts, origins, mode, stats, reason = _run_fusion_with_mock_llm(None) | |
| assert mode == "rule_based_fallback" | |
| assert reason is not None | |
| assert "Acute Myocardial Infarction" in context.normalized_medical_terms | |
| def test_fallback_on_invalid_api_key(): | |
| """Verify that unconfigured/invalid API key falls back automatically to rule-based fusion.""" | |
| with patch.object(settings, "llm_api_key", "mock_key_or_set_real_api_key"): | |
| context, conflicts, origins, mode, stats, reason = _run_fusion_with_mock_llm(None) | |
| assert mode == "rule_based_fallback" | |
| assert reason is not None | |
| assert "Acute Myocardial Infarction" in context.normalized_medical_terms | |
| def test_fallback_on_rate_limit_429(): | |
| """Verify that 429 rate limit response from LLM provider falls back automatically to rule-based fusion.""" | |
| mock_response = MagicMock() | |
| mock_response.status_code = 429 | |
| with patch.object(settings, "llm_api_key", "valid_key_123"), \ | |
| patch("httpx.Client.post", return_value=mock_response): | |
| context, conflicts, origins, mode, stats, reason = _run_fusion_with_mock_llm(None) | |
| assert mode == "rule_based_fallback" | |
| assert reason is not None | |
| assert "Acute Myocardial Infarction" in context.normalized_medical_terms | |
| def test_fallback_on_malformed_json(): | |
| """Verify that malformed/invalid JSON returned by LLM falls back automatically to rule-based fusion.""" | |
| mock_response = MagicMock() | |
| mock_response.status_code = 200 | |
| mock_response.json.return_value = { | |
| "choices": [{"message": {"content": "This is raw text, not JSON"}}] | |
| } | |
| with patch.object(settings, "llm_api_key", "valid_key_123"), \ | |
| patch("httpx.Client.post", return_value=mock_response): | |
| context, conflicts, origins, mode, stats, reason = _run_fusion_with_mock_llm(None) | |
| assert mode == "rule_based_fallback" | |
| assert reason is not None | |
| assert "Acute Myocardial Infarction" in context.normalized_medical_terms | |
| def test_fallback_on_empty_response(): | |
| """Verify that empty response content from LLM falls back automatically to rule-based fusion.""" | |
| mock_response = MagicMock() | |
| mock_response.status_code = 200 | |
| mock_response.json.return_value = {"choices": []} | |
| with patch.object(settings, "llm_api_key", "valid_key_123"), \ | |
| patch("httpx.Client.post", return_value=mock_response): | |
| context, conflicts, origins, mode, stats, reason = _run_fusion_with_mock_llm(None) | |
| assert mode == "rule_based_fallback" | |
| assert reason is not None | |
| assert "Acute Myocardial Infarction" in context.normalized_medical_terms | |
| def test_fallback_on_schema_validation_error(): | |
| """Verify that LLM output failing Pydantic schema validation falls back automatically to rule-based fusion.""" | |
| invalid_schema_json = { | |
| "unified_context": { | |
| "invalid_field": ["Acute Myocardial Infarction"] | |
| # Missing required fields like merged_findings, normalized_medical_terms, confidence_score, etc. | |
| } | |
| } | |
| mock_response = MagicMock() | |
| mock_response.status_code = 200 | |
| mock_response.json.return_value = { | |
| "choices": [{"message": {"content": str(invalid_schema_json)}}] | |
| } | |
| with patch.object(settings, "llm_api_key", "valid_key_123"), \ | |
| patch("httpx.Client.post", return_value=mock_response): | |
| context, conflicts, origins, mode, stats, reason = _run_fusion_with_mock_llm(None) | |
| assert mode == "rule_based_fallback" | |
| assert reason is not None | |
| assert "Acute Myocardial Infarction" in context.normalized_medical_terms | |