@natlibfi/melinda-rest-api-commons 2.3.2-alpha.9 → 2.3.3-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/dist/amqp.health.spec.js +69 -0
- package/dist/amqp.health.spec.js.map +1 -0
- package/dist/amqp.js +29 -17
- package/dist/amqp.js.map +1 -1
- package/dist/amqp.tests.spec.js +338 -0
- package/dist/amqp.tests.spec.js.map +1 -0
- package/dist/mongo.js +1 -0
- package/dist/mongo.js.map +1 -1
- package/dist/mongo.spec.js.draft +54 -0
- package/dist/mongoLog.js +37 -1
- package/dist/mongoLog.js.map +1 -1
- package/package.json +122 -118
- package/dist/amqp.spec.js +0 -252
- package/dist/amqp.spec.js.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
4
|
+
var _index = require("./index");
|
|
5
|
+
var _util = require("util");
|
|
6
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @licstart The following is the entire license notice for the JavaScript code in this file.
|
|
10
|
+
*
|
|
11
|
+
* Shared modules for microservices of Melinda rest api batch import system
|
|
12
|
+
*
|
|
13
|
+
* Copyright (C) 2022 University Of Helsinki (The National Library Of Finland)
|
|
14
|
+
*
|
|
15
|
+
* This file is part of melinda-rest-api-commons
|
|
16
|
+
*
|
|
17
|
+
* melinda-rest-api-commons program is free software: you can redistribute it and/or modify
|
|
18
|
+
* it under the terms of the GNU Affero General Public License as
|
|
19
|
+
* published by the Free Software Foundation, either version 3 of the
|
|
20
|
+
* License, or (at your option) any later version.
|
|
21
|
+
*
|
|
22
|
+
* melinda-rest-api-commons is distributed in the hope that it will be useful,
|
|
23
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
24
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
25
|
+
* GNU Affero General Public License for more details.
|
|
26
|
+
*
|
|
27
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
28
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
29
|
+
*
|
|
30
|
+
* @licend The above is the entire license notice
|
|
31
|
+
* for the JavaScript code in this file.
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
//import {expect} from 'chai';
|
|
36
|
+
|
|
37
|
+
const debug = (0, _debug.default)('@natlibfi/melinda-rest-api-commons:amqp:test');
|
|
38
|
+
//const debugData = debug.extend('data');
|
|
39
|
+
|
|
40
|
+
const setTimeoutPromise = (0, _util.promisify)(setTimeout);
|
|
41
|
+
describe('HealthCheck: amqpOperator should error if channel or connection fails', () => {
|
|
42
|
+
it('FIX: test healthCheck - this test does not really test anything, but error can be seen in debug!', async () => {
|
|
43
|
+
debug(`Testing amqp against a local AMQP instance - we'll need some kind of mockup for this`);
|
|
44
|
+
const amqpUrl = 'amqp://127.0.0.1:5672/';
|
|
45
|
+
const amqpOperator = await (0, _index.amqpFactory)(amqpUrl, true);
|
|
46
|
+
debug(`Connecting to ${amqpUrl}, with healthCheck running`);
|
|
47
|
+
await awaitTime(amqpOperator, false);
|
|
48
|
+
debug(`Testing healthCheckLoop for ${amqpOperator}`);
|
|
49
|
+
debug(`Waiting 0.5s and expecting healthCheckLoop to work`);
|
|
50
|
+
await awaitTime(amqpOperator, false);
|
|
51
|
+
debug(`Amqp Operator should have been alive.`);
|
|
52
|
+
debug(`Testing healthCheckLoop with closed channel`);
|
|
53
|
+
debug(`Waiting 0.5s and expecting healthCheckLoop to throw error`);
|
|
54
|
+
await awaitTime(amqpOperator, true);
|
|
55
|
+
debug(`Amqp Operator should have been errored.`);
|
|
56
|
+
debug(`Closing connection`);
|
|
57
|
+
await amqpOperator.closeConnection();
|
|
58
|
+
async function awaitTime(amqpOperator, close) {
|
|
59
|
+
if (close) {
|
|
60
|
+
await amqpOperator.closeChannel();
|
|
61
|
+
await setTimeoutPromise(500);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
await setTimeoutPromise(500);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=amqp.health.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amqp.health.spec.js","names":["debug","createDebugLogger","setTimeoutPromise","promisify","setTimeout","describe","it","amqpUrl","amqpOperator","amqpFactory","awaitTime","closeConnection","close","closeChannel"],"sources":["../src/amqp.health.spec.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Shared modules for microservices of Melinda rest api batch import system\n*\n* Copyright (C) 2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-rest-api-commons\n*\n* melinda-rest-api-commons program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Affero General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-rest-api-commons is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Affero General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\n//import {expect} from 'chai';\nimport createDebugLogger from 'debug';\nimport {amqpFactory} from './index';\n\n\nconst debug = createDebugLogger('@natlibfi/melinda-rest-api-commons:amqp:test');\n//const debugData = debug.extend('data');\n\nimport {promisify} from 'util';\nconst setTimeoutPromise = promisify(setTimeout);\n\ndescribe('HealthCheck: amqpOperator should error if channel or connection fails', () => {\n\n it('FIX: test healthCheck - this test does not really test anything, but error can be seen in debug!', async () => {\n debug(`Testing amqp against a local AMQP instance - we'll need some kind of mockup for this`);\n const amqpUrl = 'amqp://127.0.0.1:5672/';\n\n const amqpOperator = await amqpFactory(amqpUrl, true);\n debug(`Connecting to ${amqpUrl}, with healthCheck running`);\n await awaitTime(amqpOperator, false);\n\n debug(`Testing healthCheckLoop for ${amqpOperator}`);\n debug(`Waiting 0.5s and expecting healthCheckLoop to work`);\n await awaitTime(amqpOperator, false);\n debug(`Amqp Operator should have been alive.`);\n\n debug(`Testing healthCheckLoop with closed channel`);\n debug(`Waiting 0.5s and expecting healthCheckLoop to throw error`);\n await awaitTime(amqpOperator, true);\n debug(`Amqp Operator should have been errored.`);\n\n debug(`Closing connection`);\n await amqpOperator.closeConnection();\n\n async function awaitTime(amqpOperator, close) {\n if (close) {\n await amqpOperator.closeChannel();\n await setTimeoutPromise(500);\n return;\n }\n\n await setTimeoutPromise(500);\n return;\n }\n\n });\n});\n\n"],"mappings":";;AA6BA;AACA;AAMA;AAA+B;AApC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAKA,MAAMA,KAAK,GAAG,IAAAC,cAAiB,EAAC,8CAA8C,CAAC;AAC/E;;AAGA,MAAMC,iBAAiB,GAAG,IAAAC,eAAS,EAACC,UAAU,CAAC;AAE/CC,QAAQ,CAAC,uEAAuE,EAAE,MAAM;EAEtFC,EAAE,CAAC,kGAAkG,EAAE,YAAY;IACjHN,KAAK,CAAE,sFAAqF,CAAC;IAC7F,MAAMO,OAAO,GAAG,wBAAwB;IAExC,MAAMC,YAAY,GAAG,MAAM,IAAAC,kBAAW,EAACF,OAAO,EAAE,IAAI,CAAC;IACrDP,KAAK,CAAE,iBAAgBO,OAAQ,4BAA2B,CAAC;IAC3D,MAAMG,SAAS,CAACF,YAAY,EAAE,KAAK,CAAC;IAEpCR,KAAK,CAAE,+BAA8BQ,YAAa,EAAC,CAAC;IACpDR,KAAK,CAAE,oDAAmD,CAAC;IAC3D,MAAMU,SAAS,CAACF,YAAY,EAAE,KAAK,CAAC;IACpCR,KAAK,CAAE,uCAAsC,CAAC;IAE9CA,KAAK,CAAE,6CAA4C,CAAC;IACpDA,KAAK,CAAE,2DAA0D,CAAC;IAClE,MAAMU,SAAS,CAACF,YAAY,EAAE,IAAI,CAAC;IACnCR,KAAK,CAAE,yCAAwC,CAAC;IAEhDA,KAAK,CAAE,oBAAmB,CAAC;IAC3B,MAAMQ,YAAY,CAACG,eAAe,EAAE;IAEpC,eAAeD,SAAS,CAACF,YAAY,EAAEI,KAAK,EAAE;MAC5C,IAAIA,KAAK,EAAE;QACT,MAAMJ,YAAY,CAACK,YAAY,EAAE;QACjC,MAAMX,iBAAiB,CAAC,GAAG,CAAC;QAC5B;MACF;MAEA,MAAMA,iBAAiB,CAAC,GAAG,CAAC;MAC5B;IACF;EAEF,CAAC,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/amqp.js
CHANGED
|
@@ -42,19 +42,18 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
42
42
|
*
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
|
-
//import {logError} from './utils';
|
|
46
|
-
|
|
47
45
|
async function _default(AMQP_URL, runHealthCheck = false) {
|
|
48
46
|
const logger = (0, _melindaBackendCommons.createLogger)();
|
|
49
47
|
const debug = (0, _debug.default)('@natlibfi/melinda-rest-api-commons:amqp');
|
|
50
48
|
const debugHC = debug.extend('HC');
|
|
49
|
+
const debugData = debug.extend('data');
|
|
51
50
|
debug(`Creating an AMQP operator to ${AMQP_URL}`);
|
|
52
51
|
const connection = await _amqplib.default.connect(AMQP_URL);
|
|
53
52
|
const channel = await connection.createChannel();
|
|
54
|
-
const healthCheckLoop = runHealthCheck ? healthCheck() :
|
|
53
|
+
const healthCheckLoop = runHealthCheck ? healthCheck() : false;
|
|
55
54
|
debug(`Connection: ${connection}`);
|
|
56
55
|
debug(`Channel: ${channel}`);
|
|
57
|
-
debug(`HealthCheckLoop ${healthCheckLoop}`);
|
|
56
|
+
debug(`HealthCheckLoop: ${healthCheckLoop ? 'Running health check' : 'Not running health check'}`);
|
|
58
57
|
return {
|
|
59
58
|
checkQueue,
|
|
60
59
|
consumeChunk,
|
|
@@ -91,9 +90,8 @@ async function _default(AMQP_URL, runHealthCheck = false) {
|
|
|
91
90
|
debugHC(`Waiting 200ms before running healthCheck next`);
|
|
92
91
|
return healthCheck('200');
|
|
93
92
|
} catch (error) {
|
|
94
|
-
const errorToThrow = error;
|
|
95
93
|
debugHC(`HealthCheck error ${JSON.stringify(error)}`);
|
|
96
|
-
handleAmqpErrors(
|
|
94
|
+
handleAmqpErrors(error);
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
97
|
|
|
@@ -122,31 +120,40 @@ async function _default(AMQP_URL, runHealthCheck = false) {
|
|
|
122
120
|
if (style === 'messages') {
|
|
123
121
|
return channelInfo.messageCount;
|
|
124
122
|
}
|
|
125
|
-
if (channelInfo.messageCount < 1) {
|
|
126
|
-
debug(`checkQueue: ${channelInfo.messageCount} - ${queue} is empty`);
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
debug(`Queue ${queue} has ${channelInfo.messageCount} messages`);
|
|
130
123
|
|
|
131
124
|
// Note: returns one message (+ record, of toRecord: true)
|
|
132
125
|
// note: if toRecord is false returns just plain message / false
|
|
133
126
|
// note: if toRecord is true returns {headers, records, messages} -object / false
|
|
134
127
|
// should this be more consistent?
|
|
135
128
|
if (style === 'one') {
|
|
136
|
-
|
|
129
|
+
if (checkMessageCount(channelInfo)) {
|
|
130
|
+
return consumeOne(queue, toRecord);
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
137
133
|
}
|
|
138
134
|
|
|
139
135
|
// Note: returns a chunk of (100) messages (+ records, if toRecord: true)
|
|
140
136
|
// returns {headers, records, messages} object or {headers, messages} object depending on toRecord
|
|
141
137
|
if (style === 'basic') {
|
|
142
|
-
|
|
138
|
+
if (checkMessageCount(channelInfo)) {
|
|
139
|
+
return consumeChunk(queue, toRecord);
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
// Defaults:
|
|
146
|
-
throw new _melindaCommons.Error(_httpStatus.default.
|
|
145
|
+
throw new _melindaCommons.Error(_httpStatus.default.INTERNAL_SERVER_ERROR, `CheckQueue does not recognize style ${style}`);
|
|
147
146
|
} catch (error) {
|
|
148
147
|
handleAmqpErrors(error);
|
|
149
148
|
}
|
|
149
|
+
function checkMessageCount(channelInfo) {
|
|
150
|
+
if (channelInfo.messageCount < 1) {
|
|
151
|
+
debug(`checkQueue: ${channelInfo.messageCount} - ${queue} is empty`);
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
debug(`Queue ${queue} has ${channelInfo.messageCount} messages`);
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
150
157
|
function purgeQueue(purge) {
|
|
151
158
|
debug(`Purging queue: ${queue}, purge: ${purge}`);
|
|
152
159
|
if (purge) {
|
|
@@ -163,6 +170,8 @@ async function _default(AMQP_URL, runHealthCheck = false) {
|
|
|
163
170
|
|
|
164
171
|
// getData: next chunk (100) messages
|
|
165
172
|
const messages = await getData(queue);
|
|
173
|
+
|
|
174
|
+
// Note: headers are from the first message of the chunk
|
|
166
175
|
const headers = getHeaderInfo(messages[0]);
|
|
167
176
|
debug(`consumeChunk (${messages ? messages.length : '0'} from queue ${queue}) ${toRecord ? 'to records' : 'just messages'}`);
|
|
168
177
|
if (toRecord) {
|
|
@@ -190,7 +199,7 @@ async function _default(AMQP_URL, runHealthCheck = false) {
|
|
|
190
199
|
|
|
191
200
|
// Returns false if 0 items in queue
|
|
192
201
|
const message = await channel.get(queue);
|
|
193
|
-
|
|
202
|
+
debugData(`Message: ${(0, _util.inspect)(message, {
|
|
194
203
|
colors: true,
|
|
195
204
|
maxArrayLength: 3,
|
|
196
205
|
depth: 3
|
|
@@ -237,7 +246,7 @@ async function _default(AMQP_URL, runHealthCheck = false) {
|
|
|
237
246
|
try {
|
|
238
247
|
debug(`Queue ${queue}`);
|
|
239
248
|
debug(`CorrelationId ${correlationId}`);
|
|
240
|
-
|
|
249
|
+
debugData(`Data ${JSON.stringify(data)}`);
|
|
241
250
|
debug(`Headers ${JSON.stringify(headers)}`);
|
|
242
251
|
errorUndefinedQueue(queue);
|
|
243
252
|
debug(`Asserting queue: ${queue}`);
|
|
@@ -285,6 +294,7 @@ async function _default(AMQP_URL, runHealthCheck = false) {
|
|
|
285
294
|
debug(`Parsing messages (${messages.length}) to records`);
|
|
286
295
|
return messages.map(message => {
|
|
287
296
|
const content = JSON.parse(message.content.toString());
|
|
297
|
+
// Should we have here validationOptions
|
|
288
298
|
return new _marcRecord.MarcRecord(content.data);
|
|
289
299
|
});
|
|
290
300
|
}
|
|
@@ -329,10 +339,12 @@ async function _default(AMQP_URL, runHealthCheck = false) {
|
|
|
329
339
|
}
|
|
330
340
|
function handleAmqpErrors(error) {
|
|
331
341
|
const newError = error;
|
|
332
|
-
|
|
342
|
+
debug(`HandleAmqpErrors got an error: ${JSON.stringify(error)}`);
|
|
333
343
|
if (error instanceof _melindaCommons.Error) {
|
|
344
|
+
debug(`We have an ApiError`);
|
|
334
345
|
throw new _melindaCommons.Error(newError.status, newError.payload);
|
|
335
346
|
}
|
|
347
|
+
debug(`We have a non-ApiError`);
|
|
336
348
|
(0, _utils.logError)(error);
|
|
337
349
|
throw newError;
|
|
338
350
|
}
|
package/dist/amqp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"amqp.js","names":["AMQP_URL","runHealthCheck","logger","createLogger","debug","createDebugLogger","debugHC","extend","connection","amqplib","connect","channel","createChannel","healthCheckLoop","healthCheck","checkQueue","consumeChunk","consumeOne","ackMessages","nackMessages","sendToQueue","removeQueue","messagesToRecords","closeChannel","closeConnection","close","wait","setTimeoutPromise","promisify","setTimeout","assertQueue","durable","error","errorToThrow","JSON","stringify","handleAmqpErrors","queue","style","toRecord","purge","errorUndefinedQueue","channelInfo","purgeQueue","verbose","messageCount","ApiError","httpStatus","UNPROCESSABLE_ENTITY","messages","getData","headers","getHeaderInfo","length","records","message","get","inspect","colors","maxArrayLength","depth","forEach","properties","correlationId","ack","nack","data","Buffer","from","persistent","tempChannel","deleteQueue","map","content","parse","toString","MarcRecord","messagesToGet","CHUNK_SIZE","pump","count","results","identifiers","identifier","deliveryTag","fields","includes","concat","undefined","INTERNAL_SERVER_ERROR","newError","status","payload","logError"],"sources":["../src/amqp.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Shared modules for microservices of Melinda rest api batch import system\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-rest-api-commons\n*\n* melinda-rest-api-commons program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Affero General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-rest-api-commons is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Affero General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport amqplib from 'amqplib';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {Error as ApiError} from '@natlibfi/melinda-commons';\nimport {createLogger} from '@natlibfi/melinda-backend-commons';\nimport createDebugLogger from 'debug';\nimport {CHUNK_SIZE} from './constants';\n//import {logError} from './utils';\nimport {promisify, inspect} from 'util';\nimport httpStatus from 'http-status';\nimport {logError} from './utils';\n\nexport default async function (AMQP_URL, runHealthCheck = false) {\n const logger = createLogger();\n const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons:amqp');\n const debugHC = debug.extend('HC');\n\n debug(`Creating an AMQP operator to ${AMQP_URL}`);\n const connection = await amqplib.connect(AMQP_URL);\n const channel = await connection.createChannel();\n\n const healthCheckLoop = runHealthCheck ? healthCheck() : 'Not running health check';\n\n debug(`Connection: ${connection}`);\n debug(`Channel: ${channel}`);\n debug(`HealthCheckLoop ${healthCheckLoop}`);\n\n return {checkQueue, consumeChunk, consumeOne, ackMessages, nackMessages, sendToQueue, removeQueue, messagesToRecords, closeChannel, closeConnection};\n\n async function closeChannel() {\n debug(`Closing channel`);\n await channel.close();\n debug(`Channel: ${channel}`);\n }\n\n async function closeConnection() {\n debug(`Closing connection`);\n await connection.close();\n debug(`Connection: ${connection}`);\n }\n\n async function healthCheck(wait = false) {\n const setTimeoutPromise = promisify(setTimeout);\n if (wait) {\n await setTimeoutPromise(wait);\n return healthCheck(false);\n }\n\n try {\n debugHC(`Health checking amqp by asserting a queue`);\n await channel.assertQueue('HEALTHCHECK', {durable: false});\n debugHC(`Waiting 200ms before running healthCheck next`);\n return healthCheck('200');\n } catch (error) {\n const errorToThrow = error;\n debugHC(`HealthCheck error ${JSON.stringify(error)}`);\n handleAmqpErrors(errorToThrow);\n }\n }\n\n // eslint-disable-next-line max-statements\n async function checkQueue({queue, style = 'basic', toRecord = true, purge = false}) {\n debug(`checkQueue: ${queue}, Style: ${style}, toRecord: ${toRecord}, Purge: ${purge}`);\n\n try {\n\n errorUndefinedQueue(queue);\n const channelInfo = await channel.assertQueue(queue, {durable: true});\n\n if (purge) {\n await purgeQueue(purge);\n logger.verbose(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);\n debug(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);\n return checkQueue({queue, style});\n }\n\n if (style === 'messages') {\n return channelInfo.messageCount;\n }\n\n if (channelInfo.messageCount < 1) {\n debug(`checkQueue: ${channelInfo.messageCount} - ${queue} is empty`);\n return false;\n }\n debug(`Queue ${queue} has ${channelInfo.messageCount} messages`);\n\n // Note: returns one message (+ record, of toRecord: true)\n // note: if toRecord is false returns just plain message / false\n // note: if toRecord is true returns {headers, records, messages} -object / false\n // should this be more consistent?\n if (style === 'one') {\n return consumeOne(queue, toRecord);\n }\n\n // Note: returns a chunk of (100) messages (+ records, if toRecord: true)\n // returns {headers, records, messages} object or {headers, messages} object depending on toRecord\n if (style === 'basic') {\n return consumeChunk(queue, toRecord);\n }\n\n // Defaults:\n throw new ApiError(httpStatus.UNPROCESSABLE_ENTITY);\n } catch (error) {\n handleAmqpErrors(error);\n }\n\n function purgeQueue(purge) {\n debug(`Purging queue: ${queue}, purge: ${purge}`);\n if (purge) {\n return channel.purgeQueue(queue);\n }\n }\n }\n\n async function consumeChunk(queue, toRecord) {\n debug(`Prepared to consumeChunk from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // getData: next chunk (100) messages\n const messages = await getData(queue);\n const headers = getHeaderInfo(messages[0]);\n debug(`consumeChunk (${messages ? messages.length : '0'} from queue ${queue}) ${toRecord ? 'to records' : 'just messages'}`);\n\n if (toRecord) {\n const records = await messagesToRecords(messages);\n return {headers, records, messages};\n }\n\n return {headers, messages};\n } catch (error) {\n handleAmqpErrors(error);\n }\n }\n\n async function consumeOne(queue, toRecord) {\n debug(`Prepared to consumeOne from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // Returns false if 0 items in queue\n const message = await channel.get(queue);\n\n debug(`Message: ${inspect(message, {colors: true, maxArrayLength: 3, depth: 3})}`);\n // Do not spam the logs\n debug(`consumeOne from queue: ${queue} ${toRecord ? 'to records' : 'just the message'}`);\n\n if (message) {\n if (toRecord) {\n const headers = getHeaderInfo(message);\n const records = messagesToRecords([message]);\n return {headers, records, messages: [message]};\n }\n\n return message;\n }\n\n return false;\n } catch (error) {\n handleAmqpErrors(error);\n }\n }\n\n function ackMessages(messages) {\n messages.forEach(message => {\n debug(`Ack message ${message.properties.correlationId}`);\n channel.ack(message);\n });\n }\n\n function nackMessages(messages) {\n messages.forEach(message => {\n debug(`Nack message ${message.properties.correlationId}`);\n channel.nack(message);\n });\n }\n\n async function sendToQueue({queue, correlationId, headers, data}) {\n debug(`sendToQueue`);\n // eslint-disable-next-line no-useless-catch\n try {\n debug(`Queue ${queue}`);\n debug(`CorrelationId ${correlationId}`);\n debug(`Data ${JSON.stringify(data)}`);\n debug(`Headers ${JSON.stringify(headers)}`);\n\n errorUndefinedQueue(queue);\n\n debug(`Asserting queue: ${queue}`);\n await channel.assertQueue(queue, {durable: true});\n\n debug(`Actually sendToQueue: ${queue}`);\n await channel.sendToQueue(\n queue,\n Buffer.from(JSON.stringify({data})),\n {\n correlationId,\n persistent: true,\n headers\n }\n );\n debug(`Send message for ${correlationId} to queue: ${queue}`);\n\n\n } catch (error) {\n const errorToThrow = error;\n //if (error instanceof ApiError) {\n // throw error;\n //}\n debug(`SendToQueue errored: ${JSON.stringify(error)}`);\n handleAmqpErrors(errorToThrow);\n }\n }\n\n async function removeQueue(queue) {\n // deleteQueue borks the channel if the queue does not exist\n // -> use throwaway tempChannel to avoid killing actual channel in use\n // this might be doable also with assertQueue before deleteQueue\n const tempChannel = await connection.createChannel();\n logger.verbose(`Removing queue ${queue}.`);\n debug(`Removing queue ${queue}.`);\n await tempChannel.deleteQueue(queue);\n\n if (tempChannel) {\n await tempChannel.close();\n return;\n }\n\n return;\n }\n\n // ----------------\n // Helper functions\n // ----------------\n\n function messagesToRecords(messages) {\n debug(`Parsing messages (${messages.length}) to records`);\n\n return messages.map(message => {\n const content = JSON.parse(message.content.toString());\n return new MarcRecord(content.data);\n });\n }\n\n async function getData(queue) {\n debug(`Getting queue data from ${queue}`);\n try {\n const {messageCount} = await channel.checkQueue(queue);\n debug(`There is ${messageCount} messages in queue ${queue}`);\n const messagesToGet = messageCount >= CHUNK_SIZE ? CHUNK_SIZE : messageCount;\n debug(`Getting ${messagesToGet} messages from queue ${queue}`);\n\n const messages = await pump(messagesToGet);\n\n debug(`Returning ${messages.length} unique messages`);\n\n return messages;\n } catch (error) {\n handleAmqpErrors(error);\n }\n\n async function pump(count, results = [], identifiers = []) {\n if (count === 0) {\n return results;\n }\n\n const message = await channel.get(queue);\n const identifier = {\n correlationId: message.properties.correlationId,\n deliveryTag: message.fields.deliveryTag\n };\n // Filter not unique messages\n if (identifiers.includes(identifier)) {\n return pump(count - 1, results, identifiers);\n }\n\n return pump(count - 1, results.concat(message), identifiers.concat(identifier));\n }\n }\n\n function getHeaderInfo(data) {\n return data.properties.headers;\n }\n\n function errorUndefinedQueue(queue) {\n if (queue === undefined || queue === '' || queue === null) {\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Undefined queue!`);\n }\n }\n\n function handleAmqpErrors(error) {\n const newError = error;\n //debug(`HandleAmqpErrors got an error: ${JSON.stringify(error)}`);\n if (error instanceof ApiError) {\n throw new ApiError(newError.status, newError.payload);\n }\n logError(error);\n throw newError;\n }\n}\n\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"amqp.js","names":["AMQP_URL","runHealthCheck","logger","createLogger","debug","createDebugLogger","debugHC","extend","debugData","connection","amqplib","connect","channel","createChannel","healthCheckLoop","healthCheck","checkQueue","consumeChunk","consumeOne","ackMessages","nackMessages","sendToQueue","removeQueue","messagesToRecords","closeChannel","closeConnection","close","wait","setTimeoutPromise","promisify","setTimeout","assertQueue","durable","error","JSON","stringify","handleAmqpErrors","queue","style","toRecord","purge","errorUndefinedQueue","channelInfo","purgeQueue","verbose","messageCount","checkMessageCount","ApiError","httpStatus","INTERNAL_SERVER_ERROR","messages","getData","headers","getHeaderInfo","length","records","message","get","inspect","colors","maxArrayLength","depth","forEach","properties","correlationId","ack","nack","data","Buffer","from","persistent","errorToThrow","tempChannel","deleteQueue","map","content","parse","toString","MarcRecord","messagesToGet","CHUNK_SIZE","pump","count","results","identifiers","identifier","deliveryTag","fields","includes","concat","undefined","newError","status","payload","logError"],"sources":["../src/amqp.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Shared modules for microservices of Melinda rest api batch import system\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-rest-api-commons\n*\n* melinda-rest-api-commons program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Affero General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-rest-api-commons is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Affero General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport amqplib from 'amqplib';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {Error as ApiError} from '@natlibfi/melinda-commons';\nimport {createLogger} from '@natlibfi/melinda-backend-commons';\nimport createDebugLogger from 'debug';\nimport {CHUNK_SIZE} from './constants';\nimport {promisify, inspect} from 'util';\nimport httpStatus from 'http-status';\nimport {logError} from './utils';\n\nexport default async function (AMQP_URL, runHealthCheck = false) {\n const logger = createLogger();\n const debug = createDebugLogger('@natlibfi/melinda-rest-api-commons:amqp');\n const debugHC = debug.extend('HC');\n const debugData = debug.extend('data');\n\n debug(`Creating an AMQP operator to ${AMQP_URL}`);\n const connection = await amqplib.connect(AMQP_URL);\n const channel = await connection.createChannel();\n\n const healthCheckLoop = runHealthCheck ? healthCheck() : false;\n\n debug(`Connection: ${connection}`);\n debug(`Channel: ${channel}`);\n debug(`HealthCheckLoop: ${healthCheckLoop ? 'Running health check' : 'Not running health check'}`);\n\n return {checkQueue, consumeChunk, consumeOne, ackMessages, nackMessages, sendToQueue, removeQueue, messagesToRecords, closeChannel, closeConnection};\n\n async function closeChannel() {\n debug(`Closing channel`);\n await channel.close();\n debug(`Channel: ${channel}`);\n }\n\n async function closeConnection() {\n debug(`Closing connection`);\n await connection.close();\n debug(`Connection: ${connection}`);\n }\n\n async function healthCheck(wait = false) {\n const setTimeoutPromise = promisify(setTimeout);\n if (wait) {\n await setTimeoutPromise(wait);\n return healthCheck(false);\n }\n\n try {\n debugHC(`Health checking amqp by asserting a queue`);\n await channel.assertQueue('HEALTHCHECK', {durable: false});\n debugHC(`Waiting 200ms before running healthCheck next`);\n return healthCheck('200');\n } catch (error) {\n debugHC(`HealthCheck error ${JSON.stringify(error)}`);\n handleAmqpErrors(error);\n }\n }\n\n // eslint-disable-next-line max-statements\n async function checkQueue({queue, style = 'basic', toRecord = true, purge = false}) {\n debug(`checkQueue: ${queue}, Style: ${style}, toRecord: ${toRecord}, Purge: ${purge}`);\n\n try {\n\n errorUndefinedQueue(queue);\n const channelInfo = await channel.assertQueue(queue, {durable: true});\n\n if (purge) {\n await purgeQueue(purge);\n logger.verbose(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);\n debug(`Queue ${queue} has purged ${channelInfo.messageCount} messages`);\n return checkQueue({queue, style});\n }\n\n if (style === 'messages') {\n return channelInfo.messageCount;\n }\n\n\n // Note: returns one message (+ record, of toRecord: true)\n // note: if toRecord is false returns just plain message / false\n // note: if toRecord is true returns {headers, records, messages} -object / false\n // should this be more consistent?\n if (style === 'one') {\n if (checkMessageCount(channelInfo)) {\n return consumeOne(queue, toRecord);\n }\n return false;\n }\n\n // Note: returns a chunk of (100) messages (+ records, if toRecord: true)\n // returns {headers, records, messages} object or {headers, messages} object depending on toRecord\n if (style === 'basic') {\n if (checkMessageCount(channelInfo)) {\n return consumeChunk(queue, toRecord);\n }\n return false;\n }\n\n // Defaults:\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `CheckQueue does not recognize style ${style}`);\n } catch (error) {\n handleAmqpErrors(error);\n }\n\n function checkMessageCount(channelInfo) {\n if (channelInfo.messageCount < 1) {\n debug(`checkQueue: ${channelInfo.messageCount} - ${queue} is empty`);\n return false;\n }\n debug(`Queue ${queue} has ${channelInfo.messageCount} messages`);\n return true;\n }\n\n function purgeQueue(purge) {\n debug(`Purging queue: ${queue}, purge: ${purge}`);\n if (purge) {\n return channel.purgeQueue(queue);\n }\n }\n }\n\n async function consumeChunk(queue, toRecord) {\n debug(`Prepared to consumeChunk from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // getData: next chunk (100) messages\n const messages = await getData(queue);\n\n // Note: headers are from the first message of the chunk\n const headers = getHeaderInfo(messages[0]);\n debug(`consumeChunk (${messages ? messages.length : '0'} from queue ${queue}) ${toRecord ? 'to records' : 'just messages'}`);\n\n if (toRecord) {\n const records = await messagesToRecords(messages);\n return {headers, records, messages};\n }\n\n return {headers, messages};\n } catch (error) {\n handleAmqpErrors(error);\n }\n }\n\n async function consumeOne(queue, toRecord) {\n debug(`Prepared to consumeOne from queue: ${queue}`);\n try {\n await channel.assertQueue(queue, {durable: true});\n\n // Returns false if 0 items in queue\n const message = await channel.get(queue);\n\n debugData(`Message: ${inspect(message, {colors: true, maxArrayLength: 3, depth: 3})}`);\n // Do not spam the logs\n debug(`consumeOne from queue: ${queue} ${toRecord ? 'to records' : 'just the message'}`);\n\n if (message) {\n if (toRecord) {\n const headers = getHeaderInfo(message);\n const records = messagesToRecords([message]);\n return {headers, records, messages: [message]};\n }\n\n return message;\n }\n\n return false;\n } catch (error) {\n handleAmqpErrors(error);\n }\n }\n\n function ackMessages(messages) {\n messages.forEach(message => {\n debug(`Ack message ${message.properties.correlationId}`);\n channel.ack(message);\n });\n }\n\n function nackMessages(messages) {\n messages.forEach(message => {\n debug(`Nack message ${message.properties.correlationId}`);\n channel.nack(message);\n });\n }\n\n async function sendToQueue({queue, correlationId, headers, data}) {\n debug(`sendToQueue`);\n // eslint-disable-next-line no-useless-catch\n try {\n debug(`Queue ${queue}`);\n debug(`CorrelationId ${correlationId}`);\n debugData(`Data ${JSON.stringify(data)}`);\n debug(`Headers ${JSON.stringify(headers)}`);\n\n errorUndefinedQueue(queue);\n\n debug(`Asserting queue: ${queue}`);\n await channel.assertQueue(queue, {durable: true});\n\n debug(`Actually sendToQueue: ${queue}`);\n await channel.sendToQueue(\n queue,\n Buffer.from(JSON.stringify({data})),\n {\n correlationId,\n persistent: true,\n headers\n }\n );\n debug(`Send message for ${correlationId} to queue: ${queue}`);\n\n\n } catch (error) {\n const errorToThrow = error;\n //if (error instanceof ApiError) {\n // throw error;\n //}\n debug(`SendToQueue errored: ${JSON.stringify(error)}`);\n handleAmqpErrors(errorToThrow);\n }\n }\n\n async function removeQueue(queue) {\n // deleteQueue borks the channel if the queue does not exist\n // -> use throwaway tempChannel to avoid killing actual channel in use\n // this might be doable also with assertQueue before deleteQueue\n const tempChannel = await connection.createChannel();\n logger.verbose(`Removing queue ${queue}.`);\n debug(`Removing queue ${queue}.`);\n await tempChannel.deleteQueue(queue);\n\n if (tempChannel) {\n await tempChannel.close();\n return;\n }\n\n return;\n }\n\n // ----------------\n // Helper functions\n // ----------------\n\n function messagesToRecords(messages) {\n debug(`Parsing messages (${messages.length}) to records`);\n\n return messages.map(message => {\n const content = JSON.parse(message.content.toString());\n // Should we have here validationOptions\n return new MarcRecord(content.data);\n });\n }\n\n async function getData(queue) {\n debug(`Getting queue data from ${queue}`);\n try {\n const {messageCount} = await channel.checkQueue(queue);\n debug(`There is ${messageCount} messages in queue ${queue}`);\n const messagesToGet = messageCount >= CHUNK_SIZE ? CHUNK_SIZE : messageCount;\n debug(`Getting ${messagesToGet} messages from queue ${queue}`);\n\n const messages = await pump(messagesToGet);\n\n debug(`Returning ${messages.length} unique messages`);\n\n return messages;\n } catch (error) {\n handleAmqpErrors(error);\n }\n\n async function pump(count, results = [], identifiers = []) {\n if (count === 0) {\n return results;\n }\n\n const message = await channel.get(queue);\n const identifier = {\n correlationId: message.properties.correlationId,\n deliveryTag: message.fields.deliveryTag\n };\n // Filter not unique messages\n if (identifiers.includes(identifier)) {\n return pump(count - 1, results, identifiers);\n }\n\n return pump(count - 1, results.concat(message), identifiers.concat(identifier));\n }\n }\n\n function getHeaderInfo(data) {\n return data.properties.headers;\n }\n\n function errorUndefinedQueue(queue) {\n if (queue === undefined || queue === '' || queue === null) {\n throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `Undefined queue!`);\n }\n }\n\n function handleAmqpErrors(error) {\n const newError = error;\n debug(`HandleAmqpErrors got an error: ${JSON.stringify(error)}`);\n if (error instanceof ApiError) {\n debug(`We have an ApiError`);\n throw new ApiError(newError.status, newError.payload);\n }\n debug(`We have a non-ApiError`);\n logError(error);\n throw newError;\n }\n}\n\n\n"],"mappings":"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"}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _chai = require("chai");
|
|
4
|
+
var _fixura = require("@natlibfi/fixura");
|
|
5
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
6
|
+
var _fixugen = _interopRequireDefault(require("@natlibfi/fixugen"));
|
|
7
|
+
var _index = require("./index");
|
|
8
|
+
var _melindaCommons = require("@natlibfi/melinda-commons");
|
|
9
|
+
var _util = require("util");
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @licstart The following is the entire license notice for the JavaScript code in this file.
|
|
14
|
+
*
|
|
15
|
+
* Shared modules for microservices of Melinda rest api batch import system
|
|
16
|
+
*
|
|
17
|
+
* Copyright (C) 2022 University Of Helsinki (The National Library Of Finland)
|
|
18
|
+
*
|
|
19
|
+
* This file is part of melinda-rest-api-commons
|
|
20
|
+
*
|
|
21
|
+
* melinda-rest-api-commons program is free software: you can redistribute it and/or modify
|
|
22
|
+
* it under the terms of the GNU Affero General Public License as
|
|
23
|
+
* published by the Free Software Foundation, either version 3 of the
|
|
24
|
+
* License, or (at your option) any later version.
|
|
25
|
+
*
|
|
26
|
+
* melinda-rest-api-commons is distributed in the hope that it will be useful,
|
|
27
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
28
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
29
|
+
* GNU Affero General Public License for more details.
|
|
30
|
+
*
|
|
31
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
32
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
33
|
+
*
|
|
34
|
+
* @licend The above is the entire license notice
|
|
35
|
+
* for the JavaScript code in this file.
|
|
36
|
+
*
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const setTimeoutPromise = (0, _util.promisify)(setTimeout);
|
|
40
|
+
const debug = (0, _debug.default)('@natlibfi/melinda-rest-api-commons:amqp:test');
|
|
41
|
+
//const debugData = debug.extend('data');
|
|
42
|
+
|
|
43
|
+
const testData = {
|
|
44
|
+
queue: 'TESTQUEUE',
|
|
45
|
+
correlationId: 'aaaaaaaa-0000-aaaa-0000-000000000000',
|
|
46
|
+
data: {
|
|
47
|
+
'leader': '02518cam a2200745zi 4500',
|
|
48
|
+
'fields': [{
|
|
49
|
+
'tag': '001',
|
|
50
|
+
'value': '000019640'
|
|
51
|
+
}]
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
debug(`Testing amqp against a local AMQP instance - we'll need some kind of mockup for this`);
|
|
55
|
+
const amqpUrl = 'amqp://127.0.0.1:5672/';
|
|
56
|
+
// eslint-disable-next-line functional/no-let
|
|
57
|
+
let amqpOperator;
|
|
58
|
+
(0, _fixugen.default)({
|
|
59
|
+
callback,
|
|
60
|
+
path: [__dirname, '..', 'test-fixtures', 'amqp'],
|
|
61
|
+
recurse: false,
|
|
62
|
+
useMetadataFile: true,
|
|
63
|
+
fixura: {
|
|
64
|
+
failWhenNotFound: true,
|
|
65
|
+
reader: _fixura.READERS.JSON
|
|
66
|
+
},
|
|
67
|
+
mocha: {
|
|
68
|
+
before: async () => {
|
|
69
|
+
debug(`Connecting to ${amqpUrl}, with healthCheck running`);
|
|
70
|
+
amqpOperator = await (0, _index.amqpFactory)(amqpUrl, true);
|
|
71
|
+
},
|
|
72
|
+
beforeEach: async () => {
|
|
73
|
+
await amqpOperator.checkQueue({
|
|
74
|
+
queue: testData.queue,
|
|
75
|
+
toRecord: false,
|
|
76
|
+
purge: true
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
afterEach: async () => {
|
|
80
|
+
await amqpOperator.removeQueue(testData.queue);
|
|
81
|
+
},
|
|
82
|
+
after: async () => {
|
|
83
|
+
await amqpOperator.closeConnection();
|
|
84
|
+
//await testHeathCheck();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// eslint-disable-next-line max-statements
|
|
90
|
+
async function callback({
|
|
91
|
+
getFixture,
|
|
92
|
+
expectToFail = false,
|
|
93
|
+
expectedErrorStatus = '',
|
|
94
|
+
ackMessages = false,
|
|
95
|
+
nackMessages = false,
|
|
96
|
+
checkNextMessage = false,
|
|
97
|
+
checkQueueStyle = false,
|
|
98
|
+
queue = testData.queue,
|
|
99
|
+
sentToQueue,
|
|
100
|
+
expectedMessageCount,
|
|
101
|
+
removeQueue = false,
|
|
102
|
+
expectedErrorMessage = undefined,
|
|
103
|
+
expectApiError = false,
|
|
104
|
+
expectFalseCheckResult = false
|
|
105
|
+
}) {
|
|
106
|
+
try {
|
|
107
|
+
await sendMessagesToQueue();
|
|
108
|
+
await ackOrNackMessages();
|
|
109
|
+
await checkQueue();
|
|
110
|
+
await queueRemoval();
|
|
111
|
+
const messageCount = await amqpOperator.checkQueue({
|
|
112
|
+
queue,
|
|
113
|
+
style: 'messages'
|
|
114
|
+
});
|
|
115
|
+
debug(`MessageCount: ${messageCount}`);
|
|
116
|
+
(0, _chai.expect)(messageCount).to.eql(expectedMessageCount);
|
|
117
|
+
if (checkNextMessage) {
|
|
118
|
+
// eslint-disable-line
|
|
119
|
+
const {
|
|
120
|
+
headers,
|
|
121
|
+
records
|
|
122
|
+
} = await queueCheckNextMessage();
|
|
123
|
+
const nextMessage = {
|
|
124
|
+
headers,
|
|
125
|
+
records
|
|
126
|
+
};
|
|
127
|
+
const expectedNextMessage = getFixture('expectedMessage.json');
|
|
128
|
+
(0, _chai.expect)(nextMessage).to.eql(expectedNextMessage);
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (!expectToFail) {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
(0, _chai.expect)(expectToFail, 'This is expected to fail').to.equal(true);
|
|
135
|
+
testErrors(error);
|
|
136
|
+
}
|
|
137
|
+
function testErrors(error) {
|
|
138
|
+
if (expectApiError) {
|
|
139
|
+
(0, _chai.expect)(error).to.be.instanceOf(_melindaCommons.Error);
|
|
140
|
+
debug(`We expected and got an ApiError`);
|
|
141
|
+
(0, _chai.expect)(error.status).to.equal(expectedErrorStatus);
|
|
142
|
+
if (expectedErrorMessage) {
|
|
143
|
+
(0, _chai.expect)(error.payload).to.eql(expectedErrorMessage);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
(0, _chai.expect)(error).not.to.be.instanceOf(_melindaCommons.Error);
|
|
149
|
+
debug(`We expected and got an non-ApiError`);
|
|
150
|
+
debug(`Error is a ${error.constructor.name}`);
|
|
151
|
+
}
|
|
152
|
+
function queueRemoval() {
|
|
153
|
+
if (removeQueue) {
|
|
154
|
+
return amqpOperator.removeQueue(removeQueue);
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
function queueCheckNextMessage() {
|
|
159
|
+
if (checkNextMessage) {
|
|
160
|
+
return amqpOperator.consumeOne(testData.queue, true);
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// eslint-disable-next-line max-statements
|
|
166
|
+
async function checkQueue() {
|
|
167
|
+
debug(`checkQueueStyle: ${checkQueueStyle}`);
|
|
168
|
+
if (checkQueueStyle === 'oneToRecord') {
|
|
169
|
+
const result = await amqpOperator.checkQueue({
|
|
170
|
+
queue,
|
|
171
|
+
style: 'one',
|
|
172
|
+
toRecord: true,
|
|
173
|
+
purge: false
|
|
174
|
+
});
|
|
175
|
+
if (expectFalseCheckResult) {
|
|
176
|
+
(0, _chai.expect)(result).to.eql(false);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
(0, _chai.expect)(result).to.have.property('headers');
|
|
180
|
+
(0, _chai.expect)(result).to.have.property('records');
|
|
181
|
+
(0, _chai.expect)(result).to.have.property('messages');
|
|
182
|
+
(0, _chai.expect)(result.records.length).to.eql(1);
|
|
183
|
+
(0, _chai.expect)(result.messages.length).to.eql(1);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (checkQueueStyle === 'oneNotRecord') {
|
|
187
|
+
const result = await amqpOperator.checkQueue({
|
|
188
|
+
queue,
|
|
189
|
+
style: 'one',
|
|
190
|
+
toRecord: false,
|
|
191
|
+
purge: false
|
|
192
|
+
});
|
|
193
|
+
const {
|
|
194
|
+
fields
|
|
195
|
+
} = result;
|
|
196
|
+
if (expectFalseCheckResult) {
|
|
197
|
+
(0, _chai.expect)(result).to.eql(false);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
(0, _chai.expect)(fields).to.have.property('deliveryTag');
|
|
201
|
+
(0, _chai.expect)(fields).to.have.property('exchange');
|
|
202
|
+
(0, _chai.expect)(fields).to.have.property('messageCount');
|
|
203
|
+
(0, _chai.expect)(fields).to.have.property('redelivered');
|
|
204
|
+
(0, _chai.expect)(fields).to.have.property('routingKey');
|
|
205
|
+
(0, _chai.expect)(typeof fields.deliveryTag).to.be.eql('number');
|
|
206
|
+
(0, _chai.expect)(typeof fields.messageCount).to.be.eql('number');
|
|
207
|
+
(0, _chai.expect)(typeof fields.redelivered).to.be.eql('boolean');
|
|
208
|
+
(0, _chai.expect)(typeof fields.routingKey).to.be.eql('string');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (checkQueueStyle === 'basicToRecord') {
|
|
212
|
+
const result = await amqpOperator.checkQueue({
|
|
213
|
+
queue,
|
|
214
|
+
style: 'basic',
|
|
215
|
+
toRecord: true,
|
|
216
|
+
purge: false
|
|
217
|
+
});
|
|
218
|
+
if (expectFalseCheckResult) {
|
|
219
|
+
(0, _chai.expect)(result).to.eql(false);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
(0, _chai.expect)(result).to.have.property('headers');
|
|
223
|
+
(0, _chai.expect)(result).to.have.property('records');
|
|
224
|
+
(0, _chai.expect)(result).to.have.property('messages');
|
|
225
|
+
(0, _chai.expect)(result.records.length).to.eql(3);
|
|
226
|
+
(0, _chai.expect)(result.messages.length).to.eql(3);
|
|
227
|
+
const expectedResult = getFixture('expectedResult.json');
|
|
228
|
+
(0, _chai.expect)(result.records).to.eql(expectedResult);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (checkQueueStyle === 'basicNotRecord') {
|
|
232
|
+
const result = await amqpOperator.checkQueue({
|
|
233
|
+
queue,
|
|
234
|
+
style: 'basic',
|
|
235
|
+
toRecord: false,
|
|
236
|
+
purge: false
|
|
237
|
+
});
|
|
238
|
+
if (expectFalseCheckResult) {
|
|
239
|
+
(0, _chai.expect)(result).to.eql(false);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
(0, _chai.expect)(result).to.have.property('headers');
|
|
243
|
+
(0, _chai.expect)(result).to.have.property('messages');
|
|
244
|
+
(0, _chai.expect)(result.messages.length).to.eql(3);
|
|
245
|
+
const [{
|
|
246
|
+
fields
|
|
247
|
+
}] = result.messages;
|
|
248
|
+
(0, _chai.expect)(fields).to.have.property('deliveryTag');
|
|
249
|
+
(0, _chai.expect)(fields).to.have.property('exchange');
|
|
250
|
+
(0, _chai.expect)(fields).to.have.property('messageCount');
|
|
251
|
+
(0, _chai.expect)(fields).to.have.property('redelivered');
|
|
252
|
+
(0, _chai.expect)(fields).to.have.property('routingKey');
|
|
253
|
+
(0, _chai.expect)(typeof fields.deliveryTag).to.be.eql('number');
|
|
254
|
+
(0, _chai.expect)(typeof fields.messageCount).to.be.eql('number');
|
|
255
|
+
(0, _chai.expect)(typeof fields.redelivered).to.be.eql('boolean');
|
|
256
|
+
(0, _chai.expect)(typeof fields.routingKey).to.be.eql('string');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (checkQueueStyle === 'purge') {
|
|
260
|
+
return amqpOperator.checkQueue({
|
|
261
|
+
queue,
|
|
262
|
+
style: 'messages',
|
|
263
|
+
purge: true
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (checkQueueStyle === 'foobar') {
|
|
267
|
+
return amqpOperator.checkQueue({
|
|
268
|
+
queue,
|
|
269
|
+
style: 'foobar',
|
|
270
|
+
toRecord: false,
|
|
271
|
+
purge: false
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
async function ackOrNackMessages() {
|
|
277
|
+
if (ackMessages) {
|
|
278
|
+
const message = await amqpOperator.consumeOne(testData.queue, false);
|
|
279
|
+
await amqpOperator.ackMessages([message]);
|
|
280
|
+
return setTimeoutPromise(10);
|
|
281
|
+
}
|
|
282
|
+
if (nackMessages) {
|
|
283
|
+
const message = await amqpOperator.consumeOne(testData.queue, false);
|
|
284
|
+
await amqpOperator.nackMessages([message]);
|
|
285
|
+
return setTimeoutPromise(10);
|
|
286
|
+
}
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
async function sendMessagesToQueue() {
|
|
290
|
+
if (sentToQueue) {
|
|
291
|
+
const messages = getFixture('input.json');
|
|
292
|
+
// {queue, correlationId, headers, data}
|
|
293
|
+
|
|
294
|
+
const promises = messages.map(message => amqpOperator.sendToQueue(message));
|
|
295
|
+
await Promise.all(promises);
|
|
296
|
+
return setTimeoutPromise(10);
|
|
297
|
+
}
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/*
|
|
303
|
+
function testHeathCheck() {
|
|
304
|
+
return it('expects healthCheck', async () => {
|
|
305
|
+
|
|
306
|
+
const amqpOperator2 = await amqpFactory(amqpUrl, true);
|
|
307
|
+
try {
|
|
308
|
+
|
|
309
|
+
debug(`**********`);
|
|
310
|
+
await testHealthCheckLoopWorking(amqpOperator2);
|
|
311
|
+
|
|
312
|
+
debug(`**********`);
|
|
313
|
+
await testHealthCheckLoopErroring(amqpOperator2);
|
|
314
|
+
} catch (error) {
|
|
315
|
+
debug(error);
|
|
316
|
+
expect(error).to.eql('');
|
|
317
|
+
} finally {
|
|
318
|
+
amqpOperator2.closeConnection();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function testHealthCheckLoopWorking(amqpOperator) {
|
|
322
|
+
debug(`Testing healthCheckLoop for ${amqpOperator}`);
|
|
323
|
+
debug(`Waiting 0.5s and expecting healthCheckLoop to work`);
|
|
324
|
+
await setTimeoutPromise('500');
|
|
325
|
+
debug(`Amqp Operator should have been alive.`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function testHealthCheckLoopErroring(amqpOperator) {
|
|
329
|
+
debug(`Testing healthCheckLoop with closed channel`);
|
|
330
|
+
amqpOperator.closeChannel();
|
|
331
|
+
debug(`Waiting 0.5s and expecting healthCheckLoop to throw error`);
|
|
332
|
+
await setTimeoutPromise('500');
|
|
333
|
+
debug(`amqpOperator should have errored`);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
*/
|
|
338
|
+
//# sourceMappingURL=amqp.tests.spec.js.map
|