Files
arcrun-collector/cloud_latest_test.go
T
Leo 779a1b801e feat(t215): 每個知識庫顯示是否要更新,落後就給 install 頁連結
leo 08-08:「在每個知識庫會看到其他需要更新的,在每個知識庫上顯示是否要更新,
如果要,加開啓 install 頁的連結」。小幫手以前只提示自己(daemon 本體)要不要
更新,使用者連著多個雲端知識庫時完全看不出哪一個落後。

- collector/cloud_latest.go:EvalCloudUpdate + FetchLatestCloudRelease(30 分鐘節流),
  判準與 portal 版本卡 loadVersion() 同一套(bundle_version vs install.arcrun.dev/
  api/latest 的 release,semver 逐段整數比較),不是 t103 minCloudRelease 那把相容
  底線,避免同一個知識庫在兩處得到相反答案。
- direct.go/sync_status.go:每輪同步順帶算好每個帳號的 CloudUpdateKnown/
  CloudUpdateStale/CloudLatest,寫進 status.json。
- app.go:GetState 把這些欄位接進 UIAccount,供前端讀。
- main.js/style.css:首頁新增「知識庫版本」卡(每庫一行,落後才出現「前往安裝頁
  更新」按鈕,帶 email 預填);側邊欄庫名旁加警示點;各庫頁也顯示同一行版本狀態。
  查不到版本(連不上/latest 暫時查不到)一律誠實說「查不到」,不當成「已最新」。

已用假 window.go 在瀏覽器實測四種情境(落後/已最新/連不上/查得到 mine 但查不到
latest)+零知識庫的 onboarding 頁+深色模式,畫面與按鈕行為皆符合預期。

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

85 lines
3.0 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.
// cloud_latest_test.go — t215 單元測試:EvalCloudUpdate 的判準要跟 portal 版本卡一致。
package collector
import "testing"
func TestEvalCloudUpdate(t *testing.T) {
cases := []struct {
name string
mine string
mineOK bool
latest string
latestOK bool
wantKnown bool
wantUpdate bool
}{
{
name: "兩邊都拿得到、mine 落後", mine: "1.4.1", mineOK: true, latest: "1.4.2", latestOK: true,
wantKnown: true, wantUpdate: true,
},
{
name: "兩邊都拿得到、已是最新", mine: "1.4.2", mineOK: true, latest: "1.4.2", latestOK: true,
wantKnown: true, wantUpdate: false,
},
{
// 字串比較會誤判 "1.10.0" < "1.9.0";逐段整數比較才對(同 t103 迴歸守衛)。
name: "1.10.0 比 1.9.0 新,不該判落後", mine: "1.10.0", mineOK: true, latest: "1.9.0", latestOK: true,
wantKnown: true, wantUpdate: false,
},
{
// 老格式(YYYY-MM-DD+sha)——portal 版本卡註解原話:「這種情況一律當成落後」。
name: "老格式版本一律當落後", mine: "2026-07-31+8e83589", mineOK: true, latest: "1.4.2", latestOK: true,
wantKnown: true, wantUpdate: true,
},
{
name: "連不上這個知識庫(mineOK=false)→ 查不到,不能裝沒事", mine: "", mineOK: false, latest: "1.4.2", latestOK: true,
wantKnown: false, wantUpdate: false,
},
{
name: "查得到 mine 但暫時查不到最新版 → 查不到,不是已最新", mine: "1.4.2", mineOK: true, latest: "", latestOK: false,
wantKnown: false, wantUpdate: false,
},
{
name: "/health 可達但 bundle_version 空字串(老實例)→ 查不到", mine: "", mineOK: true, latest: "1.4.2", latestOK: true,
wantKnown: false, wantUpdate: false,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := EvalCloudUpdate(tc.mine, tc.mineOK, tc.latest, tc.latestOK)
if got.Known != tc.wantKnown {
t.Errorf("Known = %vwant %v", got.Known, tc.wantKnown)
}
if got.NeedsUpdate != tc.wantUpdate {
t.Errorf("NeedsUpdate = %vwant %v", got.NeedsUpdate, tc.wantUpdate)
}
})
}
}
// TestFetchLatestCloudReleaseThrottle 驗證節流:窗口內第二次呼叫不重打 fetchLatestCloudReleaseRaw。
func TestFetchLatestCloudReleaseThrottle(t *testing.T) {
calls := 0
orig := fetchLatestCloudReleaseRaw
defer func() {
fetchLatestCloudReleaseRaw = orig
latestMu.Lock()
latestCached, latestCachedOK, latestFetched = "", false, latestFetched.Add(-2*latestCacheTTL)
latestMu.Unlock()
}()
fetchLatestCloudReleaseRaw = func() (string, bool) { calls++; return "1.4.2", true }
// 強制第一次一定重打(避開其他測試留下的快取)。
latestMu.Lock()
latestFetched = latestFetched.Add(-2 * latestCacheTTL)
latestMu.Unlock()
r1, ok1 := FetchLatestCloudRelease()
r2, ok2 := FetchLatestCloudRelease()
if calls != 1 {
t.Errorf("節流窗口內第二次呼叫不該重打,calls = %d", calls)
}
if r1 != "1.4.2" || !ok1 || r2 != "1.4.2" || !ok2 {
t.Errorf("兩次結果應相同,got (%q,%v) (%q,%v)", r1, ok1, r2, ok2)
}
}