108 lines
3.3 KiB
TypeScript
108 lines
3.3 KiB
TypeScript
|
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||
|
|
import { EmailOpsHandler } from '../ts/opsserver/handlers/email-ops.handler.js';
|
||
|
|
import { StatsHandler } from '../ts/opsserver/handlers/stats.handler.js';
|
||
|
|
|
||
|
|
const createRouterStub = () => ({
|
||
|
|
addTypedHandler: (_handler: unknown) => {},
|
||
|
|
});
|
||
|
|
|
||
|
|
const queueItems = [
|
||
|
|
{
|
||
|
|
id: 'older-failed',
|
||
|
|
status: 'failed',
|
||
|
|
attempts: 3,
|
||
|
|
nextAttempt: new Date('2026-04-14T10:00:00.000Z'),
|
||
|
|
lastError: '550 mailbox unavailable',
|
||
|
|
createdAt: new Date('2026-04-14T09:00:00.000Z'),
|
||
|
|
processingResult: {
|
||
|
|
from: 'sender@example.com',
|
||
|
|
to: ['recipient@example.net'],
|
||
|
|
cc: ['copy@example.net'],
|
||
|
|
subject: 'Older message',
|
||
|
|
text: 'hello',
|
||
|
|
headers: { 'x-test': '1' },
|
||
|
|
getMessageId: () => 'message-older',
|
||
|
|
getAttachmentsSize: () => 64,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
id: 'newer-delivered',
|
||
|
|
status: 'delivered',
|
||
|
|
attempts: 1,
|
||
|
|
createdAt: new Date('2026-04-14T11:00:00.000Z'),
|
||
|
|
processingResult: {
|
||
|
|
email: {
|
||
|
|
from: 'fresh@example.com',
|
||
|
|
to: ['new@example.net'],
|
||
|
|
cc: [],
|
||
|
|
subject: 'Newest message',
|
||
|
|
},
|
||
|
|
html: '<p>newest</p>',
|
||
|
|
text: 'newest',
|
||
|
|
headers: { 'x-fresh': 'true' },
|
||
|
|
getMessageId: () => 'message-newer',
|
||
|
|
getAttachmentsSize: () => 0,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
tap.test('EmailOpsHandler maps queue items using public email server APIs', async () => {
|
||
|
|
const opsHandler = new EmailOpsHandler({
|
||
|
|
viewRouter: createRouterStub(),
|
||
|
|
adminRouter: createRouterStub(),
|
||
|
|
dcRouterRef: {
|
||
|
|
emailServer: {
|
||
|
|
getQueueItems: () => queueItems,
|
||
|
|
getQueueItem: (id: string) => queueItems.find((item) => item.id === id),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
const emails = (opsHandler as any).getAllQueueEmails();
|
||
|
|
expect(emails.map((email: any) => email.id)).toEqual(['newer-delivered', 'older-failed']);
|
||
|
|
expect(emails[0].status).toEqual('delivered');
|
||
|
|
expect(emails[1].status).toEqual('bounced');
|
||
|
|
expect(emails[0].messageId).toEqual('message-newer');
|
||
|
|
|
||
|
|
const detail = (opsHandler as any).getEmailDetail('older-failed');
|
||
|
|
expect(detail?.toList).toEqual(['recipient@example.net']);
|
||
|
|
expect(detail?.cc).toEqual(['copy@example.net']);
|
||
|
|
expect(detail?.rejectionReason).toEqual('550 mailbox unavailable');
|
||
|
|
expect(detail?.headers).toEqual({ 'x-test': '1' });
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('StatsHandler reports queue status using public email server APIs', async () => {
|
||
|
|
const statsHandler = new StatsHandler({
|
||
|
|
viewRouter: createRouterStub(),
|
||
|
|
dcRouterRef: {
|
||
|
|
emailServer: {
|
||
|
|
getQueueStats: () => ({
|
||
|
|
queueSize: 2,
|
||
|
|
status: {
|
||
|
|
pending: 0,
|
||
|
|
processing: 1,
|
||
|
|
failed: 1,
|
||
|
|
deferred: 1,
|
||
|
|
delivered: 1,
|
||
|
|
},
|
||
|
|
}),
|
||
|
|
getQueueItems: () => queueItems,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
const queueStatus = await (statsHandler as any).getQueueStatus();
|
||
|
|
expect(queueStatus.pending).toEqual(0);
|
||
|
|
expect(queueStatus.active).toEqual(1);
|
||
|
|
expect(queueStatus.failed).toEqual(1);
|
||
|
|
expect(queueStatus.retrying).toEqual(1);
|
||
|
|
expect(queueStatus.items.map((item: any) => item.id)).toEqual(['newer-delivered', 'older-failed']);
|
||
|
|
expect(queueStatus.items[1].nextRetry).toEqual(new Date('2026-04-14T10:00:00.000Z').getTime());
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('cleanup', async () => {
|
||
|
|
await tap.stopForcefully();
|
||
|
|
});
|
||
|
|
|
||
|
|
export default tap.start();
|