refactor:项目架构重构和命名规范化

- 统一文件命名为snake_case格式(kebab-case  snake_case)
- 重构zulip模块为zulip_core,明确Core层职责
- 重构user-mgmt模块为user_mgmt,统一命名规范
- 调整模块依赖关系,优化架构分层
- 删除过时的文件和目录结构
- 更新相关文档和配置文件

本次重构涉及大量文件重命名和模块重组,
旨在建立更清晰的项目架构和统一的命名规范。
This commit is contained in:
moyin
2026-01-08 00:14:14 +08:00
parent 4fa4bd1a70
commit bb796a2469
178 changed files with 24767 additions and 3484 deletions

View File

@@ -0,0 +1,237 @@
/**
* AdminController 单元测试
*
* 功能描述:
* - 测试管理员控制器的所有HTTP端点
* - 验证请求参数处理和响应格式
* - 测试权限验证和异常处理
*
* 职责分离:
* - HTTP层测试不涉及业务逻辑实现
* - Mock业务服务专注控制器逻辑
* - 验证请求响应的正确性
*
* 最近修改:
* - 2026-01-07: 代码规范优化 - 创建AdminController测试文件补充测试覆盖
*
* @author moyin
* @version 1.0.1
* @since 2026-01-07
* @lastModified 2026-01-07
*/
import { Test, TestingModule } from '@nestjs/testing';
import { Response } from 'express';
import { AdminController } from './admin.controller';
import { AdminService } from './admin.service';
import { AdminGuard } from './guards/admin.guard';
describe('AdminController', () => {
let controller: AdminController;
let adminService: jest.Mocked<AdminService>;
const mockAdminService = {
login: jest.fn(),
listUsers: jest.fn(),
getUser: jest.fn(),
resetPassword: jest.fn(),
getRuntimeLogs: jest.fn(),
getLogDirAbsolutePath: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AdminController],
providers: [
{
provide: AdminService,
useValue: mockAdminService,
},
],
})
.overrideGuard(AdminGuard)
.useValue({ canActivate: () => true })
.compile();
controller = module.get<AdminController>(AdminController);
adminService = module.get(AdminService);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('login', () => {
it('should login admin successfully', async () => {
const loginDto = { identifier: 'admin', password: 'Admin123456' };
const expectedResult = {
success: true,
data: { admin: { id: '1', username: 'admin', role: 9 }, access_token: 'token' },
message: '管理员登录成功'
};
adminService.login.mockResolvedValue(expectedResult);
const result = await controller.login(loginDto);
expect(adminService.login).toHaveBeenCalledWith('admin', 'Admin123456');
expect(result).toEqual(expectedResult);
});
it('should handle login failure', async () => {
const loginDto = { identifier: 'admin', password: 'wrong' };
const expectedResult = {
success: false,
message: '密码错误',
error_code: 'ADMIN_LOGIN_FAILED'
};
adminService.login.mockResolvedValue(expectedResult);
const result = await controller.login(loginDto);
expect(result.success).toBe(false);
expect(result.error_code).toBe('ADMIN_LOGIN_FAILED');
});
});
describe('listUsers', () => {
it('should list users with default pagination', async () => {
const expectedResult = {
success: true,
data: {
users: [{ id: '1', username: 'user1' }],
limit: 100,
offset: 0
},
message: '用户列表获取成功'
};
adminService.listUsers.mockResolvedValue(expectedResult);
const result = await controller.listUsers();
expect(adminService.listUsers).toHaveBeenCalledWith(100, 0);
expect(result).toEqual(expectedResult);
});
it('should list users with custom pagination', async () => {
const expectedResult = {
success: true,
data: {
users: [],
limit: 50,
offset: 10
},
message: '用户列表获取成功'
};
adminService.listUsers.mockResolvedValue(expectedResult);
const result = await controller.listUsers('50', '10');
expect(adminService.listUsers).toHaveBeenCalledWith(50, 10);
expect(result).toEqual(expectedResult);
});
});
describe('getUser', () => {
it('should get user by id', async () => {
const expectedResult = {
success: true,
data: { user: { id: '123', username: 'testuser' } },
message: '用户信息获取成功'
};
adminService.getUser.mockResolvedValue(expectedResult);
const result = await controller.getUser('123');
expect(adminService.getUser).toHaveBeenCalledWith(BigInt(123));
expect(result).toEqual(expectedResult);
});
});
describe('resetPassword', () => {
it('should reset user password', async () => {
const resetDto = { new_password: 'NewPass1234' };
const expectedResult = {
success: true,
message: '密码重置成功'
};
adminService.resetPassword.mockResolvedValue(expectedResult);
const result = await controller.resetPassword('123', resetDto);
expect(adminService.resetPassword).toHaveBeenCalledWith(BigInt(123), 'NewPass1234');
expect(result).toEqual(expectedResult);
});
});
describe('getRuntimeLogs', () => {
it('should get runtime logs with default lines', async () => {
const expectedResult = {
success: true,
data: {
file: 'app.log',
updated_at: '2026-01-07T00:00:00.000Z',
lines: ['log line 1', 'log line 2']
},
message: '运行日志获取成功'
};
adminService.getRuntimeLogs.mockResolvedValue(expectedResult);
const result = await controller.getRuntimeLogs();
expect(adminService.getRuntimeLogs).toHaveBeenCalledWith(undefined);
expect(result).toEqual(expectedResult);
});
it('should get runtime logs with custom lines', async () => {
const expectedResult = {
success: true,
data: {
file: 'app.log',
updated_at: '2026-01-07T00:00:00.000Z',
lines: ['log line 1']
},
message: '运行日志获取成功'
};
adminService.getRuntimeLogs.mockResolvedValue(expectedResult);
const result = await controller.getRuntimeLogs('100');
expect(adminService.getRuntimeLogs).toHaveBeenCalledWith(100);
expect(result).toEqual(expectedResult);
});
});
describe('downloadLogsArchive', () => {
let mockResponse: Partial<Response>;
beforeEach(() => {
mockResponse = {
setHeader: jest.fn(),
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
headersSent: false,
};
});
it('should handle missing log directory', async () => {
adminService.getLogDirAbsolutePath.mockReturnValue('/nonexistent/logs');
await controller.downloadLogsArchive(mockResponse as Response);
expect(mockResponse.status).toHaveBeenCalledWith(404);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: '日志目录不存在'
});
});
});
});