test(agent):回填回归测试——原生 SQL 造 NULL 老行走真实心跳+install 接口

This commit is contained in:
Muse
2026-10-22 14:45:57 +00:00
parent 8901267867
commit 5c432205ad
@@ -123,6 +123,62 @@ func TestAgentTokenBackfillOnAuthenticatedRequest(t *testing.T) {
}
}
// Regression for the production failure of the first V1.0.0 deployment:
// rows that existed before item 19 got token_plain from AutoMigrate as
// SQL NULL, not ”, and the original guard `token_plain = ”` never
// matches NULL — the backfill silently never fired on any legacy node.
// Seed the row exactly as production has it (raw SQL, explicit NULL)
// instead of through GORM, which would write ”.
func TestAgentTokenBackfillFromNullLegacyRow(t *testing.T) {
engine, node := setupBackfillTest(t)
const token = "legacy-token-backfill-00000000000000000004"
db := database.GetDB()
if err := db.Exec(
"INSERT INTO agent_nodes (token_hash, token_prefix, token_plain, name, node_id, last_seen, created_at, updated_at) VALUES (?, ?, NULL, ?, ?, 0, 0, 0)",
hashAgentToken(token), token[:12], "backfill-node", node.Id,
).Error; err != nil {
t.Fatalf("seed NULL legacy row: %v", err)
}
var seeded model.AgentNode
if err := db.Where("token_hash = ?", hashAgentToken(token)).First(&seeded).Error; err != nil {
t.Fatalf("load seeded row: %v", err)
}
var nullRows int
if err := db.Raw("SELECT COUNT(*) FROM agent_nodes WHERE id = ? AND token_plain IS NULL", seeded.Id).Scan(&nullRows).Error; err != nil {
t.Fatalf("NULL check: %v", err)
}
if nullRows != 1 {
t.Fatalf("seeded row is not SQL NULL as intended (null rows = %d)", nullRows)
}
if code := heartbeatWith(engine, token); code != http.StatusOK {
t.Fatalf("heartbeat with valid token: status %d", code)
}
if row := reloadAgent(t, seeded.Id); row.TokenPlain != token {
t.Fatalf("token not backfilled from NULL legacy row: %q", row.TokenPlain)
}
req := httptest.NewRequest(http.MethodGet, "/panel/api/agent/install/"+strconv.Itoa(node.Id), nil)
rec := httptest.NewRecorder()
engine.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("install endpoint: status %d", rec.Code)
}
var resp struct {
Success bool `json:"success"`
Obj struct {
Token string `json:"token"`
HasToken bool `json:"hasToken"`
} `json:"obj"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
t.Fatalf("install response not JSON: %v", err)
}
if !resp.Success || !resp.Obj.HasToken || resp.Obj.Token != token {
t.Fatalf("install endpoint did not return the backfilled token: %+v", resp.Obj)
}
}
func TestAgentTokenNoBackfillOnFailedAuth(t *testing.T) {
engine, node := setupBackfillTest(t)
const token = "legacy-token-backfill-00000000000000000002"