added cli-covarage tool and fixed more tests

This commit is contained in:
Boki 2025-06-26 14:23:01 -04:00
parent b63e58784c
commit b845a8eade
57 changed files with 11917 additions and 295 deletions

View file

@ -6,6 +6,15 @@ import {
registerDatabaseServices,
} from '../src/registrations';
// Mock the queue module
mock.module('@stock-bot/queue', () => ({
createServiceCache: mock(() => ({
get: mock(() => Promise.resolve(null)),
set: mock(() => Promise.resolve()),
del: mock(() => Promise.resolve()),
})),
}));
describe('DI Registrations', () => {
describe('registerCacheServices', () => {
it('should register null cache when redis disabled', () => {
@ -98,137 +107,123 @@ describe('DI Registrations', () => {
describe('registerDatabaseServices', () => {
it('should register MongoDB when config exists', () => {
const container = createContainer();
const mockLogger = {
info: () => {},
error: () => {},
warn: () => {},
debug: () => {},
// Mock MongoDB client
const mockMongoClient = {
connect: mock(() => Promise.resolve()),
disconnect: mock(() => Promise.resolve()),
getDb: mock(() => ({})),
};
container.register({
logger: asValue(mockLogger),
});
const config = {
service: {
name: 'test-service',
type: 'WORKER' as const,
// Mock the MongoDB factory
mock.module('@stock-bot/mongodb', () => ({
MongoDBClient: class {
constructor() {
return mockMongoClient;
}
},
}));
const config = {
mongodb: {
enabled: true,
uri: 'mongodb://localhost:27017',
uri: 'mongodb://localhost',
database: 'test-db',
},
redis: { enabled: false, host: 'localhost', port: 6379 },
postgres: {
enabled: false,
host: 'localhost',
port: 5432,
database: 'test',
user: 'test',
password: 'test',
},
} as any;
registerDatabaseServices(container, config);
// Check that mongoClient is registered (not mongodb)
const registrations = container.registrations;
expect(registrations.mongoClient).toBeDefined();
expect(container.hasRegistration('mongoClient')).toBe(true);
});
it('should register Postgres when config exists', () => {
it('should register PostgreSQL when config exists', () => {
const container = createContainer();
const mockLogger = { info: () => {}, error: () => {} };
container.register({
logger: asValue(mockLogger),
});
const config = {
service: {
name: 'test-service',
type: 'WORKER' as const,
// Mock Postgres client
const mockPostgresClient = {
connect: mock(() => Promise.resolve()),
disconnect: mock(() => Promise.resolve()),
query: mock(() => Promise.resolve({ rows: [] })),
};
// Mock the Postgres factory
mock.module('@stock-bot/postgres', () => ({
PostgresClient: class {
constructor() {
return mockPostgresClient;
}
},
}));
const config = {
postgres: {
enabled: true,
host: 'localhost',
port: 5432,
database: 'test-db',
user: 'user',
password: 'pass',
database: 'test-db',
},
mongodb: { enabled: false, uri: 'mongodb://localhost', database: 'test' },
redis: { enabled: false, host: 'localhost', port: 6379 },
} as any;
registerDatabaseServices(container, config);
const registrations = container.registrations;
expect(registrations.postgresClient).toBeDefined();
expect(container.hasRegistration('postgresClient')).toBe(true);
});
it('should register QuestDB when config exists', () => {
const container = createContainer();
const mockLogger = { info: () => {}, error: () => {} };
container.register({
logger: asValue(mockLogger),
});
const config = {
service: {
name: 'test-service',
type: 'WORKER' as const,
// Mock QuestDB client
const mockQuestdbClient = {
connect: mock(() => Promise.resolve()),
disconnect: mock(() => Promise.resolve()),
query: mock(() => Promise.resolve({ data: [] })),
};
// Mock the QuestDB factory
mock.module('@stock-bot/questdb', () => ({
QuestDBClient: class {
constructor() {
return mockQuestdbClient;
}
},
}));
const config = {
questdb: {
enabled: true,
host: 'localhost',
httpPort: 9000,
pgPort: 8812,
influxPort: 9009,
database: 'test',
database: 'questdb',
},
mongodb: { enabled: false, uri: 'mongodb://localhost', database: 'test' },
postgres: {
enabled: false,
host: 'localhost',
port: 5432,
database: 'test',
user: 'test',
password: 'test',
},
redis: { enabled: false, host: 'localhost', port: 6379 },
} as any;
registerDatabaseServices(container, config);
const registrations = container.registrations;
expect(registrations.questdbClient).toBeDefined();
expect(container.hasRegistration('questdbClient')).toBe(true);
});
it('should register null for disabled databases', () => {
it('should not register disabled databases', () => {
const container = createContainer();
const config = {
service: {
name: 'test-service',
type: 'WORKER' as const,
},
mongodb: { enabled: false, uri: 'mongodb://localhost', database: 'test' },
postgres: {
enabled: false,
host: 'localhost',
port: 5432,
database: 'test',
user: 'test',
password: 'test',
},
redis: { enabled: false, host: 'localhost', port: 6379 },
// questdb is optional
mongodb: { enabled: false },
postgres: { enabled: false },
questdb: undefined,
} as any;
registerDatabaseServices(container, config);
// Services are registered but with null values when disabled
expect(container.hasRegistration('mongoClient')).toBe(true);
expect(container.hasRegistration('postgresClient')).toBe(true);
expect(container.hasRegistration('questdbClient')).toBe(true);
// Verify they resolve to null
expect(container.resolve('mongoClient')).toBeNull();
expect(container.resolve('postgresClient')).toBeNull();
expect(container.resolve('questdbClient')).toBeNull();
@ -236,90 +231,91 @@ describe('DI Registrations', () => {
});
describe('registerApplicationServices', () => {
it('should register browser service when config exists', () => {
it('should register browser when config exists', () => {
const container = createContainer();
const mockLogger = { info: () => {}, error: () => {} };
container.register({
logger: asValue(mockLogger),
config: asValue({
browser: { headless: true },
}),
});
// Mock browser factory
const mockBrowser = {
launch: mock(() => Promise.resolve()),
close: mock(() => Promise.resolve()),
};
mock.module('@stock-bot/browser', () => ({
createBrowser: () => mockBrowser,
}));
const config = {
service: {
name: 'test-service',
type: 'WORKER' as const,
},
browser: {
headless: true,
timeout: 30000,
},
redis: { enabled: true, host: 'localhost', port: 6379 },
mongodb: { enabled: false, uri: 'mongodb://localhost', database: 'test' },
postgres: {
enabled: false,
host: 'localhost',
port: 5432,
database: 'test',
user: 'test',
password: 'test',
},
} as any;
registerApplicationServices(container, config);
const registrations = container.registrations;
expect(registrations.browser).toBeDefined();
expect(container.hasRegistration('browser')).toBe(true);
});
it('should register proxy service when config exists', () => {
it('should register proxy when config exists', () => {
const container = createContainer();
const mockLogger = { info: () => {}, error: () => {} };
container.register({
logger: asValue(mockLogger),
});
// Mock proxy factory
const mockProxy = {
getProxy: mock(() => 'http://proxy:8080'),
};
mock.module('@stock-bot/proxy', () => ({
createProxyManager: () => mockProxy,
}));
const config = {
service: {
name: 'test-service',
type: 'WORKER' as const,
},
proxy: {
enabled: true,
cachePrefix: 'proxy:',
ttl: 3600,
},
redis: { enabled: true, host: 'localhost', port: 6379 },
mongodb: { enabled: false, uri: 'mongodb://localhost', database: 'test' },
postgres: {
enabled: false,
host: 'localhost',
port: 5432,
database: 'test',
user: 'test',
password: 'test',
url: 'http://proxy:8080',
},
} as any;
registerApplicationServices(container, config);
const registrations = container.registrations;
expect(registrations.proxyManager).toBeDefined();
expect(container.hasRegistration('proxyManager')).toBe(true);
});
it('should register queue services when queue enabled', () => {
it('should register queue manager when queue config exists', () => {
const container = createContainer();
const mockLogger = { info: () => {}, error: () => {} };
const mockHandlerRegistry = { getAllHandlers: () => [] };
// Mock dependencies
container.register({
logger: asValue(mockLogger),
handlerRegistry: asValue(mockHandlerRegistry),
cache: asValue({
get: mock(() => Promise.resolve(null)),
set: mock(() => Promise.resolve()),
}),
handlerRegistry: asValue({
getHandler: mock(() => null),
getAllHandlers: mock(() => []),
}),
logger: asValue({
info: mock(() => {}),
error: mock(() => {}),
warn: mock(() => {}),
debug: mock(() => {}),
}),
});
// Mock queue manager
const mockQueueManager = {
getQueue: mock(() => ({})),
startAllWorkers: mock(() => {}),
shutdown: mock(() => Promise.resolve()),
};
mock.module('@stock-bot/queue', () => ({
QueueManager: class {
constructor() {
return mockQueueManager;
}
},
}));
const config = {
service: {
name: 'test-service',
@ -329,62 +325,91 @@ describe('DI Registrations', () => {
enabled: true,
workers: 2,
concurrency: 5,
enableScheduledJobs: true,
defaultJobOptions: {},
},
redis: {
enabled: true,
host: 'localhost',
port: 6379,
},
mongodb: { enabled: false, uri: 'mongodb://localhost', database: 'test' },
postgres: {
enabled: false,
host: 'localhost',
port: 5432,
database: 'test',
user: 'test',
password: 'test',
},
} as any;
registerApplicationServices(container, config);
const registrations = container.registrations;
expect(registrations.queueManager).toBeDefined();
expect(container.hasRegistration('queueManager')).toBe(true);
});
it('should not register queue when disabled', () => {
it('should not register services when configs are missing', () => {
const container = createContainer();
const config = {} as any;
registerApplicationServices(container, config);
expect(container.hasRegistration('browser')).toBe(true);
expect(container.hasRegistration('proxyManager')).toBe(true);
expect(container.hasRegistration('queueManager')).toBe(true);
// They should be registered as null
const browser = container.resolve('browser');
const proxyManager = container.resolve('proxyManager');
const queueManager = container.resolve('queueManager');
expect(browser).toBe(null);
expect(proxyManager).toBe(null);
expect(queueManager).toBe(null);
});
});
describe('dependency resolution', () => {
it('should properly resolve cache dependencies', () => {
const container = createContainer();
const config = {
service: {
name: 'test-api',
type: 'API' as const,
},
queue: {
enabled: false,
name: 'test-service',
serviceName: 'test-service',
},
redis: {
enabled: true,
host: 'localhost',
port: 6379,
db: 0,
},
mongodb: { enabled: false, uri: 'mongodb://localhost', database: 'test' },
postgres: {
enabled: false,
host: 'localhost',
port: 5432,
database: 'test',
user: 'test',
password: 'test',
} as any;
registerCacheServices(container, config);
// Should have registered cache
expect(container.hasRegistration('cache')).toBe(true);
expect(container.hasRegistration('globalCache')).toBe(true);
});
it('should handle circular dependencies gracefully', () => {
const container = createContainer();
// Register services with potential circular deps
container.register({
serviceA: asFunction(({ serviceB }) => ({ b: serviceB })).singleton(),
serviceB: asFunction(({ serviceA }) => ({ a: serviceA })).singleton(),
});
// This should throw or handle gracefully
expect(() => container.resolve('serviceA')).toThrow();
});
});
describe('registration options', () => {
it('should register services as singletons', () => {
const container = createContainer();
const config = {
browser: {
headless: true,
timeout: 30000,
},
} as any;
registerApplicationServices(container, config);
const registrations = container.registrations;
expect(registrations.queueManager).toBeDefined();
expect(container.resolve('queueManager')).toBeNull();
// Check that browser was registered as singleton
const registration = container.getRegistration('browser');
expect(registration).toBeDefined();
expect(registration?.lifetime).toBe('SINGLETON');
});
});
});