Files
mcphub/tests/services/oauthService.test.ts
2025-10-26 16:09:34 +08:00

208 lines
5.8 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(),
}));
import {
initOAuthProvider,
isOAuthEnabled,
getServerOAuthToken,
addOAuthHeader,
} from '../../src/services/oauthService.js';
import * as config from '../../src/config/index.js';
// Mock the config module
jest.mock('../../src/config/index.js', () => ({
loadSettings: jest.fn(),
}));
describe('OAuth Service', () => {
const mockLoadSettings = config.loadSettings as jest.MockedFunction<typeof config.loadSettings>;
beforeEach(() => {
jest.clearAllMocks();
});
describe('initOAuthProvider', () => {
it('should not initialize OAuth when disabled', () => {
mockLoadSettings.mockReturnValue({
mcpServers: {},
systemConfig: {
oauth: {
enabled: false,
issuerUrl: 'http://auth.example.com',
endpoints: {
authorizationUrl: 'http://auth.example.com/authorize',
tokenUrl: 'http://auth.example.com/token',
},
},
},
});
initOAuthProvider();
expect(isOAuthEnabled()).toBe(false);
});
it('should not initialize OAuth when not configured', () => {
mockLoadSettings.mockReturnValue({
mcpServers: {},
systemConfig: {},
});
initOAuthProvider();
expect(isOAuthEnabled()).toBe(false);
});
it('should attempt to initialize OAuth when enabled and properly configured', () => {
mockLoadSettings.mockReturnValue({
mcpServers: {},
systemConfig: {
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'],
},
],
},
},
});
// In a test environment, the ProxyOAuthServerProvider may not fully initialize
// due to missing dependencies or network issues, which is expected
initOAuthProvider();
// We just verify that the function doesn't throw an error
expect(mockLoadSettings).toHaveBeenCalled();
});
});
describe('getServerOAuthToken', () => {
it('should return undefined when server has no OAuth config', async () => {
mockLoadSettings.mockReturnValue({
mcpServers: {
'test-server': {
url: 'http://example.com',
},
},
});
const token = await getServerOAuthToken('test-server');
expect(token).toBeUndefined();
});
it('should return undefined when server has no access token', async () => {
mockLoadSettings.mockReturnValue({
mcpServers: {
'test-server': {
url: 'http://example.com',
oauth: {
clientId: 'test-client',
},
},
},
});
const token = await getServerOAuthToken('test-server');
expect(token).toBeUndefined();
});
it('should return access token when configured', async () => {
mockLoadSettings.mockReturnValue({
mcpServers: {
'test-server': {
url: 'http://example.com',
oauth: {
clientId: 'test-client',
accessToken: 'test-access-token',
},
},
},
});
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 () => {
mockLoadSettings.mockReturnValue({
mcpServers: {
'test-server': {
url: 'http://example.com',
},
},
});
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 () => {
mockLoadSettings.mockReturnValue({
mcpServers: {
'test-server': {
url: 'http://example.com',
oauth: {
clientId: 'test-client',
accessToken: 'test-access-token',
},
},
},
});
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 () => {
mockLoadSettings.mockReturnValue({
mcpServers: {
'test-server': {
url: 'http://example.com',
oauth: {
clientId: 'test-client',
accessToken: 'test-access-token',
},
},
},
});
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',
});
});
});
});