@natlibfi/melinda-rest-api-commons 6.0.1 → 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.
Files changed (94) hide show
  1. package/.github/workflows/melinda-node-tests-and-publish.yml +4 -2
  2. package/README.md +82 -0
  3. package/dist/amqp.d.ts +41 -0
  4. package/dist/amqp.d.ts.map +1 -0
  5. package/dist/amqp.js +242 -218
  6. package/dist/amqp.js.map +1 -7
  7. package/dist/constants.d.ts +49 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +38 -38
  10. package/dist/constants.js.map +1 -7
  11. package/dist/helpers/conversion.d.ts +8 -0
  12. package/dist/helpers/conversion.d.ts.map +1 -0
  13. package/dist/helpers/conversion.js +70 -65
  14. package/dist/helpers/conversion.js.map +1 -7
  15. package/dist/helpers/fix-constants.d.ts +76 -0
  16. package/dist/helpers/fix-constants.d.ts.map +1 -0
  17. package/dist/helpers/fix-constants.js +41 -41
  18. package/dist/helpers/fix-constants.js.map +1 -7
  19. package/dist/helpers/fix-handle-tempurns.d.ts +3 -0
  20. package/dist/helpers/fix-handle-tempurns.d.ts.map +1 -0
  21. package/dist/helpers/fix-handle-tempurns.js +73 -71
  22. package/dist/helpers/fix-handle-tempurns.js.map +1 -7
  23. package/dist/helpers/fix-strip-f884s.d.ts +10 -0
  24. package/dist/helpers/fix-strip-f884s.d.ts.map +1 -0
  25. package/dist/helpers/fix-strip-f884s.js +163 -151
  26. package/dist/helpers/fix-strip-f884s.js.map +1 -7
  27. package/dist/helpers/fix.d.ts +6 -0
  28. package/dist/helpers/fix.d.ts.map +1 -0
  29. package/dist/helpers/fix.js +133 -117
  30. package/dist/helpers/fix.js.map +1 -7
  31. package/dist/helpers/validation.d.ts +9 -0
  32. package/dist/helpers/validation.d.ts.map +1 -0
  33. package/dist/helpers/validation.js +14 -16
  34. package/dist/helpers/validation.js.map +1 -7
  35. package/dist/index.d.ts +13 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -7
  39. package/dist/mongo.d.ts +165 -0
  40. package/dist/mongo.d.ts.map +1 -0
  41. package/dist/mongo.js +603 -464
  42. package/dist/mongo.js.map +1 -7
  43. package/dist/mongoError.d.ts +2 -0
  44. package/dist/mongoError.d.ts.map +1 -0
  45. package/dist/mongoError.js +19 -0
  46. package/dist/mongoError.js.map +1 -0
  47. package/dist/mongoLog.d.ts +50 -0
  48. package/dist/mongoLog.d.ts.map +1 -0
  49. package/dist/mongoLog.js +282 -172
  50. package/dist/mongoLog.js.map +1 -7
  51. package/dist/utils.d.ts +36 -0
  52. package/dist/utils.d.ts.map +1 -0
  53. package/dist/utils.js +118 -87
  54. package/dist/utils.js.map +1 -7
  55. package/eslint.config.ts +66 -0
  56. package/package.json +23 -25
  57. package/test/amqp-error-branches.test.ts +551 -0
  58. package/{tests/amqp.healthtest.js → test/amqp.healthtest.ts} +19 -7
  59. package/{tests/amqp.tests.localtest.js → test/amqp.tests.localtest.ts} +66 -52
  60. package/{tests/helpers/conversion.test.js → test/helpers/conversion.test.ts} +39 -11
  61. package/test/helpers/fix-edge.test.ts +201 -0
  62. package/test/helpers/fix.test.ts +65 -0
  63. package/{tests/helpers/validation.test.js → test/helpers/validation.test.ts} +13 -8
  64. package/{tests/mongo-add-blob-size.test.js → test/mongo-add-blob-size.test.ts} +14 -15
  65. package/{tests/mongo-check-and-check-state.test.js → test/mongo-check-and-check-state.test.ts} +9 -9
  66. package/{tests/mongo-check-and-set-import-job-state.test.js → test/mongo-check-and-set-import-job-state.test.ts} +9 -10
  67. package/{tests/mongo-check-timeout.test.js → test/mongo-check-timeout.test.ts} +6 -9
  68. package/{tests/mongo-create-bulk.test.js → test/mongo-create-bulk.test.ts} +6 -7
  69. package/{tests/mongo-create-prio.test.js → test/mongo-create-prio.test.ts} +6 -6
  70. package/test/mongo-error-branches.test.ts +883 -0
  71. package/{tests/mongo-get-one.test.js → test/mongo-get-one.test.ts} +6 -6
  72. package/{tests/mongo-get-stream.test.js → test/mongo-get-stream.test.ts} +10 -9
  73. package/{tests/mongo-push-ids.test.js → test/mongo-push-ids.test.ts} +6 -6
  74. package/{tests/mongo-push-messages.test.js → test/mongo-push-messages.test.ts} +6 -6
  75. package/{tests/mongo-query-by-id.test.js → test/mongo-query-by-id.test.ts} +6 -9
  76. package/{tests/mongo-query.test.js → test/mongo-query.test.ts} +6 -7
  77. package/{tests/mongo-read-content.test.js → test/mongo-read-content.test.ts} +16 -9
  78. package/{tests/mongo-remove.test.js → test/mongo-remove.test.ts} +6 -8
  79. package/{tests/mongo-set-blob-size.test.js → test/mongo-set-blob-size.test.ts} +6 -6
  80. package/{tests/mongo-set-import-job-state.test.js → test/mongo-set-import-job-state.test.ts} +6 -6
  81. package/{tests/mongo-set-operation.test.js → test/mongo-set-operation.test.ts} +6 -6
  82. package/{tests/mongo-set-operations.test.js → test/mongo-set-operations.test.ts} +6 -6
  83. package/{tests/mongo-set-state.test.js → test/mongo-set-state.test.ts} +6 -6
  84. package/test/mongoLog-protect.test.ts +182 -0
  85. package/test/mongoLog.test.ts +191 -0
  86. package/{tests/testUtils.js → test/testUtils.ts} +49 -15
  87. package/test/utils.test.ts +360 -0
  88. package/tsconfig.json +62 -0
  89. package/tsconfig.test.json +17 -0
  90. package/dist/helpers/fix-utils.js +0 -39
  91. package/dist/helpers/fix-utils.js.map +0 -7
  92. package/eslint.config.js +0 -53
  93. package/tests/helpers/fix.test.js +0 -41
  94. package/tests/mongoLog.test.js +0 -84
