@itentialopensource/adapter-kafkav2 0.5.0 → 0.6.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/CHANGELOG.md +16 -0
- package/README.md +10 -0
- package/adapter.js +49 -56
- package/adapterBase.js +129 -0
- package/package.json +2 -1
- package/refs?service=git-upload-pack +0 -0
- package/test/unit/adapterBaseTestUnit.js +239 -0
- package/test/unit/adapterTestUnit.js +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
|
|
2
|
+
## 0.6.1 [05-04-2023]
|
|
3
|
+
|
|
4
|
+
* added support for separate topics files per adapter
|
|
5
|
+
|
|
6
|
+
See merge request itentialopensource/adapters/notification-messaging/adapter-kafkav2!5
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0.6.0 [04-10-2023]
|
|
11
|
+
|
|
12
|
+
* Turn Off stream if WFE or OpMgr are down
|
|
13
|
+
|
|
14
|
+
See merge request itentialopensource/adapters/notification-messaging/adapter-kafkav2!4
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
2
18
|
## 0.5.0 [03-13-2023]
|
|
3
19
|
|
|
4
20
|
* minor/adapt-2595
|
package/README.md
CHANGED
|
@@ -87,6 +87,10 @@ This section defines **all** the properties that are available for the adapter,
|
|
|
87
87
|
"stub": false,
|
|
88
88
|
"parseMessage": true,
|
|
89
89
|
"wrapMessage": "myKey",
|
|
90
|
+
"check_iap_apps": true,
|
|
91
|
+
"check_wfe_status": true,
|
|
92
|
+
"check_ops_manager_status": false,
|
|
93
|
+
"iap_apps_check_interval": 15000,
|
|
90
94
|
"client": {
|
|
91
95
|
"connectTimeout": 10000,
|
|
92
96
|
"requestTimeout": 30000,
|
|
@@ -272,6 +276,12 @@ The following properties are used to define the Kafka Consumer. These properties
|
|
|
272
276
|
|
|
273
277
|
The `parseMessage` property allows the user to define how they want the Kafka message to be published to IAP's event system. If `parseMessage` is set to true or omitted, the value of the Kafka message will be parsed as either an object or string and wrapped in an outer object. The wrapper object's key can be defined with the property `wrapMessage`, or the default value `payload` can be used if omitted. If `parseMessage` is set to false, the entire kafka payload, including metadata, would be returned and the message itself would need to be transformed at a later point.
|
|
274
278
|
|
|
279
|
+
## Turning off stream if WorkflowEngine or OperationsManager is down
|
|
280
|
+
|
|
281
|
+
`check_iap_apps` (boolean) and `iap_apps_check_interval` (integer) are used when the user wants to turn off stream if WorkflowEngine or OperationsManager is down. If `check_iap_apps` is set to true, by default, the adapter will check the status of both WorkflowEngine and OperationsManager at a defined interval. If any IAP apps are down, the consumer will be paused until the apps are active again. If the user does not want to healthcheck OperationsManager, set `check_ops_manager_status` to false. Similarly, if the user does not want to check WorkflowEngine status, set `check_wfe_status` to false.
|
|
282
|
+
|
|
283
|
+
`iap_apps_check_interval` (default 30000ms - 30s) allows the user to set the frequency in which to run IAP app healtcheck.
|
|
284
|
+
|
|
275
285
|
## Testing an Itential Product Adapter
|
|
276
286
|
|
|
277
287
|
Mocha is generally used to test all Itential Product Adapters. There are unit tests as well as integration tests performed. Integration tests can generally be run as standalone using mock data and running the adapter in stub mode, or as integrated. When running integrated, every effort is made to prevent environmental failures, however there is still a possibility.
|
package/adapter.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// Set globals
|
|
4
4
|
/* global eventSystem log */
|
|
5
|
+
/* global cogs */
|
|
5
6
|
/* eslint no-underscore-dangle: warn */
|
|
6
7
|
/* eslint no-loop-func: warn */
|
|
7
8
|
/* eslint no-cond-assign: warn */
|
|
@@ -16,7 +17,8 @@ const fs = require('fs-extra');
|
|
|
16
17
|
const path = require('path');
|
|
17
18
|
const util = require('util');
|
|
18
19
|
/* Fetch in the other needed components for the this Adaptor */
|
|
19
|
-
const EventEmitterCl = require('events').EventEmitter;
|
|
20
|
+
// const EventEmitterCl = require('events').EventEmitter;
|
|
21
|
+
const AdapterBaseCl = require(path.join(__dirname, 'adapterBase.js'));
|
|
20
22
|
const request = require('request');
|
|
21
23
|
|
|
22
24
|
function consoleLoggerProvider(name) {
|
|
@@ -160,13 +162,13 @@ function formatErrorObject(origin, type, variables, sysCode, sysRes, stack) {
|
|
|
160
162
|
/**
|
|
161
163
|
* This is the adapter/interface into Kafka
|
|
162
164
|
*/
|
|
163
|
-
class Kafkav2 extends
|
|
165
|
+
class Kafkav2 extends AdapterBaseCl {
|
|
164
166
|
/**
|
|
165
167
|
* Kafka Adapter
|
|
166
168
|
* @constructor
|
|
167
169
|
*/
|
|
168
170
|
constructor(prongid, properties) {
|
|
169
|
-
super();
|
|
171
|
+
super(prongid, properties);
|
|
170
172
|
|
|
171
173
|
this.props = properties;
|
|
172
174
|
this.alive = false;
|
|
@@ -176,11 +178,15 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
176
178
|
|
|
177
179
|
// put topics from file into memory
|
|
178
180
|
this.topicsEvents = [];
|
|
179
|
-
|
|
181
|
+
let topicsFile = path.join(__dirname, `/.topics-${this.id}.json`);
|
|
180
182
|
|
|
181
183
|
// if the file does not exist - error
|
|
182
184
|
if (fs.existsSync(topicsFile)) {
|
|
183
185
|
this.topicsEvents = JSON.parse(fs.readFileSync(topicsFile, 'utf-8'));
|
|
186
|
+
} else if (fs.existsSync(path.join(__dirname, '/.topics.json'))) {
|
|
187
|
+
log.debug('Found old .topics.json file.');
|
|
188
|
+
topicsFile = path.join(__dirname, '/.topics.json');
|
|
189
|
+
this.topicsEvents = JSON.parse(fs.readFileSync(topicsFile, 'utf-8'));
|
|
184
190
|
}
|
|
185
191
|
|
|
186
192
|
// get the topics into the right format --- fix older .topics.json files so they have the right format
|
|
@@ -393,7 +399,8 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
393
399
|
const intTime = this.props.interval_time || 30000;
|
|
394
400
|
setInterval(() => {
|
|
395
401
|
try {
|
|
396
|
-
|
|
402
|
+
const split = topicsFile.split('/');
|
|
403
|
+
log.debug(`Update ${split[split.length - 1]} file.`);
|
|
397
404
|
fs.writeFileSync(topicsFile, JSON.stringify(this.topicsEvents, null, 2));
|
|
398
405
|
} catch (err) {
|
|
399
406
|
log.error(err);
|
|
@@ -466,6 +473,36 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
466
473
|
}
|
|
467
474
|
await this.consumer.connect();
|
|
468
475
|
await this.consumer.subscribe({ topics, fromBeginning: true });
|
|
476
|
+
|
|
477
|
+
let isAppActive = null;
|
|
478
|
+
const topicPartitions = topics.map((topic) => ({ topic }));
|
|
479
|
+
|
|
480
|
+
// if any IAP apps are down, pause consumer before it consumes any messages
|
|
481
|
+
if (this.props && this.props.check_iap_apps) {
|
|
482
|
+
isAppActive = await super.checkIapAppsStatus();
|
|
483
|
+
if (!isAppActive) {
|
|
484
|
+
log.debug('Pause consumer since IAP apps are down');
|
|
485
|
+
// wait for the consumer to connect to Kafka before pausing it
|
|
486
|
+
this.consumer.on(this.consumer.events.CONNECT, async () => {
|
|
487
|
+
this.consumer.pause(topicPartitions);
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// keep checking IAP apps status
|
|
493
|
+
if (this.props && this.props.check_iap_apps) {
|
|
494
|
+
const intTime = this.props.iap_apps_check_interval || 30000;
|
|
495
|
+
setInterval(async () => {
|
|
496
|
+
isAppActive = await super.checkIapAppsStatus();
|
|
497
|
+
if (isAppActive) {
|
|
498
|
+
log.debug('Resume consumer since IAP apps are active');
|
|
499
|
+
this.consumer.resume(topicPartitions);
|
|
500
|
+
} else {
|
|
501
|
+
log.debug('Keep pausing consumer until IAP apps are active');
|
|
502
|
+
this.consumer.pause(topicPartitions);
|
|
503
|
+
}
|
|
504
|
+
}, intTime);
|
|
505
|
+
}
|
|
469
506
|
await this.consumer.run({
|
|
470
507
|
eachMessage: async ({ topic, partition, message }) => {
|
|
471
508
|
log.info(`PROCESSING NEW MESSAGE ON TOPIC: ${topic} PARTITION: ${partition} WITH OFFSET: ${message.offset}`);
|
|
@@ -610,67 +647,23 @@ class Kafkav2 extends EventEmitterCl {
|
|
|
610
647
|
return callback(retstatus);
|
|
611
648
|
}
|
|
612
649
|
|
|
613
|
-
/**
|
|
614
|
-
* getAllFunctions is used to get all of the exposed function in the adapter
|
|
615
|
-
*
|
|
616
|
-
* @function getAllFunctions
|
|
617
|
-
*/
|
|
618
|
-
getAllFunctions() {
|
|
619
|
-
let myfunctions = [];
|
|
620
|
-
let obj = this;
|
|
621
|
-
|
|
622
|
-
// find the functions in this class
|
|
623
|
-
do {
|
|
624
|
-
const l = Object.getOwnPropertyNames(obj)
|
|
625
|
-
.concat(Object.getOwnPropertySymbols(obj).map((s) => s.toString()))
|
|
626
|
-
.sort()
|
|
627
|
-
.filter((p, i, arr) => typeof obj[p] === 'function' && p !== 'constructor' && (i === 0 || p !== arr[i - 1]) && myfunctions.indexOf(p) === -1);
|
|
628
|
-
myfunctions = myfunctions.concat(l);
|
|
629
|
-
}
|
|
630
|
-
while (
|
|
631
|
-
(obj = Object.getPrototypeOf(obj)) && Object.getPrototypeOf(obj)
|
|
632
|
-
);
|
|
633
|
-
|
|
634
|
-
return myfunctions;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
650
|
/**
|
|
638
651
|
* getWorkflowFunctions is used to get all of the workflow function in the adapter
|
|
639
652
|
*
|
|
640
653
|
* @function getWorkflowFunctions
|
|
641
654
|
*/
|
|
642
|
-
getWorkflowFunctions() {
|
|
643
|
-
|
|
655
|
+
getWorkflowFunctions(inIgnore) {
|
|
656
|
+
let myIgnore = [
|
|
644
657
|
'subscribeAvroWithSubscriber',
|
|
645
658
|
'subscribeWithSubscriber'
|
|
646
659
|
];
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
// remove the functions that should not be in a Workflow
|
|
652
|
-
for (let m = 0; m < myfunctions.length; m += 1) {
|
|
653
|
-
if (myfunctions[m] === 'addListener') {
|
|
654
|
-
// got to the second tier (adapterBase)
|
|
655
|
-
break;
|
|
656
|
-
}
|
|
657
|
-
if (myfunctions[m] !== 'connect' && myfunctions[m] !== 'healthCheck'
|
|
658
|
-
&& myfunctions[m] !== 'getAllFunctions' && myfunctions[m] !== 'getWorkflowFunctions') {
|
|
659
|
-
let found = false;
|
|
660
|
-
if (myIgnore && Array.isArray(myIgnore)) {
|
|
661
|
-
for (let i = 0; i < myIgnore.length; i += 1) {
|
|
662
|
-
if (myfunctions[m].toUpperCase() === myIgnore[i].toUpperCase()) {
|
|
663
|
-
found = true;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
if (!found) {
|
|
668
|
-
wffunctions.push(myfunctions[m]);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
660
|
+
if (!inIgnore && Array.isArray(inIgnore)) {
|
|
661
|
+
myIgnore = inIgnore;
|
|
662
|
+
} else if (!inIgnore && typeof inIgnore === 'string') {
|
|
663
|
+
myIgnore = [inIgnore];
|
|
671
664
|
}
|
|
672
665
|
|
|
673
|
-
return
|
|
666
|
+
return super.getWorkflowFunctions(myIgnore);
|
|
674
667
|
}
|
|
675
668
|
|
|
676
669
|
/**
|
package/adapterBase.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/* @copyright Itential, LLC 2019 (pre-modifications) */
|
|
2
|
+
|
|
3
|
+
// Set globals
|
|
4
|
+
/* global eventSystem log */
|
|
5
|
+
/* global cogs */
|
|
6
|
+
/* eslint no-underscore-dangle: warn */
|
|
7
|
+
/* eslint no-loop-func: warn */
|
|
8
|
+
/* eslint no-cond-assign: warn */
|
|
9
|
+
/* eslint no-unused-vars: warn */
|
|
10
|
+
/* eslint consistent-return: warn */
|
|
11
|
+
/* eslint import/no-dynamic-require: warn */
|
|
12
|
+
/* eslint global-require: warn */
|
|
13
|
+
/* eslint no-await-in-loop: warn */
|
|
14
|
+
|
|
15
|
+
/* Required libraries. */
|
|
16
|
+
const EventEmitterCl = require('events').EventEmitter;
|
|
17
|
+
|
|
18
|
+
class AdapterBase extends EventEmitterCl {
|
|
19
|
+
constructor(prongid, properties) {
|
|
20
|
+
super();
|
|
21
|
+
|
|
22
|
+
this.props = properties;
|
|
23
|
+
this.alive = false;
|
|
24
|
+
this.healthy = false;
|
|
25
|
+
this.id = prongid;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* getAllFunctions is used to get all of the exposed function in the adapter
|
|
30
|
+
*
|
|
31
|
+
* @function getAllFunctions
|
|
32
|
+
*/
|
|
33
|
+
getAllFunctions() {
|
|
34
|
+
let myfunctions = [];
|
|
35
|
+
let obj = this;
|
|
36
|
+
|
|
37
|
+
// find the functions in this class
|
|
38
|
+
do {
|
|
39
|
+
const l = Object.getOwnPropertyNames(obj)
|
|
40
|
+
.concat(Object.getOwnPropertySymbols(obj).map((s) => s.toString()))
|
|
41
|
+
.sort()
|
|
42
|
+
.filter((p, i, arr) => typeof obj[p] === 'function' && p !== 'constructor' && (i === 0 || p !== arr[i - 1]) && myfunctions.indexOf(p) === -1);
|
|
43
|
+
myfunctions = myfunctions.concat(l);
|
|
44
|
+
}
|
|
45
|
+
while (
|
|
46
|
+
(obj = Object.getPrototypeOf(obj)) && Object.getPrototypeOf(obj)
|
|
47
|
+
);
|
|
48
|
+
return myfunctions;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* getWorkflowFunctions is used to get all of the workflow function in the adapter
|
|
53
|
+
*
|
|
54
|
+
* @function getWorkflowFunctions
|
|
55
|
+
*/
|
|
56
|
+
getWorkflowFunctions(ignoreThes) {
|
|
57
|
+
const myfunctions = this.getAllFunctions();
|
|
58
|
+
const wffunctions = [];
|
|
59
|
+
// remove the functions that should not be in a Workflow
|
|
60
|
+
for (let m = 0; m < myfunctions.length; m += 1) {
|
|
61
|
+
if (myfunctions[m] === 'checkIapAppsStatus') {
|
|
62
|
+
// got to the second tier (adapterBase)
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
if (myfunctions[m] !== 'connect' && myfunctions[m] !== 'healthCheck'
|
|
66
|
+
&& myfunctions[m] !== 'getAllFunctions' && myfunctions[m] !== 'getWorkflowFunctions') {
|
|
67
|
+
let found = false;
|
|
68
|
+
if (ignoreThes && Array.isArray(ignoreThes)) {
|
|
69
|
+
for (let i = 0; i < ignoreThes.length; i += 1) {
|
|
70
|
+
if (myfunctions[m].toUpperCase() === ignoreThes[i].toUpperCase()) {
|
|
71
|
+
found = true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!found) {
|
|
76
|
+
wffunctions.push(myfunctions[m]);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return wffunctions;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @summary checkIapAppsStatus is used to check if any IAP apps are down.
|
|
85
|
+
*
|
|
86
|
+
* @function checkIapAppsStatus
|
|
87
|
+
*/
|
|
88
|
+
async checkIapAppsStatus() {
|
|
89
|
+
const origin = `${this.id}-adapterBase-checkIapAppsStatus`;
|
|
90
|
+
log.trace(origin);
|
|
91
|
+
|
|
92
|
+
let wfEngineActive = true;
|
|
93
|
+
let opManagerActive = true;
|
|
94
|
+
if (this.props && (this.props.check_wfe_status || this.props.check_wfe_status === undefined)
|
|
95
|
+
&& cogs.WorkFlowEngine && cogs.WorkFlowEngine.isActive) {
|
|
96
|
+
wfEngineActive = await new Promise((resolve, reject) => {
|
|
97
|
+
cogs.WorkFlowEngine.isActive((data, error) => {
|
|
98
|
+
if (error || !data) {
|
|
99
|
+
reject(error);
|
|
100
|
+
} else {
|
|
101
|
+
resolve(true);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}).catch((error) => {
|
|
105
|
+
log.error(error);
|
|
106
|
+
return false;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (this.props && (this.props.check_ops_manager_status || this.props.check_ops_manager_status === undefined)
|
|
111
|
+
&& cogs.OperationsManager && cogs.OperationsManager.getTriggers) {
|
|
112
|
+
opManagerActive = await new Promise((resolve, reject) => {
|
|
113
|
+
cogs.OperationsManager.getTriggers({}, (data, error) => {
|
|
114
|
+
if (error || !data) {
|
|
115
|
+
reject(error);
|
|
116
|
+
} else {
|
|
117
|
+
resolve(true);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}).catch((error) => {
|
|
121
|
+
log.error(error);
|
|
122
|
+
return false;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return wfEngineActive && opManagerActive;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = AdapterBase;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itentialopensource/adapter-kafkav2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Itential adapter to connect to kafka",
|
|
5
5
|
"main": "adapter.js",
|
|
6
6
|
"wizardVersion": "2.35.0",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"preinstall": "node utils/setup.js && npm install --package-lock-only --ignore-scripts && npx npm-force-resolutions",
|
|
11
11
|
"lint": "eslint . --ext .json --ext .js",
|
|
12
12
|
"lint:errors": "node --max_old_space_size=4096 ./node_modules/eslint/bin/eslint.js . --ext .json --ext .js --quiet",
|
|
13
|
+
"test:baseunit": "mocha test/unit/adapterBaseTestUnit.js --LOG=error",
|
|
13
14
|
"test:unit": "mocha test/unit/adapterTestUnit.js --LOG=error",
|
|
14
15
|
"test:integration": "mocha test/integration/adapterTestIntegration.js --LOG=error",
|
|
15
16
|
"test:cover": "nyc --reporter html --reporter text mocha --reporter dot test/*",
|
|
Binary file
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// Set globals
|
|
2
|
+
/* global describe it log pronghornProps */
|
|
3
|
+
/* eslint global-require:warn */
|
|
4
|
+
/* eslint no-unused-vars: warn */
|
|
5
|
+
|
|
6
|
+
// include required items for testing & logging
|
|
7
|
+
const assert = require('assert');
|
|
8
|
+
const fs = require('fs-extra');
|
|
9
|
+
const mocha = require('mocha');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const util = require('util');
|
|
12
|
+
const winston = require('winston');
|
|
13
|
+
const execute = require('child_process').execSync;
|
|
14
|
+
const { expect } = require('chai');
|
|
15
|
+
const { use } = require('chai');
|
|
16
|
+
const td = require('testdouble');
|
|
17
|
+
|
|
18
|
+
const anything = td.matchers.anything();
|
|
19
|
+
|
|
20
|
+
// stub and attemptTimeout are used throughout the code so set them here
|
|
21
|
+
let logLevel = 'none';
|
|
22
|
+
const stub = true;
|
|
23
|
+
const isRapidFail = false;
|
|
24
|
+
const attemptTimeout = 120000;
|
|
25
|
+
|
|
26
|
+
// these variables can be changed to run in integrated mode so easier to set them here
|
|
27
|
+
// always check these in with bogus data!!!
|
|
28
|
+
const host = 'replace.hostorip.here';
|
|
29
|
+
const username = 'username';
|
|
30
|
+
const password = 'password';
|
|
31
|
+
const port = 80;
|
|
32
|
+
const sslenable = false;
|
|
33
|
+
const sslinvalid = false;
|
|
34
|
+
|
|
35
|
+
// these are the adapter properties. You generally should not need to alter
|
|
36
|
+
// any of these after they are initially set up
|
|
37
|
+
global.pronghornProps = {
|
|
38
|
+
pathProps: {
|
|
39
|
+
encrypted: false
|
|
40
|
+
},
|
|
41
|
+
adapterProps: {
|
|
42
|
+
adapters: [{
|
|
43
|
+
id: 'Test-kafkav2',
|
|
44
|
+
type: 'Kafkav2',
|
|
45
|
+
interval_time: 5000,
|
|
46
|
+
stub: true,
|
|
47
|
+
properties: {
|
|
48
|
+
topics: []
|
|
49
|
+
}
|
|
50
|
+
}]
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
global.$HOME = `${__dirname}/../..`;
|
|
55
|
+
|
|
56
|
+
// set the log levels that Pronghorn uses, spam and trace are not defaulted in so without
|
|
57
|
+
// this you may error on log.trace calls.
|
|
58
|
+
const myCustomLevels = {
|
|
59
|
+
levels: {
|
|
60
|
+
spam: 6,
|
|
61
|
+
trace: 5,
|
|
62
|
+
debug: 4,
|
|
63
|
+
info: 3,
|
|
64
|
+
warn: 2,
|
|
65
|
+
error: 1,
|
|
66
|
+
none: 0
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// need to see if there is a log level passed in
|
|
71
|
+
process.argv.forEach((val) => {
|
|
72
|
+
// is there a log level defined to be passed in?
|
|
73
|
+
if (val.indexOf('--LOG') === 0) {
|
|
74
|
+
// get the desired log level
|
|
75
|
+
const inputVal = val.split('=')[1];
|
|
76
|
+
|
|
77
|
+
// validate the log level is supported, if so set it
|
|
78
|
+
if (Object.hasOwnProperty.call(myCustomLevels.levels, inputVal)) {
|
|
79
|
+
logLevel = inputVal;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// need to set global logging
|
|
85
|
+
global.log = winston.createLogger({
|
|
86
|
+
level: logLevel,
|
|
87
|
+
levels: myCustomLevels.levels,
|
|
88
|
+
transports: [
|
|
89
|
+
new winston.transports.Console()
|
|
90
|
+
]
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Runs the error asserts for the test
|
|
95
|
+
*/
|
|
96
|
+
function runErrorAsserts(data, error, code, origin, displayStr) {
|
|
97
|
+
assert.equal(null, data);
|
|
98
|
+
assert.notEqual(undefined, error);
|
|
99
|
+
assert.notEqual(null, error);
|
|
100
|
+
assert.notEqual(undefined, error.IAPerror);
|
|
101
|
+
assert.notEqual(null, error.IAPerror);
|
|
102
|
+
assert.notEqual(undefined, error.IAPerror.displayString);
|
|
103
|
+
assert.notEqual(null, error.IAPerror.displayString);
|
|
104
|
+
assert.equal(code, error.icode);
|
|
105
|
+
assert.equal(origin, error.IAPerror.origin);
|
|
106
|
+
assert.equal(displayStr, error.IAPerror.displayString);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// require the adapter that we are going to be using
|
|
110
|
+
const AdapterBase = require('../../adapterBase');
|
|
111
|
+
|
|
112
|
+
// delete the .DS_Store directory in entities -- otherwise this will cause errors
|
|
113
|
+
const dirPath = path.join(__dirname, '../../entities/.DS_Store');
|
|
114
|
+
if (fs.existsSync(dirPath)) {
|
|
115
|
+
try {
|
|
116
|
+
fs.removeSync(dirPath);
|
|
117
|
+
console.log('.DS_Store deleted');
|
|
118
|
+
} catch (e) {
|
|
119
|
+
console.log('Error when deleting .DS_Store:', e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
describe('[unit] Adapter Base Test', () => {
|
|
124
|
+
describe('Adapter Base Class Tests', () => {
|
|
125
|
+
const a = new AdapterBase(
|
|
126
|
+
pronghornProps.adapterProps.adapters[0].id,
|
|
127
|
+
pronghornProps.adapterProps.adapters[0].properties
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
if (isRapidFail) {
|
|
131
|
+
const state = {};
|
|
132
|
+
state.passed = true;
|
|
133
|
+
|
|
134
|
+
mocha.afterEach(function x() {
|
|
135
|
+
state.passed = state.passed
|
|
136
|
+
&& (this.currentTest.state === 'passed');
|
|
137
|
+
});
|
|
138
|
+
mocha.beforeEach(function x() {
|
|
139
|
+
if (!state.passed) {
|
|
140
|
+
return this.currentTest.skip();
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
describe('#class instance created', () => {
|
|
147
|
+
it('should be a class with properties', (done) => {
|
|
148
|
+
assert.notEqual(null, a);
|
|
149
|
+
assert.notEqual(undefined, a);
|
|
150
|
+
const check = global.pronghornProps.adapterProps.adapters[0].id;
|
|
151
|
+
assert.equal(check, a.id);
|
|
152
|
+
done();
|
|
153
|
+
}).timeout(attemptTimeout);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('adapterBase.js', () => {
|
|
157
|
+
it('should have an adapterBase.js', (done) => {
|
|
158
|
+
try {
|
|
159
|
+
fs.exists('adapterBase.js', (val) => {
|
|
160
|
+
assert.equal(true, val);
|
|
161
|
+
done();
|
|
162
|
+
});
|
|
163
|
+
} catch (error) {
|
|
164
|
+
log.error(`Test Failure: ${error}`);
|
|
165
|
+
done(error);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('#getAllFunctions', () => {
|
|
171
|
+
it('should have a getAllFunctions function', (done) => {
|
|
172
|
+
try {
|
|
173
|
+
assert.equal(true, typeof a.getAllFunctions === 'function');
|
|
174
|
+
done();
|
|
175
|
+
} catch (error) {
|
|
176
|
+
log.error(`Test Failure: ${error}`);
|
|
177
|
+
done(error);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
it('should return a list of functions', (done) => {
|
|
181
|
+
const returnedFunctions = ['checkIapAppsStatus', 'getAllFunctions', 'getWorkflowFunctions', 'addListener', 'emit', 'eventNames', 'getMaxListeners',
|
|
182
|
+
'listenerCount', 'listeners', 'off', 'on', 'once', 'prependListener', 'prependOnceListener', 'rawListeners', 'removeAllListeners',
|
|
183
|
+
'removeListener', 'setMaxListeners'];
|
|
184
|
+
try {
|
|
185
|
+
const expectedFunctions = a.getAllFunctions();
|
|
186
|
+
try {
|
|
187
|
+
assert.equal(JSON.stringify(expectedFunctions), JSON.stringify(returnedFunctions));
|
|
188
|
+
done();
|
|
189
|
+
} catch (err) {
|
|
190
|
+
log.error(`Test Failure: ${err}`);
|
|
191
|
+
done(err);
|
|
192
|
+
}
|
|
193
|
+
} catch (error) {
|
|
194
|
+
log.error(`Adapter Exception: ${error}`);
|
|
195
|
+
done(error);
|
|
196
|
+
}
|
|
197
|
+
}).timeout(attemptTimeout);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('#getWorkflowFunctions', () => {
|
|
201
|
+
it('should have a getWorkflowFunctions function', (done) => {
|
|
202
|
+
try {
|
|
203
|
+
assert.equal(true, typeof a.getWorkflowFunctions === 'function');
|
|
204
|
+
done();
|
|
205
|
+
} catch (error) {
|
|
206
|
+
log.error(`Test Failure: ${error}`);
|
|
207
|
+
done(error);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
it('should retrieve workflow functions', (done) => {
|
|
211
|
+
try {
|
|
212
|
+
const expectedFunctions = a.getWorkflowFunctions([]);
|
|
213
|
+
try {
|
|
214
|
+
assert.equal(0, expectedFunctions.length);
|
|
215
|
+
done();
|
|
216
|
+
} catch (err) {
|
|
217
|
+
log.error(`Test Failure: ${err}`);
|
|
218
|
+
done(err);
|
|
219
|
+
}
|
|
220
|
+
} catch (error) {
|
|
221
|
+
log.error(`Adapter Exception: ${error}`);
|
|
222
|
+
done(error);
|
|
223
|
+
}
|
|
224
|
+
}).timeout(attemptTimeout);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe('#checkIapAppsStatus', () => {
|
|
228
|
+
it('should have a checkIapAppsStatus function', (done) => {
|
|
229
|
+
try {
|
|
230
|
+
assert.equal(true, typeof a.checkIapAppsStatus === 'function');
|
|
231
|
+
done();
|
|
232
|
+
} catch (error) {
|
|
233
|
+
log.error(`Test Failure: ${error}`);
|
|
234
|
+
done(error);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
@@ -156,10 +156,24 @@ describe('[unit] Kafka Adapter Test', () => {
|
|
|
156
156
|
}).timeout(attemptTimeout);
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
+
describe('adapterBase.js', () => {
|
|
160
|
+
it('should have an adapterBase.js', (done) => {
|
|
161
|
+
try {
|
|
162
|
+
fs.exists('adapterBase.js', (val) => {
|
|
163
|
+
assert.equal(true, val);
|
|
164
|
+
done();
|
|
165
|
+
});
|
|
166
|
+
} catch (error) {
|
|
167
|
+
log.error(`Test Failure: ${error}`);
|
|
168
|
+
done(error);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
159
173
|
let wffunctions = [];
|
|
160
174
|
describe('#getWorkflowFunctions', () => {
|
|
161
175
|
it('should retrieve workflow functions', (done) => {
|
|
162
|
-
wffunctions = a.getWorkflowFunctions();
|
|
176
|
+
wffunctions = a.getWorkflowFunctions([]);
|
|
163
177
|
assert.notEqual(0, wffunctions.length);
|
|
164
178
|
done();
|
|
165
179
|
}).timeout(attemptTimeout);
|