diff --git a/lib/iprod.js b/lib/iprod.js
index 26061fb1..afc673b7 100644
--- a/lib/iprod.js
+++ b/lib/iprod.js
@@ -168,20 +168,25 @@ class iProd {
];
if(!cb) { // If we do not get the third param,
if(option) { // If we get two params,
- if(xt.getClass(option) == "Function") // If it is a function,
+ if(xt.getClass(option) == "Function"){ // If it is a function,
cb = option; // then it is the callback.
+ option = "0000";
+ }
}
else { // If we have only one param,
option = "0000"; // then use *BASE as default.
}
}
- if(option < 0 || option > 99)
- option = "0000";
- else if(option < 10)
- option = "000" + option;
- else option = "00" + option;
-
+ if(Number.isInteger(option)) {
+ if(option < 0 || option > 99)
+ option = "0000";
+ else if(option < 10)
+ option = "000" + option;
+ else
+ option = "00" + option;
+ }
+
let ProdInfo = [
[prodID, "7A"],
["*ONLY", "6A"],
diff --git a/lib/itoolkit.js b/lib/itoolkit.js
index dda604e3..594b2135 100644
--- a/lib/itoolkit.js
+++ b/lib/itoolkit.js
@@ -137,8 +137,14 @@ const xmlToJson = (xml) => {
let sucFlag = sqlData[i].match(successReg);
if(sucFlag && sucFlag.length > 0) {
rs.success = true;
- if(sucFlag.length > 1)
- rs.stmt = sucFlag[1];
+ if(sucFlag.length > 1){
+ if(sucFlag[0].includes('![CDATA')){
+ let fixed = sucFlag[1].replace(/]]>/, '');
+ rs.stmt = fixed;
+ } else{
+ rs.stmt = sucFlag[1];
+ }
+ }
}
else {
rs.success = false;
@@ -224,7 +230,7 @@ class iConn {
}
// setTimeout() override the default timeout value for sync mode.
setTimeout(seconds) {
- if(__getClass(flag) == "Number")
+ if(__getClass(seconds) == "Number")
this.timeout = seconds * 1000;
}
// debug() get current verbose mode or enable/disable verbose mode for debugging.
@@ -535,11 +541,14 @@ class iSql {
}
rowCount(options) {
- this.xml += i_xml.iXmlNodeSqlRowCount(options.action, options.error);
+ if(options && options.error)
+ this.xml += i_xml.iXmlNodeSqlRowCount(options.error);
+ else
+ this.xml += i_xml.iXmlNodeSqlRowCount();
}
count(options) {
- this.xml += i_xml.iXmlNodeSqlRowCount(options.desc, options.error);
+ this.xml += i_xml.iXmlNodeSqlCount(options.desc, options.error);
}
describe(options) {
diff --git a/lib/ixml.js b/lib/ixml.js
index 5954194b..0a93a318 100644
--- a/lib/ixml.js
+++ b/lib/ixml.js
@@ -289,7 +289,7 @@ const iXmlNodeSqlConnect = (db, uid, pwd, option_label) => {
}
const iXmlNodeSqlOptions = (options) => {
- const iXml = iXmlNodeOpen(I_XML_NODE_SQL_OPTIONS_OPEN);
+ let iXml = iXmlNodeOpen(I_XML_NODE_SQL_OPTIONS_OPEN);
for(const i in options)
iXml += iXmlAttrDefault(options[i].desc, options[i].value, I_XML_ATTR_VALUE_OPTIONAL);
return iXml + I_XML_NODE_CLOSE + I_XML_NODE_SQL_OPTIONS_CLOSE;
@@ -332,7 +332,7 @@ const iXmlNodeSqlExecuteClose = () => {
const iXmlNodeSqlParmOpen = (xio) => {
return iXmlNodeOpen(I_XML_NODE_PARM_OPEN)
- + iXmlAttrDefault(I_XML_ATTR_KEY_NAME,xio,I_XML_ATTR_VALUE_OPTIONAL)
+ + iXmlAttrDefault(I_XML_ATTR_KEY_IO,xio,I_XML_ATTR_VALUE_OPTIONAL)
+ I_XML_NODE_CLOSE;
}
diff --git a/lib/utils.js b/lib/utils.js
new file mode 100644
index 00000000..5a1c1e91
--- /dev/null
+++ b/lib/utils.js
@@ -0,0 +1,12 @@
+/* eslint-disable new-cap */
+const { iConn } = require('./itoolkit.js');
+
+function returnTransports(opt) {
+ const transports = [{ name: 'idb', me: new iConn(opt.database, opt.user, opt.password) },
+ { name: 'rest', me: new iConn(opt.database, opt.user, opt.password, opt) },
+ ];
+
+ return transports;
+}
+
+module.exports = { returnTransports };
diff --git a/package.json b/package.json
index 9a40211d..90632104 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,11 @@
],
"devDependencies": {
"chai": "^4.1.2",
+ "mocha": "^5.2.0",
+ "sinon": "^7.2.3"
+ },
+ "optionalDependencies": {
"idb-connector": "^1.1.8",
- "mocha": "^5.2.0"
+ "idb-pconnector": "^1.0.2"
}
}
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 00000000..98d69f51
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,89 @@
+# Node.js Toolkit Tests
+
+Ensure dependencies are installed
+
+From the root of the project run: `npm install`
+
+***NOTE***
+
+Some tests require creating libraries, objects, tables, etc.
+
+A before hook is setup to check for theses objects and create if needed.
+
+These hooks are ran with `idb-pconnector` which requires to be run on IBM i.
+
+In any case, the functional tests test for both transports Db2 and REST.
+
+Using Db2 transport requires `idb-connector` which only runs on IBM i systems.
+
+Tests using these hooks will fail on non IBM i systems.
+
+# Running Tests
+
+From the project root
+
+`npm test test/foo`
+
+where foo is the name of subdir such as `unit` or or individual test file.
+
+***NOTE***
+
+If you experience timeout issue with network calls add
+
+`"test": "./node_modules/mocha/bin/mocha" --timeout Xs `
+
+within `package.json` file, where X is the number of seconds before timeout
+
+# Setup Rest interface
+
+- add to the default apache server conf: `/www/apachedft/conf/httpd.conf`
+
+ ```
+ ScriptAlias /cgi-bin/ /QSYS.LIB/QXMLSERVc .LIB/
+
+ AllowOverride None
+ order allow,deny
+ allow from all
+ SetHandler cgi-script
+ Options +ExecCGI
+
+
+ ```
+
+- start the server
+
+ ` STRTCPSVR SERVER(*HTTP) HTTPSVR(APACHEDFT)`
+
+- go to `http://HOSTNAME/cgi-bin/xmlcgi.pgm`
+
+ you should see an XML document
+
+- when finished testing you can shutdown server with
+
+ ` ENDTCPSVR SERVER(*HTTP) HTTPSVR(APACHEDFT)`
+
+
+# Configuring Tests
+Each functional test contains an config object that is used to create connections
+
+It is recommend to setup environment variables for these configurations
+
+Instead of hard coding credentials with the test file.
+
+you can set environment varaibales with `export KEY='value'`
+
+---
+- user `TKUSER` defaults to ''
+
+- password `TKPASS` defaults to ''
+
+- database `TKDB` defaults to `*LOCAL`
+
+For Rest Tests
+---
+- HOST `TKHOST` defaults to `localhost`
+
+- PORT `TKPORT` defaults to `80`
+
+- PATH `TKPATH` defaults to `/cgi-bin/xmlcgi.pgm`
+
diff --git a/test/functional/commandsFunctional.js b/test/functional/commandsFunctional.js
new file mode 100644
index 00000000..ec9a5407
--- /dev/null
+++ b/test/functional/commandsFunctional.js
@@ -0,0 +1,97 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+
+const { expect } = require('chai');
+const {
+ iCmd, iSh, iQsh, xmlToJson,
+} = require('../../lib/itoolkit');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iSh, iCmd, iQsh, Functional Tests', () => {
+ describe('iCmd()', () => {
+ transports.forEach((transport) => {
+ it(`calls CL command using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+ connection.add(iCmd('RTVJOBA USRLIBL(?) SYSLIBL(?)'));
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('iSh()', () => {
+ transports.forEach((transport) => {
+ it(`calls PASE shell command using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ connection.add(iSh('system -i wrksyssts'));
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ // xs does not return success property for iSh or iQsh
+ // but on error data property = '\n'
+ // so lets base success on contents of data.
+ results.forEach((result) => {
+ expect(result.data).not.to.equal('\n');
+ expect(result.data).to.match(/(System\sStatus\sInformation)/);
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('iQsh()', () => {
+ transports.forEach((transport) => {
+ it(`calls QSH command using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+ connection.add(iQsh('system wrksyssts'));
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ // xs does not return success property for iSh or iQsh
+ // but on error data property = '\n'
+ // so lets base success on contents of data.
+ results.forEach((result) => {
+ expect(result.data).not.to.equal('\n');
+ expect(result.data).to.match(/(System\sStatus\sInformation)/);
+ });
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iDataQueueFunctional.js b/test/functional/iDataQueueFunctional.js
new file mode 100644
index 00000000..e620f8ea
--- /dev/null
+++ b/test/functional/iDataQueueFunctional.js
@@ -0,0 +1,135 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iConn } = require('../../lib/itoolkit');
+const { iDataQueue } = require('../../lib/idataq');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const lib = 'NODETKTEST'; const dqName = 'TESTQ';
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iDataQueue Functional Tests', () => {
+ before('setup library for tests and create DQ', async () => {
+ // eslint-disable-next-line global-require
+ const { DBPool } = require('idb-pconnector');
+
+ const pool = new DBPool({ url: '*LOCAL' }, { incrementSize: 2 });
+
+ const qcmdexec = 'CALL QSYS2.QCMDEXC(?)';
+
+ const createLib = `CRTLIB LIB(${lib}) TYPE(*TEST) TEXT('Used to test Node.js toolkit')`;
+
+ const createDQ = `CRTDTAQ DTAQ(${lib}/${dqName}) MAXLEN(100) AUT(*EXCLUDE) TEXT('TEST DQ FOR NODE TOOLKIT TESTS')`;
+
+ const findLib = 'SELECT SCHEMA_NAME FROM qsys2.sysschemas WHERE SCHEMA_NAME = \'NODETKTEST\'';
+
+ const findDQ = 'SELECT OBJLONGNAME FROM TABLE (QSYS2.OBJECT_STATISTICS(\'NODETKTEST\', \'*DTAQ\')) AS X';
+
+ const libResult = await pool.runSql(findLib);
+
+ const dqResult = await pool.runSql(findDQ);
+
+ if (!libResult.length) {
+ await pool.prepareExecute(qcmdexec, [createLib]).catch((error) => {
+ // eslint-disable-next-line no-console
+ console.log('Unable to Create Lib!');
+ throw error;
+ });
+ // eslint-disable-next-line no-console
+ console.log('CREATED LIB!');
+ }
+ if (!dqResult.length) {
+ await pool.prepareExecute(qcmdexec, [createDQ]).catch((error) => {
+ // eslint-disable-next-line no-console
+ console.log('Unable to Create DQ!');
+ throw error;
+ });
+ // eslint-disable-next-line no-console
+ console.log('CREATED DQ!');
+ }
+ });
+ describe('constructor', () => {
+ it('creates and returns an instance of iDataQueue', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ const dq = new iDataQueue(connection);
+ expect(dq).to.be.instanceOf(iDataQueue);
+ });
+ });
+
+ describe('sendToDataQueue', () => {
+ transports.forEach((transport) => {
+ it(`sends data to specified DQ using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const dq = new iDataQueue(connection);
+
+ dq.sendToDataQueue(dqName, lib, 'Hello from DQ!', (output) => {
+ expect(output).to.equal(true);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('receiveFromDataQueue', () => {
+ transports.forEach((transport) => {
+ it(`receives data from specfied DQ using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const dq = new iDataQueue(connection);
+
+ dq.receiveFromDataQueue(dqName, lib, 100, (output) => {
+ expect(output).to.be.a('string').and.to.equal('Hello from DQ!');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('clearDataQueue', () => {
+ transports.forEach((transport) => {
+ it(`clears the specifed DQ using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const dq = new iDataQueue(connection);
+
+ dq.clearDataQueue(dqName, lib, (output) => {
+ expect(output).to.equal(true);
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iNetworkFunctional.js b/test/functional/iNetworkFunctional.js
new file mode 100644
index 00000000..450623d9
--- /dev/null
+++ b/test/functional/iNetworkFunctional.js
@@ -0,0 +1,156 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iConn } = require('../../lib/itoolkit');
+const { iNetwork } = require('../../lib/inetwork');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iNetwork Functional Tests', () => {
+ describe('constructor', () => {
+ it('creates and returns an instance of iNetwork', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ const net = new iNetwork(connection);
+
+ expect(net).to.be.instanceOf(iNetwork);
+ });
+ });
+
+ describe('getTCPIPAttr', () => {
+ transports.forEach((transport) => {
+ it(`retrieves TCP/IP Attributes using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const net = new iNetwork(connection);
+
+ net.getTCPIPAttr((output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('TCP/IPv4_stack_status');
+ expect(output).to.have.a.property('How_long_active');
+ expect(output).to.have.a.property('When_last_started_-_date');
+ expect(output).to.have.a.property('When_last_started_-_time');
+ expect(output).to.have.a.property('When_last_ended_-_date');
+ expect(output).to.have.a.property('When_last_ended_-_time');
+ expect(output).to.have.a.property('Who_last_started_-_job_name');
+ expect(output).to.have.a.property('Who_last_started_-_job_user_name');
+ expect(output).to.have.a.property('Who_last_started_-_job_number');
+ expect(output).to.have.a.property('Who_last_started_-_internal_job_identifier');
+ expect(output).to.have.a.property('Who_last_ended_-_job_name');
+ expect(output).to.have.a.property('Who_last_ended_-_job_user_name');
+ expect(output).to.have.a.property('Who_last_ended_-_job_number');
+ expect(output).to.have.a.property('Who_last_ended_-_internal_job_identifier');
+ expect(output).to.have.a.property('Offset_to_additional_information');
+ expect(output).to.have.a.property('Length_of_additional_information');
+ expect(output).to.have.a.property('Limited_mode');
+ expect(output).to.have.a.property('Offset_to_list_of_Internet_addresses');
+ expect(output).to.have.a.property('Number_of_Internet_addresses');
+ expect(output).to.have.a.property('Entry_length_for_list_of_Internet_addresses');
+ expect(output).to.have.a.property('DNS_protocol');
+ expect(output).to.have.a.property('Retries');
+ expect(output).to.have.a.property('Time_interval');
+ expect(output).to.have.a.property('Search_order');
+ expect(output).to.have.a.property('Initial_domain_name_server');
+ expect(output).to.have.a.property('DNS_listening_port');
+ expect(output).to.have.a.property('Host_name');
+ expect(output).to.have.a.property('Domain_name');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Domain_search_list');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getNetInterfaceData', () => {
+ transports.forEach((transport) => {
+ it(`retrieves IPv4 network interface info using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const net = new iNetwork(connection);
+
+ net.getNetInterfaceData('127.0.0.1', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Internet_address');
+ expect(output).to.have.a.property('Internet_address_binary');
+ expect(output).to.have.a.property('Network_address');
+ expect(output).to.have.a.property('Network_address_binary');
+ expect(output).to.have.a.property('Line_description');
+ expect(output).to.have.a.property('Interface_status');
+ expect(output).to.have.a.property('Interface_type_of_service');
+ expect(output).to.have.a.property('Interface_MTU');
+ expect(output).to.have.a.property('Interface_line_type');
+ expect(output).to.have.a.property('Host_address');
+ expect(output).to.have.a.property('Host_address_binary');
+ expect(output).to.have.a.property('Interface_subnet_mask');
+ expect(output).to.have.a.property('Interface_subnet_mask_binary');
+ expect(output).to.have.a.property('Directed_broadcast_address');
+ expect(output).to.have.a.property('Directed_broadcast_address_binary');
+ expect(output).to.have.a.property('Change_date');
+ expect(output).to.have.a.property('Change_time');
+ expect(output).to.have.a.property('Associated_local_interface');
+ expect(output).to.have.a.property('Associated_local_interface_binary');
+ expect(output).to.have.a.property('Packet_rules');
+ expect(output).to.have.a.property('Change_status');
+ expect(output).to.have.a.property('Automatic_start');
+ expect(output).to.have.a.property('TRLAN_bit_sequencing');
+ expect(output).to.have.a.property('Interface_type');
+ expect(output).to.have.a.property('Proxy_ARP_allowed');
+ expect(output).to.have.a.property('Proxy_ARP_enabled');
+ expect(output).to.have.a.property('Configured_MTU');
+ expect(output).to.have.a.property('Network_name');
+ expect(output).to.have.a.property('Interface_name');
+ expect(output).to.have.a.property('Alias_name');
+ expect(output).to.have.a.property('Interface_description');
+ expect(output).to.have.a.property('Offset_to_preferred_interface_list');
+ expect(output).to.have.a.property('Number_of_entries_in_preferred_interface_list');
+ expect(output).to.have.a.property('Length_of_one_preferred_interface_list_entry');
+ expect(output).to.have.a.property('DHCP_created');
+ expect(output).to.have.a.property('DHCP_dynamic_DNS_updates');
+ expect(output).to.have.a.property('DHCP_lease_expiration');
+ expect(output).to.have.a.property('DHCP_lease_expiration_-_date');
+ expect(output).to.have.a.property('DHCP_lease_expiration_-_time');
+ expect(output).to.have.a.property('DHCP_lease_obtained');
+ expect(output).to.have.a.property('DHCP_lease_obtained_-_date');
+ expect(output).to.have.a.property('DHCP_lease_obtained_-_time');
+ expect(output).to.have.a.property('Use_DHCP_unique_identifier');
+ expect(output).to.have.a.property('DHCP_server_IP_address');
+ expect(output).to.have.a.property('Preferred_interface_Internet_address');
+ expect(output).to.have.a.property('Preferred_interface_Internet_address_binary');
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iObjFunctional.js b/test/functional/iObjFunctional.js
new file mode 100644
index 00000000..8f1f1846
--- /dev/null
+++ b/test/functional/iObjFunctional.js
@@ -0,0 +1,367 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iConn } = require('../../lib/itoolkit');
+const { iObj } = require('../../lib/iobj');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iObj Functional Tests', () => {
+ describe('constructor', () => {
+ it('creates and returns an instance of iObj', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ const obj = new iObj(connection);
+
+ expect(obj).to.be.instanceOf(iObj);
+ });
+ });
+
+ describe('retrUsrAuth', () => {
+ transports.forEach((transport) => {
+ it(`returns uses's authority for an object using ${transport.name} tranport`, (done) => {
+ const connection = transport.me;
+
+ const obj = new iObj(connection);
+
+ obj.retrUsrAuth('*PUBLIC', '*PGM', 'XMLCGI', 'QXMLSERV', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Object_authority_/_Data_authority');
+ expect(output).to.have.a.property('Authorization_list_management');
+ expect(output).to.have.a.property('Object_operational');
+ expect(output).to.have.a.property('Object_management');
+ expect(output).to.have.a.property('Object_existence');
+ expect(output).to.have.a.property('Data_read');
+ expect(output).to.have.a.property('Data_add');
+ expect(output).to.have.a.property('Data_update');
+ expect(output).to.have.a.property('Data_delete');
+ expect(output).to.have.a.property('Authorization_list');
+ expect(output).to.have.a.property('Authority_source');
+ expect(output).to.have.a.property('Some_adopted_authority');
+ expect(output).to.have.a.property('Adopted_object_authority');
+ expect(output).to.have.a.property('Adopted_authorization_list_management');
+ expect(output).to.have.a.property('Adopted_object_operational');
+ expect(output).to.have.a.property('Adopted_object_management');
+ expect(output).to.have.a.property('Adopted_object_existence');
+ expect(output).to.have.a.property('Adopted_data_read');
+ expect(output).to.have.a.property('Adopted_data_add');
+ expect(output).to.have.a.property('Adopted_data_update');
+ expect(output).to.have.a.property('Adopted_data_delete');
+ expect(output).to.have.a.property('Adopted_data_execute');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Adopted_object_alter');
+ expect(output).to.have.a.property('Adopted_object_reference');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Data_execute');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Object_alter');
+ expect(output).to.have.a.property('Object_reference');
+ expect(output).to.have.a.property('ASP_device_name_of_library');
+ expect(output).to.have.a.property('ASP_device_name_of_object');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Offset_to_group_information_table');
+ expect(output).to.have.a.property('Number_of_group_table_entries_returned');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('rtrCmdInfo', () => {
+ transports.forEach((transport) => {
+ it(`returns command info using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const obj = new iObj(connection);
+
+ obj.retrCmdInfo('CRTLIB', '*LIBL', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Command_name');
+ expect(output).to.have.a.property('Command_library_name');
+ expect(output).to.have.a.property('Command_processing_program_or_proxy_target_command');
+ expect(output).to.have.a.property('Command_processing_program\'s_or_proxy_target_command\'s_library_name');
+ expect(output).to.have.a.property('Source_file_name');
+ expect(output).to.have.a.property('Source_file_library_name');
+ expect(output).to.have.a.property('Source_file_member_name');
+ expect(output).to.have.a.property('Validity_check_program_name');
+ expect(output).to.have.a.property('Validity_check_program_library_name');
+ expect(output).to.have.a.property('Mode_information');
+ expect(output).to.have.a.property('Where_allowed_to_run');
+ expect(output).to.have.a.property('Allow_limited_user');
+ expect(output).to.have.a.property('Maximum_positional_parameters');
+ expect(output).to.have.a.property('Prompt_message_file_name');
+ expect(output).to.have.a.property('Prompt_message_file_library_name');
+ expect(output).to.have.a.property('Message_file_name');
+ expect(output).to.have.a.property('Message_file_library_name');
+ expect(output).to.have.a.property('Help_panel_group_name');
+ expect(output).to.have.a.property('Help_panel_group_library_name');
+ expect(output).to.have.a.property('Help_identifier');
+ expect(output).to.have.a.property('Search_index_name');
+ expect(output).to.have.a.property('Search_index_library_name');
+ expect(output).to.have.a.property('Current_library');
+ expect(output).to.have.a.property('Product_library');
+ expect(output).to.have.a.property('Prompt_override_program_name');
+ expect(output).to.have.a.property('Prompt_override_program_library_name');
+ expect(output).to.have.a.property('Restricted_to_target_release');
+ expect(output).to.have.a.property('Text_description');
+ expect(output).to.have.a.property('Command_processing_program_call_state');
+ expect(output).to.have.a.property('Validity_check_program_call_state');
+ expect(output).to.have.a.property('Prompt_override_program_call_state');
+ expect(output).to.have.a.property('Offset_to_help_bookshelf_information');
+ expect(output).to.have.a.property('Length_of_help_bookshelf_information');
+ expect(output).to.have.a.property('Coded_character_set_ID_(CCSID)');
+ expect(output).to.have.a.property('Enabled_for_GUI_indicator');
+ expect(output).to.have.a.property('Threadsafe_indicator');
+ expect(output).to.have.a.property('Multithreaded_job_action');
+ expect(output).to.have.a.property('Proxy_command_indicator');
+ expect(output).to.have.a.property('Prompt_message_file_text_indicator');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('retrPgmInfo', () => {
+ transports.forEach((transport) => {
+ it(`returns program info using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const obj = new iObj(connection);
+
+ obj.retrPgmInfo('XMLCGI', 'QXMLSERV', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Program_name');
+ expect(output).to.have.a.property('Program_library_name');
+ expect(output).to.have.a.property('Program_owner');
+ expect(output).to.have.a.property('Program_attribute');
+ expect(output).to.have.a.property('Creation_date_and_time');
+ expect(output).to.have.a.property('Source_file_name');
+ expect(output).to.have.a.property('Source_file_library_name');
+ expect(output).to.have.a.property('Source_file_member_name');
+ expect(output).to.have.a.property('Source_file_updated_date_and_time');
+ expect(output).to.have.a.property('Observable_information');
+ expect(output).to.have.a.property('User_profile_option');
+ expect(output).to.have.a.property('Use_adopted_authority');
+ expect(output).to.have.a.property('Log_commands');
+ expect(output).to.have.a.property('Allow_RTVCLSRC');
+ expect(output).to.have.a.property('Fix_decimal_data');
+ expect(output).to.have.a.property('Text_description');
+ expect(output).to.have.a.property('Type_of_program');
+ expect(output).to.have.a.property('Teraspace_storage-enabled_program');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Minimum_number_of_parameters');
+ expect(output).to.have.a.property('Maximum_number_of_parameters');
+ expect(output).to.have.a.property('Program_size');
+ expect(output).to.have.a.property('Associated_space_size');
+ expect(output).to.have.a.property('Static_storage_size');
+ expect(output).to.have.a.property('Automatic_storage_size');
+ expect(output).to.have.a.property('Number_of_MI_instructions');
+ expect(output).to.have.a.property('Number_of_MI_ODT_entries');
+ expect(output).to.have.a.property('Program_state');
+ expect(output).to.have.a.property('Compiler_identification');
+ expect(output).to.have.a.property('Earliest_release_program_can_run');
+ expect(output).to.have.a.property('Sort_sequence_table_name');
+ expect(output).to.have.a.property('Sort_sequence_table_library_name');
+ expect(output).to.have.a.property('Language_identifier');
+ expect(output).to.have.a.property('Program_domain');
+ expect(output).to.have.a.property('Conversion_required');
+ expect(output).to.have.a.property('Conversion_details');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Optimization');
+ expect(output).to.have.a.property('Paging_pool');
+ expect(output).to.have.a.property('Update_program_automatic_storage_area_(PASA)');
+ expect(output).to.have.a.property('Clear_program_automatic_storage_area_(PASA)');
+ expect(output).to.have.a.property('Paging_amount');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Program_entry_procedure_module');
+ expect(output).to.have.a.property('Program_entry_procedure_module_library');
+ expect(output).to.have.a.property('Activation_group_attribute');
+ expect(output).to.have.a.property('Observable_information_compressed');
+ expect(output).to.have.a.property('Run-time_information_compressed');
+ expect(output).to.have.a.property('Release_program_created_on');
+ expect(output).to.have.a.property('Shared_activation_group');
+ expect(output).to.have.a.property('Allow_update');
+ expect(output).to.have.a.property('Program_CCSID');
+ expect(output).to.have.a.property('Number_of_modules');
+ expect(output).to.have.a.property('Number_of_service_programs');
+ expect(output).to.have.a.property('Number_of_copyrights');
+ expect(output).to.have.a.property('Number_of_unresolved_references');
+ expect(output).to.have.a.property('Release_program_created_for');
+ expect(output).to.have.a.property('Allow_static_storage_reinitialization');
+ expect(output).to.have.a.property('All_creation_data');
+ expect(output).to.have.a.property('Allow_bound_*SRVPGM_library_name_update');
+ expect(output).to.have.a.property('Profiling_data');
+ expect(output).to.have.a.property('Teraspace_storage_enabled_modules');
+ expect(output).to.have.a.property('Storage_model');
+ expect(output).to.have.a.property('Uses_argument_optimization_(ARGOPT)');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('retrSrvPgmInfo', () => {
+ transports.forEach((transport) => {
+ it(`returns service program info using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const obj = new iObj(connection);
+
+ obj.retrSrvPgmInfo('QZSRVSSL', 'QHTTPSVR', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Service_program_name');
+ expect(output).to.have.a.property('Service_program_name');
+ expect(output).to.have.a.property('Service_program_owner');
+ expect(output).to.have.a.property('Service_program_attribute');
+ expect(output).to.have.a.property('Creation_date_and_time');
+ expect(output).to.have.a.property('Export_source_file_name');
+ expect(output).to.have.a.property('Export_source_file_library_name');
+ expect(output).to.have.a.property('Export_source_file_member_name');
+ expect(output).to.have.a.property('Activation_group_attribute');
+ expect(output).to.have.a.property('Current_export_signature');
+ expect(output).to.have.a.property('User_profile');
+ expect(output).to.have.a.property('Observable_information_compressed');
+ expect(output).to.have.a.property('Run-time_information_compressed');
+ expect(output).to.have.a.property('Run-time_information_compressed');
+ expect(output).to.have.a.property('Service_program_CCSID');
+ expect(output).to.have.a.property('Number_of_modules');
+ expect(output).to.have.a.property('Number_of_service_programs');
+ expect(output).to.have.a.property('Number_of_copyrights');
+ expect(output).to.have.a.property('Text_description');
+ expect(output).to.have.a.property('Shared_activation_group');
+ expect(output).to.have.a.property('Allow_update');
+ expect(output).to.have.a.property('Number_of_unresolved_references');
+ expect(output).to.have.a.property('Use_adopted_authority');
+ expect(output).to.have.a.property('Allow_bound_*SRVPGM_library_name_update');
+ expect(output).to.have.a.property('Profiling_data');
+ expect(output).to.have.a.property('Teraspace_storage_enabled_modules');
+ expect(output).to.have.a.property('Storage_model');
+ expect(output).to.have.a.property('Uses_argument_optimization_(ARGOPT)');
+ expect(output).to.have.a.property('Reserved_\'00\'X');
+ expect(output).to.have.a.property('Service_program_state');
+ expect(output).to.have.a.property('Service_program_domain');
+ expect(output).to.have.a.property('Associated_space_size');
+ expect(output).to.have.a.property('Static_storage_size');
+ expect(output).to.have.a.property('Service_program_size');
+ expect(output).to.have.a.property('Release_service_program_created_on');
+ expect(output).to.have.a.property('Earliest_release_service_program_can_run');
+ expect(output).to.have.a.property('Release_service_program_created_for');
+ expect(output).to.have.a.property('Allow_static_storage_reinitialization');
+ expect(output).to.have.a.property('Conversion_required');
+ expect(output).to.have.a.property('All_creation_data');
+ expect(output).to.have.a.property('Conversion_details');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Paging_pool');
+ expect(output).to.have.a.property('Paging_amount');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('retrUserInfo', () => {
+ transports.forEach((transport) => {
+ it(`returns specified user profile info using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const obj = new iObj(connection);
+
+ obj.retrUserInfo('QSYS', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('User_profile_name');
+ expect(output).to.have.a.property('Previous_sign-on_date_and_time');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Sign-on_attempts_not_valid');
+ expect(output).to.have.a.property('Status');
+ expect(output).to.have.a.property('Password_change_date');
+ expect(output).to.have.a.property('No_password_indicator');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Password_expiration_interval');
+ expect(output).to.have.a.property('Date_password_expires');
+ expect(output).to.have.a.property('Days_until_password_expires');
+ expect(output).to.have.a.property('Set_password_to_expire');
+ expect(output).to.have.a.property('Display_sign-on_information');
+ expect(output).to.have.a.property('Local_password_management');
+ expect(output).to.have.a.property('Block_password_change');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('retrUsrAuthToObj', () => {
+ transports.forEach((transport) => {
+ it(`retrieves info for users who are authorized to an object using ${transport.name} transpsort`, (done) => {
+ const connection = transport.me;
+
+ const obj = new iObj(connection);
+
+ obj.retrUserAuthToObj('/home', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Profile_name');
+ expect(output).to.have.a.property('User_or_group_indicator');
+ expect(output).to.have.a.property('Data_authority');
+ expect(output).to.have.a.property('Authorization_list_management');
+ expect(output).to.have.a.property('Object_management');
+ expect(output).to.have.a.property('Object_existence');
+ expect(output).to.have.a.property('Object_alter');
+ expect(output).to.have.a.property('Object_reference');
+ expect(output).to.have.a.property('Reserved');
+ expect(output).to.have.a.property('Object_operational');
+ expect(output).to.have.a.property('Data_read');
+ expect(output).to.have.a.property('Data_add');
+ expect(output).to.have.a.property('Data_update');
+ expect(output).to.have.a.property('Data_delete');
+ expect(output).to.have.a.property('Data_execute');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('addToLibraryList', () => {
+ transports.forEach((transport) => {
+ it(`appends lib to user's lib list using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const obj = new iObj(connection);
+
+ obj.addToLibraryList('QHTTPSVR', (output) => {
+ expect(output).to.be.a('boolean').and.to.equal(true);
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iPgmFunctional.js b/test/functional/iPgmFunctional.js
new file mode 100644
index 00000000..cbdda8e0
--- /dev/null
+++ b/test/functional/iPgmFunctional.js
@@ -0,0 +1,134 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iPgm, xmlToJson } = require('../../lib/itoolkit');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iPgm Functional Tests', () => {
+ describe('Test iPgm()', () => {
+ transports.forEach((transport) => {
+ it(`calls QWCRSVAL program checks if it ran successfully using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const program = new iPgm('QWCRSVAL', { lib: 'QSYS' });
+
+ const outBuf = [
+ [0, '10i0'],
+ [0, '10i0'],
+ ['', '36h'],
+ ['', '10A'],
+ ['', '1A'],
+ ['', '1A'],
+ [0, '10i0'],
+ [0, '10i0'],
+ ];
+ program.addParam(outBuf, { io: 'out' });
+ program.addParam(66, '10i0');
+ program.addParam(1, '10i0');
+ program.addParam('QCCSID', '10A');
+ program.addParam(this.errno, { io: 'both', len: 'rec2' });
+ connection.add(program);
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ });
+ done();
+ });
+ });
+ });
+ });
+
+
+ describe('Test iPgm()', () => {
+ transports.forEach((transport) => {
+ it(`calls QWCRSVAL program and returns arbitrarily named parameter using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const program = new iPgm('QWCRSVAL', { lib: 'QSYS' });
+
+ const outBuf = [
+ [0, '10i0'],
+ [0, '10i0'],
+ ['', '36h'],
+ ['', '10A'],
+ ['', '1A'],
+ ['', '1A'],
+ [0, '10i0'],
+ [0, '10i0'],
+ ];
+ program.addParam(outBuf, { io: 'out' });
+ program.addParam(66, '10i0');
+ program.addParam(1, '10i0');
+ program.addParam('QCCSID', '10A');
+ const paramValue = 'errno';
+
+ program.addParam(this.errno, { io: 'both', len: 'rec2', name: paramValue });
+ connection.add(program);
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe.skip('Test iPgm()', () => {
+ // Skip for now ZZSRV6 program requires XMLSERVICE built with tests
+ // Refer to test/rpg/zzsrv6.rpgle
+ transports.forEach((transport) => {
+ it.skip(`Should be successful with addReturn arbitrary attribute specified using using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const program = new iPgm('ZZSRV6', { lib: 'XMLSERVICE', func: 'ZZVARY4' });
+
+ program.addParam('Gill', '10A', { letying: '4' });
+ const testValue = 'NEW_NAME';
+ program.addReturn('0', '20A', { letying: '4', name: testValue });
+ connection.add(program);
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ expect(results[0].data[1].name).to.equal(testValue);
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iProdFunctional.js b/test/functional/iProdFunctional.js
new file mode 100644
index 00000000..30417546
--- /dev/null
+++ b/test/functional/iProdFunctional.js
@@ -0,0 +1,164 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iConn } = require('../../lib/itoolkit');
+const { iProd } = require('../../lib/iprod');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iProd Functional Tests', () => {
+ describe('constructor', () => {
+ it('creates and returns an instance of iProd', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ const prod = new iProd(connection);
+
+ expect(prod).to.be.instanceOf(iProd);
+ });
+ });
+
+ describe('getPTFInfo', () => {
+ transports.forEach((transport) => {
+ it(`returns info for specified ptf using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const prod = new iProd(connection);
+
+ prod.getPTFInfo('SI67726', (ptf) => {
+ expect(ptf).to.be.an('Object');
+ expect(ptf).to.have.a.property('Product_ID');
+ expect(ptf).to.have.a.property('PTF_ID');
+ expect(ptf).to.have.a.property('Release_level');
+ expect(ptf).to.have.a.property('Product_option');
+ expect(ptf).to.have.a.property('Load_ID');
+ expect(ptf).to.have.a.property('Loaded_status');
+ expect(ptf).to.have.a.property('Cover_letter_status');
+ expect(ptf).to.have.a.property('On-order_status');
+ expect(ptf).to.have.a.property('Save_file_status');
+ expect(ptf).to.have.a.property('File_name');
+ expect(ptf).to.have.a.property('File_library_name');
+ expect(ptf).to.have.a.property('PTF_type');
+ expect(ptf).to.have.a.property('IPL_action');
+ expect(ptf).to.have.a.property('Action_pending');
+ expect(ptf).to.have.a.property('Action_required');
+ expect(ptf).to.have.a.property('PTF_is_released');
+ expect(ptf).to.have.a.property('Target_release');
+ expect(ptf).to.have.a.property('Superseding_PTF');
+ expect(ptf).to.have.a.property('Current_IPL_source');
+ expect(ptf).to.have.a.property('Minimum_level');
+ expect(ptf).to.have.a.property('Maximum_level');
+ expect(ptf).to.have.a.property('Format_information_available');
+ expect(ptf).to.have.a.property('Status_date_and_time');
+ expect(ptf).to.have.a.property('Licensed_Internal_Code_group');
+ expect(ptf).to.have.a.property('Superseded_by_PTF_ID');
+ expect(ptf).to.have.a.property('Current_server_IPL_source');
+ expect(ptf).to.have.a.property('Server_IPL_required');
+ expect(ptf).to.have.a.property('Creation_date_and_time');
+ expect(ptf).to.have.a.property('Technology_refresh_PTF');
+ expect(ptf).to.have.a.property('Reserved');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getProductInfo', () => {
+ transports.forEach((transport) => {
+ it(`returns info for specified product using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const prod = new iProd(connection);
+
+ prod.getProductInfo('5770DG1', (product) => {
+ expect(product).to.be.an('Object');
+ expect(product).to.have.a.property('Reserved');
+ expect(product).to.have.a.property('Product_ID');
+ expect(product).to.have.a.property('Release_level');
+ expect(product).to.have.a.property('Product_option');
+ expect(product).to.have.a.property('Load_ID');
+ expect(product).to.have.a.property('Symbolic_load_state');
+ expect(product).to.have.a.property('Load_error_indicator');
+ expect(product).to.have.a.property('Load_state');
+ expect(product).to.have.a.property('Supported_flag');
+ expect(product).to.have.a.property('Registration_type');
+ expect(product).to.have.a.property('Registration_value');
+ expect(product).to.have.a.property('Offset_to_additional_information');
+ expect(product).to.have.a.property('Primary_language_load_identifier');
+ expect(product).to.have.a.property('Minimum_target_release');
+ expect(product).to.have.a.property('Minimum_VRM_of_*BASE_required_by_option');
+ expect(product).to.have.a.property('Requirements_met_between_base_and_option_value');
+ expect(product).to.have.a.property('Level');
+ done();
+ });
+ });
+ });
+ });
+
+ // REST transport currently failing with 414 URI Too Long response code
+ // The requested URL's length exceeds the capacity limit for this server
+ describe('getInstalledProducts', () => {
+ transports.forEach((transport) => {
+ // eslint-disable-next-line func-names
+ it(`returns info for installed products using ${transport.name} transport`, function (done) {
+ if (transport.name === 'rest') {
+ this.skip();
+ }
+ const connection = transport.me;
+
+ const prod = new iProd(connection);
+
+ prod.getInstalledProducts((products) => {
+ expect(products).to.be.an('Array');
+ expect(products.length).to.be.greaterThan(0);
+
+ products.forEach((product) => {
+ expect(product).to.be.an('Object');
+ expect(product).to.have.a.property('Product_ID');
+ expect(product).to.have.a.property('Product_option');
+ expect(product).to.have.a.property('Release_level');
+ expect(product).to.have.a.property('Description_text_message_ID');
+ expect(product).to.have.a.property('Description_text_object_name');
+ expect(product).to.have.a.property('Description_text_library_name');
+ expect(product).to.have.a.property('Installed_flag');
+ expect(product).to.have.a.property('Supported_flag');
+ expect(product).to.have.a.property('Registration_type');
+ expect(product).to.have.a.property('Registration_value');
+ expect(product).to.have.a.property('Description_text');
+ });
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iSqlFunctional.js b/test/functional/iSqlFunctional.js
new file mode 100644
index 00000000..bf31f00b
--- /dev/null
+++ b/test/functional/iSqlFunctional.js
@@ -0,0 +1,420 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+
+const { expect } = require('chai');
+const { iSql, xmlToJson } = require('../../lib/itoolkit');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iSql Functional Tests', () => {
+ describe('prepare & execute', () => {
+ transports.forEach((transport) => {
+ it(`prepares & executes stored procedure then fetch results using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+
+ sql.prepare('call qsys2.tcpip_info()');
+ sql.execute();
+ sql.fetch();
+ sql.free();
+ connection.add(sql);
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('addQuery & fetch', () => {
+ transports.forEach((transport) => {
+ it(`runs a query and fetches results using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+
+ sql.addQuery('SELECT LSTNAM, STATE FROM QIWS.QCUSTCDT');
+ sql.fetch();
+ sql.free();
+ connection.add(sql);
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('added test to ensure issue #11 was resolved', () => {
+ transports.forEach((transport) => {
+ it(`should parse SQL result set empty data tags correctly using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+
+ sql.addQuery('SELECT \'\' AS BLANK, STATE FROM QIWS.QCUSTCDT');
+ sql.fetch();
+ sql.free();
+ connection.add(sql);
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0].value).to.equal('');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('tables', () => {
+ transports.forEach((transport) => {
+ it(`returns meta data for specified table using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+ // [catalog, schema, table, table type]
+ sql.tables(['', 'QIWS', 'QCUSTCDT', '']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('tablePriv', () => {
+ transports.forEach((transport) => {
+ it('returns privilege data for a table', (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+ // [catalog, schema, table]
+ sql.tablePriv(['', 'QIWS', 'QCUSTCDT']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('columns', () => {
+ transports.forEach((transport) => {
+ it('returns meta data for a column', (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+ // catalog, schema, table, column
+ sql.columns(['', 'QIWS', 'QCUSTCDT', 'CUSNUM']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.be.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('columnPriv', () => {
+ transports.forEach((transport) => {
+ it('returns privilege data for a column', (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+
+ sql.columnPriv(['', 'QIWS', 'QCUSTCDT', 'BALDUE']);
+
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('procedures', () => {
+ transports.forEach((transport) => {
+ it('returns meta data on for a procedure', (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+ // [catalog, schema, procedure]
+ sql.procedures(['', 'QSYS2', 'TCPIP_INFO']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('pColumns', () => {
+ transports.forEach((transport) => {
+ it('returns meta data for procedure column', (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+ // [catalog, schema, procedure, column]
+ sql.pColumns(['', 'QSYS2', 'QCMDEXC', 'COMMAND']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('primaryKeys', () => {
+ transports.forEach((transport) => {
+ it(`returns meta data for a primary key using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+ // [catalog, schema, table]
+ sql.primaryKeys(['', 'QUSRSYS', 'QASZRAIRX']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('foreignKeys', () => {
+ transports.forEach((transport) => {
+ it('returns meta data for a foreign key', (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+ // pk: [catalog, schema, table]
+ // fk: [catalog, schema, table]
+ sql.foreignKeys(['', 'QUSRSYS', 'QASZRAIRC', '', 'QUSRSYS', 'QASZRAIRX']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe('statistics', () => {
+ transports.forEach((transport) => {
+ it('returns stats info for table', (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+
+ sql.statistics(['', 'QIWS', 'QCUSTCDT', 'all']);
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.result).to.be.an('array');
+ result.result.forEach((row) => {
+ expect(row[0]).to.be.an('object');
+ expect(row[0]).haveOwnProperty('desc');
+ expect(row[0]).haveOwnProperty('value');
+ });
+ });
+ done();
+ });
+ });
+ });
+ });
+
+ describe.skip('special', () => {
+ // TODO: find passing case
+ // Below test fails with error code 9- argument value not valid
+ transports.forEach((transport) => {
+ it.skip(`returns meta data for special columns using ${transport.name} transport`, (done) => {
+ // [catalog, schema, table, row | transaction |session, no | nullable]
+ const connection = transport.me;
+
+ const sql = new iSql();
+
+ sql.special(['', 'QUSRSYS', 'QASZRAIRX', 'row', 'no'], { error: 'on' });
+ connection.add(sql.toXML());
+ connection.debug(true);
+ connection.run((xmlOut) => {
+ // eslint-disable-next-line no-console
+ console.log(`xml output: \n ${xmlOut}`);
+ const results = xmlToJson(xmlOut);
+ // eslint-disable-next-line no-console
+ console.log(JSON.stringify(results));
+ done();
+ });
+ });
+ });
+ });
+
+ describe.skip('rowCount', () => {
+ // xmlToJson does not add check for row count currently
+ // Skip for now until this is added.
+ transports.forEach((transport) => {
+ it.skip(`returns the number of rows affected by statement using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const sql = new iSql();
+
+ const insert = 'INSERT INTO QIWS.QCUSTCDT (CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) '
+ + 'VALUES (8798,\'TURNER\',\'TT\',\'MAIN\',\'NYC\',\'NY\',10001, 500, 3, 40.00, 0.00) with NONE';
+
+ sql.addQuery(insert);
+ sql.rowCount();
+ sql.free();
+ connection.add(sql.toXML());
+ connection.run((xmlOut) => {
+ const results = xmlToJson(xmlOut);
+ done();
+ results.forEach((result) => {
+ expect(result.success).to.equal(true);
+ expect(result.rowCount).to.equal(1);
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iUserSpaceFunctional.js b/test/functional/iUserSpaceFunctional.js
new file mode 100644
index 00000000..5f550e7c
--- /dev/null
+++ b/test/functional/iUserSpaceFunctional.js
@@ -0,0 +1,127 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iConn } = require('../../lib/itoolkit');
+const { iUserSpace } = require('../../lib/iuserSpace');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const lib = 'NODETKTEST';
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iUserSpace Functional Tests', () => {
+ describe('constructor', () => {
+ it('returns an instance of iUserSpace', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ const userSpace = new iUserSpace(connection);
+
+ expect(userSpace).to.be.instanceOf(iUserSpace);
+ });
+ });
+
+ describe('createUserSpace', () => {
+ transports.forEach((transport) => {
+ it(`creates a user space using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const userSpace = new iUserSpace(connection);
+
+ const description = 'Node toolkit test user space';
+
+ const userSpaceName = `USP${(transport.name).toUpperCase()}`;
+
+ userSpace.createUserSpace(userSpaceName, lib, 'LOG', 50, '*EXCLUDE',
+ description, (output) => {
+ expect(output).to.be.a('boolean').and.to.equal(true);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('setUserSpaceData', () => {
+ transports.forEach((transport) => {
+ it(`sets data within the user space using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const userSpace = new iUserSpace(connection);
+
+ const msg = 'Hello from userspace!';
+
+ const userSpaceName = `USP${(transport.name).toUpperCase()}`;
+
+ userSpace.setUserSpaceData(userSpaceName, lib, msg.length, msg,
+ (output) => {
+ expect(output).to.be.a('boolean').and.to.equal(true);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getUserSpaceData', () => {
+ transports.forEach((transport) => {
+ it(`returns specified length of data using ${transport.name} transport`,
+ (done) => {
+ const connection = transport.me;
+
+ const userSpace = new iUserSpace(connection);
+
+ const userSpaceName = `USP${(transport.name).toUpperCase()}`;
+
+ userSpace.getUserSpaceData(userSpaceName, lib, 21, (output) => {
+ expect(output).to.be.a('string').and.to.equal('Hello from userspace!');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('deleteUserSpace', () => {
+ transports.forEach((transport) => {
+ it(`removes a user space using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const userSpace = new iUserSpace(connection);
+
+ const userSpaceName = `USP${(transport.name).toUpperCase()}`;
+
+ userSpace.deleteUserSpace(userSpaceName, lib, (output) => {
+ expect(output).to.be.a('boolean').and.to.equal(true);
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/functional/iWorkFunctional.js b/test/functional/iWorkFunctional.js
new file mode 100644
index 00000000..70acd96e
--- /dev/null
+++ b/test/functional/iWorkFunctional.js
@@ -0,0 +1,275 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iConn } = require('../../lib/itoolkit');
+const { iWork } = require('../../lib/iwork');
+
+// Set Env variables or set values here.
+const opt = {
+ database: process.env.TKDB || '*LOCAL',
+ user: process.env.TKUSER || '',
+ password: process.env.TKPASS || '',
+ host: process.env.TKHOST || 'localhost',
+ port: process.env.TKPORT || 80,
+ path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
+};
+
+const { returnTransports } = require('../../lib/utils');
+
+const transports = returnTransports(opt);
+
+describe('iWork Functional Tests', () => {
+ describe('constructor', () => {
+ it('creates and returns an instance of iWork', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ const work = new iWork(connection);
+
+ expect(work).to.be.instanceOf(iWork);
+ });
+ });
+
+ describe('getSysValue', () => {
+ transports.forEach((transport) => {
+ it(`returns the value of system variable using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const work = new iWork(connection);
+
+ work.getSysValue('QCENTURY', (output) => {
+ expect(output).to.be.a('string').and.to.equal('1');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getSysStatus', () => {
+ transports.forEach((transport) => {
+ it('returns basic system status information about the signed-on users '
+ + `and batch jobs using ${transport.name} transport`,
+ (done) => {
+ const connection = transport.me;
+
+ const work = new iWork(connection);
+
+ work.getSysStatus((output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Current_date_and_time');
+ expect(output).to.have.a.property('System_name');
+ expect(output).to.have.a.property('Users_currently_signed_on');
+ expect(output).to.have.a.property('Users_temporarily_signed_off_(disconnected)');
+ expect(output).to.have.a.property('Users_suspended_by_system_request');
+ expect(output).to.have.a.property('Users_suspended_by_group_jobs');
+ expect(output).to.have.a.property('Users_signed_off_with_printer_output_waiting_to_print');
+ expect(output).to.have.a.property('Batch_jobs_waiting_for_messages');
+ expect(output).to.have.a.property('Batch_jobs_running');
+ expect(output).to.have.a.property('Batch_jobs_held_while_running');
+ expect(output).to.have.a.property('Batch_jobs_ending');
+ expect(output).to.have.a.property('Batch_jobs_waiting_to_run_or_already_scheduled');
+ expect(output).to.have.a.property('Batch_jobs_held_on_a_job_queue');
+ expect(output).to.have.a.property('Batch_jobs_on_a_held_job_queue');
+ expect(output).to.have.a.property('Batch_jobs_on_an_unassigned_job_queue');
+ expect(output).to.have.a.property('Batch_jobs_ended_with_printer_output_waiting_to_print');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getSysStatusExt', () => {
+ transports.forEach((transport) => {
+ it(`returns more detailed system status info using ${transport.name} transport`,
+ (done) => {
+ const connection = transport.me;
+
+ const work = new iWork(connection);
+
+ work.getSysStatusExt((output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Current_date_and_time');
+ expect(output).to.have.a.property('System_name');
+ expect(output).to.have.a.property('Elapsed_time');
+ expect(output).to.have.a.property('Restricted_state_flag');
+ expect(output).to.have.a.property('%_processing_unit_used');
+ expect(output).to.have.a.property('Jobs_in_system');
+ expect(output).to.have.a.property('%_permanent_addresses');
+ expect(output).to.have.a.property('%_temporary_addresses');
+ expect(output).to.have.a.property('System_ASP');
+ expect(output).to.have.a.property('%_system_ASP_used');
+ expect(output).to.have.a.property('Total_auxiliary_storage');
+ expect(output).to.have.a.property('Current_unprotected_storage_used');
+ expect(output).to.have.a.property('Maximum_unprotected_storage_used');
+ expect(output).to.have.a.property('%_DB_capability');
+ expect(output).to.have.a.property('Main_storage_size');
+ expect(output).to.have.a.property('Number_of_partitions');
+ expect(output).to.have.a.property('Partition_identifier');
+ expect(output).to.have.a.property('Current_processing_capacity');
+ expect(output).to.have.a.property('Processor_sharing_attribute');
+ expect(output).to.have.a.property('Number_of_processors');
+ expect(output).to.have.a.property('Active_jobs_in_system');
+ expect(output).to.have.a.property('Active_threads_in_system');
+ expect(output).to.have.a.property('Maximum_jobs_in_system');
+ expect(output).to.have.a.property('%_temporary_256MB_segments_used');
+ expect(output).to.have.a.property('%_temporary_4GB_segments_used');
+ expect(output).to.have.a.property('%_permanent_256MB_segments_used');
+ expect(output).to.have.a.property('%_permanent_4GB_segments_used');
+ expect(output).to.have.a.property('%_current_interactive_performance');
+ expect(output).to.have.a.property('%_uncapped_CPU_capacity_used');
+ expect(output).to.have.a.property('%_shared_processor_pool_used');
+ expect(output).to.have.a.property('Main_storage_size_(long)');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getJobStatus', () => {
+ transports.forEach((transport) => {
+ it(`returns status of specified job using ${transport.name} transport`,
+ (done) => {
+ const connection = transport.me;
+
+ const work = new iWork(connection);
+
+ work.getJobStatus('000000', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Job_status');
+ expect(output).to.have.a.property('Fully_qualified_job_name');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getJobInfo', () => {
+ transports.forEach((transport) => {
+ it(`returns info on specfed job using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const work = new iWork(connection);
+
+ work.getJobInfo('SCPF', 'QSYS', '000000', (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Job_name');
+ expect(output).to.have.a.property('User_name');
+ expect(output).to.have.a.property('Job_number');
+ expect(output).to.have.a.property('Job_status');
+ expect(output).to.have.a.property('Job_type');
+ expect(output).to.have.a.property('Job_subtype');
+ expect(output).to.have.a.property('Subsystem_description_name');
+ expect(output).to.have.a.property('Run_priority_(job)');
+ expect(output).to.have.a.property('System_pool_identifier');
+ expect(output).to.have.a.property('Processing_unit_time_used,_if_less_than_2,147,483,647_milliseconds');
+ expect(output).to.have.a.property('Number_of_auxiliary_I/O_requests,_if_less_than_2,147,483,647');
+ expect(output).to.have.a.property('Number_of_interactive_transactions');
+ expect(output).to.have.a.property('Response_time_total');
+ expect(output).to.have.a.property('Function_type');
+ expect(output).to.have.a.property('Function_name');
+ expect(output).to.have.a.property('Active_job_status');
+ expect(output).to.have.a.property('Number_of_database_lock_waits');
+ expect(output).to.have.a.property('Number_of_internal_machine_lock_waits');
+ expect(output).to.have.a.property('Number_of_nondatabase_lock_waits');
+ expect(output).to.have.a.property('Time_spent_on_database_lock_waits');
+ expect(output).to.have.a.property('Time_spent_on_internal_machine_lock_waits');
+ expect(output).to.have.a.property('Time_spent_on_nondatabase_lock_waits');
+ expect(output).to.have.a.property('Current_system_pool_identifier');
+ expect(output).to.have.a.property('Thread_count');
+ expect(output).to.have.a.property('Processing_unit_time_used_-_total_for_the_job');
+ expect(output).to.have.a.property('Number_of_auxiliary_I/O_requests');
+ expect(output).to.have.a.property('Processing_unit_time_used_for_database_-_total_for_the_job');
+ expect(output).to.have.a.property('Page_faults');
+ expect(output).to.have.a.property('Active_job_status_for_jobs_ending');
+ expect(output).to.have.a.property('Memory_pool_name');
+ expect(output).to.have.a.property('Message_reply');
+ expect(output).to.have.a.property('Message_key,_when_active_job_waiting_for_a_message');
+ expect(output).to.have.a.property('Message_queue_name,_when_active_job_waiting_for_a_message');
+ expect(output).to.have.a.property('Message_queue_library_name,_when_active_job_waiting_for_a_message');
+ expect(output).to.have.a.property('Message_queue_library_ASP_device_name,_when_active_job_waiting_for_a_message');
+ done();
+ });
+ });
+ });
+ });
+
+ describe('getDataArea', () => {
+ before('init lib, data area, and add data', async () => {
+ // eslint-disable-next-line global-require
+ const { DBPool } = require('idb-pconnector');
+ const pool = new DBPool({ url: '*LOCAL' }, { incrementSize: 2 });
+
+ const qcmdexec = 'CALL QSYS2.QCMDEXC(?)';
+ const lib = 'NODETKTEST';
+ const dataArea = 'TESTDA';
+
+ const createLib = `CRTLIB LIB(${lib}) TYPE(*TEST) TEXT('Used to test' Node.js toolkit')`;
+
+ const createDataArea = `CRTDTAARA DTAARA(${lib}/${dataArea}) TYPE(*CHAR) `
+ + 'TEXT(\'TEST DATA AREA FOR NODE TOOLKIT\') '
+ + 'VALUE(\'Hello From Test Data Area!\')';
+
+ const findLib = 'SELECT SCHEMA_NAME FROM qsys2.sysschemas WHERE SCHEMA_NAME = \'NODETKTEST\'';
+
+ const findDataArea = `SELECT OBJNAME FROM TABLE (QSYS2.OBJECT_STATISTICS('${lib}', '*DTAARA')) AS X`;
+
+ const libResult = await pool.runSql(findLib);
+
+ const dataAreaResult = await pool.runSql(findDataArea);
+
+ if (!libResult.length) {
+ await pool.prepareExecute(qcmdexec, [createLib]).catch((error) => {
+ // eslint-disable-next-line no-console
+ console.log('Unable to Create Lib!');
+ throw error;
+ });
+ // eslint-disable-next-line no-console
+ console.log('CREATED LIB!');
+ }
+ if (!dataAreaResult.length) {
+ await pool.prepareExecute(qcmdexec, [createDataArea]).catch((error) => {
+ // eslint-disable-next-line no-console
+ console.log('Unable to Create DA!');
+ throw error;
+ });
+ // eslint-disable-next-line no-console
+ console.log('CREATED DA!');
+ }
+ });
+ transports.forEach((transport) => {
+ it(`returns contents of a data area using ${transport.name} transport`, (done) => {
+ const connection = transport.me;
+
+ const work = new iWork(connection);
+
+ work.getDataArea('AMUSSE', 'TESTDA', 20, (output) => {
+ expect(output).to.be.an('Object');
+ expect(output).to.have.a.property('Type_of_value_returned');
+ expect(output).to.have.a.property('Library_name');
+ expect(output).to.have.a.property('Length_of_value_returned');
+ expect(output).to.have.a.property('Number_of_decimal_positions');
+ expect(output).to.have.a.property('Value');
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/test/test.js b/test/test.js
deleted file mode 100644
index 27aec8e8..00000000
--- a/test/test.js
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright (c) International Business Machines Corp. 2017
-// All Rights Reserved
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
-// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
-// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-
-const assert = require('assert');
-const xt = require('../lib/itoolkit');
-const hint = 'check the "success" property in return value'
-//Need change based on your server configurations
-const opt = {
- db : '*LOCAL',
- user : 'YOURNAME',
- pwd : 'PASSWORD',
- host : '0.0.0.0',
- port : 8080,
- path : '/cgi-bin/xmlcgi.pgm'
-};
-
-describe('Basic Function Test', () => {
- describe('Test iCmd()', () => {
- it(hint, (done) => {
- let conn = new xt.iConn(opt.db);
- conn.add(xt.iCmd('RTVJOBA USRLIBL(?) SYSLIBL(?)'));
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success = true;
- results.every((result, i) => {
- if(result.hasOwnProperty('success'))
- success = result.success == true;
- });
- if(success) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
- });
-
- describe('Test iSh()', () => {
- it(hint, (done) => {
- let conn = new xt.iConn(opt.db);
- conn.add(xt.iSh('system -i wrksyssts'));
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success = true;
- results.every((result, i) => {
- if(result.hasOwnProperty('success'))
- success = result.success == true;
- });
- if(success) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
- });
-
- describe('Test iQsh()', () => {
- it(hint, (done) => {
- let conn = new xt.iConn(opt.db);
- conn.add(xt.iQsh('system wrksyssts'));
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success = true;
- results.every((result, i) => {
- if(result.hasOwnProperty('success'))
- success = result.success == true;
- });
- if(success) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
- });
-
- describe('Test iPgm()', () => {
- it(hint, (done) => {
- let conn = new xt.iConn(opt.db);
- let pgm = new xt.iPgm('QWCRSVAL', {'lib':'QSYS'});
- let outBuf = [
- [0, '10i0'],
- [0, '10i0'],
- ['', '36h'],
- ['', '10A'],
- ['', '1A'],
- ['', '1A'],
- [0, '10i0'],
- [0, '10i0']
- ];
- pgm.addParam(outBuf, {'io':'out'});
- pgm.addParam(66, '10i0');
- pgm.addParam(1, '10i0');
- pgm.addParam('QCCSID', '10A');
- pgm.addParam(this.errno, {'io':'both', 'len' : 'rec2'});
- conn.add(pgm);
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success = false;
- results.every((result, i) => {
- if(result.hasOwnProperty('success'))
- success = result.success == true;
- });
- if(success) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
- it('Should return arbitrarily named parameter', (done) => {
- let conn = new xt.iConn(opt.db);
- let pgm = new xt.iPgm('QWCRSVAL', {'lib':'QSYS'});
- let outBuf = [
- [0, '10i0'],
- [0, '10i0'],
- ['', '36h'],
- ['', '10A'],
- ['', '1A'],
- ['', '1A'],
- [0, '10i0'],
- [0, '10i0']
- ];
- pgm.addParam(outBuf, {'io':'out'});
- pgm.addParam(66, '10i0');
- pgm.addParam(1, '10i0');
- pgm.addParam('QCCSID', '10A');
- let paramValue = 'errno';
- pgm.addParam(this.errno, {'io':'both', 'len' : 'rec2', 'name' : paramValue });
- conn.add(pgm);
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success = false;
- results.every((result, i) => {
- if(result.data[11].hasOwnProperty('name'))
- success = result.data[11].name == paramValue;
- });
- if(success) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
- /*** Refer to test/rpg/zzsrv6.rpgle
- it('Should return success with addReturn arbitrary attribute specified', (done) => {
- let conn = new xt.iConn(opt.db);
- let pgm = new xt.iPgm("ZZSRV6", {"lib":"XMLSERVICE", "func":"ZZVARY4"});
- pgm.addParam("Gill", "10A", {"letying":"4"});
- let test_value = "NEW_NAME";
- pgm.addReturn("0", "20A", {"letying":"4","name":test_value});
- conn.add(pgm);
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- if(results[0].data[1].name == test_value) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
- ***/
- });
-
- describe('Test iSql()', () => {
- it(hint, (done) => {
- let conn = new xt.iConn(opt.db);
- let sql = new xt.iSql(); /* Test iSql Class */
- sql.prepare('call qsys2.tcpip_info()');
- sql.execute();
- sql.fetch();
- sql.free();
- conn.add(sql);
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success = true;
- results.every((result, i) => {
- if(result.hasOwnProperty('success'))
- success = result.success == true;
- });
- if(success) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
-
- it('should return SQL result set', (done) => {
- let conn = new xt.iConn(opt.db);
- let sql = new xt.iSql();
- sql.addQuery("SELECT LSTNAM, STATE FROM QIWS.QCUSTCDT");
- sql.fetch();
- sql.free();
- conn.add(sql);
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success1 = false;
- let success2 = false;
- results.every((result, i) => {
- if(result.hasOwnProperty('success'))
- success1 = result.success == true;
- result.result.every((row, i) => {
- success2 = row[0].hasOwnProperty('desc');
- })
- });
- if(success1 && success2) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
-
- it('should parse SQL result set empty data tags correctly', (done) => {
- let conn = new xt.iConn(opt.db);
- let sql = new xt.iSql();
- sql.addQuery("SELECT '' AS BLANK, STATE FROM QIWS.QCUSTCDT");
- sql.fetch();
- sql.free();
- conn.add(sql);
- conn.run((str) => {
- let results = xt.xmlToJson(str);
- let success1 = false;
- let success2 = false;
- results.every((result, i) => {
- if(result.hasOwnProperty('success'))
- success1 = result.success == true;
- result.result.every((row, i) => {
- success2 = row[0].value === '';
- })
- });
- if(success1 && success2) done();
- else done(new Error(JSON.stringify(results)));
- });
- });
- });
-});
\ No newline at end of file
diff --git a/test/unit/commandsUnit.js b/test/unit/commandsUnit.js
new file mode 100644
index 00000000..31b6c35c
--- /dev/null
+++ b/test/unit/commandsUnit.js
@@ -0,0 +1,90 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+const { expect } = require('chai');
+const { iSh, iQsh, iCmd } = require('../../lib/itoolkit');
+
+describe('iSh, iCmd, iQsh, Unit Tests', () => {
+ describe('iSh function', () => {
+ it('accepts command input and returns XML output', () => {
+ const sh = iSh('ls -lah');
+
+ const expectedXML = 'ls -lah';
+
+ expect(sh).to.be.a('string').and.to.equal(expectedXML);
+ });
+
+ it('accepts command input and options returns with optional attributes', () => {
+ const options = {
+ error: 'on', before: '65535', after: '37', rows: 'on',
+ };
+
+ const sh = iSh('ls -lah', options);
+
+ const expectedXML = 'ls -lah';
+
+ expect(sh).to.be.a('string').and.to.equal(expectedXML);
+ });
+ });
+
+ describe('iCmd function', () => {
+ it('accepts command input and returns XML output', () => {
+ const cmd = iCmd('RTVJOBA USRLIBL(?) SYSLIBL(?)');
+
+ const expectedXML = 'RTVJOBA USRLIBL(?) SYSLIBL(?)';
+
+ expect(cmd).to.be.a('string').and.to.equal(expectedXML);
+ });
+
+ it('accepts command input and options returns with optional attributes', () => {
+ const options = {
+ exec: 'cmd', error: 'on', before: '65535', after: '37', hex: 'on',
+ };
+
+ const cmd = iCmd('RTVJOBA USRLIBL(?) SYSLIBL(?)', options);
+
+ const expectedXML = 'RTVJOBA USRLIBL(?) SYSLIBL(?)';
+
+ expect(cmd).to.be.a('string').and.to.equal(expectedXML);
+ });
+ });
+
+ describe('iQsh function', () => {
+ it('accepts command input and returns XML output', () => {
+ const qsh = iQsh('RTVJOBA USRLIBL(?) SYSLIBL(?)');
+
+ const expectedXML = 'RTVJOBA USRLIBL(?) SYSLIBL(?)';
+
+ expect(qsh).to.be.a('string').and.to.equal(expectedXML);
+ });
+
+ it('accepts command input and options returns with optional attributes', () => {
+ const options = {
+ exec: 'cmd', error: 'on', before: '65535', after: '37', hex: 'on', rows: 'on',
+ };
+ const qsh = iCmd('RTVJOBA USRLIBL(?) SYSLIBL(?)', options);
+
+ const expectedXML = 'RTVJOBA USRLIBL(?) SYSLIBL(?)';
+
+ expect(qsh).to.be.a('string').and.to.equal(expectedXML);
+ });
+ });
+});
diff --git a/test/unit/iConnUnit.js b/test/unit/iConnUnit.js
new file mode 100644
index 00000000..0062b9d6
--- /dev/null
+++ b/test/unit/iConnUnit.js
@@ -0,0 +1,172 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const sinon = require('sinon');
+const { iConn, iSh } = require('../../lib/itoolkit');
+
+// const iNetwork = require('../lib/inetwork')
+// Need change based on your server configurations
+/* const opt = {
+ db : '*LOCAL',
+ user : 'YOURNAME',
+ pwd : 'PASSWORD',
+ host : '0.0.0.0',
+ port : 8080,
+ path : '/cgi-bin/xmlcgi.pgm'
+};
+ */
+const opt = {
+ database: '*LOCAL',
+ user: process.env.USERID,
+ password: process.env.PASSWD,
+ host: 'lp13ut28.rch.stglabs.ibm.com',
+ port: 80,
+ path: '/cgi-bin/xmlcgi.pgm',
+};
+
+
+describe('iConn Class Unit Tests', () => {
+ describe('constructor', () => {
+ it('creates and returns an instance of iConn with idb transport', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ expect(connection).to.be.instanceOf(iConn);
+ expect(connection.conn).to.be.an('Object');
+ expect(connection.conn.I_TRANSPORT_DB2_DATABASE).to.equal(opt.database);
+ expect(connection.conn.I_TRANSPORT_DB2_USER).to.equal(opt.user);
+ expect(connection.conn.I_TRANSPORT_DB2_PASSWORD).to.equal(opt.password);
+ expect(connection.conn.I_TRANSPORT).to.equal('DB2');
+ expect(connection.conn.I_TRANSPORT_CTL).to.equal('*here');
+ expect(connection.conn.I_TRANSPORT_IPC).to.equal('*NA');
+ expect(connection.conn.I_XML_SERVICE_LIB).to.equal('QXMLSERV');
+ expect(connection.cmds).to.be.an('Array');
+ expect(connection.cmds.length).to.equal(0);
+ expect(connection.timeout).to.equal(5000);
+ expect(connection.I_DEBUG_VERBOSE).to.equal(false);
+ });
+
+ it('creates and returns an instance of iConn with rest transport', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password, opt);
+
+ expect(connection).to.be.instanceOf(iConn);
+ expect(connection.conn).to.be.an('Object');
+ expect(connection.conn.I_TRANSPORT_DB2_DATABASE).to.equal(opt.database);
+ expect(connection.conn.I_TRANSPORT_DB2_USER).to.equal(opt.user);
+ expect(connection.conn.I_TRANSPORT_DB2_PASSWORD).to.equal(opt.password);
+ expect(connection.conn.I_TRANSPORT).to.equal('REST');
+ expect(connection.conn.I_TRANSPORT_CTL).to.equal('*here');
+ expect(connection.conn.I_TRANSPORT_IPC).to.equal('*NA');
+ expect(connection.conn.I_XML_SERVICE_LIB).to.equal('QXMLSERV');
+ expect(connection.cmds).to.be.an('Array');
+ expect(connection.cmds.length).to.equal(0);
+ expect(connection.timeout).to.equal(5000);
+ expect(connection.I_DEBUG_VERBOSE).to.equal(false);
+ });
+ });
+
+ describe('add', () => {
+ it('appends to xml service request to the command list', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ connection.add(iSh('ls -lah'));
+ expect(connection.cmds.length).to.equal(1);
+ expect(connection.cmds[0]).to.equal('ls -lah');
+ });
+ });
+
+
+ describe('debug', () => {
+ it('turns verbose mode on/off', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ connection.debug(true);
+ expect(connection.debug()).to.equal(true);
+ connection.debug(false);
+ expect(connection.debug()).to.equal(false);
+ });
+ });
+
+
+ describe('getConnection', () => {
+ it('returns conn (object) property from iConn instance', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ const returned = connection.getConnection();
+
+ expect(returned).to.be.an('Object');
+ expect(returned.I_TRANSPORT_DB2_DATABASE).to.equal(opt.database);
+ expect(returned.I_TRANSPORT_DB2_USER).to.equal(opt.user);
+ expect(returned.I_TRANSPORT_DB2_PASSWORD).to.equal(opt.password);
+ expect(returned.I_TRANSPORT).to.equal('DB2');
+ expect(returned.I_TRANSPORT_CTL).to.equal('*here');
+ expect(returned.I_TRANSPORT_IPC).to.equal('*NA');
+ expect(returned.I_XML_SERVICE_LIB).to.equal('QXMLSERV');
+ });
+ });
+
+
+ describe('run', () => {
+ it('invokes transport to execute xml input and returns xml output in callback', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+ const xmlOut = `
+
+
+
+
+ HenningTX
+ JonesNY
+ VineVT
+ JohnsonGA
+ TyronNY
+ StevensCO
+ AlisonMN
+ DoeCA
+ ThomasWY
+ WilliamsTX
+ LeeNY
+ AbrahamMN
+ +++ success stmt1
+
+ +++ success
+
+
+ `;
+
+ sinon.stub(connection, 'run').yields(xmlOut);
+
+ connection.run((result) => {
+ expect(result).to.equal(xmlOut);
+ });
+ });
+ });
+
+
+ describe('setTimeout', () => {
+ it('override timeout for sync mode', () => {
+ const connection = new iConn(opt.database, opt.user, opt.password);
+
+ expect(connection.timeout).to.equal(5000);
+ connection.setTimeout(3);
+ expect(connection.timeout).to.equal(3000);
+ });
+ });
+});
diff --git a/test/unit/iPgmUnit.js b/test/unit/iPgmUnit.js
new file mode 100644
index 00000000..81d534b6
--- /dev/null
+++ b/test/unit/iPgmUnit.js
@@ -0,0 +1,156 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iPgm } = require('../../lib/itoolkit');
+
+const outBuf = [
+ [0, '10i0'],
+ [0, '10i0'],
+ ['', '36h'],
+ ['', '10A'],
+ ['', '1A'],
+ ['', '1A'],
+ [0, '10i0'],
+ [0, '10i0'],
+];
+const errno = [
+ [0, '10i0'],
+ [0, '10i0', { setlen: 'rec2' }],
+ ['', '7A'],
+ ['', '1A'],
+];
+
+describe('iPgm Class Unit Tests', () => {
+ describe('constructor', () => {
+ it('creates and returns an instance of iPgm with lib and function set', () => {
+ const pgm = new iPgm('QTOCNETSTS');
+ expect(pgm).to.be.instanceOf(iPgm);
+ });
+ });
+
+ describe('toXML', () => {
+ it('returns pgm XML', () => {
+ const pgm = new iPgm('QTOCNETSTS',
+ {
+ lib: 'QSYS',
+ func: 'QtoRtvTCPA',
+ error: 'on',
+ });
+
+ const expectedXML = '';
+
+ expect(pgm.toXML()).to.be.a('string').and.to.equal(expectedXML);
+ });
+ });
+
+ describe('addParam', () => {
+ it('appends param to pgm xml', () => {
+ const pgm = new iPgm('QTOCNETSTS',
+ {
+ lib: 'QSYS',
+ func: 'QtoRtvTCPA',
+ error: 'fast',
+ });
+
+ pgm.addParam(outBuf, { io: 'out' });
+
+ let expectedXML = ''
+ + '0'
+ + '0'
+ + ''
+ + '00';
+
+ expect(pgm.toXML()).to.equal(expectedXML);
+
+ pgm.addParam(66, '10i0');
+
+ expectedXML = ''
+ + '0'
+ + '0'
+ + ''
+ + '00'
+ + '66';
+
+ expect(pgm.toXML()).to.equal(expectedXML);
+
+ pgm.addParam(1, '10i0');
+
+ expectedXML = ''
+ + '0'
+ + '0'
+ + ''
+ + '00'
+ + '66'
+ + '1';
+
+ expect(pgm.toXML()).to.equal(expectedXML);
+
+ pgm.addParam('QCCSID', '10A');
+
+ expectedXML = ''
+ + '0'
+ + '0'
+ + ''
+ + '00'
+ + '66'
+ + '1'
+ + 'QCCSID';
+
+ expect(pgm.toXML()).to.equal(expectedXML);
+
+ pgm.addParam(errno, { io: 'both', len: 'rec2' });
+
+ expectedXML = ''
+ + '0'
+ + '0'
+ + ''
+ + '00'
+ + '66'
+ + '1'
+ + 'QCCSID'
+ + '0'
+ + '0'
+ + '';
+
+ expect(pgm.toXML()).to.equal(expectedXML);
+ });
+ });
+
+
+ describe('addReturn', () => {
+ it('appends return to pgm xml', () => {
+ const pgm = new iPgm('QTOCNETSTS',
+ {
+ lib: 'QSYS',
+ func: 'QtoRtvTCPA',
+ error: 'fast',
+ });
+
+ pgm.addReturn('0', '20A');
+
+ const expectedXML = '0';
+
+ expect(pgm.toXML()).to.equal(expectedXML);
+ });
+ });
+});
diff --git a/test/unit/iSqlUnit.js b/test/unit/iSqlUnit.js
new file mode 100644
index 00000000..75ad7217
--- /dev/null
+++ b/test/unit/iSqlUnit.js
@@ -0,0 +1,260 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+/* eslint-disable new-cap */
+
+const { expect } = require('chai');
+const { iSql } = require('../../lib/itoolkit');
+
+describe('iSql Class Unit Tests', () => {
+ describe('constructor', () => {
+ it('creates returns an instance of iSql', () => {
+ const sql = new iSql();
+
+ expect(sql).to.be.instanceOf(iSql);
+ });
+ });
+ describe('toXML', () => {
+ it('returns current sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('addQuery', () => {
+ it('appends query to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'select * from QIWS.QCUSTCDT';
+
+ sql.addQuery('select * from QIWS.QCUSTCDT', { error: 'on' });
+
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('fetch', () => {
+ it('appends fetch to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+
+ sql.fetch();
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('commit', () => {
+ it('appends commit to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+
+ sql.commit({ action: 'commit' });
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('prepare', () => {
+ it('appends prepare to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'SELECT * FROM QIWS.QCUSTCDT WHERE BALDUE > ?';
+
+ sql.prepare('SELECT * FROM QIWS.QCUSTCDT WHERE BALDUE > ?');
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+
+ describe('execute', () => {
+ it('appends execute to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '30';
+
+ sql.execute([[30, 'in']]);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('connect', () => {
+ it('appends connect to sql XML', () => {
+ const sql = new iSql();
+
+
+ const expectedXML = '';
+
+ sql.connect({ db: 'local', uid: 'me', pwd: 'mypass' });
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('setOptions', () => {
+ it('appends options to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+
+ sql.setOptions([{ desc: 'autocommit', value: 'on' },
+ { desc: 'naming', value: 'system' }]);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('tables', () => {
+ it('appends tables to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QIWS';
+ // catalog, schema, table, table type
+ sql.tables(['', 'QIWS', '', '']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('tablePriv', () => {
+ it('appends tablepriv to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QIWSQCUSTCDT';
+ // catalog, schema, table
+ sql.tablePriv(['', 'QIWS', 'QCUSTCDT']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('columns', () => {
+ it('appends columns to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QIWSQCUSTCDT';
+ // catalog, schema, table, column
+ sql.columns(['', 'QIWS', 'QCUSTCDT', '']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('columnPriv', () => {
+ it('appends columnpriv to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QIWSQCUSTCDT';
+ // catalog, schema, table, column
+ sql.columnPriv(['', 'QIWS', 'QCUSTCDT', '']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('procedures', () => {
+ it('appends procedures to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QSYS2TCPIP_INFO';
+ // catalog, schema, procedure
+ sql.procedures(['', 'QSYS2', 'TCPIP_INFO']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('pColumns', () => {
+ it('appends pColumns to sql XML', () => {
+ // procedure columns:
+
+ const sql = new iSql();
+
+ const expectedXML = 'QSYS2QCMDEXCCOMMAND';
+ // catalog, schema, procedure, column
+ sql.pColumns(['', 'QSYS2', 'QCMDEXC', 'COMMAND']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('primaryKeys', () => {
+ it('appends primarykeys to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QUSRSYSQASZRAIRX';
+ // catalog, schema, table
+ sql.primaryKeys(['', 'QUSRSYS', 'QASZRAIRX']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('foreignKeys', () => {
+ it('appends foreignkeys to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QUSRSYSQASZRAIRCQUSRSYSQASZRAIRX';
+
+ // pk: catalog, schema, table
+ // fk: catalog, schema, table
+ sql.foreignKeys(['', 'QUSRSYS', 'QASZRAIRC', '', 'QUSRSYS', 'QASZRAIRX']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('statistics', () => {
+ it('appends statistics to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QIWSQCUSTCDTall';
+ // catalog, schema, table, all | unique
+ sql.statistics(['', 'QIWS', 'QCUSTCDT', 'all']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('special', () => {
+ it('appends special to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = 'QIWSQCUSTCDTrowno';
+ // catalog, schema, table, row | transaction | session, no | unique
+ sql.special(['', 'QIWS', 'QCUSTCDT', 'row', 'no']);
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('count', () => {
+ it('appends count to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+ // catalog, schema, table, all | unique
+ sql.count({ desc: 'both' });
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('rowCount', () => {
+ it('appends rowcount to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+ // catalog, schema, table, all | unique
+ sql.rowCount();
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('free', () => {
+ it('appends free to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+ // catalog, schema, table, all | unique
+ sql.free();
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+ describe('describe', () => {
+ it('appends describe to sql XML', () => {
+ const sql = new iSql();
+
+ const expectedXML = '';
+
+ sql.describe({ desc: 'both' });
+ expect(sql.toXML()).to.equal(expectedXML);
+ });
+ });
+});
diff --git a/test/unit/xmlToJsonUnit.js b/test/unit/xmlToJsonUnit.js
new file mode 100644
index 00000000..baa9f224
--- /dev/null
+++ b/test/unit/xmlToJsonUnit.js
@@ -0,0 +1,204 @@
+// Copyright (c) International Business Machines Corp. 2019
+// All Rights Reserved
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+// associated documentation files (the "Software"), to deal in the Software without restriction,
+// including without limitation the rights to use, copy, modify, merge, publish, distribute,
+// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+/* eslint-env mocha */
+
+const { expect } = require('chai');
+const { xmlToJson } = require('../../lib/itoolkit');
+
+describe('xmlToJson Tests', () => {
+ it('converts CL command XML output to js object', () => {
+ const xmlOut = ''
+ + '+++ success RTVJOBA USRLIBL(?) SYSLIBL(?)'
+ + 'QGPL QTEMP QDEVELOP QBLDSYS'
+ + ' QBLDSYSR
QSYS'
+ + ' QSYS2 QHLPSYS QUSRSYS
';
+
+ const result = xmlToJson(xmlOut);
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0]).to.be.an('object');
+ expect(result[0]).to.haveOwnProperty('type').and.to.equal('cmd');
+ const cmd = 'RTVJOBA USRLIBL(?) SYSLIBL(?)';
+ expect(result[0]).to.haveOwnProperty('cmd').and.to.equal(cmd);
+ expect(result[0]).to.haveOwnProperty('data');
+ expect(result[0].data).to.be.an('array');
+ expect(result[0].data.length).to.equal(2);
+ expect(result[0].data[0]).to.be.an('object');
+ const name = 'USRLIBL';
+ expect(result[0].data[0]).to.haveOwnProperty('name').and.to.equal(name);
+ const value = 'QGPL QTEMP QDEVELOP QBLDSYS QBLDSYSR';
+ expect(result[0].data[0]).to.haveOwnProperty('value').and.to.equal(value);
+ });
+
+ it('converts sh command XML output to js object', () => {
+ const xmlOut = '\n'
+ + 'bin\n'
+ + 'ccs\n'
+ + 'icu4c\n'
+ + 'includ\n'
+ + 'lbin\n'
+ + 'lib\n'
+ + 'lib64\n'
+ + 'lpp\n'
+ + 'sbin\n'
+ + 'share\n'
+ + 'vacpp\n'
+ + '\n'
+ + '';
+
+ const result = xmlToJson(xmlOut);
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0]).to.be.an('object');
+ expect(result[0]).to.haveOwnProperty('type').and.to.equal('sh');
+ const data = '\nbin\nccs\nicu4c\ninclud\nlbin\nlib\nlib64\nlpp\nsbin\n'
+ + 'share\nvacpp\n';
+ expect(result[0]).to.haveOwnProperty('data').and.to.equal(data);
+ });
+
+
+ it('converts qsh command XML output to js object', () => {
+ const xmlOut = '\n'
+ + 'bin\n'
+ + 'ccs\n'
+ + 'icu4c\n'
+ + 'includ\n'
+ + 'lbin\n'
+ + 'lib\n'
+ + 'lib64\n'
+ + 'lpp\n'
+ + 'sbin\n'
+ + 'share\n'
+ + 'vacpp\n'
+ + '\n'
+ + '';
+
+ const result = xmlToJson(xmlOut);
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0]).to.be.an('object');
+ expect(result[0]).to.haveOwnProperty('type').and.to.equal('qsh');
+ const data = '\nbin\nccs\nicu4c\ninclud\nlbin\nlib\nlib64\nlpp\nsbin\n'
+ + 'share\nvacpp\n';
+ expect(result[0]).to.haveOwnProperty('data').and.to.equal(data);
+ });
+
+ it('converts pgm command XML output to js object', () => {
+ const xmlOut = `
+
+
+ 1
+ 8
+ QCENTURY
+ C
+
+ 1
+ 1
+
+
+
+ 28
+
+
+ 1
+
+
+ QCENTURY
+
+
+
+ 0
+ 16
+
+
+
+
+
+
+ `;
+
+ const result = xmlToJson(xmlOut);
+
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0]).to.be.an('object');
+ expect(result[0]).to.haveOwnProperty('type').and.to.equal('pgm');
+ expect(result[0]).to.haveOwnProperty('success').and.to.equal(true);
+ expect(result[0]).to.haveOwnProperty('pgm').and.to.equal('QWCRSVAL');
+ expect(result[0]).to.haveOwnProperty('lib').and.to.equal('QSYS');
+ expect(result[0]).to.haveOwnProperty('data');
+ expect(result[0].data).to.be.an('array');
+ expect(result[0].data.length).to.equal(14);
+
+ result[0].data.forEach((part) => {
+ expect(part).to.be.an('object');
+ expect(result[0].data[0]).to.haveOwnProperty('value');
+ expect(result[0].data[0]).to.haveOwnProperty('type');
+ });
+ });
+
+ it('converts sql command XML output to js object', () => {
+ const xmlOut = `
+
+
+
+
+ HenningTX
+ JonesNY
+ VineVT
+ JohnsonGA
+ TyronNY
+ StevensCO
+ AlisonMN
+ DoeCA
+ ThomasWY
+ WilliamsTX
+ LeeNY
+ AbrahamMN
+ +++ success stmt1
+
+ +++ success
+
+
+ `;
+
+ const result = xmlToJson(xmlOut);
+
+ expect(result).to.be.an('array');
+ expect(result.length).to.equal(1);
+ expect(result[0]).to.be.an('object');
+ expect(result[0]).to.haveOwnProperty('type').and.to.equal('sql');
+ expect(result[0]).to.haveOwnProperty('success').and.to.equal(true);
+ const stmt = 'SELECT LSTNAM, STATE FROM QIWS.QCUSTCDT';
+ expect(result[0]).to.haveOwnProperty('stmt').and.to.equal(stmt);
+ expect(result[0]).to.haveOwnProperty('result');
+ expect(result[0].result).to.be.an('array');
+ expect(result[0].result.length).to.equal(12);
+
+ // result is 2D array: each of its element is another array of objects
+ // Propose to simplify for result to be 1D array of objects
+ result[0].result.forEach((childArray) => {
+ expect(childArray).to.be.an('array');
+ childArray.forEach((element) => {
+ expect(element).to.haveOwnProperty('desc');
+ expect(element).to.haveOwnProperty('value');
+ });
+ });
+ });
+});