chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -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);
});
});