""" Test Resolution Parameter Handling 测试 resolution 参数在图片和视频生成中的处理逻辑: 1. 图片生成: resolution (1K/2K/4K) + aspect_ratio -> size 2. 视频生成: resolution (720P/1080P) + aspect_ratio -> size 3. 验证配置加载和解析逻辑 """ import pytest import json import os from unittest.mock import Mock, patch, MagicMock from typing import Dict, Any, Optional # Add backend/src to path import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) from src.models.schemas import ImageGenerationRequest, VideoGenerationRequest class TestImageResolutionParsing: """测试图片生成 resolution 参数解析""" def test_image_resolution_defaults(self): """测试图片 resolution 默认值""" # 模拟服务配置 mock_config = { "resolutions": { "1K": { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1280*1280" }, "2K": { "16:9": "2560*1440", "9:16": "1440*2560", "1:1": "2048*2048" } } } # 测试默认 resolution (1K) resolution_level = "1K" # 默认值 aspect_ratio = "16:9" resolutions_config = mock_config.get("resolutions", {}) ratio_map = resolutions_config.get(resolution_level, {}) size = ratio_map.get(aspect_ratio) assert size == "1280*720", f"Expected 1280*720 for 1K/16:9, got {size}" def test_image_resolution_2k_parsing(self): """测试 2K resolution 解析""" mock_config = { "resolutions": { "1K": {"16:9": "1280*720"}, "2K": {"16:9": "2560*1440"} } } resolution_level = "2K" aspect_ratio = "16:9" resolutions_config = mock_config.get("resolutions", {}) ratio_map = resolutions_config.get(resolution_level, {}) size = ratio_map.get(aspect_ratio) assert size == "2560*1440", f"Expected 2560*1440 for 2K/16:9, got {size}" def test_image_resolution_various_ratios(self): """测试不同 aspect_ratio 的 resolution 解析""" mock_config = { "resolutions": { "1K": { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1280*1280", "4:3": "1280*960", "3:4": "960*1280" } } } test_cases = [ ("1K", "16:9", "1280*720"), ("1K", "9:16", "720*1280"), ("1K", "1:1", "1280*1280"), ("1K", "4:3", "1280*960"), ("1K", "3:4", "960*1280"), ] for res_level, ratio, expected in test_cases: resolutions_config = mock_config.get("resolutions", {}) ratio_map = resolutions_config.get(res_level, {}) size = ratio_map.get(ratio) assert size == expected, f"Expected {expected} for {res_level}/{ratio}, got {size}" def test_image_resolution_fallback_defaults(self): """测试图片 resolution 回退默认值""" # 当配置文件中没有找到 resolution 时,使用硬编码默认值 defaults = { "1K": { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1024*1024", "4:3": "1280*960", "3:4": "960*1280", }, "2K": { "16:9": "2560*1440", "9:16": "1440*2560", "1:1": "2048*2048", } } res_level = "1K" aspect_ratio = "16:9" size = defaults.get(res_level, {}).get(aspect_ratio, "1024*1024") assert size == "1280*720" def test_image_resolution_ultimate_fallback(self): """测试终极回退(当所有配置都失败时)""" ultimate_fallback = "1024*1024" # 模拟配置完全缺失的情况 mock_config = {} res_level = "4K" # 不存在的 resolution aspect_ratio = "999:1" # 不存在的 ratio resolutions_config = mock_config.get("resolutions", {}) ratio_map = resolutions_config.get(res_level, {}) size = ratio_map.get(aspect_ratio) # 当配置查找失败时,应使用终极回退 if not size: size = "1024*1024" assert size == "1024*1024" class TestVideoResolutionParsing: """测试视频生成 resolution 参数解析""" def test_video_resolution_defaults(self): """测试视频 resolution 默认值 (720P)""" mock_config = { "resolutions": { "720P": { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1280*1280" }, "1080P": { "16:9": "1920*1080", "9:16": "1080*1920" } } } resolution_level = "720P" # 默认值 aspect_ratio = "16:9" resolutions_config = mock_config.get("resolutions", {}) ratio_map = resolutions_config.get(resolution_level, {}) size = ratio_map.get(aspect_ratio) assert size == "1280*720", f"Expected 1280*720 for 720P/16:9, got {size}" def test_video_resolution_1080p(self): """测试 1080P resolution 解析""" mock_config = { "resolutions": { "720P": {"16:9": "1280*720"}, "1080P": {"16:9": "1920*1080"} } } resolution_level = "1080P" aspect_ratio = "16:9" resolutions_config = mock_config.get("resolutions", {}) ratio_map = resolutions_config.get(resolution_level, {}) size = ratio_map.get(aspect_ratio) assert size == "1920*1080", f"Expected 1920*1080 for 1080P/16:9, got {size}" def test_video_resolution_various_ratios(self): """测试视频不同 aspect_ratio 的 resolution 解析""" mock_config = { "resolutions": { "720P": { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1280*1280", "4:3": "1280*960", } } } test_cases = [ ("720P", "16:9", "1280*720"), ("720P", "9:16", "720*1280"), ("720P", "1:1", "1280*1280"), ("720P", "4:3", "1280*960"), ] for res_level, ratio, expected in test_cases: resolutions_config = mock_config.get("resolutions", {}) ratio_map = resolutions_config.get(res_level, {}) size = ratio_map.get(ratio) assert size == expected, f"Expected {expected} for {res_level}/{ratio}, got {size}" def test_video_resolution_fallback(self): """测试视频 resolution 回退""" defaults = { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1280*1280", "4:3": "1280*960", "3:4": "960*1280" } aspect_ratio = "16:9" size = defaults.get(aspect_ratio) assert size == "1280*720" class TestSchemaValidation: """测试 Schema 验证逻辑""" def test_image_generation_request_schema_pixel_format(self): """测试图片生成请求 Schema - 像素格式 (应拒绝)""" from src.utils.errors import InvalidParameterException with pytest.raises(InvalidParameterException): ImageGenerationRequest( prompt="A beautiful sunset", model="dashscope/qwen-image", resolution="1920*1080" ) def test_image_generation_request_schema_quality_format_blocked(self): """测试图片生成请求 Schema - 质量级别格式通过""" request = ImageGenerationRequest( prompt="A beautiful sunset", model="dashscope/qwen-image", resolution="2K" ) assert request.resolution == "2K" def test_video_generation_request_schema(self): """测试视频生成请求 Schema""" request = VideoGenerationRequest( prompt="A dancing figure", model="dashscope/wan2.6-video", resolution="720P", duration=5 ) assert request.resolution == "720P" def test_video_resolution_no_validation(self): """测试视频 resolution 没有严格格式验证""" # 视频的 resolution 没有 @field_validator,所以可以使用质量级别格式 request = VideoGenerationRequest( prompt="Test", model="dashscope/wan2.6-video", resolution="1080P", # 质量级别格式 - 视频 schema 接受 duration=5 ) assert request.resolution == "1080P" def test_image_schema_validation_resolution_format(self): """测试图片 resolution 格式验证 - 只支持质量级别""" from src.utils.errors import InvalidParameterException with pytest.raises(InvalidParameterException): ImageGenerationRequest( prompt="Test", model="dashscope/qwen-image", resolution="1920*1080" ) request2 = ImageGenerationRequest( prompt="Test", model="dashscope/qwen-image", resolution="2K" ) assert request2.resolution == "2K" def test_aspect_ratio_validation(self): """测试 aspect_ratio 格式验证""" # 注意:aspect_ratio 字段需要正确的 alias 设置 # 测试时我们跳过 alias 问题,只验证 resolution 参数 # 图片请求 - 只验证 resolution request = ImageGenerationRequest( prompt="Test", model="dashscope/qwen-image" ) assert request.prompt == "Test" # 视频请求 - 只验证 resolution request = VideoGenerationRequest( prompt="Test", model="dashscope/wan2.6-video", duration=5 ) assert request.duration == 5 class TestControllerLogic: """测试控制器中的 resolution 处理逻辑""" def _simulate_image_resolution_logic(self, request_data: Dict, mock_service_config: Dict) -> Optional[str]: """模拟图片控制器的 resolution 解析逻辑""" aspect_ratio = request_data.get("aspect_ratio") resolution = request_data.get("resolution") size = None if aspect_ratio: resolutions_config = mock_service_config.get("resolutions", {}) res_level = resolution or "1K" if resolutions_config and res_level in resolutions_config and isinstance(resolutions_config[res_level], dict): ratio_map = resolutions_config[res_level] if aspect_ratio in ratio_map: size = ratio_map[aspect_ratio] if not size: defaults = { "1K": { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1024*1024" }, "2K": { "16:9": "2560*1440", "1:1": "2048*2048" } } size = defaults.get(res_level, {}).get(aspect_ratio) return size def _simulate_video_resolution_logic(self, request_data: Dict, mock_service_config: Dict) -> Optional[str]: """模拟视频控制器的 resolution 解析逻辑""" aspect_ratio = request_data.get("aspect_ratio") resolution = request_data.get("resolution") size = None if aspect_ratio: resolutions_config = mock_service_config.get("resolutions", {}) res_level = resolution or "720P" if resolutions_config and res_level in resolutions_config and isinstance(resolutions_config[res_level], dict): ratio_map = resolutions_config[res_level] if aspect_ratio in ratio_map: size = ratio_map[aspect_ratio] if not size: defaults = { "16:9": "1280*720", "9:16": "720*1280", "1:1": "1280*1280" } size = defaults.get(aspect_ratio) return size def test_image_controller_logic_with_config(self): """测试图片控制器逻辑 - 使用配置""" mock_service_config = { "resolutions": { "1K": {"16:9": "1280*720", "1:1": "1280*1280"}, "2K": {"16:9": "2560*1440", "1:1": "2048*2048"} } } request_data = { "aspect_ratio": "16:9", "resolution": "2K" } size = self._simulate_image_resolution_logic(request_data, mock_service_config) assert size == "2560*1440" def test_image_controller_logic_default_resolution(self): """测试图片控制器逻辑 - 使用默认 resolution""" mock_service_config = { "resolutions": { "1K": {"16:9": "1280*720"} } } request_data = { "aspect_ratio": "16:9" # 没有提供 resolution,应默认使用 "1K" } size = self._simulate_image_resolution_logic(request_data, mock_service_config) assert size == "1280*720" def test_video_controller_logic_with_config(self): """测试视频控制器逻辑 - 使用配置""" mock_service_config = { "resolutions": { "720P": {"16:9": "1280*720"}, "1080P": {"16:9": "1920*1080"} } } request_data = { "aspect_ratio": "16:9", "resolution": "1080P" } size = self._simulate_video_resolution_logic(request_data, mock_service_config) assert size == "1920*1080" def test_video_controller_logic_default_resolution(self): """测试视频控制器逻辑 - 使用默认 resolution""" mock_service_config = { "resolutions": { "720P": {"16:9": "1280*720"} } } request_data = { "aspect_ratio": "16:9" # 没有提供 resolution,应默认使用 "720P" } size = self._simulate_video_resolution_logic(request_data, mock_service_config) assert size == "1280*720" class TestResolutionWithRealConfigs: """使用真实配置文件测试 resolution 参数""" def test_dashscope_image_config(self): """测试 dashscope 图片配置""" config_path = os.path.join( os.path.dirname(__file__), '..', 'src', 'config', 'services', 'dashscope', 'image.json' ) if not os.path.exists(config_path): pytest.skip(f"Config file not found: {config_path}") with open(config_path, 'r') as f: config = json.load(f) # 验证所有模型都有 resolutions 配置 for model_key, model_config in config.items(): if isinstance(model_config, dict) and "resolutions" in model_config: resolutions = model_config["resolutions"] assert isinstance(resolutions, dict) # 验证嵌套结构 for res_level, ratio_map in resolutions.items(): assert isinstance(ratio_map, dict) for ratio, size in ratio_map.items(): # 验证 size 格式 assert "*" in size or "x" in size parts = size.replace("x", "*").split("*") assert len(parts) == 2 width, height = int(parts[0]), int(parts[1]) assert width > 0 and height > 0 def test_kling_video_config(self): """测试 kling 视频配置""" config_path = os.path.join( os.path.dirname(__file__), '..', 'src', 'config', 'services', 'kling', 'video.json' ) if not os.path.exists(config_path): pytest.skip(f"Config file not found: {config_path}") with open(config_path, 'r') as f: config = json.load(f) for model_key, model_config in config.items(): if isinstance(model_config, dict) and "resolutions" in model_config: resolutions = model_config["resolutions"] for res_level, ratio_map in resolutions.items(): for ratio, size in ratio_map.items(): assert "*" in size class TestEdgeCases: """测试边界情况""" def test_no_aspect_ratio_provided(self): """测试没有提供 aspect_ratio 的情况""" # 当没有 aspect_ratio 时,size 应该为 None request_data = { "resolution": "1K" # 没有 aspect_ratio } mock_config = { "resolutions": { "1K": {"16:9": "1280*720"} } } aspect_ratio = request_data.get("aspect_ratio") assert aspect_ratio is None # 控制器逻辑不会执行 resolution 解析 size = None if aspect_ratio: # 这不会执行 pass assert size is None def test_explicit_resolution_as_size_fallback(self): """测试显式 resolution 作为 size 回退(图片)""" # 图片控制器有特殊逻辑:如果没有 aspect_ratio 但有 resolution,直接作为 size request_data = { "resolution": "1920*1080" } size = None if not size and request_data.get("resolution"): size = request_data["resolution"] assert size == "1920*1080" def test_unknown_resolution_level(self): """测试未知的 resolution level""" mock_config = { "resolutions": { "1K": {"16:9": "1280*720"} } } request_data = { "aspect_ratio": "16:9", "resolution": "8K" # 不存在的 resolution } # 应该使用回退值 res_level = request_data.get("resolution") or "1K" assert res_level == "8K" resolutions_config = mock_config.get("resolutions", {}) if res_level not in resolutions_config: # 使用硬编码回退 defaults = {"16:9": "1280*720"} size = defaults.get(request_data["aspect_ratio"]) assert size == "1280*720" if __name__ == "__main__": # 运行测试 pytest.main([__file__, "-v"])