moved folders around
This commit is contained in:
parent
4f89affc2b
commit
36cb84b343
202 changed files with 1160 additions and 660 deletions
404
libs/core/config/test/real-usage.test.ts
Normal file
404
libs/core/config/test/real-usage.test.ts
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import {
|
||||
getConfig,
|
||||
getDatabaseConfig,
|
||||
getLoggingConfig,
|
||||
getProviderConfig,
|
||||
getServiceConfig,
|
||||
initializeServiceConfig,
|
||||
isDevelopment,
|
||||
isProduction,
|
||||
isTest,
|
||||
resetConfig
|
||||
} from '../src/index';
|
||||
|
||||
const TEST_DIR = join(__dirname, 'real-usage-tests');
|
||||
|
||||
describe('Real Usage Scenarios', () => {
|
||||
let originalEnv: NodeJS.ProcessEnv;
|
||||
let originalCwd: string;
|
||||
|
||||
beforeEach(() => {
|
||||
originalEnv = { ...process.env };
|
||||
originalCwd = process.cwd();
|
||||
|
||||
resetConfig();
|
||||
|
||||
if (existsSync(TEST_DIR)) {
|
||||
rmSync(TEST_DIR, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
setupRealUsageScenarios();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
process.chdir(originalCwd);
|
||||
resetConfig();
|
||||
|
||||
if (existsSync(TEST_DIR)) {
|
||||
rmSync(TEST_DIR, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('should work like real data-ingestion usage', async () => {
|
||||
const dataServiceDir = join(TEST_DIR, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
// Simulate how data-ingestion would initialize config
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
// Test typical data-ingestion config access patterns
|
||||
expect(config.app.name).toBe('data-ingestion');
|
||||
expect(config.service.port).toBe(3001);
|
||||
|
||||
// Test database config access
|
||||
const dbConfig = getDatabaseConfig();
|
||||
expect(dbConfig.postgres.host).toBe('localhost');
|
||||
expect(dbConfig.postgres.port).toBe(5432);
|
||||
expect(dbConfig.questdb.host).toBe('localhost');
|
||||
|
||||
// Test provider access
|
||||
const yahooConfig = getProviderConfig('yahoo');
|
||||
expect(yahooConfig).toBeDefined();
|
||||
expect((yahooConfig as any).enabled).toBe(true);
|
||||
|
||||
// Test environment helpers
|
||||
expect(isDevelopment()).toBe(true);
|
||||
expect(isProduction()).toBe(false);
|
||||
});
|
||||
|
||||
test('should work like real web-api usage', async () => {
|
||||
const webApiDir = join(TEST_DIR, 'apps', 'web-api');
|
||||
process.chdir(webApiDir);
|
||||
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
expect(config.app.name).toBe('web-api');
|
||||
expect(config.service.port).toBe(4000);
|
||||
|
||||
// Web API should have access to all the same configs
|
||||
const serviceConfig = getServiceConfig();
|
||||
expect(serviceConfig.name).toBe('web-api');
|
||||
|
||||
const loggingConfig = getLoggingConfig();
|
||||
expect(loggingConfig.level).toBe('info');
|
||||
});
|
||||
|
||||
test('should work like real shared library usage', async () => {
|
||||
const cacheLibDir = join(TEST_DIR, 'libs', 'cache');
|
||||
process.chdir(cacheLibDir);
|
||||
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
// Libraries should inherit from root config
|
||||
expect(config.app.name).toBe('cache-lib');
|
||||
expect(config.app.version).toBe('1.0.0'); // From root
|
||||
|
||||
// Should have access to cache config
|
||||
const dbConfig = getDatabaseConfig();
|
||||
expect(dbConfig.dragonfly).toBeDefined();
|
||||
expect(dbConfig.dragonfly.host).toBe('localhost');
|
||||
expect(dbConfig.dragonfly.port).toBe(6379);
|
||||
});
|
||||
|
||||
test('should handle production environment correctly', async () => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
const dataServiceDir = join(TEST_DIR, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
resetConfig();
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
expect(config.environment).toBe('production');
|
||||
expect(config.logging.level).toBe('warn'); // Production should use different log level
|
||||
|
||||
expect(isProduction()).toBe(true);
|
||||
expect(isDevelopment()).toBe(false);
|
||||
});
|
||||
|
||||
test('should handle test environment correctly', async () => {
|
||||
process.env.NODE_ENV = 'test';
|
||||
|
||||
const dataServiceDir = join(TEST_DIR, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
resetConfig();
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
expect(config.environment).toBe('test');
|
||||
expect(config.logging.level).toBe('debug'); // Test should use debug level
|
||||
|
||||
expect(isTest()).toBe(true);
|
||||
expect(isDevelopment()).toBe(false);
|
||||
});
|
||||
|
||||
test('should work with environment variable overrides in production', async () => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
process.env.DATABASE_POSTGRES_HOST = 'prod-db.example.com';
|
||||
process.env.DATABASE_POSTGRES_PORT = '5433';
|
||||
process.env.EOD_API_KEY = 'prod-eod-key';
|
||||
process.env.SERVICE_PORT = '8080';
|
||||
|
||||
const dataServiceDir = join(TEST_ROOT, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
resetConfig();
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
// Environment variables should override file configs
|
||||
const dbConfig = getDatabaseConfig();
|
||||
expect(dbConfig.postgres.host).toBe('prod-db.example.com');
|
||||
expect(dbConfig.postgres.port).toBe(5433);
|
||||
|
||||
const serviceConfig = getServiceConfig();
|
||||
expect(serviceConfig.port).toBe(8080);
|
||||
|
||||
const eodConfig = getProviderConfig('eod');
|
||||
expect((eodConfig as any).apiKey).toBe('prod-eod-key');
|
||||
});
|
||||
|
||||
test('should handle missing provider configurations gracefully', async () => {
|
||||
const dataServiceDir = join(TEST_DIR, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
// Should throw for non-existent providers
|
||||
expect(() => getProviderConfig('nonexistent')).toThrow('Provider configuration not found: nonexistent');
|
||||
|
||||
// Should work for providers that exist but might not be configured
|
||||
// (they should have defaults from schema)
|
||||
const yahooConfig = getProviderConfig('yahoo');
|
||||
expect(yahooConfig).toBeDefined();
|
||||
});
|
||||
|
||||
test('should support dynamic config access patterns', async () => {
|
||||
const dataServiceDir = join(TEST_DIR, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
const config = await initializeServiceConfig();
|
||||
|
||||
// Test various access patterns used in real applications
|
||||
const configManager = (await import('../src/index')).getConfigManager();
|
||||
|
||||
// Direct path access
|
||||
expect(configManager.getValue('app.name')).toBe('data-ingestion');
|
||||
expect(configManager.getValue('service.port')).toBe(3001);
|
||||
|
||||
// Check if paths exist
|
||||
expect(configManager.has('app.name')).toBe(true);
|
||||
expect(configManager.has('nonexistent.path')).toBe(false);
|
||||
|
||||
// Typed access
|
||||
const port = configManager.getValue<number>('service.port');
|
||||
expect(typeof port).toBe('number');
|
||||
expect(port).toBe(3001);
|
||||
});
|
||||
|
||||
test('should handle config updates at runtime', async () => {
|
||||
const dataServiceDir = join(TEST_DIR, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
await initializeServiceConfig();
|
||||
const configManager = (await import('../src/index')).getConfigManager();
|
||||
|
||||
// Update config at runtime (useful for testing)
|
||||
configManager.set({
|
||||
service: {
|
||||
port: 9999
|
||||
}
|
||||
});
|
||||
|
||||
const updatedConfig = getConfig();
|
||||
expect(updatedConfig.service.port).toBe(9999);
|
||||
|
||||
// Other values should be preserved
|
||||
expect(updatedConfig.app.name).toBe('data-ingestion');
|
||||
});
|
||||
|
||||
test('should work across multiple service initializations', async () => {
|
||||
// Simulate multiple services in the same process (like tests)
|
||||
|
||||
// First service
|
||||
const dataServiceDir = join(TEST_DIR, 'apps', 'data-ingestion');
|
||||
process.chdir(dataServiceDir);
|
||||
|
||||
let config = await initializeServiceConfig();
|
||||
expect(config.app.name).toBe('data-ingestion');
|
||||
|
||||
// Reset and switch to another service
|
||||
resetConfig();
|
||||
const webApiDir = join(TEST_DIR, 'apps', 'web-api');
|
||||
process.chdir(webApiDir);
|
||||
|
||||
config = await initializeServiceConfig();
|
||||
expect(config.app.name).toBe('web-api');
|
||||
|
||||
// Each service should get its own config
|
||||
expect(config.service.port).toBe(4000); // web-api port
|
||||
});
|
||||
});
|
||||
|
||||
const TEST_ROOT = TEST_DIR;
|
||||
|
||||
function setupRealUsageScenarios() {
|
||||
const scenarios = {
|
||||
root: TEST_ROOT,
|
||||
dataService: join(TEST_ROOT, 'apps', 'data-ingestion'),
|
||||
webApi: join(TEST_ROOT, 'apps', 'web-api'),
|
||||
cacheLib: join(TEST_ROOT, 'libs', 'cache'),
|
||||
};
|
||||
|
||||
// Create directory structure
|
||||
Object.values(scenarios).forEach(dir => {
|
||||
mkdirSync(join(dir, 'config'), { recursive: true });
|
||||
});
|
||||
|
||||
// Root config (monorepo/config/*)
|
||||
const rootConfigs = {
|
||||
development: {
|
||||
app: {
|
||||
name: 'stock-bot-monorepo',
|
||||
version: '1.0.0'
|
||||
},
|
||||
database: {
|
||||
postgres: {
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
database: 'trading_bot',
|
||||
username: 'trading_user',
|
||||
password: 'trading_pass_dev'
|
||||
},
|
||||
questdb: {
|
||||
host: 'localhost',
|
||||
port: 9009,
|
||||
database: 'questdb'
|
||||
},
|
||||
mongodb: {
|
||||
host: 'localhost',
|
||||
port: 27017,
|
||||
database: 'stock'
|
||||
},
|
||||
dragonfly: {
|
||||
host: 'localhost',
|
||||
port: 6379
|
||||
}
|
||||
},
|
||||
logging: {
|
||||
level: 'info',
|
||||
format: 'json'
|
||||
},
|
||||
providers: {
|
||||
yahoo: {
|
||||
name: 'Yahoo Finance',
|
||||
enabled: true,
|
||||
priority: 1,
|
||||
baseUrl: 'https://query1.finance.yahoo.com'
|
||||
},
|
||||
eod: {
|
||||
name: 'EOD Historical Data',
|
||||
enabled: false,
|
||||
priority: 2,
|
||||
apiKey: 'demo-api-key',
|
||||
baseUrl: 'https://eodhistoricaldata.com/api'
|
||||
}
|
||||
}
|
||||
},
|
||||
production: {
|
||||
logging: {
|
||||
level: 'warn'
|
||||
},
|
||||
database: {
|
||||
postgres: {
|
||||
host: 'prod-postgres.internal',
|
||||
port: 5432
|
||||
}
|
||||
}
|
||||
},
|
||||
test: {
|
||||
logging: {
|
||||
level: 'debug'
|
||||
},
|
||||
database: {
|
||||
postgres: {
|
||||
database: 'trading_bot_test'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object.entries(rootConfigs).forEach(([env, config]) => {
|
||||
writeFileSync(
|
||||
join(scenarios.root, 'config', `${env}.json`),
|
||||
JSON.stringify(config, null, 2)
|
||||
);
|
||||
});
|
||||
|
||||
// Data service config
|
||||
writeFileSync(
|
||||
join(scenarios.dataService, 'config', 'development.json'),
|
||||
JSON.stringify({
|
||||
app: {
|
||||
name: 'data-ingestion'
|
||||
},
|
||||
service: {
|
||||
name: 'data-ingestion',
|
||||
port: 3001,
|
||||
workers: 2
|
||||
}
|
||||
}, null, 2)
|
||||
);
|
||||
|
||||
// Web API config
|
||||
writeFileSync(
|
||||
join(scenarios.webApi, 'config', 'development.json'),
|
||||
JSON.stringify({
|
||||
app: {
|
||||
name: 'web-api'
|
||||
},
|
||||
service: {
|
||||
name: 'web-api',
|
||||
port: 4000,
|
||||
cors: {
|
||||
origin: ['http://localhost:3000', 'http://localhost:4200']
|
||||
}
|
||||
}
|
||||
}, null, 2)
|
||||
);
|
||||
|
||||
// Cache lib config
|
||||
writeFileSync(
|
||||
join(scenarios.cacheLib, 'config', 'development.json'),
|
||||
JSON.stringify({
|
||||
app: {
|
||||
name: 'cache-lib'
|
||||
},
|
||||
service: {
|
||||
name: 'cache-lib'
|
||||
}
|
||||
}, null, 2)
|
||||
);
|
||||
|
||||
// Root .env file
|
||||
writeFileSync(
|
||||
join(scenarios.root, '.env'),
|
||||
`NODE_ENV=development
|
||||
DEBUG=true
|
||||
# Provider API keys
|
||||
EOD_API_KEY=demo-key
|
||||
WEBSHARE_API_KEY=demo-webshare-key
|
||||
`
|
||||
);
|
||||
|
||||
// Service-specific .env files
|
||||
writeFileSync(
|
||||
join(scenarios.dataService, '.env'),
|
||||
`SERVICE_DEBUG=true
|
||||
DATA_SERVICE_RATE_LIMIT=1000
|
||||
`
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue