@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 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 EventEmitterCl {
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
- const topicsFile = path.join(__dirname, '/.topics.json');
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
- log.debug('Update .topics.json file');
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
- const myIgnore = [
655
+ getWorkflowFunctions(inIgnore) {
656
+ let myIgnore = [
644
657
  'subscribeAvroWithSubscriber',
645
658
  'subscribeWithSubscriber'
646
659
  ];
647
-
648
- const myfunctions = this.getAllFunctions();
649
- const wffunctions = [];
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 wffunctions;
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.5.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);