326 lines
6.8 KiB
Go
326 lines
6.8 KiB
Go
|
|
package cache
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"os"
|
|||
|
|
"path/filepath"
|
|||
|
|
"testing"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func TestGenerateCacheKey(t *testing.T) {
|
|||
|
|
tests := []struct {
|
|||
|
|
name string
|
|||
|
|
text string
|
|||
|
|
fromLang string
|
|||
|
|
toLang string
|
|||
|
|
wantSame bool
|
|||
|
|
}{
|
|||
|
|
{
|
|||
|
|
name: "相同输入应生成相同键",
|
|||
|
|
text: "Hello world",
|
|||
|
|
fromLang: "en",
|
|||
|
|
toLang: "zh-CN",
|
|||
|
|
wantSame: true,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "不同文本应生成不同键",
|
|||
|
|
text: "Hello universe",
|
|||
|
|
fromLang: "en",
|
|||
|
|
toLang: "zh-CN",
|
|||
|
|
wantSame: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "不同语言对应生成不同键",
|
|||
|
|
text: "Hello world",
|
|||
|
|
fromLang: "en",
|
|||
|
|
toLang: "zh-TW",
|
|||
|
|
wantSame: false,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "大小写不敏感的语言代码",
|
|||
|
|
text: "Hello world",
|
|||
|
|
fromLang: "EN",
|
|||
|
|
toLang: "zh-cn",
|
|||
|
|
wantSame: true,
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "多余空白字符应规范化",
|
|||
|
|
text: " Hello world ",
|
|||
|
|
fromLang: "en",
|
|||
|
|
toLang: "zh-CN",
|
|||
|
|
wantSame: true,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
t.Run(tt.name, func(t *testing.T) {
|
|||
|
|
key1 := GenerateCacheKey(tt.text, tt.fromLang, tt.toLang)
|
|||
|
|
key2 := GenerateCacheKey(tt.text, tt.fromLang, tt.toLang)
|
|||
|
|
|
|||
|
|
if key1 != key2 {
|
|||
|
|
t.Errorf("相同输入生成了不同的键: %s != %s", key1, key2)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查键的长度(SHA256哈希应为64个字符)
|
|||
|
|
if len(key1) != 64 {
|
|||
|
|
t.Errorf("缓存键长度不正确: got %d, want 64", len(key1))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestSQLiteCache(t *testing.T) {
|
|||
|
|
// 创建临时目录
|
|||
|
|
tmpDir, err := os.MkdirTemp("", "cache_test")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("创建临时目录失败: %v", err)
|
|||
|
|
}
|
|||
|
|
defer os.RemoveAll(tmpDir)
|
|||
|
|
|
|||
|
|
dbPath := filepath.Join(tmpDir, "test_cache.db")
|
|||
|
|
|
|||
|
|
// 创建缓存配置
|
|||
|
|
config := &CacheConfig{
|
|||
|
|
Enabled: true,
|
|||
|
|
MaxRecords: 100,
|
|||
|
|
ExpireDays: 1,
|
|||
|
|
DBPath: dbPath,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建缓存实例
|
|||
|
|
cache, err := NewSQLiteCache(config)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("创建缓存实例失败: %v", err)
|
|||
|
|
}
|
|||
|
|
defer cache.Close()
|
|||
|
|
|
|||
|
|
ctx := context.Background()
|
|||
|
|
|
|||
|
|
// 测试设置缓存
|
|||
|
|
entry := &CacheEntry{
|
|||
|
|
CacheKey: "test_key_1",
|
|||
|
|
OriginalText: "Hello world",
|
|||
|
|
TranslatedText: "你好世界",
|
|||
|
|
FromLang: "en",
|
|||
|
|
ToLang: "zh-CN",
|
|||
|
|
Model: "gpt-3.5-turbo",
|
|||
|
|
PromptName: "simple",
|
|||
|
|
PromptContent: "请用简单易懂的语言翻译以下内容。",
|
|||
|
|
PromptTokens: 10,
|
|||
|
|
CompletionTokens: 5,
|
|||
|
|
TotalTokens: 15,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
err = cache.Set(ctx, entry)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("设置缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试获取缓存
|
|||
|
|
cachedEntry, err := cache.Get(ctx, "test_key_1")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("获取缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
if cachedEntry == nil {
|
|||
|
|
t.Fatal("缓存未命中")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if cachedEntry.TranslatedText != "你好世界" {
|
|||
|
|
t.Errorf("缓存翻译结果不正确: got %s, want 你好世界", cachedEntry.TranslatedText)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试缓存未命中
|
|||
|
|
missingEntry, err := cache.Get(ctx, "non_existent_key")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("查询不存在的缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
if missingEntry != nil {
|
|||
|
|
t.Error("不存在的缓存应该返回nil")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试统计信息
|
|||
|
|
stats, err := cache.Stats(ctx)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("获取统计信息失败: %v", err)
|
|||
|
|
}
|
|||
|
|
if stats.TotalRecords != 1 {
|
|||
|
|
t.Errorf("统计记录数不正确: got %d, want 1", stats.TotalRecords)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试删除缓存
|
|||
|
|
err = cache.Delete(ctx, "test_key_1")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("删除缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证删除
|
|||
|
|
deletedEntry, err := cache.Get(ctx, "test_key_1")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("查询已删除的缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
if deletedEntry != nil {
|
|||
|
|
t.Error("已删除的缓存应该返回nil")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 测试清空缓存
|
|||
|
|
err = cache.Set(ctx, entry)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("设置缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
err = cache.Clear(ctx)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("清空缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
stats, err = cache.Stats(ctx)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("获取统计信息失败: %v", err)
|
|||
|
|
}
|
|||
|
|
if stats.TotalRecords != 0 {
|
|||
|
|
t.Errorf("清空后记录数不正确: got %d, want 0", stats.TotalRecords)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestCacheExpiration(t *testing.T) {
|
|||
|
|
// 创建临时目录
|
|||
|
|
tmpDir, err := os.MkdirTemp("", "cache_test")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("创建临时目录失败: %v", err)
|
|||
|
|
}
|
|||
|
|
defer os.RemoveAll(tmpDir)
|
|||
|
|
|
|||
|
|
dbPath := filepath.Join(tmpDir, "test_cache.db")
|
|||
|
|
|
|||
|
|
// 创建缓存配置,设置很短的过期时间
|
|||
|
|
config := &CacheConfig{
|
|||
|
|
Enabled: true,
|
|||
|
|
MaxRecords: 100,
|
|||
|
|
ExpireDays: 0, // 0天表示立即过期
|
|||
|
|
DBPath: dbPath,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 创建缓存实例
|
|||
|
|
cache, err := NewSQLiteCache(config)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("创建缓存实例失败: %v", err)
|
|||
|
|
}
|
|||
|
|
defer cache.Close()
|
|||
|
|
|
|||
|
|
ctx := context.Background()
|
|||
|
|
|
|||
|
|
// 设置缓存
|
|||
|
|
entry := &CacheEntry{
|
|||
|
|
CacheKey: "test_key_1",
|
|||
|
|
OriginalText: "Hello world",
|
|||
|
|
TranslatedText: "你好世界",
|
|||
|
|
FromLang: "en",
|
|||
|
|
ToLang: "zh-CN",
|
|||
|
|
Model: "gpt-3.5-turbo",
|
|||
|
|
PromptTokens: 10,
|
|||
|
|
CompletionTokens: 5,
|
|||
|
|
TotalTokens: 15,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
err = cache.Set(ctx, entry)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("设置缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 立即清理(应该删除所有记录,因为过期时间为0)
|
|||
|
|
err = cache.Cleanup(ctx)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("清理缓存失败: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查统计信息
|
|||
|
|
stats, err := cache.Stats(ctx)
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("获取统计信息失败: %v", err)
|
|||
|
|
}
|
|||
|
|
if stats.TotalRecords != 0 {
|
|||
|
|
t.Errorf("清理后记录数不正确: got %d, want 0", stats.TotalRecords)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestNormalizeText(t *testing.T) {
|
|||
|
|
tests := []struct {
|
|||
|
|
name string
|
|||
|
|
input string
|
|||
|
|
expected string
|
|||
|
|
}{
|
|||
|
|
{
|
|||
|
|
name: "正常文本",
|
|||
|
|
input: "Hello world",
|
|||
|
|
expected: "Hello world",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "多余空白字符",
|
|||
|
|
input: " Hello world ",
|
|||
|
|
expected: "Hello world",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "制表符和换行符",
|
|||
|
|
input: "Hello\tworld\n",
|
|||
|
|
expected: "Hello world",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "空字符串",
|
|||
|
|
input: "",
|
|||
|
|
expected: "",
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
t.Run(tt.name, func(t *testing.T) {
|
|||
|
|
result := normalizeText(tt.input)
|
|||
|
|
if result != tt.expected {
|
|||
|
|
t.Errorf("normalizeText(%q) = %q, want %q", tt.input, result, tt.expected)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestNormalizeLanguageCode(t *testing.T) {
|
|||
|
|
tests := []struct {
|
|||
|
|
name string
|
|||
|
|
input string
|
|||
|
|
expected string
|
|||
|
|
}{
|
|||
|
|
{
|
|||
|
|
name: "正常语言代码",
|
|||
|
|
input: "zh-CN",
|
|||
|
|
expected: "zh-cn",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "大写语言代码",
|
|||
|
|
input: "EN-US",
|
|||
|
|
expected: "en-us",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "空字符串",
|
|||
|
|
input: "",
|
|||
|
|
expected: "auto",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "auto",
|
|||
|
|
input: "auto",
|
|||
|
|
expected: "auto",
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
name: "前后空白",
|
|||
|
|
input: " zh-CN ",
|
|||
|
|
expected: "zh-cn",
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for _, tt := range tests {
|
|||
|
|
t.Run(tt.name, func(t *testing.T) {
|
|||
|
|
result := normalizeLanguageCode(tt.input)
|
|||
|
|
if result != tt.expected {
|
|||
|
|
t.Errorf("normalizeLanguageCode(%q) = %q, want %q", tt.input, result, tt.expected)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|