From 3b92106937459878be65d592d7ba76f6e46d4f69 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:14:09 -0500 Subject: [PATCH] test: cleanup infrastructure --- test/asyncStatementTest.js | 297 ++++++++++++++++++----------- test/failTests.js | 373 ------------------------------------- test/statementTest.js | 86 +++++++-- test/syncStatementTest.js | 184 +++++++++++------- 4 files changed, 378 insertions(+), 562 deletions(-) delete mode 100644 test/failTests.js diff --git a/test/asyncStatementTest.js b/test/asyncStatementTest.js index 6766474..a2bd202 100644 --- a/test/asyncStatementTest.js +++ b/test/asyncStatementTest.js @@ -2,28 +2,95 @@ const { expect } = require('chai'); const db2a = require('../lib/db2a'); const { - OUT, IN, CHAR, CLOB, NUMERIC, dbstmt, dbconn, + OUT, IN, CHAR, CLOB, NUMERIC, INT, dbstmt, dbconn, } = db2a; +const schema = 'IDBTEST'; +const table = 'SCORES'; +const selectSchema = `SELECT SCHEMA_NAME FROM QSYS2.sysschemas WHERE SCHEMA_NAME = '${schema}'`; +const createSchema = `CREATE SCHEMA ${schema}`; +const createTable = `CREATE OR REPLACE TABLE ${schema}.${table}(team CHAR(10), score INTEGER)`; +const insertTable = `INSERT INTO ${schema}.${table}(TEAM,SCORE) VALUES (?,?)` +const countTeams = `SELECT COUNT(TEAM) as TEAMCOUNT FROM ${schema}.${table}`; +const dropTable = `DROP TABLE ${schema}.${table}`; + // Test Statement Class Async Methods -describe('Statement Async Test', () => { +describe('Statement Async Test', function () { + // global connection and statement that will be used for test cases + // dbConn is initialized in before hook and destoryed in after hook + // dbStmt is initialized in beforeEach hook and destoryed in afterEach hook var dbConn, dbStmt; - before(() => { - dbConn = new dbconn(); - dbConn.conn('*LOCAL'); - }); + function cleanup(connection, statement) { + statement.close(); + connection.disconn(); + connection.close(); + } + + before('setup schema for tests', function (done) { + // setup the test infrastructure + this.timeout(0); // disbale timeout for hook + const connection = new dbconn(); + connection.conn('*LOCAL'); + const statement = new dbstmt(connection); + statement.exec(selectSchema, (schemaResult, schemaError) => { + if (schemaError){ + cleanup(connection, statement); + done(schemaError); + return; + } + const rc = statement.closeCursor(); + if (!schemaResult.length) { + statement.exec(createSchema, (createSchemaResult, createSchemaError) => { + if (createSchemaError) { + cleanup(connection, statement); + done(createSchemaError); + return; + } + }); + } + statement.exec(createTable, (createTableResult, createTableError) => { + if (createTableError) { + cleanup(connection, statement); + done(createTableError); + return; + } + cleanup(connection, statement); + // create connection that will be used in all the later test cases + dbConn = new dbconn(); + dbConn.conn('*LOCAL'); + done(); + }); + }); + }); - after(() => { + after('drop objects after the tests', function (done) { + // close connection used in thetest cases dbConn.disconn(); dbConn.close(); + // tear down test infrastructure + this.timeout(0); // disable timeout for hook + const connection = new dbconn(); + connection.conn('*LOCAL'); + const statement = new dbstmt(connection); + statement.exec(dropTable, (dropTableResult, dropTableError) => { + if (dropTableError){ + cleanup(connection, statement); + done(dropTableError); + return; + } + cleanup(connection, statement); + done(); + }); }); - beforeEach(() => { + // create a new statement before each test case + beforeEach( function () { dbStmt = new dbstmt(dbConn); }); - afterEach(() => { + // close the statement after each test case + afterEach(function () { dbStmt.close(); }); @@ -32,7 +99,8 @@ describe('Statement Async Test', () => { const sql = 'SELECT * FROM QIWS.QCUSTCDT'; dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; done(); @@ -42,55 +110,50 @@ describe('Statement Async Test', () => { describe('async bindParams (2-D array)', () => { it('associate parameter markers in an SQL statement to app variables', (done) => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); const params = [ - [9997, IN, NUMERIC], // CUSNUM - ['Doe', IN, CHAR], // LASTNAME - ['J D', IN, CHAR], // INITIAL - ['123 Broadway', IN, CHAR], // ADDRESS - ['Hope', IN, CHAR], // CITY - ['WA', IN, CHAR], // STATE - [98101, IN, NUMERIC], // ZIP - [2000, IN, NUMERIC], // CREDIT LIMIT - [1, IN, NUMERIC], // change - [250, IN, NUMERIC], // BAL DUE - [0.00, IN, NUMERIC], // CREDIT DUE + ['TEST', IN, CHAR], // TEAM + [100, IN, INT], // SCORE ]; - dbStmt.exec('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT', (result, error) => { + dbStmt.exec(countTeams, (result, error) => { if (error) { - throw error; + done(error); + return; } - let rowsBefore = result[0]['00001']; + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); dbStmt.close(); - dbStmt2.prepare(sql, (error) => { + dbStmt2.prepare(insertTable, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt2.bindParam(params, (error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.close(); dbStmt = new dbstmt(dbConn); - dbStmt.exec('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT', + dbStmt.exec(countTeams, (result, error) => { if (error) { - throw error; + done(error); + return; } - let rowsAfter = result[0]['00001']; + let rowsAfter = result[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); expect(rowsAfter).to.equal(rowsBefore + 1); done(); @@ -104,43 +167,48 @@ describe('Statement Async Test', () => { describe('async bindParams (1-D array)', () => { it('associate parameter markers in an SQL statement to app variables', (done) => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); - const params = [9997, 'Doe', 'J D', '123 Broadway', 'Hope', 'WA', 98101, 2000, 1, 250, 0.00]; + const params = ['TEST2', 200]; - dbStmt.exec('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT', (result, error) => { + dbStmt.exec(countTeams, (result, error) => { if (error) { - throw error; + done(error); + return; } - let rowsBefore = result[0]['00001']; + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); dbStmt.close(); - dbStmt2.prepare(sql, (error) => { + dbStmt2.prepare(insertTable, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt2.bindParam(params, (error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.close(); + dbConn2.close(); dbStmt = new dbstmt(dbConn); - dbStmt.exec('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT', + dbStmt.exec(countTeams, (result, error) => { if (error) { - throw error; + done(error); + return; } - let rowsAfter = result[0]['00001']; + let rowsAfter = result[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); expect(rowsAfter).to.equal(rowsBefore + 1); done(); @@ -151,48 +219,36 @@ describe('Statement Async Test', () => { }); }); it("should insert spaces into CHAR columns when given a Javascript empty-string.", done => { - const sql = ` - INSERT INTO QIWS.QCUSTCDT ( - CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE - ) - VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE `; const dbConn2 = new dbconn(); dbConn2.conn("*LOCAL"); const dbStmt2 = new dbstmt(dbConn2); - const params = [ - 9998, - "", - "", - "123 Broadway", - "Hope", - "WA", - 98101, - 2000, - 1, - 250, - 0.0, - ]; - dbStmt2.prepare(sql, error => { + const params = ["", 0 ]; + + dbStmt2.prepare(insertTable, error => { if (error) { - throw error; + done(error); + return; } dbStmt2.bindParameters(params, error => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.close(); dbStmt = new dbstmt(dbConn); dbStmt.exec( - "SELECT q.*, hex(lstnam) AS hexlstnam FROM QIWS.QCUSTCDT q where q.lstnam = ' '", + `SELECT q.*, hex(TEAM) AS hexteam FROM ${schema}.${table} q where q.TEAM = ' '`, (result, error) => { if (error) { - throw error; + done(error); + return; } const rowsSelected = Number(result.length); @@ -208,43 +264,45 @@ describe('Statement Async Test', () => { describe('async bindParameters (1-D array)', () => { it('associate parameter markers in an SQL statement to app variables', (done) => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); - - const params = [9997, 'Doe', 'J D', '123 Broadway', 'Hope', 'WA', 98101, 2000, 1, 250, 0.00]; - - dbStmt.exec('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT', (result, error) => { + const params = ['TEST3', 300]; + dbStmt.exec(countTeams, (result, error) => { if (error) { - throw error; + done(error); + return; } - let rowsBefore = result[0]['00001']; + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); dbStmt.close(); - dbStmt2.prepare(sql, (error) => { + dbStmt2.prepare(insertTable, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt2.bindParameters(params, (error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; dbStmt2.close(); dbStmt = new dbstmt(dbConn); - dbStmt.exec('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT', + dbStmt.exec(countTeams, (result, error) => { if (error) { - throw error; + done(error); + return; } - let rowsAfter = result[0]['00001']; + let rowsAfter = result[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); expect(rowsAfter).to.equal(rowsBefore + 1); done(); @@ -272,15 +330,18 @@ describe('Statement Async Test', () => { dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.bindParam(params, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(out).to.be.a('array'); @@ -299,15 +360,18 @@ describe('Statement Async Test', () => { dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.bindParam(params, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(out).to.be.null; @@ -329,15 +393,18 @@ describe('Statement Async Test', () => { dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.bindParam(params, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(out).to.be.a('array'); @@ -354,15 +421,18 @@ describe('Statement Async Test', () => { dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.bindParam(params, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(out).to.be.a('array'); @@ -385,15 +455,18 @@ describe('Statement Async Test', () => { dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.bindParameters(params, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(out).to.be.a('array'); @@ -410,15 +483,18 @@ describe('Statement Async Test', () => { dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.bindParameters(params, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(out).to.be.a('array'); @@ -435,7 +511,8 @@ describe('Statement Async Test', () => { const sql = 'SELECT * FROM QIWS.QCUSTCDT'; dbStmt.exec(sql, (result, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(result).to.be.an('array'); @@ -450,15 +527,18 @@ describe('Statement Async Test', () => { const sql = 'SELECT * FROM QIWS.QCUSTCDT'; dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } dbStmt.fetchAll((result, error) => { if (error) { - throw error; + done(error); + return; } expect(error).to.be.null; expect(result).to.be.a('array'); @@ -476,15 +556,18 @@ describe('Statement Async Test', () => { const sql = 'SELECT * FROM QIWS.QCUSTCDT'; dbStmt.prepare(sql, (error) => { if (error) { - throw error; + done(error); + return; } dbStmt.execute((out, error) => { if (error) { - throw error; + done(error); + return; } dbStmt.fetch((row, returnCode) => { if (returnCode !== 0) { // SQL_SUCCESS - throw new Error('Rreturn Code was Not SQL SUCESS'); + done(new Error('Rreturn Code was Not SQL SUCESS')); + return; } expect(returnCode).to.equal(0); expect(row).to.be.a('object'); diff --git a/test/failTests.js b/test/failTests.js deleted file mode 100644 index f1ef298..0000000 --- a/test/failTests.js +++ /dev/null @@ -1,373 +0,0 @@ -const {assert} = require('chai'); -const {expect} = require('chai'); -const addon = require('bindings')('db2ia'); -const util = require('util'); -const db2a = require('../lib/db2a'); - -// // Test Connection Class - -// describe('validStmtFail', () => { -// it('error caused by providing invalid SQL as a param', () => { -// const sql = 'garbageInput'; -// const dbConn = new addon.DbConn(); -// const result = dbConn.validStmt(); -// console.log(`Valid Stmt output: ${result}`); -// expect(result).to.be.a('string'); -// }); -// }); - -// describe('getConnAttrFail', () => { -// it('error caused by providing invalid attr as a param', () => { -// const attr = 50; -// const dbConn = new addon.DbConn(); -// const result = dbConn.getConnAttr(attr); -// console.log(`Attrubte:: ${result}`); -// expect(result).to.satisfy((result) => { -// return result === 'string' || typeof result === 'number'; -// }); -// }); -// }); - -// describe('setConnAttrFail', () => { -// it('error caused by providing invlaid attr and value params', () => { -// const attr = ''; -// const value = -5; -// const dbConn = new addon.DbConn(); -// const result = dbConn.setConnAttr(attr, value); -// expect(result).to.be.a('undefined'); -// }); -// }); - -// describe('debugFail', () => { -// it('error caused by using invalid param type instead of a boolean', () => { -// const choice = 1; -// const dbConn = new addon.DbConn(); -// const result = dbConn.debug('choice'); -// expect(result).to.be.a('undefined'); -// }); -// }); - -// // need to create a Failure Case for disconn() -// describe('disconnFail', () => { -// it('error caused by calling disconn before Conn was established ', () => { -// const dbConn = new addon.Connection().constructor(); -// const result = dbConn.disconn(); -// expect(result).to.be.a('undefined'); -// }); -// }); - -// // need to create a Failure Case for close() -// describe('closeFail' , () => { -// it('error caused by calling close before Conn was established. ', () => { -// // const dbConn = new addon.DbConn(); -// const result = dbConn.close(); -// expect(result).to.be.a('undefined'); -// }); -// }); - -// // need to test the conn method - -// // Test Statement Class - -// describe('prepareFail', () => { -// it('error caused by preparing invalid SQL as a param', () => { -// const sql = 'SELECT * '; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// const result = dbStmt.prepare(sql); -// expect(result).to.be.a('undefined'); -// }); -// }); - -// // if successful returns undefined. - - -// describe('bindParamsFail', () => { -// it('error caused by not providing correct params within the params[]', () => { -// const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// const result = dbStmt.bindParam([ -// [1, addon.SQL_PARAM_INPUT, addon.SQL_NUMERIC], // change -// [250, addon.SQL_PARAM_INPUT, addon.SQL_NUMERIC], // BAL DUE -// ]); -// dbStmt.execute(); -// expect(result).to.be.a('undefined'); -// }); -// }); - - -// describe('closeFail' , () => { -// it('error caused by calling close before statement was executed. ', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbStmt = new addon.Connection().connect().getStatement(); -// // dbStmt.exec(sql); -// const result = dbStmt.close(); -// expect(result).to.be.a('undefined'); -// }); -// }); - - -// describe('closeCursorFail' , () => { -// it('error caused by calling closeCursor before statement was executed. ', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbStmt = new addon.Connection().connect().getStatement(); -// // dbStmt.exec(sql); -// const result = dbStmt.closeCursor(); -// expect(result).to.be.a('undefined'); -// }); -// }); - - -// // need to create a Failure Case for commit() -// describe('commitFail' , () => { -// it('error caused by calling commit before statement was executed. ', () => { -// const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; -// const dbStmt = new addon.Connection().connect().getStatement(); -// dbStmt.prepare(sql); -// let result = dbStmt.bindParam([ [4234,addon.PARM_TYPE_INPUT,2], ['sublime', addon.PARM_TYPE_INPUT, 1] ]); -// // dbStmt.execute(); -// result = dbStmt.commit(); -// expect(result).to.be.a('undefined'); -// }); -// }); - - -// describe('execFail', () => { -// it('error caused by calling exec without params', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// const result = dbStmt.exec(); -// assert.isNotObject(result, 'object was not returned'); -// console.log(`Type of result = ${typeof result}`); -// console.log(`Select results: ${JSON.stringify(result)}`); -// expect(result).to.be.an('array'); -// }); -// }); - - -// describe('executeFail', () => { -// it('error caused by calling execute before statement was prepared.', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// // dbStmt.prepare(sql); -// const result = dbStmt.execute(); -// console.log(`Select results: ${JSON.stringify(result)}`); -// console.log(`Size of the returned array:${result.length}`); -// expect(result).to.be.a('array'); -// }); -// }); - - -// describe('fetchAllFail', () => { -// it('error caused by calling fetchAll before results were available', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// // dbStmt.execute(); -// const result = dbStmt.fetchAll(); -// console.log(`Select results: ${JSON.stringify(result)}`); -// expect(result).to.be.a('array'); -// }); -// }); - - -// describe('fetchFail', () => { -// it('error caused by calling fetch before results were available', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// // dbStmt.execute(); -// const result = dbStmt.fetch(); -// console.log(`Select results: ${JSON.stringify(result)}`); -// expect(result).to.be.a('object'); -// }); -// }); - -// describe('numFieldsFail', () => { -// it('error caused by calling numFields before results were available.', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// // dbStmt.execute(); -// const fields = dbStmt.numFields(); -// console.log(`Number of Fields: ${fields}`); -// expect(fields).to.be.a('number'); -// }); -// }); - -// describe('numRowsFail', () => { -// it('error caused by calling numRows before results were available.', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// // dbStmt.execute(); -// const rows = dbStmt.numRows(); -// console.log(`Number of Rows: ${rows}`); -// expect(rows).to.be.a('number'); -// }); -// }); - -// describe('fieldTypeFail', () => { -// it('error caused by not providing an index as a param', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// dbStmt.execute(); -// const col1 = dbStmt.fieldType(); -// const col2 = dbStmt.fieldType(); -// console.log(`column 1 fieldType = : ${col1}`); -// console.log(`column 2 fieldType = : ${col2}`); -// expect(col1).to.be.a('number'); -// expect(col2).to.be.a('number'); -// }); -// }); - -// describe('fieldWidthFail', () => { -// it('error caused by not providing an index as a param', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// dbStmt.execute(); -// const col1 = dbStmt.fieldWidth(); -// const col2 = dbStmt.fieldWidth(); -// console.log(`column 1 fieldWidth = : ${col1}`); -// console.log(`column 2 fieldWidth = : ${col2}`); -// expect(col1).to.be.a('number'); -// expect(col2).to.be.a('number'); -// }); -// }); - -// describe('fieldNullableFail', () => { -// it('error caused by not providing an index as a param', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// dbStmt.execute(); -// const col1 = dbStmt.fieldNullable(); -// console.log(col1); -// }); -// }); - -// describe('fieldNameFail', () => { -// it('error caused by providing an invalid index as a param', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// dbStmt.execute(); -// const col1 = dbStmt.fieldName('garbageInput'); -// const col2 = dbStmt.fieldName('fake'); -// console.log(`column 1 Name = : ${col1}`); -// console.log(`column 2 Name = : ${col2}`); -// expect(col1).to.be.a('string'); -// expect(col2).to.be.a('string'); -// }); -// }); - -// describe('fieldPreciseFail', () => { -// it('error caused by not providing an index as a param', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// dbStmt.execute(); -// const col1 = dbStmt.fieldPrecise(); -// const col2 = dbStmt.fieldPrecise(); -// console.log(`column 1 fieldPrecision = ${col1}`); -// console.log(`column 2 fieldPrecision = ${col2}`); -// expect(col1).to.be.a('number'); -// expect(col2).to.be.a('number'); -// }); -// }); - -// describe('fieldScaleFail', () => { -// it('error caused by providing an invalid index as a param', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// dbStmt.execute(); -// const col1 = dbStmt.fieldScale('c'); -// const col2 = dbStmt.fieldScale('a'); -// console.log(`column 1 fieldScale = ${col1}`); -// console.log(`column 2 fieldScale = ${col2}`); -// expect(col1).to.be.a('number'); -// expect(col2).to.be.a('number'); -// }); -// }); - -// describe('setStmtAttrFail', () => { -// it('error caused by providing invalid attr and value as params', () => { -// // invalid attr insert -// const attr = -500; -// const value = 1; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// const result = dbStmt.setStmtAttr(attr, value); -// expect(result).to.be.a('undefined'); -// }); -// }); - -// describe('getStmtAttrFail', () => { -// it('error caused by providing invalid attr as a param.', () => { -// // insert invalid attr -// const attr = 2; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// const result = dbStmt.getStmtAttr(attr); -// expect(result).to.satisfy((result) => { -// return result === 'string' || typeof result === 'number'; -// }); -// }); -// }); - -// describe('nextResultFail', () => { -// it('err', () => { -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbConn = new addon.DbConn(); -// dbConn.conn('*LOCAL'); -// const dbStmt = new addon.DbStmt(dbConn); -// dbStmt.prepare(sql); -// dbStmt.execute(); -// const result = dbStmt.nextResult(); -// expect(result).to.be.a('object'); -// }); -// }); - -// // need to create fail case for rollback -// describe('rollbackFail', () => { -// it('error caused by ', () => { -// const result = dbStmt.rollback(); -// const sql = 'SELECT * FROM QIWS.QCUSTCDT'; -// const dbStmt = new addon.Connection().connect().getStatement(); -// dbStmt.prepare(sql); -// // dbStmt.execute(); -// expect(result).to.be.a('undefined'); -// }); -// }); - -// // need to create failure case for stmtErr -// describe('stmtError', () => { -// it('error was caused by: ', () => { -// const dbStmt = new addon.Connection().connect().getStatement(); -// dbStmt.stmtError(hType, recno); -// }); -// }); diff --git a/test/statementTest.js b/test/statementTest.js index fda9b89..a4887b3 100644 --- a/test/statementTest.js +++ b/test/statementTest.js @@ -2,21 +2,85 @@ const { expect } = require('chai'); const db2a = require('../lib/db2a'); const { - IN, CHAR, NUMERIC, dbstmt, dbconn, + dbstmt, dbconn, } = db2a; +const schema = 'IDBTEST'; +const table = 'SCORES'; +const selectSchema = `SELECT SCHEMA_NAME FROM QSYS2.sysschemas WHERE SCHEMA_NAME = '${schema}'`; +const createSchema = `CREATE SCHEMA ${schema}`; +const createTable = `CREATE OR REPLACE TABLE ${schema}.${table}(team CHAR(10), score INTEGER)`; +const insertTable = `INSERT INTO ${schema}.${table}(TEAM,SCORE) VALUES (?,?)` +const dropTable = `DROP TABLE ${schema}.${table}`; + // Test Statement Misc describe('Statement Misc Test', () => { + // global connection and statement that will be used for test cases + // dbConn is initialized in before hook and destoryed in after hook + // dbStmt is initialized in beforeEach hook and destoryed in afterEach hook var dbConn, dbStmt; - before(() => { - dbConn = new dbconn(); - dbConn.conn('*LOCAL'); - }); + function cleanup(connection, statement) { + statement.close(); + connection.disconn(); + connection.close(); + } + + before('setup schema for tests', function (done) { + // setup the test infrastructure + this.timeout(0); // disbale timeout for hook + const connection = new dbconn(); + connection.conn('*LOCAL'); + const statement = new dbstmt(connection); + statement.exec(selectSchema, (schemaResult, schemaError) => { + if (schemaError){ + cleanup(connection, statement); + done(schemaError); + return; + } + const rc = statement.closeCursor(); + if (!schemaResult.length) { + statement.exec(createSchema, (createSchemaResult, createSchemaError) => { + if (createSchemaError) { + cleanup(connection, statement); + done(createSchemaError); + return; + } + }); + } + statement.exec(createTable, (createTableResult, createTableError) => { + if (createTableError) { + cleanup(connection, statement); + done(createTableError); + return; + } + cleanup(connection, statement); + // create connection that will be used in all the later test cases + dbConn = new dbconn(); + dbConn.conn('*LOCAL'); + done(); + }); + }); + }); - after(() => { + after('drop objects after the tests', function (done) { + // close connection used in thetest cases dbConn.disconn(); dbConn.close(); + // tear down test infrastructure + this.timeout(0); // disable timeout for hook + const connection = new dbconn(); + connection.conn('*LOCAL'); + const statement = new dbstmt(connection); + statement.exec(dropTable, (dropTableResult, dropTableError) => { + if (dropTableError){ + cleanup(connection, statement); + done(dropTableError); + return; + } + cleanup(connection, statement); + done(); + }); }); beforeEach(() => { @@ -49,8 +113,8 @@ describe('Statement Misc Test', () => { }); /* - TODO create pssing unit test for nextResult() - + TODO create passing unit test for nextResult() + 1) Create a Procedure that returns multiple reseult sets describe('nextResult', () => { it('Determines whether there is more information available on the statement', () => { let sql = 'SELECT * FROM QIWS.QCUSTCDT'; @@ -85,11 +149,9 @@ describe('Statement Misc Test', () => { describe('commit', () => { it('adds all changes to the database that have been made on the connection since connect time ', (done) => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; - - const params = [9997, 'Doe', 'J D', '123 Broadway', 'Hope', 'WA', 98101, 2000, 1, 250, 0.00]; + const params = ['TEST', 100]; - dbStmt.prepare(sql, (error) => { + dbStmt.prepare(insertTable, (error) => { if (error) { throw error; } diff --git a/test/syncStatementTest.js b/test/syncStatementTest.js index c896f64..c616d34 100644 --- a/test/syncStatementTest.js +++ b/test/syncStatementTest.js @@ -3,20 +3,88 @@ const util = require('util'); const db2a = require('../lib/db2a'); const { - OUT, IN, CHAR, CLOB, NUMERIC, dbconn, dbstmt, + OUT, IN, CHAR, CLOB, NUMERIC, INT, dbconn, dbstmt, } = db2a; +const schema = 'IDBTEST'; +const table = 'SCORES'; +const selectSchema = `SELECT SCHEMA_NAME FROM QSYS2.sysschemas WHERE SCHEMA_NAME = '${schema}'`; +const createSchema = `CREATE SCHEMA ${schema}`; +const createTable = `CREATE OR REPLACE TABLE ${schema}.${table}(team CHAR(10), score INTEGER)`; +const insertTable = `INSERT INTO ${schema}.${table}(TEAM,SCORE) VALUES (?,?)` +const countTeams = `SELECT COUNT(TEAM) as TEAMCOUNT FROM ${schema}.${table}`; +const dropTable = `DROP TABLE ${schema}.${table}`; + describe('Statement Sync Test', () => { + // global connection and statement that will be used for test cases + // dbConn is initialized in before hook and destoryed in after hook + // dbStmt is initialized in beforeEach hook and destoryed in afterEach hook var dbConn, dbStmt; - before(() => { - dbConn = new dbconn(); - dbConn.conn('*LOCAL'); - }); + function cleanup(connection, statement) { + statement.close(); + connection.disconn(); + connection.close(); + } + + before('setup schema for tests', function (done) { + // setup the test infrastructure + this.timeout(0); // disbale timeout for hook + const connection = new dbconn(); + connection.conn('*LOCAL'); + const statement = new dbstmt(connection); + statement.exec(selectSchema, (schemaResult, schemaError) => { + if (schemaError){ + cleanup(connection, statement); + done(schemaError); + return; + } + const rc = statement.closeCursor(); + if (!schemaResult.length) { + statement.exec(createSchema, (createSchemaResult, createSchemaError) => { + if (createSchemaError) { + cleanup(connection, statement); + console.error(`failed to create the schema: ${schema}`); + console.error(createSchemaError); + done(createSchemaError); + return; + } + }); + } + statement.exec(createTable, (createTableResult, createTableError) => { + if (createTableError) { + cleanup(connection, statement); + done(createTableError); + return; + } + console.log(`\n\nBefore hook: Created table: ${table}!\n\n`); + cleanup(connection, statement); + // create connection that will be used in all the later test cases + dbConn = new dbconn(); + dbConn.conn('*LOCAL'); + done(); + }); + }); + }); - after(() => { + after('drop objects after the tests', function (done) { + // close connection used in thetest cases dbConn.disconn(); dbConn.close(); + // tear down test infrastructure + this.timeout(0); // disable timeout for hook + const connection = new dbconn(); + connection.conn('*LOCAL'); + const statement = new dbstmt(connection); + statement.exec(dropTable, (dropTableResult, dropTableError) => { + if (dropTableError){ + cleanup(connection, statement); + done(dropTableError); + return; + } + cleanup(connection, statement); + done(); + }); }); beforeEach(() => { @@ -48,32 +116,22 @@ describe('Statement Sync Test', () => { describe('bindParams callback', () => { it('associate parameter markers in an SQL statement to app variables', () => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; const params = [ - [9997, IN, NUMERIC], // CUSNUM - ['Doe', IN, CHAR], // LASTNAME - ['J D', IN, CHAR], // INITIAL - ['123 Broadway', IN, CHAR], // ADDRESS - ['Hope', IN, CHAR], // CITY - ['WA', IN, CHAR], // STATE - [98101, IN, NUMERIC], // ZIP - [2000, IN, NUMERIC], // CREDIT LIMIT - [1, IN, NUMERIC], // change - [250, IN, NUMERIC], // BAL DUE - [0.00, IN, NUMERIC], // CREDIT DUE + ['TEST', IN, CHAR], // TEAM + [100, IN, INT], // SCORE ]; const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); - const result = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsBefore = result[0]['00001']; + const result = dbStmt.execSync(countTeams); + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); dbStmt.close(); - dbStmt2.prepareSync(sql, (error) => { + dbStmt2.prepareSync(insertTable, (error) => { if (error) { throw error; } @@ -89,8 +147,8 @@ describe('Statement Sync Test', () => { } dbStmt = new dbstmt(dbConn); - const result2 = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsAfter = result2[0]['00001']; + const result2 = dbStmt.execSync(countTeams); + let rowsAfter = result2[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); @@ -103,20 +161,18 @@ describe('Statement Sync Test', () => { describe('bindParams callback (1-D array)', () => { it('associate parameter markers in an SQL statement to app variables', () => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; - const params = [9997, 'Doe', 'J D', '123 Broadway', 'Hope', 'WA', 98101, 2000, 1, 250, 0.00]; - + const params = ['TEST2', 200]; const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); - const result = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsBefore = result[0]['00001']; + const result = dbStmt.execSync(countTeams); + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); dbStmt.close(); - dbStmt2.prepareSync(sql, (error) => { + dbStmt2.prepareSync(insertTable, (error) => { if (error) { throw error; } @@ -132,8 +188,8 @@ describe('Statement Sync Test', () => { } dbStmt = new dbstmt(dbConn); - const result2 = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsAfter = result2[0]['00001']; + const result2 = dbStmt.execSync(countTeams); + let rowsAfter = result2[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); @@ -146,20 +202,18 @@ describe('Statement Sync Test', () => { describe('bindParameters callback', () => { it('associate parameter markers in an SQL statement to app variables', () => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; - const params = [9997, 'Doe', 'J D', '123 Broadway', 'Hope', 'WA', 98101, 2000, 1, 250, 0.00]; - + const params = ['TEST3', 300]; const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); - const result = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsBefore = result[0]['00001']; + const result = dbStmt.execSync(countTeams); + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); dbStmt.close(); - dbStmt2.prepareSync(sql, (error) => { + dbStmt2.prepareSync(insertTable, (error) => { if (error) { throw error; } @@ -175,8 +229,8 @@ describe('Statement Sync Test', () => { } dbStmt = new dbstmt(dbConn); - const result2 = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsAfter = result2[0]['00001']; + const result2 = dbStmt.execSync(countTeams); + let rowsAfter = result2[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); @@ -189,41 +243,32 @@ describe('Statement Sync Test', () => { describe('bindParams no-callback', () => { it('associate parameter markers in an SQL statement to app variables', () => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; const params = [ - [9997, IN, NUMERIC], // CUSNUM - ['Doe', IN, CHAR], // LASTNAME - ['J D', IN, CHAR], // INITIAL - ['123 Broadway', IN, CHAR], // ADDRESS - ['Hope', IN, CHAR], // CITY - ['WA', IN, CHAR], // STATE - [98101, IN, NUMERIC], // ZIP - [2000, IN, NUMERIC], // CREDIT LIMIT - [1, IN, NUMERIC], // change - [250, IN, NUMERIC], // BAL DUE - [0.00, IN, NUMERIC], // CREDIT DUE + ['TEST4', IN, CHAR], // TEAM + [400, IN, INT], // SCORE ]; + const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); // first get count of current rows - const result = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsBefore = result[0]['00001']; + const result = dbStmt.execSync(countTeams); + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); // count retrurns as a String cast it to Number dbStmt.close(); // now perform insert - dbStmt2.prepareSync(sql); + dbStmt2.prepareSync(insertTable); dbStmt2.bindParamSync(params); dbStmt2.executeSync(); dbStmt = new dbstmt(dbConn); - const result2 = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsAfter = result2[0]['00001']; + const result2 = dbStmt.execSync(countTeams); + let rowsAfter = result2[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); @@ -233,29 +278,29 @@ describe('Statement Sync Test', () => { describe('bindParams no-callback (1-D array)', () => { it('associate parameter markers in an SQL statement to app variables', () => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; - const params = [9997, 'Doe', 'J D', '123 Broadway', 'Hope', 'WA', 98101, 2000, 1, 250, 0.00]; + const params = ['TEST5', 500]; + const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); // first get count of current rows - const result = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsBefore = result[0]['00001']; + const result = dbStmt.execSync(countTeams); + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); // count retrurns as a String cast it to Number dbStmt.close(); // now perform insert - dbStmt2.prepareSync(sql); + dbStmt2.prepareSync(insertTable); dbStmt2.bindParamSync(params); dbStmt2.executeSync(); dbStmt = new dbstmt(dbConn); - const result2 = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsAfter = result2[0]['00001']; + const result2 = dbStmt.execSync(countTeams); + let rowsAfter = result2[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter); @@ -265,29 +310,28 @@ describe('Statement Sync Test', () => { describe('bindParameters no-callback', () => { it('associate parameter markers in an SQL statement to app variables', () => { - const sql = 'INSERT INTO QIWS.QCUSTCDT(CUSNUM,LSTNAM,INIT,STREET,CITY,STATE,ZIPCOD,CDTLMT,CHGCOD,BALDUE,CDTDUE) VALUES (?,?,?,?,?,?,?,?,?,?,?) with NONE '; - const params = [9997, 'Doe', 'J D', '123 Broadway', 'Hope', 'WA', 98101, 2000, 1, 250, 0.00]; + const params = ['TEST6', 600]; const dbConn2 = new dbconn(); dbConn2.conn('*LOCAL'); const dbStmt2 = new dbstmt(dbConn2); // first get count of current rows - const result = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsBefore = result[0]['00001']; + const result = dbStmt.execSync(countTeams); + let rowsBefore = result[0]['TEAMCOUNT']; rowsBefore = Number(rowsBefore); // count retrurns as a String cast it to Number dbStmt.close(); // now perform insert - dbStmt2.prepareSync(sql); + dbStmt2.prepareSync(insertTable); dbStmt2.bindParametersSync(params); dbStmt2.executeSync(); dbStmt = new dbstmt(dbConn); - const result2 = dbStmt.execSync('SELECT COUNT(CUSNUM) FROM QIWS.QCUSTCDT'); - let rowsAfter = result2[0]['00001']; + const result2 = dbStmt.execSync(countTeams); + let rowsAfter = result2[0]['TEAMCOUNT']; rowsAfter = Number(rowsAfter);