587 lines
18 KiB
JavaScript
587 lines
18 KiB
JavaScript
/*
|
|
Copyright (c) 2013, Oracle and/or its affiliates. All rights
|
|
reserved.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; version 2 of
|
|
the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
02110-1301 USA
|
|
*/
|
|
|
|
"use strict";
|
|
/*global fail_openSession */
|
|
|
|
var assert = require("assert");
|
|
|
|
var good_properties = global.test_conn_properties;
|
|
|
|
var bad_properties = {
|
|
"implementation" : global.test_conn_properties.implementation,
|
|
"mysql_host" : "localhost",
|
|
"mysql_port" : "3306",
|
|
"mysql_user" : "_BAD_USER_",
|
|
"mysql_password" : "_NOT_A_REAL_PASSWORD!_",
|
|
"ndb_connectstring" : "this_host_does_not_exist"
|
|
};
|
|
|
|
var tests = [];
|
|
|
|
/* 2.2.2 if onFulfilled is a function:
|
|
2.2.2.1 it must be called after promise is fulfilled, with promise's value
|
|
as its first argument.
|
|
2.2.2.2 it must not be called before promise is fulfilled
|
|
2.2.2.3 it must not be called more than once.
|
|
*/
|
|
var t_222 = new harness.ConcurrentTest("2.2.2 onFulfilled");
|
|
t_222.run = function() {
|
|
var n, p, test;
|
|
n = 0;
|
|
test = this;
|
|
|
|
function onSession(session) {
|
|
n++;
|
|
assert(n === 1); // 2.2.2.3 ; could happen after test has already passed
|
|
test.errorIfUnset("PromisesTest.t_222 onFulfilled gets a value", session); // 2.2.2.1
|
|
test.errorIfNotEqual("PromisesTest.t_222 Not a session", typeof session.find, "function");
|
|
test.errorIfNotEqual("typeof this (2.2.5) " + this, "undefined", typeof this);
|
|
session.close(function() {
|
|
test.failOnError();
|
|
});
|
|
}
|
|
|
|
p = mynode.openSession(good_properties, null);
|
|
if(typeof p === 'object' && typeof p.then === 'function') {
|
|
p.then(onSession);
|
|
} else {
|
|
this.fail("PromisesTest.t_222 not thenable");
|
|
}
|
|
};
|
|
tests.push(t_222);
|
|
|
|
|
|
|
|
/* 2.2.3 if onRejected is a function:
|
|
2.2.3.1 it must be called after promise is rejected, with promise's reason
|
|
as its first argument.
|
|
2.2.3.2 it must not be called before promise is rejected
|
|
2.2.3.3 it must not be called more than once.
|
|
*/
|
|
var t_223 = new harness.ConcurrentTest("2.2.3 onRejected");
|
|
t_223.run = function() {
|
|
var n, p, test;
|
|
n = 0;
|
|
test = this;
|
|
|
|
function onSession(s) {
|
|
assert("PromisesTest.t_223 openSession should fail" === 0);
|
|
s.close();
|
|
}
|
|
|
|
function onError(e) {
|
|
n++;
|
|
assert(n === 1); // 2.2.3.3 ; could happen after test has passed
|
|
test.errorIfUnset("onRejected must get a reason", e);
|
|
test.errorIfNotEqual("typeof this (2.2.5) " + this, "undefined", typeof this);
|
|
test.failOnError();
|
|
}
|
|
|
|
p = mynode.openSession(bad_properties, null);
|
|
if(typeof p === 'object' && typeof p.then === 'function') {
|
|
p.then(onSession, onError);
|
|
} else {
|
|
this.fail("PromisesTest.t_223 not thenable");
|
|
}
|
|
};
|
|
tests.push(t_223);
|
|
|
|
|
|
/* 2.2.6 then may be called multiple times on the same promise.
|
|
2.2.6.1 If/when promise is fulfilled, all respective onFulfilled callbacks
|
|
must execute in the order of their originating calls to then.
|
|
2.2.6.2 If/when promise is rejected, all respective onRejected callbacks
|
|
must execute in the order of their originating calls to then.
|
|
*/
|
|
var t_2261 = new harness.ConcurrentTest("2.2.6.1 multiple onFulfilled called in order");
|
|
t_2261.run = function() {
|
|
var n, p, test;
|
|
n = 0;
|
|
test = this;
|
|
|
|
function onSession_1(s) {
|
|
n++;
|
|
test.errorIfNotEqual("PromisesTest.t_2261 wrong order; onSession_1 should be called first", 1, n);
|
|
}
|
|
|
|
function onSession_2(s) {
|
|
n++;
|
|
test.errorIfNotEqual("PromisesTest.t_2261 wrong order; onSession_2 should be called second", 2, n);
|
|
s.close(function() { test.failOnError(); });
|
|
}
|
|
|
|
p = mynode.openSession(good_properties, null);
|
|
if(typeof p === 'object' && typeof p.then === 'function') {
|
|
p.then(onSession_1);
|
|
p.then(onSession_2);
|
|
} else {
|
|
this.fail("PromisesTest.t_2261 not thenable");
|
|
}
|
|
};
|
|
tests.push(t_2261);
|
|
|
|
var t_2262 = new harness.ConcurrentTest("2.2.6.2 multiple onRejected called in order");
|
|
t_2262.run = function() {
|
|
var n, p, test;
|
|
n = 0;
|
|
test = this;
|
|
|
|
function onSession(s) {
|
|
test.fail("PromisesTest.t_2262 openSession should fail");
|
|
s.close();
|
|
}
|
|
|
|
function onErr_1(e) {
|
|
n++;
|
|
test.errorIfNotEqual("PromisesTest.t_2262 wrong order; onErr_1 should be called first", 1, n);
|
|
}
|
|
|
|
function onErr_2(e) {
|
|
n++;
|
|
test.errorIfNotEqual("PromisesTest.t_2262 wrong order; onErr_2 should be called second", 2, n);
|
|
test.failOnError();
|
|
}
|
|
|
|
p = mynode.openSession(bad_properties, null);
|
|
if(typeof p === 'object') {
|
|
p.then(onSession, onErr_1);
|
|
p.then(onSession, onErr_2);
|
|
} else {
|
|
this.fail("PromisesTest.t_2262 not thenable");
|
|
}
|
|
};
|
|
tests.push(t_2262);
|
|
|
|
|
|
/* 2.2.7 "then" must return a promise
|
|
*/
|
|
var t_227 = new harness.ConcurrentTest("2.2.7 then returns a promise");
|
|
t_227.run = function() {
|
|
var p1, p2, test;
|
|
test = this;
|
|
|
|
function onSession(s) {
|
|
s.close(function() { test.failOnError(); });
|
|
}
|
|
|
|
p1 = mynode.openSession(good_properties, null);
|
|
if(typeof p1 !== 'object' || typeof p1.then !== 'function') {
|
|
this.fail("PromisesTest.t_227 p1 not thenable");
|
|
} else {
|
|
p2 = p1.then(onSession);
|
|
if(typeof p2 !== 'object' || typeof p2.then !== 'function') {
|
|
this.appendErrorMessage("PromisesTest.t_227 p2 not thenable");
|
|
}
|
|
}
|
|
};
|
|
tests.push(t_227);
|
|
|
|
/* 2.2.7.1 If onFulfilled returns a value x, run the Promise Resolution Procedure.
|
|
*/
|
|
var t_2271fv = new harness.ConcurrentTest("2.2.7.1 onFulfilled returns a value");
|
|
t_2271fv.run = function() {
|
|
var p1, p2 ,p3, test, session;
|
|
test = this;
|
|
|
|
function onSession(s) {
|
|
// onFulfilled returns a value; should fulfill p3 as well
|
|
s.close();
|
|
return 49;
|
|
}
|
|
|
|
function onP2Fulfilled(v) {
|
|
test.errorIfNotEqual("t_2271fv onP2Fulfilled value", 49, v);
|
|
test.failOnError();
|
|
}
|
|
|
|
p1 = mynode.openSession(good_properties, null);
|
|
if(typeof p1 !== 'object' || typeof p1.then !== 'function') {
|
|
this.fail("PromisesTest.t_227 p1 not thenable");
|
|
} else {
|
|
p2 = p1.then(onSession);
|
|
if(typeof p2 !== 'object' || typeof p2.then !== 'function') {
|
|
this.appendErrorMessage("PromisesTest.t_2271 p2 not thenable");
|
|
}
|
|
p3 = p2.then(onP2Fulfilled);
|
|
}
|
|
};
|
|
tests.push(t_2271fv);
|
|
|
|
/* 2.2.7.1 If onRejected returns a value x, run the Promise Resolution Procedure.
|
|
*/
|
|
var t_2271rv = new harness.ConcurrentTest("2.2.7.1 onRejected returns a value");
|
|
t_2271rv.run = function() {
|
|
var p1, p2 ,p3, test, session, onSession;
|
|
test = this;
|
|
|
|
function onError(err) {
|
|
// onError returns a value; should fulfill p3 as well
|
|
return 49;
|
|
}
|
|
|
|
function onP2Fulfilled(v) {
|
|
test.errorIfNotEqual("t_2271rv onP2Rejected value", 49, v);
|
|
test.failOnError();
|
|
}
|
|
|
|
function onP2Rejected(e) {
|
|
test.fail('t_2271rv should not reject because onRejected returned a value.');
|
|
}
|
|
|
|
p1 = mynode.openSession(bad_properties, null);
|
|
p1.name = 'p1';
|
|
if(typeof p1 !== 'object' || typeof p1.then !== 'function') {
|
|
this.fail("PromisesTest.t_227 p1 not thenable");
|
|
} else {
|
|
p2 = p1.then(onSession, onError);
|
|
p2.name = 'p2';
|
|
if(typeof p2 !== 'object' || typeof p2.then !== 'function') {
|
|
this.appendErrorMessage("PromisesTest.t_2271 p2 not thenable");
|
|
}
|
|
// p3 tests for the result of p2
|
|
p3 = p2.then(onP2Fulfilled, onP2Rejected);
|
|
p3.name = 'p3';
|
|
}
|
|
};
|
|
tests.push(t_2271rv);
|
|
|
|
|
|
/* 2.2.7.2 If onFulfilled throws an exception e, promise2 must be rejected with e as the reason.
|
|
*/
|
|
var t_2272fe = new harness.ConcurrentTest("2.2.7.2 onFulfilled throws an error");
|
|
t_2272fe.run = function() {
|
|
var p1, p2, p3, test, p2OnFulfilled;
|
|
test = this;
|
|
|
|
function onSession(s) {
|
|
// onSession throws an exception; should reject p2
|
|
s.close();
|
|
throw new Error("PromisesTest.t_2272fe");
|
|
}
|
|
|
|
function p2OnRejected(e) {
|
|
test.errorIfNotEqual('t_2272fe error value', 'PromisesTest.t_2272fe', e.message);
|
|
test.failOnError();
|
|
}
|
|
|
|
p1 = mynode.openSession(good_properties, null);
|
|
if(typeof p1 !== 'object' || typeof p1.then !== 'function') {
|
|
this.fail("PromisesTest.t_2272fe p1 not thenable");
|
|
} else {
|
|
p2 = p1.then(onSession);
|
|
if(typeof p2 !== 'object' || typeof p2.then !== 'function') {
|
|
this.appendErrorMessage("PromisesTest.t_2271fe p2 not thenable");
|
|
}
|
|
p3 = p2.then(p2OnFulfilled, p2OnRejected);
|
|
}
|
|
};
|
|
tests.push(t_2272fe);
|
|
|
|
/* 2.2.7.2 If onRejected throws an exception e, promise2 must be rejected with e as the reason.
|
|
*/
|
|
var t_2272re = new harness.ConcurrentTest("2.2.7.2 onRejected throws an error");
|
|
t_2272re.run = function() {
|
|
var p1, p2, p3, test, onSession, p2OnFulfilled;
|
|
test = this;
|
|
|
|
function onError(err) {
|
|
// onError throws an exception; should reject p2
|
|
throw new Error("PromisesTest.t_2272re");
|
|
}
|
|
|
|
function p2OnRejected(e) {
|
|
test.errorIfNotEqual('t_2272re error value', 'PromisesTest.t_2272re', e.message);
|
|
test.failOnError();
|
|
}
|
|
|
|
p1 = mynode.openSession(bad_properties, null);
|
|
if(typeof p1 !== 'object' || typeof p1.then !== 'function') {
|
|
this.fail("PromisesTest.t_2272re p1 not thenable");
|
|
} else {
|
|
p2 = p1.then(onSession, onError);
|
|
if(typeof p2 !== 'object' || typeof p2.then !== 'function') {
|
|
this.appendErrorMessage("PromisesTest.t_227 p2 not thenable");
|
|
}
|
|
p3 = p2.then(p2OnFulfilled, p2OnRejected);
|
|
}
|
|
};
|
|
tests.push(t_2272re);
|
|
|
|
/* 2.2.7.3 If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value.
|
|
*/
|
|
var t_2273 = new harness.ConcurrentTest("2.2.7.3 missing onFulfilled");
|
|
t_2273.run = function() {
|
|
var p1, p2, p3, test;
|
|
test = this;
|
|
|
|
function p2OnFulfilled(v) {
|
|
v.close(function(){test.failOnError();});
|
|
}
|
|
|
|
p1 = mynode.openSession(good_properties, null);
|
|
if(typeof p1 !== 'object' || typeof p1.then !== 'function') {
|
|
this.fail("PromisesTest.t_2273 p1 not thenable");
|
|
} else {
|
|
p2 = p1.then();
|
|
if(typeof p2 !== 'object' || typeof p2.then !== 'function') {
|
|
this.appendErrorMessage("PromisesTest.t_2273 p2 not thenable");
|
|
}
|
|
p3 = p2.then(p2OnFulfilled);
|
|
}
|
|
};
|
|
tests.push(t_2273);
|
|
|
|
/* 2.2.7.4 If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason.
|
|
*/
|
|
var t_2274 = new harness.ConcurrentTest("2.2.7.4 missing onRejected");
|
|
t_2274.run = function() {
|
|
var p1, p2, p3, test, p2OnFulfilled;
|
|
test = this;
|
|
|
|
function p2OnRejected(err) {
|
|
test.failOnError();
|
|
}
|
|
|
|
p1 = mynode.openSession(bad_properties, null);
|
|
if(typeof p1 !== 'object' || typeof p1.then !== 'function') {
|
|
this.fail("PromisesTest.t_227 p1 not thenable");
|
|
} else {
|
|
p2 = p1.then();
|
|
if(typeof p2 !== 'object' || typeof p2.then !== 'function') {
|
|
this.appendErrorMessage("PromisesTest.t_227 p2 not thenable");
|
|
}
|
|
p3 = p2.then(p2OnFulfilled, p2OnRejected);
|
|
}
|
|
};
|
|
tests.push(t_2274);
|
|
|
|
/* 2.3 If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that
|
|
* x behaves at least somewhat like a promise.
|
|
* Otherwise, it fulfills promise with the value x.
|
|
*/
|
|
var t_23f = new harness.ConcurrentTest("2.3 The Promise Resolution Procedure: fulfilled");
|
|
t_23f.run = function() {
|
|
var test = this;
|
|
var session;
|
|
var p1, p2, p3, p4;
|
|
|
|
function onSession(s) {
|
|
session = s;
|
|
p4 = s.close();
|
|
return p4;
|
|
}
|
|
|
|
function reportSuccess(result) {
|
|
if (result) {
|
|
test.appendErrorMessage('t_23f result of session.close should be null or undefined but is ' + result, result);
|
|
}
|
|
test.failOnError();
|
|
}
|
|
|
|
function reportFailure(err) {
|
|
test.fail('t_23f failed', err);
|
|
}
|
|
|
|
// t_23 begins here
|
|
p1 = mynode.openSession(good_properties);
|
|
p2 = p1.then(onSession);
|
|
p3 = p2.then(reportSuccess, reportFailure);
|
|
};
|
|
tests.push(t_23f);
|
|
|
|
/* 2.3 If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that
|
|
* x behaves at least somewhat like a promise.
|
|
* Otherwise, it fulfills promise with the value x.
|
|
*/
|
|
var t_23r = new harness.ConcurrentTest("2.3 The Promise Resolution Procedure: rejected");
|
|
t_23r.run = function() {
|
|
var test = this;
|
|
var session;
|
|
var p1, p2, p3, p4;
|
|
|
|
function onSession(s) {
|
|
session = s;
|
|
p4 = s.close();
|
|
return p4;
|
|
}
|
|
|
|
function reportSuccess(result) {
|
|
test.errorIfNotNull('t_23r result of session.close should be null', result);
|
|
test.fail('t_23r should fail.');
|
|
}
|
|
|
|
function reportFailure(err) {
|
|
// make sure err is what we expect it to be
|
|
if (typeof(err.message) !== 'string') {
|
|
test.appendErrorMessage('t_23r err.message must be a string.');
|
|
}
|
|
if (typeof(err.sqlstate) === 'string') {
|
|
test.errorIfNull('t_23r err.sqlstate', err.sqlstate.match('0800'));
|
|
} else {
|
|
test.appendErrorMessage('t_23r err.sqlstate must be a string.');
|
|
}
|
|
test.failOnError();
|
|
}
|
|
|
|
// t_23 begins here
|
|
p1 = mynode.openSession(bad_properties);
|
|
p2 = p1.then(onSession);
|
|
p3 = p2.then(reportSuccess, reportFailure);
|
|
};
|
|
tests.push(t_23r);
|
|
|
|
/** Transaction state tests.
|
|
* Helpers is a closure of testCase, session, errorSqlStateMatch, and errorMessageMatch.
|
|
* Methods of Helpers are called with no 'this' and they use the original parameters passed.
|
|
*/
|
|
function createHelpers(testCase, session, errorSqlStateMatch, errorMessageMatch) {
|
|
return {
|
|
begin : function() {
|
|
var result = session.currentTransaction().begin();
|
|
return result;
|
|
},
|
|
commit : function() {
|
|
return session.currentTransaction().commit();
|
|
},
|
|
activeBeginFails : function(err) {
|
|
// check for the right err
|
|
testCase.errorIfNull('activeBeginFails: ' + err.message,
|
|
err.message.match('Active cannot begin'));
|
|
throw err;
|
|
},
|
|
rollback : function() {
|
|
return session.currentTransaction().rollback();
|
|
},
|
|
setRollbackOnly : function() {
|
|
session.currentTransaction().setRollbackOnly();
|
|
},
|
|
errorReportSuccess : function() {
|
|
testCase.fail('must return an error but did not.');
|
|
},
|
|
checkReportFailure : function(err) {
|
|
if (errorSqlStateMatch) {
|
|
if (typeof(err.sqlstate) === 'string') {
|
|
testCase.errorIfNull('wrong sqlstate: ' + err.sqlstate + '; should match ' + errorSqlStateMatch,
|
|
err.sqlstate.match(errorSqlStateMatch));
|
|
} else {
|
|
testCase.appendErrorMessage('err.sqlstate must be a string.');
|
|
}
|
|
}
|
|
if (errorMessageMatch) {
|
|
if (typeof(err.message) === 'string') {
|
|
testCase.errorIfNull('wrong err.message ' + err.message + '; should match ' + errorMessageMatch,
|
|
err.message.match(errorMessageMatch));
|
|
} else {
|
|
testCase.appendErrorMessage('err.message must be a string.');
|
|
}
|
|
}
|
|
if (session.currentTransaction().isActive()) {
|
|
session.currentTransaction().rollback(function(err) {
|
|
if (err) {
|
|
err.message += '\n failure occurred on rollback after test in checkReportFailure';
|
|
testCase.fail(err);
|
|
} else {
|
|
testCase.failOnError();
|
|
}
|
|
});
|
|
} else {
|
|
testCase.failOnError();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
var testIdleCommit = new harness.ConcurrentTest('Idle commit must fail');
|
|
testIdleCommit.run = function() {
|
|
var testCase = this;
|
|
mynode.openSession(good_properties, null, function(err, session) {
|
|
testCase.session = session;
|
|
if (err) throw err;
|
|
var helpers = createHelpers(testCase, session, '2500', 'Idle cannot commit');
|
|
helpers.commit().
|
|
then(helpers.errorReportSuccess, helpers.checkReportFailure);
|
|
});
|
|
};
|
|
tests.push(testIdleCommit);
|
|
|
|
var testIdleRollback = new harness.ConcurrentTest('Idle rollback must fail');
|
|
testIdleRollback.run = function() {
|
|
var testCase = this;
|
|
mynode.openSession(good_properties, null, function(err, session) {
|
|
testCase.session = session;
|
|
if (err) throw err;
|
|
var helpers = createHelpers(testCase, session, '2500', 'Idle cannot rollback');
|
|
helpers.rollback().
|
|
then(helpers.errorReportSuccess, helpers.checkReportFailure);
|
|
});
|
|
};
|
|
tests.push(testIdleRollback);
|
|
|
|
var testActiveBegin = new harness.ConcurrentTest('Active begin must fail');
|
|
testActiveBegin.run = function() {
|
|
var testCase = this;
|
|
mynode.openSession(good_properties, null, function(err, session) {
|
|
if (err) throw err;
|
|
testCase.session = session;
|
|
var helpers = createHelpers(testCase, session, '2500', 'Active cannot begin');
|
|
var p1 = helpers.begin();
|
|
var p2 = p1.then(helpers.begin);
|
|
p2.name = 'p2';
|
|
var p3 = p2.then(helpers.errorReportSuccess, helpers.checkReportFailure);
|
|
p3.name = 'p3';
|
|
});
|
|
};
|
|
tests.push(testActiveBegin);
|
|
|
|
var testRollbackOnlyBegin = new harness.ConcurrentTest('RollbackOnly begin must fail');
|
|
testRollbackOnlyBegin.run = function() {
|
|
var testCase = this;
|
|
mynode.openSession(good_properties, null, function(err, session) {
|
|
testCase.session = session;
|
|
if (err) throw err;
|
|
var helpers = createHelpers(testCase, session, '2500', 'RollbackOnly cannot begin');
|
|
helpers.begin().
|
|
then(helpers.setRollbackOnly).
|
|
then(helpers.begin).
|
|
then(helpers.errorReportSuccess, helpers.checkReportFailure);
|
|
});
|
|
};
|
|
tests.push(testRollbackOnlyBegin);
|
|
|
|
var testRollbackOnlyCommit = new harness.ConcurrentTest('RollbackOnly commit must fail');
|
|
testRollbackOnlyCommit.run = function() {
|
|
var testCase = this;
|
|
mynode.openSession(good_properties, null, function(err, session) {
|
|
testCase.session = session;
|
|
if (err) throw err;
|
|
var helpers = createHelpers(testCase, session, '2500', 'RollbackOnly cannot commit');
|
|
helpers.begin().
|
|
then(helpers.setRollbackOnly).
|
|
then(helpers.commit).
|
|
then(helpers.errorReportSuccess, helpers.checkReportFailure);
|
|
});
|
|
};
|
|
tests.push(testRollbackOnlyCommit);
|
|
|
|
// need to test "then" when the promise has already been fulfilled or rejected
|
|
|
|
module.exports.tests = tests;
|