stock-bot/libs/core/config/test/provider-config.test.ts
2025-06-22 17:55:51 -04:00

323 lines
12 KiB
TypeScript

import { existsSync, mkdirSync, rmSync, writeFileSync } from 'fs';
import { join } from 'path';
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
import { ConfigManager } from '../src/config-manager';
import { getProviderConfig, resetConfig } from '../src/index';
import { EnvLoader } from '../src/loaders/env.loader';
import { FileLoader } from '../src/loaders/file.loader';
import { appConfigSchema } from '../src/schemas';
const TEST_DIR = join(__dirname, 'provider-tests');
describe('Provider Configuration Tests', () => {
let originalEnv: NodeJS.ProcessEnv;
beforeEach(() => {
// Save original environment
originalEnv = { ...process.env };
// Reset config singleton
resetConfig();
// Clean up test directory
if (existsSync(TEST_DIR)) {
rmSync(TEST_DIR, { recursive: true, force: true });
}
mkdirSync(TEST_DIR, { recursive: true });
});
afterEach(() => {
// Restore original environment
process.env = originalEnv;
// Clean up
resetConfig();
if (existsSync(TEST_DIR)) {
rmSync(TEST_DIR, { recursive: true, force: true });
}
});
test('should load WebShare provider config from environment variables', async () => {
// Set WebShare environment variables
process.env.WEBSHARE_API_KEY = 'test-webshare-key';
process.env.WEBSHARE_API_URL = 'https://custom.webshare.io/api/v2/';
process.env.WEBSHARE_ENABLED = 'true';
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.webshare).toBeDefined();
expect(config.webshare?.apiKey).toBe('test-webshare-key');
expect(config.webshare?.apiUrl).toBe('https://custom.webshare.io/api/v2/');
expect(config.webshare?.enabled).toBe(true);
});
test('should load EOD provider config from environment variables', async () => {
// Set EOD environment variables
process.env.EOD_API_KEY = 'test-eod-key';
process.env.EOD_BASE_URL = 'https://custom.eod.com/api';
process.env.EOD_TIER = 'all-in-one';
process.env.EOD_ENABLED = 'true';
process.env.EOD_PRIORITY = '10';
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.providers?.eod).toBeDefined();
expect(config.providers?.eod?.apiKey).toBe('test-eod-key');
expect(config.providers?.eod?.baseUrl).toBe('https://custom.eod.com/api');
expect(config.providers?.eod?.tier).toBe('all-in-one');
expect(config.providers?.eod?.enabled).toBe(true);
expect(config.providers?.eod?.priority).toBe(10);
});
test('should load Interactive Brokers provider config from environment variables', async () => {
// Set IB environment variables
process.env.IB_GATEWAY_HOST = 'ib-gateway.example.com';
process.env.IB_GATEWAY_PORT = '7497';
process.env.IB_CLIENT_ID = '123';
process.env.IB_ACCOUNT = 'DU123456';
process.env.IB_MARKET_DATA_TYPE = 'live';
process.env.IB_ENABLED = 'true';
process.env.IB_PRIORITY = '5';
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.providers?.ib).toBeDefined();
expect(config.providers?.ib?.gateway.host).toBe('ib-gateway.example.com');
expect(config.providers?.ib?.gateway.port).toBe(7497);
expect(config.providers?.ib?.gateway.clientId).toBe(123);
expect(config.providers?.ib?.account).toBe('DU123456');
expect(config.providers?.ib?.marketDataType).toBe('live');
expect(config.providers?.ib?.enabled).toBe(true);
expect(config.providers?.ib?.priority).toBe(5);
});
test('should load QuoteMedia provider config from environment variables', async () => {
// Set QM environment variables
process.env.QM_USERNAME = 'test-qm-user';
process.env.QM_PASSWORD = 'test-qm-pass';
process.env.QM_BASE_URL = 'https://custom.quotemedia.com/api';
process.env.QM_WEBMASTER_ID = 'webmaster123';
process.env.QM_ENABLED = 'true';
process.env.QM_PRIORITY = '15';
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.providers?.qm).toBeDefined();
expect(config.providers?.qm?.username).toBe('test-qm-user');
expect(config.providers?.qm?.password).toBe('test-qm-pass');
expect(config.providers?.qm?.baseUrl).toBe('https://custom.quotemedia.com/api');
expect(config.providers?.qm?.webmasterId).toBe('webmaster123');
expect(config.providers?.qm?.enabled).toBe(true);
expect(config.providers?.qm?.priority).toBe(15);
});
test('should load Yahoo Finance provider config from environment variables', async () => {
// Set Yahoo environment variables
process.env.YAHOO_BASE_URL = 'https://custom.yahoo.com/api';
process.env.YAHOO_COOKIE_JAR = 'false';
process.env.YAHOO_CRUMB = 'test-crumb';
process.env.YAHOO_ENABLED = 'true';
process.env.YAHOO_PRIORITY = '20';
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.providers?.yahoo).toBeDefined();
expect(config.providers?.yahoo?.baseUrl).toBe('https://custom.yahoo.com/api');
expect(config.providers?.yahoo?.cookieJar).toBe(false);
expect(config.providers?.yahoo?.crumb).toBe('test-crumb');
expect(config.providers?.yahoo?.enabled).toBe(true);
expect(config.providers?.yahoo?.priority).toBe(20);
});
test('should merge file config with environment variables', async () => {
// Create a config file
const configDir = join(TEST_DIR, 'config');
mkdirSync(configDir, { recursive: true });
writeFileSync(
join(configDir, 'development.json'),
JSON.stringify(
{
providers: {
eod: {
name: 'EOD Historical Data',
apiKey: 'file-eod-key',
baseUrl: 'https://file.eod.com/api',
tier: 'free',
enabled: false,
priority: 1,
},
yahoo: {
name: 'Yahoo Finance',
baseUrl: 'https://file.yahoo.com',
enabled: true,
priority: 2,
},
},
},
null,
2
)
);
// Set environment variables that should override file config
process.env.EOD_API_KEY = 'env-eod-key';
process.env.EOD_ENABLED = 'true';
process.env.EOD_PRIORITY = '10';
process.env.YAHOO_PRIORITY = '25';
const manager = new ConfigManager({
loaders: [new FileLoader(configDir, 'development'), new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
// EOD config should be merged (env overrides file)
expect(config.providers?.eod?.name).toBe('EOD Historical Data'); // From file
expect(config.providers?.eod?.apiKey).toBe('env-eod-key'); // From env
expect(config.providers?.eod?.baseUrl).toBe('https://file.eod.com/api'); // From file
expect(config.providers?.eod?.enabled).toBe(true); // From env (overrides file)
expect(config.providers?.eod?.priority).toBe(10); // From env (overrides file)
// Yahoo config should be merged
expect(config.providers?.yahoo?.name).toBe('Yahoo Finance'); // From file
expect(config.providers?.yahoo?.baseUrl).toBe('https://file.yahoo.com'); // From file
expect(config.providers?.yahoo?.priority).toBe(25); // From env (overrides file)
});
test('should handle invalid provider configurations', async () => {
// Set invalid values
process.env.EOD_TIER = 'invalid-tier'; // Should be one of ['free', 'fundamentals', 'all-in-one']
process.env.IB_MARKET_DATA_TYPE = 'invalid-type'; // Should be one of ['live', 'delayed', 'frozen']
process.env.IB_GATEWAY_PORT = 'not-a-number'; // Should be a number
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
// Should throw validation error
await expect(manager.initialize(appConfigSchema)).rejects.toThrow();
});
test('should work with getProviderConfig helper function', async () => {
// Set up multiple providers
process.env.EOD_API_KEY = 'test-eod-key';
process.env.EOD_ENABLED = 'true';
process.env.WEBSHARE_API_KEY = 'test-webshare-key';
process.env.WEBSHARE_ENABLED = 'true';
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
await manager.initialize(appConfigSchema);
// Test getProviderConfig helper
const eodConfig = getProviderConfig('eod');
expect(eodConfig).toBeDefined();
expect((eodConfig as any).apiKey).toBe('test-eod-key');
const webshareConfig = getProviderConfig('webshare');
expect(webshareConfig).toBeDefined();
expect((webshareConfig as any).apiKey).toBe('test-webshare-key');
// Test non-existent provider
expect(() => getProviderConfig('nonexistent')).toThrow(
'Provider configuration not found: nonexistent'
);
});
test('should handle boolean string parsing correctly', async () => {
// Test various boolean representations
process.env.EOD_ENABLED = 'TRUE';
process.env.YAHOO_ENABLED = 'False';
process.env.IB_ENABLED = '1';
process.env.QM_ENABLED = '0';
process.env.WEBSHARE_ENABLED = 'yes'; // Should be treated as string, not boolean
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.providers?.eod?.enabled).toBe(true);
expect(config.providers?.yahoo?.enabled).toBe(false);
expect(config.providers?.ib?.enabled).toBe(true); // 1 is parsed as number, not boolean
expect(config.providers?.qm?.enabled).toBe(false); // 0 is parsed as number, not boolean
// webshare.enabled should be the string 'yes', but schema validation might reject it
});
test('should handle nested configuration correctly', async () => {
// Test nested IB gateway configuration
process.env.IB_GATEWAY_HOST = 'gateway.ib.com';
process.env.IB_GATEWAY_PORT = '7497';
process.env.IB_GATEWAY_CLIENT_ID = '999';
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.providers?.ib?.gateway).toBeDefined();
expect(config.providers?.ib?.gateway.host).toBe('gateway.ib.com');
expect(config.providers?.ib?.gateway.port).toBe(7497);
expect(config.providers?.ib?.gateway.clientId).toBe(999);
});
test('should load provider configs from .env file', async () => {
// Create .env file with provider configs
writeFileSync(
join(TEST_DIR, '.env'),
`# Provider configurations
EOD_API_KEY=env-file-eod-key
EOD_ENABLED=true
WEBSHARE_API_KEY=env-file-webshare-key
IB_GATEWAY_HOST=env-file-ib-host
IB_GATEWAY_PORT=7498
YAHOO_BASE_URL=https://env-file.yahoo.com
`
);
const originalCwd = process.cwd();
try {
process.chdir(TEST_DIR);
const manager = new ConfigManager({
loaders: [new EnvLoader('')],
});
const config = await manager.initialize(appConfigSchema);
expect(config.providers?.eod?.apiKey).toBe('env-file-eod-key');
expect(config.providers?.eod?.enabled).toBe(true);
expect(config.webshare?.apiKey).toBe('env-file-webshare-key');
expect(config.providers?.ib?.gateway.host).toBe('env-file-ib-host');
expect(config.providers?.ib?.gateway.port).toBe(7498);
expect(config.providers?.yahoo?.baseUrl).toBe('https://env-file.yahoo.com');
} finally {
process.chdir(originalCwd);
}
});
});