Files
HomeDash/history-server/synccount_test.go
JianFeeeee 292e77097d fix(history): 访问计数按设备去重 + 后台返回全量
- Entry 增加 DeviceVisits:同一 URL 多次/多设备上报取各设备最大值再求和,
  不再平方级放大(30 次访问曾被计成 465 次)
- handleGet 不再截断 100 条,返回 {items,total},后台显示当前条数
- 清理死代码(hostVisits/hostOf/visitCount/isCodeHostVal/dashySection)
- 守门测试:重复上报、多设备求和、陈旧数据、持久化、统计、门户文案、第 101 条可见性
2026-10-02 11:24:55 +08:00

82 lines
3.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
)
// 辅助:切换到临时数据目录并重置全局 history。
func withTempHistory(t *testing.T) {
t.Helper()
oldDir, oldFile := dataDir, historyFile
dataDir = t.TempDir()
historyFile = filepath.Join(dataDir, "history.json")
history = map[string]*Entry{}
t.Cleanup(func() { dataDir, historyFile = oldDir, oldFile })
}
func postSync(t *testing.T, items ...SyncItem) {
t.Helper()
body, _ := json.Marshal(SyncRequest{Items: items})
req := httptest.NewRequest(http.MethodPost, "/sync", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer t")
old := syncToken
syncToken = "t"
defer func() { syncToken = old }()
w := httptest.NewRecorder()
handleSync(w, req)
if w.Code != http.StatusOK {
t.Fatalf("status = %d, body = %s", w.Code, w.Body.String())
}
}
// 多设备:每台设备各报自己的绝对累计值,应求和而非取全局 max。
func TestSyncSumsAcrossDevices(t *testing.T) {
withTempHistory(t)
// 笔记本上该 URL 累计 10 次;手机上是 4 次
postSync(t, SyncItem{URL: "https://ex.com/a", Device: "laptop", Timestamp: 1700000000, VisitCount: 10})
postSync(t, SyncItem{URL: "https://ex.com/a", Device: "phone", Timestamp: 1700000060, VisitCount: 4})
if got := history["https://ex.com/a"].TotalVisits; got != 14 {
t.Errorf("TotalVisits = %d; 两设备绝对值应求和 10+4=14", got)
}
// 两台设备各自继续增长,重复上报不重复累加
postSync(t, SyncItem{URL: "https://ex.com/a", Device: "laptop", Timestamp: 1700000120, VisitCount: 12})
postSync(t, SyncItem{URL: "https://ex.com/a", Device: "phone", Timestamp: 1700000180, VisitCount: 4})
if got := history["https://ex.com/a"].TotalVisits; got != 16 {
t.Errorf("TotalVisits = %d; 期望 12+4=16(phone 的 4 不应再加一次)", got)
}
}
// 上报值变小(用户清了浏览器历史)时,不得把已有计数拉低。
func TestSyncNeverDecreasesOnStaleReport(t *testing.T) {
withTempHistory(t)
postSync(t, SyncItem{URL: "https://ex.com/a", Device: "laptop", Timestamp: 1700000000, VisitCount: 20})
postSync(t, SyncItem{URL: "https://ex.com/a", Device: "laptop", Timestamp: 1700000060, VisitCount: 3})
if got := history["https://ex.com/a"].TotalVisits; got != 20 {
t.Errorf("TotalVisits = %d; 迟到的陈旧上报不应把 20 拉低到 3", got)
}
}
// 旧版 history.json 没有 device_visits 字段,升级后不能归零。
func TestSyncLegacyEntryWithoutDeviceVisits(t *testing.T) {
withTempHistory(t)
// 模拟旧记录:只有 devices + total_visits
history["https://ex.com/old"] = &Entry{
URL: "https://ex.com/old", Title: "Old", TotalVisits: 8,
Devices: []string{"laptop"}, LastVisit: 1700000000,
}
postSync(t, SyncItem{URL: "https://ex.com/old", Device: "laptop", Timestamp: 1700000060, VisitCount: 9})
if got := history["https://ex.com/old"].TotalVisits; got != 9 {
t.Errorf("TotalVisits = %d; 旧记录的 8 次应在同一设备上被 9 接续,得到 9", got)
}
// 另一台设备加入 → 9 + 其自身绝对值
postSync(t, SyncItem{URL: "https://ex.com/old", Device: "phone", Timestamp: 1700000120, VisitCount: 2})
if got := history["https://ex.com/old"].TotalVisits; got != 11 {
t.Errorf("TotalVisits = %d; 期望 9+2=11", got)
}
}