test: cover backfill params end-to-end (mutation isolation + seq_offset)
This commit is contained in:
@@ -580,6 +580,90 @@ class TestPipelineV2:
|
||||
if result.accepted:
|
||||
assert len(result.heavy_sampled) == len(result.accepted)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_backfill_params_do_not_mutate_caller_objects(
|
||||
self, tree, default_config, store, tmp_path
|
||||
):
|
||||
"""补生成三参:传入的 used_node_ids / embed_pool 对象不被就地修改。
|
||||
|
||||
内部应复制而非别名 —— run 完之后调用方传入的容器长度/内容保持原样。
|
||||
"""
|
||||
vlm = MockVLM([_make_candidate_json(f"Q{i}?") for i in range(20)])
|
||||
llm = MockLLM([_make_gate_pass_response()] * 100)
|
||||
|
||||
config = PipelineConfig(
|
||||
per_type=2,
|
||||
retry_limit=2,
|
||||
heavy_sample_rate=0.0,
|
||||
dedup_threshold=0.85,
|
||||
concurrency=1,
|
||||
seed=42,
|
||||
output_dir=tmp_path / "out",
|
||||
)
|
||||
|
||||
initial_used_node_ids = {"some_node"}
|
||||
seed_vec = _mock_embed_fn("seed embedding text")
|
||||
initial_embed_pool = [seed_vec]
|
||||
|
||||
result = await run_pipeline_v2(
|
||||
video_ids=["vid_L1_000"],
|
||||
trees={"vid_L1_000": tree},
|
||||
vlm=vlm,
|
||||
llm=llm,
|
||||
embed_fn=_mock_embed_fn,
|
||||
store=store,
|
||||
config=config,
|
||||
task_types=["Action Recognition"],
|
||||
initial_used_node_ids=initial_used_node_ids,
|
||||
initial_embed_pool=initial_embed_pool,
|
||||
)
|
||||
|
||||
# 至少接受一题,确保内部确实往副本里追加了 node/embedding
|
||||
assert len(result.accepted) > 0
|
||||
|
||||
# 调用方对象未被 mutation:集合仍只含原始节点
|
||||
assert initial_used_node_ids == {"some_node"}
|
||||
# embed_pool 仍只含最初的一个向量,且内容未变
|
||||
assert len(initial_embed_pool) == 1
|
||||
assert np.array_equal(initial_embed_pool[0], seed_vec)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_seq_offset_continues_question_ids(
|
||||
self, tree, default_config, store, tmp_path
|
||||
):
|
||||
"""补生成三参:seq_offset 端到端续编 question_id 的 seq,避开旧 run 号段。"""
|
||||
vlm = MockVLM([_make_candidate_json(f"Q{i}?") for i in range(20)])
|
||||
llm = MockLLM([_make_gate_pass_response()] * 100)
|
||||
|
||||
config = PipelineConfig(
|
||||
per_type=2,
|
||||
retry_limit=2,
|
||||
heavy_sample_rate=0.0,
|
||||
dedup_threshold=0.85,
|
||||
concurrency=1,
|
||||
seed=42,
|
||||
output_dir=tmp_path / "out",
|
||||
)
|
||||
|
||||
result = await run_pipeline_v2(
|
||||
video_ids=["vid_L1_000"],
|
||||
trees={"vid_L1_000": tree},
|
||||
vlm=vlm,
|
||||
llm=llm,
|
||||
embed_fn=_mock_embed_fn,
|
||||
store=store,
|
||||
config=config,
|
||||
task_types=["Action Recognition"],
|
||||
seq_offset=30,
|
||||
)
|
||||
|
||||
assert len(result.accepted) > 0
|
||||
# question_id 格式 "{video_id}_{task_type}_{seq:04d}",seq 是最后一段 4 位数字
|
||||
seqs = [int(q.question_id.rsplit("_", 1)[1]) for q in result.accepted]
|
||||
assert all(s > 30 for s in seqs), seqs
|
||||
# per_type=2 → seq 从 31 起续编,不与 0-30 撞
|
||||
assert min(seqs) == 31
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_records_all(self, tree, default_config, store, tmp_path):
|
||||
"""验证 store 中记录了每道题的生成与门控结果。"""
|
||||
|
||||
Reference in New Issue
Block a user