Spaces:
Running
Running
File size: 3,052 Bytes
85a7101 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | """
Tests for 3b multi-method MSA:
- EBI_TOOLS catalog covers all five methods with correct base URLs
- AlignRequest defaults to clustalo (backwards compatible)
- POST /api/alignment/run validates method before any network call
- run_alignment delegates to the shared run_ebi_msa and preserves response shape
All network calls are mocked; these run fully offline.
"""
import pytest
from fastapi import HTTPException
from app.tools.ebi_msa import EBI_TOOLS, run_ebi_msa
from app.routers import alignment as alignment_router
from app.routers.alignment import AlignRequest, run_alignment
class TestEbiToolsCatalog:
def test_five_methods_present(self):
assert set(EBI_TOOLS) == {"clustalo", "muscle", "kalign", "mafft", "tcoffee"}
def test_base_urls_match_tool_name(self):
for name, url in EBI_TOOLS.items():
assert url.endswith(f"/rest/{name}")
assert url.startswith("https://www.ebi.ac.uk/Tools/services/rest/")
class TestAlignRequestModel:
def test_default_method_clustalo(self):
req = AlignRequest(sequence=">a\nMEEPQSDPSV")
assert req.method == "clustalo"
def test_explicit_method_accepted(self):
req = AlignRequest(sequence=">a\nMEEPQSDPSV", method="mafft")
assert req.method == "mafft"
class TestRunAlignment:
@pytest.mark.asyncio
async def test_invalid_method_rejected_before_network(self):
req = AlignRequest(sequence=">a\nMEEPQSDPSV", method="clustalw")
with pytest.raises(HTTPException) as exc:
await run_alignment(req)
assert exc.value.status_code == 400
assert "method must be one of" in exc.value.detail
@pytest.mark.asyncio
async def test_success_delegates_to_shared_runner(self, monkeypatch):
canned = {
"job_id": "job-1",
"aln_fasta": ">a\nMEEPQSDPSV\n",
"phylotree": "(a:0.0,b:0.1);",
"method": "muscle",
}
async def fake_run_ebi_msa(**kwargs):
assert kwargs["base_url"] == EBI_TOOLS["muscle"]
return canned
monkeypatch.setattr(alignment_router, "run_ebi_msa", fake_run_ebi_msa)
req = AlignRequest(sequence=">a\nMEEPQSDPSV\n>b\nMEEPQSDPSA", method="muscle")
result = await run_alignment(req)
assert result["job_id"] == "job-1"
assert result["aln_fasta"] == canned["aln_fasta"]
assert result["phylotree"] == canned["phylotree"]
assert result["stype"] == "protein"
assert result["method"] == "muscle"
@pytest.mark.asyncio
async def test_runner_failure_maps_to_502(self, monkeypatch):
async def fake_run_ebi_msa(**kwargs):
raise ValueError("EBI submission failed (HTTP 500): boom")
monkeypatch.setattr(alignment_router, "run_ebi_msa", fake_run_ebi_msa)
req = AlignRequest(sequence=">a\nMEEPQSDPSV")
with pytest.raises(HTTPException) as exc:
await run_alignment(req)
assert exc.value.status_code == 502
assert "boom" in exc.value.detail
|