feat: Enhance dependency injection and service integration
- Updated main.go to initialize email service and include it in the dependency injection container. - Refactored handlers to utilize context in service method calls, improving consistency and error handling. - Introduced new service options for upload, security, and captcha services, enhancing modularity and testability. - Removed unused repository implementations to streamline the codebase. This commit continues the effort to improve the architecture by ensuring all services are properly injected and utilized across the application.
This commit is contained in:
@@ -1,358 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/zaptest"
|
||||
)
|
||||
|
||||
// TestSignatureService_Constants 测试签名服务相关常量
|
||||
func TestSignatureService_Constants(t *testing.T) {
|
||||
if RSAKeySize != 4096 {
|
||||
t.Errorf("RSAKeySize = %d, want 4096", RSAKeySize)
|
||||
}
|
||||
|
||||
if PrivateKeyRedisKey == "" {
|
||||
t.Error("PrivateKeyRedisKey should not be empty")
|
||||
}
|
||||
|
||||
if PublicKeyRedisKey == "" {
|
||||
t.Error("PublicKeyRedisKey should not be empty")
|
||||
}
|
||||
|
||||
if KeyExpirationTime != 24*7*time.Hour {
|
||||
t.Errorf("KeyExpirationTime = %v, want 7 days", KeyExpirationTime)
|
||||
}
|
||||
|
||||
if CertificateRefreshInterval != 24*time.Hour {
|
||||
t.Errorf("CertificateRefreshInterval = %v, want 24 hours", CertificateRefreshInterval)
|
||||
}
|
||||
|
||||
if CertificateExpirationPeriod != 24*7*time.Hour {
|
||||
t.Errorf("CertificateExpirationPeriod = %v, want 7 days", CertificateExpirationPeriod)
|
||||
}
|
||||
}
|
||||
|
||||
// TestSignatureService_DataValidation 测试签名数据验证逻辑
|
||||
func TestSignatureService_DataValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data string
|
||||
wantValid bool
|
||||
}{
|
||||
{
|
||||
name: "非空数据有效",
|
||||
data: "test data",
|
||||
wantValid: true,
|
||||
},
|
||||
{
|
||||
name: "空数据无效",
|
||||
data: "",
|
||||
wantValid: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
isValid := tt.data != ""
|
||||
if isValid != tt.wantValid {
|
||||
t.Errorf("Data validation failed: got %v, want %v", isValid, tt.wantValid)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPlayerCertificate_Structure 测试PlayerCertificate结构
|
||||
func TestPlayerCertificate_Structure(t *testing.T) {
|
||||
cert := PlayerCertificate{
|
||||
ExpiresAt: "2025-01-01T00:00:00Z",
|
||||
RefreshedAfter: "2025-01-01T00:00:00Z",
|
||||
PublicKeySignature: "signature",
|
||||
PublicKeySignatureV2: "signaturev2",
|
||||
}
|
||||
|
||||
// 验证结构体字段
|
||||
if cert.ExpiresAt == "" {
|
||||
t.Error("ExpiresAt should not be empty")
|
||||
}
|
||||
|
||||
if cert.RefreshedAfter == "" {
|
||||
t.Error("RefreshedAfter should not be empty")
|
||||
}
|
||||
|
||||
// PublicKeySignature是可选的
|
||||
if cert.PublicKeySignature == "" {
|
||||
t.Log("PublicKeySignature is optional")
|
||||
}
|
||||
}
|
||||
|
||||
// TestWrapString 测试字符串换行函数
|
||||
func TestWrapString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
str string
|
||||
width int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "正常换行",
|
||||
str: "1234567890",
|
||||
width: 5,
|
||||
expected: "12345\n67890",
|
||||
},
|
||||
{
|
||||
name: "字符串长度等于width",
|
||||
str: "12345",
|
||||
width: 5,
|
||||
expected: "12345",
|
||||
},
|
||||
{
|
||||
name: "字符串长度小于width",
|
||||
str: "123",
|
||||
width: 5,
|
||||
expected: "123",
|
||||
},
|
||||
{
|
||||
name: "width为0,返回原字符串",
|
||||
str: "1234567890",
|
||||
width: 0,
|
||||
expected: "1234567890",
|
||||
},
|
||||
{
|
||||
name: "width为负数,返回原字符串",
|
||||
str: "1234567890",
|
||||
width: -1,
|
||||
expected: "1234567890",
|
||||
},
|
||||
{
|
||||
name: "空字符串",
|
||||
str: "",
|
||||
width: 5,
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "width为1",
|
||||
str: "12345",
|
||||
width: 1,
|
||||
expected: "1\n2\n3\n4\n5",
|
||||
},
|
||||
{
|
||||
name: "长字符串多次换行",
|
||||
str: "123456789012345",
|
||||
width: 5,
|
||||
expected: "12345\n67890\n12345",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := WrapString(tt.str, tt.width)
|
||||
if result != tt.expected {
|
||||
t.Errorf("WrapString(%q, %d) = %q, want %q", tt.str, tt.width, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWrapString_LineCount 测试换行后的行数
|
||||
func TestWrapString_LineCount(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
str string
|
||||
width int
|
||||
wantLines int
|
||||
}{
|
||||
{
|
||||
name: "10个字符,width=5,应该2行",
|
||||
str: "1234567890",
|
||||
width: 5,
|
||||
wantLines: 2,
|
||||
},
|
||||
{
|
||||
name: "15个字符,width=5,应该3行",
|
||||
str: "123456789012345",
|
||||
width: 5,
|
||||
wantLines: 3,
|
||||
},
|
||||
{
|
||||
name: "5个字符,width=5,应该1行",
|
||||
str: "12345",
|
||||
width: 5,
|
||||
wantLines: 1,
|
||||
},
|
||||
{
|
||||
name: "width为0,应该1行",
|
||||
str: "1234567890",
|
||||
width: 0,
|
||||
wantLines: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := WrapString(tt.str, tt.width)
|
||||
lines := strings.Count(result, "\n") + 1
|
||||
if lines != tt.wantLines {
|
||||
t.Errorf("Line count = %d, want %d (result: %q)", lines, tt.wantLines, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWrapString_NoTrailingNewline 测试末尾不换行
|
||||
func TestWrapString_NoTrailingNewline(t *testing.T) {
|
||||
str := "1234567890"
|
||||
result := WrapString(str, 5)
|
||||
|
||||
// 验证末尾没有换行符
|
||||
if strings.HasSuffix(result, "\n") {
|
||||
t.Error("Result should not end with newline")
|
||||
}
|
||||
|
||||
// 验证包含换行符(除了最后一行)
|
||||
if !strings.Contains(result, "\n") {
|
||||
t.Error("Result should contain newline for multi-line output")
|
||||
}
|
||||
}
|
||||
|
||||
// TestEncodePrivateKeyToPEM_ActualCall 实际调用EncodePrivateKeyToPEM函数
|
||||
func TestEncodePrivateKeyToPEM_ActualCall(t *testing.T) {
|
||||
// 生成测试用的RSA私钥
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatalf("生成RSA私钥失败: %v", err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
keyType []string
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "默认类型",
|
||||
keyType: []string{},
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "RSA类型",
|
||||
keyType: []string{"RSA"},
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pemBytes, err := EncodePrivateKeyToPEM(privateKey, tt.keyType...)
|
||||
if (err != nil) != tt.wantError {
|
||||
t.Errorf("EncodePrivateKeyToPEM() error = %v, wantError %v", err, tt.wantError)
|
||||
return
|
||||
}
|
||||
if !tt.wantError {
|
||||
if len(pemBytes) == 0 {
|
||||
t.Error("EncodePrivateKeyToPEM() 返回的PEM字节不应为空")
|
||||
}
|
||||
pemStr := string(pemBytes)
|
||||
// 验证PEM格式
|
||||
if !strings.Contains(pemStr, "BEGIN") || !strings.Contains(pemStr, "END") {
|
||||
t.Error("EncodePrivateKeyToPEM() 返回的PEM格式不正确")
|
||||
}
|
||||
// 验证类型
|
||||
if len(tt.keyType) > 0 && tt.keyType[0] == "RSA" {
|
||||
if !strings.Contains(pemStr, "RSA PRIVATE KEY") {
|
||||
t.Error("EncodePrivateKeyToPEM() 应包含 'RSA PRIVATE KEY'")
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(pemStr, "PRIVATE KEY") {
|
||||
t.Error("EncodePrivateKeyToPEM() 应包含 'PRIVATE KEY'")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestEncodePublicKeyToPEM_ActualCall 实际调用EncodePublicKeyToPEM函数
|
||||
func TestEncodePublicKeyToPEM_ActualCall(t *testing.T) {
|
||||
logger := zaptest.NewLogger(t)
|
||||
|
||||
// 生成测试用的RSA密钥对
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
t.Fatalf("生成RSA密钥对失败: %v", err)
|
||||
}
|
||||
publicKey := &privateKey.PublicKey
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
keyType []string
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "默认类型",
|
||||
keyType: []string{},
|
||||
wantError: false,
|
||||
},
|
||||
{
|
||||
name: "RSA类型",
|
||||
keyType: []string{"RSA"},
|
||||
wantError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pemBytes, err := EncodePublicKeyToPEM(logger, publicKey, tt.keyType...)
|
||||
if (err != nil) != tt.wantError {
|
||||
t.Errorf("EncodePublicKeyToPEM() error = %v, wantError %v", err, tt.wantError)
|
||||
return
|
||||
}
|
||||
if !tt.wantError {
|
||||
if len(pemBytes) == 0 {
|
||||
t.Error("EncodePublicKeyToPEM() 返回的PEM字节不应为空")
|
||||
}
|
||||
pemStr := string(pemBytes)
|
||||
// 验证PEM格式
|
||||
if !strings.Contains(pemStr, "BEGIN") || !strings.Contains(pemStr, "END") {
|
||||
t.Error("EncodePublicKeyToPEM() 返回的PEM格式不正确")
|
||||
}
|
||||
// 验证类型
|
||||
if len(tt.keyType) > 0 && tt.keyType[0] == "RSA" {
|
||||
if !strings.Contains(pemStr, "RSA PUBLIC KEY") {
|
||||
t.Error("EncodePublicKeyToPEM() 应包含 'RSA PUBLIC KEY'")
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(pemStr, "PUBLIC KEY") {
|
||||
t.Error("EncodePublicKeyToPEM() 应包含 'PUBLIC KEY'")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestEncodePublicKeyToPEM_NilKey 测试nil公钥
|
||||
func TestEncodePublicKeyToPEM_NilKey(t *testing.T) {
|
||||
logger := zaptest.NewLogger(t)
|
||||
_, err := EncodePublicKeyToPEM(logger, nil)
|
||||
if err == nil {
|
||||
t.Error("EncodePublicKeyToPEM() 对于nil公钥应返回错误")
|
||||
}
|
||||
}
|
||||
|
||||
// TestNewSignatureService 测试创建SignatureService
|
||||
func TestNewSignatureService(t *testing.T) {
|
||||
logger := zaptest.NewLogger(t)
|
||||
// 注意:这里需要实际的redis client,但我们只测试结构体创建
|
||||
// 在实际测试中,可以使用mock redis client
|
||||
service := NewSignatureService(logger, nil)
|
||||
if service == nil {
|
||||
t.Error("NewSignatureService() 不应返回nil")
|
||||
}
|
||||
if service.logger != logger {
|
||||
t.Error("NewSignatureService() logger 设置不正确")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user