264 lines
8.3 KiB
Go
264 lines
8.3 KiB
Go
//go:build unit
|
|
|
|
package service
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// ==================== RefreshClient ====================
|
|
|
|
func TestRefreshClient(t *testing.T) {
|
|
s := newS3StorageWithCDN("https://cdn.example.com")
|
|
require.NotNil(t, s.client)
|
|
require.NotNil(t, s.cfg)
|
|
|
|
s.RefreshClient()
|
|
require.Nil(t, s.client)
|
|
require.Nil(t, s.cfg)
|
|
}
|
|
|
|
func TestRefreshClient_AlreadyNil(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
s.RefreshClient() // 不应 panic
|
|
require.Nil(t, s.client)
|
|
require.Nil(t, s.cfg)
|
|
}
|
|
|
|
// ==================== GetMediaTypeFromKey ====================
|
|
|
|
func TestGetMediaTypeFromKey_VideoExtensions(t *testing.T) {
|
|
for _, ext := range []string{".mp4", ".mov", ".webm", ".m4v", ".avi", ".mkv", ".3gp", ".flv"} {
|
|
require.Equal(t, "video", GetMediaTypeFromKey("path/to/file"+ext), "ext=%s", ext)
|
|
}
|
|
}
|
|
|
|
func TestGetMediaTypeFromKey_VideoUpperCase(t *testing.T) {
|
|
require.Equal(t, "video", GetMediaTypeFromKey("file.MP4"))
|
|
require.Equal(t, "video", GetMediaTypeFromKey("file.MOV"))
|
|
}
|
|
|
|
func TestGetMediaTypeFromKey_ImageExtensions(t *testing.T) {
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file.png"))
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file.jpg"))
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file.jpeg"))
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file.gif"))
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file.webp"))
|
|
}
|
|
|
|
func TestGetMediaTypeFromKey_NoExtension(t *testing.T) {
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file"))
|
|
require.Equal(t, "image", GetMediaTypeFromKey("path/to/file"))
|
|
}
|
|
|
|
func TestGetMediaTypeFromKey_UnknownExtension(t *testing.T) {
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file.bin"))
|
|
require.Equal(t, "image", GetMediaTypeFromKey("file.xyz"))
|
|
}
|
|
|
|
// ==================== Enabled ====================
|
|
|
|
func TestEnabled_NilSettingService(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
require.False(t, s.Enabled(context.Background()))
|
|
}
|
|
|
|
func TestEnabled_ConfigDisabled(t *testing.T) {
|
|
settingRepo := newStubSettingRepoForQuota(map[string]string{
|
|
SettingKeySoraS3Enabled: "false",
|
|
SettingKeySoraS3Bucket: "test-bucket",
|
|
})
|
|
settingService := NewSettingService(settingRepo, &config.Config{})
|
|
s := NewSoraS3Storage(settingService)
|
|
require.False(t, s.Enabled(context.Background()))
|
|
}
|
|
|
|
func TestEnabled_ConfigEnabledWithBucket(t *testing.T) {
|
|
settingRepo := newStubSettingRepoForQuota(map[string]string{
|
|
SettingKeySoraS3Enabled: "true",
|
|
SettingKeySoraS3Bucket: "my-bucket",
|
|
})
|
|
settingService := NewSettingService(settingRepo, &config.Config{})
|
|
s := NewSoraS3Storage(settingService)
|
|
require.True(t, s.Enabled(context.Background()))
|
|
}
|
|
|
|
func TestEnabled_ConfigEnabledEmptyBucket(t *testing.T) {
|
|
settingRepo := newStubSettingRepoForQuota(map[string]string{
|
|
SettingKeySoraS3Enabled: "true",
|
|
})
|
|
settingService := NewSettingService(settingRepo, &config.Config{})
|
|
s := NewSoraS3Storage(settingService)
|
|
require.False(t, s.Enabled(context.Background()))
|
|
}
|
|
|
|
// ==================== initClient ====================
|
|
|
|
func TestInitClient_Disabled(t *testing.T) {
|
|
settingRepo := newStubSettingRepoForQuota(map[string]string{
|
|
SettingKeySoraS3Enabled: "false",
|
|
})
|
|
settingService := NewSettingService(settingRepo, &config.Config{})
|
|
s := NewSoraS3Storage(settingService)
|
|
|
|
_, _, err := s.getClient(context.Background())
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "disabled")
|
|
}
|
|
|
|
func TestInitClient_IncompleteConfig(t *testing.T) {
|
|
settingRepo := newStubSettingRepoForQuota(map[string]string{
|
|
SettingKeySoraS3Enabled: "true",
|
|
SettingKeySoraS3Bucket: "test-bucket",
|
|
// 缺少 access_key_id 和 secret_access_key
|
|
})
|
|
settingService := NewSettingService(settingRepo, &config.Config{})
|
|
s := NewSoraS3Storage(settingService)
|
|
|
|
_, _, err := s.getClient(context.Background())
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "incomplete")
|
|
}
|
|
|
|
func TestInitClient_DefaultRegion(t *testing.T) {
|
|
settingRepo := newStubSettingRepoForQuota(map[string]string{
|
|
SettingKeySoraS3Enabled: "true",
|
|
SettingKeySoraS3Bucket: "test-bucket",
|
|
SettingKeySoraS3AccessKeyID: "AKID",
|
|
SettingKeySoraS3SecretAccessKey: "SECRET",
|
|
// Region 为空 → 默认 us-east-1
|
|
})
|
|
settingService := NewSettingService(settingRepo, &config.Config{})
|
|
s := NewSoraS3Storage(settingService)
|
|
|
|
client, cfg, err := s.getClient(context.Background())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, client)
|
|
require.Equal(t, "test-bucket", cfg.Bucket)
|
|
}
|
|
|
|
func TestInitClient_DoubleCheck(t *testing.T) {
|
|
// 验证双重检查锁定:第二次 getClient 命中缓存
|
|
settingRepo := newStubSettingRepoForQuota(map[string]string{
|
|
SettingKeySoraS3Enabled: "true",
|
|
SettingKeySoraS3Bucket: "test-bucket",
|
|
SettingKeySoraS3AccessKeyID: "AKID",
|
|
SettingKeySoraS3SecretAccessKey: "SECRET",
|
|
})
|
|
settingService := NewSettingService(settingRepo, &config.Config{})
|
|
s := NewSoraS3Storage(settingService)
|
|
|
|
client1, _, err1 := s.getClient(context.Background())
|
|
require.NoError(t, err1)
|
|
client2, _, err2 := s.getClient(context.Background())
|
|
require.NoError(t, err2)
|
|
require.Equal(t, client1, client2) // 同一客户端实例
|
|
}
|
|
|
|
func TestInitClient_NilSettingService(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
_, _, err := s.getClient(context.Background())
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "setting service not available")
|
|
}
|
|
|
|
// ==================== GenerateObjectKey ====================
|
|
|
|
func TestGenerateObjectKey_ExtWithoutDot(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
key := s.GenerateObjectKey("", 1, "mp4")
|
|
require.Contains(t, key, ".mp4")
|
|
require.True(t, len(key) > 0)
|
|
}
|
|
|
|
func TestGenerateObjectKey_ExtWithDot(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
key := s.GenerateObjectKey("", 1, ".mp4")
|
|
require.Contains(t, key, ".mp4")
|
|
// 不应出现 ..mp4
|
|
require.NotContains(t, key, "..mp4")
|
|
}
|
|
|
|
func TestGenerateObjectKey_WithPrefix(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
key := s.GenerateObjectKey("uploads/", 42, ".png")
|
|
require.True(t, len(key) > 0)
|
|
require.Contains(t, key, "uploads/sora/42/")
|
|
}
|
|
|
|
func TestGenerateObjectKey_PrefixWithoutTrailingSlash(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
key := s.GenerateObjectKey("uploads", 42, ".png")
|
|
require.Contains(t, key, "uploads/sora/42/")
|
|
}
|
|
|
|
// ==================== GeneratePresignedURL ====================
|
|
|
|
func TestGeneratePresignedURL_GetClientError(t *testing.T) {
|
|
s := NewSoraS3Storage(nil) // settingService=nil → getClient 失败
|
|
_, err := s.GeneratePresignedURL(context.Background(), "key", 3600)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ==================== GetAccessURL ====================
|
|
|
|
func TestGetAccessURL_CDN(t *testing.T) {
|
|
s := newS3StorageWithCDN("https://cdn.example.com")
|
|
url, err := s.GetAccessURL(context.Background(), "sora/1/2024/01/01/video.mp4")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "https://cdn.example.com/sora/1/2024/01/01/video.mp4", url)
|
|
}
|
|
|
|
func TestGetAccessURL_CDNTrailingSlash(t *testing.T) {
|
|
s := newS3StorageWithCDN("https://cdn.example.com/")
|
|
url, err := s.GetAccessURL(context.Background(), "key.mp4")
|
|
require.NoError(t, err)
|
|
require.Equal(t, "https://cdn.example.com/key.mp4", url)
|
|
}
|
|
|
|
func TestGetAccessURL_GetClientError(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
_, err := s.GetAccessURL(context.Background(), "key")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ==================== TestConnection ====================
|
|
|
|
func TestTestConnection_GetClientError(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
err := s.TestConnection(context.Background())
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ==================== UploadFromURL ====================
|
|
|
|
func TestUploadFromURL_GetClientError(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
_, _, err := s.UploadFromURL(context.Background(), 1, "https://example.com/file.mp4")
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// ==================== DeleteObjects ====================
|
|
|
|
func TestDeleteObjects_EmptyKeys(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
err := s.DeleteObjects(context.Background(), []string{})
|
|
require.NoError(t, err) // 空列表直接返回
|
|
}
|
|
|
|
func TestDeleteObjects_NilKeys(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
err := s.DeleteObjects(context.Background(), nil)
|
|
require.NoError(t, err) // nil 列表直接返回
|
|
}
|
|
|
|
func TestDeleteObjects_GetClientError(t *testing.T) {
|
|
s := NewSoraS3Storage(nil)
|
|
err := s.DeleteObjects(context.Background(), []string{"key1", "key2"})
|
|
require.Error(t, err)
|
|
}
|