@@ -4,10 +4,10 @@ import {READERS} from '@natlibfi/fixura';
4
4
  import mongoFixturesFactory from '@natlibfi/fixura-mongo';
5
5
  import generateTests from '@natlibfi/fixugen';
6
6
  //import {handleError, compareToFirstDbEntry, compareToDbEntry, formatQueueItem, streamToString} from './testUtils.js';
7
- import {getMongoOperator, handleError, compareToFirstDbEntry} from './testUtils.js';
7
+ import {getMongoOperator, handleError, compareToFirstDbEntry} from './testUtils.ts';
8
8
 
9
9
 
10
- let mongoFixtures; // eslint-disable-line functional/no-let
10
+ let mongoFixtures: any;
11
11
  const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons/mongo:set-state: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', 'set-state'],
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
  expectedToThrow = false,
58
58
  expectedErrorMessage = '',
59
59
  expectedErrorStatus = ''
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;
@@ -0,0 +1,182 @@
1
+ import assert from 'node:assert';
2
+ import {test, before, after} from 'node:test';
3
+ import mongoFixturesFactory from '@natlibfi/fixura-mongo';
4
+ import {Error as ApiError} from '@natlibfi/melinda-commons';
5
+ import createMongoLogOperator from '../src/mongoLog.ts';
6
+ import type {MongoLogOperator} from '../src/mongoLog.ts';
7
+
8
+ let mongoFixtures: any;
9
+ let mongoLogOperator: MongoLogOperator;
10
+
11
+ async function initMongofixtures() {
12
+ mongoFixtures = await mongoFixturesFactory({
13
+ rootPath: [import.meta.dirname, '..', 'test-fixtures', 'mongoLog'],
14
+ gridFS: {bucketName: 'blobs'},
15
+ useObjectId: true,
16
+ format: {
17
+ logs: {
18
+ creationTime: v => new Date(String(v)),
19
+ modificationTime: v => new Date(String(v))
20
+ }
21
+ }
22
+ });
23
+ const mongoUri = await mongoFixtures.getUri();
24
+ mongoLogOperator = await createMongoLogOperator(mongoUri, '');
25
+ }
26
+
27
+ async function cleanup() {
28
+ await mongoFixtures.clear();
29
+ await mongoFixtures.close();
30
+ }
31
+
32
+ before(async () => {
33
+ await initMongofixtures();
34
+ });
35
+
36
+ after(async () => {
37
+ await cleanup();
38
+ });
39
+
40
+ test('protect is idempotent: protecting an already protected log keeps it protected', async () => {
41
+ const logItem = {
42
+ logItemType: 'MERGE_LOG',
43
+ cataloger: 'IMP_TEST1',
44
+ correlationId: '22222222-2222-4222-8222-222222222222',
45
+ blobSequence: 1
46
+ };
47
+ await mongoLogOperator.addLogItem(logItem);
48
+
49
+ await mongoLogOperator.protect(logItem.correlationId, logItem.blobSequence);
50
+
51
+ // a second call must not toggle the log back to unprotected
52
+ await mongoLogOperator.protect(logItem.correlationId, logItem.blobSequence);
53
+
54
+ const {logs} = await mongoFixtures.dump();
55
+ const own = logs.filter((doc: any) => doc.correlationId === logItem.correlationId);
56
+ assert.equal(own.length, 1);
57
+ assert.equal(own[0].protected, true);
58
+ });
59
+
60
+ test('unprotect sets protected to false after protect', async () => {
61
+ const logItem = {
62
+ logItemType: 'MERGE_LOG',
63
+ cataloger: 'IMP_TEST1',
64
+ correlationId: '33333333-3333-4333-8333-333333333333',
65
+ blobSequence: 2
66
+ };
67
+ await mongoLogOperator.addLogItem(logItem);
68
+
69
+ await mongoLogOperator.protect(logItem.correlationId, logItem.blobSequence);
70
+ const result = await mongoLogOperator.unprotect(logItem.correlationId, logItem.blobSequence);
71
+ assert.equal(result.modifiedCount, 1);
72
+
73
+ const {logs} = await mongoFixtures.dump();
74
+ const own = logs.filter((doc: any) => doc.correlationId === logItem.correlationId);
75
+ assert.equal(own.length, 1);
76
+ assert.equal(own[0].protected, false);
77
+ });
78
+
79
+ test('unprotect without blobSequence unprotects all logs of the correlationId', async () => {
80
+ const correlationId = '44444444-4444-4444-8444-444444444444';
81
+ await mongoLogOperator.addLogItem({logItemType: 'MERGE_LOG', cataloger: 'IMP_TEST1', correlationId, blobSequence: 1});
82
+ await mongoLogOperator.addLogItem({logItemType: 'MATCH_LOG', cataloger: 'IMP_TEST1', correlationId, blobSequence: 2});
83
+
84
+ await mongoLogOperator.protect(correlationId);
85
+ const result = await mongoLogOperator.unprotect(correlationId);
86
+ assert.equal(result.modifiedCount, 2);
87
+
88
+ const {logs} = await mongoFixtures.dump();
89
+ const own = logs.filter((doc: any) => doc.correlationId === correlationId);
90
+ assert.equal(own.length, 2);
91
+ assert.ok(own.every((doc: any) => doc.protected === false));
92
+ });
93
+
94
+ test('getExpandedListOfLogs throws ApiError when logItemTypes is provided but is not an array', async () => {
95
+ await assert.rejects(
96
+ () => mongoLogOperator.getExpandedListOfLogs({logItemTypes: 'MERGE_LOG'}),
97
+ (error) => {
98
+ assert.ok(error instanceof ApiError);
99
+ assert.strictEqual(error.status, 400);
100
+ assert.ok((error.payload as string).includes('logItemTypes must be an array'));
101
+ return true;
102
+ }
103
+ );
104
+ });
105
+
106
+ test('getExpandedListOfLogs throws ApiError when logItemTypes contains an unknown element', async () => {
107
+ await assert.rejects(
108
+ () => mongoLogOperator.getExpandedListOfLogs({logItemTypes: ['MERGE_LOG', 'BOGUS_LOG']}),
109
+ (error) => {
110
+ assert.ok(error instanceof ApiError);
111
+ assert.strictEqual(error.status, 400);
112
+ assert.ok((error.payload as string).includes('Unknown logItemType'));
113
+ return true;
114
+ }
115
+ );
116
+ });
117
+
118
+ test('getExpandedListOfLogs uses Date instances for dateBefore and dateAfter as-is', async () => {
119
+ const logItem = {
120
+ logItemType: 'MERGE_LOG',
121
+ cataloger: 'IMP_TEST1',
122
+ correlationId: '66666666-6666-4666-8666-666666666666',
123
+ blobSequence: 1
124
+ };
125
+ await mongoLogOperator.addLogItem(logItem);
126
+ // both bounds as Date instances: the match must use them as-is (no UTC
127
+ // midnight anchoring), so the freshly created log is inside the window
128
+ const result = await mongoLogOperator.getExpandedListOfLogs({
129
+ logItemTypes: ['MERGE_LOG'],
130
+ catalogers: ['IMP_TEST1'],
131
+ dateBefore: new Date(Date.now() + 60 * 60 * 1000),
132
+ dateAfter: new Date(Date.now() - 60 * 60 * 1000)
133
+ });
134
+ const own = result.filter(entry => entry.correlationId === logItem.correlationId);
135
+ assert.equal(own.length, 1);
136
+ assert.equal(own[0]?.logCount, 1);
137
+ });
138
+
139
+ test('getListOfLogs throws ApiError 500 for an unknown logItemType', async () => {
140
+ await assert.rejects(
141
+ () => mongoLogOperator.getListOfLogs('BOGUS_LOG'),
142
+ (error) => {
143
+ assert.ok(error instanceof ApiError);
144
+ assert.strictEqual(error.status, 500);
145
+ assert.ok((error.payload as string).includes('Unknown logItemType'));
146
+ return true;
147
+ }
148
+ );
149
+ });
150
+
151
+ test('addLogItem with an unknown logItemType does not throw (warn path)', async () => {
152
+ const logItem = {
153
+ logItemType: 'BOGUS_LOG',
154
+ cataloger: 'IMP_TEST1',
155
+ correlationId: '77777777-7777-4777-8777-777777777777',
156
+ blobSequence: 1
157
+ };
158
+ // checkLogItemType is called with errorUnknown=false for addLogItem, so an
159
+ // unknown type must only warn, not throw, and the log must be stored
160
+ await mongoLogOperator.addLogItem(logItem);
161
+
162
+ const {logs} = await mongoFixtures.dump();
163
+ const own = logs.filter((doc: any) => doc.correlationId === logItem.correlationId);
164
+ assert.equal(own.length, 1);
165
+ assert.equal(own[0].logItemType, 'BOGUS_LOG');
166
+ });
167
+
168
+ test('getExpandedListOfLogs with a valid logItemTypes array still works', async () => {
169
+ const logItem = {
170
+ logItemType: 'MERGE_LOG',
171
+ cataloger: 'IMP_TEST1',
172
+ correlationId: '55555555-5555-4555-8555-555555555555',
173
+ blobSequence: 1
174
+ };
175
+ await mongoLogOperator.addLogItem(logItem);
176
+ const result = await mongoLogOperator.getExpandedListOfLogs({logItemTypes: ['MERGE_LOG'], catalogers: ['IMP_TEST1'], dateBefore: new Date(Date.now() + 60 * 60 * 1000)});
177
+ const own = result.filter(entry => entry.correlationId === logItem.correlationId);
178
+ assert.equal(own.length, 1);
179
+ assert.equal(own[0]?.logItemType, 'MERGE_LOG');
180
+ assert.equal(own[0]?.cataloger, 'IMP_TEST1');
181
+ assert.equal(own[0]?.logCount, 1);
182
+ });
@@ -0,0 +1,191 @@
1
+ import assert from 'node:assert';
2
+ import {READERS} from '@natlibfi/fixura';
3
+ import {Error as ApiError} from '@natlibfi/melinda-commons';
4
+ import generateTests from '@natlibfi/fixugen';
5
+ import mongoFixturesFactory from '@natlibfi/fixura-mongo';
6
+ import createMongoLogOperator from '../src/mongoLog.ts';
7
+
8
+ let mongoFixtures: any;
9
+
10
+ generateTests({
11
+ callback,
12
+ path: [import.meta.dirname, '..', 'test-fixtures', 'mongoLog'],
13
+ recurse: false,
14
+ useMetadataFile: true,
15
+ fixura: {
16
+ failWhenNotFound: true,
17
+ reader: READERS.JSON
18
+ },
19
+ hooks: {
20
+ before: async () => {
21
+ await initMongofixtures();
22
+ },
23
+ beforeEach: () => mongoFixtures.clear(),
24
+ afterEach: () => mongoFixtures.clear(),
25
+ after: async () => {
26
+ await mongoFixtures.close();
27
+ }
28
+ }
29
+ });
30
+
31
+ async function initMongofixtures() {
32
+ mongoFixtures = await mongoFixturesFactory({
33
+ rootPath: [import.meta.dirname, '..', 'test-fixtures', 'mongoLog'],
34
+ gridFS: {bucketName: 'blobs'},
35
+ useObjectId: true,
36
+ // fixura-mongo format is keyed by COLLECTION name, so the old
37
+ // {creationTime, modificationTime} form never applied and the fixtures
38
+ // stored creationTime as an ISO string (production addLogItem stores a
39
+ // Date). Format under the 'logs' collection so tests see the real
40
+ // production shape.
41
+ format: {
42
+ logs: {
43
+ creationTime: v => new Date(String(v)),
44
+ modificationTime: v => new Date(String(v))
45
+ }
46
+ }
47
+ });
48
+ }
49
+
50
+ async function callback(callbackParams: Record<string, any>) {
51
+ const {
52
+ getFixture,
53
+ functionName,
54
+ params,
55
+ preFillDb = false,
56
+ expectError = false,
57
+ expectedErrorStatus = 500
58
+ } = callbackParams;
59
+ const mongoUri = await mongoFixtures.getUri();
60
+ const mongoLogOperator = await createMongoLogOperator(mongoUri, '');
61
+ const expectedResult = expectError ? undefined : await getFixture('expectedResult.json');
62
+
63
+ if (expectError) {
64
+ // assert the throw (like the removeBySequences branch below)
65
+ if (functionName === 'protect') {
66
+ const [correlationId, blobSequence] = params;
67
+ return assert.rejects(
68
+ () => mongoLogOperator.protect(correlationId, blobSequence),
69
+ error => error instanceof ApiError && error.status === expectedErrorStatus
70
+ );
71
+ }
72
+ if (functionName === 'remove') {
73
+ const [correlationId, force] = params;
74
+ return assert.rejects(
75
+ () => mongoLogOperator.remove(correlationId, force),
76
+ error => error instanceof ApiError && error.status === expectedErrorStatus
77
+ );
78
+ }
79
+ if (functionName === 'removeBySequences') {
80
+ const [correlationId, sequences, force] = params;
81
+ return assert.rejects(
82
+ () => mongoLogOperator.removeBySequences(correlationId, sequences, force),
83
+ error => error instanceof ApiError && error.status === expectedErrorStatus
84
+ );
85
+ }
86
+ throw new Error(`Unknown functionName with expectError: ${functionName}`);
87
+ }
88
+
89
+ // console.log(typeof mongoUri); // eslint-disable-line
90
+
91
+ if (preFillDb) {
92
+ await mongoFixtures.populate(getFixture('dbContents.json'));
93
+ }
94
+
95
+ if (functionName === 'addLogItem') {
96
+ await mongoLogOperator.addLogItem(params);
97
+ const dump = await mongoFixtures.dump();
98
+ return assert.deepStrictEqual(dump.logs[0]['0'], expectedResult);
99
+ }
100
+
101
+ if (functionName === 'getListOfCatalogers') {
102
+ const result = await mongoLogOperator.getListOfCatalogers();
103
+ // console.log(result); // eslint-disable-line
104
+
105
+ return assert.deepEqual(result, expectedResult);
106
+ }
107
+
108
+ if (functionName === 'getExpandedListOfLogs') {
109
+ const result = await mongoLogOperator.getExpandedListOfLogs(params);
110
+ // console.log(result); // eslint-disable-line
111
+
112
+ return assert.deepEqual(normalizeDates(result), expectedResult);
113
+ }
114
+
115
+ if (functionName === 'getListOfLogs') {
116
+ const result = await mongoLogOperator.getListOfLogs(params);
117
+ // console.log(result); // eslint-disable-line
118
+ return assert.deepEqual(result, expectedResult);
119
+ }
120
+
121
+ if (functionName === 'query') {
122
+ const result = normalizeDates(await mongoLogOperator.query(params));
123
+ // console.log(result); // eslint-disable-line
124
+ return assert.deepEqual(result, expectedResult);
125
+ }
126
+
127
+ if (functionName === 'queryById') {
128
+ const [correlationId, logItemType, skip, limit] = params;
129
+ const result = normalizeDates(await mongoLogOperator.queryById(correlationId, logItemType, skip, limit));
130
+ // console.log(result); // eslint-disable-line
131
+ return assert.deepEqual(result, expectedResult);
132
+ }
133
+
134
+ if (functionName === 'getListOfCorrelationIds') {
135
+ const result = await mongoLogOperator.getListOfCorrelationIds();
136
+ // console.log(result); // eslint-disable-line
137
+ return assert.deepEqual(result, expectedResult);
138
+ }
139
+
140
+ if (functionName === 'protect') {
141
+ const [correlationId, blobSequence] = params;
142
+ const result = await mongoLogOperator.protect(correlationId, blobSequence);
143
+ assert.deepEqual(result, expectedResult);
144
+ const remaining = (await dumpRemaining()).map(doc => {
145
+ // protect() sets modificationTime to the current time, so it can't be
146
+ // compared against a static fixture
147
+ const fixed = {...doc};
148
+ delete fixed.modificationTime;
149
+ return fixed;
150
+ });
151
+ return assert.deepEqual(remaining, getFixture('expectedRemaining.json'));
152
+ }
153
+
154
+ if (functionName === 'remove') {
155
+ const [correlationId, force] = params;
156
+ const result = await mongoLogOperator.remove(correlationId, force);
157
+ assert.deepEqual(result, expectedResult);
158
+ return assert.deepEqual(await dumpRemaining(), getFixture('expectedRemaining.json'));
159
+ }
160
+
161
+ if (functionName === 'removeBySequences') {
162
+ const [correlationId, sequences, force] = params;
163
+ const result = await mongoLogOperator.removeBySequences(correlationId, sequences, force);
164
+ assert.deepEqual(result, expectedResult);
165
+ return assert.deepEqual(await dumpRemaining(), getFixture('expectedRemaining.json'));
166
+ }
167
+
168
+ throw new Error(`Unknown functionName: ${functionName}`);
169
+ }
170
+
171
+ // Dump the surviving logs, normalized for comparison against a fixture
172
+ async function dumpRemaining() {
173
+ return normalizeDates((await mongoFixtures.dump()).logs);
174
+ }
175
+
176
+ // Convert BSON Dates in the result to ISO strings and drop _id, so the result
177
+ // can be compared with the plain strings in expectedResult.json /
178
+ // expectedRemaining.json (fixura-mongo dump also strips _id)
179
+ function normalizeDates(docs: any[]): any[] {
180
+ return docs.map(doc => {
181
+ const fixed = {...doc};
182
+ delete fixed._id;
183
+ if (fixed.creationTime instanceof Date) {
184
+ fixed.creationTime = fixed.creationTime.toISOString();
185
+ }
186
+ if (fixed.modificationTime instanceof Date) {
187
+ fixed.modificationTime = fixed.modificationTime.toISOString();
188
+ }
189
+ return fixed;
190
+ });
191
+ }
@@ -1,23 +1,39 @@
1
-
2
1
  import assert from 'node:assert';
