From: Jens Geyer Date: Fri, 10 Jan 2014 20:26:25 +0000 (+0100) Subject: THRIFT-2205 Node.js Test Server to support test.js JavaScript Browser test and sundry... X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=b9d55220ceb718b8fc32ef78874744072ef27893;p=common%2Fthrift.git THRIFT-2205 Node.js Test Server to support test.js JavaScript Browser test and sundry fixes Patch: Randy Abernethy, Pierre Lamot --- diff --git a/lib/nodejs/lib/thrift/connection.js b/lib/nodejs/lib/thrift/connection.js index 8303b08f..8bcc9dfa 100644 --- a/lib/nodejs/lib/thrift/connection.js +++ b/lib/nodejs/lib/thrift/connection.js @@ -91,25 +91,27 @@ var Connection = exports.Connection = function(stream, options) { this.connection.addListener("data", self.transport.receiver(function(transport_with_data) { var message = new self.protocol(transport_with_data); try { - var header = message.readMessageBegin(); - var dummy_seqid = header.rseqid * -1; - var client = self.client; - client._reqs[dummy_seqid] = function(err, success){ - transport_with_data.commitPosition(); - - var callback = client._reqs[header.rseqid]; - delete client._reqs[header.rseqid]; - if (callback) { - callback(err, success); + while (true) { + var header = message.readMessageBegin(); + var dummy_seqid = header.rseqid * -1; + var client = self.client; + client._reqs[dummy_seqid] = function(err, success){ + transport_with_data.commitPosition(); + + var callback = client._reqs[header.rseqid]; + delete client._reqs[header.rseqid]; + if (callback) { + callback(err, success); + } + }; + + if(!client['recv_' + header.fname]) { + // msg was for another serivce, just drop it + delete client._reqs[dummy_seqid] + return } - }; - -if(!client['recv_' + header.fname]) { -// msg was for another serivce, just drop it -delete client._reqs[dummy_seqid] -return -} - client['recv_' + header.fname](message, header.mtype, dummy_seqid); + client['recv_' + header.fname](message, header.mtype, dummy_seqid); + } } catch (e) { if (e instanceof ttransport.InputBufferUnderrunError) { diff --git a/lib/nodejs/lib/thrift/multiplexed_processor.js b/lib/nodejs/lib/thrift/multiplexed_processor.js index cb885f47..351733e0 100644 --- a/lib/nodejs/lib/thrift/multiplexed_processor.js +++ b/lib/nodejs/lib/thrift/multiplexed_processor.js @@ -31,7 +31,7 @@ MultiplexedProcessor.prototype.process = function(inp, out) { var begin = inp.readMessageBegin(); if (begin.mtype != Thrift.MessageType.CALL || begin.mtype == Thrift.MessageType.ONEWAY) { - throw Thrift.TException("TMultiplexedProcessor: Unexpected message type"); + throw new Thrift.TException("TMultiplexedProcessor: Unexpected message type"); } var p = begin.fname.split(":"); @@ -39,18 +39,23 @@ MultiplexedProcessor.prototype.process = function(inp, out) { var fname = p[1]; if (!this.services.has(sname)) { - throw Thrift.TException("TMultiplexedProcessor: Unknown service: " + sname); + throw new Thrift.TException("TMultiplexedProcessor: Unknown service: " + sname); } - inp.readMessageBegin = function() { - + //construct a proxy object which stubs the readMessageBegin + //for the service + var inpProxy = {}; + for (var attr in inp) { + inpProxy[attr] = inp[attr]; + } + inpProxy.readMessageBegin = function() { return { fname: fname, mtype: begin.mtype, rseqid: begin.rseqid }; - } + }; - this.services.get(sname).process(inp, out); + this.services.get(sname).process(inpProxy, out); }; diff --git a/lib/nodejs/lib/thrift/protocol.js b/lib/nodejs/lib/thrift/protocol.js index f3cd9389..5e26ff50 100644 --- a/lib/nodejs/lib/thrift/protocol.js +++ b/lib/nodejs/lib/thrift/protocol.js @@ -23,6 +23,8 @@ var util = require('util'), var binary = require('./binary'), Int64 = require('node-int64'); +var InputBufferUnderrunError = require('./transport').InputBufferUnderrunError; + var UNKNOWN = 0, INVALID_DATA = 1, NEGATIVE_SIZE = 2, @@ -175,14 +177,14 @@ TBinaryProtocol.prototype.readMessageBegin = function() { var version = sz & VERSION_MASK; if (version != VERSION_1) { console.log("BAD: " + version); - throw TProtocolException(BAD_VERSION, "Bad version in readMessageBegin: " + sz); + throw new TProtocolException(BAD_VERSION, "Bad version in readMessageBegin: " + sz); } type = sz & TYPE_MASK; name = this.readString(); seqid = this.readI32(); } else { if (this.strictRead) { - throw TProtocolException(BAD_VERSION, "No protocol version header"); + throw new TProtocolException(BAD_VERSION, "No protocol version header"); } name = this.trans.read(sz); type = this.readByte(); @@ -344,7 +346,7 @@ TBinaryProtocol.prototype.skip = function(type) { this.readListEnd(); break; default: - throw Error("Invalid type: " + type); + throw new Error("Invalid type: " + type); } } @@ -438,8 +440,13 @@ TJSONProtocol.prototype.writeFieldEnd = function() { var value = this.tstack.pop(); var fieldInfo = this.tstack.pop(); - this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + - fieldInfo.fieldType + ':' + value + '}'; + if (':' + value === ":[object Object]") { + this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + + fieldInfo.fieldType + ':' + JSON.stringify(value) + '}'; + } else { + this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = '{' + + fieldInfo.fieldType + ':' + value + '}'; + } this.tpos.pop(); } @@ -550,37 +557,37 @@ TJSONProtocol.prototype.writeString = function(str) { if (str === null) { this.tstack.push(null); } else { - // concat may be slower than building a byte buffer - var escapedString = ''; - for (var i = 0; i < str.length; i++) { - var ch = str.charAt(i); // a single double quote: " - if (ch === '\\\\"') { - escapedString += '\\\\\\\\\\\\"'; // write out as: \\\\" - } else if (ch === '\\\\\\\\') { // a single backslash: \\\\ - escapedString += '\\\\\\\\\\\\\\\\'; // write out as: \\\\\\\\ - /* Currently escaped forward slashes break TJSONProtocol. - * As it stands, we can simply pass forward slashes into - * our strings across the wire without being escaped. - * I think this is the protocol's bug, not thrift.js - * } else if(ch === '/') { // a single forward slash: / - * escapedString += '\\\\\\\\/'; // write out as \\\\/ - * } - */ - } else if (ch === '\\\\b') { // a single backspace: invisible - escapedString += '\\\\\\\\b'; // write out as: \\\\b" - } else if (ch === '\\\\f') { // a single formfeed: invisible - escapedString += '\\\\\\\\f'; // write out as: \\\\f" - } else if (ch === '\\\\n') { // a single newline: invisible - escapedString += '\\\\\\\\n'; // write out as: \\\\n" - } else if (ch === '\\\\r') { // a single return: invisible - escapedString += '\\\\\\\\r'; // write out as: \\\\r" - } else if (ch === '\\\\t') { // a single tab: invisible - escapedString += '\\\\\\\\t'; // write out as: \\\\t" - } else { - escapedString += ch; // Else it need not be escaped + // concat may be slower than building a byte buffer + var escapedString = ''; + for (var i = 0; i < str.length; i++) { + var ch = str.charAt(i); // a single double quote: " + if (ch === '\"') { + escapedString += '\\\"'; // write out as: \" + } else if (ch === '\\') { // a single backslash: \ + escapedString += '\\\\'; // write out as: \\ + /* Currently escaped forward slashes break TJSONProtocol. + * As it stands, we can simply pass forward slashes into + * our strings across the wire without being escaped. + * I think this is the protocol's bug, not thrift.js + * } else if(ch === '/') { // a single forward slash: / + * escapedString += '\\/'; // write out as \/ + * } + */ + } else if (ch === '\b') { // a single backspace: invisible + escapedString += '\\b'; // write out as: \b" + } else if (ch === '\f') { // a single formfeed: invisible + escapedString += '\\f'; // write out as: \f" + } else if (ch === '\n') { // a single newline: invisible + escapedString += '\\n'; // write out as: \n" + } else if (ch === '\r') { // a single return: invisible + escapedString += '\\r'; // write out as: \r" + } else if (ch === '\t') { // a single tab: invisible + escapedString += '\\t'; // write out as: \t" + } else { + escapedString += ch; // Else it need not be escaped + } } - } - this.tstack.push('"' + escapedString + '"'); + this.tstack.push('"' + escapedString + '"'); } } @@ -592,23 +599,68 @@ TJSONProtocol.prototype.readMessageBegin = function() { this.rstack = []; this.rpos = []; - this.robj = JSON.parse(this.trans.readAll()); + //Borrow the inbound transport buffer and ensure data is present/consistent + var transBuf = this.trans.borrow(); + if (transBuf.readIndex >= transBuf.writeIndex) { + throw new InputBufferUnderrunError(); + } + var cursor = transBuf.readIndex; - var r = {}; - var version = this.robj.shift(); + if (transBuf.buf[cursor] !== 0x5B) { //[ + throw new Error("Malformed JSON input, no opening bracket"); + } + + //Parse a single message (there may be several in the buffer) + // TODO: Handle characters using multiple code units + cursor++; + var openBracketCount = 1; + var inString = false; + for (; cursor < transBuf.writeIndex; cursor++) { + var chr = transBuf.buf[cursor]; + //we use hexa charcode here because data[i] returns an int and not a char + if (inString) { + if (chr === 0x22) { //" + inString = false; + } else if (chr === 0x5C) { //\ + //escaped character, skip + cursor += 1; + } + } else { + if (chr === 0x5B) { //[ + openBracketCount += 1; + } else if (chr === 0x5D) { //] + openBracketCount -= 1; + if (openBracketCount === 0) { + //end of json message detected + break; + } + } else if (chr === 0x22) { //" + inString = true; + } + } + } + if (openBracketCount !== 0) { + throw new Error("Malformed JSON input, mismatched backets"); + } + + //Reconstitute the JSON object and conume the necessary bytes + this.robj = JSON.parse(transBuf.buf.slice(transBuf.readIndex, cursor+1)); + this.trans.consume(cursor + 1 - transBuf.readIndex); + + //Verify the protocol version + var version = this.robj.shift(); if (version != TJSONProtocol.Version) { throw 'Wrong thrift protocol version: ' + version; } + //Objectify the thrift message {name/type/sequence-number} for return + // and then save the JSON object in rstack + var r = {}; r.fname = this.robj.shift(); r.mtype = this.robj.shift(); r.rseqid = this.robj.shift(); - - - //get to the main obj this.rstack.push(this.robj.shift()); - return r; } @@ -628,9 +680,7 @@ TJSONProtocol.prototype.readStructBegin = function() { } TJSONProtocol.prototype.readStructEnd = function() { - if (this.rstack[this.rstack.length - 2] instanceof Array) { - this.rstack.pop(); - } + this.rstack.pop(); } TJSONProtocol.prototype.readFieldBegin = function() { diff --git a/lib/nodejs/lib/thrift/server.js b/lib/nodejs/lib/thrift/server.js index fee07d49..24ec9804 100644 --- a/lib/nodejs/lib/thrift/server.js +++ b/lib/nodejs/lib/thrift/server.js @@ -18,6 +18,9 @@ */ var net = require('net'); var http = require('http'); +var url = require("url"); +var path = require("path"); +var fs = require("fs"); var ttransport = require('./transport'), TBinaryProtocol = require('./protocol').TBinaryProtocol; @@ -42,14 +45,31 @@ exports.createMultiplexServer = function(processor, options) { })); try { - processor.process(input, output); - transportWithData.commitPosition(); + do { + processStatus = processor.process(input, output); + transportWithData.commitPosition(); + } while (true); } catch (err) { if (err instanceof ttransport.InputBufferUnderrunError) { + //The last data in the buffer was not a complete message, wait for the rest + transportWithData.rollbackPosition(); + } + else if (err.message === "Invalid type: undefined") { + //No more data in the buffer + //This trap is a bit hackish + //The next step to improve the node behavior here is to have + // the compiler generated process method throw a more explicit + // error when the network buffer is empty (regardles of the + // protocol/transport stack in use) and replace this heuristic. + // Also transports should probably not force upper layers to + // manage their buffer positions (i.e. rollbackPosition() and + // commitPosition() should be eliminated in lieu of a transport + // encapsulated buffer management strategy.) transportWithData.rollbackPosition(); } else { + //Unexpected error self.emit('error', err); stream.end(); } diff --git a/lib/nodejs/lib/thrift/static_server.js b/lib/nodejs/lib/thrift/static_server.js index a1d2eaa6..b61bd303 100644 --- a/lib/nodejs/lib/thrift/static_server.js +++ b/lib/nodejs/lib/thrift/static_server.js @@ -52,6 +52,11 @@ var TBinaryProtocol = require('./protocol').TBinaryProtocol; exports.createStaticHttpThriftServer = function(options) { //Set the static dir to serve files from var baseDir = typeof options.staticFilePath != "string" ? process.cwd() : options.staticFilePath; + var contentTypesByExtension = { + '.html': "text/html", + '.css': "text/css", + '.js': "text/javascript" + }; //Setup all of the services var services = options.services; @@ -113,8 +118,8 @@ exports.createStaticHttpThriftServer = function(options) { //Locate the file requested var uri = url.parse(request.url).pathname; var filename = path.join(baseDir, uri); - path.exists(filename, function(exists) { - if (!exists) { + fs.exists(filename, function(exists) { + if(!exists) { response.writeHead(404); response.end(); return; @@ -130,8 +135,12 @@ exports.createStaticHttpThriftServer = function(options) { response.end(err + "\n"); return; } - - response.writeHead(200); + var headers = {}; + var contentType = contentTypesByExtension[path.extname(filename)]; + if (contentType) { + headers["Content-Type"] = contentType; + } + response.writeHead(200, headers); response.write(file, "binary"); response.end(); }); diff --git a/lib/nodejs/lib/thrift/transport.js b/lib/nodejs/lib/thrift/transport.js index db3cd874..3adeaf89 100644 --- a/lib/nodejs/lib/thrift/transport.js +++ b/lib/nodejs/lib/thrift/transport.js @@ -19,9 +19,12 @@ var emptyBuf = new Buffer(0); var binary = require('./binary'); +var util = require("util"); -var InputBufferUnderrunError = exports.InputBufferUnderrunError = function() { +var InputBufferUnderrunError = exports.InputBufferUnderrunError = function(message) { + Error.call(this, message); }; +util.inherits(InputBufferUnderrunError, Error); var TFramedTransport = exports.TFramedTransport = function(buffer, callback) { this.inBuf = buffer || emptyBuf; @@ -42,7 +45,6 @@ TFramedTransport.receiver = function(callback) { var dat = new Buffer(data.length + residual.length); residual.copy(dat, 0, 0); data.copy(dat, residual.length, 0); - data = dat; residual = null; } @@ -53,7 +55,7 @@ TFramedTransport.receiver = function(callback) { if (data.length < 4) { console.log("Expecting > 4 bytes, found only " + data.length); residual = data; - break; + throw new InputBufferUnderrunError(); //throw Error("Expecting > 4 bytes, found only " + data.length); } frameLeft = binary.readI32(data, 0); @@ -65,7 +67,7 @@ TFramedTransport.receiver = function(callback) { if (data.length >= frameLeft) { data.copy(frame, framePos, 0, frameLeft); data = data.slice(frameLeft, data.length); - + frameLeft = 0; callback(new TFramedTransport(frame)); } else if (data.length) { @@ -73,6 +75,7 @@ TFramedTransport.receiver = function(callback) { frameLeft -= data.length; framePos += data.length; data = data.slice(data.length, data.length); + throw new InputBufferUnderrunError(); } } }; @@ -127,8 +130,12 @@ TFramedTransport.prototype = { return str; }, - readAll: function() { - return this.inBuf; + borrow: function() { + return { buf: this.inBuf, readIndex: this.readPos, writeIndex: this.inBuf.length }; + }, + + consume: function(bytesConsumed) { + this.readPos += bytesConsumed; }, write: function(buf, encoding) { @@ -189,14 +196,15 @@ TBufferedTransport.receiver = function(callback) { TBufferedTransport.prototype = { commitPosition: function(){ - var unreadedSize = this.writeCursor - this.readCursor; - var bufSize = (unreadedSize * 2 > this.defaultReadBufferSize) ? unreadedSize * 2 : this.defaultReadBufferSize; + var unreadSize = this.writeCursor - this.readCursor; + var bufSize = (unreadSize * 2 > this.defaultReadBufferSize) ? + unreadSize * 2 : this.defaultReadBufferSize; var buf = new Buffer(bufSize); - if (unreadedSize > 0) { + if (unreadSize > 0) { this.inBuf.copy(buf, 0, this.readCursor, this.writeCursor); } this.readCursor = 0; - this.writeCursor = unreadedSize; + this.writeCursor = unreadSize; this.inBuf = buf; }, rollbackPosition: function(){ @@ -255,33 +263,21 @@ TBufferedTransport.prototype = { return str; }, + borrow: function() { + var obj = {buf: this.inBuf, readIndex: this.readCursor, writeIndex: this.writeCursor}; + return obj; + }, - readAll: function() { - if (this.readCursor >= this.writeCursor) { - throw new InputBufferUnderrunError(); - } - var buf = new Buffer(this.writeCursor - this.readCursor); - this.inBuf.copy(buf, 0, this.readCursor, this.writeCursor); - this.readCursor = this.writeCursor; - return buf; + consume: function(bytesConsumed) { + this.readCursor += bytesConsumed; }, - write: function(buf, encoding) { + write: function(buf) { if (typeof(buf) === "string") { - // Defaulting to ascii encoding here since that's more like the original - // code, but I feel like 'utf8' would be a better choice. - buf = new Buffer(buf, encoding || 'ascii'); - } - if (this.outCount + buf.length > this.writeBufferSize) { - this.flush(); + buf = new Buffer(buf, 'utf8'); } - this.outBuffers.push(buf); this.outCount += buf.length; - - if (this.outCount >= this.writeBufferSize) { - this.flush(); - } }, flush: function() { diff --git a/test/nodejs/client.js b/test/nodejs/client.js index d96400ef..d70ec0ce 100644 --- a/test/nodejs/client.js +++ b/test/nodejs/client.js @@ -16,246 +16,29 @@ * specific language governing permissions and limitations * under the License. */ -var thrift = require('thrift'); -var ttransport = require('transport'); -var assert = require('assert'); -var ThriftTest = require('./gen-nodejs/ThriftTest'), - ttypes = require('./gen-nodejs/ThriftTest_types'); +//Client test for the following I/O stack: +// TBinaryProtocol +// TFramedTransport +// TSocket + +var assert = require('assert'); +var thrift = require('thrift'); +var TFramedTransport = require('thrift/transport').TFramedTransport; +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var ThriftTestDriver = require('./thrift_test_driver').ThriftTestDriver; -var connection = thrift.createConnection('localhost', 9090, { 'transport': ttransport.TFramedTransport }), -//var connection = thrift.createConnection('localhost', 9090), - client = thrift.createClient(ThriftTest, connection); +var connection = thrift.createConnection('localhost', 9090, { transport: TFramedTransport} ); +var client = thrift.createClient(ThriftTest, connection); connection.on('error', function(err) { assert(false, err); }); - // deepEqual doesn't work with fields using node-int64 -function checkRecursively(map1, map2) { - if (typeof map1 !== 'function' && typeof map2 !== 'function') { - if (!map1 || typeof map1 !== 'object') { - assert.equal(map1, map2); - } else { - for (var key in map1) { - checkRecursively(map1[key], map2[key]); - } - } - } -} - - -client.testVoid(function(err, response) { - assert( ! err); - assert.equal(undefined, response); //void -}); - - -client.testString("Test", function(err, response) { - assert( ! err); - assert.equal("Test", response); -}); - -client.testString("", function(err, response) { - assert( ! err); - assert.equal("", response); -}); - -// all Languages in UTF-8 -var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; -client.testString(stringTest, function(err, response) { - assert( ! err); - assert.equal(stringTest, response); -}); - -var specialCharacters = 'quote: \" backslash:' + - ' forwardslash-escaped: \/ ' + - ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + - ' now-all-of-them-together: "\\\/\b\n\r\t' + - ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; -client.testString(specialCharacters, function(err, response) { - assert( ! err); - assert.equal(specialCharacters, response); -}); - - -client.testByte(1, function(err, response) { - assert( ! err); - assert.equal(1, response); -}); -client.testByte(0, function(err, response) { - assert( ! err); - assert.equal(0, response); -}); -client.testByte(-1, function(err, response) { - assert( ! err); - assert.equal(-1, response); -}); -client.testByte(-127, function(err, response) { - assert( ! err); - assert.equal(-127, response); -}); - -client.testI32(-1, function(err, response) { - assert( ! err); - assert.equal(-1, response); -}); - -client.testI64(5, function(err, response) { - assert( ! err); - assert.equal(5, response); -}); -client.testI64(-5, function(err, response) { - assert( ! err); - assert.equal(-5, response); -}); -client.testI64(-34359738368, function(err, response) { - assert( ! err); - assert.equal(-34359738368, response); -}); - -client.testDouble(-5.2098523, function(err, response) { - assert( ! err); - assert.equal(-5.2098523, response); -}); -client.testDouble(7.012052175215044, function(err, response) { - assert( ! err); - assert.equal(7.012052175215044, response); -}); - - -var out = new ttypes.Xtruct({ - string_thing: 'Zero', - byte_thing: 1, - i32_thing: -3, - i64_thing: 1000000 -}); -client.testStruct(out, function(err, response) { - assert( ! err); - checkRecursively(out, response); -}); - - -var out2 = new ttypes.Xtruct2(); -out2.byte_thing = 1; -out2.struct_thing = out; -out2.i32_thing = 5; -client.testNest(out2, function(err, response) { - assert( ! err); - checkRecursively(out2, response); -}); - - -var mapout = {}; -for (var i = 0; i < 5; ++i) { - mapout[i] = i-10; -} -client.testMap(mapout, function(err, response) { - assert( ! err); - assert.deepEqual(mapout, response); -}); - - -var mapTestInput = { - "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key", - "longValue":stringTest, stringTest:"long key" -}; -client.testStringMap(mapTestInput, function(err, response) { - assert( ! err); - assert.deepEqual(mapTestInput, response); -}); - - -var setTestInput = [1,2,3]; -client.testSet(setTestInput, function(err, response) { - assert( ! err); - assert.deepEqual(setTestInput, response); -}); -client.testList(setTestInput, function(err, response) { - assert( ! err); - assert.deepEqual(setTestInput, response); -}); - -client.testEnum(ttypes.Numberz.ONE, function(err, response) { - assert( ! err); - assert.equal(ttypes.Numberz.ONE, response); -}); - -client.testTypedef(69, function(err, response) { - assert( ! err); - assert.equal(69, response); -}); - - -var mapMapTest = { - "4": {"1":1, "2":2, "3":3, "4":4}, - "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1} -}; -client.testMapMap(mapMapTest, function(err, response) { - assert( ! err); - assert.deepEqual(mapMapTest, response); -}); - -var crazy = new ttypes.Insanity({ - "userMap":{ "5":5, "8":8 }, - "xtructs":[new ttypes.Xtruct({ - "string_thing":"Goodbye4", - "byte_thing":4, - "i32_thing":4, - "i64_thing":4 - }), new ttypes.Xtruct({ - "string_thing":"Hello2", - "byte_thing":2, - "i32_thing":2, - "i64_thing":2 - })] -}); -var insanity = { - "1":{ "2": crazy, "3": crazy }, - "2":{ "6":{ "userMap":null, "xtructs":null } } -}; -client.testInsanity(crazy, function(err, response) { - assert( ! err); - checkRecursively(insanity, response); -}); - - -client.testException('TException', function(err, response) { - //assert(err); //BUG? - assert( ! response); -}); -client.testException('Xception', function(err, response) { - assert( ! response); - assert.equal(err.errorCode, 1001); - assert.equal('Xception', err.message); -}); -client.testException('no Exception', function(err, response) { - assert( ! err); - assert.equal(undefined, response); //void -}); - - -client.testOneway(1, function(err, response) { - assert(false); //should not answer -}); - -/** - * redo a simple test after the oneway to make sure we aren't "off by one" -- - * if the server treated oneway void like normal void, this next test will - * fail since it will get the void confirmation rather than the correct - * result. In this circumstance, the client will throw the exception: - * - * TApplicationException: Wrong method namea - */ -client.testI32(-1, function(err, response) { - assert( ! err); - assert.equal(-1, response); -}); - -setTimeout(function() { - console.log("Server successfully tested!"); +ThriftTestDriver(client, function (status) { + console.log(status); connection.end(); -}, 1500); +}); // to make it also run on expresso exports.expressoTest = function() {}; diff --git a/test/nodejs/client_bin.js b/test/nodejs/client_bin.js new file mode 100644 index 00000000..d077202c --- /dev/null +++ b/test/nodejs/client_bin.js @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Node client test for the following I/O stack: +// TJSONProtocol +// TBufferedTransport +// TSocket + +var assert = require('assert'); +var thrift = require('thrift'); +var TBufferedTransport = require('thrift/transport').TBufferedTransport; +var TBinaryProtocol = require('thrift/protocol').TBinaryProtocol; +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var ThriftTestDriver = require('./thrift_test_driver').ThriftTestDriver; + +var connection = thrift.createConnection('localhost', 9090, + { protocol: TBinaryProtocol, transport: TBufferedTransport} ); +var client = thrift.createClient(ThriftTest, connection); + +connection.on('error', function(err) { + assert(false, err); +}); + +ThriftTestDriver(client, function (status) { + console.log(status); + connection.end(); +}); + +// to make it also run on expresso +exports.expressoTest = function() {}; + diff --git a/test/nodejs/client_json.js b/test/nodejs/client_json.js new file mode 100644 index 00000000..de0190fc --- /dev/null +++ b/test/nodejs/client_json.js @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Node client test for the following I/O stack: +// TJSONProtocol +// TBufferedTransport +// TSocket + +var assert = require('assert'); +var thrift = require('thrift'); +var TBufferedTransport = require('thrift/transport').TBufferedTransport; +var TJSONProtocol = require('thrift/protocol').TJSONProtocol; +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var ThriftTestDriver = require('./thrift_test_driver').ThriftTestDriver; + +var connection = thrift.createConnection('localhost', 9090, + { protocol: TJSONProtocol, transport: TBufferedTransport} ); +var client = thrift.createClient(ThriftTest, connection); + +connection.on('error', function(err) { + assert(false, err); +}); + +ThriftTestDriver(client, function (status) { + console.log(status); + connection.end(); +}); + +// to make it also run on expresso +exports.expressoTest = function() {}; + diff --git a/test/nodejs/client_json_frame.js b/test/nodejs/client_json_frame.js new file mode 100644 index 00000000..f23ddd49 --- /dev/null +++ b/test/nodejs/client_json_frame.js @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Node client test for the following I/O stack: +// TJSONProtocol +// TBufferedTransport +// TSocket + +var assert = require('assert'); +var thrift = require('thrift'); +var TFramedTransport = require('thrift/transport').TFramedTransport; +var TJSONProtocol = require('thrift/protocol').TJSONProtocol; +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var ThriftTestDriver = require('./thrift_test_driver').ThriftTestDriver; + +var connection = thrift.createConnection('localhost', 9090, + { protocol: TJSONProtocol, transport: TFramedTransport} ); +var client = thrift.createClient(ThriftTest, connection); + +connection.on('error', function(err) { + assert(false, err); +}); + +ThriftTestDriver(client, function (status) { + console.log(status); + connection.end(); +}); + +// to make it also run on expresso +exports.expressoTest = function() {}; + diff --git a/test/nodejs/server.js b/test/nodejs/server.js index 28eeeaea..78a21c63 100644 --- a/test/nodejs/server.js +++ b/test/nodejs/server.js @@ -16,207 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -var thrift = require('thrift'); -var Thrift = thrift.Thrift; -var ttransport = require('transport'); - -var ThriftTest = require('./gen-nodejs/ThriftTest'), - ttypes = require('./gen-nodejs/ThriftTest_types'); - - -var server = thrift.createServer(ThriftTest, { - testVoid: function(result) { - console.log('testVoid()'); - result(null); - }, - - testString: function(thing, result) { - console.log('testString(\'' + thing + '\')'); - result(null, thing); - }, - - testByte: function(thing, result) { - console.log('testByte(' + thing + ')'); - result(null, thing); - }, - - testI32: function(thing, result) { - console.log('testI32(' + thing + ')'); - result(null, thing); - }, - - testI64: function(thing, result) { - console.log('testI64(' + thing + ')'); - result(null, thing); - }, - - testDouble: function(thing, result) { - console.log('testDouble(' + thing + ')'); - result(null, thing); - }, - - testStruct: function(thing, result) { - console.log('testStruct('); - console.log(thing); - console.log(')'); - result(null, thing); - }, - - testNest: function(nest, result) { - console.log('testNest('); - console.log(nest); - console.log(')'); - result(null, nest); - }, - - testMap: function(thing, result) { - console.log('testMap('); - console.log(thing); - console.log(')'); - result(null, thing); - }, - - testStringMap: function(thing, result) { - console.log('testStringMap('); - console.log(thing); - console.log(')'); - result(null, thing); - }, - - testSet: function(thing, result) { - console.log('testSet('); - console.log(thing); - console.log(')'); - result(null, thing); - }, - - testList: function(thing, result) { - console.log('testList('); - console.log(thing); - console.log(')'); - result(null, thing); - }, - - testEnum: function(thing, result) { - console.log('testEnum(' + thing + ')'); - result(null, thing); - }, - - testTypedef: function(thing, result) { - console.log('testTypedef(' + thing + ')'); - result(null, thing); - }, - testMapMap: function(hello, result) { - console.log('testMapMap(' + hello + ')'); +//Server test for the following I/O stack: +// TBinaryProtocol +// TFramedTransport +// TSocket - var mapmap = []; - var pos = []; - var neg = []; - for (var i = 1; i < 5; i++) { - pos[i] = i; - neg[-i] = -i; - } - mapmap[4] = pos; - mapmap[-4] = neg; - - result(null, mapmap); - }, - - testInsanity: function(argument, result) { - console.log('testInsanity('); - console.log(argument); - console.log(')'); - - var hello = new ttypes.Xtruct(); - hello.string_thing = 'Hello2'; - hello.byte_thing = 2; - hello.i32_thing = 2; - hello.i64_thing = 2; - - var goodbye = new ttypes.Xtruct(); - goodbye.string_thing = 'Goodbye4'; - goodbye.byte_thing = 4; - goodbye.i32_thing = 4; - goodbye.i64_thing = 4; - - var crazy = new ttypes.Insanity(); - crazy.userMap = []; - crazy.userMap[ttypes.Numberz.EIGHT] = 8; - crazy.userMap[ttypes.Numberz.FIVE] = 5; - crazy.xtructs = [goodbye, hello]; - - var first_map = []; - var second_map = []; - - first_map[ttypes.Numberz.TWO] = crazy; - first_map[ttypes.Numberz.THREE] = crazy; - - var looney = new ttypes.Insanity(); - second_map[ttypes.Numberz.SIX] = looney; - - var insane = []; - insane[1] = first_map; - insane[2] = second_map; - - console.log('insane result:'); - console.log(insane); - result(null, insane); - }, - - testMulti: function(arg0, arg1, arg2, arg3, arg4, arg5, result) { - console.log('testMulti()'); - - var hello = new ttypes.Xtruct();; - hello.string_thing = 'Hello2'; - hello.byte_thing = arg0; - hello.i32_thing = arg1; - hello.i64_thing = arg2; - result(null, hello); - }, - - testException: function(arg, result) { - console.log('testException('+arg+')'); - if (arg === 'Xception') { - var x = new ttypes.Xception(); - x.errorCode = 1001; - x.message = arg; - result(x); - } else if (arg === 'TException') { - result(new Thrift.TException(arg)); - } else { - result(null); - } - }, - - testMultiException: function(arg0, arg1, result) { - console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); - if (arg0 === ('Xception')) { - var x = new ttypes.Xception(); - x.errorCode = 1001; - x.message = 'This is an Xception'; - result(x); - } else if (arg0 === ('Xception2')) { - var x = new ttypes.Xception2(); - x.errorCode = 2002; - x.struct_thing = new ttypes.Xtruct(); - x.struct_thing.string_thing = 'This is an Xception2'; - result(x); - } - - var res = new ttypes.Xtruct(); - res.string_thing = arg1; - result(null, res); - }, +var thrift = require('thrift'); +var TFramedTransport = require('thrift/transport').TFramedTransport; +var ThriftTest = require('./gen-nodejs/ThriftTest'); +var ThriftTestHandler = require('./test_handler').ThriftTestHandler; - testOneway: function(sleepFor, result) { - console.log('testOneway(' + sleepFor + ') => sleeping...'); - setTimeout(function(){ - console.log('Done sleeping for testOneway!'); - }, sleepFor*1000); //seconds - } -}, { //server options - 'transport': ttransport.TFramedTransport -}); +thrift.createServer(ThriftTest, + ThriftTestHandler, + {'transport': TFramedTransport}).listen(9090); -server.listen(9090); diff --git a/test/nodejs/server_bin.js b/test/nodejs/server_bin.js new file mode 100644 index 00000000..ba844490 --- /dev/null +++ b/test/nodejs/server_bin.js @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Node server test for the following I/O stack: +// TJSONProtocol +// TBufferedTransport +// TSocket + +var thrift = require('thrift'); +var TBufferedTransport = require('thrift/transport').TBufferedTransport; +var TBinaryProtocol = require('thrift/protocol').TBinaryProtocol; +var ThriftTestSvc = require('./gen-nodejs/ThriftTest'); +var ThriftTestHandler = require('./test_handler').ThriftTestHandler; + +var ThriftTestSvcOpt = { + transport: TBufferedTransport, + protocol: TBinaryProtocol +}; + +thrift.createServer(ThriftTestSvc, + ThriftTestHandler, + ThriftTestSvcOpt).listen(9090); diff --git a/test/nodejs/server_http.js b/test/nodejs/server_http.js new file mode 100644 index 00000000..43669437 --- /dev/null +++ b/test/nodejs/server_http.js @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//This HTTP server is designed to server the test.html browser +// based JavaScript test page (which must be in the current directory). +// This server also supplies the Thrift based test service, which depends +// on the standard ThriftTest.thrift IDL service (which must be compiled +// for Node and browser based JavaScript in ./gen-nodejs and ./gen-js +// respectively). The current directory must also include the browser +// support libraries for test.html (jquery.js, qunit.js and qunit.css +// in ./build/js/lib). + +var thrift = require('thrift'); +var TBufferedTransport = require('thrift/transport').TBufferedTransport; +var TJSONProtocol = require('thrift/protocol').TJSONProtocol; +var ThriftTestSvc = require('./gen-nodejs/ThriftTest.js'); +var ThriftTestHandler = require('./test_handler').ThriftTestHandler; + +var ThriftTestSvcOpt = { + transport: TBufferedTransport, + protocol: TJSONProtocol, + cls: ThriftTestSvc, + handler: ThriftTestHandler +}; + +var StaticHttpThriftServerOptions = { + staticFilePath: ".", + services: { + "/service": ThriftTestSvcOpt + } +} + +var server = thrift.createStaticHttpThriftServer(StaticHttpThriftServerOptions); +var port = 8088; +server.listen(port); +console.log("Http/Thrift Server running on port: " + port); diff --git a/test/nodejs/server_json.js b/test/nodejs/server_json.js new file mode 100644 index 00000000..406c9820 --- /dev/null +++ b/test/nodejs/server_json.js @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Node server test for the following I/O stack: +// TJSONProtocol +// TBufferedTransport +// TSocket + +var thrift = require('thrift'); +var TBufferedTransport = require('thrift/transport').TBufferedTransport; +var TJSONProtocol = require('thrift/protocol').TJSONProtocol; +var ThriftTestSvc = require('./gen-nodejs/ThriftTest'); +var ThriftTestHandler = require('./test_handler').ThriftTestHandler; + +var ThriftTestSvcOpt = { + transport: TBufferedTransport, + protocol: TJSONProtocol +}; + +thrift.createServer(ThriftTestSvc, + ThriftTestHandler, + ThriftTestSvcOpt).listen(9090); diff --git a/test/nodejs/server_json_frame.js b/test/nodejs/server_json_frame.js new file mode 100644 index 00000000..828063ac --- /dev/null +++ b/test/nodejs/server_json_frame.js @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//Node server test for the following I/O stack: +// TJSONProtocol +// TBufferedTransport +// TSocket + +var thrift = require('thrift'); +var TFramedTransport = require('thrift/transport').TFramedTransport; +var TJSONProtocol = require('thrift/protocol').TJSONProtocol; +var ThriftTestSvc = require('./gen-nodejs/ThriftTest'); +var ThriftTestHandler = require('./test_handler').ThriftTestHandler; + +var ThriftTestSvcOpt = { + transport: TFramedTransport, + protocol: TJSONProtocol +}; + +thrift.createServer(ThriftTestSvc, + ThriftTestHandler, + ThriftTestSvcOpt).listen(9090); diff --git a/test/nodejs/test.html b/test/nodejs/test.html new file mode 100644 index 00000000..fe0e52b2 --- /dev/null +++ b/test/nodejs/test.html @@ -0,0 +1,51 @@ + + + + + + Thrift Javascript Bindings: Unit Test + + + + + + + + + + + + + + + + +

Thrift Javascript Bindings: Unit Test (ThriftTest.thrift)

+

+
+

+
+

+ Valid XHTML 1.0! +

+ + diff --git a/test/nodejs/test.js b/test/nodejs/test.js new file mode 100644 index 00000000..91ba4d10 --- /dev/null +++ b/test/nodejs/test.js @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /* jshint -W100 */ + +/* + * JavaScript test suite + */ + +var transport = new Thrift.Transport("/service"); +var protocol = new Thrift.Protocol(transport); +var client = new ThriftTest.ThriftTestClient(protocol); + +// all Languages in UTF-8 +var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; + +function checkRecursively(map1, map2) { + if (typeof map1 !== 'function' && typeof map2 !== 'function') { + if (!map1 || typeof map1 !== 'object') { + equal(map1, map2); + } else { + for (var key in map1) { + checkRecursively(map1[key], map2[key]); + } + } + } +} + +module("Base Types"); + + test("Void", function() { + equal(client.testVoid(), undefined); + }); + test("String", function() { + equal(client.testString(''), ''); + equal(client.testString(stringTest), stringTest); + + var specialCharacters = 'quote: \" backslash:' + + ' forwardslash-escaped: \/ ' + + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + + ' now-all-of-them-together: "\\\/\b\n\r\t' + + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><'; + equal(client.testString(specialCharacters),specialCharacters); + }); + test("Double", function() { + equal(client.testDouble(0), 0); + equal(client.testDouble(-1), -1); + equal(client.testDouble(3.14), 3.14); + equal(client.testDouble(Math.pow(2,60)), Math.pow(2,60)); + }); + test("Byte", function() { + equal(client.testByte(0), 0); + equal(client.testByte(0x01), 0x01); + }); + test("I32", function() { + equal(client.testI32(0), 0); + equal(client.testI32(Math.pow(2,30)), Math.pow(2,30)); + equal(client.testI32(-Math.pow(2,30)), -Math.pow(2,30)); + }); + test("I64", function() { + equal(client.testI64(0), 0); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + equal(client.testI64(Math.pow(2,52)), Math.pow(2,52)); + equal(client.testI64(-Math.pow(2,52)), -Math.pow(2,52)); + }); + + +module("Structured Types"); + + test("Struct", function() { + var structTestInput = new ThriftTest.Xtruct(); + structTestInput.string_thing = 'worked'; + structTestInput.byte_thing = 0x01; + structTestInput.i32_thing = Math.pow(2,30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + structTestInput.i64_thing = Math.pow(2,52); + + var structTestOutput = client.testStruct(structTestInput); + + equal(structTestOutput.string_thing, structTestInput.string_thing); + equal(structTestOutput.byte_thing, structTestInput.byte_thing); + equal(structTestOutput.i32_thing, structTestInput.i32_thing); + equal(structTestOutput.i64_thing, structTestInput.i64_thing); + + equal(JSON.stringify(structTestOutput), JSON.stringify(structTestInput)); + }); + + test("Nest", function() { + var xtrTestInput = new ThriftTest.Xtruct(); + xtrTestInput.string_thing = 'worked'; + xtrTestInput.byte_thing = 0x01; + xtrTestInput.i32_thing = Math.pow(2,30); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + xtrTestInput.i64_thing = Math.pow(2,52); + + var nestTestInput = new ThriftTest.Xtruct2(); + nestTestInput.byte_thing = 0x02; + nestTestInput.struct_thing = xtrTestInput; + nestTestInput.i32_thing = Math.pow(2,15); + + var nestTestOutput = client.testNest(nestTestInput); + + equal(nestTestOutput.byte_thing, nestTestInput.byte_thing); + equal(nestTestOutput.struct_thing.string_thing, nestTestInput.struct_thing.string_thing); + equal(nestTestOutput.struct_thing.byte_thing, nestTestInput.struct_thing.byte_thing); + equal(nestTestOutput.struct_thing.i32_thing, nestTestInput.struct_thing.i32_thing); + equal(nestTestOutput.struct_thing.i64_thing, nestTestInput.struct_thing.i64_thing); + equal(nestTestOutput.i32_thing, nestTestInput.i32_thing); + + equal(JSON.stringify(nestTestOutput), JSON.stringify(nestTestInput)); + }); + + test("Map", function() { + var mapTestInput = {7:77, 8:88, 9:99}; + + var mapTestOutput = client.testMap(mapTestInput); + + for (var key in mapTestOutput) { + equal(mapTestOutput[key], mapTestInput[key]); + } + }); + + test("StringMap", function() { + var mapTestInput = { + "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key", + "longValue":stringTest, stringTest:"long key" + }; + + var mapTestOutput = client.testStringMap(mapTestInput); + + for (var key in mapTestOutput) { + equal(mapTestOutput[key], mapTestInput[key]); + } + }); + + test("Set", function() { + var setTestInput = [1,2,3]; + ok(client.testSet(setTestInput), setTestInput); + }); + + test("List", function() { + var listTestInput = [1,2,3]; + ok(client.testList(listTestInput), listTestInput); + }); + + test("Enum", function() { + equal(client.testEnum(ThriftTest.Numberz.ONE), ThriftTest.Numberz.ONE); + }); + + test("TypeDef", function() { + equal(client.testTypedef(69), 69); + }); + + +module("deeper!"); + + test("MapMap", function() { + var mapMapTestExpectedResult = { + "4":{"1":1,"2":2,"3":3,"4":4}, + "-4":{"-4":-4, "-3":-3, "-2":-2, "-1":-1} + }; + + var mapMapTestOutput = client.testMapMap(1); + + + for (var key in mapMapTestOutput) { + for (var key2 in mapMapTestOutput[key]) { + equal(mapMapTestOutput[key][key2], mapMapTestExpectedResult[key][key2]); + } + } + + checkRecursively(mapMapTestOutput, mapMapTestExpectedResult); + }); + + +module("Exception"); + + test("Xception", function() { + expect(2); + try{ + client.testException("Xception"); + }catch(e){ + equal(e.errorCode, 1001); + equal(e.message, "Xception"); + } + }); + + test("no Exception", 0, function() { + try{ + client.testException("no Exception"); + }catch(e){ + ok(false); + } + }); + + test("TException", function() { + //ThriftTest does not list TException as a legal exception so it will + // generate an exception on the server that does not propagate back to + // the client. This test has been modified to equate to "no exception" + expect(1); + try{ + client.testException("TException"); + } catch(e) { + //ok(false); + } + ok(true); + }); + + +module("Insanity"); + + test("testInsanity", function() { + var insanity = { + "1":{ + "2":{ + "userMap":{ "5":5, "8":8 }, + "xtructs":[{ + "string_thing":"Goodbye4", + "byte_thing":4, + "i32_thing":4, + "i64_thing":4 + }, + { + "string_thing":"Hello2", + "byte_thing":2, + "i32_thing":2, + "i64_thing":2 + } + ] + }, + "3":{ + "userMap":{ "5":5, "8":8 }, + "xtructs":[{ + "string_thing":"Goodbye4", + "byte_thing":4, + "i32_thing":4, + "i64_thing":4 + }, + { + "string_thing":"Hello2", + "byte_thing":2, + "i32_thing":2, + "i64_thing":2 + } + ] + } + }, + "2":{ "6":{ "userMap":null, "xtructs":null } } + }; + var res = client.testInsanity(new ThriftTest.Insanity()); + ok(res, JSON.stringify(res)); + ok(insanity, JSON.stringify(insanity)); + + checkRecursively(res, insanity); + }); + + +////////////////////////////////// +//Run same tests asynchronously +jQuery.ajaxSetup({ timeout: 0 }); +$(document).ajaxError( function() { QUnit.start(); } ); + +module("Async Manual"); + + test("testI32", function() { + expect( 2 ); + QUnit.stop(); + + var transport = new Thrift.Transport(); + var protocol = new Thrift.Protocol(transport); + var client = new ThriftTest.ThriftTestClient(protocol); + + var jqxhr = jQuery.ajax({ + url: "/service", + data: client.send_testI32(Math.pow(-2,31)), + type: "POST", + cache: false, + dataType: "text", + success: function(res){ + transport.setRecvBuffer( res ); + equal(client.recv_testI32(), Math.pow(-2,31)); + }, + error: function() { ok(false); }, + complete: function() { + ok(true); + QUnit.start(); + } + }); + }); + + + test("testI64", function() { + expect( 2 ); + QUnit.stop(); + + var transport = new Thrift.Transport(); + var protocol = new Thrift.Protocol(transport); + var client = new ThriftTest.ThriftTestClient(protocol); + + jQuery.ajax({ + url: "/service", + //This is usually 2^61 but JS cannot represent anything over 2^52 accurately + data: client.send_testI64(Math.pow(-2,52)), + type: "POST", + cache: false, + dataType: "text", + success: function(res){ + transport.setRecvBuffer( res ); + //This is usually 2^61 but JS cannot represent anything over 2^52 accurately + equal(client.recv_testI64(), Math.pow(-2,52)); + }, + error: function() { ok(false); }, + complete: function() { + ok(true); + QUnit.start(); + } + }); + }); + + +module("Async"); + + test("Double", function() { + expect( 1 ); + + QUnit.stop(); + client.testDouble(3.14159265, function(result) { + equal(result, 3.14159265); + QUnit.start(); + }); + }); + + test("Byte", function() { + expect( 1 ); + + QUnit.stop(); + client.testByte(0x01, function(result) { + equal(result, 0x01); + QUnit.start(); + }); + }); + + test("I32", function() { + expect( 3 ); + + QUnit.stop(); + client.testI32(Math.pow(2,30), function(result) { + equal(result, Math.pow(2,30)); + QUnit.start(); + }); + + QUnit.stop(); + var jqxhr = client.testI32(Math.pow(-2,31), function(result) { + equal(result, Math.pow(-2,31)); + }); + + jqxhr.success(function(result) { + equal(result, Math.pow(-2,31)); + QUnit.start(); + }); + }); + + test("I64", function() { + expect( 4 ); + + QUnit.stop(); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + client.testI64(Math.pow(2,52), function(result) { + equal(result, Math.pow(2,52)); + QUnit.start(); + }); + + QUnit.stop(); + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + client.testI64(Math.pow(-2,52), function(result) { + equal(result, Math.pow(-2,52)); + }) + .error( function(xhr, status, e) { ok(false, e.message); } ) + .success(function(result) { + //This is usually 2^60 but JS cannot represent anything over 2^52 accurately + equal(result, Math.pow(-2,52)); + }) + .complete(function() { + ok(true); + QUnit.start(); + }); + }); + + test("Xception", function() { + expect( 2 ); + + QUnit.stop(); + + var dfd = client.testException("Xception", function(result) { + ok(false); + QUnit.start(); + }) + .error(function(xhr, status, e){ + equal(e.errorCode, 1001); + equal(e.message, "Xception"); + //QUnit.start(); + //Note start is not required here because: + //$(document).ajaxError( function() { QUnit.start(); } ); + }); + }); diff --git a/test/nodejs/test_handler.js b/test/nodejs/test_handler.js new file mode 100644 index 00000000..e697408a --- /dev/null +++ b/test/nodejs/test_handler.js @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +//This is the server side Node test handler for the standard +// Apache Thrift test service. + +var ttypes = require('./gen-nodejs/ThriftTest_types'); +var TException = require('thrift/thrift').TException; + +var ThriftTestHandler = exports.ThriftTestHandler = { + testVoid: function(result) { + console.log('testVoid()'); + result(null); + }, + testString: function(thing, result) { + console.log('testString(\'' + thing + '\')'); + result(null, thing); + }, + testByte: function(thing, result) { + console.log('testByte(' + thing + ')'); + result(null, thing); + }, + testI32: function(thing, result) { + console.log('testI32(' + thing + ')'); + result(null, thing); + }, + testI64: function(thing, result) { + console.log('testI64(' + thing + ')'); + result(null, thing); + }, + testDouble: function(thing, result) { + console.log('testDouble(' + thing + ')'); + result(null, thing); + }, + testStruct: function(thing, result) { + console.log('testStruct('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testNest: function(nest, result) { + console.log('testNest('); + console.log(nest); + console.log(')'); + result(null, nest); + }, + testMap: function(thing, result) { + console.log('testMap('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testStringMap: function(thing, result) { + console.log('testStringMap('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testSet: function(thing, result) { + console.log('testSet('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testList: function(thing, result) { + console.log('testList('); + console.log(thing); + console.log(')'); + result(null, thing); + }, + testEnum: function(thing, result) { + console.log('testEnum(' + thing + ')'); + result(null, thing); + }, + testTypedef: function(thing, result) { + console.log('testTypedef(' + thing + ')'); + result(null, thing); + }, + testMapMap: function(hello, result) { + console.log('testMapMap(' + hello + ')'); + + var mapmap = []; + var pos = []; + var neg = []; + for (var i = 1; i < 5; i++) { + pos[i] = i; + neg[-i] = -i; + } + mapmap[4] = pos; + mapmap[-4] = neg; + + result(null, mapmap); + }, + testInsanity: function(argument, result) { + console.log('testInsanity('); + console.log(argument); + console.log(')'); + + var hello = new ttypes.Xtruct(); + hello.string_thing = 'Hello2'; + hello.byte_thing = 2; + hello.i32_thing = 2; + hello.i64_thing = 2; + + var goodbye = new ttypes.Xtruct(); + goodbye.string_thing = 'Goodbye4'; + goodbye.byte_thing = 4; + goodbye.i32_thing = 4; + goodbye.i64_thing = 4; + + var crazy = new ttypes.Insanity(); + crazy.userMap = []; + crazy.userMap[ttypes.Numberz.EIGHT] = 8; + crazy.userMap[ttypes.Numberz.FIVE] = 5; + crazy.xtructs = [goodbye, hello]; + + var first_map = []; + var second_map = []; + + first_map[ttypes.Numberz.TWO] = crazy; + first_map[ttypes.Numberz.THREE] = crazy; + + var looney = new ttypes.Insanity(); + second_map[ttypes.Numberz.SIX] = looney; + + var insane = []; + insane[1] = first_map; + insane[2] = second_map; + + console.log('insane result:'); + console.log(insane); + result(null, insane); + }, + testMulti: function(arg0, arg1, arg2, arg3, arg4, arg5, result) { + console.log('testMulti()'); + + var hello = new ttypes.Xtruct();; + hello.string_thing = 'Hello2'; + hello.byte_thing = arg0; + hello.i32_thing = arg1; + hello.i64_thing = arg2; + result(null, hello); + }, + testException: function(arg, result) { + console.log('testException('+arg+')'); + if (arg === 'Xception') { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = arg; + result(x); + } else if (arg === 'TException') { + result(new TException(arg)); + } else { + result(null); + } + }, + testMultiException: function(arg0, arg1, result) { + console.log('testMultiException(' + arg0 + ', ' + arg1 + ')'); + if (arg0 === ('Xception')) { + var x = new ttypes.Xception(); + x.errorCode = 1001; + x.message = 'This is an Xception'; + result(x); + } else if (arg0 === ('Xception2')) { + var x = new ttypes.Xception2(); + x.errorCode = 2002; + x.struct_thing = new ttypes.Xtruct(); + x.struct_thing.string_thing = 'This is an Xception2'; + result(x); + } + + var res = new ttypes.Xtruct(); + res.string_thing = arg1; + result(null, res); + }, + testOneway: function(sleepFor, result) { + console.log('testOneway(' + sleepFor + ') => JavaScript (like Rust) never sleeps!'); + } +} //ThriftTestSvcHandler diff --git a/test/nodejs/thrift_test_driver.js b/test/nodejs/thrift_test_driver.js new file mode 100644 index 00000000..451573db --- /dev/null +++ b/test/nodejs/thrift_test_driver.js @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * 'License'); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + // This is the Node test driver for the standard Apache Thrift + // test service. The driver invokes every function defined in the + // Thrift Test service with a representative range of parameters. + // + // The ThriftTestDriver function requires a client object + // connected to a server hosting the Thrift Test service and + // supports an optional callback function which is called with + // a status message when the test is complete. + +var assert = require('assert'); +var ttypes = require('./gen-nodejs/ThriftTest_types'); + +var ThriftTestDriver = exports.ThriftTestDriver = function(client, callback) { + + // deepEqual doesn't work with fields using node-int64 + function checkRecursively(map1, map2) { + if (typeof map1 !== 'function' && typeof map2 !== 'function') { + if (!map1 || typeof map1 !== 'object') { + assert.equal(map1, map2); + } else { + for (var key in map1) { + checkRecursively(map1[key], map2[key]); + } + } + } + } + + client.testVoid(function(err, response) { + assert( ! err); + assert.equal(undefined, response); //void + }); + + client.testString("Test", function(err, response) { + assert( ! err); + assert.equal("Test", response); + }); + + client.testString("", function(err, response) { + assert( ! err); + assert.equal("", response); + }); + + //all Languages in UTF-8 + var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語"; + client.testString(stringTest, function(err, response) { + assert( ! err); + assert.equal(stringTest, response); + }); + + var specialCharacters = 'quote: \" backslash:' + + ' forwardslash-escaped: \/ ' + + ' backspace: \b formfeed: \f newline: \n return: \r tab: ' + + ' now-all-of-them-together: "\\\/\b\n\r\t' + + ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><' + + ' char-to-test-json-parsing: ]] \"]] \\" }}}{ [[[ '; + client.testString(specialCharacters, function(err, response) { + assert( ! err); + assert.equal(specialCharacters, response); + }); + + + client.testByte(1, function(err, response) { + assert( ! err); + assert.equal(1, response); + }); + client.testByte(0, function(err, response) { + assert( ! err); + assert.equal(0, response); + }); + client.testByte(-1, function(err, response) { + assert( ! err); + assert.equal(-1, response); + }); + client.testByte(-127, function(err, response) { + assert( ! err); + assert.equal(-127, response); + }); + + client.testI32(-1, function(err, response) { + assert( ! err); + assert.equal(-1, response); + }); + + client.testI64(5, function(err, response) { + assert( ! err); + assert.equal(5, response); + }); + client.testI64(-5, function(err, response) { + assert( ! err); + assert.equal(-5, response); + }); + client.testI64(-34359738368, function(err, response) { + assert( ! err); + assert.equal(-34359738368, response); + }); + + client.testDouble(-5.2098523, function(err, response) { + assert( ! err); + assert.equal(-5.2098523, response); + }); + client.testDouble(7.012052175215044, function(err, response) { + assert( ! err); + assert.equal(7.012052175215044, response); + }); + + var out = new ttypes.Xtruct({ + string_thing: 'Zero', + byte_thing: 1, + i32_thing: -3, + i64_thing: 1000000 + }); + client.testStruct(out, function(err, response) { + assert( ! err); + checkRecursively(out, response); + }); + + var out2 = new ttypes.Xtruct2(); + out2.byte_thing = 1; + out2.struct_thing = out; + out2.i32_thing = 5; + client.testNest(out2, function(err, response) { + assert( ! err); + checkRecursively(out2, response); + }); + + var mapout = {}; + for (var i = 0; i < 5; ++i) { + mapout[i] = i-10; + } + client.testMap(mapout, function(err, response) { + assert( ! err); + assert.deepEqual(mapout, response); + }); + + var mapTestInput = { + "a":"123", "a b":"with spaces ", "same":"same", "0":"numeric key", + "longValue":stringTest, stringTest:"long key" + }; + client.testStringMap(mapTestInput, function(err, response) { + assert( ! err); + assert.deepEqual(mapTestInput, response); + }); + + var setTestInput = [1,2,3]; + client.testSet(setTestInput, function(err, response) { + assert( ! err); + assert.deepEqual(setTestInput, response); + }); + client.testList(setTestInput, function(err, response) { + assert( ! err); + assert.deepEqual(setTestInput, response); + }); + + client.testEnum(ttypes.Numberz.ONE, function(err, response) { + assert( ! err); + assert.equal(ttypes.Numberz.ONE, response); + }); + + client.testTypedef(69, function(err, response) { + assert( ! err); + assert.equal(69, response); + }); + + var mapMapTest = { + "4": {"1":1, "2":2, "3":3, "4":4}, + "-4": {"-4":-4, "-3":-3, "-2":-2, "-1":-1} + }; + client.testMapMap(mapMapTest, function(err, response) { + assert( ! err); + assert.deepEqual(mapMapTest, response); + }); + + var crazy = new ttypes.Insanity({ + "userMap":{ "5":5, "8":8 }, + "xtructs":[new ttypes.Xtruct({ + "string_thing":"Goodbye4", + "byte_thing":4, + "i32_thing":4, + "i64_thing":4 + }), new ttypes.Xtruct({ + "string_thing":"Hello2", + "byte_thing":2, + "i32_thing":2, + "i64_thing":2 + })] + }); + var insanity = { + "1":{ "2": crazy, "3": crazy }, + "2":{ "6":{ "userMap":null, "xtructs":null } } + }; + client.testInsanity(crazy, function(err, response) { + assert( ! err); + checkRecursively(insanity, response); + }); + + client.testException('TException', function(err, response) { + assert( ! response); + }); + + client.testException('Xception', function(err, response) { + assert( ! response); + assert.equal(err.errorCode, 1001); + assert.equal('Xception', err.message); + }); + + client.testException('no Exception', function(err, response) { + assert( ! err); + assert.equal(undefined, response); //void + }); + + client.testOneway(0, function(err, response) { + assert(false); //should not answer + }); + + (function() { + var test_complete = false; + var retrys = 0; + var retry_limit = 30; + var retry_interval = 100; + /** + * redo a simple test after the oneway to make sure we aren't "off by one" -- + * if the server treated oneway void like normal void, this next test will + * fail since it will get the void confirmation rather than the correct + * result. In this circumstance, the client will throw the exception: + * + * Because this is the last test against the server, when it completes + * the entire suite is complete by definition (the tests run serially). + */ + client.testI32(-1, function(err, response) { + assert( ! err); + assert.equal(-1, response); + test_complete = true; + }); + + //We wait up to retry_limit * retry_interval for the test suite to complete + function TestForCompletion() { + if(test_complete) { + if (callback) { + callback("Server successfully tested!"); + } + } else { + if (++retrys < retry_limit) { + setTimeout(TestForCompletion, retry_interval); + } else { + if (callback) { + callback("Server test failed to complete after " + + (retry_limit*retry_interval/1000) + " seconds"); + } + } + } + } + + setTimeout(TestForCompletion, retry_interval); + })(); +} \ No newline at end of file