Files
Web_BLS_Heartbeat_Server/test/stats.test.js
XuJiacheng 2f8857f98e feat: 添加 G5 独立写入功能
- 新增 G5 数据库连接配置与可关闭的写入开关
- 在现有 legacy/G4 写入成功路径后,追加独立的 G5 写入流程
- G5 使用与 G4 相同的数据结构映射,但不写入 guid,由数据库自生成 int4 guid
- room_status 新增 G5 独立 upsert 写入路径,并保留旧表与 G5 表的独立开关
- 新增 G5 写入统计与启动摘要输出
- 更新 StatsCounters 和 StatsReporter 以支持 G5 统计
- 增加测试覆盖,确保 G5 写入逻辑与 room_status 的独立执行
- 新增 G5 相关数据库表结构 SQL 文件
2026-03-10 16:29:24 +08:00

89 lines
3.3 KiB
JavaScript

import assert from 'node:assert/strict';
import { StatsCounters, StatsReporter } from '../src/stats/statsManager.js';
import { HeartbeatProcessor } from '../src/processor/heartbeatProcessor.js';
describe('StatsCounters', () => {
it('snapshots and resets minute counters atomically', () => {
const stats = new StatsCounters();
stats.incDbWritten(3);
stats.incFiltered(2);
stats.incKafkaPulled(5);
stats.incDbWriteFailed(4);
stats.incG5Written(6);
stats.incG5WriteFailed(1);
const first = stats.snapshotAndResetMinute();
assert.equal(first.dbWritten, 3n);
assert.equal(first.filtered, 2n);
assert.equal(first.kafkaPulled, 5n);
assert.equal(first.dbWriteFailed, 4n);
assert.equal(first.g5Written, 6n);
assert.equal(first.g5WriteFailed, 1n);
const second = stats.snapshotAndResetMinute();
assert.equal(second.dbWritten, 0n);
assert.equal(second.filtered, 0n);
assert.equal(second.kafkaPulled, 0n);
assert.equal(second.dbWriteFailed, 0n);
assert.equal(second.g5Written, 0n);
assert.equal(second.g5WriteFailed, 0n);
});
});
describe('StatsReporter', () => {
it('writes all [STATS] info logs to redis console', () => {
const stats = new StatsCounters();
stats.incDbWritten(7);
stats.incFiltered(8);
stats.incKafkaPulled(9);
stats.incDbWriteFailed(2);
stats.incG5Written(5);
stats.incG5WriteFailed(1);
const calls = { push: [] };
const redis = {
isEnabled: () => true,
pushConsoleLog: ({ level, message, metadata }) => {
calls.push.push({ level, message, metadata });
},
};
const reporter = new StatsReporter({ redis, stats });
reporter.flushOnce();
assert.equal(calls.push.length, 11);
for (const c of calls.push) assert.equal(c.level, 'info');
assert.match(calls.push[0].message, /Legacy写入量: 7条$/);
assert.match(calls.push[1].message, /Legacy写入失败量: 2条$/);
assert.match(calls.push[2].message, /G4Hot写入量: 0条$/);
assert.match(calls.push[3].message, /G4Hot写入失败量: 0条$/);
assert.match(calls.push[4].message, /G5写入量: 5条$/);
assert.match(calls.push[5].message, /G5写入失败量: 1条$/);
assert.match(calls.push[6].message, /RoomStatus写入量: 0条$/);
assert.match(calls.push[7].message, /RoomStatus失败量: 0条$/);
assert.match(calls.push[8].message, /G4Hot错误表插入量: 0条$/);
assert.match(calls.push[9].message, /数据过滤量: 8条$/);
assert.match(calls.push[10].message, /Kafka拉取量: 9条$/);
});
});
describe('HeartbeatProcessor db write error logging', () => {
it('emits [ERROR] warn log with raw data', () => {
const calls = { warn: [] };
const redis = {
isEnabled: () => true,
pushConsoleLog: ({ level, message }) => {
if (level === 'warn') calls.warn.push(message);
},
};
const processor = new HeartbeatProcessor({ batchSize: 1, batchTimeout: 10 }, {}, { redis });
processor._emitDbWriteError(new Error('boom'), [{ a: 1 }]);
assert.equal(calls.warn.length >= 1, true);
assert.match(calls.warn[0], /^\[ERROR\] \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} db_write_failed: /);
assert.match(calls.warn[0], /"errorId":"db_write_failed"/);
assert.match(calls.warn[0], /"rawData":\{"a":1\}/);
});
});