@remit/backend 0.0.76 → 0.0.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/auth.test.ts +12 -0
- package/src/handlers/outbox.test.ts +104 -2
package/package.json
CHANGED
package/src/auth.test.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import { deriveAccountConfigId } from "./auth.js";
|
|
4
|
+
|
|
5
|
+
describe("derived ids are stored primary keys: a changed value orphans every row already written and needs a migration, never a new expectation here", () => {
|
|
6
|
+
test("deriveAccountConfigId pins the account a Cognito subject resolves to", () => {
|
|
7
|
+
assert.equal(
|
|
8
|
+
deriveAccountConfigId("golden-cognito-sub"),
|
|
9
|
+
"97h2fhd0c32ocenk6ju12oxto",
|
|
10
|
+
);
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -143,6 +143,22 @@ const createInMemoryOutboxRepository = (): IOutboxMessageRepository => {
|
|
|
143
143
|
const acceptingSqsClient = (): SQSClient =>
|
|
144
144
|
({ send: async () => ({}) }) as unknown as SQSClient;
|
|
145
145
|
|
|
146
|
+
/** A queue that refuses every send until `accept()` is called. */
|
|
147
|
+
const refusingSqsClient = (): { client: SQSClient; accept: () => void } => {
|
|
148
|
+
let accepting = false;
|
|
149
|
+
return {
|
|
150
|
+
client: {
|
|
151
|
+
send: async () => {
|
|
152
|
+
if (!accepting) throw new Error("SQS unavailable");
|
|
153
|
+
return {};
|
|
154
|
+
},
|
|
155
|
+
} as unknown as SQSClient,
|
|
156
|
+
accept: () => {
|
|
157
|
+
accepting = true;
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
|
|
146
162
|
const accountRepository = {
|
|
147
163
|
get: async () => ({
|
|
148
164
|
accountId: ACCOUNT_ID,
|
|
@@ -210,7 +226,7 @@ const createAttachmentRepository = (
|
|
|
210
226
|
},
|
|
211
227
|
}) as unknown as IOutboxAttachmentRepository;
|
|
212
228
|
|
|
213
|
-
const installClient = (): void => {
|
|
229
|
+
const installClient = (sqsClient: SQSClient = acceptingSqsClient()): void => {
|
|
214
230
|
const outboxMessage = createInMemoryOutboxRepository();
|
|
215
231
|
const storage = createMockStorageService();
|
|
216
232
|
attachmentRows = new Map<string, OutboxAttachmentItem>();
|
|
@@ -230,7 +246,7 @@ const installClient = (): void => {
|
|
|
230
246
|
outboxAttachmentService,
|
|
231
247
|
accountService: accountRepository,
|
|
232
248
|
sqsSmtpQueueUrl: "http://localhost:9324/queue/outbox-test",
|
|
233
|
-
sqsClient
|
|
249
|
+
sqsClient,
|
|
234
250
|
}),
|
|
235
251
|
} as unknown as RemitClient);
|
|
236
252
|
};
|
|
@@ -259,6 +275,8 @@ const updateDraft =
|
|
|
259
275
|
OutboxDetailOperations.OutboxDetailOperations_updateOutboxMessage as Handler;
|
|
260
276
|
const deleteDraft =
|
|
261
277
|
OutboxDetailOperations.OutboxDetailOperations_deleteOutboxMessage as Handler;
|
|
278
|
+
const getMessage =
|
|
279
|
+
OutboxDetailOperations.OutboxDetailOperations_getOutboxMessage as Handler;
|
|
262
280
|
|
|
263
281
|
type Outcome =
|
|
264
282
|
| { readonly ok: true; readonly body: Record<string, unknown> }
|
|
@@ -394,6 +412,90 @@ describe("an outbox entry that has left draft (#604)", () => {
|
|
|
394
412
|
});
|
|
395
413
|
});
|
|
396
414
|
|
|
415
|
+
describe("a send whose enqueue fails (#845.8)", () => {
|
|
416
|
+
const draftAgainstQueue = async (
|
|
417
|
+
queue: SQSClient,
|
|
418
|
+
): Promise<{ outboxMessageId: string; response: APIGatewayProxyResult }> => {
|
|
419
|
+
installClient(queue);
|
|
420
|
+
const draft = await createDraft(
|
|
421
|
+
requestContext({}),
|
|
422
|
+
authorizedEvent({
|
|
423
|
+
accountId: ACCOUNT_ID,
|
|
424
|
+
toAddresses: ["recipient@example.com"],
|
|
425
|
+
subject: "the one that got stuck",
|
|
426
|
+
textBody: "sending",
|
|
427
|
+
}),
|
|
428
|
+
);
|
|
429
|
+
const outboxMessageId = String(draft.outboxMessageId);
|
|
430
|
+
const response = await respond(() =>
|
|
431
|
+
sendMessage(
|
|
432
|
+
requestContext({ params: { outboxMessageId } }),
|
|
433
|
+
authorizedEvent(),
|
|
434
|
+
),
|
|
435
|
+
);
|
|
436
|
+
return { outboxMessageId, response };
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
const statusOf = async (outboxMessageId: string): Promise<unknown> => {
|
|
440
|
+
const response = await respond(() =>
|
|
441
|
+
getMessage(
|
|
442
|
+
requestContext({ params: { outboxMessageId } }),
|
|
443
|
+
authorizedEvent(),
|
|
444
|
+
),
|
|
445
|
+
);
|
|
446
|
+
assert.equal(response.statusCode, 200);
|
|
447
|
+
return (JSON.parse(response.body) as { status?: string }).status;
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
it("answers 500, never a success the send never had", async () => {
|
|
451
|
+
const { response } = await draftAgainstQueue(refusingSqsClient().client);
|
|
452
|
+
|
|
453
|
+
assert.equal(response.statusCode, 500);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it("leaves the row a draft, not stranded at queued", async () => {
|
|
457
|
+
const { outboxMessageId } = await draftAgainstQueue(
|
|
458
|
+
refusingSqsClient().client,
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
assert.equal(await statusOf(outboxMessageId), OutboxMessageStatus.draft);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it("still lets the user discard what could not be queued", async () => {
|
|
465
|
+
const { outboxMessageId } = await draftAgainstQueue(
|
|
466
|
+
refusingSqsClient().client,
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const response = await respond(() =>
|
|
470
|
+
deleteDraft(
|
|
471
|
+
requestContext({ params: { outboxMessageId } }),
|
|
472
|
+
authorizedEvent(),
|
|
473
|
+
),
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
assert.equal(response.statusCode, 204);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it("sends once the queue comes back", async () => {
|
|
480
|
+
const queue = refusingSqsClient();
|
|
481
|
+
const { outboxMessageId } = await draftAgainstQueue(queue.client);
|
|
482
|
+
queue.accept();
|
|
483
|
+
|
|
484
|
+
const response = await respond(() =>
|
|
485
|
+
sendMessage(
|
|
486
|
+
requestContext({ params: { outboxMessageId } }),
|
|
487
|
+
authorizedEvent(),
|
|
488
|
+
),
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
assert.equal(response.statusCode, 200);
|
|
492
|
+
assert.equal(
|
|
493
|
+
(JSON.parse(response.body) as { status?: string }).status,
|
|
494
|
+
OutboxMessageStatus.queued,
|
|
495
|
+
);
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
397
499
|
describe("discarding a draft that carries files (#679)", () => {
|
|
398
500
|
it("takes the stored bytes with it, leaving nothing behind", async () => {
|
|
399
501
|
installClient();
|