96 lines
3.5 KiB
Go
96 lines
3.5 KiB
Go
package worker
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestClassifyDramaErrorTreatsTimeoutAsUpstreamFailure 验证超时不会再进入提交未知状态。
|
|
func TestClassifyDramaErrorTreatsTimeoutAsUpstreamFailure(t *testing.T) {
|
|
if code := classifyDramaError(context.DeadlineExceeded); code != "upstream_timeout" {
|
|
t.Fatalf("timeout code = %q, want upstream_timeout", code)
|
|
}
|
|
}
|
|
|
|
// TestDramaModelRetryLimit 验证剧本解析调用的自动重试次数。
|
|
func TestDramaModelRetryLimit(t *testing.T) {
|
|
if maxDramaModelAttempts != 5 {
|
|
t.Fatalf("retry attempts = %d, want 5", maxDramaModelAttempts)
|
|
}
|
|
}
|
|
|
|
func TestDramaHTTPClientAllowsLongTextResponses(t *testing.T) {
|
|
sharedTransport := &http.Transport{TLSHandshakeTimeout: 10 * time.Second, ResponseHeaderTimeout: time.Minute}
|
|
shared := &http.Client{Transport: sharedTransport}
|
|
client := dramaHTTPClient(shared)
|
|
transport, ok := client.Transport.(*http.Transport)
|
|
if !ok {
|
|
t.Fatal("drama client transport was not preserved")
|
|
}
|
|
if transport.TLSHandshakeTimeout != 30*time.Second || transport.ResponseHeaderTimeout != 10*time.Minute {
|
|
t.Fatalf("unexpected drama timeouts: TLS=%s response=%s", transport.TLSHandshakeTimeout, transport.ResponseHeaderTimeout)
|
|
}
|
|
if sharedTransport.TLSHandshakeTimeout != 10*time.Second || sharedTransport.ResponseHeaderTimeout != time.Minute {
|
|
t.Fatal("shared AI transport was modified")
|
|
}
|
|
}
|
|
|
|
func TestParseDramaJSONNormalizesStoryboard(t *testing.T) {
|
|
result, err := parseDramaJSON("<think>hidden</think>```json\n{\"entities\":{\"roles\":[{\"name\":\"林夏\",\"image_prompt\":\"二十五岁女性,黑色长发\"}]},\"storyboards\":[{\"content\":\"走进房间\",\"duration_seconds\":99}]}\n```")
|
|
if err != nil {
|
|
t.Fatalf("parseDramaJSON returned error: %v", err)
|
|
}
|
|
if len(result.Entities.Characters) != 1 || len(result.Storyboards) != 1 {
|
|
t.Fatalf("unexpected normalized result: %#v", result)
|
|
}
|
|
if result.Storyboards[0].ScriptContent != "走进房间" || result.Storyboards[0].DurationSeconds != 5 {
|
|
t.Fatalf("storyboard was not normalized: %#v", result.Storyboards[0])
|
|
}
|
|
if result.Entities.Characters[0].ImagePrompt != "二十五岁女性,黑色长发" {
|
|
t.Fatalf("asset image prompt was not preserved: %#v", result.Entities.Characters[0])
|
|
}
|
|
}
|
|
|
|
func TestEstimateTextTokens(t *testing.T) {
|
|
if estimateTextTokens("中文ABCD") != 3 {
|
|
t.Fatalf("unexpected token estimate")
|
|
}
|
|
}
|
|
|
|
func TestBuildDramaUserPromptUsesOnlyCurrentContext(t *testing.T) {
|
|
snapshot := dramaParseSnapshot{
|
|
ProjectName: "测试项目",
|
|
StyleName: "国风水墨",
|
|
EraType: "ancient_xianxia",
|
|
EpisodeNo: 4,
|
|
EpisodeName: "再入山门",
|
|
}
|
|
prompt := buildDramaUserPrompt(snapshot, "当前集正文", []map[string]any{{"name": "林夏"}})
|
|
for _, expected := range []string{
|
|
"视觉风格:国风水墨",
|
|
"故事时代:古代仙侠",
|
|
"项目资产:",
|
|
"林夏",
|
|
"当前原文:\n当前集正文",
|
|
"按上述视觉风格和故事时代解析角色、场景、道具及分镜",
|
|
} {
|
|
if !strings.Contains(prompt, expected) {
|
|
t.Fatalf("prompt does not contain %q: %s", expected, prompt)
|
|
}
|
|
}
|
|
for _, forbidden := range []string{"continuity", "解析分段", "前序"} {
|
|
if strings.Contains(prompt, forbidden) {
|
|
t.Fatalf("prompt contains forbidden content %q: %s", forbidden, prompt)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDramaEraNameUsesCustomEra(t *testing.T) {
|
|
if got := dramaEraName("other", " 民国时期 "); got != "民国时期" {
|
|
t.Fatalf("unexpected custom era: %q", got)
|
|
}
|
|
}
|