chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 单元测试: deviceId
|
||||
*
|
||||
* 测试设备 ID 生成、缓存与异常回退逻辑
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
// Mock electron-log
|
||||
vi.mock('electron-log', () => ({
|
||||
default: {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock node-machine-id
|
||||
const mockMachineIdSync = vi.fn();
|
||||
vi.mock('node-machine-id', () => ({
|
||||
machineIdSync: (...args: unknown[]) => mockMachineIdSync(...args),
|
||||
}));
|
||||
|
||||
// Mock os.hostname
|
||||
const mockHostname = vi.fn(() => 'mock-hostname');
|
||||
vi.mock('os', () => ({
|
||||
hostname: () => mockHostname(),
|
||||
}));
|
||||
|
||||
describe('deviceId', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetModules();
|
||||
mockMachineIdSync.mockReturnValue('mock-machine-id');
|
||||
mockHostname.mockReturnValue('mock-hostname');
|
||||
});
|
||||
|
||||
it('should return a 64-char hex string', async () => {
|
||||
const { getDeviceId } = await import('./deviceId');
|
||||
const id = getDeviceId();
|
||||
|
||||
expect(id).toMatch(/^[0-9a-f]{64}$/);
|
||||
});
|
||||
|
||||
it('should hash machineId + salt with SHA-256', async () => {
|
||||
const { getDeviceId } = await import('./deviceId');
|
||||
const id = getDeviceId();
|
||||
|
||||
const expected = createHash('sha256')
|
||||
.update('mock-machine-id' + 'qiming-agent')
|
||||
.digest('hex');
|
||||
expect(id).toBe(expected);
|
||||
});
|
||||
|
||||
it('should call machineIdSync with original=true', async () => {
|
||||
const { getDeviceId } = await import('./deviceId');
|
||||
getDeviceId();
|
||||
|
||||
expect(mockMachineIdSync).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('should cache the result on subsequent calls', async () => {
|
||||
const { getDeviceId } = await import('./deviceId');
|
||||
const first = getDeviceId();
|
||||
const second = getDeviceId();
|
||||
|
||||
expect(first).toBe(second);
|
||||
expect(mockMachineIdSync).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should log the deviceId on first call', async () => {
|
||||
const { getDeviceId } = await import('./deviceId');
|
||||
const log = (await import('electron-log')).default;
|
||||
const id = getDeviceId();
|
||||
|
||||
expect(log.info).toHaveBeenCalledWith(`[DeviceId] ${id}`);
|
||||
});
|
||||
|
||||
it('should fallback to hostname when machineIdSync throws', async () => {
|
||||
mockMachineIdSync.mockImplementation(() => {
|
||||
throw new Error('no machine-id');
|
||||
});
|
||||
|
||||
const { getDeviceId } = await import('./deviceId');
|
||||
const log = (await import('electron-log')).default;
|
||||
const id = getDeviceId();
|
||||
|
||||
const expected = createHash('sha256')
|
||||
.update('mock-hostname' + 'qiming-agent')
|
||||
.digest('hex');
|
||||
expect(id).toBe(expected);
|
||||
expect(log.warn).toHaveBeenCalledWith(
|
||||
'[DeviceId] Failed to read machineId, using hostname fallback:',
|
||||
expect.any(Error),
|
||||
);
|
||||
});
|
||||
|
||||
it('should produce different IDs for different machineIds', async () => {
|
||||
mockMachineIdSync.mockReturnValue('machine-a');
|
||||
const mod1 = await import('./deviceId');
|
||||
const idA = mod1.getDeviceId();
|
||||
|
||||
vi.resetModules();
|
||||
mockMachineIdSync.mockReturnValue('machine-b');
|
||||
const mod2 = await import('./deviceId');
|
||||
const idB = mod2.getDeviceId();
|
||||
|
||||
expect(idA).not.toBe(idB);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user