Files
arcrun-collector/scan_dedup_scale_test.go
Leo 89d9b314fb 出貨 1.4.20:安裝器釘子 → 8be98b8+收 daemon 去重的規模測試
釘子:c1566cf → 8be98b8(release 1.4.20,source Arcrun@c7a0b31)
jsDelivr 已驗(用戶端的路,四個檔全 200 且內容逐項對):
  manifest release=1.4.20 core=5 顆(懶載設計保住)
  cypher ANALYTICS_KV.put 殘留 0/kbdb empty_reason 5/UI 匯出診斷檔按鈕 1

順帶收 daemon agent 留下的 scan_dedup_scale_test.go(它沙盒推不了)。
親跑驗過不是空檔:TestScan_FormatDuplicate_EvanDatasetScale
10,545 個白名單內檔案(9,045 獨立 md + 500 組三格式撞 stem)耗時 688ms,PASS。

🔴 出貨時抓到兩個「用 staging 覆蓋 prod」的陷阱(已避開,記入 wiki):
1. rsync --delete 會砍掉 prod 才有的 daemon/(20 個安裝檔)與 README.md
   => 推上去封測者就下載不到 daemon。靠 git status 顯示 D 才抓到。
2. core 陣列會從 5 顆變 24 顆——prod 只裝 5 顆是懶載設計(其他用到才長)。
   歷史警察指出 bbb433e 就是修「core 陣列被整個蓋掉」=> 同一個坑有前科,今天差點重演。
共同教訓:staging 與 prod 的內容範圍不一樣,不能整包蓋。

⏸️ 安裝器部署(wrangler deploy --config)被 classifier 擋,等 leo 執行。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 23:33:21 +08:00

73 lines
2.9 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.
// scan_dedup_scale_test.go — 同內容多格式去重在「真實規模」下的驗證(2026-08-07 驗收補測)。
//
// 為什麼要有這支:scan_dedup_test.go 只在 2~3 個檔案的小規模下驗證邏輯正確,
// 沒有驗過演算法在 leo 實據的規模(27,164 檔=9,045 md9,044 json9,043 html)下
// ①結果仍然正確(恰好 9,045 個 stem,一個 stem 只留一份)②不會因為規模爆炸而卡住
// detectFormatDuplicates 是 map 分組+逐組排序,理論上是 O(n log n),這裡實測而非空想)。
package collector
import (
"fmt"
"testing"
"time"
)
func TestScan_FormatDuplicate_EvanDatasetScale(t *testing.T) {
if testing.Short() {
t.Skip("scale test skipped in -short mode")
}
root := t.TempDir()
const nStems = 9045 // leo 實據:9,045 md 為最大宗,json/html 各少於此數(非每個 md 都有 json/html 對應)
const nJSON = 9044
const nHTML = 9043
for i := 0; i < nStems; i++ {
writeFile(t, root, fmt.Sprintf("markdown/%05d.md", i), "md 內容", baseTime)
}
for i := 0; i < nJSON; i++ {
writeFile(t, root, fmt.Sprintf("json/%05d.json", i), "json 內容", baseTime)
}
for i := 0; i < nHTML; i++ {
writeFile(t, root, fmt.Sprintf("html/%05d.html", i), "html 內容", baseTime)
}
// .json/.html 不在 allowedExt 白名單裡(見 scan.go),不會進 current 候選集合——
// 白名單先擋掉非文件格式與「去重」是獨立的兩層。為了真的測到「三格式並存去重」,
// 額外補一批白名單內、彼此撞 stem 的三種格式(.md/.txt/.csv 皆在 allowedExt 內)。
const nTripleStem = 500
for i := 0; i < nTripleStem; i++ {
stem := fmt.Sprintf("triple-%05d", i)
writeFile(t, root, "a/"+stem+".md", "md", baseTime)
writeFile(t, root, "b/"+stem+".txt", "txt", baseTime)
writeFile(t, root, "c/"+stem+".csv", "csv,x", baseTime)
}
m := newTestManifest()
start := time.Now()
payload, err := Scan(root, m, ScanOptions{})
elapsed := time.Since(start)
if err != nil {
t.Fatal(err)
}
t.Logf("Scan() 於 %d 個白名單內檔案(%d 個獨立 md + %d 組三格式撞 stem)耗時 %v",
nStems+3*nTripleStem, nStems, nTripleStem, elapsed)
if elapsed > 30*time.Second {
t.Errorf("規模測試耗時 %v,超過可接受上限(可能有 O(n^2) 的迴歸)", elapsed)
}
added := 0
for _, ev := range payload.Events {
if ev.Type == "added" {
added++
}
}
// 期望:nStems 個獨立 md(彼此 stem 不同,不受去重影響)+ nTripleStem 個(三選一去重後只留一張)
wantAdded := nStems + nTripleStem
if added != wantAdded {
t.Fatalf("added 事件數=%dwant %d(去重後每個 triple stem 應只產生 1 個事件)", added, wantAdded)
}
if len(payload.DuplicateFormats) != 2*nTripleStem {
t.Fatalf("DuplicateFormats=%dwant %d(每個 triple stem 應有 2 份被標記為重複)",
len(payload.DuplicateFormats), 2*nTripleStem)
}
}