Adds missing server dir
This commit is contained in:
327
server/config.test.ts
Normal file
327
server/config.test.ts
Normal file
@@ -0,0 +1,327 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { readFileSync } from 'fs';
|
||||
import { loadConfig, validateConfig, Config } from './config';
|
||||
|
||||
// Mock fs module
|
||||
vi.mock('fs');
|
||||
const mockedReadFileSync = vi.mocked(readFileSync);
|
||||
|
||||
describe('Configuration Management', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clear environment variables
|
||||
delete process.env.GITHUB_TOKEN;
|
||||
delete process.env.PORT;
|
||||
delete process.env.HOST;
|
||||
});
|
||||
|
||||
describe('loadConfig', () => {
|
||||
it('should load configuration from file', () => {
|
||||
const mockConfig = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
};
|
||||
|
||||
mockedReadFileSync.mockReturnValueOnce(JSON.stringify(mockConfig));
|
||||
|
||||
const result = loadConfig();
|
||||
|
||||
expect(result).toEqual(mockConfig);
|
||||
expect(mockedReadFileSync).toHaveBeenCalledWith(
|
||||
expect.stringContaining('config.json'),
|
||||
'utf8'
|
||||
);
|
||||
});
|
||||
|
||||
it('should use environment variables when config file is not found', () => {
|
||||
process.env.GITHUB_TOKEN = 'env-token';
|
||||
process.env.PORT = '8080';
|
||||
process.env.HOST = '127.0.0.1';
|
||||
|
||||
mockedReadFileSync.mockImplementationOnce(() => {
|
||||
throw new Error('ENOENT: no such file or directory');
|
||||
});
|
||||
|
||||
const result = loadConfig();
|
||||
|
||||
expect(result).toEqual({
|
||||
github: {
|
||||
token: 'env-token',
|
||||
repositories: []
|
||||
},
|
||||
server: {
|
||||
port: 8080,
|
||||
host: '127.0.0.1'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should merge file config with environment variables', () => {
|
||||
process.env.GITHUB_TOKEN = 'env-token';
|
||||
process.env.PORT = '8080';
|
||||
|
||||
const mockConfig = {
|
||||
github: {
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 600
|
||||
}
|
||||
};
|
||||
|
||||
mockedReadFileSync.mockReturnValueOnce(JSON.stringify(mockConfig));
|
||||
|
||||
const result = loadConfig();
|
||||
|
||||
expect(result).toEqual({
|
||||
github: {
|
||||
token: 'env-token', // From environment
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 8080, // From environment
|
||||
host: '0.0.0.0' // From file
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 600 // From file
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should use default values when neither file nor env vars are provided', () => {
|
||||
mockedReadFileSync.mockImplementationOnce(() => {
|
||||
throw new Error('ENOENT: no such file or directory');
|
||||
});
|
||||
|
||||
const result = loadConfig();
|
||||
|
||||
expect(result).toEqual({
|
||||
github: {
|
||||
token: '',
|
||||
repositories: []
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle invalid JSON in config file', () => {
|
||||
mockedReadFileSync.mockReturnValueOnce('invalid json');
|
||||
|
||||
const result = loadConfig();
|
||||
|
||||
// Should fallback to defaults
|
||||
expect(result).toEqual({
|
||||
github: {
|
||||
token: '',
|
||||
repositories: []
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateConfig', () => {
|
||||
it('should validate correct configuration', () => {
|
||||
const config: Config = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(config)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw error when GitHub token is missing', () => {
|
||||
const config: Config = {
|
||||
github: {
|
||||
token: '',
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(config)).toThrow('GitHub token is required');
|
||||
});
|
||||
|
||||
it('should throw error when no repositories are configured', () => {
|
||||
const config: Config = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: []
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(config)).toThrow('At least one repository is required');
|
||||
});
|
||||
|
||||
it('should throw error for invalid repository configuration', () => {
|
||||
const config: Config = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: [
|
||||
{ owner: '', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(config)).toThrow('Invalid repository configuration');
|
||||
});
|
||||
|
||||
it('should throw error for repository missing name', () => {
|
||||
const config: Config = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: '' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(config)).toThrow('Invalid repository configuration');
|
||||
});
|
||||
|
||||
it('should validate multiple repositories', () => {
|
||||
const config: Config = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: [
|
||||
{ owner: 'owner1', name: 'repo1' },
|
||||
{ owner: 'owner2', name: 'repo2' },
|
||||
{ owner: 'owner3', name: 'repo3' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 300
|
||||
}
|
||||
};
|
||||
|
||||
expect(() => validateConfig(config)).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('cache configuration', () => {
|
||||
it('should use default cache timeout when not specified', () => {
|
||||
const mockConfig = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
}
|
||||
};
|
||||
|
||||
mockedReadFileSync.mockReturnValueOnce(JSON.stringify(mockConfig));
|
||||
|
||||
const result = loadConfig();
|
||||
|
||||
expect(result.cache?.timeoutSeconds).toBe(300);
|
||||
});
|
||||
|
||||
it('should use custom cache timeout when specified', () => {
|
||||
const mockConfig = {
|
||||
github: {
|
||||
token: 'test-token',
|
||||
repositories: [
|
||||
{ owner: 'test-owner', name: 'test-repo' }
|
||||
]
|
||||
},
|
||||
server: {
|
||||
port: 3001,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
cache: {
|
||||
timeoutSeconds: 600
|
||||
}
|
||||
};
|
||||
|
||||
mockedReadFileSync.mockReturnValueOnce(JSON.stringify(mockConfig));
|
||||
|
||||
const result = loadConfig();
|
||||
|
||||
expect(result.cache?.timeoutSeconds).toBe(600);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user