279 lines
9.2 KiB
TypeScript
279 lines
9.2 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { CommandLog, createCommandLog } from '../../src/commands/CommandLog';
|
|
import { Command, CommandActionType, CommandExecutionResult, StepResult } from '../../src/commands/Command';
|
|
|
|
describe('CommandLog', () => {
|
|
let log: CommandLog;
|
|
|
|
beforeEach(() => {
|
|
log = createCommandLog();
|
|
});
|
|
|
|
const sampleCommand: Command = {
|
|
id: 'test-command',
|
|
name: 'Test Command',
|
|
steps: [
|
|
{ action: CommandActionType.CreateMeeple, params: { id: 'm1', color: 'red' } },
|
|
],
|
|
};
|
|
|
|
const sampleResult: CommandExecutionResult = {
|
|
success: true,
|
|
executedSteps: 1,
|
|
totalSteps: 1,
|
|
};
|
|
|
|
const sampleStepResults: StepResult[] = [
|
|
{
|
|
stepIndex: 0,
|
|
action: CommandActionType.CreateMeeple,
|
|
success: true,
|
|
params: { id: 'm1', color: 'red' },
|
|
},
|
|
];
|
|
|
|
describe('log', () => {
|
|
it('should log a command execution', () => {
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
|
|
const entries = log.getEntries();
|
|
expect(entries.length).toBe(1);
|
|
expect(entries[0].commandId).toBe('test-command');
|
|
expect(entries[0].commandName).toBe('Test Command');
|
|
expect(entries[0].result.success).toBe(true);
|
|
});
|
|
|
|
it('should add timestamp to log entry', () => {
|
|
const beforeTime = Date.now();
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
const afterTime = Date.now();
|
|
|
|
const entry = log.getEntries()[0];
|
|
expect(entry.timestamp).toBeGreaterThanOrEqual(beforeTime);
|
|
expect(entry.timestamp).toBeLessThanOrEqual(afterTime);
|
|
});
|
|
|
|
it('should log multiple entries', () => {
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
|
|
expect(log.getEntries().length).toBe(3);
|
|
});
|
|
});
|
|
|
|
describe('getFilteredEntries', () => {
|
|
it('should filter by commandId', () => {
|
|
const command1: Command = { ...sampleCommand, id: 'cmd-1', name: 'Command 1' };
|
|
const command2: Command = { ...sampleCommand, id: 'cmd-2', name: 'Command 2' };
|
|
|
|
log.log(command1, sampleResult, sampleStepResults);
|
|
log.log(command2, sampleResult, sampleStepResults);
|
|
log.log(command1, sampleResult, sampleStepResults);
|
|
|
|
const filtered = log.getFilteredEntries({ commandId: 'cmd-1' });
|
|
expect(filtered.length).toBe(2);
|
|
});
|
|
|
|
it('should filter by success status', () => {
|
|
const successResult: CommandExecutionResult = { success: true, executedSteps: 1, totalSteps: 1 };
|
|
const failResult: CommandExecutionResult = { success: false, executedSteps: 0, totalSteps: 1, error: 'Failed' };
|
|
|
|
log.log(sampleCommand, successResult, sampleStepResults);
|
|
log.log(sampleCommand, failResult, []);
|
|
log.log(sampleCommand, successResult, sampleStepResults);
|
|
|
|
const failed = log.getFilteredEntries({ success: false });
|
|
expect(failed.length).toBe(1);
|
|
|
|
const successful = log.getFilteredEntries({ success: true });
|
|
expect(successful.length).toBe(2);
|
|
});
|
|
|
|
it('should filter by time range', () => {
|
|
const startTime = Date.now();
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
|
|
// 模拟时间流逝
|
|
const midTime = Date.now() + 100;
|
|
|
|
// 手动创建一个带时间戳的条目来测试时间过滤
|
|
const entries = log.getEntries();
|
|
expect(entries[0].timestamp).toBeGreaterThanOrEqual(startTime);
|
|
});
|
|
});
|
|
|
|
describe('getCommandHistory', () => {
|
|
it('should return history for a specific command', () => {
|
|
const command1: Command = { ...sampleCommand, id: 'cmd-1', name: 'Command 1' };
|
|
const command2: Command = { ...sampleCommand, id: 'cmd-2', name: 'Command 2' };
|
|
|
|
log.log(command1, sampleResult, sampleStepResults);
|
|
log.log(command2, sampleResult, sampleStepResults);
|
|
log.log(command1, sampleResult, sampleStepResults);
|
|
|
|
const history = log.getCommandHistory('cmd-1');
|
|
expect(history.length).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe('getFailedCommands', () => {
|
|
it('should return only failed commands', () => {
|
|
const successResult: CommandExecutionResult = { success: true, executedSteps: 1, totalSteps: 1 };
|
|
const failResult: CommandExecutionResult = { success: false, executedSteps: 0, totalSteps: 1, error: 'Error' };
|
|
|
|
log.log(sampleCommand, successResult, sampleStepResults);
|
|
log.log(sampleCommand, failResult, []);
|
|
log.log(sampleCommand, successResult, sampleStepResults);
|
|
|
|
const failed = log.getFailedCommands();
|
|
expect(failed.length).toBe(1);
|
|
expect(failed[0].result.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getSuccessfulCommands', () => {
|
|
it('should return only successful commands', () => {
|
|
const successResult: CommandExecutionResult = { success: true, executedSteps: 1, totalSteps: 1 };
|
|
const failResult: CommandExecutionResult = { success: false, executedSteps: 0, totalSteps: 1, error: 'Error' };
|
|
|
|
log.log(sampleCommand, successResult, sampleStepResults);
|
|
log.log(sampleCommand, failResult, []);
|
|
log.log(sampleCommand, successResult, sampleStepResults);
|
|
|
|
const successful = log.getSuccessfulCommands();
|
|
expect(successful.length).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe('clear', () => {
|
|
it('should clear all log entries', () => {
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
|
|
expect(log.getEntries().length).toBe(2);
|
|
|
|
log.clear();
|
|
|
|
expect(log.getEntries().length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('exportToJson', () => {
|
|
it('should export logs as JSON string', () => {
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
|
|
const json = log.exportToJson();
|
|
const parsed = JSON.parse(json);
|
|
|
|
expect(Array.isArray(parsed)).toBe(true);
|
|
expect(parsed.length).toBe(1);
|
|
expect(parsed[0].commandId).toBe('test-command');
|
|
});
|
|
});
|
|
|
|
describe('getCount', () => {
|
|
it('should return the number of log entries', () => {
|
|
expect(log.getCount()).toBe(0);
|
|
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
expect(log.getCount()).toBe(1);
|
|
|
|
log.log(sampleCommand, sampleResult, sampleStepResults);
|
|
expect(log.getCount()).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe('getLastEntry', () => {
|
|
it('should return the last log entry', () => {
|
|
const command1: Command = { ...sampleCommand, id: 'cmd-1', name: 'First' };
|
|
const command2: Command = { ...sampleCommand, id: 'cmd-2', name: 'Last' };
|
|
|
|
log.log(command1, sampleResult, sampleStepResults);
|
|
log.log(command2, sampleResult, sampleStepResults);
|
|
|
|
const lastEntry = log.getLastEntry();
|
|
expect(lastEntry).not.toBeNull();
|
|
expect(lastEntry?.commandId).toBe('cmd-2');
|
|
});
|
|
|
|
it('should return null when log is empty', () => {
|
|
const lastEntry = log.getLastEntry();
|
|
expect(lastEntry).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('Queue management', () => {
|
|
describe('enqueue', () => {
|
|
it('should add command to queue', () => {
|
|
const queued = log.enqueue(sampleCommand);
|
|
|
|
expect(queued.id).toBe('test-command');
|
|
expect(log.getQueueLength()).toBe(1);
|
|
});
|
|
|
|
it('should set initial status to Pending', () => {
|
|
const queued = log.enqueue(sampleCommand);
|
|
expect(queued.status).toBe('pending');
|
|
});
|
|
});
|
|
|
|
describe('dequeue', () => {
|
|
it('should remove and return the first command from queue', () => {
|
|
const command1: Command = { ...sampleCommand, id: 'cmd-1' };
|
|
const command2: Command = { ...sampleCommand, id: 'cmd-2' };
|
|
|
|
log.enqueue(command1);
|
|
log.enqueue(command2);
|
|
|
|
const dequeued = log.dequeue();
|
|
expect(dequeued?.command.id).toBe('cmd-1');
|
|
expect(log.getQueueLength()).toBe(1);
|
|
});
|
|
|
|
it('should return null when queue is empty', () => {
|
|
const dequeued = log.dequeue();
|
|
expect(dequeued).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('updateQueueStatus', () => {
|
|
it('should update command status in queue', () => {
|
|
log.enqueue(sampleCommand);
|
|
|
|
log.updateQueueStatus('test-command', 'executing');
|
|
const queue = log.getQueue();
|
|
expect(queue[0].status).toBe('executing');
|
|
});
|
|
|
|
it('should set executedAt and result when status is Completed', () => {
|
|
const result: CommandExecutionResult = { success: true, executedSteps: 1, totalSteps: 1 };
|
|
log.enqueue(sampleCommand);
|
|
|
|
const beforeTime = Date.now();
|
|
log.updateQueueStatus('test-command', 'completed', result);
|
|
const afterTime = Date.now();
|
|
|
|
const queue = log.getQueue();
|
|
expect(queue[0].status).toBe('completed');
|
|
expect(queue[0].result).toEqual(result);
|
|
expect(queue[0].executedAt).toBeGreaterThanOrEqual(beforeTime);
|
|
expect(queue[0].executedAt).toBeLessThanOrEqual(afterTime);
|
|
});
|
|
});
|
|
|
|
describe('clearQueue', () => {
|
|
it('should clear all queued commands', () => {
|
|
log.enqueue(sampleCommand);
|
|
log.enqueue(sampleCommand);
|
|
|
|
expect(log.getQueueLength()).toBe(2);
|
|
|
|
log.clearQueue();
|
|
|
|
expect(log.getQueueLength()).toBe(0);
|
|
});
|
|
});
|
|
});
|
|
});
|