blob: 7c9a91914bf9193f5924ddda555b5c5f7af8231d [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
37exports.ThriftTestDriver = function(client, callback) {
bforbisda1169d2018-10-28 11:27:38 -040038 test(
39 "NodeJS Style Callback Client Tests",
40 { skip: helpers.ecmaMode === "es6" },
41 function(assert) {
42 const checkRecursively = makeRecursiveCheck(assert);
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -080043
bforbisda1169d2018-10-28 11:27:38 -040044 function makeAsserter(assertionFn) {
45 return function(c) {
46 const fnName = c[0];
47 const expected = c[1];
48 client[fnName](expected, function(err, actual) {
49 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(
56 makeAsserter(function(a, e, m) {
57 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 }
63 })
64 );
65 testCases.deep.forEach(makeAsserter(assert.deepEqual));
66 testCases.deepUnordered.forEach(
67 makeAsserter(makeUnorderedDeepEqual(assert))
68 );
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);
75 client.testBinary(buf, function(err, response) {
76 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);
81 client.testBinary(buf.toString("binary"), function(err, response) {
82 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
bforbisda1169d2018-10-28 11:27:38 -040087 client.testMapMap(42, function(err, response) {
88 const expected = {
89 "4": { "1": 1, "2": 2, "3": 3, "4": 4 },
90 "-4": { "-4": -4, "-3": -3, "-2": -2, "-1": -1 }
91 };
92 assert.error(err, "testMapMap: no callback error");
93 assert.deepEqual(expected, response, "testMapMap");
94 });
95
96 client.testStruct(testCases.out, function(err, response) {
97 assert.error(err, "testStruct: no callback error");
98 checkRecursively(testCases.out, response, "testStruct");
99 });
100
101 client.testNest(testCases.out2, function(err, response) {
102 assert.error(err, "testNest: no callback error");
103 checkRecursively(testCases.out2, response, "testNest");
104 });
105
106 client.testInsanity(testCases.crazy, function(err, response) {
107 assert.error(err, "testInsanity: no callback error");
108 checkRecursively(testCases.insanity, response, "testInsanity");
109 });
110
111 client.testInsanity(testCases.crazy2, function(err, response) {
112 assert.error(err, "testInsanity2: no callback error");
113 checkRecursively(testCases.insanity, response, "testInsanity2");
114 });
115
116 client.testException("TException", function(err, response) {
117 assert.ok(
118 err instanceof TException,
119 "testException: correct error type"
120 );
121 assert.ok(!response, "testException: no response");
122 });
123
124 client.testException("Xception", function(err, response) {
125 assert.ok(
126 err instanceof ttypes.Xception,
127 "testException: correct error type"
128 );
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,
134 "testException: correct error message"
135 );
136 });
137
138 client.testException("no Exception", function(err, response) {
139 assert.error(err, "testException: no callback error");
140 assert.ok(!response, "testException: no response");
141 });
142
143 client.testOneway(0, function(err, response) {
144 assert.error(err, "testOneway: no callback error");
145 assert.strictEqual(response, undefined, "testOneway: void response");
146 });
147
148 checkOffByOne(function(done) {
149 client.testI32(-1, function(err, response) {
150 assert.error(err, "checkOffByOne: no callback error");
151 assert.equal(-1, response);
152 assert.end();
153 done();
154 });
155 }, callback);
156 }
157 );
158
159 // ES6 does not support callback style
160 if (helpers.ecmaMode === "es6") {
161 checkOffByOne(done => done(), callback);
162 }
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800163};
164
165exports.ThriftTestDriverPromise = function(client, callback) {
bforbisda1169d2018-10-28 11:27:38 -0400166 test("Promise Client Tests", function(assert) {
167 const checkRecursively = makeRecursiveCheck(assert);
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800168
Randy Abernethyd8187c52015-02-16 01:25:53 -0800169 function makeAsserter(assertionFn) {
170 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)
174 .then(function(actual) {
175 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(
182 makeAsserter(function(a, e, m) {
183 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 }
189 })
190 );
Randy Abernethyd8187c52015-02-16 01:25:53 -0800191 testCases.deep.forEach(makeAsserter(assert.deepEqual));
bforbisda1169d2018-10-28 11:27:38 -0400192 testCases.deepUnordered.forEach(
193 makeAsserter(makeUnorderedDeepEqual(assert))
194 );
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800195
bforbisda1169d2018-10-28 11:27:38 -0400196 client
197 .testStruct(testCases.out)
Randy Abernethy3b9ff4d2015-02-16 00:51:24 -0800198 .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)
Randy Abernethyd8187c52015-02-16 01:25:53 -0800205 .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)
Randy Abernethyd8187c52015-02-16 01:25:53 -0800212 .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)
Henrique Mendonça15d90422015-06-25 22:31:41 +1000219 .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")
226 .then(function() {
227 assert.fail("testException: TException");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800228 })
bforbisda1169d2018-10-28 11:27:38 -0400229 .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")
235 .then(function() {
236 assert.fail("testException: Xception");
Randy Abernethyd8187c52015-02-16 01:25:53 -0800237 })
bforbisda1169d2018-10-28 11:27:38 -0400238 .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")
Randy Abernethyd8187c52015-02-16 01:25:53 -0800246 .then(function(response) {
247 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)
bforbisf2867c22018-07-17 12:19:49 -0400253 .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
258 checkOffByOne(function(done) {
bforbisda1169d2018-10-28 11:27:38 -0400259 client
260 .testI32(-1)
Randy Abernethyd8187c52015-02-16 01:25:53 -0800261 .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) {
bforbisda1169d2018-10-28 11:27:38 -0400275 return function(map1, map2, msg) {
276 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 {
298 return Object.keys(map1).every(function(key) {
299 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 */
322 done(function() {
323 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 +
337 " seconds"
338 );
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) {
347 return function(actual, expected, name) {
348 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}