@@ -886,3 +886,120 @@ class TestTemplateConfigPropagation:
assert clip_cfg . get ( " speed_ratio " ) == 1.2
assert clip_cfg . get ( " name " ) == " 开场 "
assert clip_cfg . get ( " custom_field " ) == " value "
class TestAssetDurationsAlwaysFetched :
""" 验证 asset_durations 不再受 random_preview 条件限制。
修复前:asset_durations 仅在 random_preview=True 时传入 distribute_assets
修复后:只要 _asset_repo 存在,就始终获取 asset_durations
"""
def _make_service_with_asset_repo ( self ) :
""" 创建带 mock asset_repo 的 PlanGeneratorService """
from apps . api . app . services . plan_generator_service import PlanGeneratorService
plan_repo = StubEditPlanRepository ( )
clip_repo = StubEditPlanClipRepository ( )
# mock asset_repo: 返回带 duration 的素材
asset_repo = MagicMock ( )
def fake_get ( asset_id ) :
mock_asset = MagicMock ( )
mock_asset . duration = 30.0 # 每个素材 30 秒
return mock_asset
asset_repo . get = MagicMock ( side_effect = fake_get )
with (
patch (
" apps.api.app.services.plan_generator_service.SQLAlchemyEditPlanRepository " ,
return_value = plan_repo ,
) ,
patch (
" apps.api.app.services.plan_generator_service.SQLAlchemyEditPlanClipRepository " ,
return_value = clip_repo ,
) ,
) :
db = MagicMock ( )
svc = PlanGeneratorService ( db , asset_repo = asset_repo )
svc . _plan_repo = plan_repo
svc . _clip_repo = clip_repo
return svc , asset_repo
def test_asset_durations_fetched_without_random_preview ( self ) :
""" random_preview=False 时也应获取 asset_durations """
svc , asset_repo = self . _make_service_with_asset_repo ( )
template = _make_template ( " one_take " )
clip_configs = _make_clip_configs (
template_id = template . id ,
specs = [ { " clip_type " : ClipType . MAIN , " order " : 0 , " min_duration " : 3.0 , " max_duration " : 5.0 } ] ,
)
# patch distribute_assets 以捕获传入的参数
with patch ( " apps.api.app.services.plan_generator_service.distribute_assets " ) as mock_distribute :
svc . generate_from_template (
template = template ,
clip_configs = clip_configs ,
asset_ids = [ " a1 " , " a2 " ] ,
random_preview = False , # 关键:非随机预览模式
)
# 验证 asset_durations 被传入(不是 None)
mock_distribute . assert_called_once ( )
call_kwargs = mock_distribute . call_args
asset_durations = call_kwargs . kwargs . get ( " asset_durations " , call_kwargs [ 1 ] . get ( " asset_durations " ) )
assert asset_durations is not None , " asset_durations should be fetched even when random_preview=False "
assert " a1 " in asset_durations
assert " a2 " in asset_durations
assert asset_durations [ " a1 " ] == 30.0
# 验证 asset_repo.get 被调用(说明 _fetch_asset_durations 执行了)
assert asset_repo . get . call_count > = 2
def test_asset_durations_fetched_with_random_preview ( self ) :
""" random_preview=True 时仍正常获取 asset_durations(行为不变) """
svc , asset_repo = self . _make_service_with_asset_repo ( )
template = _make_template ( " one_take " )
clip_configs = _make_clip_configs (
template_id = template . id ,
specs = [ { " clip_type " : ClipType . MAIN , " order " : 0 , " min_duration " : 3.0 , " max_duration " : 5.0 } ] ,
)
with patch ( " apps.api.app.services.plan_generator_service.distribute_assets " ) as mock_distribute :
svc . generate_from_template (
template = template ,
clip_configs = clip_configs ,
asset_ids = [ " a1 " ] ,
random_preview = True ,
)
call_kwargs = mock_distribute . call_args
asset_durations = call_kwargs . kwargs . get ( " asset_durations " , call_kwargs [ 1 ] . get ( " asset_durations " ) )
assert asset_durations is not None
assert " a1 " in asset_durations
def test_no_asset_repo_means_no_durations ( self ) :
""" _asset_repo 为 None 时 asset_durations 应为 None """
svc , _ , _ = _make_generator ( ) # 默认不带 asset_repo
template = _make_template ( " one_take " )
clip_configs = _make_clip_configs (
template_id = template . id ,
specs = [ { " clip_type " : ClipType . MAIN , " order " : 0 , " min_duration " : 3.0 , " max_duration " : 5.0 } ] ,
)
with patch ( " apps.api.app.services.plan_generator_service.distribute_assets " ) as mock_distribute :
svc . generate_from_template (
template = template ,
clip_configs = clip_configs ,
asset_ids = [ " a1 " ] ,
)
call_kwargs = mock_distribute . call_args
asset_durations = call_kwargs . kwargs . get ( " asset_durations " , call_kwargs [ 1 ] . get ( " asset_durations " ) )
assert asset_durations is None