fase(2): shared infrastructure layer
This commit is contained in:
112
tests/shared/infrastructure.test.ts
Normal file
112
tests/shared/infrastructure.test.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { loadConfig } from '../../src/shared/infrastructure/Config';
|
||||
import { InProcessEventBus } from '../../src/shared/infrastructure/InProcessEventBus';
|
||||
import { LocalStorageProvider } from '../../src/shared/infrastructure/StorageProvider';
|
||||
import { createLogger } from '../../src/shared/infrastructure/Logger';
|
||||
import { DomainEvent } from '../../src/shared/domain/DomainEvent';
|
||||
import { randomUUID } from 'crypto';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import fs from 'fs';
|
||||
|
||||
// --- Config ---
|
||||
describe('Config', () => {
|
||||
it('loads with defaults when no env vars set', () => {
|
||||
const config = loadConfig();
|
||||
expect(config.port).toBe(3001);
|
||||
expect(config.db.driver).toBe('sqlite');
|
||||
expect(['development', 'test']).toContain(config.nodeEnv);
|
||||
});
|
||||
|
||||
it('picks up PORT env var', () => {
|
||||
process.env['ABE_PORT'] = '4000';
|
||||
const config = loadConfig();
|
||||
expect(config.port).toBe(4000);
|
||||
delete process.env['ABE_PORT'];
|
||||
});
|
||||
});
|
||||
|
||||
// --- EventBus ---
|
||||
describe('InProcessEventBus', () => {
|
||||
const logger = createLogger({ level: 'silent', nodeEnv: 'test' });
|
||||
|
||||
it('publishes and subscribes to events', async () => {
|
||||
const bus = new InProcessEventBus(logger);
|
||||
const received: DomainEvent[] = [];
|
||||
|
||||
bus.subscribe('test.event', {
|
||||
handle: async (event) => { received.push(event); },
|
||||
});
|
||||
|
||||
const event: DomainEvent = {
|
||||
eventId: randomUUID(),
|
||||
eventName: 'test.event',
|
||||
aggregateId: 'agg-1',
|
||||
occurredOn: new Date(),
|
||||
payload: { foo: 'bar' },
|
||||
};
|
||||
|
||||
await bus.publish(event);
|
||||
await new Promise(r => setTimeout(r, 10));
|
||||
expect(received).toHaveLength(1);
|
||||
expect(received[0]?.aggregateId).toBe('agg-1');
|
||||
});
|
||||
|
||||
it('does not crash when handler throws', async () => {
|
||||
const bus = new InProcessEventBus(logger);
|
||||
|
||||
bus.subscribe('error.event', {
|
||||
handle: async () => { throw new Error('handler error'); },
|
||||
});
|
||||
|
||||
const event: DomainEvent = {
|
||||
eventId: randomUUID(),
|
||||
eventName: 'error.event',
|
||||
aggregateId: 'agg-2',
|
||||
occurredOn: new Date(),
|
||||
payload: {},
|
||||
};
|
||||
|
||||
await expect(bus.publish(event)).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
// --- StorageProvider ---
|
||||
describe('LocalStorageProvider', () => {
|
||||
let tmpDir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'abe-test-'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('saves and retrieves data', async () => {
|
||||
const storage = new LocalStorageProvider(tmpDir);
|
||||
const data = Buffer.from('hello world');
|
||||
await storage.save('subdir/test.txt', data);
|
||||
const result = await storage.get('subdir/test.txt');
|
||||
expect(result?.toString()).toBe('hello world');
|
||||
});
|
||||
|
||||
it('returns null for missing file', async () => {
|
||||
const storage = new LocalStorageProvider(tmpDir);
|
||||
const result = await storage.get('nonexistent.txt');
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('exists returns true after save', async () => {
|
||||
const storage = new LocalStorageProvider(tmpDir);
|
||||
await storage.save('file.bin', Buffer.from([1, 2, 3]));
|
||||
expect(await storage.exists('file.bin')).toBe(true);
|
||||
expect(await storage.exists('other.bin')).toBe(false);
|
||||
});
|
||||
|
||||
it('delete removes file', async () => {
|
||||
const storage = new LocalStorageProvider(tmpDir);
|
||||
await storage.save('file.txt', Buffer.from('data'));
|
||||
await storage.delete('file.txt');
|
||||
expect(await storage.exists('file.txt')).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user