| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- import { Agent } from './api/models';
- import { LEADER_STALE_MS, leaderHealth } from './leader-health';
- /**
- * 组长健康度。
- *
- * 组长制下所有需求都走组长,一旦掉线整组停摆。
- * 重点回归:
- * ① 心跳超时能被识别(光看 status 会误判成「在忙」)
- * ② 没设组长要提示
- * ③ 在忙 ≠ 掉线(提示要区别开)
- */
- describe('leader-health', () => {
- const NOW = new Date('2026-10-27T12:00:00Z').getTime();
- function agent(over: Partial<Agent> = {}): Agent {
- return {
- id: 'lj',
- name: 'lj',
- status: 'idle',
- matrixReady: true,
- unread: 0,
- heartbeatAt: new Date(NOW - 30_000).toISOString(), // 30 秒前,新鲜
- ...over,
- };
- }
- it('没设组长 → 提示去设置', () => {
- const r = leaderHealth(undefined, NOW);
- expect(r.health).toBe('none');
- expect(r.warn).toBeTrue();
- expect(r.suggestReplace).toBeTrue();
- expect(r.message).toContain('还没有设置组长');
- });
- it('组长正常 → 不提示', () => {
- const r = leaderHealth(agent(), NOW);
- expect(r.health).toBe('ok');
- expect(r.warn).toBeFalse();
- });
- it('组长在忙(有具体任务)→ 提示,但不建议更换', () => {
- const r = leaderHealth(agent({ status: 'running', currentTask: '处理企业微信对话' }), NOW);
- expect(r.health).toBe('busy');
- expect(r.warn).toBeTrue();
- expect(r.suggestReplace).toBeFalse();
- expect(r.message).toContain('正在处理');
- });
- it('🔴 status=running 但 currentTask 为空 → 不算忙(实测:上报器常态)', () => {
- const r = leaderHealth(agent({ status: 'running', currentTask: '' }), NOW);
- expect(r.health).toBe('ok');
- expect(r.warn).toBeFalse();
- });
- it('🔴 组长离线 → 建议更换', () => {
- const r = leaderHealth(agent({ status: 'offline' }), NOW);
- expect(r.health).toBe('offline');
- expect(r.suggestReplace).toBeTrue();
- expect(r.message).toContain('建议更换');
- });
- it('组长已停止 → 建议更换', () => {
- expect(leaderHealth(agent({ status: 'stopped' }), NOW).suggestReplace).toBeTrue();
- });
- it('🔴 status 是 running 但心跳超时 → 判定掉线(不能当成在忙)', () => {
- const stale = new Date(NOW - LEADER_STALE_MS - 60_000).toISOString();
- const r = leaderHealth(agent({ status: 'running', heartbeatAt: stale }), NOW);
- expect(r.health).toBe('stale');
- expect(r.suggestReplace).toBeTrue();
- expect(r.message).toContain('没有上报');
- });
- it('心跳刚好在阈值内 → 不算掉线', () => {
- const fresh = new Date(NOW - LEADER_STALE_MS + 10_000).toISOString();
- const r = leaderHealth(agent({ heartbeatAt: fresh }), NOW);
- expect(r.health).toBe('ok');
- });
- it('没有心跳字段 → 不据此判掉线(避免误报)', () => {
- const r = leaderHealth(agent({ heartbeatAt: undefined }), NOW);
- expect(r.health).toBe('ok');
- });
- it('心跳时间无法解析 → 不据此判掉线', () => {
- const r = leaderHealth(agent({ heartbeatAt: 'not-a-date' }), NOW);
- expect(r.health).toBe('ok');
- });
- it('提示里带上组长名字(用户知道是哪个)', () => {
- const r = leaderHealth(agent({ name: 'lj', status: 'offline' }), NOW);
- expect(r.message).toContain('lj');
- });
- });
|