| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
- import { DataSource, Repository } from 'typeorm';
- import { PrintTaskService } from '../../src/services/print-task.service';
- import { FeiePrintTaskMt } from '../../src/entities/feie-print-task.mt.entity';
- import { FeiePrinterMt } from '../../src/entities/feie-printer.mt.entity';
- import type { FeieApiConfig, CreatePrintTaskDto } from '../../src/types/feie.types';
- import { FileLogger } from '@d8d/shared-utils';
- // Mock dependencies
- vi.mock('../../src/services/feie-api.service', () => {
- return {
- FeieApiService: vi.fn().mockImplementation(() => ({
- printReceipt: vi.fn().mockResolvedValue({ ret: 0, msg: 'success', data: '123456' }),
- queryOrderStatus: vi.fn().mockResolvedValue({ ret: 0, data: '已打印' })
- }))
- };
- });
- vi.mock('../../src/services/printer.service', () => {
- return {
- PrinterService: vi.fn().mockImplementation(() => ({}))
- };
- });
- vi.mock('@d8d/shared-crud', () => {
- return {
- GenericCrudService: vi.fn().mockImplementation(() => ({
- create: vi.fn(),
- findOne: vi.fn(),
- findMany: vi.fn(),
- update: vi.fn(),
- delete: vi.fn(),
- repository: {
- findAndCount: vi.fn()
- }
- }))
- };
- });
- // Mock the file logger and other exports from shared-utils
- vi.mock('@d8d/shared-utils', () => {
- const mockLogger = {
- info: vi.fn(),
- warn: vi.fn(),
- error: vi.fn(),
- debug: vi.fn(),
- log: vi.fn()
- };
- return {
- createServiceLogger: vi.fn().mockReturnValue(mockLogger),
- FileLogger: vi.fn().mockImplementation(() => mockLogger),
- // Mock other exports that might be needed
- jwt: {
- sign: vi.fn(),
- verify: vi.fn()
- },
- errorHandler: vi.fn(),
- parseWithAwait: vi.fn(),
- logger: {
- info: vi.fn(),
- warn: vi.fn(),
- error: vi.fn(),
- debug: vi.fn()
- },
- redis: {
- get: vi.fn(),
- set: vi.fn(),
- del: vi.fn()
- }
- };
- });
- describe('PrintTaskService 日志功能测试', () => {
- let printTaskService: PrintTaskService;
- let mockDataSource: DataSource;
- let mockPrinterRepository: Repository<FeiePrinterMt>;
- let mockLogger: any;
- const mockFeieConfig: FeieApiConfig = {
- baseUrl: 'http://api.feieyun.cn/Api/Open/',
- user: 'test_user',
- ukey: 'test_ukey'
- };
- beforeEach(() => {
- vi.clearAllMocks();
- vi.useFakeTimers();
- mockPrinterRepository = {
- findOne: vi.fn()
- } as unknown as Repository<FeiePrinterMt>;
- mockDataSource = {
- getRepository: vi.fn().mockReturnValue(mockPrinterRepository),
- query: vi.fn().mockResolvedValue([{ db_time: new Date() }])
- } as unknown as DataSource;
- // Get the mocked logger instance
- const { createServiceLogger } = require('@d8d/shared-utils');
- mockLogger = createServiceLogger();
- printTaskService = new PrintTaskService(mockDataSource, mockFeieConfig);
- });
- afterEach(() => {
- vi.useRealTimers();
- });
- describe('日志记录功能', () => {
- it('应该在创建打印任务时记录日志', async () => {
- const tenantId = 1;
- const taskDto: CreatePrintTaskDto = {
- printerSn: 'TEST123456',
- content: '测试打印内容',
- printType: 'RECEIPT',
- delaySeconds: 0
- };
- const mockPrinter: Partial<FeiePrinterMt> = {
- id: 1,
- tenantId,
- printerSn: taskDto.printerSn,
- printerStatus: 'ACTIVE'
- };
- const mockTask: Partial<FeiePrintTaskMt> = {
- id: 1,
- tenantId,
- taskId: 'FEIE_123456789_1234',
- printerSn: taskDto.printerSn,
- content: taskDto.content,
- printType: taskDto.printType,
- printStatus: 'PENDING'
- };
- // Mock dependencies
- vi.mocked(mockPrinterRepository.findOne).mockResolvedValue(mockPrinter as FeiePrinterMt);
- (printTaskService as any).create = vi.fn().mockResolvedValue(mockTask);
- (printTaskService as any).executePrintTask = vi.fn().mockResolvedValue(mockTask);
- await printTaskService.createPrintTask(tenantId, taskDto);
- // 验证日志器被正确创建
- const { createServiceLogger } = require('@d8d/shared-utils');
- expect(createServiceLogger).toHaveBeenCalledWith('feie-print-task-service');
- });
- it('应该在获取数据库时间失败时记录警告日志', async () => {
- const tenantId = 1;
- const taskDto: CreatePrintTaskDto = {
- printerSn: 'TEST123456',
- content: '测试打印内容',
- printType: 'RECEIPT',
- delaySeconds: 10
- };
- const mockPrinter: Partial<FeiePrinterMt> = {
- id: 1,
- tenantId,
- printerSn: taskDto.printerSn,
- printerStatus: 'ACTIVE'
- };
- const mockTask: Partial<FeiePrintTaskMt> = {
- id: 1,
- tenantId,
- taskId: 'FEIE_123456789_1234',
- printerSn: taskDto.printerSn,
- content: taskDto.content,
- printType: taskDto.printType,
- printStatus: 'DELAYED'
- };
- // Mock database query to fail
- vi.mocked(mockDataSource.query).mockRejectedValue(new Error('数据库连接失败'));
- vi.mocked(mockPrinterRepository.findOne).mockResolvedValue(mockPrinter as FeiePrinterMt);
- (printTaskService as any).create = vi.fn().mockResolvedValue(mockTask);
- await printTaskService.createPrintTask(tenantId, taskDto);
- // 验证警告日志被记录
- expect(mockLogger.warn).toHaveBeenCalledWith(
- expect.stringContaining('获取数据库时间失败,使用本地时间'),
- expect.any(Error)
- );
- });
- it('应该在执行打印任务时记录调试日志', async () => {
- const tenantId = 1;
- const taskId = 'FEIE_123456789_1234';
- const mockTask: Partial<FeiePrintTaskMt> = {
- id: 1,
- tenantId,
- taskId,
- printerSn: 'TEST123456',
- content: '测试内容',
- printType: 'RECEIPT',
- printStatus: 'PENDING',
- retryCount: 0,
- maxRetries: 3
- };
- const updatedTask: Partial<FeiePrintTaskMt> = {
- ...mockTask,
- printStatus: 'SUCCESS',
- printedAt: new Date()
- };
- // Mock dependencies
- (printTaskService as any).findOne = vi.fn().mockResolvedValue(mockTask);
- (printTaskService as any).update = vi.fn().mockResolvedValue(updatedTask);
- await printTaskService.executePrintTask(tenantId, taskId);
- // 验证调试日志被记录
- expect(mockLogger.debug).toHaveBeenCalledWith(
- '调用飞鹅API打印response',
- expect.objectContaining({ response: expect.any(Object) })
- );
- expect(mockLogger.debug).toHaveBeenCalledWith(
- '更新任务状态为成功updatedTask:',
- expect.objectContaining({ updatedTask: expect.any(Object) })
- );
- });
- it('应该在打印失败时记录错误日志并安排重试', async () => {
- const tenantId = 1;
- const taskId = 'FEIE_123456789_1234';
- const mockTask: Partial<FeiePrintTaskMt> = {
- id: 1,
- tenantId,
- taskId,
- printerSn: 'TEST123456',
- content: '测试内容',
- printType: 'RECEIPT',
- printStatus: 'PENDING',
- retryCount: 0,
- maxRetries: 3
- };
- // Mock dependencies
- (printTaskService as any).findOne = vi.fn().mockResolvedValue(mockTask);
- (printTaskService as any).update = vi.fn().mockImplementation(async (id, data) => ({
- ...mockTask,
- ...data
- }));
- // Mock printReceipt to throw error
- const mockFeieApiService = {
- printReceipt: vi.fn().mockRejectedValue(new Error('打印失败'))
- };
- (printTaskService as any).feieApiService = mockFeieApiService;
- await expect(printTaskService.executePrintTask(tenantId, taskId))
- .rejects
- .toThrow('打印失败');
- // 验证错误日志被记录
- expect(mockLogger.info).toHaveBeenCalledWith(
- 'executePrintTask执行失败:',
- expect.objectContaining({ error: expect.any(Error) })
- );
- expect(mockLogger.info).toHaveBeenCalledWith(
- 'maxRetries最大重试次数:',
- expect.objectContaining({ maxRetries: expect.any(Number) })
- );
- expect(mockLogger.info).toHaveBeenCalledWith(
- expect.stringContaining('打印任务失败,5000ms后重试')
- );
- });
- it('应该在订单号重复时记录信息日志并标记为成功', async () => {
- const tenantId = 1;
- const taskId = 'FEIE_123456789_1234';
- const mockTask: Partial<FeiePrintTaskMt> = {
- id: 1,
- tenantId,
- taskId,
- printerSn: 'TEST123456',
- content: '测试内容',
- printType: 'RECEIPT',
- printStatus: 'PENDING',
- retryCount: 0,
- maxRetries: 3
- };
- const updatedTask: Partial<FeiePrintTaskMt> = {
- ...mockTask,
- printStatus: 'SUCCESS',
- printedAt: new Date(),
- errorMessage: '订单号重复,飞鹅API已打印',
- retryCount: 1
- };
- // Mock dependencies
- (printTaskService as any).findOne = vi.fn().mockResolvedValue(mockTask);
- (printTaskService as any).update = vi.fn().mockResolvedValue(updatedTask);
- // Mock printReceipt to throw order duplicate error
- const mockFeieApiService = {
- printReceipt: vi.fn().mockRejectedValue(new Error('错误代码: -6, 订单号重复'))
- };
- (printTaskService as any).feieApiService = mockFeieApiService;
- const result = await printTaskService.executePrintTask(tenantId, taskId);
- // 验证信息日志被记录
- expect(mockLogger.info).toHaveBeenCalledWith(
- expect.stringContaining('打印任务 订单号重复,飞鹅API已打印,标记为成功')
- );
- expect(result.printStatus).toBe('SUCCESS');
- });
- it('应该在任务已经在打印中时记录警告日志', async () => {
- const tenantId = 1;
- const taskId = 'FEIE_123456789_1234';
- const mockTask: Partial<FeiePrintTaskMt> = {
- id: 1,
- tenantId,
- taskId,
- printerSn: 'TEST123456',
- content: '测试内容',
- printType: 'RECEIPT',
- printStatus: 'PRINTING', // 已经在打印中
- retryCount: 0,
- maxRetries: 3
- };
- // Mock dependencies
- (printTaskService as any).findOne = vi.fn().mockResolvedValue(mockTask);
- const result = await printTaskService.executePrintTask(tenantId, taskId);
- // 验证警告日志被记录
- expect(mockLogger.warn).toHaveBeenCalledWith(
- expect.stringContaining('打印任务 已经在打印中,跳过重复执行')
- );
- expect(result).toEqual(mockTask);
- });
- it('应该在回滚事务失败时记录警告日志', async () => {
- const tenantId = 1;
- const taskId = 'FEIE_123456789_1234';
- // Mock dependencies to throw error during transaction
- (printTaskService as any).findOne = vi.fn().mockRejectedValue(new Error('事务执行失败'));
- // Mock queryRunner to throw error during rollback
- const mockQueryRunner = {
- connect: vi.fn(),
- startTransaction: vi.fn(),
- rollbackTransaction: vi.fn().mockRejectedValue(new Error('回滚失败')),
- release: vi.fn()
- };
- (printTaskService as any).dataSource.createQueryRunner = vi.fn().mockReturnValue(mockQueryRunner);
- await expect(printTaskService.executePrintTask(tenantId, taskId))
- .rejects
- .toThrow('事务执行失败');
- // 验证警告日志被记录
- expect(mockLogger.warn).toHaveBeenCalledWith(
- expect.stringContaining('回滚事务失败'),
- expect.any(Error)
- );
- });
- it('应该在获取租户配置失败时记录警告日志', async () => {
- const tenantId = 1;
- const key = 'test_key';
- const defaultValue = 'default_value';
- // Mock config repository to throw error
- const mockConfigRepository = {
- findOne: vi.fn().mockRejectedValue(new Error('数据库查询失败'))
- };
- (printTaskService as any).configRepository = mockConfigRepository;
- const result = await (printTaskService as any).getTenantConfigValue(tenantId, key, defaultValue);
- // 验证警告日志被记录
- expect(mockLogger.warn).toHaveBeenCalledWith(
- expect.stringContaining(`[租户${tenantId}] 获取配置失败,key: ${key}`),
- expect.any(Error)
- );
- expect(result).toBe(defaultValue);
- });
- });
- describe('日志级别测试', () => {
- it('应该支持所有日志级别', async () => {
- // 测试各种日志级别
- await mockLogger.info('测试信息日志', { data: 'test' });
- await mockLogger.warn('测试警告日志', { data: 'test' });
- await mockLogger.error('测试错误日志', { data: 'test' });
- await mockLogger.debug('测试调试日志', { data: 'test' });
- expect(mockLogger.info).toHaveBeenCalledWith('测试信息日志', { data: 'test' });
- expect(mockLogger.warn).toHaveBeenCalledWith('测试警告日志', { data: 'test' });
- expect(mockLogger.error).toHaveBeenCalledWith('测试错误日志', { data: 'test' });
- expect(mockLogger.debug).toHaveBeenCalledWith('测试调试日志', { data: 'test' });
- });
- it('应该正确处理日志元数据', async () => {
- const testData = {
- taskId: 'FEIE_123456789_1234',
- tenantId: 1,
- status: 'PENDING',
- nested: {
- level1: {
- level2: 'value'
- }
- }
- };
- await mockLogger.info('测试结构化日志', testData);
- expect(mockLogger.info).toHaveBeenCalledWith(
- '测试结构化日志',
- testData
- );
- });
- });
- });
|