@natlibfi/melinda-rest-api-commons 6.1.0-alpha.0 → 6.2.0-alpha.1
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 +211 -14
- package/dist/amqp.d.ts +41 -0
- package/dist/amqp.d.ts.map +1 -0
- package/dist/amqp.js +251 -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 +17 -11
- package/{tests/amqp-error-branches.test.js → test/amqp-error-branches.test.ts} +135 -61
- package/{tests/amqp.healthtest.js → test/amqp.healthtest.ts} +19 -11
- 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} +166 -65
- 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
|
@@ -3,8 +3,11 @@ import createDebugLogger from 'debug';
|
|
|
3
3
|
import {promisify} from 'util';
|
|
4
4
|
import {READERS} from '@natlibfi/fixura';
|
|
5
5
|
import generateTests from '@natlibfi/fixugen';
|
|
6
|
+
import type {CallbackArgs} from '@natlibfi/fixugen';
|
|
6
7
|
import {Error as ApiError} from '@natlibfi/melinda-commons';
|
|
7
|
-
import {
|
|
8
|
+
import type {GetMessage, Message} from 'amqplib';
|
|
9
|
+
import {amqpFactory} from '../src/index.ts';
|
|
10
|
+
import type {AmqpOperator, QueueItemMessagePayload, QueueItemRecordPayload, SendToQueueParams} from '../src/amqp.ts';
|
|
8
11
|
|
|
9
12
|
const setTimeoutPromise = promisify(setTimeout);
|
|
10
13
|
const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons:amqp:test');
|
|
@@ -18,8 +21,7 @@ const testData = {
|
|
|
18
21
|
|
|
19
22
|
debug(`Testing amqp against a local AMQP instance - we'll need some kind of mockup for this`);
|
|
20
23
|
const amqpUrl = 'amqp://127.0.0.1:5672/';
|
|
21
|
-
|
|
22
|
-
let amqpOperator;
|
|
24
|
+
let amqpOperator: AmqpOperator;
|
|
23
25
|
|
|
24
26
|
generateTests({
|
|
25
27
|
callback,
|
|
@@ -48,8 +50,15 @@ generateTests({
|
|
|
48
50
|
}
|
|
49
51
|
});
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
/**
|
|
54
|
+
* One fixture case. See the fixture metadata files in test-fixtures/amqp
|
|
55
|
+
* for the possible keys (getFixture, expectToFail, expectedErrorStatus,
|
|
56
|
+
* ackMessages, nackMessages, checkNextMessage, checkQueueStyle, queue,
|
|
57
|
+
* sentToQueue, expectedMessageCount, removeQueue, expectedErrorMessage,
|
|
58
|
+
* expectApiError, expectFalseCheckResult).
|
|
59
|
+
*/
|
|
60
|
+
async function callback(callbackParams: CallbackArgs) {
|
|
61
|
+
const {
|
|
53
62
|
getFixture,
|
|
54
63
|
expectToFail = false,
|
|
55
64
|
expectedErrorStatus = '',
|
|
@@ -57,14 +66,16 @@ async function callback({
|
|
|
57
66
|
nackMessages = false,
|
|
58
67
|
checkNextMessage = false,
|
|
59
68
|
checkQueueStyle = false,
|
|
60
|
-
queue = testData.queue,
|
|
69
|
+
queue: queueFromFixture = testData.queue,
|
|
61
70
|
sentToQueue,
|
|
62
71
|
expectedMessageCount,
|
|
63
72
|
removeQueue = false,
|
|
64
73
|
expectedErrorMessage = undefined,
|
|
65
74
|
expectApiError = false,
|
|
66
75
|
expectFalseCheckResult = false
|
|
67
|
-
}
|
|
76
|
+
} = callbackParams;
|
|
77
|
+
// the fixture contract passes the queue name as a string
|
|
78
|
+
const queue = queueFromFixture as string;
|
|
68
79
|
try {
|
|
69
80
|
await sendMessagesToQueue();
|
|
70
81
|
|
|
@@ -79,7 +90,7 @@ async function callback({
|
|
|
79
90
|
assert.equal(messageCount, expectedMessageCount);
|
|
80
91
|
|
|
81
92
|
if (checkNextMessage) {
|
|
82
|
-
const {headers, records} = await queueCheckNextMessage();
|
|
93
|
+
const {headers, records} = (await queueCheckNextMessage()) as QueueItemRecordPayload;
|
|
83
94
|
const nextMessage = {headers, records};
|
|
84
95
|
const expectedNextMessage = getFixture('expectedMessage.json');
|
|
85
96
|
assert.deepStrictEqual(
|
|
@@ -97,15 +108,19 @@ async function callback({
|
|
|
97
108
|
testErrors(error);
|
|
98
109
|
}
|
|
99
110
|
|
|
100
|
-
|
|
111
|
+
/**
|
|
112
|
+
* @param error
|
|
113
|
+
*/
|
|
114
|
+
function testErrors(error: unknown) {
|
|
101
115
|
const isApiError = error instanceof ApiError;
|
|
102
116
|
if (expectApiError) {
|
|
103
117
|
assert.equal(isApiError, true);
|
|
104
118
|
debug(`We expected and got an ApiError`);
|
|
105
|
-
|
|
119
|
+
const apiError = error as ApiError;
|
|
120
|
+
assert.equal(apiError.status, expectedErrorStatus);
|
|
106
121
|
|
|
107
122
|
if (expectedErrorMessage) {
|
|
108
|
-
assert.equal(
|
|
123
|
+
assert.equal(apiError.payload, expectedErrorMessage);
|
|
109
124
|
return;
|
|
110
125
|
}
|
|
111
126
|
|
|
@@ -113,26 +128,26 @@ async function callback({
|
|
|
113
128
|
}
|
|
114
129
|
assert.equal(isApiError, false);
|
|
115
130
|
debug(`We expected and got an non-ApiError`);
|
|
116
|
-
|
|
131
|
+
const maybeError = error as Error;
|
|
132
|
+
debug(`Error is a ${maybeError.constructor.name}`);
|
|
117
133
|
}
|
|
118
134
|
|
|
119
135
|
function queueRemoval() {
|
|
120
136
|
if (removeQueue) {
|
|
121
|
-
return amqpOperator.removeQueue(removeQueue);
|
|
137
|
+
return amqpOperator.removeQueue(removeQueue as string);
|
|
122
138
|
}
|
|
123
139
|
|
|
124
140
|
return;
|
|
125
141
|
}
|
|
126
142
|
|
|
127
|
-
function queueCheckNextMessage() {
|
|
143
|
+
function queueCheckNextMessage(): Promise<QueueItemRecordPayload> | false {
|
|
128
144
|
if (checkNextMessage) {
|
|
129
|
-
return amqpOperator.consumeOne(testData.queue, true)
|
|
145
|
+
return amqpOperator.consumeOne(testData.queue, true) as Promise<QueueItemRecordPayload>;
|
|
130
146
|
}
|
|
131
147
|
|
|
132
148
|
return false;
|
|
133
149
|
}
|
|
134
150
|
|
|
135
|
-
// eslint-disable-next-line max-statements
|
|
136
151
|
async function checkQueue() {
|
|
137
152
|
debug(`checkQueueStyle: ${checkQueueStyle}`);
|
|
138
153
|
|
|
@@ -144,18 +159,19 @@ async function callback({
|
|
|
144
159
|
return;
|
|
145
160
|
}
|
|
146
161
|
|
|
147
|
-
|
|
148
|
-
assert.equal(Object.hasOwn(
|
|
149
|
-
assert.equal(Object.hasOwn(
|
|
150
|
-
assert.equal(
|
|
151
|
-
assert.equal(
|
|
162
|
+
const recordResult = result as QueueItemRecordPayload;
|
|
163
|
+
assert.equal(Object.hasOwn(recordResult, 'headers'), true);
|
|
164
|
+
assert.equal(Object.hasOwn(recordResult, 'records'), true);
|
|
165
|
+
assert.equal(Object.hasOwn(recordResult, 'messages'), true);
|
|
166
|
+
assert.equal(recordResult.records.length, 1);
|
|
167
|
+
assert.equal(recordResult.messages.length, 1);
|
|
152
168
|
|
|
153
169
|
return;
|
|
154
170
|
}
|
|
155
171
|
|
|
156
172
|
if (checkQueueStyle === 'oneNotRecord') {
|
|
157
173
|
const result = await amqpOperator.checkQueue({queue, style: 'one', toRecord: false, purge: false});
|
|
158
|
-
const {fields} = result;
|
|
174
|
+
const {fields} = result as GetMessage;
|
|
159
175
|
|
|
160
176
|
if (expectFalseCheckResult) {
|
|
161
177
|
assert.strictEqual(result, false);
|
|
@@ -178,14 +194,15 @@ async function callback({
|
|
|
178
194
|
return;
|
|
179
195
|
}
|
|
180
196
|
|
|
181
|
-
|
|
182
|
-
assert.equal(Object.hasOwn(
|
|
183
|
-
assert.equal(Object.hasOwn(
|
|
184
|
-
assert.equal(
|
|
185
|
-
assert.equal(
|
|
197
|
+
const recordResult = result as QueueItemRecordPayload;
|
|
198
|
+
assert.equal(Object.hasOwn(recordResult, 'headers'), true);
|
|
199
|
+
assert.equal(Object.hasOwn(recordResult, 'records'), true);
|
|
200
|
+
assert.equal(Object.hasOwn(recordResult, 'messages'), true);
|
|
201
|
+
assert.equal(recordResult.records.length, 3);
|
|
202
|
+
assert.equal(recordResult.messages.length, 3);
|
|
186
203
|
const expectedResult = getFixture('expectedResult.json');
|
|
187
204
|
assert.deepStrictEqual(
|
|
188
|
-
JSON.parse(JSON.stringify(
|
|
205
|
+
JSON.parse(JSON.stringify(recordResult.records)),
|
|
189
206
|
expectedResult,
|
|
190
207
|
);
|
|
191
208
|
|
|
@@ -200,11 +217,13 @@ async function callback({
|
|
|
200
217
|
return;
|
|
201
218
|
}
|
|
202
219
|
|
|
203
|
-
|
|
204
|
-
assert.equal(Object.hasOwn(
|
|
205
|
-
assert.equal(
|
|
220
|
+
const messageResult = result as QueueItemMessagePayload;
|
|
221
|
+
assert.equal(Object.hasOwn(messageResult, 'headers'), true);
|
|
222
|
+
assert.equal(Object.hasOwn(messageResult, 'messages'), true);
|
|
223
|
+
assert.equal(messageResult.messages.length, 3);
|
|
206
224
|
|
|
207
|
-
const [
|
|
225
|
+
const [firstMessage] = messageResult.messages as [Message, ...Message[]];
|
|
226
|
+
const {fields} = firstMessage;
|
|
208
227
|
|
|
209
228
|
assert.equal(typeof fields.deliveryTag, 'number');
|
|
210
229
|
assert.equal(typeof fields.messageCount, 'number');
|
|
@@ -228,14 +247,14 @@ async function callback({
|
|
|
228
247
|
async function ackOrNackMessages() {
|
|
229
248
|
if (ackMessages) {
|
|
230
249
|
const message = await amqpOperator.consumeOne(testData.queue, false);
|
|
231
|
-
await amqpOperator.ackMessages([message]);
|
|
250
|
+
await amqpOperator.ackMessages([message as GetMessage]);
|
|
232
251
|
|
|
233
252
|
return setTimeoutPromise(10);
|
|
234
253
|
}
|
|
235
254
|
|
|
236
255
|
if (nackMessages) {
|
|
237
256
|
const message = await amqpOperator.consumeOne(testData.queue, false);
|
|
238
|
-
await amqpOperator.nackMessages([message]);
|
|
257
|
+
await amqpOperator.nackMessages([message as GetMessage]);
|
|
239
258
|
|
|
240
259
|
return setTimeoutPromise(10);
|
|
241
260
|
}
|
|
@@ -245,7 +264,7 @@ async function callback({
|
|
|
245
264
|
|
|
246
265
|
async function sendMessagesToQueue() {
|
|
247
266
|
if (sentToQueue) {
|
|
248
|
-
const messages = getFixture('input.json');
|
|
267
|
+
const messages = getFixture('input.json') as SendToQueueParams[];
|
|
249
268
|
// {queue, correlationId, headers, data}
|
|
250
269
|
|
|
251
270
|
const promises = messages.map(message => amqpOperator.sendToQueue(message));
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
import assert from 'node:assert';
|
|
4
2
|
import {describe, it} from 'node:test';
|
|
5
3
|
import fixtureFactory from '@natlibfi/fixura';
|
|
6
4
|
import {MarcRecord} from '@natlibfi/marc-record';
|
|
5
|
+
import type {MarcRecordObject} from '@natlibfi/marc-record';
|
|
7
6
|
import {Error as ConversionError} from '@natlibfi/melinda-commons';
|
|
8
|
-
import createConversionService from '../../src/helpers/conversion.
|
|
9
|
-
import {CONVERSION_FORMATS} from '../../src/constants.
|
|
7
|
+
import createConversionService from '../../src/helpers/conversion.ts';
|
|
8
|
+
import {CONVERSION_FORMATS} from '../../src/constants.ts';
|
|
10
9
|
|
|
11
10
|
describe('services/conversion', () => {
|
|
12
11
|
const {getFixture} = fixtureFactory({
|
|
@@ -20,11 +19,11 @@ describe('services/conversion', () => {
|
|
|
20
19
|
});
|
|
21
20
|
const conversionService = createConversionService();
|
|
22
21
|
|
|
23
|
-
const marcRecord = new MarcRecord(JSON.parse(getFixture({components: ['json1']})), {subfieldValues: false});
|
|
24
|
-
const marcXml = getFixture({components: ['marcxml1']});
|
|
25
|
-
const iso2709 = getFixture({components: ['iso2709_1']});
|
|
26
|
-
const json = getFixture({components: ['json1']});
|
|
27
|
-
const alephSeq = getFixture({components: ['aleph_sequential']});
|
|
22
|
+
const marcRecord = new MarcRecord(JSON.parse(getFixture({components: ['json1']}) as string) as MarcRecordObject, {subfieldValues: false});
|
|
23
|
+
const marcXml = getFixture({components: ['marcxml1']}) as string;
|
|
24
|
+
const iso2709 = getFixture({components: ['iso2709_1']}) as string;
|
|
25
|
+
const json = getFixture({components: ['json1']}) as string;
|
|
26
|
+
const alephSeq = getFixture({components: ['aleph_sequential']}) as string;
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
describe('factory', () => {
|
|
@@ -38,11 +37,16 @@ describe('services/conversion', () => {
|
|
|
38
37
|
|
|
39
38
|
describe('#serialize', () => {
|
|
40
39
|
it('Should throw because of unsupported format', () => {
|
|
40
|
+
let threw = false;
|
|
41
41
|
try {
|
|
42
|
-
|
|
42
|
+
// the undefined inputs are the point of this test: serialize must
|
|
43
|
+
// throw a ConversionError for an unsupported format, not a TypeError
|
|
44
|
+
conversionService.serialize(undefined as never, undefined as never);
|
|
43
45
|
} catch (error) {
|
|
46
|
+
threw = true;
|
|
44
47
|
assert(error instanceof ConversionError);
|
|
45
48
|
}
|
|
49
|
+
assert.equal(threw, true);
|
|
46
50
|
});
|
|
47
51
|
|
|
48
52
|
it('Should serialize to MARCXML', () => {
|
|
@@ -68,15 +72,15 @@ describe('services/conversion', () => {
|
|
|
68
72
|
it('Should rewrap a plain (non-ConversionError) serializer error into a ConversionError with 400', () => {
|
|
69
73
|
// a plain {} makes MARCXML.to throw a TypeError, which serialize must
|
|
70
74
|
// rewrap into a ConversionError 400 (not propagate the raw TypeError)
|
|
71
|
-
// eslint-disable-next-line functional/no-let
|
|
72
75
|
let threw = false;
|
|
73
76
|
try {
|
|
74
|
-
conversionService.serialize({}, CONVERSION_FORMATS.MARCXML);
|
|
77
|
+
conversionService.serialize({} as never, CONVERSION_FORMATS.MARCXML);
|
|
75
78
|
} catch (error) {
|
|
76
79
|
threw = true;
|
|
77
80
|
assert(error instanceof ConversionError);
|
|
78
81
|
assert.equal(error.status, 400);
|
|
79
|
-
|
|
82
|
+
// the payload is a string here: 'Error while serializing record. ...'
|
|
83
|
+
assert.ok((error.payload as string).includes('Error while serializing record.'));
|
|
80
84
|
}
|
|
81
85
|
assert.equal(threw, true);
|
|
82
86
|
});
|
|
@@ -85,11 +89,16 @@ describe('services/conversion', () => {
|
|
|
85
89
|
|
|
86
90
|
describe('#unserialize', () => {
|
|
87
91
|
it('Should throw because of unsupported format', () => {
|
|
92
|
+
let threw = false;
|
|
88
93
|
try {
|
|
89
|
-
|
|
94
|
+
// the undefined inputs are the point of this test: unserialize must
|
|
95
|
+
// throw a ConversionError for an unsupported format, not a TypeError
|
|
96
|
+
conversionService.unserialize(undefined as never, undefined as never);
|
|
90
97
|
} catch (error) {
|
|
98
|
+
threw = true;
|
|
91
99
|
assert(error instanceof ConversionError);
|
|
92
100
|
}
|
|
101
|
+
assert.equal(threw, true);
|
|
93
102
|
});
|
|
94
103
|
|
|
95
104
|
it('Should unserialize from MARCXML', async () => {
|
|
@@ -114,11 +123,14 @@ describe('services/conversion', () => {
|
|
|
114
123
|
|
|
115
124
|
|
|
116
125
|
it('Should throw because the record could not be unserialized', () => {
|
|
126
|
+
let threw = false;
|
|
117
127
|
try {
|
|
118
128
|
conversionService.unserialize('', CONVERSION_FORMATS.JSON);
|
|
119
129
|
} catch (error) {
|
|
130
|
+
threw = true;
|
|
120
131
|
assert(error instanceof ConversionError);
|
|
121
132
|
}
|
|
133
|
+
assert.equal(threw, true);
|
|
122
134
|
});
|
|
123
135
|
});
|
|
124
136
|
});
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import assert from 'node:assert';
|
|
4
4
|
import {test} from 'node:test';
|
|
5
5
|
import {MarcRecord} from '@natlibfi/marc-record';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import type {MarcField} from '@natlibfi/marc-record';
|
|
7
|
+
import {fixRecord} from '../../src/helpers/fix.ts';
|
|
8
|
+
import {BIB_STRIP_F884S_SETTINGS, BIB_F035_TO_SID} from '../../src/helpers/fix-constants.ts';
|
|
8
9
|
|
|
9
10
|
// a Melinda f884 (tag 884, $5 MELINDA, $a + $g present) that
|
|
10
11
|
// has NO $k subfield. findSource/findHash used to call `sfK.replace(...)` on
|
|
@@ -52,7 +53,8 @@ test('fixRecord handles Melinda f884 without $k subfield without crashing', () =
|
|
|
52
53
|
const result = fixRecord(record, BIB_STRIP_F884S_SETTINGS);
|
|
53
54
|
|
|
54
55
|
// Both Melinda f884s survive (they are not identical, so uniq keeps both)
|
|
55
|
-
|
|
56
|
+
// these are data fields: mirrors the JSDoc baseline MarcField[] cast
|
|
57
|
+
const f884s = (result.fields as MarcField[]).filter((f) => f.tag === '884');
|
|
56
58
|
assert.equal(f884s.length, 2);
|
|
57
59
|
|
|
58
60
|
// The field WITHOUT $k still has its $a, $g and $5 MELINDA
|
|
@@ -62,8 +64,8 @@ test('fixRecord handles Melinda f884 without $k subfield without crashing', () =
|
|
|
62
64
|
noK.subfields.map((s) => s.code).sort(),
|
|
63
65
|
['5', 'a', 'g']
|
|
64
66
|
);
|
|
65
|
-
const gNoK = noK.subfields.find((s) => s.code === 'g')
|
|
66
|
-
const aNoK = noK.subfields.find((s) => s.code === 'a')
|
|
67
|
+
const gNoK = noK.subfields.find((s) => s.code === 'g')?.value;
|
|
68
|
+
const aNoK = noK.subfields.find((s) => s.code === 'a')?.value;
|
|
67
69
|
assert.equal(aNoK, 'ONIX3 to MARC transformation');
|
|
68
70
|
assert.equal(gNoK, '20220101');
|
|
69
71
|
|
|
@@ -74,8 +76,8 @@ test('fixRecord handles Melinda f884 without $k subfield without crashing', () =
|
|
|
74
76
|
withK.subfields.map((s) => s.code).sort(),
|
|
75
77
|
['5', 'a', 'g', 'k']
|
|
76
78
|
);
|
|
77
|
-
assert.equal(withK.subfields.find((s) => s.code === 'g')
|
|
78
|
-
assert.equal(withK.subfields.find((s) => s.code === 'k')
|
|
79
|
+
assert.equal(withK.subfields.find((s) => s.code === 'g')?.value, '20000718');
|
|
80
|
+
assert.equal(withK.subfields.find((s) => s.code === 'k')?.value,
|
|
79
81
|
'SRC_4:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
|
80
82
|
});
|
|
81
83
|
|
|
@@ -146,11 +148,12 @@ test('fixRecord ignores an existing SID field whose $b is not in fSIDFilters and
|
|
|
146
148
|
}, {subfieldValues: false});
|
|
147
149
|
|
|
148
150
|
const result = fixRecord(record, {generateMissingSIDs: BIB_F035_TO_SID});
|
|
149
|
-
|
|
151
|
+
// these are data fields: mirrors the JSDoc baseline MarcField[] cast
|
|
152
|
+
const sids = (result.fields as MarcField[]).filter((f) => f.tag === 'SID');
|
|
150
153
|
assert.equal(sids.length, 2);
|
|
151
154
|
const generated = sids.find((f) => f.subfields.some((s) => s.code === 'b' && s.value === 'FI-BTJ'));
|
|
152
155
|
assert.ok(generated, 'a new SID with $b FI-BTJ should have been generated');
|
|
153
|
-
assert.equal(generated.subfields.find((s) => s.code === 'c')
|
|
156
|
+
assert.equal(generated.subfields.find((s) => s.code === 'c')?.value, '12345');
|
|
154
157
|
});
|
|
155
158
|
|
|
156
159
|
test('fixRecord ignores an existing SID field with a matching $b but missing $c and generates the SID from the f035', () => {
|
|
@@ -173,12 +176,13 @@ test('fixRecord ignores an existing SID field with a matching $b but missing $c
|
|
|
173
176
|
}, {subfieldValues: false});
|
|
174
177
|
|
|
175
178
|
const result = fixRecord(record, {generateMissingSIDs: BIB_F035_TO_SID});
|
|
176
|
-
|
|
179
|
+
// these are data fields: mirrors the JSDoc baseline MarcField[] cast
|
|
180
|
+
const sids = (result.fields as MarcField[]).filter((f) => f.tag === 'SID');
|
|
177
181
|
assert.equal(sids.length, 2);
|
|
178
182
|
const generated = sids.find((f) => f.subfields.some((s) => s.code === 'c'));
|
|
179
183
|
assert.ok(generated, 'a generated SID with $c should exist');
|
|
180
|
-
assert.equal(generated.subfields.find((s) => s.code === 'b')
|
|
181
|
-
assert.equal(generated.subfields.find((s) => s.code === 'c')
|
|
184
|
+
assert.equal(generated.subfields.find((s) => s.code === 'b')?.value, 'FI-BTJ');
|
|
185
|
+
assert.equal(generated.subfields.find((s) => s.code === 'c')?.value, '12345');
|
|
182
186
|
});
|
|
183
187
|
|
|
184
188
|
test('fixRecord adds no SID when the f035 $a matches no f035Filter', () => {
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import createDebugLogger from 'debug';
|
|
3
3
|
import {MarcRecord} from '@natlibfi/marc-record';
|
|
4
|
+
import type {MarcRecordObject} from '@natlibfi/marc-record';
|
|
4
5
|
import {READERS} from '@natlibfi/fixura';
|
|
5
|
-
import generateTests from '@natlibfi/fixugen';
|
|
6
|
-
import {fixRecord} from '../../src/helpers/fix.
|
|
7
|
-
import * as fixSettings from '../../src/helpers/fix-constants.
|
|
6
|
+
import generateTests, {type CallbackArgs} from '@natlibfi/fixugen';
|
|
7
|
+
import {fixRecord} from '../../src/helpers/fix.ts';
|
|
8
|
+
import * as fixSettings from '../../src/helpers/fix-constants.ts';
|
|
9
|
+
import type {FixSettings} from '../../src/helpers/fix-constants.ts';
|
|
8
10
|
// import inspect from 'util';
|
|
9
11
|
|
|
10
12
|
const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons:fix:test');
|
|
11
13
|
const debugData = debug.extend('data');
|
|
12
14
|
|
|
15
|
+
// the settings names usable via metadata.json
|
|
16
|
+
type SettingsKey = 'BIB_FORMAT_SETTINGS' | 'BIB_PREVALIDATION_FIX_SETTINGS' | 'BIB_POSTMERGE_FIX_SETTINGS' | 'BIB_PREIMPORT_FIX_SETTINGS' | 'AUTNAME_PREIMPORT_FIX_SETTINGS' | 'BIB_HANDLE_TEMP_URNS_SETTINGS' | 'BIB_STRIP_F884S_SETTINGS' | 'BIB_STRIP_F984S_SETTINGS' | 'BIB_STRIP_MELINDA_TEMP_SUBFIELDS_SETTINGS';
|
|
17
|
+
|
|
13
18
|
generateTests({
|
|
14
19
|
callback,
|
|
15
20
|
path: [import.meta.dirname, '..', '..', 'test-fixtures', 'fix'],
|
|
@@ -21,15 +26,16 @@ generateTests({
|
|
|
21
26
|
}
|
|
22
27
|
});
|
|
23
28
|
|
|
24
|
-
function callback(
|
|
29
|
+
function callback(callbackParams: CallbackArgs) {
|
|
30
|
+
const {getFixture, settings = undefined} = callbackParams;
|
|
25
31
|
if (
|
|
26
32
|
settings !== undefined
|
|
27
33
|
&& typeof settings !== 'object'
|
|
28
|
-
&& fixSettings[settings] === undefined
|
|
34
|
+
&& (fixSettings[settings as SettingsKey]) === undefined
|
|
29
35
|
) {
|
|
30
36
|
throw new Error(`There are no settings ${settings} defined!`);
|
|
31
37
|
}
|
|
32
|
-
let runSettings = fixSettings[settings] || settings;
|
|
38
|
+
let runSettings: FixSettings | undefined = (fixSettings[settings as SettingsKey]) || (settings as FixSettings);
|
|
33
39
|
// metadata.json is plain JSON, so f035Filters may contain string
|
|
34
40
|
// patterns which fix.js cannot use as-is; convert them to RegExp
|
|
35
41
|
if (runSettings && runSettings.generateMissingSIDs) {
|
|
@@ -38,14 +44,14 @@ function callback({getFixture, settings = undefined}) {
|
|
|
38
44
|
generateMissingSIDs: {
|
|
39
45
|
...runSettings.generateMissingSIDs,
|
|
40
46
|
f035Filters: (runSettings.generateMissingSIDs.f035Filters || []).map(
|
|
41
|
-
filter => (typeof filter === 'string' ? new RegExp(filter) : filter)
|
|
47
|
+
(filter): RegExp => (typeof filter === 'string' ? new RegExp(filter) : filter)
|
|
42
48
|
),
|
|
43
49
|
fSIDFilters: runSettings.generateMissingSIDs.fSIDFilters
|
|
44
50
|
}
|
|
45
51
|
};
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
const record = new MarcRecord(getFixture('record.json'), {subfieldValues: false});
|
|
54
|
+
const record = new MarcRecord(getFixture('record.json') as MarcRecordObject, {subfieldValues: false});
|
|
49
55
|
const expectedRecord = getFixture('expectedRecord.json');
|
|
50
56
|
|
|
51
57
|
debug(`Running fixer with settings ${settings}.`);
|
|
@@ -2,7 +2,9 @@ import assert from 'node:assert';
|
|
|
2
2
|
import {describe, it} from 'node:test';
|
|
3
3
|
import fixtureFactory, {READERS} from '@natlibfi/fixura';
|
|
4
4
|
import {MarcRecord} from '@natlibfi/marc-record';
|
|
5
|
-
import
|
|
5
|
+
import type {MarcRecordObject} from '@natlibfi/marc-record';
|
|
6
|
+
|
|
7
|
+
import createValidator from '../../src/helpers/validation.ts';
|
|
6
8
|
|
|
7
9
|
describe('services/validate', () => {
|
|
8
10
|
const FIXTURES_PATH = [
|
|
@@ -22,14 +24,14 @@ describe('services/validate', () => {
|
|
|
22
24
|
'in',
|
|
23
25
|
'f003-fi-melinda.json'
|
|
24
26
|
]
|
|
25
|
-
}));
|
|
27
|
+
}) as MarcRecordObject);
|
|
26
28
|
const result = await validator(record.toObject());
|
|
27
29
|
const {record: expectedRecord, ...rest} = getFixture({
|
|
28
30
|
components: [
|
|
29
31
|
'out',
|
|
30
32
|
'f003-fi-melinda.json'
|
|
31
33
|
]
|
|
32
|
-
})
|
|
34
|
+
}) as Record<string, any>;
|
|
33
35
|
const {_validationOptions, ...expectedRecordData} = expectedRecord;
|
|
34
36
|
const {record: actualRecord, ...actualRest} = result;
|
|
35
37
|
assert.deepStrictEqual(actualRest, rest);
|
|
@@ -46,14 +48,14 @@ describe('services/validate', () => {
|
|
|
46
48
|
'in',
|
|
47
49
|
'f003-not-fi-melinda.json'
|
|
48
50
|
]
|
|
49
|
-
}));
|
|
51
|
+
}) as MarcRecordObject);
|
|
50
52
|
const result = await validator(record.toObject());
|
|
51
53
|
const {record: expectedRecord, ...rest} = getFixture({
|
|
52
54
|
components: [
|
|
53
55
|
'out',
|
|
54
56
|
'f003-not-fi-melinda.json'
|
|
55
57
|
]
|
|
56
|
-
})
|
|
58
|
+
}) as Record<string, any>;
|
|
57
59
|
const {_validationOptions, ...expectedRecordData} = expectedRecord;
|
|
58
60
|
const {record: actualRecord, ...actualRest} = result;
|
|
59
61
|
assert.deepStrictEqual(actualRest, rest);
|
|
@@ -62,4 +64,3 @@ describe('services/validate', () => {
|
|
|
62
64
|
});
|
|
63
65
|
});
|
|
64
66
|
});
|
|
65
|
-
|
|
@@ -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, compareToFirstDbEntry} from './testUtils.
|
|
7
|
+
import {getMongoOperator, handleError, compareToFirstDbEntry} 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:add-blob-size:test');
|
|
12
12
|
|
|
13
13
|
generateTests({
|
|
@@ -41,32 +41,31 @@ 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', 'add-blob-size'],
|
|
46
45
|
gridFS: {bucketName: 'foobar'},
|
|
47
46
|
useObjectId: true
|
|
48
47
|
});
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
async function callback(callbackParams: Record<string, any>) {
|
|
51
|
+
const {
|
|
52
|
+
getFixture,
|
|
53
|
+
functionName,
|
|
54
|
+
params,
|
|
55
|
+
expectModificationTime = false,
|
|
56
|
+
preFillDb = false,
|
|
57
|
+
expectedToThrow = false,
|
|
58
|
+
expectedErrorMessage = '',
|
|
59
|
+
expectedErrorStatus = ''
|
|
61
60
|
|
|
62
|
-
}
|
|
61
|
+
} = callbackParams;
|
|
63
62
|
|
|
64
63
|
const mongoOperator = await getMongoOperator(mongoFixtures);
|
|
65
64
|
const expectedResult = await getFixture('expectedResult.json');
|
|
66
65
|
|
|
67
66
|
await doPreFillDb(preFillDb);
|
|
68
67
|
|
|
69
|
-
async function doPreFillDb(preFillDb) {
|
|
68
|
+
async function doPreFillDb(preFillDb: boolean) {
|
|
70
69
|
if (preFillDb) {
|
|
71
70
|
await mongoFixtures.populate(getFixture('dbContents.json'));
|
|
72
71
|
return;
|
package/{tests/mongo-check-and-check-state.test.js → test/mongo-check-and-check-state.test.ts}
RENAMED
|
@@ -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, compareToFirstDbEntry} from './testUtils.
|
|
7
|
+
import {getMongoOperator, handleError, compareToFirstDbEntry} 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: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', 'check-and-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,
|
|
@@ -59,14 +59,14 @@ async function callback({
|
|
|
59
59
|
expectedErrorStatus = '',
|
|
60
60
|
expectedOpResult = undefined,
|
|
61
61
|
updateStateBeforeTest = undefined
|
|
62
|
-
}
|
|
62
|
+
} = callbackParams;
|
|
63
63
|
|
|
64
64
|
const mongoOperator = await getMongoOperator(mongoFixtures);
|
|
65
65
|
const expectedResult = await getFixture('expectedResult.json');
|
|
66
66
|
|
|
67
67
|
await doPreFillDb(preFillDb);
|
|
68
68
|
|
|
69
|
-
async function doPreFillDb(preFillDb) {
|
|
69
|
+
async function doPreFillDb(preFillDb: boolean) {
|
|
70
70
|
if (preFillDb) {
|
|
71
71
|
await mongoFixtures.populate(getFixture('dbContents.json'));
|
|
72
72
|
return;
|
|
@@ -81,7 +81,6 @@ async function callback({
|
|
|
81
81
|
//{correlationId, state, errorMessage = undefined, errorStatus = undefined})
|
|
82
82
|
// timeout
|
|
83
83
|
|
|
84
|
-
// eslint-disable-next-line functional/no-conditional-statements
|
|
85
84
|
if (updateStateBeforeTest && params.correlationId) {
|
|
86
85
|
debug(`setState to reset modificationTime`);
|
|
87
86
|
await mongoOperator.setState({correlationId: params.correlationId, state: updateStateBeforeTest});
|
|
@@ -91,7 +90,6 @@ async function callback({
|
|
|
91
90
|
|
|
92
91
|
// checkAndSetState now returns a discriminated result
|
|
93
92
|
// {status: 'updated' | 'timeout' | 'unchanged', queueItem} - compare status
|
|
94
|
-
// eslint-disable-next-line functional/no-conditional-statements
|
|
95
93
|
if (expectedOpResult !== undefined) {
|
|
96
94
|
assert.deepStrictEqual(opResult.status, expectedOpResult);
|
|
97
95
|
}
|