blob: 0593aeab67191d5d32d27773c6b2473bc274d4b5 [file] [log] [blame]
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -08001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * 'License'); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
bforbisda1169d2018-10-28 11:27:38 -040020// This is the Node.js test driver for the standard Apache Thrift
21// test service. The driver invokes every function defined in the
22// Thrift Test service with a representative range of parameters.
23//
24// The ThriftTestDriver function requires a client object
25// connected to a server hosting the Thrift Test service and
26// supports an optional callback function which is called with
27// a status message when the test is complete.
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080028
bforbisda1169d2018-10-28 11:27:38 -040029const test = require("tape");
30
31const helpers = require("./helpers");
32const ttypes = require(`./${helpers.genPath}/ThriftTest_types`);
33const TException = require("thrift").Thrift.TException;
34const Int64 = require("node-int64");
35const testCases = require("./test-cases");
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080036
Cameron Martincaef0ed2025-01-15 11:58:39 +010037exports.ThriftTestDriver = function (client, callback) {
bforbisda1169d2018-10-28 11:27:38 -040038 test(
39 "NodeJS Style Callback Client Tests",
40 { skip: helpers.ecmaMode === "es6" },
Cameron Martincaef0ed2025-01-15 11:58:39 +010041 function (assert) {
bforbisda1169d2018-10-28 11:27:38 -040042 const checkRecursively = makeRecursiveCheck(assert);
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080043
bforbisda1169d2018-10-28 11:27:38 -040044 function makeAsserter(assertionFn) {
Cameron Martincaef0ed2025-01-15 11:58:39 +010045 return function (c) {
bforbisda1169d2018-10-28 11:27:38 -040046 const fnName = c[0];
47 const expected = c[1];
Cameron Martincaef0ed2025-01-15 11:58:39 +010048 client[fnName](expected, function (err, actual) {
bforbisda1169d2018-10-28 11:27:38 -040049 assert.error(err, fnName + ": no callback error");
50 assertionFn(actual, expected, fnName);
51 });
52 };
Nobuaki Sukegawaf56b9072015-11-23 19:38:18 +090053 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080054
bforbisda1169d2018-10-28 11:27:38 -040055 testCases.simple.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +010056 makeAsserter(function (a, e, m) {
bforbisda1169d2018-10-28 11:27:38 -040057 if (a instanceof Int64) {
58 const e64 = e instanceof Int64 ? e : new Int64(e);
59 assert.deepEqual(a.buffer, e64.buffer, m);
60 } else {
61 assert.equal(a, e, m);
62 }
Cameron Martincaef0ed2025-01-15 11:58:39 +010063 }),
bforbisda1169d2018-10-28 11:27:38 -040064 );
65 testCases.deep.forEach(makeAsserter(assert.deepEqual));
66 testCases.deepUnordered.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +010067 makeAsserter(makeUnorderedDeepEqual(assert)),
bforbisda1169d2018-10-28 11:27:38 -040068 );
Nobuaki Sukegawa8a4d06f2015-11-06 21:24:26 +090069
bforbisda1169d2018-10-28 11:27:38 -040070 const arr = [];
71 for (let i = 0; i < 256; ++i) {
72 arr[i] = 255 - i;
73 }
74 let buf = new Buffer(arr);
Cameron Martincaef0ed2025-01-15 11:58:39 +010075 client.testBinary(buf, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -040076 assert.error(err, "testBinary: no callback error");
77 assert.equal(response.length, 256, "testBinary");
78 assert.deepEqual(response, buf, "testBinary(Buffer)");
Randy Abernethyd8187c52015-02-16 01:25:53 -080079 });
bforbisda1169d2018-10-28 11:27:38 -040080 buf = new Buffer(arr);
Cameron Martincaef0ed2025-01-15 11:58:39 +010081 client.testBinary(buf.toString("binary"), function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -040082 assert.error(err, "testBinary: no callback error");
83 assert.equal(response.length, 256, "testBinary");
84 assert.deepEqual(response, buf, "testBinary(string)");
85 });
Randy Abernethyd8187c52015-02-16 01:25:53 -080086
Cameron Martincaef0ed2025-01-15 11:58:39 +010087 client.testMapMap(42, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -040088 const expected = {
Cameron Martincaef0ed2025-01-15 11:58:39 +010089 4: { 1: 1, 2: 2, 3: 3, 4: 4 },
90 "-4": { "-4": -4, "-3": -3, "-2": -2, "-1": -1 },
bforbisda1169d2018-10-28 11:27:38 -040091 };
92 assert.error(err, "testMapMap: no callback error");
93 assert.deepEqual(expected, response, "testMapMap");
94 });
95
Cameron Martincaef0ed2025-01-15 11:58:39 +010096 client.testStruct(testCases.out, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -040097 assert.error(err, "testStruct: no callback error");
98 checkRecursively(testCases.out, response, "testStruct");
99 });
100
Cameron Martincaef0ed2025-01-15 11:58:39 +0100101 client.testNest(testCases.out2, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400102 assert.error(err, "testNest: no callback error");
103 checkRecursively(testCases.out2, response, "testNest");
104 });
105
Cameron Martincaef0ed2025-01-15 11:58:39 +0100106 client.testInsanity(testCases.crazy, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400107 assert.error(err, "testInsanity: no callback error");
108 checkRecursively(testCases.insanity, response, "testInsanity");
109 });
110
Cameron Martincaef0ed2025-01-15 11:58:39 +0100111 client.testInsanity(testCases.crazy2, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400112 assert.error(err, "testInsanity2: no callback error");
113 checkRecursively(testCases.insanity, response, "testInsanity2");
114 });
115
Cameron Martincaef0ed2025-01-15 11:58:39 +0100116 client.testException("TException", function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400117 assert.ok(
118 err instanceof TException,
Cameron Martincaef0ed2025-01-15 11:58:39 +0100119 "testException: correct error type",
bforbisda1169d2018-10-28 11:27:38 -0400120 );
121 assert.ok(!response, "testException: no response");
122 });
123
Cameron Martincaef0ed2025-01-15 11:58:39 +0100124 client.testException("Xception", function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400125 assert.ok(
126 err instanceof ttypes.Xception,
Cameron Martincaef0ed2025-01-15 11:58:39 +0100127 "testException: correct error type",
bforbisda1169d2018-10-28 11:27:38 -0400128 );
129 assert.ok(!response, "testException: no response");
130 assert.equal(err.errorCode, 1001, "testException: correct error code");
131 assert.equal(
132 "Xception",
133 err.message,
Cameron Martincaef0ed2025-01-15 11:58:39 +0100134 "testException: correct error message",
bforbisda1169d2018-10-28 11:27:38 -0400135 );
136 });
137
Cameron Martincaef0ed2025-01-15 11:58:39 +0100138 client.testException("no Exception", function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400139 assert.error(err, "testException: no callback error");
140 assert.ok(!response, "testException: no response");
141 });
142
Cameron Martincaef0ed2025-01-15 11:58:39 +0100143 client.testOneway(0, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400144 assert.error(err, "testOneway: no callback error");
145 assert.strictEqual(response, undefined, "testOneway: void response");
146 });
147
Cameron Martincaef0ed2025-01-15 11:58:39 +0100148 checkOffByOne(function (done) {
149 client.testI32(-1, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400150 assert.error(err, "checkOffByOne: no callback error");
151 assert.equal(-1, response);
152 assert.end();
153 done();
154 });
155 }, callback);
Cameron Martincaef0ed2025-01-15 11:58:39 +0100156 },
bforbisda1169d2018-10-28 11:27:38 -0400157 );
158
159 // ES6 does not support callback style
160 if (helpers.ecmaMode === "es6") {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100161 checkOffByOne((done) => done(), callback);
bforbisda1169d2018-10-28 11:27:38 -0400162 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800163};
164
Cameron Martincaef0ed2025-01-15 11:58:39 +0100165exports.ThriftTestDriverPromise = function (client, callback) {
166 test("Promise Client Tests", function (assert) {
bforbisda1169d2018-10-28 11:27:38 -0400167 const checkRecursively = makeRecursiveCheck(assert);
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800168
Randy Abernethyd8187c52015-02-16 01:25:53 -0800169 function makeAsserter(assertionFn) {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100170 return function (c) {
bforbisda1169d2018-10-28 11:27:38 -0400171 const fnName = c[0];
172 const expected = c[1];
Randy Abernethyd8187c52015-02-16 01:25:53 -0800173 client[fnName](expected)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100174 .then(function (actual) {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800175 assertionFn(actual, expected, fnName);
176 })
bforbisda1169d2018-10-28 11:27:38 -0400177 .catch(() => assert.fail("fnName"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800178 };
179 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800180
bforbisda1169d2018-10-28 11:27:38 -0400181 testCases.simple.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +0100182 makeAsserter(function (a, e, m) {
bforbisda1169d2018-10-28 11:27:38 -0400183 if (a instanceof Int64) {
184 const e64 = e instanceof Int64 ? e : new Int64(e);
185 assert.deepEqual(a.buffer, e64.buffer, m);
186 } else {
187 assert.equal(a, e, m);
188 }
Cameron Martincaef0ed2025-01-15 11:58:39 +0100189 }),
bforbisda1169d2018-10-28 11:27:38 -0400190 );
Randy Abernethyd8187c52015-02-16 01:25:53 -0800191 testCases.deep.forEach(makeAsserter(assert.deepEqual));
bforbisda1169d2018-10-28 11:27:38 -0400192 testCases.deepUnordered.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +0100193 makeAsserter(makeUnorderedDeepEqual(assert)),
bforbisda1169d2018-10-28 11:27:38 -0400194 );
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800195
bforbisda1169d2018-10-28 11:27:38 -0400196 client
197 .testStruct(testCases.out)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100198 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400199 checkRecursively(testCases.out, response, "testStruct");
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800200 })
bforbisda1169d2018-10-28 11:27:38 -0400201 .catch(() => assert.fail("testStruct"));
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800202
bforbisda1169d2018-10-28 11:27:38 -0400203 client
204 .testNest(testCases.out2)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100205 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400206 checkRecursively(testCases.out2, response, "testNest");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800207 })
bforbisda1169d2018-10-28 11:27:38 -0400208 .catch(() => assert.fail("testNest"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800209
bforbisda1169d2018-10-28 11:27:38 -0400210 client
211 .testInsanity(testCases.crazy)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100212 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400213 checkRecursively(testCases.insanity, response, "testInsanity");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800214 })
bforbisda1169d2018-10-28 11:27:38 -0400215 .catch(() => assert.fail("testInsanity"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800216
bforbisda1169d2018-10-28 11:27:38 -0400217 client
218 .testInsanity(testCases.crazy2)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100219 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400220 checkRecursively(testCases.insanity, response, "testInsanity2");
Henrique Mendonça15d90422015-06-25 22:31:41 +1000221 })
bforbisda1169d2018-10-28 11:27:38 -0400222 .catch(() => assert.fail("testInsanity2"));
Henrique Mendonça15d90422015-06-25 22:31:41 +1000223
bforbisda1169d2018-10-28 11:27:38 -0400224 client
225 .testException("TException")
Cameron Martincaef0ed2025-01-15 11:58:39 +0100226 .then(function () {
bforbisda1169d2018-10-28 11:27:38 -0400227 assert.fail("testException: TException");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800228 })
Cameron Martincaef0ed2025-01-15 11:58:39 +0100229 .catch(function (err) {
Randy Abernethybd60b922015-02-26 16:59:14 -0800230 assert.ok(err instanceof TException);
231 });
Randy Abernethyd8187c52015-02-16 01:25:53 -0800232
bforbisda1169d2018-10-28 11:27:38 -0400233 client
234 .testException("Xception")
Cameron Martincaef0ed2025-01-15 11:58:39 +0100235 .then(function () {
bforbisda1169d2018-10-28 11:27:38 -0400236 assert.fail("testException: Xception");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800237 })
Cameron Martincaef0ed2025-01-15 11:58:39 +0100238 .catch(function (err) {
Randy Abernethybd60b922015-02-26 16:59:14 -0800239 assert.ok(err instanceof ttypes.Xception);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800240 assert.equal(err.errorCode, 1001);
bforbisda1169d2018-10-28 11:27:38 -0400241 assert.equal("Xception", err.message);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800242 });
243
bforbisda1169d2018-10-28 11:27:38 -0400244 client
245 .testException("no Exception")
Cameron Martincaef0ed2025-01-15 11:58:39 +0100246 .then(function (response) {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800247 assert.equal(undefined, response); //void
248 })
bforbisda1169d2018-10-28 11:27:38 -0400249 .catch(() => assert.fail("testException"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800250
bforbisda1169d2018-10-28 11:27:38 -0400251 client
252 .testOneway(0)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100253 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400254 assert.strictEqual(response, undefined, "testOneway: void response");
bforbisf2867c22018-07-17 12:19:49 -0400255 })
bforbisda1169d2018-10-28 11:27:38 -0400256 .catch(() => assert.fail("testOneway: should not reject"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800257
Cameron Martincaef0ed2025-01-15 11:58:39 +0100258 checkOffByOne(function (done) {
bforbisda1169d2018-10-28 11:27:38 -0400259 client
260 .testI32(-1)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100261 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400262 assert.equal(-1, response);
263 assert.end();
264 done();
Randy Abernethyd8187c52015-02-16 01:25:53 -0800265 })
bforbisda1169d2018-10-28 11:27:38 -0400266 .catch(() => assert.fail("checkOffByOne"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800267 }, callback);
268 });
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800269};
270
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800271// Helper Functions
272// =========================================================
273
Randy Abernethyd8187c52015-02-16 01:25:53 -0800274function makeRecursiveCheck(assert) {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100275 return function (map1, map2, msg) {
bforbisda1169d2018-10-28 11:27:38 -0400276 const equal = checkRecursively(map1, map2);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800277
278 assert.ok(equal, msg);
279
280 // deepEqual doesn't work with fields using node-int64
281 function checkRecursively(map1, map2) {
bforbisda1169d2018-10-28 11:27:38 -0400282 if (typeof map1 !== "function" && typeof map2 !== "function") {
283 if (!map1 || typeof map1 !== "object") {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800284 //Handle int64 types (which use node-int64 in Node.js JavaScript)
bforbisda1169d2018-10-28 11:27:38 -0400285 if (
286 typeof map1 === "number" &&
287 typeof map2 === "object" &&
288 map2.buffer &&
289 map2.buffer instanceof Buffer &&
290 map2.buffer.length === 8
291 ) {
292 const n = new Int64(map2.buffer);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800293 return map1 === n.toNumber();
294 } else {
295 return map1 == map2;
296 }
297 } else {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100298 return Object.keys(map1).every(function (key) {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800299 return checkRecursively(map1[key], map2[key]);
300 });
301 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800302 }
303 }
bforbisda1169d2018-10-28 11:27:38 -0400304 };
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800305}
306
307function checkOffByOne(done, callback) {
bforbisda1169d2018-10-28 11:27:38 -0400308 const retry_limit = 30;
309 const retry_interval = 100;
310 let test_complete = false;
311 let retrys = 0;
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800312
313 /**
314 * redo a simple test after the oneway to make sure we aren't "off by one" --
315 * if the server treated oneway void like normal void, this next test will
316 * fail since it will get the void confirmation rather than the correct
317 * result. In this circumstance, the client will throw the exception:
318 *
319 * Because this is the last test against the server, when it completes
320 * the entire suite is complete by definition (the tests run serially).
321 */
Cameron Martincaef0ed2025-01-15 11:58:39 +0100322 done(function () {
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800323 test_complete = true;
324 });
325
326 //We wait up to retry_limit * retry_interval for the test suite to complete
327 function TestForCompletion() {
bforbisda1169d2018-10-28 11:27:38 -0400328 if (test_complete && callback) {
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800329 callback("Server successfully tested!");
330 } else {
331 if (++retrys < retry_limit) {
332 setTimeout(TestForCompletion, retry_interval);
333 } else if (callback) {
bforbisda1169d2018-10-28 11:27:38 -0400334 callback(
335 "Server test failed to complete after " +
336 (retry_limit * retry_interval) / 1000 +
Cameron Martincaef0ed2025-01-15 11:58:39 +0100337 " seconds",
bforbisda1169d2018-10-28 11:27:38 -0400338 );
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800339 }
340 }
341 }
342
343 setTimeout(TestForCompletion, retry_interval);
344}
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700345
346function makeUnorderedDeepEqual(assert) {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100347 return function (actual, expected, name) {
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700348 assert.equal(actual.length, expected.length, name);
bforbisda1169d2018-10-28 11:27:38 -0400349 for (const k in actual) {
350 let found = false;
351 for (const k2 in expected) {
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700352 if (actual[k] === expected[k2]) {
353 found = true;
354 }
355 }
356 if (!found) {
bforbisda1169d2018-10-28 11:27:38 -0400357 assert.fail("Unexpected value " + actual[k] + " with key " + k);
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700358 }
359 }
360 };
361}