779a1b801e
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>
76 lines
3.0 KiB
Go
76 lines
3.0 KiB
Go
// cloud_version_test.go — t103 雲端版本判定函式 4 案單元測試。
|
||
package collector
|
||
|
||
import (
|
||
"os"
|
||
"testing"
|
||
)
|
||
|
||
// TestMain 在所有測試執行前把 fetchCloudVersion 換成 stub(回 ("", false)),
|
||
// 避免各測試的假 httptest.Server 或離線環境因真實 /health 呼叫炸掉測試。
|
||
// TestCloudVersionStale 直接測 cloudVersionStale 邏輯,不受此 stub 影響。
|
||
func TestMain(m *testing.M) {
|
||
fetchCloudVersion = func(string) (string, bool) { return "", false }
|
||
// t215:同一個理由——避免 EvalCloudUpdate 相關測試因為真的打了
|
||
// install.arcrun.dev 而變成看網路臉色的測試。
|
||
fetchLatestCloudReleaseRaw = func() (string, bool) { return "", false }
|
||
os.Exit(m.Run())
|
||
}
|
||
|
||
// TestCloudVersionStale 驗證四種判定情境:空版本/過舊/正常/解析失敗。
|
||
func TestCloudVersionStale(t *testing.T) {
|
||
cases := []struct {
|
||
name string
|
||
version string
|
||
checkOK bool
|
||
wantStale bool
|
||
}{
|
||
{
|
||
// 老實例:/health 可達但 bundle_version 為空字串 → 需要更新
|
||
name: "空版本(老實例)", version: "", checkOK: true, wantStale: true,
|
||
},
|
||
{
|
||
// 日期早於 minCloudBuilt → 需要更新
|
||
name: "過舊日期", version: "2026-07-27+abc1234", checkOK: true, wantStale: true,
|
||
},
|
||
{
|
||
// 日期等於 minCloudBuilt → 正常(剛好達標)
|
||
name: "正常(剛好達標)", version: "2026-07-28+abc1234", checkOK: true, wantStale: false,
|
||
},
|
||
{
|
||
// /health 不可達(解析失敗/逾時)→ 靜默不判定
|
||
name: "解析失敗(/health 不可達)", version: "", checkOK: false, wantStale: false,
|
||
},
|
||
|
||
// 🔴 2026-08-02 迴歸守衛(leo 實撞:兩帳號都更新到 1.4.1,卻**都**顯示需要更新且消不掉)。
|
||
// 病根:舊實作 `head < minCloudBuilt` 是**字串比較**,semver 進來後
|
||
// "1.4.1" < "2026-07-28" 恆為真 ⇒ 最新版被判過舊。
|
||
// 這幾則若變紅,代表版本比較又退回字串比較,或新格式沒被辨識。
|
||
{
|
||
name: "semver 最新版(1.4.1)不該被判過舊", version: "1.4.1", checkOK: true, wantStale: false,
|
||
},
|
||
{
|
||
name: "semver 剛好達標(1.4.0)", version: "1.4.0", checkOK: true, wantStale: false,
|
||
},
|
||
{
|
||
name: "semver 過舊(1.3.9)需要更新", version: "1.3.9", checkOK: true, wantStale: true,
|
||
},
|
||
{
|
||
// 字串比較會誤判成 "1.10.0" < "1.9.0";整數逐段比較才對
|
||
name: "semver 1.10.0 比 1.9.0 新(防字串比較)", version: "1.10.0", checkOK: true, wantStale: false,
|
||
},
|
||
{
|
||
// 舊格式仍須正確辨識——兩種格式並存期間,老實例不可被誤判成最新而收不到提示
|
||
name: "舊格式過舊仍要判過舊(相容)", version: "2026-07-01+deadbee", checkOK: true, wantStale: true,
|
||
},
|
||
}
|
||
for _, tc := range cases {
|
||
t.Run(tc.name, func(t *testing.T) {
|
||
got := cloudVersionStale(tc.version, tc.checkOK)
|
||
if got != tc.wantStale {
|
||
t.Errorf("cloudVersionStale(%q, %v) = %v,want %v", tc.version, tc.checkOK, got, tc.wantStale)
|
||
}
|
||
})
|
||
}
|
||
}
|