removed old tests, created new ones and format

This commit is contained in:
Boki 2025-06-25 07:46:59 -04:00
parent 7579afa3c3
commit b03231b849
57 changed files with 4092 additions and 5901 deletions

View file

@ -1,7 +1,7 @@
import { asClass, asFunction, createContainer, InjectionMode, type AwilixContainer } from 'awilix';
import type { BaseAppConfig as StockBotAppConfig, UnifiedAppConfig } from '@stock-bot/config';
import { toUnifiedConfig } from '@stock-bot/config';
import { HandlerRegistry } from '@stock-bot/handler-registry';
import { asClass, asFunction, createContainer, InjectionMode, type AwilixContainer } from 'awilix';
import { appConfigSchema, type AppConfig } from '../config/schemas';
import {
registerApplicationServices,

264
libs/core/di/src/di.test.ts Normal file
View file

@ -0,0 +1,264 @@
import { describe, it, expect, beforeEach, mock } from 'bun:test';
import { createContainer, InjectionMode, asClass, asFunction, asValue } from 'awilix';
import { ServiceContainerBuilder } from './container/builder';
import { ServiceApplication } from './service-application';
import { HandlerScanner } from './scanner/handler-scanner';
import { OperationContext } from './operation-context';
import { PoolSizeCalculator } from './pool-size-calculator';
describe('Dependency Injection', () => {
describe('ServiceContainerBuilder', () => {
let builder: ServiceContainerBuilder;
beforeEach(() => {
builder = new ServiceContainerBuilder();
});
it('should create container with default configuration', async () => {
const config = {
name: 'test-service',
version: '1.0.0',
service: {
name: 'test-service',
type: 'WORKER' as const,
serviceName: 'test-service',
port: 3000,
},
log: {
level: 'info',
format: 'json',
},
};
builder.withConfig(config);
builder.skipInitialization(); // Skip initialization for testing
const container = await builder.build();
expect(container).toBeDefined();
});
it('should configure services', async () => {
const config = {
name: 'test-service',
version: '1.0.0',
service: {
name: 'test-service',
type: 'WORKER' as const,
serviceName: 'test-service',
port: 3000,
},
log: {
level: 'info',
format: 'json',
},
};
builder
.withConfig(config)
.withOptions({
enableCache: true,
enableQueue: false,
})
.skipInitialization();
const container = await builder.build();
expect(container).toBeDefined();
});
});
describe('Basic Container Operations', () => {
it('should register and resolve values', () => {
const container = createContainer({
injectionMode: InjectionMode.PROXY,
});
container.register({
testValue: asValue('test'),
});
expect(container.resolve('testValue')).toBe('test');
});
it('should register and resolve classes', () => {
class TestClass {
getValue() {
return 'test';
}
}
const container = createContainer({
injectionMode: InjectionMode.PROXY,
});
container.register({
testClass: asClass(TestClass),
});
const instance = container.resolve('testClass');
expect(instance).toBeInstanceOf(TestClass);
expect(instance.getValue()).toBe('test');
});
it('should handle dependencies', () => {
const container = createContainer({
injectionMode: InjectionMode.PROXY,
});
// Test with scoped container
container.register({
config: asValue({ host: 'localhost', port: 5432 }),
connection: asFunction(() => {
const config = container.resolve('config');
return `postgresql://${config.host}:${config.port}/mydb`;
}).scoped(),
});
const connection = container.resolve('connection');
expect(connection).toBe('postgresql://localhost:5432/mydb');
});
});
describe('OperationContext', () => {
it('should create operation context', () => {
const context = new OperationContext({
handlerName: 'test-handler',
operationName: 'test-op',
});
expect(context.traceId).toBeDefined();
expect(context.logger).toBeDefined();
expect(context.metadata).toEqual({});
});
it('should include metadata', () => {
const metadata = { userId: '123', source: 'api' };
const context = new OperationContext({
handlerName: 'test-handler',
operationName: 'test-op',
metadata,
});
expect(context.metadata).toEqual(metadata);
});
it('should track execution time', async () => {
const context = new OperationContext({
handlerName: 'test-handler',
operationName: 'test-op',
});
await new Promise(resolve => setTimeout(resolve, 10));
const executionTime = context.getExecutionTime();
expect(executionTime).toBeGreaterThanOrEqual(10);
});
it('should create child context', () => {
const parentContext = new OperationContext({
handlerName: 'parent-handler',
operationName: 'parent-op',
metadata: { parentId: '123' },
});
const childContext = parentContext.createChild('child-op', { childId: '456' });
expect(childContext.traceId).toBe(parentContext.traceId);
expect(childContext.metadata).toEqual({ parentId: '123', childId: '456' });
});
});
describe('HandlerScanner', () => {
it('should create scanner instance', () => {
const mockRegistry = {
register: mock(() => {}),
getHandlers: mock(() => []),
};
const mockContainer = createContainer({
injectionMode: InjectionMode.PROXY,
});
const scanner = new HandlerScanner(mockRegistry as any, mockContainer);
expect(scanner).toBeDefined();
expect(scanner.scanHandlers).toBeDefined();
});
});
describe('ServiceApplication', () => {
it('should create service application', () => {
const mockConfig = {
name: 'test-service',
version: '1.0.0',
service: {
name: 'test-service',
type: 'WORKER' as const,
serviceName: 'test-service',
port: 3000,
},
log: {
level: 'info',
format: 'json',
},
};
const serviceConfig = {
serviceName: 'test-service',
};
const app = new ServiceApplication(mockConfig, serviceConfig);
expect(app).toBeDefined();
expect(app.start).toBeDefined();
expect(app.stop).toBeDefined();
});
});
describe('Pool Size Calculator', () => {
it('should calculate pool size for services', () => {
const recommendation = PoolSizeCalculator.calculate('web-api');
expect(recommendation.min).toBe(2);
expect(recommendation.max).toBe(10);
expect(recommendation.idle).toBe(2);
});
it('should calculate pool size for handlers', () => {
const recommendation = PoolSizeCalculator.calculate('data-ingestion', 'batch-import');
expect(recommendation.min).toBe(10);
expect(recommendation.max).toBe(100);
expect(recommendation.idle).toBe(20);
});
it('should use custom configuration', () => {
const recommendation = PoolSizeCalculator.calculate('custom', undefined, {
minConnections: 5,
maxConnections: 50,
});
expect(recommendation.min).toBe(5);
expect(recommendation.max).toBe(50);
expect(recommendation.idle).toBe(13); // (5+50)/4 = 13.75 -> 13
});
it('should fall back to defaults', () => {
const recommendation = PoolSizeCalculator.calculate('unknown-service');
expect(recommendation.min).toBe(2);
expect(recommendation.max).toBe(10);
expect(recommendation.idle).toBe(3);
});
it('should calculate optimal pool size', () => {
const size = PoolSizeCalculator.getOptimalPoolSize(
100, // 100 requests per second
50, // 50ms average query time
100 // 100ms target latency
);
expect(size).toBeGreaterThan(0);
expect(size).toBe(50); // max(100*0.05*1.2, 100*50/100, 2) = max(6, 50, 2) = 50
});
});
});

View file

@ -1,6 +1,6 @@
import { asClass, asFunction, asValue, type AwilixContainer } from 'awilix';
import { Browser } from '@stock-bot/browser';
import { ProxyManager } from '@stock-bot/proxy';
import { asClass, asFunction, asValue, type AwilixContainer } from 'awilix';
import type { AppConfig } from '../config/schemas';
import type { ServiceDefinitions } from '../container/types';

View file

@ -82,7 +82,9 @@ export class HandlerScanner {
* Check if an exported value is a handler
*/
private isHandler(exported: any): boolean {
if (typeof exported !== 'function') {return false;}
if (typeof exported !== 'function') {
return false;
}
// Check for handler metadata added by decorators
const hasHandlerName = !!(exported as any).__handlerName;