Skip to content

Commit 163939c

Browse files
committed
Added unit and functional tests
Unit Tests added for - iSh, iQsh, iCmd function (commandsUnit.js) - iConn methods, stubbed out run method - iPgm methods - iSql methods - xmlToJson function Functional tests added for - iDataQueue Class methods - iNetwork Class methods - iObj methods - iPgm methods - iProd methods - iSql methods - iUserSpace methods - iWork methods Removed test.js - Moved functional tests from test.js to the appropriate class test Added utils.js - contains helper function return transports - returns iConn objects intialized to transports - used to dynamically generate functional tests that only differ by iConn object used for transport Added test/README.md - provides instructions to setup and run tests - lists available environment variables to configure tests
1 parent 6aeacf6 commit 163939c

17 files changed

+2858
-226
lines changed

lib/utils.js

Lines changed: 12 additions & 0 deletions
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 };

test/README.md

Lines changed: 89 additions & 0 deletions
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+
Lines changed: 97 additions & 0 deletions
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+
});
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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+
/* eslint-disable new-cap */
21+
22+
const { expect } = require('chai');
23+
const { iConn } = require('../../lib/itoolkit');
24+
const { iDataQueue } = require('../../lib/idataq');
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 lib = 'NODETKTEST'; const dqName = 'TESTQ';
37+
38+
const { returnTransports } = require('../../lib/utils');
39+
40+
const transports = returnTransports(opt);
41+
42+
describe('iDataQueue Functional Tests', () => {
43+
before('setup library for tests and create DQ', async () => {
44+
// eslint-disable-next-line global-require
45+
const { DBPool } = require('idb-pconnector');
46+
47+
const pool = new DBPool({ url: '*LOCAL' }, { incrementSize: 2 });
48+
49+
const qcmdexec = 'CALL QSYS2.QCMDEXC(?)';
50+
51+
const createLib = `CRTLIB LIB(${lib}) TYPE(*TEST) TEXT('Used to test Node.js toolkit')`;
52+
53+
const createDQ = `CRTDTAQ DTAQ(${lib}/${dqName}) MAXLEN(100) AUT(*EXCLUDE) TEXT('TEST DQ FOR NODE TOOLKIT TESTS')`;
54+
55+
const findLib = 'SELECT SCHEMA_NAME FROM qsys2.sysschemas WHERE SCHEMA_NAME = \'NODETKTEST\'';
56+
57+
const findDQ = 'SELECT OBJLONGNAME FROM TABLE (QSYS2.OBJECT_STATISTICS(\'NODETKTEST\', \'*DTAQ\')) AS X';
58+
59+
const libResult = await pool.runSql(findLib);
60+
61+
const dqResult = await pool.runSql(findDQ);
62+
63+
if (!libResult.length) {
64+
await pool.prepareExecute(qcmdexec, [createLib]).catch((error) => {
65+
// eslint-disable-next-line no-console
66+
console.log('Unable to Create Lib!');
67+
throw error;
68+
});
69+
// eslint-disable-next-line no-console
70+
console.log('CREATED LIB!');
71+
}
72+
if (!dqResult.length) {
73+
await pool.prepareExecute(qcmdexec, [createDQ]).catch((error) => {
74+
// eslint-disable-next-line no-console
75+
console.log('Unable to Create DQ!');
76+
throw error;
77+
});
78+
// eslint-disable-next-line no-console
79+
console.log('CREATED DQ!');
80+
}
81+
});
82+
describe('constructor', () => {
83+
it('creates and returns an instance of iDataQueue', () => {
84+
const connection = new iConn(opt.database, opt.user, opt.password);
85+
86+
const dq = new iDataQueue(connection);
87+
expect(dq).to.be.instanceOf(iDataQueue);
88+
});
89+
});
90+
91+
describe('sendToDataQueue', () => {
92+
transports.forEach((transport) => {
93+
it(`sends data to specified DQ using ${transport.name} transport`, (done) => {
94+
const connection = transport.me;
95+
96+
const dq = new iDataQueue(connection);
97+
98+
dq.sendToDataQueue(dqName, lib, 'Hello from DQ!', (output) => {
99+
expect(output).to.equal(true);
100+
done();
101+
});
102+
});
103+
});
104+
});
105+
106+
describe('receiveFromDataQueue', () => {
107+
transports.forEach((transport) => {
108+
it(`receives data from specfied DQ using ${transport.name} transport`, (done) => {
109+
const connection = transport.me;
110+
111+
const dq = new iDataQueue(connection);
112+
113+
dq.receiveFromDataQueue(dqName, lib, 100, (output) => {
114+
expect(output).to.be.a('string').and.to.equal('Hello from DQ!');
115+
done();
116+
});
117+
});
118+
});
119+
});
120+
121+
describe('clearDataQueue', () => {
122+
transports.forEach((transport) => {
123+
it(`clears the specifed DQ using ${transport.name} transport`, (done) => {
124+
const connection = transport.me;
125+
126+
const dq = new iDataQueue(connection);
127+
128+
dq.clearDataQueue(dqName, lib, (output) => {
129+
expect(output).to.equal(true);
130+
done();
131+
});
132+
});
133+
});
134+
});
135+
});

0 commit comments

Comments
 (0)