"""模型限制表的测试。 每个用例对应官方文档里两个已接入模型的一条具体限制。这些限制若搞错,表现是 用户提交后拿到一个失败任务(厂商 400),而本地测试全绿——所以值得逐条钉住。 """ from __future__ import annotations import pytest from app.providers.volcengine.capabilities import ( AUTO_DURATION, SEEDANCE_2_0, SEEDANCE_2_5, limits_for, validate, ) #: 账号实际接入的两个模型 ID。 MODEL_2_5 = "doubao-seedance-2-5-260628" MODEL_2_0 = "doubao-seedance-2-0-260128" class TestFamilyDetection: def test_both_activated_models_are_recognised(self): assert limits_for(MODEL_2_5) is SEEDANCE_2_5 assert limits_for(MODEL_2_0) is SEEDANCE_2_0 def test_matching_is_by_family_prefix_not_exact_id(self): """尾部日期版本会随厂商更新而变。 按前缀匹配使一次模型小版本升级(如 2-5-261231)不需要改这张表。 """ assert limits_for("doubao-seedance-2-5-999999") is SEEDANCE_2_5 def test_unknown_model_has_no_limits(self): assert limits_for("some-future-model") is None class TestUnknownModelsArePassedThrough: """账号新开通一个模型时不该因为这张表没更新就用不了。 否则「开通即可用」会变成「开通还得改代码发版」。代价只是失去本地预校验。 """ def test_anything_goes_for_an_unknown_model(self): validate( "brand-new-model", resolution="8k", duration_sec=999, ratio="16:9", has_first_frame=True, ) class TestResolutionLimits: def test_2_5_has_no_4k(self): # 官方:2.5 可选 480p / 720p / 1080p。 with pytest.raises(ValueError, match="不支持分辨率 4k"): validate(MODEL_2_5, resolution="4k") def test_2_0_does_have_4k(self): validate(MODEL_2_0, resolution="4k") def test_shared_resolutions_work_on_both(self): for model in (MODEL_2_5, MODEL_2_0): for resolution in ("480p", "720p", "1080p"): validate(model, resolution=resolution) def test_error_names_the_model_and_lists_the_options(self): with pytest.raises(ValueError) as exc: validate(MODEL_2_5, resolution="4k") assert MODEL_2_5 in str(exc.value) assert "1080p" in str(exc.value) class TestDurationLimits: def test_2_5_allows_up_to_30_seconds(self): validate(MODEL_2_5, duration_sec=30) def test_2_0_caps_at_15_seconds(self): # 官方:2.0 系列取值范围 [4, 15]。 validate(MODEL_2_0, duration_sec=15) with pytest.raises(ValueError, match=r"\[4, 15\]"): validate(MODEL_2_0, duration_sec=20) def test_the_same_20_seconds_is_fine_on_2_5(self): """同一个时长在两个模型上一个合法一个不合法——这正是需要这张表的理由。""" validate(MODEL_2_5, duration_sec=20) with pytest.raises(ValueError): validate(MODEL_2_0, duration_sec=20) def test_below_minimum_is_rejected_on_both(self): for model in (MODEL_2_5, MODEL_2_0): with pytest.raises(ValueError): validate(model, duration_sec=2) def test_auto_duration_bypasses_the_range_check(self): # -1 表示交给模型在有效范围内自选,不该被范围校验拦下。 validate(MODEL_2_5, duration_sec=AUTO_DURATION) validate(MODEL_2_0, duration_sec=AUTO_DURATION) def test_omitted_duration_is_not_checked(self): validate(MODEL_2_5) class TestRatioLockedToAdaptiveOnImageToVideo: """2.5 在图生视频时输出宽高比自动与首帧图片一致,不接受指定值。""" def test_2_5_rejects_a_specific_ratio_when_a_first_frame_is_given(self): with pytest.raises(ValueError, match="只支持 ratio=adaptive"): validate(MODEL_2_5, ratio="16:9", has_first_frame=True) def test_2_5_accepts_adaptive_with_a_first_frame(self): validate(MODEL_2_5, ratio="adaptive", has_first_frame=True) def test_2_5_accepts_a_specific_ratio_for_text_to_video(self): # 限制只在图生视频场景成立;文生视频可指定宽高比。 validate(MODEL_2_5, ratio="16:9", has_first_frame=False) def test_2_0_accepts_a_specific_ratio_even_with_a_first_frame(self): validate(MODEL_2_0, ratio="16:9", has_first_frame=True) class TestOutputFormatSupport: def test_only_2_5_supports_mov(self): # 我们当前不发送 output_format(默认 mp4),但这张表记录了差异, # 以便将来开放该参数时不必重读文档。 assert SEEDANCE_2_5.supports_output_format is True assert SEEDANCE_2_0.supports_output_format is False