108 lines
4.9 KiB
JavaScript
108 lines
4.9 KiB
JavaScript
// MySQL 存储层自测:会往库里写几条 TEST- 开头的测试数据,跑完自动删掉
|
||
// 用法:node server/test-db.js(需要 config.js 里配好 db)
|
||
const assert = require('assert')
|
||
const store = require('./store.js')
|
||
const { getPool, settings } = require('./db.js')
|
||
|
||
const TEST_OPENID = 'oTestStoreUser'
|
||
|
||
async function main() {
|
||
if (store.backend !== 'mysql') {
|
||
throw new Error('现在走的是 JSONL 后端:请在 config.js 里配好 db(库名 + 账号)再跑这个自测')
|
||
}
|
||
await store.ready()
|
||
|
||
const outTradeNo = 'TEST' + Date.now()
|
||
const createdAt = Date.now()
|
||
|
||
try {
|
||
await store.saveOrder({
|
||
outTradeNo,
|
||
openid: TEST_OPENID,
|
||
productId: '10001',
|
||
env: 0,
|
||
amount: 3900,
|
||
status: 'created',
|
||
createdAt,
|
||
})
|
||
|
||
const created = await store.get(outTradeNo)
|
||
assert.strictEqual(created.openid, TEST_OPENID)
|
||
assert.strictEqual(created.amount, 3900)
|
||
assert.strictEqual(created.code, '', '刚下单时不该有激活码')
|
||
assert.strictEqual(created.createdAt, createdAt)
|
||
|
||
// 时间列要是可读的 DATETIME(不是时间戳),且毫秒能原样存取
|
||
const [columnTypes] = await getPool().query(
|
||
`SELECT DATA_TYPE FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = 'codes' AND COLUMN_NAME = 'created_at'`,
|
||
[settings.database]
|
||
)
|
||
assert.strictEqual(columnTypes[0].DATA_TYPE, 'datetime', '时间列应该是 DATETIME,不该是时间戳')
|
||
|
||
const delivered = await store.assignCode(outTradeNo, { wxOrderId: 'wx-test-1', paidFee: 3900 })
|
||
assert.ok(/^[0-9A-HJKMNP-TV-Z]{4}(-[0-9A-HJKMNP-TV-Z]{4}){3}$/.test(delivered.code), delivered.code)
|
||
assert.strictEqual(delivered.status, 'delivered')
|
||
|
||
// 幂等:同一单再发一次还是同一张码(唯一索引挡住)
|
||
const again = await store.assignCode(outTradeNo, {})
|
||
assert.strictEqual(again.code, delivered.code)
|
||
|
||
let mine = await store.listByOpenid(TEST_OPENID)
|
||
assert.deepStrictEqual(mine.map((o) => o.code), [delivered.code])
|
||
|
||
await store.markNotified(outTradeNo)
|
||
assert.strictEqual((await store.get(outTradeNo)).notified, true)
|
||
|
||
// 退款后码作废:从「我的」和待发货里都消失,但记录还在
|
||
await store.markRefunded(outTradeNo, 'R' + outTradeNo)
|
||
mine = await store.listByOpenid(TEST_OPENID)
|
||
assert.deepStrictEqual(mine, [], '退款后不该再出现在我的激活码里')
|
||
const [codeRows] = await getPool().query('SELECT status FROM codes WHERE out_trade_no = ?', [outTradeNo])
|
||
assert.strictEqual(codeRows[0].status, 'revoked')
|
||
|
||
// 价目表播种:至少有四个道具,价格和 MP 后台一致
|
||
const goods = await store.listGoods()
|
||
assert.ok(goods.length >= 4, 'goods 表应该有播种的价目表')
|
||
assert.strictEqual(goods.find((g) => g.productId === '10000').price, 9900)
|
||
assert.strictEqual(goods.find((g) => g.productId === '90001').price, 10)
|
||
// 文案配置表:默认值会播种进去,备注列告诉你在哪显示
|
||
const settings = await store.getSettings()
|
||
assert.strictEqual(settings['buy.title'], '选择套餐')
|
||
const [copyRows] = await getPool().query(`SELECT remark FROM settings WHERE cfg_key = 'buy.title'`)
|
||
assert.strictEqual(copyRows[0].remark, '开通页的大标题')
|
||
|
||
const stats = await store.stats()
|
||
assert.ok(stats.orders >= 1)
|
||
assert.ok(stats.users >= 1, '用户表应该有记录')
|
||
|
||
// 用户表:首次使用时间建一次就不该再被覆盖,管理员标志默认 0
|
||
const [userRows] = await getPool().query('SELECT * FROM users WHERE openid = ?', [TEST_OPENID])
|
||
assert.strictEqual(userRows.length, 1)
|
||
assert.strictEqual(userRows[0].is_admin, 0)
|
||
const firstSeen = userRows[0].created_at.getTime()
|
||
await store.touchUser(TEST_OPENID)
|
||
const [againUsers] = await getPool().query('SELECT created_at, last_seen_at FROM users WHERE openid = ?', [TEST_OPENID])
|
||
assert.strictEqual(againUsers[0].created_at.getTime(), firstSeen, '首次使用时间不该被覆盖')
|
||
assert.ok(againUsers[0].last_seen_at.getTime() >= firstSeen)
|
||
|
||
// 管理员标志从 users.is_admin 读
|
||
assert.strictEqual((await store.getUser(TEST_OPENID)).isAdmin, false)
|
||
await getPool().query('UPDATE users SET is_admin = 1 WHERE openid = ?', [TEST_OPENID])
|
||
assert.strictEqual((await store.getUser(TEST_OPENID)).isAdmin, true)
|
||
|
||
console.log(`数据库自测通过(当前库里 ${stats.orders} 笔单 / ${stats.codes} 个码 / ${stats.users} 个用户)`)
|
||
} finally {
|
||
// 收尾:把测试数据删掉,别脏了真库
|
||
await getPool().query('DELETE FROM codes WHERE out_trade_no = ?', [outTradeNo])
|
||
await getPool().query('DELETE FROM orders WHERE out_trade_no = ?', [outTradeNo])
|
||
await getPool().query('DELETE FROM users WHERE openid = ?', [TEST_OPENID])
|
||
await getPool().end()
|
||
}
|
||
}
|
||
|
||
main().catch((err) => {
|
||
console.error('数据库自测失败:', err.message)
|
||
process.exit(1)
|
||
})
|