| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 1 | /* | 
 | 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 |  | 
 | 20 |  // 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. | 
 | 28 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 29 | var test = require('tape'); | 
 | 30 | //var assert = require('assert'); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 31 | var ttypes = require('./gen-nodejs/ThriftTest_types'); | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 32 | var TException = require('thrift').Thrift.TException; | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 33 | var Int64 = require('node-int64'); | 
 | 34 | var testCases = require('./test-cases'); | 
 | 35 |  | 
 | 36 | exports.ThriftTestDriver = function(client, callback) { | 
 | 37 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 38 |   test('NodeJS Style Callback Client Tests', function(assert) { | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 39 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 40 |     var checkRecursively = makeRecursiveCheck(assert); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 41 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 42 |     function makeAsserter(assertionFn) { | 
 | 43 |       return function(c) { | 
 | 44 |         var fnName = c[0]; | 
 | 45 |         var expected = c[1]; | 
 | 46 |         client[fnName](expected, function(err, actual) { | 
 | 47 |           assert.error(err, fnName + ': no callback error'); | 
 | 48 |           assertionFn(actual, expected, fnName); | 
 | 49 |         }) | 
 | 50 |       }; | 
 | 51 |     } | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 52 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 53 |     testCases.simple.forEach(makeAsserter(assert.equal)); | 
 | 54 |     testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){ | 
 | 55 |       assert.ok(a == e, m); | 
 | 56 |     })); | 
 | 57 |     testCases.deep.forEach(makeAsserter(assert.deepEqual)); | 
| Randy Abernethy | 983bf7d | 2015-10-09 12:28:57 -0700 | [diff] [blame] | 58 |     testCases.deepUnordered.forEach(makeAsserter(makeUnorderedDeepEqual(assert))); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 59 |  | 
| Nobuaki Sukegawa | 8a4d06f | 2015-11-06 21:24:26 +0900 | [diff] [blame^] | 60 |     var arr = []; | 
 | 61 |     for (var i = 0; i < 256; ++i) { | 
 | 62 |       arr[i] = 255 - i; | 
 | 63 |     } | 
 | 64 |     var buf = new Buffer(arr); | 
 | 65 |     client.testBinary(buf, function(err, response) { | 
 | 66 |       assert.error(err, 'testBinary: no callback error'); | 
 | 67 |       assert.equal(response.length, 256, 'testBinary'); | 
 | 68 |       assert.deepEqual(response, buf, 'testBinary(Buffer)'); | 
 | 69 |     }); | 
 | 70 |     var buf = new Buffer(arr); | 
 | 71 |     client.testBinary(buf.toString('binary'), function(err, response) { | 
 | 72 |       assert.error(err, 'testBinary: no callback error'); | 
 | 73 |       assert.equal(response.length, 256, 'testBinary'); | 
 | 74 |       assert.deepEqual(response, buf, 'testBinary(string)'); | 
 | 75 |     }); | 
 | 76 |  | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 77 |     client.testMapMap(42, function(err, response) { | 
 | 78 |       var expected = { | 
 | 79 |         "4": {"1":1, "2":2, "3":3, "4":4}, | 
 | 80 |         "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1} | 
 | 81 |       }; | 
 | 82 |       assert.error(err, 'testMapMap: no callback error'); | 
 | 83 |       assert.deepEqual(expected, response, 'testMapMap'); | 
 | 84 |     }); | 
 | 85 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 86 |     client.testStruct(testCases.out, function(err, response) { | 
 | 87 |       assert.error(err, 'testStruct: no callback error'); | 
 | 88 |       checkRecursively(testCases.out, response, 'testStruct'); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 89 |     }); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 90 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 91 |     client.testNest(testCases.out2, function(err, response) { | 
 | 92 |       assert.error(err, 'testNest: no callback error'); | 
 | 93 |       checkRecursively(testCases.out2, response, 'testNest'); | 
 | 94 |     }); | 
 | 95 |  | 
 | 96 |     client.testInsanity(testCases.crazy, function(err, response) { | 
 | 97 |       assert.error(err, 'testInsanity: no callback error'); | 
 | 98 |       checkRecursively(testCases.insanity, response, 'testInsanity'); | 
 | 99 |     }); | 
 | 100 |  | 
| Henrique Mendonça | 15d9042 | 2015-06-25 22:31:41 +1000 | [diff] [blame] | 101 |     client.testInsanity(testCases.crazy2, function(err, response) { | 
 | 102 |       assert.error(err, 'testInsanity2: no callback error'); | 
 | 103 |       checkRecursively(testCases.insanity, response, 'testInsanity2'); | 
 | 104 |     }); | 
 | 105 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 106 |     client.testException('TException', function(err, response) { | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 107 |       assert.ok(err instanceof TException, 'testException: correct error type'); | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 108 |       assert.ok(!response, 'testException: no response'); | 
 | 109 |     }); | 
 | 110 |  | 
 | 111 |     client.testException('Xception', function(err, response) { | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 112 |       assert.ok(err instanceof ttypes.Xception, 'testException: correct error type'); | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 113 |       assert.ok(!response, 'testException: no response'); | 
 | 114 |       assert.equal(err.errorCode, 1001, 'testException: correct error code'); | 
 | 115 |       assert.equal('Xception', err.message, 'testException: correct error message'); | 
 | 116 |     }); | 
 | 117 |  | 
 | 118 |     client.testException('no Exception', function(err, response) { | 
 | 119 |       assert.error(err, 'testException: no callback error'); | 
 | 120 |       assert.ok(!response, 'testException: no response'); | 
 | 121 |     }); | 
 | 122 |  | 
 | 123 |     client.testOneway(0, function(err, response) { | 
 | 124 |       assert.fail('testOneway should not answer'); | 
 | 125 |     }); | 
 | 126 |  | 
 | 127 |     checkOffByOne(function(done) { | 
 | 128 |       client.testI32(-1, function(err, response) { | 
 | 129 |         assert.error(err, 'checkOffByOne: no callback error'); | 
 | 130 |         assert.equal(-1, response); | 
 | 131 |         assert.end(); | 
 | 132 |         done(); | 
 | 133 |       }); | 
 | 134 |     }, callback); | 
 | 135 |  | 
 | 136 |   }); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 137 | }; | 
 | 138 |  | 
 | 139 | exports.ThriftTestDriverPromise = function(client, callback) { | 
 | 140 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 141 |   test('Q Promise Client Tests', function(assert) { | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 142 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 143 |     var checkRecursively = makeRecursiveCheck(assert); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 144 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 145 |     function fail(msg) { | 
 | 146 |       return function() { | 
 | 147 |         assert.fail(msg); | 
 | 148 |       } | 
 | 149 |     } | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 150 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 151 |     function makeAsserter(assertionFn) { | 
 | 152 |       return function(c) { | 
 | 153 |         var fnName = c[0]; | 
 | 154 |         var expected = c[1]; | 
 | 155 |         client[fnName](expected) | 
 | 156 |           .then(function(actual) { | 
 | 157 |             assertionFn(actual, expected, fnName); | 
 | 158 |           }) | 
 | 159 |           .fail(fail('fnName')); | 
 | 160 |       }; | 
 | 161 |     } | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 162 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 163 |     testCases.simple.forEach(makeAsserter(assert.equal)); | 
 | 164 |     testCases.simpleLoose.forEach(makeAsserter(function(a, e, m){ | 
 | 165 |       assert.ok(a == e, m); | 
 | 166 |     })); | 
 | 167 |     testCases.deep.forEach(makeAsserter(assert.deepEqual)); | 
| Randy Abernethy | 983bf7d | 2015-10-09 12:28:57 -0700 | [diff] [blame] | 168 |     testCases.deepUnordered.forEach(makeAsserter(makeUnorderedDeepEqual(assert))); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 169 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 170 |     client.testStruct(testCases.out) | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 171 |       .then(function(response) { | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 172 |         checkRecursively(testCases.out, response, 'testStruct'); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 173 |       }) | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 174 |       .fail(fail('testStruct')); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 175 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 176 |     client.testNest(testCases.out2) | 
 | 177 |       .then(function(response) { | 
 | 178 |         checkRecursively(testCases.out2, response, 'testNest'); | 
 | 179 |       }) | 
 | 180 |       .fail(fail('testNest')); | 
 | 181 |  | 
 | 182 |     client.testInsanity(testCases.crazy) | 
 | 183 |       .then(function(response) { | 
 | 184 |         checkRecursively(testCases.insanity, response, 'testInsanity'); | 
 | 185 |       }) | 
 | 186 |       .fail(fail('testInsanity')); | 
 | 187 |  | 
| Henrique Mendonça | 15d9042 | 2015-06-25 22:31:41 +1000 | [diff] [blame] | 188 |     client.testInsanity(testCases.crazy2) | 
 | 189 |       .then(function(response) { | 
 | 190 |         checkRecursively(testCases.insanity, response, 'testInsanity2'); | 
 | 191 |       }) | 
 | 192 |       .fail(fail('testInsanity2')); | 
 | 193 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 194 |     client.testException('TException') | 
 | 195 |       .then(function(response) { | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 196 |         fail('testException: TException'); | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 197 |       }) | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 198 |       .fail(function(err) { | 
 | 199 |         assert.ok(err instanceof TException); | 
 | 200 |       }); | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 201 |  | 
 | 202 |     client.testException('Xception') | 
 | 203 |       .then(function(response) { | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 204 |         fail('testException: Xception'); | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 205 |       }) | 
 | 206 |       .fail(function(err) { | 
| Randy Abernethy | bd60b92 | 2015-02-26 16:59:14 -0800 | [diff] [blame] | 207 |         assert.ok(err instanceof ttypes.Xception); | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 208 |         assert.equal(err.errorCode, 1001); | 
 | 209 |         assert.equal('Xception', err.message); | 
 | 210 |       }); | 
 | 211 |  | 
 | 212 |     client.testException('no Exception') | 
 | 213 |       .then(function(response) { | 
 | 214 |         assert.equal(undefined, response); //void | 
 | 215 |       }) | 
 | 216 |       .fail(fail('testException')); | 
 | 217 |  | 
 | 218 |     client.testOneway(0, fail('testOneway: should not answer')); | 
 | 219 |  | 
 | 220 |     checkOffByOne(function(done) { | 
 | 221 |       client.testI32(-1) | 
 | 222 |         .then(function(response) { | 
 | 223 |             assert.equal(-1, response); | 
 | 224 |             assert.end(); | 
 | 225 |             done(); | 
 | 226 |         }) | 
 | 227 |         .fail(fail('checkOffByOne')); | 
 | 228 |     }, callback); | 
 | 229 |   }); | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 230 | }; | 
 | 231 |  | 
 | 232 |  | 
 | 233 | // Helper Functions | 
 | 234 | // ========================================================= | 
 | 235 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 236 | function makeRecursiveCheck(assert) { | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 237 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 238 |   return function (map1, map2, msg) { | 
 | 239 |     var equal = true; | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 240 |  | 
| Randy Abernethy | d8187c5 | 2015-02-16 01:25:53 -0800 | [diff] [blame] | 241 |     var equal = checkRecursively(map1, map2); | 
 | 242 |  | 
 | 243 |     assert.ok(equal, msg); | 
 | 244 |  | 
 | 245 |     // deepEqual doesn't work with fields using node-int64 | 
 | 246 |     function checkRecursively(map1, map2) { | 
 | 247 |       if (typeof map1 !== 'function' && typeof map2 !== 'function') { | 
 | 248 |         if (!map1 || typeof map1 !== 'object') { | 
 | 249 |           //Handle int64 types (which use node-int64 in Node.js JavaScript) | 
 | 250 |           if ((typeof map1 === "number") && (typeof map2 === "object") && | 
 | 251 |               (map2.buffer) && (map2.buffer instanceof Buffer) && (map2.buffer.length === 8)) { | 
 | 252 |             var n = new Int64(map2.buffer); | 
 | 253 |             return map1 === n.toNumber(); | 
 | 254 |           } else { | 
 | 255 |             return map1 == map2; | 
 | 256 |           } | 
 | 257 |         } else { | 
 | 258 |           return Object.keys(map1).every(function(key) { | 
 | 259 |             return checkRecursively(map1[key], map2[key]); | 
 | 260 |           }); | 
 | 261 |         } | 
| Randy Abernethy | 3b9ff4d | 2015-02-16 00:51:24 -0800 | [diff] [blame] | 262 |       } | 
 | 263 |     } | 
 | 264 |   } | 
 | 265 | } | 
 | 266 |  | 
 | 267 | function checkOffByOne(done, callback) { | 
 | 268 |  | 
 | 269 |   var retry_limit = 30; | 
 | 270 |   var retry_interval = 100; | 
 | 271 |   var test_complete = false; | 
 | 272 |   var retrys = 0; | 
 | 273 |  | 
 | 274 |   /** | 
 | 275 |    * redo a simple test after the oneway to make sure we aren't "off by one" -- | 
 | 276 |    * if the server treated oneway void like normal void, this next test will | 
 | 277 |    * fail since it will get the void confirmation rather than the correct | 
 | 278 |    * result. In this circumstance, the client will throw the exception: | 
 | 279 |    * | 
 | 280 |    * Because this is the last test against the server, when it completes | 
 | 281 |    * the entire suite is complete by definition (the tests run serially). | 
 | 282 |    */ | 
 | 283 |   done(function() { | 
 | 284 |     test_complete = true; | 
 | 285 |   }); | 
 | 286 |  | 
 | 287 |   //We wait up to retry_limit * retry_interval for the test suite to complete | 
 | 288 |   function TestForCompletion() { | 
 | 289 |     if(test_complete && callback) { | 
 | 290 |       callback("Server successfully tested!"); | 
 | 291 |     } else { | 
 | 292 |       if (++retrys < retry_limit) { | 
 | 293 |         setTimeout(TestForCompletion, retry_interval); | 
 | 294 |       } else if (callback) { | 
 | 295 |         callback("Server test failed to complete after " + | 
 | 296 |                  (retry_limit * retry_interval / 1000) + " seconds"); | 
 | 297 |       } | 
 | 298 |     } | 
 | 299 |   } | 
 | 300 |  | 
 | 301 |   setTimeout(TestForCompletion, retry_interval); | 
 | 302 | } | 
| Randy Abernethy | 983bf7d | 2015-10-09 12:28:57 -0700 | [diff] [blame] | 303 |  | 
 | 304 | function makeUnorderedDeepEqual(assert) { | 
 | 305 |   return function(actual, expected, name) { | 
 | 306 |     assert.equal(actual.length, expected.length, name); | 
 | 307 |     for (var k in actual) { | 
 | 308 |       var found = false; | 
 | 309 |       for (var k2 in expected) { | 
 | 310 |         if (actual[k] === expected[k2]) { | 
 | 311 |           found = true; | 
 | 312 |         } | 
 | 313 |       } | 
 | 314 |       if (!found) { | 
 | 315 |         assert.fail('Unexpected value ' + actual[k] + ' with key ' + k); | 
 | 316 |       } | 
 | 317 |     } | 
 | 318 |   }; | 
 | 319 | } |