Skip to content

Commit 3df623d

Browse files
authored
Merge pull request #34 from abmusse/addTests
Add Unit and Functional Tests
2 parents 6aeacf6 + 85a2e54 commit 3df623d

21 files changed

+2891
-241
lines changed

lib/iprod.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -168,20 +168,25 @@ class iProd {
168168
];
169169
if(!cb) { // If we do not get the third param,
170170
if(option) { // If we get two params,
171-
if(xt.getClass(option) == "Function") // If it is a function,
171+
if(xt.getClass(option) == "Function"){ // If it is a function,
172172
cb = option; // then it is the callback.
173+
option = "0000";
174+
}
173175
}
174176
else { // If we have only one param,
175177
option = "0000"; // then use *BASE as default.
176178
}
177179

178180
}
179-
if(option < 0 || option > 99)
180-
option = "0000";
181-
else if(option < 10)
182-
option = "000" + option;
183-
else option = "00" + option;
184-
181+
if(Number.isInteger(option)) {
182+
if(option < 0 || option > 99)
183+
option = "0000";
184+
else if(option < 10)
185+
option = "000" + option;
186+
else
187+
option = "00" + option;
188+
}
189+
185190
let ProdInfo = [
186191
[prodID, "7A"],
187192
["*ONLY", "6A"],

lib/itoolkit.js

+14-5
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,14 @@ const xmlToJson = (xml) => {
137137
let sucFlag = sqlData[i].match(successReg);
138138
if(sucFlag && sucFlag.length > 0) {
139139
rs.success = true;
140-
if(sucFlag.length > 1)
141-
rs.stmt = sucFlag[1];
140+
if(sucFlag.length > 1){
141+
if(sucFlag[0].includes('![CDATA')){
142+
let fixed = sucFlag[1].replace(/]]>/, '');
143+
rs.stmt = fixed;
144+
} else{
145+
rs.stmt = sucFlag[1];
146+
}
147+
}
142148
}
143149
else {
144150
rs.success = false;
@@ -224,7 +230,7 @@ class iConn {
224230
}
225231
// setTimeout() override the default timeout value for sync mode.
226232
setTimeout(seconds) {
227-
if(__getClass(flag) == "Number")
233+
if(__getClass(seconds) == "Number")
228234
this.timeout = seconds * 1000;
229235
}
230236
// debug() get current verbose mode or enable/disable verbose mode for debugging.
@@ -535,11 +541,14 @@ class iSql {
535541
}
536542

537543
rowCount(options) {
538-
this.xml += i_xml.iXmlNodeSqlRowCount(options.action, options.error);
544+
if(options && options.error)
545+
this.xml += i_xml.iXmlNodeSqlRowCount(options.error);
546+
else
547+
this.xml += i_xml.iXmlNodeSqlRowCount();
539548
}
540549

541550
count(options) {
542-
this.xml += i_xml.iXmlNodeSqlRowCount(options.desc, options.error);
551+
this.xml += i_xml.iXmlNodeSqlCount(options.desc, options.error);
543552
}
544553

545554
describe(options) {

lib/ixml.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ const iXmlNodeSqlConnect = (db, uid, pwd, option_label) => {
289289
}
290290

291291
const iXmlNodeSqlOptions = (options) => {
292-
const iXml = iXmlNodeOpen(I_XML_NODE_SQL_OPTIONS_OPEN);
292+
let iXml = iXmlNodeOpen(I_XML_NODE_SQL_OPTIONS_OPEN);
293293
for(const i in options)
294294
iXml += iXmlAttrDefault(options[i].desc, options[i].value, I_XML_ATTR_VALUE_OPTIONAL);
295295
return iXml + I_XML_NODE_CLOSE + I_XML_NODE_SQL_OPTIONS_CLOSE;
@@ -332,7 +332,7 @@ const iXmlNodeSqlExecuteClose = () => {
332332

333333
const iXmlNodeSqlParmOpen = (xio) => {
334334
return iXmlNodeOpen(I_XML_NODE_PARM_OPEN)
335-
+ iXmlAttrDefault(I_XML_ATTR_KEY_NAME,xio,I_XML_ATTR_VALUE_OPTIONAL)
335+
+ iXmlAttrDefault(I_XML_ATTR_KEY_IO,xio,I_XML_ATTR_VALUE_OPTIONAL)
336336
+ I_XML_NODE_CLOSE;
337337
}
338338

lib/utils.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* eslint-disable new-cap */
2+
const { iConn } = require('./itoolkit.js');
3+
4+
function returnTransports(opt) {
5+
const transports = [{ name: 'idb', me: new iConn(opt.database, opt.user, opt.password) },
6+
{ name: 'rest', me: new iConn(opt.database, opt.user, opt.password, opt) },
7+
];
8+
9+
return transports;
10+
}
11+
12+
module.exports = { returnTransports };

package.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@
3838
],
3939
"devDependencies": {
4040
"chai": "^4.1.2",
41+
"mocha": "^5.2.0",
42+
"sinon": "^7.2.3"
43+
},
44+
"optionalDependencies": {
4145
"idb-connector": "^1.1.8",
42-
"mocha": "^5.2.0"
46+
"idb-pconnector": "^1.0.2"
4347
}
4448
}

test/README.md

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Node.js Toolkit Tests
2+
3+
Ensure dependencies are installed
4+
5+
From the root of the project run: `npm install`
6+
7+
***NOTE***
8+
9+
Some tests require creating libraries, objects, tables, etc.
10+
11+
A before hook is setup to check for theses objects and create if needed.
12+
13+
These hooks are ran with `idb-pconnector` which requires to be run on IBM i.
14+
15+
In any case, the functional tests test for both transports Db2 and REST.
16+
17+
Using Db2 transport requires `idb-connector` which only runs on IBM i systems.
18+
19+
Tests using these hooks will fail on non IBM i systems.
20+
21+
# Running Tests
22+
23+
From the project root
24+
25+
`npm test test/foo`
26+
27+
where foo is the name of subdir such as `unit` or or individual test file.
28+
29+
***NOTE***
30+
31+
If you experience timeout issue with network calls add
32+
33+
`"test": "./node_modules/mocha/bin/mocha" --timeout Xs `
34+
35+
within `package.json` file, where X is the number of seconds before timeout
36+
37+
# Setup Rest interface
38+
39+
- add to the default apache server conf: `/www/apachedft/conf/httpd.conf`
40+
41+
```
42+
ScriptAlias /cgi-bin/ /QSYS.LIB/QXMLSERVc .LIB/
43+
<Directory /QSYS.LIB/QXMLSERV.LIB/>
44+
AllowOverride None
45+
order allow,deny
46+
allow from all
47+
SetHandler cgi-script
48+
Options +ExecCGI
49+
</Directory>
50+
51+
```
52+
53+
- start the server
54+
55+
` STRTCPSVR SERVER(*HTTP) HTTPSVR(APACHEDFT)`
56+
57+
- go to `http://HOSTNAME/cgi-bin/xmlcgi.pgm`
58+
59+
you should see an XML document
60+
61+
- when finished testing you can shutdown server with
62+
63+
` ENDTCPSVR SERVER(*HTTP) HTTPSVR(APACHEDFT)`
64+
65+
66+
# Configuring Tests
67+
Each functional test contains an config object that is used to create connections
68+
69+
It is recommend to setup environment variables for these configurations
70+
71+
Instead of hard coding credentials with the test file.
72+
73+
you can set environment varaibales with `export KEY='value'`
74+
75+
---
76+
- user `TKUSER` defaults to ''
77+
78+
- password `TKPASS` defaults to ''
79+
80+
- database `TKDB` defaults to `*LOCAL`
81+
82+
For Rest Tests
83+
---
84+
- HOST `TKHOST` defaults to `localhost`
85+
86+
- PORT `TKPORT` defaults to `80`
87+
88+
- PATH `TKPATH` defaults to `/cgi-bin/xmlcgi.pgm`
89+

test/functional/commandsFunctional.js

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) International Business Machines Corp. 2019
2+
// All Rights Reserved
3+
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5+
// associated documentation files (the "Software"), to deal in the Software without restriction,
6+
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
7+
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
10+
// The above copyright notice and this permission notice shall be included in all copies or
11+
// substantial portions of the Software.
12+
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14+
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18+
19+
/* eslint-env mocha */
20+
21+
const { expect } = require('chai');
22+
const {
23+
iCmd, iSh, iQsh, xmlToJson,
24+
} = require('../../lib/itoolkit');
25+
26+
// Set Env variables or set values here.
27+
const opt = {
28+
database: process.env.TKDB || '*LOCAL',
29+
user: process.env.TKUSER || '',
30+
password: process.env.TKPASS || '',
31+
host: process.env.TKHOST || 'localhost',
32+
port: process.env.TKPORT || 80,
33+
path: process.env.TKPATH || '/cgi-bin/xmlcgi.pgm',
34+
};
35+
36+
const { returnTransports } = require('../../lib/utils');
37+
38+
const transports = returnTransports(opt);
39+
40+
describe('iSh, iCmd, iQsh, Functional Tests', () => {
41+
describe('iCmd()', () => {
42+
transports.forEach((transport) => {
43+
it(`calls CL command using ${transport.name} transport`, (done) => {
44+
const connection = transport.me;
45+
connection.add(iCmd('RTVJOBA USRLIBL(?) SYSLIBL(?)'));
46+
connection.run((xmlOut) => {
47+
const results = xmlToJson(xmlOut);
48+
results.forEach((result) => {
49+
expect(result.success).to.equal(true);
50+
});
51+
done();
52+
});
53+
});
54+
});
55+
});
56+
57+
describe('iSh()', () => {
58+
transports.forEach((transport) => {
59+
it(`calls PASE shell command using ${transport.name} transport`, (done) => {
60+
const connection = transport.me;
61+
62+
connection.add(iSh('system -i wrksyssts'));
63+
connection.run((xmlOut) => {
64+
const results = xmlToJson(xmlOut);
65+
// xs does not return success property for iSh or iQsh
66+
// but on error data property = '\n'
67+
// so lets base success on contents of data.
68+
results.forEach((result) => {
69+
expect(result.data).not.to.equal('\n');
70+
expect(result.data).to.match(/(System\sStatus\sInformation)/);
71+
});
72+
done();
73+
});
74+
});
75+
});
76+
});
77+
78+
describe('iQsh()', () => {
79+
transports.forEach((transport) => {
80+
it(`calls QSH command using ${transport.name} transport`, (done) => {
81+
const connection = transport.me;
82+
connection.add(iQsh('system wrksyssts'));
83+
connection.run((xmlOut) => {
84+
const results = xmlToJson(xmlOut);
85+
// xs does not return success property for iSh or iQsh
86+
// but on error data property = '\n'
87+
// so lets base success on contents of data.
88+
results.forEach((result) => {
89+
expect(result.data).not.to.equal('\n');
90+
expect(result.data).to.match(/(System\sStatus\sInformation)/);
91+
});
92+
done();
93+
});
94+
});
95+
});
96+
});
97+
});

0 commit comments

Comments
 (0)