| package app |
|
|
| import ( |
| "context" |
| "math" |
| "testing" |
| "time" |
|
|
| "ccLoad/internal/model" |
| "ccLoad/internal/storage" |
| ) |
|
|
| func TestFillHealthTimeline_UsesSecondsForAvgTimes(t *testing.T) { |
| store, err := storage.CreateSQLiteStore(t.TempDir() + "/test.db") |
| if err != nil { |
| t.Fatalf("创建测试数据库失败: %v", err) |
| } |
| t.Cleanup(func() { _ = store.Close() }) |
|
|
| s := &Server{store: store} |
|
|
| now := time.Now().Truncate(time.Second) |
| startTime := now.Add(-24 * time.Hour) |
| endTime := now |
|
|
| channelID64 := int64(1) |
| channelID := int(channelID64) |
| modelName := "claude-test" |
|
|
| logTime := now.Add(-12 * time.Hour) |
| if err := store.AddLog(context.Background(), &model.LogEntry{ |
| Time: model.JSONTime{Time: logTime}, |
| Model: modelName, |
| ActualModel: modelName, |
| ChannelID: channelID64, |
| StatusCode: 200, |
| Message: "ok", |
| Duration: 2.3, |
| IsStreaming: true, |
| FirstByteTime: 1.5, |
| }); err != nil { |
| t.Fatalf("写入日志失败: %v", err) |
| } |
|
|
| stats := []model.StatsEntry{ |
| { |
| ChannelID: ptrInt(channelID), |
| Model: modelName, |
| }, |
| } |
| filter := &model.LogFilter{ |
| ChannelID: ptrInt64(channelID64), |
| Model: modelName, |
| } |
|
|
| s.fillHealthTimeline(context.Background(), stats, startTime, endTime, filter, false) |
|
|
| if len(stats) == 0 { |
| t.Fatal("stats 切片为空") |
| } |
| if len(stats[0].HealthTimeline) != 48 { |
| t.Fatalf("期望 health timeline 长度=48,实际=%d", len(stats[0].HealthTimeline)) |
| } |
|
|
| var found bool |
| for _, point := range stats[0].HealthTimeline { |
| if point.SuccessCount == 1 && point.ErrorCount == 0 { |
| found = true |
| if math.Abs(point.AvgFirstByteTime-1.5) > 1e-9 { |
| t.Fatalf("AvgFirstByteTime 期望≈1.5(秒),实际=%v", point.AvgFirstByteTime) |
| } |
| if math.Abs(point.AvgDuration-2.3) > 1e-9 { |
| t.Fatalf("AvgDuration 期望≈2.3(秒),实际=%v", point.AvgDuration) |
| } |
| break |
| } |
| } |
| if !found { |
| t.Fatalf("未找到包含写入日志的时间桶") |
| } |
| } |
|
|
| func ptrInt64(v int64) *int64 { return &v } |
|
|
| func ptrInt(v int) *int { return &v } |
|
|