Files
PlantAI-dev/tests/unit/test_result_browser_persistence.py
potaserandClaude Opus 5 e641c8b9ab feat: 轻量拓展分析 + WGS2GWAS 阶段支持 + 结果区域重构 + 物种角色解析增强 + 会话 Job 隔离
【轻量拓展分析】
- 新增 gfa_core/extension_stage_lightweight/ 核心模块,支持用户上传代码/数据/原始命令
- 前端卡片式交互流程:候选核对 → 验证 → 结果审查 → 授权发布 → 运行
- Celery 不受限任务 + 轮询机制 + sessionStorage 操作恢复
- 启动脚本新增 BBAV5_LIGHTWEIGHT_* 环境变量

【WGS2GWAS 支持】
- 新增 13 个 WGS 阶段定义(QC → MAF/Missing Filter)
- email_haplotype_region.py 新增 LTR-RT 分析功能

【结果区域重构】
- 单层折叠 → 三组双层折叠:RNA-seq / 基因家族 / WGS2GWAS
- 结果按执行时间排序,保留最新尝试

【物种角色解析增强】
- 新增 _resolve_subfamily_request_species_roles()
- 支持 reference 角色的识别
- 直接 stage 请求保留 intent 中的物种角色

【会话 Job 隔离】
- rebind_job() 跨 job 时创建新会话,返回新 conversation_id

【前端交互增强】
- RAG 文献问答模式
- NL 触发 config/samples 自动填写、亚家族确认表、基因家族成员确认表
- 执行状态从后端 resource_tasks 恢复

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 09:40:45 +08:00

78 lines
3.0 KiB
Python

import asyncio
import json
import os
from pathlib import Path
def test_result_browser_prefers_latest_manifest_and_shows_subfamily_evidence(monkeypatch, tmp_path):
from apps.web.vue3 import main as web_main
workspace_root = tmp_path / "workspace"
final_dir = workspace_root / "job-results" / "final"
final_dir.mkdir(parents=True)
image = final_dir / "Target.PEBP.target-Os.ref-At.subfamily_evidence.motif.png"
image.write_bytes(b"png")
success = final_dir / "Target.PEBP.target-Os.ref-At.subfamily_evidence.motif.manifest.json"
success.write_text(
json.dumps(
{
"stage": "motif",
"status": "success",
"prefix": "Os.PEBP",
"output_prefix": "Target.PEBP.target-Os.ref-At.subfamily_evidence",
"scope_id": "PEBP.target-Os.ref-At.target_plus_reference",
"scope_mode": "target_plus_reference",
"analysis_route": "subfamily_evidence",
"result_group": "motif_subfamily_evidence",
"elapsed_sec": 3.0,
"artifacts": {
"motif_plot_png": {
"artifact": "motif_plot",
"path": f"final/{image.name}",
"type": "image",
}
},
}
),
encoding="utf-8",
)
failed = final_dir / "Os.PEBP.target_only.motif.manifest.json"
failed.write_text(
json.dumps(
{
"stage": "motif",
"status": "failed",
"prefix": "Os.PEBP",
"scope_id": "PEBP.target-Os.target_only",
"analysis_route": "multi_species",
"parameters": {"error": "old failed attempt"},
"artifacts": {},
}
),
encoding="utf-8",
)
os.utime(failed, (1, 1))
os.utime(success, (2, 2))
monkeypatch.setattr(web_main, "WORKSPACE_ROOT", workspace_root)
result = asyncio.run(web_main.get_results(job_id="job-results", stage="motif"))
assert result["motif"]["status"] == "success"
assert image.name in json.dumps(result["motif"], ensure_ascii=False)
def test_result_panel_has_three_persistent_workflow_groups():
html = (Path(__file__).resolve().parents[2] / "apps/web/vue3/index.html").read_text(encoding="utf-8")
assert "RNA-seq" in html
assert "基因家族" in html
assert "WGS2GWAS(遗传变异与群体分析)" in html
assert "const resultGroups = computed" in html
assert "const groupStages = stages.filter(stage => resultGroupNameForStage(stage.name) === group.name);" in html
assert "wgsPopulationGwasResultRank(a.name) - wgsPopulationGwasResultRank(b.name)" in html
assert "name: 'wgs_qc'" in html
assert "name: 'wgs_maf_missing_filter'" in html
assert "await refreshResults(completedJobId, stageName);" in html
assert "await refreshResults(latestConversation.job_id);" in html