removed old tests, created new ones and format
This commit is contained in:
parent
7579afa3c3
commit
b03231b849
57 changed files with 4092 additions and 5901 deletions
|
|
@ -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
264
libs/core/di/src/di.test.ts
Normal 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
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -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';
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue