Give IncomingRequests a port instead of the Session it drives #33
@@ -88,8 +88,7 @@ src/
|
|||||||
|
|
||||||
Imports point one way: `defs` knows nothing above it but `result.ts`, `pdu` uses `defs`, `session`
|
Imports point one way: `defs` knows nothing above it but `result.ts`, `pdu` uses `defs`, `session`
|
||||||
uses `pdu`, and `client`/`server` use `session`. The one way back up is the `Session` handed to
|
uses `pdu`, and `client`/`server` use `session`. The one way back up is the `Session` handed to
|
||||||
`createSms()`, imported as a type only; `IncomingRequests` reaches its session through the
|
`createSms()`, imported as a type only.
|
||||||
`IncomingDeps` port.
|
|
||||||
|
|
||||||
**Parameter order is wire order.** The key order inside `cmds.*.params` is the order the fields are
|
**Parameter order is wire order.** The key order inside `cmds.*.params` is the order the fields are
|
||||||
written to and read from the buffer. Never sort those alphabetically — the alphabetical-ordering
|
written to and read from the buffer. Never sort those alphabetically — the alphabetical-ordering
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export type IncomingDeps = {
|
|||||||
offerSms: (sms: Sms) => boolean;
|
offerSms: (sms: Sms) => boolean;
|
||||||
/** The application's first refusal, answering true where it took the request itself. */
|
/** The application's first refusal, answering true where it took the request itself. */
|
||||||
onRequest?: ((pduObj: PduObject) => Promise<boolean> | boolean) | undefined;
|
onRequest?: ((pduObj: PduObject) => Promise<boolean> | boolean) | undefined;
|
||||||
peerUnbound: () => Promise<unknown>;
|
peerUnbound: () => Promise<VoidResult>;
|
||||||
reportDlr: (dlr: Dlr, pduObj: PduObject) => void;
|
reportDlr: (dlr: Dlr, pduObj: PduObject) => void;
|
||||||
reportError: (err: Error) => void;
|
reportError: (err: Error) => void;
|
||||||
reportMessageDlr: (merged: MessageDlr) => void;
|
reportMessageDlr: (merged: MessageDlr) => void;
|
||||||
|
|||||||
+29
-32
@@ -100,7 +100,6 @@ function abortAfter(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A port with no link behind it; the session is only what an Sms carries and answers through. */
|
|
||||||
function stubPort(session: Session, port: Partial<IncomingDeps> = {}): IncomingDeps {
|
function stubPort(session: Session, port: Partial<IncomingDeps> = {}): IncomingDeps {
|
||||||
return {
|
return {
|
||||||
answer: (pduObj, status, params) => session.sendReturn(pduObj, status, params),
|
answer: (pduObj, status, params) => session.sendReturn(pduObj, status, params),
|
||||||
@@ -109,7 +108,7 @@ function stubPort(session: Session, port: Partial<IncomingDeps> = {}): IncomingD
|
|||||||
createSms: (input, handlers) => createSms({ ...input, session }, handlers),
|
createSms: (input, handlers) => createSms({ ...input, session }, handlers),
|
||||||
linkEnd: () => 'smsc',
|
linkEnd: () => 'smsc',
|
||||||
offerSms: sms => session.emit('sms', sms),
|
offerSms: sms => session.emit('sms', sms),
|
||||||
peerUnbound: () => Promise.resolve(),
|
peerUnbound: () => Promise.resolve({}),
|
||||||
reportDlr: () => undefined,
|
reportDlr: () => undefined,
|
||||||
reportError: () => undefined,
|
reportError: () => undefined,
|
||||||
reportMessageDlr: () => undefined,
|
reportMessageDlr: () => undefined,
|
||||||
@@ -773,36 +772,6 @@ describe('reconnect', () => {
|
|||||||
assert.equal(messages, 1, 'the harness delivers a message whose link stayed');
|
assert.equal(messages, 1, 'the harness delivers a message whose link stayed');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('answers an unbind before asking the session to end, and answers a command outside the bind', async t => {
|
|
||||||
const session = new Session({ sock: new net.Socket() });
|
|
||||||
|
|
||||||
closeAfter(t, session);
|
|
||||||
|
|
||||||
const calls: string[] = [];
|
|
||||||
const incoming = new IncomingRequests({
|
|
||||||
deps: stubPort(session, {
|
|
||||||
answer: (pduObj, status) => {
|
|
||||||
calls.push(`${pduObj.cmdName} ${status ?? 'ESME_ROK'}`);
|
|
||||||
|
|
||||||
return Promise.resolve({});
|
|
||||||
},
|
|
||||||
bindAllows: cmdName => cmdName !== 'submit_sm',
|
|
||||||
peerUnbound: () => {
|
|
||||||
calls.push('peerUnbound');
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
dlrMerger: new DlrMerger({ log: silentLog, max: 10, timeout: 10_000 }),
|
|
||||||
log: silentLog,
|
|
||||||
});
|
|
||||||
|
|
||||||
await incoming.handle(submitPdu(1));
|
|
||||||
await incoming.handle({ ...submitPdu(2), cmdId: 0x00000006, cmdName: 'unbind', params: {} });
|
|
||||||
|
|
||||||
assert.deepEqual(calls, ['submit_sm ESME_RINVBNDSTS', 'unbind ESME_ROK', 'peerUnbound']);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('does not reconnect after an explicit close', async t => {
|
test('does not reconnect after an explicit close', async t => {
|
||||||
const smpp = await startServer(t);
|
const smpp = await startServer(t);
|
||||||
const { session } = await connect(t, smpp, { reconnect: { maxDelay: 50, minDelay: 10 } });
|
const { session } = await connect(t, smpp, { reconnect: { maxDelay: 50, minDelay: 10 } });
|
||||||
@@ -3114,6 +3083,34 @@ describe('graceful shutdown', () => {
|
|||||||
|
|
||||||
assert.deepEqual(reported, []);
|
assert.deepEqual(reported, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('answers a peer\'s unbind before asking the session to end', async t => {
|
||||||
|
const session = new Session({ sock: new net.Socket() });
|
||||||
|
|
||||||
|
closeAfter(t, session);
|
||||||
|
|
||||||
|
const calls: string[] = [];
|
||||||
|
const incoming = new IncomingRequests({
|
||||||
|
deps: stubPort(session, {
|
||||||
|
answer: pduObj => {
|
||||||
|
calls.push(pduObj.cmdName);
|
||||||
|
|
||||||
|
return Promise.resolve({});
|
||||||
|
},
|
||||||
|
peerUnbound: () => {
|
||||||
|
calls.push('peerUnbound');
|
||||||
|
|
||||||
|
return Promise.resolve({});
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
dlrMerger: new DlrMerger({ log: silentLog, max: 10, timeout: 10_000 }),
|
||||||
|
log: silentLog,
|
||||||
|
});
|
||||||
|
|
||||||
|
await incoming.handle({ ...submitPdu(1), cmdId: 0x00000006, cmdName: 'unbind', params: {} });
|
||||||
|
|
||||||
|
assert.deepEqual(calls, ['unbind', 'peerUnbound']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('message id notation', () => {
|
describe('message id notation', () => {
|
||||||
|
|||||||
@@ -301,8 +301,7 @@ next work ([decision](docs/decisions.md#internals-and-tests)).
|
|||||||
says "`src/` stays flat until a module has to move for another reason. Valid while that map is
|
says "`src/` stays flat until a module has to move for another reason. Valid while that map is
|
||||||
what a reader navigates by" — and both architects reported that the map is now AGENTS.md rather
|
what a reader navigates by" — and both architects reported that the map is now AGENTS.md rather
|
||||||
than the tree, which is that premise failing. `todo.md` already carries the opposite
|
than the tree, which is that premise failing. `todo.md` already carries the opposite
|
||||||
instruction under Worth doing. Two records, opposite answers; one has to go. Do it in the same
|
instruction under Worth doing. Two records, opposite answers; one has to go.
|
||||||
change as the `IncomingRequests` port or the imports are rewritten twice.
|
|
||||||
|
|
||||||
- [ ] **Split `test/session-extras.test.ts` by the question each block answers.** 3,010 lines, 19
|
- [ ] **Split `test/session-extras.test.ts` by the question each block answers.** 3,010 lines, 19
|
||||||
unrelated `describe` blocks whose names are already the file names they should be. With
|
unrelated `describe` blocks whose names are already the file names they should be. With
|
||||||
|
|||||||
Reference in New Issue
Block a user