Add OpenAPI support and enhance settings aggregation (#500)

This commit is contained in:
samanhappy
2025-12-11 17:42:50 +08:00
committed by GitHub
parent 1dfa0a990b
commit 2028233b53
8 changed files with 274 additions and 74 deletions

View File

@@ -1,10 +1,7 @@
import { getMcpSettingsJson } from '../../src/controllers/configController.js';
import * as config from '../../src/config/index.js';
import * as DaoFactory from '../../src/dao/DaoFactory.js';
import { Request, Response } from 'express';
// Mock the config module
jest.mock('../../src/config/index.js');
// Mock the DaoFactory module
jest.mock('../../src/dao/DaoFactory.js');
@@ -13,9 +10,17 @@ describe('ConfigController - getMcpSettingsJson', () => {
let mockResponse: Partial<Response>;
let mockJson: jest.Mock;
let mockStatus: jest.Mock;
let mockServerDao: { findById: jest.Mock };
let mockServerDao: { findById: jest.Mock; findAll: jest.Mock };
let mockUserDao: { findAll: jest.Mock };
let mockGroupDao: { findAll: jest.Mock };
let mockSystemConfigDao: { get: jest.Mock };
let mockUserConfigDao: { getAll: jest.Mock };
let mockOAuthClientDao: { findAll: jest.Mock };
let mockOAuthTokenDao: { findAll: jest.Mock };
beforeEach(() => {
jest.clearAllMocks();
mockJson = jest.fn();
mockStatus = jest.fn().mockReturnThis();
mockRequest = {
@@ -27,35 +32,73 @@ describe('ConfigController - getMcpSettingsJson', () => {
};
mockServerDao = {
findById: jest.fn(),
findAll: jest.fn(),
};
mockUserDao = { findAll: jest.fn() };
mockGroupDao = { findAll: jest.fn() };
mockSystemConfigDao = { get: jest.fn() };
mockUserConfigDao = { getAll: jest.fn() };
mockOAuthClientDao = { findAll: jest.fn() };
mockOAuthTokenDao = { findAll: jest.fn() };
// Setup ServerDao mock
(DaoFactory.getServerDao as jest.Mock).mockReturnValue(mockServerDao);
// Reset mocks
jest.clearAllMocks();
(DaoFactory.getUserDao as jest.Mock).mockReturnValue(mockUserDao);
(DaoFactory.getGroupDao as jest.Mock).mockReturnValue(mockGroupDao);
(DaoFactory.getSystemConfigDao as jest.Mock).mockReturnValue(mockSystemConfigDao);
(DaoFactory.getUserConfigDao as jest.Mock).mockReturnValue(mockUserConfigDao);
(DaoFactory.getOAuthClientDao as jest.Mock).mockReturnValue(mockOAuthClientDao);
(DaoFactory.getOAuthTokenDao as jest.Mock).mockReturnValue(mockOAuthTokenDao);
});
describe('Full Settings Export', () => {
it('should handle settings without users array', async () => {
const mockSettings = {
mcpServers: {
'test-server': {
command: 'test',
args: ['--test'],
},
it('should return settings aggregated from DAOs', async () => {
mockServerDao.findAll.mockResolvedValue([
{ name: 'server-a', command: 'node', args: ['index.js'], env: { A: '1' } },
{ name: 'server-b', command: 'npx', args: ['run'], env: null },
]);
mockUserDao.findAll.mockResolvedValue([
{ username: 'admin', password: 'hash', isAdmin: true },
]);
mockGroupDao.findAll.mockResolvedValue([{ id: 'g1', name: 'Group', servers: [] }]);
mockSystemConfigDao.get.mockResolvedValue({ routing: { skipAuth: false } });
mockUserConfigDao.getAll.mockResolvedValue({ admin: { routing: {} } });
mockOAuthClientDao.findAll.mockResolvedValue([
{ clientId: 'c1', clientSecret: 's', name: 'client' },
]);
mockOAuthTokenDao.findAll.mockResolvedValue([
{
accessToken: 'a',
accessTokenExpiresAt: new Date('2024-01-01T00:00:00Z'),
clientId: 'c1',
username: 'admin',
},
};
(config.loadOriginalSettings as jest.Mock).mockReturnValue(mockSettings);
]);
await getMcpSettingsJson(mockRequest as Request, mockResponse as Response);
expect(mockServerDao.findAll).toHaveBeenCalled();
expect(mockUserDao.findAll).toHaveBeenCalled();
expect(mockJson).toHaveBeenCalledWith({
success: true,
data: {
mcpServers: mockSettings.mcpServers,
users: undefined,
mcpServers: {
'server-a': { command: 'node', args: ['index.js'], env: { A: '1' } },
'server-b': { command: 'npx', args: ['run'] },
},
users: [{ username: 'admin', password: 'hash', isAdmin: true }],
groups: [{ id: 'g1', name: 'Group', servers: [] }],
systemConfig: { routing: { skipAuth: false } },
userConfigs: { admin: { routing: {} } },
oauthClients: [{ clientId: 'c1', clientSecret: 's', name: 'client' }],
oauthTokens: [
{
accessToken: 'a',
accessTokenExpiresAt: new Date('2024-01-01T00:00:00Z'),
clientId: 'c1',
username: 'admin',
},
],
},
});
});
@@ -146,10 +189,13 @@ describe('ConfigController - getMcpSettingsJson', () => {
describe('Error Handling', () => {
it('should handle errors gracefully and return 500', async () => {
const errorMessage = 'Failed to load settings';
(config.loadOriginalSettings as jest.Mock).mockImplementation(() => {
throw new Error(errorMessage);
});
mockServerDao.findAll.mockRejectedValue(new Error('boom'));
mockUserDao.findAll.mockResolvedValue([]);
mockGroupDao.findAll.mockResolvedValue([]);
mockSystemConfigDao.get.mockResolvedValue({});
mockUserConfigDao.getAll.mockResolvedValue({});
mockOAuthClientDao.findAll.mockResolvedValue([]);
mockOAuthTokenDao.findAll.mockResolvedValue([]);
await getMcpSettingsJson(mockRequest as Request, mockResponse as Response);