Files
huya-go/internal/gui/logfile_test.go
T
yml2213 41565566c5 GUI 日志落盘,修复同一奖品重复兑换与监控结束竞态
- 日志落盘:新增 internal/gui/logfile.go,写到 <用户配置目录>/huya-go/logs/huya-go.log,单文件 5MB 后滚动保留 5 个备份;「日志」页签顶部显示路径并支持打开目录/复制路径;写盘失败自动降级为仅界面输出
- 修复重复兑换:界面选品会同时提交 pid、名称与 targetText 里的同一 pid,normalizeTargets 现按 pid/名称去重;runState 再按「账号+奖品」记账,多个 target 命中同一奖品时只兑换一次(新增 skip_duplicate 结果)
- 修复 use of closed network connection:成功后的异步刷新改为 runState.refresh 等待,RunTargets 返回前不再提前关闭连接
- queryHttpDns 增加 single-flight 与失败冷却,多账号并发建连只解析一次
- 新增 internal/gui/logfile_test.go 与 sniper/huya 回归测试;README 补日志说明
2026-10-13 20:34:43 +08:00

139 lines
3.2 KiB
Go

package gui
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
)
func TestLogSinkWritesFormattedLines(t *testing.T) {
sink, err := newLogSinkAt(t.TempDir())
if err != nil {
t.Fatal(err)
}
defer sink.Close()
at := time.Date(2026, 10, 13, 20, 21, 57, 822000000, time.Local)
if err := sink.Write(LogEntry{
Time: "20:21:57.822",
at: at,
Level: "debug",
Message: "[WSS] 请求 launch.pingSignal requestID=2",
}); err != nil {
t.Fatal(err)
}
data, err := os.ReadFile(sink.Path())
if err != nil {
t.Fatal(err)
}
want := "2026-10-13 20:21:57.822 [debug] [WSS] 请求 launch.pingSignal requestID=2\n"
if string(data) != want {
t.Fatalf("日志内容=%q, want %q", data, want)
}
if sink.Dir() != filepath.Dir(sink.Path()) {
t.Fatalf("Dir=%q Path=%q", sink.Dir(), sink.Path())
}
}
func TestLogSinkRotatesAndDropsOldest(t *testing.T) {
dir := t.TempDir()
sink, err := newLogSinkAt(dir)
if err != nil {
t.Fatal(err)
}
defer sink.Close()
sink.maxBytes = 200
sink.backups = 2
for i := 0; i < 60; i++ {
if err := sink.Write(LogEntry{Level: "info", Message: fmt.Sprintf("第 %d 条日志,用于触发滚动", i)}); err != nil {
t.Fatal(err)
}
}
if _, err := os.Stat(sink.Path() + ".1"); err != nil {
t.Fatalf("期望存在滚动文件 .1: %v", err)
}
if _, err := os.Stat(sink.Path() + ".2"); err != nil {
t.Fatalf("期望存在滚动文件 .2: %v", err)
}
if _, err := os.Stat(sink.Path() + ".3"); err == nil {
t.Fatal("backups=2 时不应出现 .3")
}
entries, err := os.ReadDir(dir)
if err != nil {
t.Fatal(err)
}
for _, entry := range entries {
info, err := entry.Info()
if err != nil {
t.Fatal(err)
}
if info.Size() > int64(sink.maxBytes)+200 {
t.Fatalf("%s 体积异常: %d", entry.Name(), info.Size())
}
}
}
func TestLogSinkAppendsAcrossReopen(t *testing.T) {
dir := t.TempDir()
sink, err := newLogSinkAt(dir)
if err != nil {
t.Fatal(err)
}
if err := sink.Write(LogEntry{Level: "info", Message: "第一条"}); err != nil {
t.Fatal(err)
}
if err := sink.Close(); err != nil {
t.Fatal(err)
}
reopened, err := newLogSinkAt(dir)
if err != nil {
t.Fatal(err)
}
defer reopened.Close()
if err := reopened.Write(LogEntry{Level: "info", Message: "第二条"}); err != nil {
t.Fatal(err)
}
data, err := os.ReadFile(reopened.Path())
if err != nil {
t.Fatal(err)
}
text := string(data)
if !strings.Contains(text, "第一条") || !strings.Contains(text, "第二条") {
t.Fatalf("追加写入失败: %q", text)
}
if strings.Index(text, "第一条") > strings.Index(text, "第二条") {
t.Fatalf("日志顺序异常: %q", text)
}
}
func TestAppWritesLogsToFile(t *testing.T) {
sink, err := newLogSinkAt(t.TempDir())
if err != nil {
t.Fatal(err)
}
defer sink.Close()
app := &App{logSink: sink}
app.addLog("info", "日志文件: %s", sink.Path())
app.addLog("debug", "[WSS] pingSignal 往返=28ms 服务端=17ms")
data, err := os.ReadFile(sink.Path())
if err != nil {
t.Fatal(err)
}
text := string(data)
if !strings.Contains(text, "日志文件: ") || !strings.Contains(text, "pingSignal") {
t.Fatalf("日志未落盘: %q", text)
}
if !strings.Contains(text, "[info]") || !strings.Contains(text, "[debug]") {
t.Fatalf("日志级别未写入: %q", text)
}
}