3
2
  import createDebugLogger from 'debug';
4
- import createMongoOperator from '../src/mongo.js';
3
+ import type {Readable} from 'node:stream';
4
+ import createMongoOperator from '../src/mongo.ts';
5
5
 
6
6
 
7
7
  const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons/mongo:test');
8
8
 
9
- export async function getMongoOperator(mongoFixtures) {
9
+ // the fixura-mongo fixtures object is intentionally untyped in tests
10
+ // (fixture-driven scaffolding, see the eslint house rules for test/)
11
+ export async function getMongoOperator(mongoFixtures: any) {
10
12
  const mongoUri = await mongoFixtures.getUri();
11
13
  const mongoOperator = await createMongoOperator(mongoUri, 'foobar', '');
12
14
  return mongoOperator;
13
15
  }
14
16
 
15
- export async function compareToFirstDbEntry({mongoFixtures, expectedResult, expectModificationTime = false, formatDates = true, expectedFileCount = undefined}) {
17
+ interface DbEntryCompareParams {
18
+ mongoFixtures: any;
19
+ expectedResult: unknown;
20
+ expectModificationTime?: boolean;
21
+ formatDates?: boolean;
22
+ expectedFileCount?: number;
23
+ }
24
+
25
+ export async function compareToFirstDbEntry(params: DbEntryCompareParams) {
26
+ const {mongoFixtures, expectedResult, expectModificationTime = false, formatDates = true, expectedFileCount = undefined} = params;
16
27
  const result = await compareToDbEntry({mongoFixtures, expectedResult, resultIndex: 0, expectModificationTime, formatDates, expectedFileCount});
17
28
  return result;
18
29
  }
19
30
 
20
- export async function compareToDbEntry({mongoFixtures, expectedResult, resultIndex = 0, expectModificationTime = false, formatDates = true, expectedFileCount = undefined}) {
31
+ interface DbEntryParams extends DbEntryCompareParams {
32
+ resultIndex?: number;
33
+ }
34
+
35
+ export async function compareToDbEntry(params: DbEntryParams) {
36
+ const {mongoFixtures, expectedResult, resultIndex = 0, expectModificationTime = false, formatDates = true, expectedFileCount = undefined} = params;
21
37
  const dump = await mongoFixtures.dump();
22
38
  debug(`--- We have ${dump.foobar.length} documents in db`);
23
39
  debug(dump.foobar);
@@ -39,7 +55,13 @@ export async function compareToDbEntry({mongoFixtures, expectedResult, resultInd
39
55
  return;
40
56
  }
41
57
 
42
- function checkFileCount({dump, expectedFileCount}) {
58
+ interface CheckFileCountParams {
59
+ dump: any;
60
+ expectedFileCount: number | undefined;
61
+ }
62
+
63
+ function checkFileCount(params: CheckFileCountParams) {
64
+ const {dump, expectedFileCount} = params;
43
65
  if (expectedFileCount !== undefined) {
44
66
  const fileCount = dump['foobar.files']?.length;
45
67
  debug(`--- We have ${fileCount} files in db`);
@@ -50,7 +72,13 @@ function checkFileCount({dump, expectedFileCount}) {
50
72
 
51
73
  }
52
74
 
53
- function checkModificationTime({result, expectModificationTime}) {
75
+ interface CheckModificationTimeParams {
76
+ result: any;
77
+ expectModificationTime: boolean;
78
+ }
79
+
80
+ function checkModificationTime(params: CheckModificationTimeParams) {
81
+ const {result, expectModificationTime} = params;
54
82
  if (expectModificationTime) {
55
83
  debug('Check if modificationTime was edited');
56
84
  const isNotEmpty = result.modificationTime !== '';
@@ -62,7 +90,7 @@ function checkModificationTime({result, expectModificationTime}) {
62
90
  }
63
91
 
64
92
 
65
- export function formatQueueItem(queueItem) {
93
+ export function formatQueueItem(queueItem: any): any {
66
94
  const filteredQueueItem = {
67
95
  ...queueItem,
68
96
  creationTime: '',
@@ -72,12 +100,19 @@ export function formatQueueItem(queueItem) {
72
100
  return filteredQueueItem;
73
101
  }
74
102
 
75
- export function handleError({error, expectedToThrow, expectedErrorMessage, expectedErrorStatus}) {
103
+ interface HandleErrorParams {
104
+ error: any;
105
+ expectedToThrow: boolean;
106
+ expectedErrorMessage: string;
107
+ expectedErrorStatus: string;
108
+ }
109
+
110
+ export function handleError(params: HandleErrorParams) {
111
+ const {error, expectedToThrow, expectedErrorMessage, expectedErrorStatus} = params;
76
112
  debug(error);
77
113
  if (expectedToThrow) {
78
114
  debug('OK. Expected to throw');
79
115
  debug(JSON.stringify(error));
80
- // eslint-disable-next-line max-lines
81
116
  if (expectedErrorMessage !== '' || expectedErrorStatus !== '') {
82
117
  const errorMessage = error.message || error.payload.message || error.payload || '';
83
118
  debug(errorMessage);
@@ -92,12 +127,11 @@ export function handleError({error, expectedToThrow, expectedErrorMessage, expec
92
127
  throw error;
93
128
  }
94
129
 
95
- export function streamToString(stream) {
96
- const chunks = [];
130
+ export function streamToString(stream: Readable): Promise<string> {
131
+ const chunks: Buffer[] = [];
97
132
  return new Promise((resolve, reject) => {
98
- // eslint-disable-next-line functional/immutable-data
99
- stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
100
- stream.on('error', (err) => reject(err));
133
+ stream.on('data', (chunk: Buffer) => chunks.push(Buffer.from(chunk)));
134
+ stream.on('error', (err: unknown) => reject(err));
101
135
  stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
102
136
  });
103
137
  }