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) } }