package db import ( "testing" "github.com/stretchr/testify/require" ) // TestBackfillPagePasswordVer 覆盖 2026-11-05 那个 P0 的数据面: // 新增列 AutoMigrate 只补 0,而 0 恰好等于「session 里没有授权记录」的零值, // 不回填的话存量页面密码在升级瞬间全部失效。 func TestBackfillPagePasswordVer(t *testing.T) { conn, clean := newTestDB(t) defer clean("users") mustCreate := func(domain string, pagePassword string, pageVer uint, askPassword string, askVer uint) *User { u := &User{ Name: domain, Email: domain + "@example.com", Password: "x", Domain: domain, PagePassword: pagePassword, PagePasswordVer: pageVer, AskPassword: askPassword, AskPasswordVer: askVer, } require.NoError(t, conn.Create(u).Error) return u } // 存量:有密码但版本号仍为默认 0 —— 必须被回填。 legacy := mustCreate("legacy", "hashed-page", 0, "hashed-ask", 0) // 已轮换过密码:版本号非 0,不能被重置。 rotated := mustCreate("rotated", "hashed-page", 3, "hashed-ask", 5) // 没有密码:版本号保持 0,回填不应凭空造出授权。 noPassword := mustCreate("nopassword", "", 0, "", 0) require.NoError(t, backfillPagePasswordVer(conn)) var gotLegacy, gotRotated, gotNoPassword User require.NoError(t, conn.First(&gotLegacy, legacy.ID).Error) require.NoError(t, conn.First(&gotRotated, rotated.ID).Error) require.NoError(t, conn.First(&gotNoPassword, noPassword.ID).Error) require.EqualValues(t, 1, gotLegacy.PagePasswordVer, "存量页面密码应回填为 1") require.EqualValues(t, 1, gotLegacy.AskPasswordVer, "存量提问密码应回填为 1") require.EqualValues(t, 3, gotRotated.PagePasswordVer, "已轮换的版本号不能被覆盖") require.EqualValues(t, 5, gotRotated.AskPasswordVer, "已轮换的版本号不能被覆盖") require.EqualValues(t, 0, gotNoPassword.PagePasswordVer, "没设密码的账号不应被写版本号") require.EqualValues(t, 0, gotNoPassword.AskPasswordVer, "没设密码的账号不应被写版本号") // 幂等:再跑一次不应把已回填的行推到 2。 require.NoError(t, backfillPagePasswordVer(conn)) require.NoError(t, conn.First(&gotLegacy, legacy.ID).Error) require.EqualValues(t, 1, gotLegacy.PagePasswordVer, "迁移必须幂等") }