test(backend): 补充改动代码单元测试覆盖率至 85%+
新增 48 个测试用例覆盖修复代码的各分支路径: - subscription_maintenance_queue: nil receiver/task、Stop 幂等、零值参数 (+6) - billing_service: CalculateCostWithConfig、错误传播、SoraImageCost 等 (+12) - timing_wheel_service: Schedule/ScheduleRecurring after Stop (+3) - sora_media_cleanup_service: nil guard、Start/Stop 各分支、timezone (+10) - sora_gateway_service: normalizeSoraMediaURLs、buildSoraContent 等辅助函数 (+17) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -100,6 +101,150 @@ func TestSoraGatewayService_BuildSoraMediaURLSigned(t *testing.T) {
|
||||
require.Contains(t, url, "sig=")
|
||||
}
|
||||
|
||||
func TestNormalizeSoraMediaURLs_Empty(t *testing.T) {
|
||||
svc := NewSoraGatewayService(nil, nil, nil, &config.Config{})
|
||||
result := svc.normalizeSoraMediaURLs(nil)
|
||||
require.Empty(t, result)
|
||||
|
||||
result = svc.normalizeSoraMediaURLs([]string{})
|
||||
require.Empty(t, result)
|
||||
}
|
||||
|
||||
func TestNormalizeSoraMediaURLs_HTTPUrls(t *testing.T) {
|
||||
svc := NewSoraGatewayService(nil, nil, nil, &config.Config{})
|
||||
urls := []string{"https://example.com/a.png", "http://example.com/b.mp4"}
|
||||
result := svc.normalizeSoraMediaURLs(urls)
|
||||
require.Equal(t, urls, result)
|
||||
}
|
||||
|
||||
func TestNormalizeSoraMediaURLs_LocalPaths(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
svc := NewSoraGatewayService(nil, nil, nil, cfg)
|
||||
urls := []string{"/image/2025/01/a.png", "video/2025/01/b.mp4"}
|
||||
result := svc.normalizeSoraMediaURLs(urls)
|
||||
require.Len(t, result, 2)
|
||||
require.Contains(t, result[0], "/sora/media")
|
||||
require.Contains(t, result[1], "/sora/media")
|
||||
}
|
||||
|
||||
func TestNormalizeSoraMediaURLs_SkipsBlank(t *testing.T) {
|
||||
svc := NewSoraGatewayService(nil, nil, nil, &config.Config{})
|
||||
urls := []string{"https://example.com/a.png", "", " ", "https://example.com/b.png"}
|
||||
result := svc.normalizeSoraMediaURLs(urls)
|
||||
require.Len(t, result, 2)
|
||||
}
|
||||
|
||||
func TestBuildSoraContent_Image(t *testing.T) {
|
||||
content := buildSoraContent("image", []string{"https://a.com/1.png", "https://a.com/2.png"})
|
||||
require.Contains(t, content, "")
|
||||
require.Contains(t, content, "")
|
||||
}
|
||||
|
||||
func TestBuildSoraContent_Video(t *testing.T) {
|
||||
content := buildSoraContent("video", []string{"https://a.com/v.mp4"})
|
||||
require.Contains(t, content, "<video src='https://a.com/v.mp4'")
|
||||
}
|
||||
|
||||
func TestBuildSoraContent_VideoEmpty(t *testing.T) {
|
||||
content := buildSoraContent("video", nil)
|
||||
require.Empty(t, content)
|
||||
}
|
||||
|
||||
func TestBuildSoraContent_Prompt(t *testing.T) {
|
||||
content := buildSoraContent("prompt", nil)
|
||||
require.Empty(t, content)
|
||||
}
|
||||
|
||||
func TestSoraImageSizeFromModel(t *testing.T) {
|
||||
require.Equal(t, "360", soraImageSizeFromModel("gpt-image"))
|
||||
require.Equal(t, "540", soraImageSizeFromModel("gpt-image-landscape"))
|
||||
require.Equal(t, "540", soraImageSizeFromModel("gpt-image-portrait"))
|
||||
require.Equal(t, "540", soraImageSizeFromModel("something-landscape"))
|
||||
require.Equal(t, "360", soraImageSizeFromModel("unknown-model"))
|
||||
}
|
||||
|
||||
func TestFirstMediaURL(t *testing.T) {
|
||||
require.Equal(t, "", firstMediaURL(nil))
|
||||
require.Equal(t, "", firstMediaURL([]string{}))
|
||||
require.Equal(t, "a", firstMediaURL([]string{"a", "b"}))
|
||||
}
|
||||
|
||||
func TestSoraProErrorMessage(t *testing.T) {
|
||||
require.Contains(t, soraProErrorMessage("sora2pro-hd", ""), "Pro-HD")
|
||||
require.Contains(t, soraProErrorMessage("sora2pro", ""), "Pro")
|
||||
require.Empty(t, soraProErrorMessage("sora-basic", ""))
|
||||
}
|
||||
|
||||
func TestShouldFailoverUpstreamError(t *testing.T) {
|
||||
svc := NewSoraGatewayService(nil, nil, nil, &config.Config{})
|
||||
require.True(t, svc.shouldFailoverUpstreamError(401))
|
||||
require.True(t, svc.shouldFailoverUpstreamError(429))
|
||||
require.True(t, svc.shouldFailoverUpstreamError(500))
|
||||
require.True(t, svc.shouldFailoverUpstreamError(502))
|
||||
require.False(t, svc.shouldFailoverUpstreamError(200))
|
||||
require.False(t, svc.shouldFailoverUpstreamError(400))
|
||||
}
|
||||
|
||||
func TestWithSoraTimeout_NilService(t *testing.T) {
|
||||
var svc *SoraGatewayService
|
||||
ctx, cancel := svc.withSoraTimeout(context.Background(), false)
|
||||
require.NotNil(t, ctx)
|
||||
require.Nil(t, cancel)
|
||||
}
|
||||
|
||||
func TestWithSoraTimeout_ZeroTimeout(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
svc := NewSoraGatewayService(nil, nil, nil, cfg)
|
||||
ctx, cancel := svc.withSoraTimeout(context.Background(), false)
|
||||
require.NotNil(t, ctx)
|
||||
require.Nil(t, cancel)
|
||||
}
|
||||
|
||||
func TestWithSoraTimeout_PositiveTimeout(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Gateway: config.GatewayConfig{
|
||||
SoraRequestTimeoutSeconds: 30,
|
||||
},
|
||||
}
|
||||
svc := NewSoraGatewayService(nil, nil, nil, cfg)
|
||||
ctx, cancel := svc.withSoraTimeout(context.Background(), false)
|
||||
require.NotNil(t, ctx)
|
||||
require.NotNil(t, cancel)
|
||||
cancel()
|
||||
}
|
||||
|
||||
func TestPollInterval(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Sora: config.SoraConfig{
|
||||
Client: config.SoraClientConfig{
|
||||
PollIntervalSeconds: 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
svc := NewSoraGatewayService(nil, nil, nil, cfg)
|
||||
require.Equal(t, 5*time.Second, svc.pollInterval())
|
||||
|
||||
// 默认值
|
||||
svc2 := NewSoraGatewayService(nil, nil, nil, &config.Config{})
|
||||
require.True(t, svc2.pollInterval() > 0)
|
||||
}
|
||||
|
||||
func TestPollMaxAttempts(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Sora: config.SoraConfig{
|
||||
Client: config.SoraClientConfig{
|
||||
MaxPollAttempts: 100,
|
||||
},
|
||||
},
|
||||
}
|
||||
svc := NewSoraGatewayService(nil, nil, nil, cfg)
|
||||
require.Equal(t, 100, svc.pollMaxAttempts())
|
||||
|
||||
// 默认值
|
||||
svc2 := NewSoraGatewayService(nil, nil, nil, &config.Config{})
|
||||
require.True(t, svc2.pollMaxAttempts() > 0)
|
||||
}
|
||||
|
||||
func TestDecodeSoraImageInput_BlockPrivateURL(t *testing.T) {
|
||||
_, _, err := decodeSoraImageInput(context.Background(), "http://127.0.0.1/internal.png")
|
||||
require.Error(t, err)
|
||||
|
||||
Reference in New Issue
Block a user