Files
HomeDash/history-server/countbug_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

78 lines
2.7 KiB
Go
Raw 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"
)
// 复现「访问次数被平方级放大」:扩展每 30s 上报一次该 URL 的
// chrome.history.search visitCount —— 那是**绝对累计值**(1,2,3,4,5…),
// 而 handleSync 用 `e.TotalVisits += item.VisitCount` 把它当增量累加。
// 结果 5 次真实访问被记成 15 次。
func TestSyncDoubleCountsAbsoluteVisitCount(t *testing.T) {
dir := t.TempDir()
oldDir, oldFile, oldTok := dataDir, historyFile, syncToken
dataDir = dir
historyFile = filepath.Join(dir, "history.json")
syncToken = "t"
defer func() { dataDir, historyFile, syncToken = oldDir, oldFile, oldTok }()
history = map[string]*Entry{}
// 模拟 5 轮同步:同一 URL 的绝对 visitCount 依次为 1..5
for round, vc := range []int{1, 2, 3, 4, 5} {
body, _ := json.Marshal(SyncRequest{Items: []SyncItem{{
URL: "https://ex.com/a", Title: "A", Device: "desktop",
Timestamp: float64(1700000000 + round*30), VisitCount: vc,
}}})
req := httptest.NewRequest(http.MethodPost, "/sync", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer t")
w := httptest.NewRecorder()
handleSync(w, req)
if w.Code != http.StatusOK {
t.Fatalf("round %d: status = %d", round, w.Code)
}
}
e := history["https://ex.com/a"]
if e == nil {
t.Fatal("entry not created")
}
t.Logf("真实访问 5 次 → 落盘 TotalVisits = %d", e.TotalVisits)
if e.TotalVisits != 5 {
t.Errorf("TotalVisits = %d; 真实只访问 5 次,被平方级放大(期望 5)", e.TotalVisits)
}
}
// 上报 100 次同一 URL 会放大到什么程度 —— 量化后果。
func TestSyncInflationScalesQuadratically(t *testing.T) {
dir := t.TempDir()
oldDir, oldFile, oldTok := dataDir, historyFile, syncToken
dataDir = dir
historyFile = filepath.Join(dir, "history.json")
syncToken = "t"
defer func() { dataDir, historyFile, syncToken = oldDir, oldFile, oldTok }()
history = map[string]*Entry{}
// 真实访问 30 次,但扩展每 30s 同步一次 → 上报 30 次绝对值
for round := 1; round <= 30; round++ {
body, _ := json.Marshal(SyncRequest{Items: []SyncItem{{
URL: "https://ex.com/b", Device: "desktop",
Timestamp: float64(1700000000 + round*30), VisitCount: round,
}}})
req := httptest.NewRequest(http.MethodPost, "/sync", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer t")
handleSync(httptest.NewRecorder(), req)
}
got := history["https://ex.com/b"].TotalVisits
want := 30
t.Logf("真实 30 次访问 → 落盘 %d 次(虚高 %.1f×)", got, float64(got)/float64(want))
if got != want {
t.Errorf("TotalVisits = %d; want %d", got, want)
}
}