feat: implement third-party order sync
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { CallHandler, ExecutionContext } from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { lastValueFrom, of, throwError } from 'rxjs';
|
||||
import { AuditService } from './audit.service';
|
||||
import { OperationLogInterceptor } from './operation-log.interceptor';
|
||||
|
||||
function createContext(request: Record<string, unknown>) {
|
||||
return {
|
||||
getHandler: () => function handler() {},
|
||||
getClass: () => class Controller {},
|
||||
switchToHttp: () => ({
|
||||
getRequest: () => request,
|
||||
}),
|
||||
} as unknown as ExecutionContext;
|
||||
}
|
||||
|
||||
describe('OperationLogInterceptor', () => {
|
||||
it('writes a success operation log with masked request body', async () => {
|
||||
const write = jest.fn();
|
||||
const reflector = {
|
||||
getAllAndOverride: jest.fn().mockReturnValue({
|
||||
action: 'admin.users.create',
|
||||
resourceType: 'user',
|
||||
resourceIdFromResult: 'id',
|
||||
metadataFromBody: ['name', 'password'],
|
||||
}),
|
||||
} as unknown as Reflector;
|
||||
const interceptor = new OperationLogInterceptor(
|
||||
{ write } as unknown as AuditService,
|
||||
reflector,
|
||||
);
|
||||
|
||||
const request = {
|
||||
user: { id: 'actor-1', name: 'root' },
|
||||
params: {},
|
||||
query: {},
|
||||
body: { name: 'demo', password: '123456' },
|
||||
headers: { 'user-agent': 'vitest' },
|
||||
ip: '127.0.0.1',
|
||||
};
|
||||
const next = {
|
||||
handle: () => of({ id: 'user-1' }),
|
||||
} as CallHandler;
|
||||
|
||||
await expect(lastValueFrom(interceptor.intercept(createContext(request), next))).resolves.toEqual({
|
||||
id: 'user-1',
|
||||
});
|
||||
|
||||
expect(write).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
actorId: 'actor-1',
|
||||
actorUsername: 'root',
|
||||
action: 'admin.users.create',
|
||||
resourceType: 'user',
|
||||
resourceId: 'user-1',
|
||||
ipAddress: '127.0.0.1',
|
||||
metadata: expect.objectContaining({
|
||||
status: 'success',
|
||||
request: expect.objectContaining({
|
||||
body: { name: 'demo', password: '******' },
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('writes a failed operation log and rethrows the error', async () => {
|
||||
const write = jest.fn();
|
||||
const reflector = {
|
||||
getAllAndOverride: jest.fn().mockReturnValue({
|
||||
action: 'admin.users.update',
|
||||
resourceType: 'user',
|
||||
resourceIdParam: 'id',
|
||||
}),
|
||||
} as unknown as Reflector;
|
||||
const interceptor = new OperationLogInterceptor(
|
||||
{ write } as unknown as AuditService,
|
||||
reflector,
|
||||
);
|
||||
const error = new Error('保存失败');
|
||||
const request = {
|
||||
user: { id: 'actor-1', name: 'root' },
|
||||
params: { id: 'user-1' },
|
||||
query: {},
|
||||
body: {},
|
||||
headers: {},
|
||||
ip: '127.0.0.1',
|
||||
};
|
||||
const next = {
|
||||
handle: () => throwError(() => error),
|
||||
} as CallHandler;
|
||||
|
||||
await expect(
|
||||
lastValueFrom(interceptor.intercept(createContext(request), next)),
|
||||
).rejects.toThrow('保存失败');
|
||||
|
||||
expect(write).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
action: 'admin.users.update',
|
||||
resourceId: 'user-1',
|
||||
metadata: expect.objectContaining({
|
||||
status: 'failed',
|
||||
error: {
|
||||
name: 'Error',
|
||||
message: '保存失败',
|
||||
},
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user