Files
mcphub/tests/services/oauthService.test.ts
2025-11-29 17:45:25 +08:00

204 lines
6.1 KiB
TypeScript

// Mock openid-client before importing services
jest.mock('openid-client', () => ({
discovery: jest.fn(),
dynamicClientRegistration: jest.fn(),
ClientSecretPost: jest.fn(() => jest.fn()),
ClientSecretBasic: jest.fn(() => jest.fn()),
None: jest.fn(() => jest.fn()),
calculatePKCECodeChallenge: jest.fn(),
randomPKCECodeVerifier: jest.fn(),
buildAuthorizationUrl: jest.fn(),
authorizationCodeGrant: jest.fn(),
refreshTokenGrant: jest.fn(),
}));
// Mock the DAO module
jest.mock('../../src/dao/index.js', () => ({
getSystemConfigDao: jest.fn(),
getServerDao: jest.fn(),
}));
import {
initOAuthProvider,
isOAuthEnabled,
getServerOAuthToken,
addOAuthHeader,
} from '../../src/services/oauthService.js';
import * as daoModule from '../../src/dao/index.js';
describe('OAuth Service', () => {
const mockGetSystemConfigDao = daoModule.getSystemConfigDao as jest.MockedFunction<
typeof daoModule.getSystemConfigDao
>;
const mockGetServerDao = daoModule.getServerDao as jest.MockedFunction<
typeof daoModule.getServerDao
>;
beforeEach(() => {
jest.clearAllMocks();
});
describe('initOAuthProvider', () => {
it('should not initialize OAuth when disabled', async () => {
mockGetSystemConfigDao.mockReturnValue({
get: jest.fn().mockResolvedValue({
oauth: {
enabled: false,
issuerUrl: 'http://auth.example.com',
endpoints: {
authorizationUrl: 'http://auth.example.com/authorize',
tokenUrl: 'http://auth.example.com/token',
},
},
enableSessionRebuild: false,
}),
} as any);
await initOAuthProvider();
expect(isOAuthEnabled()).toBe(false);
});
it('should not initialize OAuth when not configured', async () => {
mockGetSystemConfigDao.mockReturnValue({
get: jest.fn().mockResolvedValue({
enableSessionRebuild: false,
}),
} as any);
await initOAuthProvider();
expect(isOAuthEnabled()).toBe(false);
});
it('should attempt to initialize OAuth when enabled and properly configured', async () => {
const mockGet = jest.fn().mockResolvedValue({
oauth: {
enabled: true,
issuerUrl: 'http://auth.example.com',
endpoints: {
authorizationUrl: 'http://auth.example.com/authorize',
tokenUrl: 'http://auth.example.com/token',
},
clients: [
{
client_id: 'test-client',
redirect_uris: ['http://localhost:3000/callback'],
},
],
},
enableSessionRebuild: false,
});
mockGetSystemConfigDao.mockReturnValue({
get: mockGet,
} as any);
// In a test environment, the ProxyOAuthServerProvider may not fully initialize
// due to missing dependencies or network issues, which is expected
await initOAuthProvider();
// We just verify that the function doesn't throw an error
expect(mockGet).toHaveBeenCalled();
});
});
describe('getServerOAuthToken', () => {
it('should return undefined when server has no OAuth config', async () => {
mockGetServerDao.mockReturnValue({
findById: jest.fn().mockResolvedValue({
url: 'http://example.com',
}),
} as any);
const token = await getServerOAuthToken('test-server');
expect(token).toBeUndefined();
});
it('should return undefined when server has no access token', async () => {
mockGetServerDao.mockReturnValue({
findById: jest.fn().mockResolvedValue({
url: 'http://example.com',
oauth: {
clientId: 'test-client',
},
}),
} as any);
const token = await getServerOAuthToken('test-server');
expect(token).toBeUndefined();
});
it('should return access token when configured', async () => {
mockGetServerDao.mockReturnValue({
findById: jest.fn().mockResolvedValue({
url: 'http://example.com',
oauth: {
clientId: 'test-client',
accessToken: 'test-access-token',
},
}),
} as any);
const token = await getServerOAuthToken('test-server');
expect(token).toBe('test-access-token');
});
});
describe('addOAuthHeader', () => {
it('should not modify headers when no OAuth token is configured', async () => {
mockGetServerDao.mockReturnValue({
findById: jest.fn().mockResolvedValue({
url: 'http://example.com',
}),
} as any);
const headers = { 'Content-Type': 'application/json' };
const result = await addOAuthHeader('test-server', headers);
expect(result).toEqual(headers);
expect(result.Authorization).toBeUndefined();
});
it('should add Authorization header when OAuth token is configured', async () => {
mockGetServerDao.mockReturnValue({
findById: jest.fn().mockResolvedValue({
url: 'http://example.com',
oauth: {
clientId: 'test-client',
accessToken: 'test-access-token',
},
}),
} as any);
const headers = { 'Content-Type': 'application/json' };
const result = await addOAuthHeader('test-server', headers);
expect(result).toEqual({
'Content-Type': 'application/json',
Authorization: 'Bearer test-access-token',
});
});
it('should preserve existing headers when adding OAuth token', async () => {
mockGetServerDao.mockReturnValue({
findById: jest.fn().mockResolvedValue({
url: 'http://example.com',
oauth: {
clientId: 'test-client',
accessToken: 'test-access-token',
},
}),
} as any);
const headers = {
'Content-Type': 'application/json',
'X-Custom-Header': 'custom-value',
};
const result = await addOAuthHeader('test-server', headers);
expect(result).toEqual({
'Content-Type': 'application/json',
'X-Custom-Header': 'custom-value',
Authorization: 'Bearer test-access-token',
});
});
});
});