""" 1080P API 集成测试 — 验证 video_generate_view 的入口校验。 """ import os import sys import django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings') sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) django.setup() import unittest from django.test import TestCase from django.contrib.auth import get_user_model from rest_framework.test import APIClient from apps.accounts.models import Team from apps.generation.models import QuotaConfig User = get_user_model() class TestVideoGenerateResolution(TestCase): """video_generate_view 的分辨率+模型组合校验。""" def setUp(self): # 初始化 QuotaConfig QuotaConfig.objects.get_or_create(pk=1) # 建测试 team + user self.team = Team.objects.create( name='test-1080p', is_active=True, monthly_spending_limit=1000, markup_percentage=0, balance=1000, frozen_amount=0, ) self.user = User.objects.create_user( username='test_1080p_user', email='test1080p@example.com', password='testpass123', team=self.team, spending_limit=-1, daily_generation_limit=-1, monthly_generation_limit=-1, ) self.client = APIClient() self.client.force_authenticate(user=self.user) def test_reject_fast_plus_1080p(self): """原则 1:Fast + 1080P 组合必须 400 拒绝,不能静默降级。""" resp = self.client.post('/api/v1/video/generate', { 'prompt': '测试', 'mode': 'universal', 'model': 'seedance_2.0_fast', 'aspect_ratio': '16:9', 'duration': 5, 'resolution': '1080p', 'references': [], }, format='json') self.assertEqual(resp.status_code, 400) body = resp.json() self.assertEqual(body.get('error'), 'invalid_resolution') # 提示信息要明确告知用户原因 self.assertIn('1080P', body.get('message', '')) self.assertIn('Fast', body.get('message', '')) def test_reject_adaptive_ratio(self): """原则 1:adaptive 不在 6 选 1 白名单,拒绝。""" resp = self.client.post('/api/v1/video/generate', { 'prompt': '测试', 'mode': 'universal', 'model': 'seedance_2.0', 'aspect_ratio': 'adaptive', 'duration': 5, 'resolution': '720p', 'references': [], }, format='json') self.assertEqual(resp.status_code, 400) # serializer 错误:aspect_ratio 不在 choices self.assertIn('aspect_ratio', str(resp.content)) def test_reject_invalid_resolution(self): """resolution 不在 480p/720p/1080p 白名单,拒绝。""" resp = self.client.post('/api/v1/video/generate', { 'prompt': '测试', 'mode': 'universal', 'model': 'seedance_2.0', 'aspect_ratio': '16:9', 'duration': 5, 'resolution': '4K', 'references': [], }, format='json') self.assertEqual(resp.status_code, 400) def test_resolution_default_720p_when_missing(self): """旧客户端不传 resolution 字段时,serializer default='720p' 生效。""" # 不传 resolution(兼容旧客户端) resp = self.client.post('/api/v1/video/generate', { 'prompt': '测试', 'mode': 'universal', 'model': 'seedance_2.0', 'aspect_ratio': '16:9', 'duration': 5, 'references': [], }, format='json') # serializer 应该接受(default='720p');可能因火山 API 未开通等其他原因失败, # 但不该是 resolution 相关的 400 错误 if resp.status_code == 400: body = resp.json() self.assertNotEqual(body.get('error'), 'invalid_resolution') def test_accept_valid_1080p_airdrama(self): """原则:AirDrama + 1080P 组合合法,不被 400 拒绝。""" resp = self.client.post('/api/v1/video/generate', { 'prompt': '测试', 'mode': 'universal', 'model': 'seedance_2.0', 'aspect_ratio': '16:9', 'duration': 5, 'resolution': '1080p', 'references': [], }, format='json') # 不应该因为分辨率被 400(可能因余额/API 未开通等其他原因失败) if resp.status_code == 400: body = resp.json() self.assertNotEqual(body.get('error'), 'invalid_resolution') class TestAdminSettingsResponse(TestCase): """GET /api/v1/admin/settings 必须返回所有 token_price 字段, 以防 v0.19.0 那种"字段在 serializer 里加了、但 _settings_dict 漏了"的回归。""" def setUp(self): QuotaConfig.objects.get_or_create(pk=1) self.admin = User.objects.create_user( username='test_admin_settings', email='test_admin_settings@example.com', password='testpass123', is_staff=True, is_superuser=True, ) self.client = APIClient() self.client.force_authenticate(user=self.admin) def test_get_returns_all_token_price_fields(self): """GET 返回 4 档单价(全部分辨率 + 是否含视频),缺一不可 — 缺字段会导致前端输入框显示空。""" resp = self.client.get('/api/v1/admin/settings') self.assertEqual(resp.status_code, 200) body = resp.json() for field in ( 'base_token_price', 'base_token_price_video', 'base_token_price_fast', 'base_token_price_fast_video', 'base_token_price_1080p', 'base_token_price_1080p_video', ): self.assertIn(field, body, f'GET /admin/settings response missing {field!r} — 前端这个输入框会显示空') self.assertIsInstance(body[field], (int, float), f'{field} 应该是数字类型') if __name__ == '__main__': unittest.main(verbosity=2)