Inbox injection endpoint: POST /api/messages + MCP inject_message (#12) (#18)
CI / build + unit (push) Successful in 1m14s
CI / build + unit (push) Successful in 1m14s
This commit was merged in pull request #18.
This commit is contained in:
@@ -561,6 +561,94 @@ describe('MeshService message history', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('MeshService injectMessage', () => {
|
||||
it('injects rx records that appear newest-first in messages()', () => {
|
||||
const svc = new MeshService();
|
||||
expect(svc.messages()).toEqual([]);
|
||||
|
||||
const r1 = svc.injectMessage('first');
|
||||
const r2 = svc.injectMessage('second', KAMIL_NUM);
|
||||
expect(r1.id).toBeGreaterThan(0); // random non-zero uint32, like tx ids
|
||||
expect(r2.id).toBeGreaterThan(0);
|
||||
|
||||
expect(svc.messages()).toEqual([
|
||||
{
|
||||
id: r2.id,
|
||||
dir: 'rx',
|
||||
from: KAMIL_NUM,
|
||||
text: 'second',
|
||||
channel: 0,
|
||||
at: expect.any(Number),
|
||||
},
|
||||
{
|
||||
id: r1.id,
|
||||
dir: 'rx',
|
||||
text: 'first',
|
||||
channel: 0,
|
||||
at: expect.any(Number),
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('omits from when not provided and rejects empty text or invalid from', () => {
|
||||
const svc = new MeshService();
|
||||
const rec = svc.injectMessage('no sender');
|
||||
expect(svc.messages()[0]).toEqual({
|
||||
id: rec.id,
|
||||
dir: 'rx',
|
||||
text: 'no sender',
|
||||
channel: 0,
|
||||
at: expect.any(Number),
|
||||
});
|
||||
expect(svc.messages()[0]).not.toHaveProperty('from');
|
||||
|
||||
for (const bad of ['', undefined]) {
|
||||
expect(() => svc.injectMessage(bad as unknown as string)).toThrow(
|
||||
'text must be a non-empty string',
|
||||
);
|
||||
}
|
||||
for (const bad of [0, -1, 42.5, BROADCAST_ADDR + 1]) {
|
||||
expect(() => svc.injectMessage('x', bad)).toThrow(/invalid node number/);
|
||||
}
|
||||
expect(svc.messages()).toHaveLength(1); // rejected calls add nothing
|
||||
});
|
||||
|
||||
it('caps history at 100 records, dropping the oldest', () => {
|
||||
const svc = new MeshService();
|
||||
for (let i = 0; i < 105; i++) svc.injectMessage(`m-${i}`);
|
||||
expect(svc.messages()).toHaveLength(100);
|
||||
expect(svc.messages()[0]?.text).toBe('m-104'); // newest first
|
||||
expect(svc.messages()[99]?.text).toBe('m-5'); // m-0..m-4 dropped
|
||||
});
|
||||
|
||||
it('shares the history buffer with captured packets', async () => {
|
||||
const bridge = await startBridge();
|
||||
process.env.MESH_HOST = '127.0.0.1';
|
||||
process.env.MESH_PORT = String(bridge.port);
|
||||
const svc = new MeshService();
|
||||
try {
|
||||
svc.onModuleInit();
|
||||
await waitFor(
|
||||
() => bridge.sockets.length === 1 && svc.status().connected,
|
||||
);
|
||||
|
||||
svc.injectMessage('injected');
|
||||
bridge.sockets[0].write(textPacketFrame(KAMIL_NUM, 42, 'real', 2));
|
||||
|
||||
await waitFor(() => svc.messages().length === 2);
|
||||
expect(svc.messages()[0]).toMatchObject({ dir: 'rx', text: 'real' }); // newest first
|
||||
expect(svc.messages()[1]).toMatchObject({
|
||||
dir: 'rx',
|
||||
text: 'injected',
|
||||
channel: 0,
|
||||
});
|
||||
} finally {
|
||||
svc.onModuleDestroy();
|
||||
bridge.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('MeshService telemetry', () => {
|
||||
it('captures device metrics and environment variants with from/kind/data', async () => {
|
||||
const bridge = await startBridge();
|
||||
|
||||
Reference in New Issue
Block a user