alarm_review.test.mjs 5.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. // PostgreSQL 兼容性回归,不替代 KingbaseES 最终验收;不连接实际数据库。
  2. // node --test alarm_review.test.mjs;通过 PGLITE_MODULE 指向已有 PGlite ESM 模块。
  3. import { readFile } from 'node:fs/promises'
  4. import { pathToFileURL } from 'node:url'
  5. import assert from 'node:assert/strict'
  6. import { test, after } from 'node:test'
  7. const { PGlite } = await import(process.env.PGLITE_MODULE ? pathToFileURL(process.env.PGLITE_MODULE).href : '@electric-sql/pglite')
  8. const db = new PGlite()
  9. const sql = await readFile(new URL('../migration_alarm_review.sql', import.meta.url), 'utf8')
  10. await db.exec(`
  11. CREATE SCHEMA app_user;
  12. CREATE TABLE app_user.alarm_data(id varchar(64) PRIMARY KEY, alarm_status integer DEFAULT 0, alarm_level integer,
  13. warning_code text, warning_type text, remark text, actual_value numeric, min_value numeric, max_value numeric,
  14. create_time timestamp, work_order_id int8);
  15. CREATE TABLE app_user.work_order_log(log_id int8, work_order_id int8, oper_desc text, attach_url text,
  16. oper_user_id int8, oper_user_name text, oper_time timestamp);
  17. CREATE TABLE app_user.sys_menu(menu_id int8 PRIMARY KEY, menu_name text, parent_id int8, order_num integer,
  18. path text, component text, query text, is_frame integer, is_cache integer, menu_type text, visible text,
  19. status text, perms text, icon text, create_by text, create_time timestamp, update_time timestamp);
  20. CREATE TABLE app_user.sys_role_menu(role_id int8, menu_id int8, PRIMARY KEY(role_id, menu_id));
  21. INSERT INTO app_user.alarm_data(id,alarm_level) VALUES ('history',1);
  22. INSERT INTO app_user.sys_menu(menu_id,parent_id,path,component) VALUES
  23. (2118,100,'audit','water'),(2142,101,'bjsh','drainage'),(2097,102,'krqildjc','gas'),(2024,103,'alarmList','manhole'),(3000,104,'keep','keep');
  24. INSERT INTO app_user.sys_role_menu VALUES (9,2118),(9,2142),(9,2097),(9,2024);
  25. `)
  26. await db.exec(sql)
  27. const rows = async query => (await db.query(query)).rows
  28. after(() => db.close())
  29. test('int8 primary key uses dedicated owned sequence, no auxiliary source key or history backfill', async () => {
  30. const [column] = await rows("SELECT udt_name,column_default FROM information_schema.columns WHERE table_schema='app_user' AND table_name='alarm_log' AND column_name='log_id'")
  31. assert.equal(column.udt_name, 'int8'); assert.match(column.column_default, /nextval\('app_user.alarm_log_id_seq'::regclass\)/)
  32. assert.equal((await rows("SELECT pg_get_serial_sequence('app_user.alarm_log','log_id') AS seq"))[0].seq, 'app_user.alarm_log_id_seq')
  33. assert.equal((await rows('SELECT * FROM app_user.alarm_log')).length, 0)
  34. assert.equal((await rows("SELECT column_name FROM information_schema.columns WHERE table_schema='app_user' AND column_name='source_key'")).length, 0)
  35. assert.equal((await rows("SELECT audit_status,alarm_level FROM app_user.alarm_data WHERE id='history'"))[0].alarm_level, 1)
  36. })
  37. test('four existing menu IDs get alarmAudit and exact independent scopes, unrelated menu untouched', async () => {
  38. const menus = await rows('SELECT * FROM app_user.sys_menu WHERE menu_id IN (2118,2142,2097,2024) ORDER BY menu_id')
  39. const scope = { 2118:{rootTypeId:1}, 2142:{rootTypeId:2}, 2097:{rootTypeId:3,warning_code:'WARN-GAS-CONCENTRATION'}, 2024:{rootTypeId:4} }
  40. for (const menu of menus) {
  41. assert.equal(menu.path, 'alarmAudit'); assert.equal(menu.component, 'subSystem/alarm/common/audit')
  42. assert.deepEqual(JSON.parse(menu.query), scope[menu.menu_id]); assert.equal(menu.perms,'alarm:review:list')
  43. }
  44. assert.equal((await rows('SELECT path FROM app_user.sys_menu WHERE menu_id=3000'))[0].path,'keep')
  45. assert.equal((await rows("SELECT * FROM app_user.sys_menu WHERE perms='alarm:review:audit'")).length,4)
  46. })
  47. test('repeated deployment preserves existing logs, IDs and intentional permission revocations', async () => {
  48. const oldLogs = await rows('SELECT log_id FROM app_user.alarm_log ORDER BY log_id')
  49. await db.exec("DELETE FROM app_user.sys_role_menu WHERE menu_id IN (SELECT menu_id FROM app_user.sys_menu WHERE parent_id=2118 AND perms='alarm:review:audit')")
  50. await db.exec(sql)
  51. assert.deepEqual(await rows('SELECT log_id FROM app_user.alarm_log ORDER BY log_id'), oldLogs)
  52. assert.equal((await rows("SELECT * FROM app_user.sys_menu WHERE perms='alarm:review:audit'")).length,4)
  53. assert.equal((await rows("SELECT * FROM app_user.sys_role_menu WHERE menu_id IN (SELECT menu_id FROM app_user.sys_menu WHERE parent_id=2118 AND perms='alarm:review:audit')")).length,0)
  54. await db.exec("INSERT INTO app_user.alarm_data(id) VALUES ('a2')")
  55. assert.equal((await rows("SELECT * FROM app_user.alarm_log WHERE alarm_id='a2'")).length,0)
  56. })
  57. test('transaction rollback also rolls back initialized logs', async () => {
  58. await db.exec("BEGIN; INSERT INTO app_user.alarm_data(id) VALUES ('rolled-back'); ROLLBACK;")
  59. assert.equal((await rows("SELECT * FROM app_user.alarm_log WHERE alarm_id='rolled-back'")).length,0)
  60. await assert.rejects(db.exec("UPDATE app_user.alarm_data SET audit_status=3 WHERE id='a2'"))
  61. })
  62. test('schema contains no stored lifecycle functions or triggers',async()=>{
  63. assert.equal((await rows("SELECT * FROM pg_trigger WHERE tgname IN ('trg_alarm_lifecycle_log','trg_work_order_alarm_log')")).length,0)
  64. assert.deepEqual(await rows("SELECT to_regprocedure('app_user.record_alarm_lifecycle()') AS lifecycle,to_regprocedure('app_user.record_alarm_work_order_log()') AS mirror"),[{lifecycle:null,mirror:null}])
  65. })