@natlibfi/melinda-rest-api-commons 6.1.0-alpha.0 → 6.2.0-alpha.0
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/.github/workflows/melinda-node-tests-and-publish.yml +4 -2
- package/README.md +53 -5
- package/dist/amqp.d.ts +41 -0
- package/dist/amqp.d.ts.map +1 -0
- package/dist/amqp.js +237 -235
- package/dist/amqp.js.map +1 -7
- package/dist/constants.d.ts +49 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +38 -38
- package/dist/constants.js.map +1 -7
- package/dist/helpers/conversion.d.ts +8 -0
- package/dist/helpers/conversion.d.ts.map +1 -0
- package/dist/helpers/conversion.js +70 -64
- package/dist/helpers/conversion.js.map +1 -7
- package/dist/helpers/fix-constants.d.ts +76 -0
- package/dist/helpers/fix-constants.d.ts.map +1 -0
- package/dist/helpers/fix-constants.js +41 -41
- package/dist/helpers/fix-constants.js.map +1 -7
- package/dist/helpers/fix-handle-tempurns.d.ts +3 -0
- package/dist/helpers/fix-handle-tempurns.d.ts.map +1 -0
- package/dist/helpers/fix-handle-tempurns.js +73 -71
- package/dist/helpers/fix-handle-tempurns.js.map +1 -7
- package/dist/helpers/fix-strip-f884s.d.ts +10 -0
- package/dist/helpers/fix-strip-f884s.d.ts.map +1 -0
- package/dist/helpers/fix-strip-f884s.js +161 -163
- package/dist/helpers/fix-strip-f884s.js.map +1 -7
- package/dist/helpers/fix.d.ts +6 -0
- package/dist/helpers/fix.d.ts.map +1 -0
- package/dist/helpers/fix.js +133 -121
- package/dist/helpers/fix.js.map +1 -7
- package/dist/helpers/validation.d.ts +9 -0
- package/dist/helpers/validation.d.ts.map +1 -0
- package/dist/helpers/validation.js +14 -16
- package/dist/helpers/validation.js.map +1 -7
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -7
- package/dist/mongo.d.ts +165 -0
- package/dist/mongo.d.ts.map +1 -0
- package/dist/mongo.js +595 -547
- package/dist/mongo.js.map +1 -7
- package/dist/mongoError.d.ts +2 -0
- package/dist/mongoError.d.ts.map +1 -0
- package/dist/mongoError.js +19 -0
- package/dist/mongoError.js.map +1 -0
- package/dist/mongoLog.d.ts +50 -0
- package/dist/mongoLog.d.ts.map +1 -0
- package/dist/mongoLog.js +274 -242
- package/dist/mongoLog.js.map +1 -7
- package/dist/utils.d.ts +36 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +112 -110
- package/dist/utils.js.map +1 -7
- package/eslint.config.ts +66 -0
- package/package.json +15 -11
- package/{tests/amqp-error-branches.test.js → test/amqp-error-branches.test.ts} +68 -52
- package/{tests/amqp.healthtest.js → test/amqp.healthtest.ts} +7 -3
- package/{tests/amqp.tests.localtest.js → test/amqp.tests.localtest.ts} +54 -35
- package/{tests/helpers/conversion.test.js → test/helpers/conversion.test.ts} +26 -14
- package/{tests/helpers/fix-edge.test.js → test/helpers/fix-edge.test.ts} +16 -12
- package/{tests/helpers/fix.test.js → test/helpers/fix.test.ts} +14 -8
- package/{tests/helpers/validation.test.js → test/helpers/validation.test.ts} +7 -6
- package/{tests/mongo-add-blob-size.test.js → test/mongo-add-blob-size.test.ts} +14 -15
- package/{tests/mongo-check-and-check-state.test.js → test/mongo-check-and-check-state.test.ts} +6 -8
- package/{tests/mongo-check-and-set-import-job-state.test.js → test/mongo-check-and-set-import-job-state.test.ts} +6 -9
- package/{tests/mongo-check-timeout.test.js → test/mongo-check-timeout.test.ts} +6 -9
- package/{tests/mongo-create-bulk.test.js → test/mongo-create-bulk.test.ts} +6 -7
- package/{tests/mongo-create-prio.test.js → test/mongo-create-prio.test.ts} +6 -6
- package/{tests/mongo-error-branches.test.js → test/mongo-error-branches.test.ts} +147 -51
- package/{tests/mongo-get-one.test.js → test/mongo-get-one.test.ts} +6 -6
- package/{tests/mongo-get-stream.test.js → test/mongo-get-stream.test.ts} +6 -8
- package/{tests/mongo-push-ids.test.js → test/mongo-push-ids.test.ts} +6 -6
- package/{tests/mongo-push-messages.test.js → test/mongo-push-messages.test.ts} +6 -6
- package/{tests/mongo-query-by-id.test.js → test/mongo-query-by-id.test.ts} +6 -9
- package/{tests/mongo-query.test.js → test/mongo-query.test.ts} +6 -7
- package/{tests/mongo-read-content.test.js → test/mongo-read-content.test.ts} +6 -9
- package/{tests/mongo-remove.test.js → test/mongo-remove.test.ts} +6 -8
- package/{tests/mongo-set-blob-size.test.js → test/mongo-set-blob-size.test.ts} +6 -6
- package/{tests/mongo-set-import-job-state.test.js → test/mongo-set-import-job-state.test.ts} +6 -6
- package/{tests/mongo-set-operation.test.js → test/mongo-set-operation.test.ts} +6 -6
- package/{tests/mongo-set-operations.test.js → test/mongo-set-operations.test.ts} +6 -6
- package/{tests/mongo-set-state.test.js → test/mongo-set-state.test.ts} +6 -6
- package/{tests/mongoLog-protect.test.js → test/mongoLog-protect.test.ts} +18 -17
- package/{tests/mongoLog.test.js → test/mongoLog.test.ts} +8 -8
- package/{tests/testUtils.js → test/testUtils.ts} +49 -15
- package/{tests/utils.test.js → test/utils.test.ts} +5 -5
- package/tsconfig.json +62 -0
- package/tsconfig.test.json +17 -0
- package/dist/helpers/fix-utils.js +0 -39
- package/dist/helpers/fix-utils.js.map +0 -7
- package/eslint.config.js +0 -53
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
|
|
2
1
|
import assert from 'node:assert';
|
|
3
2
|
import {test} from 'node:test';
|
|
4
3
|
import {Readable, PassThrough} from 'node:stream';
|
|
5
4
|
import httpStatus from 'http-status';
|
|
6
5
|
import {MongoDriverError} from 'mongodb';
|
|
7
6
|
import {Error as ApiError} from '@natlibfi/melinda-commons';
|
|
8
|
-
import createMongo from '../src/mongo.
|
|
9
|
-
import createMongoLog from '../src/mongoLog.
|
|
7
|
+
import createMongo from '../src/mongo.ts';
|
|
8
|
+
import createMongoLog from '../src/mongoLog.ts';
|
|
10
9
|
|
|
11
10
|
const DUMMY_URI = 'mongodb://stub:27017/rest-api';
|
|
12
11
|
const COLLECTION = 'foobar';
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
// the deps seam takes unknown-typed dependencies, so plain stub objects
|
|
14
|
+
// are fine to inject (the driver types are never exercised here)
|
|
15
|
+
|
|
16
|
+
function makeOperator(overrides: Record<string, any> = {}) {
|
|
15
17
|
return {
|
|
16
18
|
insertOne: async () => ({acknowledged: true, insertedId: 1}),
|
|
17
19
|
deleteOne: async () => ({acknowledged: true, deletedCount: 1}),
|
|
@@ -19,7 +21,7 @@ function makeOperator(overrides = {}) {
|
|
|
19
21
|
};
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
function makeGridFSBucket(overrides = {}) {
|
|
24
|
+
function makeGridFSBucket(overrides: Record<string, any> = {}) {
|
|
23
25
|
return {
|
|
24
26
|
find: () => ({toArray: async () => []}),
|
|
25
27
|
openDownloadStreamByName: () => {
|
|
@@ -29,10 +31,18 @@ function makeGridFSBucket(overrides = {}) {
|
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
/**
|
|
35
|
+
* @param deps the injected stub operator/gridFSBucket
|
|
36
|
+
*/
|
|
37
|
+
async function makeMongo(deps: Record<string, any>) {
|
|
33
38
|
return createMongo(DUMMY_URI, COLLECTION, 'rest-api', deps);
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
// The 400-guard tests pass intentionally malformed inputs (non-string
|
|
42
|
+
// correlationId, non-array ids, ...) that break the operator param types on
|
|
43
|
+
// purpose; this helper bypasses the type check for those objects
|
|
44
|
+
const asMalformed = <T>(params: any): T => params as T;
|
|
45
|
+
|
|
36
46
|
test('createPrio: insertOne with acknowledged=false throws ApiError 500', async () => {
|
|
37
47
|
const mongo = await makeMongo({
|
|
38
48
|
operator: makeOperator({insertOne: async () => ({acknowledged: false})}),
|
|
@@ -60,7 +70,7 @@ test('createPrio: insertOne rejecting throws ApiError 500 with "Mongo errored" m
|
|
|
60
70
|
(error) => {
|
|
61
71
|
assert.ok(error instanceof ApiError);
|
|
62
72
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
63
|
-
assert.ok(error.payload.includes('Mongo errored'));
|
|
73
|
+
assert.ok((error.payload as string).includes('Mongo errored'));
|
|
64
74
|
return true;
|
|
65
75
|
}
|
|
66
76
|
);
|
|
@@ -105,13 +115,12 @@ test('remove: MongoDriverError "File not found" deletes queueItem and reports wh
|
|
|
105
115
|
});
|
|
106
116
|
|
|
107
117
|
test('remove: returns {removed: true, deletedContent: true} when the queueItem and its GridFS file both exist', async () => {
|
|
108
|
-
const deletedFiles = [];
|
|
118
|
+
const deletedFiles: any[] = [];
|
|
109
119
|
const mongo = await makeMongo({
|
|
110
120
|
operator: makeOperator({deleteOne: async () => ({acknowledged: true, deletedCount: 1})}),
|
|
111
121
|
gridFSBucket: makeGridFSBucket({
|
|
112
122
|
find: () => ({toArray: async () => [{_id: 'file-1', filename: 'FOO'}]}),
|
|
113
|
-
delete: async (id) => {
|
|
114
|
-
// eslint-disable-next-line functional/immutable-data
|
|
123
|
+
delete: async (id: unknown) => {
|
|
115
124
|
deletedFiles.push(id);
|
|
116
125
|
return true;
|
|
117
126
|
}
|
|
@@ -147,7 +156,7 @@ test('remove: MongoDriverError with other message throws ApiError 500', async ()
|
|
|
147
156
|
(error) => {
|
|
148
157
|
assert.ok(error instanceof ApiError);
|
|
149
158
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
150
|
-
assert.ok(error.payload.includes('some other driver error'));
|
|
159
|
+
assert.ok((error.payload as string).includes('some other driver error'));
|
|
151
160
|
return true;
|
|
152
161
|
}
|
|
153
162
|
);
|
|
@@ -190,7 +199,7 @@ test('getStream rejects with ApiError 500 when openDownloadStreamByName throws',
|
|
|
190
199
|
(error) => {
|
|
191
200
|
assert.ok(error instanceof ApiError);
|
|
192
201
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
193
|
-
assert.ok(error.payload.includes('Mongo errored'));
|
|
202
|
+
assert.ok((error.payload as string).includes('Mongo errored'));
|
|
194
203
|
return true;
|
|
195
204
|
}
|
|
196
205
|
);
|
|
@@ -276,7 +285,7 @@ test('createBulk (stream) returns the normalized {correlationId, acknowledged, q
|
|
|
276
285
|
});
|
|
277
286
|
|
|
278
287
|
test('checkTimeOut honours MONGO_TIMEOUT_MINUTES (older item than the window is aborted)', async () => {
|
|
279
|
-
process.env
|
|
288
|
+
process.env['MONGO_TIMEOUT_MINUTES'] = '5';
|
|
280
289
|
const oldDate = new Date(Date.now() - 4 * 60 * 1000); // 4 min old: fine at 5m, not at 1m
|
|
281
290
|
const mongo = await makeMongo({
|
|
282
291
|
operator: makeOperator({
|
|
@@ -290,7 +299,7 @@ test('checkTimeOut honours MONGO_TIMEOUT_MINUTES (older item than the window is
|
|
|
290
299
|
gridFSBucket: makeGridFSBucket()
|
|
291
300
|
});
|
|
292
301
|
const result = await mongo.checkTimeOut({correlationId: 'FOO'});
|
|
293
|
-
delete process.env
|
|
302
|
+
delete process.env['MONGO_TIMEOUT_MINUTES'];
|
|
294
303
|
assert.equal(result, true);
|
|
295
304
|
});
|
|
296
305
|
|
|
@@ -299,7 +308,7 @@ test('checkTimeOut honours MONGO_TIMEOUT_MINUTES (older item than the window is
|
|
|
299
308
|
// (orphan partial chunks). Both are now wired to reject + cleanup.
|
|
300
309
|
|
|
301
310
|
test('createBulk rejects with ApiError 500 when input stream errors mid-upload, and cleans up the partial file', async () => {
|
|
302
|
-
const deletedFiles = [];
|
|
311
|
+
const deletedFiles: any[] = [];
|
|
303
312
|
// errors itself once flowing mode starts
|
|
304
313
|
const input = new Readable({
|
|
305
314
|
read() {
|
|
@@ -311,8 +320,7 @@ test('createBulk rejects with ApiError 500 when input stream errors mid-upload,
|
|
|
311
320
|
gridFSBucket: makeGridFSBucket({
|
|
312
321
|
openUploadStream: () => new PassThrough(),
|
|
313
322
|
find: () => ({toArray: async () => [{_id: 'partial-1', filename: 'FOO'}]}),
|
|
314
|
-
delete: async (id) => {
|
|
315
|
-
// eslint-disable-next-line functional/immutable-data
|
|
323
|
+
delete: async (id: unknown) => {
|
|
316
324
|
deletedFiles.push(id);
|
|
317
325
|
return true;
|
|
318
326
|
}
|
|
@@ -331,7 +339,7 @@ test('createBulk rejects with ApiError 500 when input stream errors mid-upload,
|
|
|
331
339
|
(error) => {
|
|
332
340
|
assert.ok(error instanceof ApiError);
|
|
333
341
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
334
|
-
assert.ok(error.payload.includes('input stream boom'));
|
|
342
|
+
assert.ok((error.payload as string).includes('input stream boom'));
|
|
335
343
|
return true;
|
|
336
344
|
}
|
|
337
345
|
);
|
|
@@ -363,7 +371,7 @@ test('createBulk rejects with ApiError 500 when the GridFS output stream errors
|
|
|
363
371
|
(error) => {
|
|
364
372
|
assert.ok(error instanceof ApiError);
|
|
365
373
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
366
|
-
assert.ok(error.payload.includes('disk on fire'));
|
|
374
|
+
assert.ok((error.payload as string).includes('disk on fire'));
|
|
367
375
|
return true;
|
|
368
376
|
}
|
|
369
377
|
);
|
|
@@ -375,7 +383,8 @@ test('createBulk rejects with ApiError 500 when the GridFS output stream errors
|
|
|
375
383
|
test('pushIds rejects with ApiError 400 when handledIds is not an array', async () => {
|
|
376
384
|
const mongo = await makeMongo({operator: makeOperator(), gridFSBucket: makeGridFSBucket()});
|
|
377
385
|
await assert.rejects(
|
|
378
|
-
|
|
386
|
+
// intentionally malformed input: handledIds must be string[]
|
|
387
|
+
() => mongo.pushIds(asMalformed({correlationId: 'FOO', handledIds: 'nope', rejectedIds: []})),
|
|
379
388
|
(error) => {
|
|
380
389
|
assert.ok(error instanceof ApiError);
|
|
381
390
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -387,7 +396,8 @@ test('pushIds rejects with ApiError 400 when handledIds is not an array', async
|
|
|
387
396
|
test('pushIds rejects with ApiError 400 when rejectedIds is not an array', async () => {
|
|
388
397
|
const mongo = await makeMongo({operator: makeOperator(), gridFSBucket: makeGridFSBucket()});
|
|
389
398
|
await assert.rejects(
|
|
390
|
-
|
|
399
|
+
// intentionally malformed input: rejectedIds must be string[]
|
|
400
|
+
() => mongo.pushIds(asMalformed({correlationId: 'FOO', handledIds: [], rejectedIds: undefined})),
|
|
391
401
|
(error) => {
|
|
392
402
|
assert.ok(error instanceof ApiError);
|
|
393
403
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -408,8 +418,8 @@ test('pushIds rejects with ApiError 500 "Mongo errored" when updateOne throws',
|
|
|
408
418
|
(error) => {
|
|
409
419
|
assert.ok(error instanceof ApiError);
|
|
410
420
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
411
|
-
assert.ok(error.payload.includes('Mongo errored'));
|
|
412
|
-
assert.ok(error.payload.includes('pushIds boom'));
|
|
421
|
+
assert.ok((error.payload as string).includes('Mongo errored'));
|
|
422
|
+
assert.ok((error.payload as string).includes('pushIds boom'));
|
|
413
423
|
return true;
|
|
414
424
|
}
|
|
415
425
|
);
|
|
@@ -418,7 +428,8 @@ test('pushIds rejects with ApiError 500 "Mongo errored" when updateOne throws',
|
|
|
418
428
|
test('pushMessages rejects with ApiError 400 when messages is not an array', async () => {
|
|
419
429
|
const mongo = await makeMongo({operator: makeOperator(), gridFSBucket: makeGridFSBucket()});
|
|
420
430
|
await assert.rejects(
|
|
421
|
-
|
|
431
|
+
// intentionally malformed input: messages must be an array
|
|
432
|
+
() => mongo.pushMessages(asMalformed({correlationId: 'FOO', messages: 'nope'})),
|
|
422
433
|
(error) => {
|
|
423
434
|
assert.ok(error instanceof ApiError);
|
|
424
435
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -439,8 +450,8 @@ test('pushMessages rejects with ApiError 500 "Mongo errored" when updateOne thro
|
|
|
439
450
|
(error) => {
|
|
440
451
|
assert.ok(error instanceof ApiError);
|
|
441
452
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
442
|
-
assert.ok(error.payload.includes('Mongo errored'));
|
|
443
|
-
assert.ok(error.payload.includes('pushMessages boom'));
|
|
453
|
+
assert.ok((error.payload as string).includes('Mongo errored'));
|
|
454
|
+
assert.ok((error.payload as string).includes('pushMessages boom'));
|
|
444
455
|
return true;
|
|
445
456
|
}
|
|
446
457
|
);
|
|
@@ -452,7 +463,8 @@ test('pushMessages rejects with ApiError 500 "Mongo errored" when updateOne thro
|
|
|
452
463
|
test('checkAndSetState rejects with ApiError 400 when correlationId is not a string', async () => {
|
|
453
464
|
const mongo = await makeMongo({operator: makeOperator(), gridFSBucket: makeGridFSBucket()});
|
|
454
465
|
await assert.rejects(
|
|
455
|
-
|
|
466
|
+
// intentionally malformed input: correlationId must be a string
|
|
467
|
+
() => mongo.checkAndSetState(asMalformed({correlationId: {'$ne': ''}, state: 'VALIDATING'})),
|
|
456
468
|
(error) => {
|
|
457
469
|
assert.ok(error instanceof ApiError);
|
|
458
470
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -464,7 +476,8 @@ test('checkAndSetState rejects with ApiError 400 when correlationId is not a str
|
|
|
464
476
|
test('getOne rejects with ApiError 400 when queueItemState is not a string', async () => {
|
|
465
477
|
const mongo = await makeMongo({operator: makeOperator({findOne: async () => null}), gridFSBucket: makeGridFSBucket()});
|
|
466
478
|
await assert.rejects(
|
|
467
|
-
|
|
479
|
+
// intentionally malformed input: queueItemState must be a string
|
|
480
|
+
() => mongo.getOne(asMalformed({queueItemState: {'$ne': ''}})),
|
|
468
481
|
(error) => {
|
|
469
482
|
assert.ok(error instanceof ApiError);
|
|
470
483
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -476,7 +489,8 @@ test('getOne rejects with ApiError 400 when queueItemState is not a string', asy
|
|
|
476
489
|
test('getOne rejects with ApiError 400 when importJobState is not an object', async () => {
|
|
477
490
|
const mongo = await makeMongo({operator: makeOperator({findOne: async () => null}), gridFSBucket: makeGridFSBucket()});
|
|
478
491
|
await assert.rejects(
|
|
479
|
-
|
|
492
|
+
// intentionally malformed input: importJobState must be an object
|
|
493
|
+
() => mongo.getOne(asMalformed({importJobState: 'IN_QUEUE'})),
|
|
480
494
|
(error) => {
|
|
481
495
|
assert.ok(error instanceof ApiError);
|
|
482
496
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -510,10 +524,9 @@ test('getOne rejects with ApiError 400 when an importJobState value is not a str
|
|
|
510
524
|
});
|
|
511
525
|
|
|
512
526
|
test('getOne queries findOne with a valid importJobState filter', async () => {
|
|
513
|
-
const filters = [];
|
|
527
|
+
const filters: any[] = [];
|
|
514
528
|
const mongo = await makeMongo({
|
|
515
|
-
operator: makeOperator({findOne: async (filter) => {
|
|
516
|
-
// eslint-disable-next-line functional/immutable-data
|
|
529
|
+
operator: makeOperator({findOne: async (filter: unknown) => {
|
|
517
530
|
filters.push(filter);
|
|
518
531
|
return null;
|
|
519
532
|
}}),
|
|
@@ -527,7 +540,8 @@ test('getOne queries findOne with a valid importJobState filter', async () => {
|
|
|
527
540
|
test('setBlobSize rejects with ApiError 400 when blobSize is not a number', async () => {
|
|
528
541
|
const mongo = await makeMongo({operator: makeOperator(), gridFSBucket: makeGridFSBucket()});
|
|
529
542
|
await assert.rejects(
|
|
530
|
-
|
|
543
|
+
// intentionally malformed input: blobSize must be a number
|
|
544
|
+
() => mongo.setBlobSize(asMalformed({correlationId: 'FOO', blobSize: '7'})),
|
|
531
545
|
(error) => {
|
|
532
546
|
assert.ok(error instanceof ApiError);
|
|
533
547
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -537,10 +551,9 @@ test('setBlobSize rejects with ApiError 400 when blobSize is not a number', asyn
|
|
|
537
551
|
});
|
|
538
552
|
|
|
539
553
|
test('setBlobSize stores a real number when blobSize is a number', async () => {
|
|
540
|
-
const updates = [];
|
|
554
|
+
const updates: any[] = [];
|
|
541
555
|
const mongo = await makeMongo({
|
|
542
|
-
operator: makeOperator({findOneAndUpdate: async (filter, update) => {
|
|
543
|
-
// eslint-disable-next-line functional/immutable-data
|
|
556
|
+
operator: makeOperator({findOneAndUpdate: async (filter: unknown, update: unknown) => {
|
|
544
557
|
updates.push({filter, update});
|
|
545
558
|
return {correlationId: 'FOO', blobSize: 7};
|
|
546
559
|
}}),
|
|
@@ -555,7 +568,8 @@ test('setBlobSize stores a real number when blobSize is a number', async () => {
|
|
|
555
568
|
test('pushMessages rejects with ApiError 400 when messageField is not a string', async () => {
|
|
556
569
|
const mongo = await makeMongo({operator: makeOperator(), gridFSBucket: makeGridFSBucket()});
|
|
557
570
|
await assert.rejects(
|
|
558
|
-
|
|
571
|
+
// intentionally malformed input: messageField must be a string
|
|
572
|
+
() => mongo.pushMessages(asMalformed({correlationId: 'FOO', messages: ['m1'], messageField: 42})),
|
|
559
573
|
(error) => {
|
|
560
574
|
assert.ok(error instanceof ApiError);
|
|
561
575
|
assert.equal(error.status, httpStatus.BAD_REQUEST);
|
|
@@ -588,7 +602,7 @@ test('createBulk (stream): insertOne with acknowledged=false throws ApiError 500
|
|
|
588
602
|
(error) => {
|
|
589
603
|
assert.ok(error instanceof ApiError);
|
|
590
604
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
591
|
-
assert.ok(error.payload.includes('Mongo errored'));
|
|
605
|
+
assert.ok((error.payload as string).includes('Mongo errored'));
|
|
592
606
|
return true;
|
|
593
607
|
}
|
|
594
608
|
);
|
|
@@ -625,8 +639,8 @@ test('createBulk (stream): a failing GridFS cleanup does not mask the original u
|
|
|
625
639
|
(error) => {
|
|
626
640
|
assert.ok(error instanceof ApiError);
|
|
627
641
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
628
|
-
assert.ok(error.payload.includes('input stream boom'));
|
|
629
|
-
assert.ok(!error.payload.includes('gridfs cleanup boom'));
|
|
642
|
+
assert.ok((error.payload as string).includes('input stream boom'));
|
|
643
|
+
assert.ok(!(error.payload as string).includes('gridfs cleanup boom'));
|
|
630
644
|
return true;
|
|
631
645
|
}
|
|
632
646
|
);
|
|
@@ -644,7 +658,7 @@ test('remove: non-MongoDriverError from deleteOne throws ApiError 500 with the e
|
|
|
644
658
|
(error) => {
|
|
645
659
|
assert.ok(error instanceof ApiError);
|
|
646
660
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
647
|
-
assert.ok(error.payload.includes('plain delete boom'));
|
|
661
|
+
assert.ok((error.payload as string).includes('plain delete boom'));
|
|
648
662
|
return true;
|
|
649
663
|
}
|
|
650
664
|
);
|
|
@@ -663,18 +677,62 @@ test('setOperation rejects with ApiError 404 when findOneAndUpdate returns null'
|
|
|
663
677
|
(error) => {
|
|
664
678
|
assert.ok(error instanceof ApiError);
|
|
665
679
|
assert.equal(error.status, httpStatus.NOT_FOUND);
|
|
666
|
-
assert.ok(error.payload.message.includes('not found'));
|
|
680
|
+
assert.ok((error.payload as {message: string}).message.includes('not found'));
|
|
667
681
|
return true;
|
|
668
682
|
}
|
|
669
683
|
);
|
|
670
684
|
});
|
|
671
685
|
|
|
686
|
+
// Q-3: previously-unwrapped public methods now reject with ApiError 500
|
|
687
|
+
// ("Mongo errored: ...") when the driver fails, instead of leaking the raw
|
|
688
|
+
// MongoDriverError. Non-driver errors (400/404 ApiErrors) still pass
|
|
689
|
+
// through unchanged.
|
|
690
|
+
|
|
691
|
+
test('mongo query: MongoDriverError from find rejects with ApiError 500 "Mongo errored"', async () => {
|
|
692
|
+
const mongo = await makeMongo({
|
|
693
|
+
operator: makeOperator({find: () => {
|
|
694
|
+
throw new MongoDriverError('query driver boom');
|
|
695
|
+
}}),
|
|
696
|
+
gridFSBucket: makeGridFSBucket()
|
|
697
|
+
});
|
|
698
|
+
await assert.rejects(
|
|
699
|
+
() => mongo.query({}),
|
|
700
|
+
mongoErrored500('query driver boom')
|
|
701
|
+
);
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
test('mongo queryById: MongoDriverError from findOne rejects with ApiError 500 "Mongo errored"', async () => {
|
|
705
|
+
const mongo = await makeMongo({
|
|
706
|
+
operator: makeOperator({findOne: async () => {
|
|
707
|
+
throw new MongoDriverError('queryById driver boom');
|
|
708
|
+
}}),
|
|
709
|
+
gridFSBucket: makeGridFSBucket()
|
|
710
|
+
});
|
|
711
|
+
await assert.rejects(
|
|
712
|
+
() => mongo.queryById({correlationId: 'FOO'}),
|
|
713
|
+
mongoErrored500('queryById driver boom')
|
|
714
|
+
);
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
test('mongo checkTimeOut: MongoDriverError from findOne rejects with ApiError 500 "Mongo errored"', async () => {
|
|
718
|
+
const mongo = await makeMongo({
|
|
719
|
+
operator: makeOperator({findOne: async () => {
|
|
720
|
+
throw new MongoDriverError('checkTimeOut driver boom');
|
|
721
|
+
}}),
|
|
722
|
+
gridFSBucket: makeGridFSBucket()
|
|
723
|
+
});
|
|
724
|
+
await assert.rejects(
|
|
725
|
+
() => mongo.checkTimeOut({correlationId: 'FOO'}),
|
|
726
|
+
mongoErrored500('checkTimeOut driver boom')
|
|
727
|
+
);
|
|
728
|
+
});
|
|
729
|
+
|
|
672
730
|
// mongoLog: same deps-seam convention as mongo (factory last param). When
|
|
673
731
|
// deps.collection is provided no real connection is made and every
|
|
674
732
|
// db.collection('logs') call routes to the injected object. These tests
|
|
675
733
|
// cover the catch blocks that re-wrap driver failures as ApiError 500.
|
|
676
734
|
|
|
677
|
-
function makeLogCollection(overrides = {}) {
|
|
735
|
+
function makeLogCollection(overrides: Record<string, any> = {}) {
|
|
678
736
|
return {
|
|
679
737
|
insertOne: async () => ({acknowledged: true, insertedId: 1}),
|
|
680
738
|
updateMany: async () => ({acknowledged: true, matchedCount: 0, modifiedCount: 0}),
|
|
@@ -683,16 +741,19 @@ function makeLogCollection(overrides = {}) {
|
|
|
683
741
|
};
|
|
684
742
|
}
|
|
685
743
|
|
|
686
|
-
|
|
744
|
+
/**
|
|
745
|
+
* @param deps the injected stub collection
|
|
746
|
+
*/
|
|
747
|
+
async function makeMongoLog(deps: Record<string, any>) {
|
|
687
748
|
return createMongoLog(DUMMY_URI, 'rest-api', deps);
|
|
688
749
|
}
|
|
689
750
|
|
|
690
|
-
function mongoErrored500(text) {
|
|
691
|
-
return (error) => {
|
|
751
|
+
function mongoErrored500(text: string) {
|
|
752
|
+
return (error: unknown) => {
|
|
692
753
|
assert.ok(error instanceof ApiError);
|
|
693
754
|
assert.equal(error.status, httpStatus.INTERNAL_SERVER_ERROR);
|
|
694
|
-
assert.ok(error.payload.includes('Mongo errored'));
|
|
695
|
-
assert.ok(error.payload.includes(text));
|
|
755
|
+
assert.ok((error.payload as string).includes('Mongo errored'));
|
|
756
|
+
assert.ok((error.payload as string).includes(text));
|
|
696
757
|
return true;
|
|
697
758
|
};
|
|
698
759
|
}
|
|
@@ -723,6 +784,42 @@ test('mongoLog addLogItem: insertOne rejecting throws ApiError 500 with "Mongo e
|
|
|
723
784
|
);
|
|
724
785
|
});
|
|
725
786
|
|
|
787
|
+
test('mongoLog query: MongoDriverError from find rejects with ApiError 500 "Mongo errored"', async () => {
|
|
788
|
+
const mongoLog = await makeMongoLog({
|
|
789
|
+
collection: makeLogCollection({find: () => {
|
|
790
|
+
throw new MongoDriverError('mongoLog query driver boom');
|
|
791
|
+
}})
|
|
792
|
+
});
|
|
793
|
+
await assert.rejects(
|
|
794
|
+
() => mongoLog.query({}),
|
|
795
|
+
mongoErrored500('mongoLog query driver boom')
|
|
796
|
+
);
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
test('mongoLog queryById: MongoDriverError from find rejects with ApiError 500 "Mongo errored"', async () => {
|
|
800
|
+
const mongoLog = await makeMongoLog({
|
|
801
|
+
collection: makeLogCollection({find: () => {
|
|
802
|
+
throw new MongoDriverError('mongoLog queryById driver boom');
|
|
803
|
+
}})
|
|
804
|
+
});
|
|
805
|
+
await assert.rejects(
|
|
806
|
+
() => mongoLog.queryById('FOO'),
|
|
807
|
+
mongoErrored500('mongoLog queryById driver boom')
|
|
808
|
+
);
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
test('mongoLog getListOfCatalogers: MongoDriverError from distinct rejects with ApiError 500 "Mongo errored"', async () => {
|
|
812
|
+
const mongoLog = await makeMongoLog({
|
|
813
|
+
collection: makeLogCollection({distinct: async () => {
|
|
814
|
+
throw new MongoDriverError('mongoLog distinct driver boom');
|
|
815
|
+
}})
|
|
816
|
+
});
|
|
817
|
+
await assert.rejects(
|
|
818
|
+
() => mongoLog.getListOfCatalogers(),
|
|
819
|
+
mongoErrored500('mongoLog distinct driver boom')
|
|
820
|
+
);
|
|
821
|
+
});
|
|
822
|
+
|
|
726
823
|
test('mongoLog protect: updateMany rejecting throws ApiError 500 with "Mongo errored" message', async () => {
|
|
727
824
|
const mongoLog = await makeMongoLog({
|
|
728
825
|
collection: makeLogCollection({updateMany: async () => {
|
|
@@ -772,11 +869,10 @@ test('mongoLog removeBySequences: deleteMany rejecting throws ApiError 500 with
|
|
|
772
869
|
});
|
|
773
870
|
|
|
774
871
|
test('mongoLog protect: injected collection routes the update and returns its result', async () => {
|
|
775
|
-
const filters = [];
|
|
872
|
+
const filters: any[] = [];
|
|
776
873
|
const result = {acknowledged: true, matchedCount: 1, modifiedCount: 1};
|
|
777
874
|
const mongoLog = await makeMongoLog({
|
|
778
|
-
collection: makeLogCollection({updateMany: async (filter) => {
|
|
779
|
-
// eslint-disable-next-line functional/immutable-data
|
|
875
|
+
collection: makeLogCollection({updateMany: async (filter: unknown) => {
|
|
780
876
|
filters.push(filter);
|
|
781
877
|
return result;
|
|
782
878
|
}})
|
|
@@ -4,10 +4,10 @@ import mongoFixturesFactory from '@natlibfi/fixura-mongo';
|
|
|
4
4
|
import generateTests from '@natlibfi/fixugen';
|
|
5
5
|
import createDebugLogger from 'debug';
|
|
6
6
|
//import {handleError, compareToFirstDbEntry, compareToDbEntry, formatQueueItem, streamToString} from './testUtils.js';
|
|
7
|
-
import {getMongoOperator, handleError} from './testUtils.
|
|
7
|
+
import {getMongoOperator, handleError} from './testUtils.ts';
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
let mongoFixtures;
|
|
10
|
+
let mongoFixtures: any;
|
|
11
11
|
const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons/mongo:get-one:test');
|
|
12
12
|
|
|
13
13
|
generateTests({
|
|
@@ -41,14 +41,14 @@ generateTests({
|
|
|
41
41
|
|
|
42
42
|
async function initMongofixtures() {
|
|
43
43
|
mongoFixtures = await mongoFixturesFactory({
|
|
44
|
-
recurse: false,
|
|
45
44
|
rootPath: [import.meta.dirname, '..', 'test-fixtures', 'mongo', 'get-one'],
|
|
46
45
|
gridFS: {bucketName: 'foobar'},
|
|
47
46
|
useObjectId: true
|
|
48
47
|
});
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
async function callback({
|
|
50
|
+
async function callback(callbackParams: Record<string, any>) {
|
|
51
|
+
const {
|
|
52
52
|
getFixture,
|
|
53
53
|
functionName,
|
|
54
54
|
params,
|
|
@@ -57,14 +57,14 @@ async function callback({
|
|
|
57
57
|
expectedErrorMessage = '',
|
|
58
58
|
expectedErrorStatus = '',
|
|
59
59
|
expectedOpResult = undefined
|
|
60
|
-
}
|
|
60
|
+
} = callbackParams;
|
|
61
61
|
|
|
62
62
|
const mongoOperator = await getMongoOperator(mongoFixtures);
|
|
63
63
|
//const expectedResult = await getFixture('expectedResult.json');
|
|
64
64
|
|
|
65
65
|
await doPreFillDb(preFillDb);
|
|
66
66
|
|
|
67
|
-
async function doPreFillDb(preFillDb) {
|
|
67
|
+
async function doPreFillDb(preFillDb: boolean) {
|
|
68
68
|
if (preFillDb) {
|
|
69
69
|
await mongoFixtures.populate(getFixture('dbContents.json'));
|
|
70
70
|
return;
|
|
@@ -4,9 +4,9 @@ import mongoFixturesFactory from '@natlibfi/fixura-mongo';
|
|
|
4
4
|
import generateTests from '@natlibfi/fixugen';
|
|
5
5
|
import createDebugLogger from 'debug';
|
|
6
6
|
//import {handleError, compareToFirstDbEntry, compareToDbEntry, formatQueueItem, streamToString} from './testUtils.js';
|
|
7
|
-
import {getMongoOperator, handleError, streamToString} from './testUtils.
|
|
7
|
+
import {getMongoOperator, handleError, streamToString} from './testUtils.ts';
|
|
8
8
|
|
|
9
|
-
let mongoFixtures;
|
|
9
|
+
let mongoFixtures: any;
|
|
10
10
|
const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons/mongo:get-stream:test');
|
|
11
11
|
|
|
12
12
|
generateTests({
|
|
@@ -40,15 +40,14 @@ generateTests({
|
|
|
40
40
|
|
|
41
41
|
async function initMongofixtures() {
|
|
42
42
|
mongoFixtures = await mongoFixturesFactory({
|
|
43
|
-
recurse: false,
|
|
44
43
|
rootPath: [import.meta.dirname, '..', 'test-fixtures', 'mongo', 'get-stream'],
|
|
45
44
|
gridFS: {bucketName: 'foobar'},
|
|
46
45
|
useObjectId: true
|
|
47
46
|
});
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
async function callback(callbackParams: Record<string, any>) {
|
|
50
|
+
const {
|
|
52
51
|
getFixture,
|
|
53
52
|
functionName,
|
|
54
53
|
params,
|
|
@@ -58,14 +57,14 @@ async function callback({
|
|
|
58
57
|
expectedErrorStatus = '',
|
|
59
58
|
contentStream = false,
|
|
60
59
|
createBulkParams = undefined
|
|
61
|
-
}
|
|
60
|
+
} = callbackParams;
|
|
62
61
|
|
|
63
62
|
const mongoOperator = await getMongoOperator(mongoFixtures);
|
|
64
63
|
//const expectedResult = await getFixture('expectedResult.json');
|
|
65
64
|
|
|
66
65
|
await doPreFillDb(preFillDb);
|
|
67
66
|
|
|
68
|
-
async function doPreFillDb(preFillDb) {
|
|
67
|
+
async function doPreFillDb(preFillDb: boolean) {
|
|
69
68
|
if (preFillDb) {
|
|
70
69
|
await mongoFixtures.populate(getFixture('dbContents.json'));
|
|
71
70
|
return;
|
|
@@ -80,7 +79,6 @@ async function callback({
|
|
|
80
79
|
debug(JSON.stringify(params));
|
|
81
80
|
//correlationId
|
|
82
81
|
|
|
83
|
-
// eslint-disable-next-line functional/no-conditional-statements
|
|
84
82
|
if (createBulkParams) {
|
|
85
83
|
const stream = contentStream ? await getFixture({components: ['contentStream'], reader: READERS.STREAM}) : createBulkParams.stream;
|
|
86
84
|
//debug(stream);
|
|
@@ -3,10 +3,10 @@ import mongoFixturesFactory from '@natlibfi/fixura-mongo';
|
|
|
3
3
|
import generateTests from '@natlibfi/fixugen';
|
|
4
4
|
import createDebugLogger from 'debug';
|
|
5
5
|
//import {handleError, compareToFirstDbEntry, compareToDbEntry, formatQueueItem, streamToString} from './testUtils.js';
|
|
6
|
-
import {getMongoOperator, handleError, compareToFirstDbEntry} from './testUtils.
|
|
6
|
+
import {getMongoOperator, handleError, compareToFirstDbEntry} from './testUtils.ts';
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
let mongoFixtures;
|
|
9
|
+
let mongoFixtures: any;
|
|
10
10
|
const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons/mongo:push-ids:test');
|
|
11
11
|
|
|
12
12
|
generateTests({
|
|
@@ -40,14 +40,14 @@ generateTests({
|
|
|
40
40
|
|
|
41
41
|
async function initMongofixtures() {
|
|
42
42
|
mongoFixtures = await mongoFixturesFactory({
|
|
43
|
-
recurse: false,
|
|
44
43
|
rootPath: [import.meta.dirname, '..', 'test-fixtures', 'mongo', 'push-ids'],
|
|
45
44
|
gridFS: {bucketName: 'foobar'},
|
|
46
45
|
useObjectId: true
|
|
47
46
|
});
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
async function callback({
|
|
49
|
+
async function callback(callbackParams: Record<string, any>) {
|
|
50
|
+
const {
|
|
51
51
|
getFixture,
|
|
52
52
|
functionName,
|
|
53
53
|
params,
|
|
@@ -56,14 +56,14 @@ async function callback({
|
|
|
56
56
|
expectedToThrow = false,
|
|
57
57
|
expectedErrorMessage = '',
|
|
58
58
|
expectedErrorStatus = ''
|
|
59
|
-
}
|
|
59
|
+
} = callbackParams;
|
|
60
60
|
|
|
61
61
|
const mongoOperator = await getMongoOperator(mongoFixtures);
|
|
62
62
|
const expectedResult = await getFixture('expectedResult.json');
|
|
63
63
|
|
|
64
64
|
await doPreFillDb(preFillDb);
|
|
65
65
|
|
|
66
|
-
async function doPreFillDb(preFillDb) {
|
|
66
|
+
async function doPreFillDb(preFillDb: boolean) {
|
|
67
67
|
if (preFillDb) {
|
|
68
68
|
await mongoFixtures.populate(getFixture('dbContents.json'));
|
|
69
69
|
return;
|
|
@@ -4,9 +4,9 @@ import mongoFixturesFactory from '@natlibfi/fixura-mongo';
|
|
|
4
4
|
import generateTests from '@natlibfi/fixugen';
|
|
5
5
|
import createDebugLogger from 'debug';
|
|
6
6
|
//import {handleError, compareToFirstDbEntry, compareToDbEntry, formatQueueItem, streamToString} from './testUtils.js';
|
|
7
|
-
import {getMongoOperator, handleError, compareToFirstDbEntry} from './testUtils.
|
|
7
|
+
import {getMongoOperator, handleError, compareToFirstDbEntry} from './testUtils.ts';
|
|
8
8
|
|
|
9
|
-
let mongoFixtures;
|
|
9
|
+
let mongoFixtures: any;
|
|
10
10
|
const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons/mongo:push-messages:test');
|
|
11
11
|
|
|
12
12
|
generateTests({
|
|
@@ -40,14 +40,14 @@ generateTests({
|
|
|
40
40
|
|
|
41
41
|
async function initMongofixtures() {
|
|
42
42
|
mongoFixtures = await mongoFixturesFactory({
|
|
43
|
-
recurse: false,
|
|
44
43
|
rootPath: [import.meta.dirname, '..', 'test-fixtures', 'mongo', 'push-messages'],
|
|
45
44
|
gridFS: {bucketName: 'foobar'},
|
|
46
45
|
useObjectId: true
|
|
47
46
|
});
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
async function callback({
|
|
49
|
+
async function callback(callbackParams: Record<string, any>) {
|
|
50
|
+
const {
|
|
51
51
|
getFixture,
|
|
52
52
|
functionName,
|
|
53
53
|
params,
|
|
@@ -56,14 +56,14 @@ async function callback({
|
|
|
56
56
|
expectedToThrow = false,
|
|
57
57
|
expectedErrorMessage = '',
|
|
58
58
|
expectedErrorStatus = ''
|
|
59
|
-
}
|
|
59
|
+
} = callbackParams;
|
|
60
60
|
|
|
61
61
|
const mongoOperator = await getMongoOperator(mongoFixtures);
|
|
62
62
|
const expectedResult = await getFixture('expectedResult.json');
|
|
63
63
|
|
|
64
64
|
await doPreFillDb(preFillDb);
|
|
65
65
|
|
|
66
|
-
async function doPreFillDb(preFillDb) {
|
|
66
|
+
async function doPreFillDb(preFillDb: boolean) {
|
|
67
67
|
if (preFillDb) {
|
|
68
68
|
await mongoFixtures.populate(getFixture('dbContents.json'));
|
|
69
69
|
return;
|