- Entry 增加 DeviceVisits:同一 URL 多次/多设备上报取各设备最大值再求和,
不再平方级放大(30 次访问曾被计成 465 次)
- handleGet 不再截断 100 条,返回 {items,total},后台显示当前条数
- 清理死代码(hostVisits/hostOf/visitCount/isCodeHostVal/dashySection)
- 守门测试:重复上报、多设备求和、陈旧数据、持久化、统计、门户文案、第 101 条可见性
82 lines
3.3 KiB
Go
82 lines
3.3 KiB
Go
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)
|
||
}
|
||
}
|