blob: eca56ba773c7e0296fc0b7e15c4c5ccf94b3d8f4 [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
Cameron Martin21ed4a22024-04-22 11:08:19 +010029import test from "tape";
bforbisda1169d2018-10-28 11:27:38 -040030
Cameron Martin21ed4a22024-04-22 11:08:19 +010031import helpers from "./helpers.js";
32import thrift from "thrift";
33import Int64 from "node-int64";
34import * as testCases from "./test-cases.mjs";
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080035
Cameron Martin21ed4a22024-04-22 11:08:19 +010036const ttypes = await import(
37 `./${helpers.genPath}/ThriftTest_types.${helpers.moduleExt}`
38);
39
40const TException = thrift.Thrift.TException;
41
42export const ThriftTestDriver = function (client, callback) {
bforbisda1169d2018-10-28 11:27:38 -040043 test(
44 "NodeJS Style Callback Client Tests",
45 { skip: helpers.ecmaMode === "es6" },
Cameron Martincaef0ed2025-01-15 11:58:39 +010046 function (assert) {
bforbisda1169d2018-10-28 11:27:38 -040047 const checkRecursively = makeRecursiveCheck(assert);
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080048
bforbisda1169d2018-10-28 11:27:38 -040049 function makeAsserter(assertionFn) {
Cameron Martincaef0ed2025-01-15 11:58:39 +010050 return function (c) {
bforbisda1169d2018-10-28 11:27:38 -040051 const fnName = c[0];
52 const expected = c[1];
Cameron Martincaef0ed2025-01-15 11:58:39 +010053 client[fnName](expected, function (err, actual) {
bforbisda1169d2018-10-28 11:27:38 -040054 assert.error(err, fnName + ": no callback error");
55 assertionFn(actual, expected, fnName);
56 });
57 };
Nobuaki Sukegawaf56b9072015-11-23 19:38:18 +090058 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080059
bforbisda1169d2018-10-28 11:27:38 -040060 testCases.simple.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +010061 makeAsserter(function (a, e, m) {
bforbisda1169d2018-10-28 11:27:38 -040062 if (a instanceof Int64) {
63 const e64 = e instanceof Int64 ? e : new Int64(e);
64 assert.deepEqual(a.buffer, e64.buffer, m);
65 } else {
66 assert.equal(a, e, m);
67 }
Cameron Martincaef0ed2025-01-15 11:58:39 +010068 }),
bforbisda1169d2018-10-28 11:27:38 -040069 );
70 testCases.deep.forEach(makeAsserter(assert.deepEqual));
71 testCases.deepUnordered.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +010072 makeAsserter(makeUnorderedDeepEqual(assert)),
bforbisda1169d2018-10-28 11:27:38 -040073 );
Nobuaki Sukegawa8a4d06f2015-11-06 21:24:26 +090074
bforbisda1169d2018-10-28 11:27:38 -040075 const arr = [];
76 for (let i = 0; i < 256; ++i) {
77 arr[i] = 255 - i;
78 }
79 let buf = new Buffer(arr);
Cameron Martincaef0ed2025-01-15 11:58:39 +010080 client.testBinary(buf, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -040081 assert.error(err, "testBinary: no callback error");
82 assert.equal(response.length, 256, "testBinary");
83 assert.deepEqual(response, buf, "testBinary(Buffer)");
Randy Abernethyd8187c52015-02-16 01:25:53 -080084 });
bforbisda1169d2018-10-28 11:27:38 -040085 buf = new Buffer(arr);
Cameron Martincaef0ed2025-01-15 11:58:39 +010086 client.testBinary(buf.toString("binary"), function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -040087 assert.error(err, "testBinary: no callback error");
88 assert.equal(response.length, 256, "testBinary");
89 assert.deepEqual(response, buf, "testBinary(string)");
90 });
Randy Abernethyd8187c52015-02-16 01:25:53 -080091
Cameron Martincaef0ed2025-01-15 11:58:39 +010092 client.testMapMap(42, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -040093 const expected = {
Cameron Martincaef0ed2025-01-15 11:58:39 +010094 4: { 1: 1, 2: 2, 3: 3, 4: 4 },
95 "-4": { "-4": -4, "-3": -3, "-2": -2, "-1": -1 },
bforbisda1169d2018-10-28 11:27:38 -040096 };
97 assert.error(err, "testMapMap: no callback error");
98 assert.deepEqual(expected, response, "testMapMap");
99 });
100
Cameron Martincaef0ed2025-01-15 11:58:39 +0100101 client.testStruct(testCases.out, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400102 assert.error(err, "testStruct: no callback error");
103 checkRecursively(testCases.out, response, "testStruct");
104 });
105
Cameron Martincaef0ed2025-01-15 11:58:39 +0100106 client.testNest(testCases.out2, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400107 assert.error(err, "testNest: no callback error");
108 checkRecursively(testCases.out2, response, "testNest");
109 });
110
Cameron Martincaef0ed2025-01-15 11:58:39 +0100111 client.testInsanity(testCases.crazy, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400112 assert.error(err, "testInsanity: no callback error");
113 checkRecursively(testCases.insanity, response, "testInsanity");
114 });
115
Cameron Martincaef0ed2025-01-15 11:58:39 +0100116 client.testInsanity(testCases.crazy2, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400117 assert.error(err, "testInsanity2: no callback error");
118 checkRecursively(testCases.insanity, response, "testInsanity2");
119 });
120
Cameron Martincaef0ed2025-01-15 11:58:39 +0100121 client.testException("TException", function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400122 assert.ok(
123 err instanceof TException,
Cameron Martincaef0ed2025-01-15 11:58:39 +0100124 "testException: correct error type",
bforbisda1169d2018-10-28 11:27:38 -0400125 );
126 assert.ok(!response, "testException: no response");
127 });
128
Cameron Martincaef0ed2025-01-15 11:58:39 +0100129 client.testException("Xception", function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400130 assert.ok(
131 err instanceof ttypes.Xception,
Cameron Martincaef0ed2025-01-15 11:58:39 +0100132 "testException: correct error type",
bforbisda1169d2018-10-28 11:27:38 -0400133 );
134 assert.ok(!response, "testException: no response");
135 assert.equal(err.errorCode, 1001, "testException: correct error code");
136 assert.equal(
137 "Xception",
138 err.message,
Cameron Martincaef0ed2025-01-15 11:58:39 +0100139 "testException: correct error message",
bforbisda1169d2018-10-28 11:27:38 -0400140 );
141 });
142
Cameron Martincaef0ed2025-01-15 11:58:39 +0100143 client.testException("no Exception", function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400144 assert.error(err, "testException: no callback error");
145 assert.ok(!response, "testException: no response");
146 });
147
Cameron Martincaef0ed2025-01-15 11:58:39 +0100148 client.testOneway(0, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400149 assert.error(err, "testOneway: no callback error");
150 assert.strictEqual(response, undefined, "testOneway: void response");
151 });
152
Cameron Martincaef0ed2025-01-15 11:58:39 +0100153 checkOffByOne(function (done) {
154 client.testI32(-1, function (err, response) {
bforbisda1169d2018-10-28 11:27:38 -0400155 assert.error(err, "checkOffByOne: no callback error");
156 assert.equal(-1, response);
157 assert.end();
158 done();
159 });
160 }, callback);
Cameron Martincaef0ed2025-01-15 11:58:39 +0100161 },
bforbisda1169d2018-10-28 11:27:38 -0400162 );
163
164 // ES6 does not support callback style
165 if (helpers.ecmaMode === "es6") {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100166 checkOffByOne((done) => done(), callback);
bforbisda1169d2018-10-28 11:27:38 -0400167 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800168};
169
Cameron Martin21ed4a22024-04-22 11:08:19 +0100170export const ThriftTestDriverPromise = function (client, callback) {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100171 test("Promise Client Tests", function (assert) {
bforbisda1169d2018-10-28 11:27:38 -0400172 const checkRecursively = makeRecursiveCheck(assert);
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800173
Randy Abernethyd8187c52015-02-16 01:25:53 -0800174 function makeAsserter(assertionFn) {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100175 return function (c) {
bforbisda1169d2018-10-28 11:27:38 -0400176 const fnName = c[0];
177 const expected = c[1];
Randy Abernethyd8187c52015-02-16 01:25:53 -0800178 client[fnName](expected)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100179 .then(function (actual) {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800180 assertionFn(actual, expected, fnName);
181 })
bforbisda1169d2018-10-28 11:27:38 -0400182 .catch(() => assert.fail("fnName"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800183 };
184 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800185
bforbisda1169d2018-10-28 11:27:38 -0400186 testCases.simple.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +0100187 makeAsserter(function (a, e, m) {
bforbisda1169d2018-10-28 11:27:38 -0400188 if (a instanceof Int64) {
189 const e64 = e instanceof Int64 ? e : new Int64(e);
190 assert.deepEqual(a.buffer, e64.buffer, m);
191 } else {
192 assert.equal(a, e, m);
193 }
Cameron Martincaef0ed2025-01-15 11:58:39 +0100194 }),
bforbisda1169d2018-10-28 11:27:38 -0400195 );
Randy Abernethyd8187c52015-02-16 01:25:53 -0800196 testCases.deep.forEach(makeAsserter(assert.deepEqual));
bforbisda1169d2018-10-28 11:27:38 -0400197 testCases.deepUnordered.forEach(
Cameron Martincaef0ed2025-01-15 11:58:39 +0100198 makeAsserter(makeUnorderedDeepEqual(assert)),
bforbisda1169d2018-10-28 11:27:38 -0400199 );
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800200
bforbisda1169d2018-10-28 11:27:38 -0400201 client
202 .testStruct(testCases.out)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100203 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400204 checkRecursively(testCases.out, response, "testStruct");
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800205 })
bforbisda1169d2018-10-28 11:27:38 -0400206 .catch(() => assert.fail("testStruct"));
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800207
bforbisda1169d2018-10-28 11:27:38 -0400208 client
209 .testNest(testCases.out2)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100210 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400211 checkRecursively(testCases.out2, response, "testNest");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800212 })
bforbisda1169d2018-10-28 11:27:38 -0400213 .catch(() => assert.fail("testNest"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800214
bforbisda1169d2018-10-28 11:27:38 -0400215 client
216 .testInsanity(testCases.crazy)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100217 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400218 checkRecursively(testCases.insanity, response, "testInsanity");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800219 })
bforbisda1169d2018-10-28 11:27:38 -0400220 .catch(() => assert.fail("testInsanity"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800221
bforbisda1169d2018-10-28 11:27:38 -0400222 client
223 .testInsanity(testCases.crazy2)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100224 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400225 checkRecursively(testCases.insanity, response, "testInsanity2");
Henrique Mendonça15d90422015-06-25 22:31:41 +1000226 })
bforbisda1169d2018-10-28 11:27:38 -0400227 .catch(() => assert.fail("testInsanity2"));
Henrique Mendonça15d90422015-06-25 22:31:41 +1000228
bforbisda1169d2018-10-28 11:27:38 -0400229 client
230 .testException("TException")
Cameron Martincaef0ed2025-01-15 11:58:39 +0100231 .then(function () {
bforbisda1169d2018-10-28 11:27:38 -0400232 assert.fail("testException: TException");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800233 })
Cameron Martincaef0ed2025-01-15 11:58:39 +0100234 .catch(function (err) {
Randy Abernethybd60b922015-02-26 16:59:14 -0800235 assert.ok(err instanceof TException);
236 });
Randy Abernethyd8187c52015-02-16 01:25:53 -0800237
bforbisda1169d2018-10-28 11:27:38 -0400238 client
239 .testException("Xception")
Cameron Martincaef0ed2025-01-15 11:58:39 +0100240 .then(function () {
bforbisda1169d2018-10-28 11:27:38 -0400241 assert.fail("testException: Xception");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800242 })
Cameron Martincaef0ed2025-01-15 11:58:39 +0100243 .catch(function (err) {
Randy Abernethybd60b922015-02-26 16:59:14 -0800244 assert.ok(err instanceof ttypes.Xception);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800245 assert.equal(err.errorCode, 1001);
bforbisda1169d2018-10-28 11:27:38 -0400246 assert.equal("Xception", err.message);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800247 });
248
bforbisda1169d2018-10-28 11:27:38 -0400249 client
250 .testException("no Exception")
Cameron Martincaef0ed2025-01-15 11:58:39 +0100251 .then(function (response) {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800252 assert.equal(undefined, response); //void
253 })
bforbisda1169d2018-10-28 11:27:38 -0400254 .catch(() => assert.fail("testException"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800255
bforbisda1169d2018-10-28 11:27:38 -0400256 client
257 .testOneway(0)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100258 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400259 assert.strictEqual(response, undefined, "testOneway: void response");
bforbisf2867c22018-07-17 12:19:49 -0400260 })
bforbisda1169d2018-10-28 11:27:38 -0400261 .catch(() => assert.fail("testOneway: should not reject"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800262
Cameron Martincaef0ed2025-01-15 11:58:39 +0100263 checkOffByOne(function (done) {
bforbisda1169d2018-10-28 11:27:38 -0400264 client
265 .testI32(-1)
Cameron Martincaef0ed2025-01-15 11:58:39 +0100266 .then(function (response) {
bforbisda1169d2018-10-28 11:27:38 -0400267 assert.equal(-1, response);
268 assert.end();
269 done();
Randy Abernethyd8187c52015-02-16 01:25:53 -0800270 })
bforbisda1169d2018-10-28 11:27:38 -0400271 .catch(() => assert.fail("checkOffByOne"));
Randy Abernethyd8187c52015-02-16 01:25:53 -0800272 }, callback);
273 });
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800274};
275
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800276// Helper Functions
277// =========================================================
278
Randy Abernethyd8187c52015-02-16 01:25:53 -0800279function makeRecursiveCheck(assert) {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100280 return function (map1, map2, msg) {
bforbisda1169d2018-10-28 11:27:38 -0400281 const equal = checkRecursively(map1, map2);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800282
283 assert.ok(equal, msg);
284
285 // deepEqual doesn't work with fields using node-int64
286 function checkRecursively(map1, map2) {
bforbisda1169d2018-10-28 11:27:38 -0400287 if (typeof map1 !== "function" && typeof map2 !== "function") {
288 if (!map1 || typeof map1 !== "object") {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800289 //Handle int64 types (which use node-int64 in Node.js JavaScript)
bforbisda1169d2018-10-28 11:27:38 -0400290 if (
291 typeof map1 === "number" &&
292 typeof map2 === "object" &&
293 map2.buffer &&
294 map2.buffer instanceof Buffer &&
295 map2.buffer.length === 8
296 ) {
297 const n = new Int64(map2.buffer);
Randy Abernethyd8187c52015-02-16 01:25:53 -0800298 return map1 === n.toNumber();
299 } else {
300 return map1 == map2;
301 }
302 } else {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100303 return Object.keys(map1).every(function (key) {
Randy Abernethyd8187c52015-02-16 01:25:53 -0800304 return checkRecursively(map1[key], map2[key]);
305 });
306 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800307 }
308 }
bforbisda1169d2018-10-28 11:27:38 -0400309 };
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800310}
311
312function checkOffByOne(done, callback) {
bforbisda1169d2018-10-28 11:27:38 -0400313 const retry_limit = 30;
314 const retry_interval = 100;
315 let test_complete = false;
316 let retrys = 0;
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800317
318 /**
319 * redo a simple test after the oneway to make sure we aren't "off by one" --
320 * if the server treated oneway void like normal void, this next test will
321 * fail since it will get the void confirmation rather than the correct
322 * result. In this circumstance, the client will throw the exception:
323 *
324 * Because this is the last test against the server, when it completes
325 * the entire suite is complete by definition (the tests run serially).
326 */
Cameron Martincaef0ed2025-01-15 11:58:39 +0100327 done(function () {
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800328 test_complete = true;
329 });
330
331 //We wait up to retry_limit * retry_interval for the test suite to complete
332 function TestForCompletion() {
bforbisda1169d2018-10-28 11:27:38 -0400333 if (test_complete && callback) {
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800334 callback("Server successfully tested!");
335 } else {
336 if (++retrys < retry_limit) {
337 setTimeout(TestForCompletion, retry_interval);
338 } else if (callback) {
bforbisda1169d2018-10-28 11:27:38 -0400339 callback(
340 "Server test failed to complete after " +
341 (retry_limit * retry_interval) / 1000 +
Cameron Martincaef0ed2025-01-15 11:58:39 +0100342 " seconds",
bforbisda1169d2018-10-28 11:27:38 -0400343 );
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800344 }
345 }
346 }
347
348 setTimeout(TestForCompletion, retry_interval);
349}
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700350
351function makeUnorderedDeepEqual(assert) {
Cameron Martincaef0ed2025-01-15 11:58:39 +0100352 return function (actual, expected, name) {
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700353 assert.equal(actual.length, expected.length, name);
bforbisda1169d2018-10-28 11:27:38 -0400354 for (const k in actual) {
355 let found = false;
356 for (const k2 in expected) {
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700357 if (actual[k] === expected[k2]) {
358 found = true;
359 }
360 }
361 if (!found) {
bforbisda1169d2018-10-28 11:27:38 -0400362 assert.fail("Unexpected value " + actual[k] + " with key " + k);
Randy Abernethy983bf7d2015-10-09 12:28:57 -0700363 }
364 }
365 };
366}