From fd81e70443a4a185bcc14ab38f52a1aa8b1a2782 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 16 Jan 2015 14:22:14 -0800 Subject: [PATCH 1/8] Made method names more idiomatically cased for clients and servers --- src/node/common.js | 5 +++++ src/node/examples/math_server.js | 8 ++++---- src/node/package.json | 3 ++- src/node/surface_client.js | 12 ++++++++---- src/node/surface_server.js | 10 +++++++--- src/node/test/math_client_test.js | 8 ++++---- src/node/test/surface_test.js | 6 +++--- 7 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/node/common.js b/src/node/common.js index 656a4aca953..c9684f0ec48 100644 --- a/src/node/common.js +++ b/src/node/common.js @@ -31,6 +31,8 @@ * */ +var s = require('underscore.string'); + /** * Get a function that deserializes a specific type of protobuf. * @param {function()} cls The constructor of the message type to deserialize @@ -73,6 +75,9 @@ function fullyQualifiedName(value) { return ''; } var name = value.name; + if (value.className === 'Service.RPCMethod') { + name = s(name).capitalize().value(); + } if (value.hasOwnProperty('parent')) { var parent_name = fullyQualifiedName(value.parent); if (parent_name !== '') { diff --git a/src/node/examples/math_server.js b/src/node/examples/math_server.js index 366513dc17d..d649b4fd6d0 100644 --- a/src/node/examples/math_server.js +++ b/src/node/examples/math_server.js @@ -119,10 +119,10 @@ function mathDivMany(stream) { var server = new Server({ 'math.Math' : { - Div: mathDiv, - Fib: mathFib, - Sum: mathSum, - DivMany: mathDivMany + div: mathDiv, + fib: mathFib, + sum: mathSum, + divMany: mathDivMany } }); diff --git a/src/node/package.json b/src/node/package.json index ed93c4ff41e..7051f1c8491 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -8,8 +8,9 @@ "dependencies": { "bindings": "^1.2.1", "nan": "~1.3.0", + "protobufjs": "murgatroid99/ProtoBuf.js", "underscore": "^1.7.0", - "protobufjs": "murgatroid99/ProtoBuf.js" + "underscore.string": "^3.0.0" }, "devDependencies": { "mocha": "~1.21.0", diff --git a/src/node/surface_client.js b/src/node/surface_client.js index 77dab5ca6f8..996e3d101fc 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -33,6 +33,9 @@ var _ = require('underscore'); +var capitalize = require('underscore.string/capitalize'); +var decapitalize = require('underscore.string/decapitalize'); + var client = require('./client.js'); var common = require('./common.js'); @@ -352,10 +355,11 @@ function makeClientConstructor(service) { method_type = 'unary'; } } - SurfaceClient.prototype[method.name] = requester_makers[method_type]( - prefix + method.name, - common.serializeCls(method.resolvedRequestType.build()), - common.deserializeCls(method.resolvedResponseType.build())); + SurfaceClient.prototype[decapitalize(method.name)] = + requester_makers[method_type]( + prefix + capitalize(method.name), + common.serializeCls(method.resolvedRequestType.build()), + common.deserializeCls(method.resolvedResponseType.build())); }); SurfaceClient.service = service; diff --git a/src/node/surface_server.js b/src/node/surface_server.js index b6e0c37b4cd..0b19d96b4cb 100644 --- a/src/node/surface_server.js +++ b/src/node/surface_server.js @@ -33,6 +33,9 @@ var _ = require('underscore'); +var capitalize = require('underscore.string/capitalize'); +var decapitalize = require('underscore.string/decapitalize'); + var Server = require('./server.js'); var stream = require('stream'); @@ -332,15 +335,16 @@ function makeServerConstructor(services) { method_type = 'unary'; } } - if (service_handlers[service_name][method.name] === undefined) { + if (service_handlers[service_name][decapitalize(method.name)] === + undefined) { throw new Error('Method handler for ' + common.fullyQualifiedName(method) + ' not provided.'); } var binary_handler = handler_makers[method_type]( - service_handlers[service_name][method.name], + service_handlers[service_name][decapitalize(method.name)], common.serializeCls(method.resolvedResponseType.build()), common.deserializeCls(method.resolvedRequestType.build())); - server.register(prefix + method.name, binary_handler); + server.register(prefix + capitalize(method.name), binary_handler); }); }, this); } diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js index 45c956d1793..5ddf75a2006 100644 --- a/src/node/test/math_client_test.js +++ b/src/node/test/math_client_test.js @@ -61,7 +61,7 @@ describe('Math client', function() { }); it('should handle a single request', function(done) { var arg = {dividend: 7, divisor: 4}; - var call = math_client.Div(arg, function handleDivResult(err, value) { + var call = math_client.div(arg, function handleDivResult(err, value) { assert.ifError(err); assert.equal(value.quotient, 1); assert.equal(value.remainder, 3); @@ -72,7 +72,7 @@ describe('Math client', function() { }); }); it('should handle a server streaming request', function(done) { - var call = math_client.Fib({limit: 7}); + var call = math_client.fib({limit: 7}); var expected_results = [1, 1, 2, 3, 5, 8, 13]; var next_expected = 0; call.on('data', function checkResponse(value) { @@ -85,7 +85,7 @@ describe('Math client', function() { }); }); it('should handle a client streaming request', function(done) { - var call = math_client.Sum(function handleSumResult(err, value) { + var call = math_client.sum(function handleSumResult(err, value) { assert.ifError(err); assert.equal(value.num, 21); }); @@ -103,7 +103,7 @@ describe('Math client', function() { assert.equal(value.quotient, index); assert.equal(value.remainder, 1); } - var call = math_client.DivMany(); + var call = math_client.divMany(); var response_index = 0; call.on('data', function(value) { checkResponse(response_index, value); diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 8d0d8ec3bc9..34f1a156eb9 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -59,9 +59,9 @@ describe('Surface server constructor', function() { assert.throws(function() { new Server({ 'math.Math': { - 'Div': function() {}, - 'DivMany': function() {}, - 'Fib': function() {} + 'div': function() {}, + 'divMany': function() {}, + 'fib': function() {} } }); }, /math.Math.Sum/); From 53116ffd7a120ce512594758f19f4f8eff78e5c9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 16 Jan 2015 14:22:58 -0800 Subject: [PATCH 2/8] Fixed casing functionality in common.js --- src/node/common.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/common.js b/src/node/common.js index c9684f0ec48..54247e3fa11 100644 --- a/src/node/common.js +++ b/src/node/common.js @@ -31,7 +31,7 @@ * */ -var s = require('underscore.string'); +var capitalize = require('underscore.string/capitalize'); /** * Get a function that deserializes a specific type of protobuf. @@ -76,7 +76,7 @@ function fullyQualifiedName(value) { } var name = value.name; if (value.className === 'Service.RPCMethod') { - name = s(name).capitalize().value(); + name = capitalize(name); } if (value.hasOwnProperty('parent')) { var parent_name = fullyQualifiedName(value.parent); From 7d1a19af2694c27ec5e86809b5188c546b3f8a03 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Jan 2015 15:59:43 -0800 Subject: [PATCH 3/8] Added interop client and server --- src/node/client.js | 1 + src/node/package.json | 2 +- src/node/surface_client.js | 1 + src/node/test/interop_sanity_test.js | 69 ++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 src/node/test/interop_sanity_test.js diff --git a/src/node/client.js b/src/node/client.js index edaa115d0fc..e3e9fec026a 100644 --- a/src/node/client.js +++ b/src/node/client.js @@ -115,6 +115,7 @@ function GrpcClientStream(call, options) { }, function(event) { self.emit('metadata', event.data); }, function(event) { + debugger; self.emit('status', event.data); }, 0); this.on('finish', function() { diff --git a/src/node/package.json b/src/node/package.json index 7051f1c8491..dde43f82175 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -14,7 +14,7 @@ }, "devDependencies": { "mocha": "~1.21.0", - "highland": "~2.0.0" + "minimist": "^1.1.0" }, "main": "main.js" } diff --git a/src/node/surface_client.js b/src/node/surface_client.js index 996e3d101fc..84af774b9c8 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -52,6 +52,7 @@ var util = require('util'); function forwardEvent(fromEmitter, toEmitter, event) { fromEmitter.on(event, function forward() { + debugger; _.partial(toEmitter.emit, event).apply(toEmitter, arguments); }); } diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js new file mode 100644 index 00000000000..99e5fa1e047 --- /dev/null +++ b/src/node/test/interop_sanity_test.js @@ -0,0 +1,69 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var interop_server = require('../interop/interop_server.js'); +var interop_client = require('../interop/interop_client.js'); + +var port_picker = require('../port_picker'); + +var server; + +var port; + +describe('Interop tests', function() { + before(function(done) { + port_picker.nextAvailablePort(function(addr) { + server = interop_server.getServer(addr.substring(addr.indexOf(':') + 1)); + port = addr; + done(); + }); + }); + it.only('should pass empty_unary', function(done) { + interop_client.runTest(port, null, 'empty_unary', false, done); + }); + it('should pass large_unary', function(done) { + interop_client.runTest(port, null, 'large_unary', false, done); + }); + it('should pass client_streaming', function(done) { + interop_client.runTest(port, null, 'client_streaming', false, done); + }); + it('should pass server_streaming', function(done) { + interop_client.runTest(port, null, 'server_streaming', false, done); + }); + it('should pass ping_pong', function(done) { + interop_client.runTest(port, null, 'ping_pong', false, done); + }); + it('should pass empty_stream', function(done) { + interop_client.runTest(port, null, 'empty_stream', false, done); + }); +}); From 97d61308f0d5f15e555c5e5da52973480b8f3cf4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Jan 2015 18:06:43 -0800 Subject: [PATCH 4/8] Added and fixed interop tests --- src/node/client.js | 7 +- src/node/interop/empty.proto | 19 +++ src/node/interop/interop_client.js | 218 +++++++++++++++++++++++++++ src/node/interop/interop_client.js~ | 34 +++++ src/node/interop/interop_server.js | 144 ++++++++++++++++++ src/node/interop/interop_server.js~ | 53 +++++++ src/node/interop/messages.proto | 94 ++++++++++++ src/node/interop/test.proto | 42 ++++++ src/node/interop/test.proto~ | 42 ++++++ src/node/main.js | 2 +- src/node/server.js | 1 + src/node/surface_client.js | 1 - src/node/test/interop_sanity_test.js | 7 +- 13 files changed, 658 insertions(+), 6 deletions(-) create mode 100644 src/node/interop/empty.proto create mode 100644 src/node/interop/interop_client.js create mode 100644 src/node/interop/interop_client.js~ create mode 100644 src/node/interop/interop_server.js create mode 100644 src/node/interop/interop_server.js~ create mode 100644 src/node/interop/messages.proto create mode 100644 src/node/interop/test.proto create mode 100644 src/node/interop/test.proto~ diff --git a/src/node/client.js b/src/node/client.js index e3e9fec026a..6649c1ed680 100644 --- a/src/node/client.js +++ b/src/node/client.js @@ -115,11 +115,14 @@ function GrpcClientStream(call, options) { }, function(event) { self.emit('metadata', event.data); }, function(event) { - debugger; self.emit('status', event.data); }, 0); this.on('finish', function() { - call.writesDone(function() {}); + try { + call.writesDone(function() {}); + } catch (e) { + debugger; + } }); /** * Indicate that reads should start, and start them if the INVOKE_ACCEPTED diff --git a/src/node/interop/empty.proto b/src/node/interop/empty.proto new file mode 100644 index 00000000000..c9920a22eec --- /dev/null +++ b/src/node/interop/empty.proto @@ -0,0 +1,19 @@ +syntax = "proto2"; + +package grpc.testing; + +// An empty message that you can re-use to avoid defining duplicated empty +// messages in your project. A typical example is to use it as argument or the +// return value of a service API. For instance: +// +// service Foo { +// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; +// }; +// +// MOE:begin_strip +// The difference between this one and net/rpc/empty-message.proto is that +// 1) The generated message here is in proto2 C++ API. +// 2) The proto2.Empty has minimum dependencies +// (no message_set or net/rpc dependencies) +// MOE:end_strip +message Empty {} diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js new file mode 100644 index 00000000000..7cacf83cb99 --- /dev/null +++ b/src/node/interop/interop_client.js @@ -0,0 +1,218 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var grpc = require('..'); +var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; + +var assert = require('assert'); + +function zeroBuffer(size) { + var zeros = new Buffer(size); + zeros.fill(0); + return zeros; +} + +function emptyUnary(client, done) { + var call = client.emptyCall({}, function(err, resp) { + assert.ifError(err); + }); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); +} + +function largeUnary(client, done) { + var arg = { + response_type: testProto.PayloadType.COMPRESSABLE, + response_size: 314159, + payload: { + body: zeroBuffer(271828) + } + }; + var call = client.unaryCall(arg, function(err, resp) { + assert.ifError(err); + assert.strictEqual(resp.payload.type, testProto.PayloadType.COMPRESSABLE); + assert.strictEqual(resp.payload.body.limit - resp.payload.body.offset, + 314159); + }); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); +} + +function clientStreaming(client, done) { + var call = client.streamingInputCall(function(err, resp) { + assert.ifError(err); + assert.strictEqual(resp.aggregated_payload_size, 74922); + }); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); + var payload_sizes = [27182, 8, 1828, 45904]; + for (var i = 0; i < payload_sizes.length; i++) { + call.write({payload: {body: zeroBuffer(payload_sizes[i])}}); + } + call.end(); +} + +function serverStreaming(client, done) { + var arg = { + response_type: testProto.PayloadType.COMPRESSABLE, + response_parameters: [ + {size: 31415}, + {size: 9}, + {size: 2653}, + {size: 58979} + ] + }; + var call = client.streamingOutputCall(arg); + var resp_index = 0; + call.on('data', function(value) { + assert(resp_index < 4); + assert.strictEqual(value.payload.type, testProto.PayloadType.COMPRESSABLE); + assert.strictEqual(value.payload.body.limit - value.payload.body.offset, + arg.response_parameters[resp_index].size); + resp_index += 1; + }); + call.on('status', function(status) { + assert.strictEqual(resp_index, 4); + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); +} + +function pingPong(client, done) { + var payload_sizes = [27182, 8, 1828, 45904]; + var response_sizes = [31415, 9, 2653, 58979]; + var call = client.fullDuplexCall(); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); + var index = 0; + call.write({ + response_type: testProto.PayloadType.COMPRESSABLE, + response_parameters: [ + {size: response_sizes[index]} + ], + payload: {body: zeroBuffer(payload_sizes[index])} + }); + call.on('data', function(response) { + assert.strictEqual(response.payload.type, + testProto.PayloadType.COMPRESSABLE); + assert.equal(response.payload.body.limit - response.payload.body.offset, + response_sizes[index]); + index += 1; + if (index == 4) { + call.end(); + } else { + call.write({ + response_type: testProto.PayloadType.COMPRESSABLE, + response_parameters: [ + {size: response_sizes[index]} + ], + payload: {body: zeroBuffer(payload_sizes[index])} + }); + } + }); +} + +function emptyStream(client, done) { + var call = client.fullDuplexCall(); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); + call.on('data', function(value) { + assert.fail(value, null, 'No data should have been received', '!=='); + }); + call.end(); +} + +var test_cases = { + empty_unary: emptyUnary, + large_unary: largeUnary, + client_streaming: clientStreaming, + server_streaming: serverStreaming, + ping_pong: pingPong, + empty_stream: emptyStream +}; + +/** + * Execute a single test case. + * @param {string} address The address of the server to connect to, in the + * format "hostname:port" + * @param {string} host_overrirde The hostname of the server to use as an SSL + * override + * @param {string} test_case The name of the test case to run + * @param {bool} tls Indicates that a secure channel should be used + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function runTest(address, host_override, test_case, tls, done) { + // TODO(mlumish): enable TLS functionality + // TODO(mlumish): fix namespaces and service name + var client = new testProto.TestService(address); + + test_cases[test_case](client, done); +} + +if (require.main === module) { + var parseArgs = require('minimist'); + var argv = parseArgs(process.argv, { + string: ['server_host', 'server_host_override', 'server_port', 'test_case', + 'use_tls', 'use_test_ca'] + }); + runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, + argv.test_case, argv.use_tls === 'true'); +} + +/** + * See docs for runTest + */ +exports.runTest = runTest; diff --git a/src/node/interop/interop_client.js~ b/src/node/interop/interop_client.js~ new file mode 100644 index 00000000000..c22879702df --- /dev/null +++ b/src/node/interop/interop_client.js~ @@ -0,0 +1,34 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var grpc = require('..'); diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js new file mode 100644 index 00000000000..3eb663c1d5f --- /dev/null +++ b/src/node/interop/interop_server.js @@ -0,0 +1,144 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var _ = require('underscore'); +var grpc = require('..'); +var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; +var Server = grpc.buildServer([testProto.TestService.service]); + +function zeroBuffer(size) { + var zeros = new Buffer(size); + zeros.fill(0); + return zeros; +} + +function handleEmpty(call, callback) { + callback(null, {}); +} + +function handleUnary(call, callback) { + var req = call.request; + var zeros = zeroBuffer(req.response_size); + var payload_type = req.response_type; + if (payload_type === testProto.PayloadType.RANDOM) { + payload_type = [ + testProto.PayloadType.COMPRESSABLE, + testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1]; + } + callback(null, {payload: {type: payload_type, body: zeros}}); +} + +function handleStreamingInput(call, callback) { + var aggregate_size = 0; + call.on('data', function(value) { + aggregate_size += value.payload.body.limit - value.payload.body.offset; + }); + call.on('end', function() { + callback(null, {aggregated_payload_size: aggregate_size}); + }); +} + +function handleStreamingOutput(call) { + var req = call.request; + var payload_type = req.response_type; + if (payload_type === testProto.PayloadType.RANDOM) { + payload_type = [ + testProto.PayloadType.COMPRESSABLE, + testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1]; + } + _.each(req.response_parameters, function(resp_param) { + call.write({ + payload: { + body: zeroBuffer(resp_param.size), + type: payload_type + } + }); + }); + call.end(); +} + +function handleFullDuplex(call) { + call.on('data', function(value) { + var payload_type = value.response_type; + if (payload_type === testProto.PayloadType.RANDOM) { + payload_type = [ + testProto.PayloadType.COMPRESSABLE, + testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1]; + } + _.each(value.response_parameters, function(resp_param) { + call.write({ + payload: { + body: zeroBuffer(resp_param.size), + type: payload_type + } + }); + }); + }); + call.on('end', function() { + call.end(); + }); +} + +function handleHalfDuplex(call) { + throw new Error('HalfDuplexCall not yet implemented'); +} + +function getServer(port, tls) { + // TODO(mlumish): enable TLS functionality + var server = new Server({ + 'grpc.testing.TestService' : { + emptyCall: handleEmpty, + unaryCall: handleUnary, + streamingOutputCall: handleStreamingOutput, + streamingInputCall: handleStreamingInput, + fullDuplexCall: handleFullDuplex, + halfDuplexCall: handleHalfDuplex + } + }); + server.bind('0.0.0.0:' + port); + return server; +} + +if (require.main === module) { + var parseArgs = require('minimist'); + var argv = parseArgs(process.argv, { + string: ['port', 'use_tls'] + }); + var server = getServer(argv.port, argv.use_tls === 'true'); + server.start(); +} + +/** + * See docs for getServer + */ +exports.getServer = getServer; diff --git a/src/node/interop/interop_server.js~ b/src/node/interop/interop_server.js~ new file mode 100644 index 00000000000..7250fa7eece --- /dev/null +++ b/src/node/interop/interop_server.js~ @@ -0,0 +1,53 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var grpc = require('..'); +var testProto = grpc.load('test.proto').grpc.testing; +var Server = grpc.buildServer([testProto.TestService.Service]); + +function handleEmpty(call, callback) { + callback(null, {}); +} + +function handleUnary(call, callback) { + var req = call.request; + var zeros = new Buffer(req.response_size); + zeros.fill(0); + var payload_type = req.response_type; + if (payload_type === testProto.PayloadType.RANDOM) { + payload_type = [ + testProto.PayloadType.COMPRESSABLE, + testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1]; + } + callback(null, {payload: {type: payload_type, body: zeros}}); +} diff --git a/src/node/interop/messages.proto b/src/node/interop/messages.proto new file mode 100644 index 00000000000..29db0dd8b1a --- /dev/null +++ b/src/node/interop/messages.proto @@ -0,0 +1,94 @@ +// Message definitions to be used by integration test service definitions. + +syntax = "proto2"; + +package grpc.testing; + +// The type of payload that should be returned. +enum PayloadType { + // Compressable text format. + COMPRESSABLE = 0; + + // Uncompressable binary format. + UNCOMPRESSABLE = 1; + + // Randomly chosen from all other formats defined in this enum. + RANDOM = 2; +} + +// A block of data, to simply increase gRPC message size. +message Payload { + // The type of data in body. + optional PayloadType type = 1; + // Primary contents of payload. + optional bytes body = 2; +} + +// Unary request. +message SimpleRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, server randomly chooses one from other formats. + optional PayloadType response_type = 1; + + // Desired payload size in the response from the server. + // If response_type is COMPRESSABLE, this denotes the size before compression. + optional int32 response_size = 2; + + // Optional input payload sent along with the request. + optional Payload payload = 3; +} + +// Unary response, as configured by the request. +message SimpleResponse { + // Payload to increase message size. + optional Payload payload = 1; + // The user the request came from, for verifying authentication was + // successful when the client expected it. + optional int64 effective_gaia_user_id = 2; +} + +// Client-streaming request. +message StreamingInputCallRequest { + // Optional input payload sent along with the request. + optional Payload payload = 1; + + // Not expecting any payload from the response. +} + +// Client-streaming response. +message StreamingInputCallResponse { + // Aggregated size of payloads received from the client. + optional int32 aggregated_payload_size = 1; +} + +// Configuration for a particular response. +message ResponseParameters { + // Desired payload sizes in responses from the server. + // If response_type is COMPRESSABLE, this denotes the size before compression. + optional int32 size = 1; + + // Desired interval between consecutive responses in the response stream in + // microseconds. + optional int32 interval_us = 2; +} + +// Server-streaming request. +message StreamingOutputCallRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, the payload from each response in the stream + // might be of different types. This is to simulate a mixed type of payload + // stream. + optional PayloadType response_type = 1; + + // Configuration for each expected response message. + repeated ResponseParameters response_parameters = 2; + + // Optional input payload sent along with the request. + optional Payload payload = 3; +} + +// Server-streaming response, as configured by the request and parameters. +message StreamingOutputCallResponse { + // Payload to increase response size. + optional Payload payload = 1; +} diff --git a/src/node/interop/test.proto b/src/node/interop/test.proto new file mode 100644 index 00000000000..8380ebb31de --- /dev/null +++ b/src/node/interop/test.proto @@ -0,0 +1,42 @@ +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. +syntax = "proto2"; + +import "empty.proto"; +import "messages.proto"; + +package grpc.testing; + +// A simple service to test the various types of RPCs and experiment with +// performance with various types of payload. +service TestService { + // One empty request followed by one empty response. + rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); + + // One request followed by one response. + // The server returns the client payload as-is. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by a sequence of responses (streamed download). + // The server returns the payload with client desired type and sizes. + rpc StreamingOutputCall(StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by one response (streamed upload). + // The server returns the aggregated size of client payload as the result. + rpc StreamingInputCall(stream StreamingInputCallRequest) + returns (StreamingInputCallResponse); + + // A sequence of requests with each request served by the server immediately. + // As one request could lead to multiple responses, this interface + // demonstrates the idea of full duplexing. + rpc FullDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by a sequence of responses. + // The server buffers all the client requests and then serves them in order. A + // stream of responses are returned to the client when the server starts with + // first request. + rpc HalfDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); +} diff --git a/src/node/interop/test.proto~ b/src/node/interop/test.proto~ new file mode 100644 index 00000000000..e358f3bea5b --- /dev/null +++ b/src/node/interop/test.proto~ @@ -0,0 +1,42 @@ +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. +syntax = "proto2"; + +import "test/cpp/interop/empty.proto"; +import "test/cpp/interop/messages.proto"; + +package grpc.testing; + +// A simple service to test the various types of RPCs and experiment with +// performance with various types of payload. +service TestService { + // One empty request followed by one empty response. + rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); + + // One request followed by one response. + // The server returns the client payload as-is. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by a sequence of responses (streamed download). + // The server returns the payload with client desired type and sizes. + rpc StreamingOutputCall(StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by one response (streamed upload). + // The server returns the aggregated size of client payload as the result. + rpc StreamingInputCall(stream StreamingInputCallRequest) + returns (StreamingInputCallResponse); + + // A sequence of requests with each request served by the server immediately. + // As one request could lead to multiple responses, this interface + // demonstrates the idea of full duplexing. + rpc FullDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by a sequence of responses. + // The server buffers all the client requests and then serves them in order. A + // stream of responses are returned to the client when the server starts with + // first request. + rpc HalfDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); +} diff --git a/src/node/main.js b/src/node/main.js index a8dfa200245..024806bf613 100644 --- a/src/node/main.js +++ b/src/node/main.js @@ -55,7 +55,7 @@ function loadObject(value) { return result; } else if (value.className === 'Service') { return surface_client.makeClientConstructor(value); - } else if (value.className === 'Service.Message') { + } else if (value.className === 'Message' || value.className === 'Enum') { return value.build(); } else { return value; diff --git a/src/node/server.js b/src/node/server.js index e947032b297..8f6f7504c0c 100644 --- a/src/node/server.js +++ b/src/node/server.js @@ -193,6 +193,7 @@ function Server(options) { * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW */ function handleNewCall(event) { + debugger; var call = event.call; var data = event.data; if (data == null) { diff --git a/src/node/surface_client.js b/src/node/surface_client.js index 84af774b9c8..996e3d101fc 100644 --- a/src/node/surface_client.js +++ b/src/node/surface_client.js @@ -52,7 +52,6 @@ var util = require('util'); function forwardEvent(fromEmitter, toEmitter, event) { fromEmitter.on(event, function forward() { - debugger; _.partial(toEmitter.emit, event).apply(toEmitter, arguments); }); } diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index 99e5fa1e047..08ee1af77a2 100644 --- a/src/node/test/interop_sanity_test.js +++ b/src/node/test/interop_sanity_test.js @@ -44,11 +44,13 @@ describe('Interop tests', function() { before(function(done) { port_picker.nextAvailablePort(function(addr) { server = interop_server.getServer(addr.substring(addr.indexOf(':') + 1)); + server.listen(); port = addr; done(); }); }); - it.only('should pass empty_unary', function(done) { + // This depends on not using a binary stream + it.skip('should pass empty_unary', function(done) { interop_client.runTest(port, null, 'empty_unary', false, done); }); it('should pass large_unary', function(done) { @@ -63,7 +65,8 @@ describe('Interop tests', function() { it('should pass ping_pong', function(done) { interop_client.runTest(port, null, 'ping_pong', false, done); }); - it('should pass empty_stream', function(done) { + // This depends on the new invoke API + it.skip('should pass empty_stream', function(done) { interop_client.runTest(port, null, 'empty_stream', false, done); }); }); From 621d0b98bfcd67ce1b1114ff3ec5f919c19cc0e3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Jan 2015 18:07:04 -0800 Subject: [PATCH 5/8] Removed temp files --- src/node/interop/interop_client.js~ | 34 ------------------ src/node/interop/interop_server.js~ | 53 ----------------------------- src/node/interop/test.proto~ | 42 ----------------------- 3 files changed, 129 deletions(-) delete mode 100644 src/node/interop/interop_client.js~ delete mode 100644 src/node/interop/interop_server.js~ delete mode 100644 src/node/interop/test.proto~ diff --git a/src/node/interop/interop_client.js~ b/src/node/interop/interop_client.js~ deleted file mode 100644 index c22879702df..00000000000 --- a/src/node/interop/interop_client.js~ +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var grpc = require('..'); diff --git a/src/node/interop/interop_server.js~ b/src/node/interop/interop_server.js~ deleted file mode 100644 index 7250fa7eece..00000000000 --- a/src/node/interop/interop_server.js~ +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2014, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -var grpc = require('..'); -var testProto = grpc.load('test.proto').grpc.testing; -var Server = grpc.buildServer([testProto.TestService.Service]); - -function handleEmpty(call, callback) { - callback(null, {}); -} - -function handleUnary(call, callback) { - var req = call.request; - var zeros = new Buffer(req.response_size); - zeros.fill(0); - var payload_type = req.response_type; - if (payload_type === testProto.PayloadType.RANDOM) { - payload_type = [ - testProto.PayloadType.COMPRESSABLE, - testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1]; - } - callback(null, {payload: {type: payload_type, body: zeros}}); -} diff --git a/src/node/interop/test.proto~ b/src/node/interop/test.proto~ deleted file mode 100644 index e358f3bea5b..00000000000 --- a/src/node/interop/test.proto~ +++ /dev/null @@ -1,42 +0,0 @@ -// An integration test service that covers all the method signature permutations -// of unary/streaming requests/responses. -syntax = "proto2"; - -import "test/cpp/interop/empty.proto"; -import "test/cpp/interop/messages.proto"; - -package grpc.testing; - -// A simple service to test the various types of RPCs and experiment with -// performance with various types of payload. -service TestService { - // One empty request followed by one empty response. - rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); - - // One request followed by one response. - // The server returns the client payload as-is. - rpc UnaryCall(SimpleRequest) returns (SimpleResponse); - - // One request followed by a sequence of responses (streamed download). - // The server returns the payload with client desired type and sizes. - rpc StreamingOutputCall(StreamingOutputCallRequest) - returns (stream StreamingOutputCallResponse); - - // A sequence of requests followed by one response (streamed upload). - // The server returns the aggregated size of client payload as the result. - rpc StreamingInputCall(stream StreamingInputCallRequest) - returns (StreamingInputCallResponse); - - // A sequence of requests with each request served by the server immediately. - // As one request could lead to multiple responses, this interface - // demonstrates the idea of full duplexing. - rpc FullDuplexCall(stream StreamingOutputCallRequest) - returns (stream StreamingOutputCallResponse); - - // A sequence of requests followed by a sequence of responses. - // The server buffers all the client requests and then serves them in order. A - // stream of responses are returned to the client when the server starts with - // first request. - rpc HalfDuplexCall(stream StreamingOutputCallRequest) - returns (stream StreamingOutputCallResponse); -} From 6d10bda989f41d88746aa1b7e760707d71a49407 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Jan 2015 18:07:46 -0800 Subject: [PATCH 6/8] Added emacs temp files to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3efc25aafb1..63332d1b16b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ coverage # cache for run_tests.py .run_tests_cache +# emacs temp files +*~ \ No newline at end of file From b6ab1b477f2c0df860acafd91047da2de288e9fe Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 21 Jan 2015 10:30:36 -0800 Subject: [PATCH 7/8] Added TLS support to interop tests --- src/node/interop/interop_client.js | 60 ++++++++++++++++++++++++++- src/node/interop/interop_server.js | 62 +++++++++++++++++++++++++++- src/node/main.js | 10 +++++ src/node/package.json | 1 + src/node/test/interop_sanity_test.js | 16 +++---- 5 files changed, 138 insertions(+), 11 deletions(-) diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index 7cacf83cb99..cf75b9a77ac 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -31,17 +31,30 @@ * */ +var fs = require('fs'); +var path = require('path'); var grpc = require('..'); var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; var assert = require('assert'); +/** + * Create a buffer filled with size zeroes + * @param {number} size The length of the buffer + * @return {Buffer} The new buffer + */ function zeroBuffer(size) { var zeros = new Buffer(size); zeros.fill(0); return zeros; } +/** + * Run the empty_unary test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ function emptyUnary(client, done) { var call = client.emptyCall({}, function(err, resp) { assert.ifError(err); @@ -54,6 +67,12 @@ function emptyUnary(client, done) { }); } +/** + * Run the large_unary test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ function largeUnary(client, done) { var arg = { response_type: testProto.PayloadType.COMPRESSABLE, @@ -76,6 +95,12 @@ function largeUnary(client, done) { }); } +/** + * Run the client_streaming test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ function clientStreaming(client, done) { var call = client.streamingInputCall(function(err, resp) { assert.ifError(err); @@ -94,6 +119,12 @@ function clientStreaming(client, done) { call.end(); } +/** + * Run the server_streaming test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ function serverStreaming(client, done) { var arg = { response_type: testProto.PayloadType.COMPRESSABLE, @@ -122,6 +153,12 @@ function serverStreaming(client, done) { }); } +/** + * Run the ping_pong test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ function pingPong(client, done) { var payload_sizes = [27182, 8, 1828, 45904]; var response_sizes = [31415, 9, 2653, 58979]; @@ -160,6 +197,13 @@ function pingPong(client, done) { }); } +/** + * Run the empty_stream test. + * NOTE: This does not work, but should with the new invoke API + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ function emptyStream(client, done) { var call = client.fullDuplexCall(); call.on('status', function(status) { @@ -174,6 +218,9 @@ function emptyStream(client, done) { call.end(); } +/** + * Map from test case names to test functions + */ var test_cases = { empty_unary: emptyUnary, large_unary: largeUnary, @@ -196,8 +243,17 @@ var test_cases = { */ function runTest(address, host_override, test_case, tls, done) { // TODO(mlumish): enable TLS functionality - // TODO(mlumish): fix namespaces and service name - var client = new testProto.TestService(address); + var options = {}; + if (tls) { + var ca_path = path.join(__dirname, '../test/data/ca.pem'); + var ca_data = fs.readFileSync(ca_path); + var creds = grpc.Credentials.createSsl(ca_data); + options.credentials = creds; + if (host_override) { + options['grpc.ssl_target_name_override'] = host_override; + } + } + var client = new testProto.TestService(address, options); test_cases[test_case](client, done); } diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js index 3eb663c1d5f..735b7a6d18b 100644 --- a/src/node/interop/interop_server.js +++ b/src/node/interop/interop_server.js @@ -31,21 +31,41 @@ * */ +var fs = require('fs'); +var path = require('path'); var _ = require('underscore'); var grpc = require('..'); var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; var Server = grpc.buildServer([testProto.TestService.service]); +/** + * Create a buffer filled with size zeroes + * @param {number} size The length of the buffer + * @return {Buffer} The new buffer + */ function zeroBuffer(size) { var zeros = new Buffer(size); zeros.fill(0); return zeros; } +/** + * Respond to an empty parameter with an empty response. + * NOTE: this currently does not work due to issue #137 + * @param {Call} call Call to handle + * @param {function(Error, Object)} callback Callback to call with result + * or error + */ function handleEmpty(call, callback) { callback(null, {}); } +/** + * Handle a unary request by sending the requested payload + * @param {Call} call Call to handle + * @param {function(Error, Object)} callback Callback to call with result or + * error + */ function handleUnary(call, callback) { var req = call.request; var zeros = zeroBuffer(req.response_size); @@ -58,6 +78,12 @@ function handleUnary(call, callback) { callback(null, {payload: {type: payload_type, body: zeros}}); } +/** + * Respond to a streaming call with the total size of all payloads + * @param {Call} call Call to handle + * @param {function(Error, Object)} callback Callback to call with result or + * error + */ function handleStreamingInput(call, callback) { var aggregate_size = 0; call.on('data', function(value) { @@ -68,6 +94,10 @@ function handleStreamingInput(call, callback) { }); } +/** + * Respond to a payload request with a stream of the requested payloads + * @param {Call} call Call to handle + */ function handleStreamingOutput(call) { var req = call.request; var payload_type = req.response_type; @@ -87,6 +117,11 @@ function handleStreamingOutput(call) { call.end(); } +/** + * Respond to a stream of payload requests with a stream of payload responses as + * they arrive. + * @param {Call} call Call to handle + */ function handleFullDuplex(call) { call.on('data', function(value) { var payload_type = value.response_type; @@ -109,12 +144,35 @@ function handleFullDuplex(call) { }); } +/** + * Respond to a stream of payload requests with a stream of payload responses + * after all requests have arrived + * @param {Call} call Call to handle + */ function handleHalfDuplex(call) { throw new Error('HalfDuplexCall not yet implemented'); } +/** + * Get a server object bound to the given port + * @param {string} port Port to which to bind + * @param {boolean} tls Indicates that the bound port should use TLS + * @return {Server} Server object bound to the support + */ function getServer(port, tls) { // TODO(mlumish): enable TLS functionality + var options = {}; + if (tls) { + var key_path = path.join(__dirname, '../test/data/server1.key'); + var pem_path = path.join(__dirname, '../test/data/server1.pem'); + + var key_data = fs.readFileSync(key_path); + var pem_data = fs.readFileSync(pem_path); + var server_creds = grpc.ServerCredentials.createSsl(null, + key_data, + pem_data); + options.credentials = server_creds; + } var server = new Server({ 'grpc.testing.TestService' : { emptyCall: handleEmpty, @@ -124,8 +182,8 @@ function getServer(port, tls) { fullDuplexCall: handleFullDuplex, halfDuplexCall: handleHalfDuplex } - }); - server.bind('0.0.0.0:' + port); + }, options); + server.bind('0.0.0.0:' + port, tls); return server; } diff --git a/src/node/main.js b/src/node/main.js index 024806bf613..751c3525d37 100644 --- a/src/node/main.js +++ b/src/node/main.js @@ -96,3 +96,13 @@ exports.status = grpc.status; * Call error name to code number mapping */ exports.callError = grpc.callError; + +/** + * Credentials factories + */ +exports.Credentials = grpc.Credentials; + +/** + * ServerCredentials factories + */ +exports.ServerCredentials = grpc.ServerCredentials; diff --git a/src/node/package.json b/src/node/package.json index dde43f82175..5f3c6fa3455 100644 --- a/src/node/package.json +++ b/src/node/package.json @@ -13,6 +13,7 @@ "underscore.string": "^3.0.0" }, "devDependencies": { + "highland": "~2.2.0", "mocha": "~1.21.0", "minimist": "^1.1.0" }, diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index 08ee1af77a2..9959a165ad1 100644 --- a/src/node/test/interop_sanity_test.js +++ b/src/node/test/interop_sanity_test.js @@ -40,10 +40,12 @@ var server; var port; +var name_override = 'foo.test.google.com'; + describe('Interop tests', function() { before(function(done) { port_picker.nextAvailablePort(function(addr) { - server = interop_server.getServer(addr.substring(addr.indexOf(':') + 1)); + server = interop_server.getServer(addr.substring(addr.indexOf(':') + 1), true); server.listen(); port = addr; done(); @@ -51,22 +53,22 @@ describe('Interop tests', function() { }); // This depends on not using a binary stream it.skip('should pass empty_unary', function(done) { - interop_client.runTest(port, null, 'empty_unary', false, done); + interop_client.runTest(port, name_override, 'empty_unary', true, done); }); it('should pass large_unary', function(done) { - interop_client.runTest(port, null, 'large_unary', false, done); + interop_client.runTest(port, name_override, 'large_unary', true, done); }); it('should pass client_streaming', function(done) { - interop_client.runTest(port, null, 'client_streaming', false, done); + interop_client.runTest(port, name_override, 'client_streaming', true, done); }); it('should pass server_streaming', function(done) { - interop_client.runTest(port, null, 'server_streaming', false, done); + interop_client.runTest(port, name_override, 'server_streaming', true, done); }); it('should pass ping_pong', function(done) { - interop_client.runTest(port, null, 'ping_pong', false, done); + interop_client.runTest(port, name_override, 'ping_pong', true, done); }); // This depends on the new invoke API it.skip('should pass empty_stream', function(done) { - interop_client.runTest(port, null, 'empty_stream', false, done); + interop_client.runTest(port, name_override, 'empty_stream', true, done); }); }); From 0397061095a05736dee043bc449b9b5318e31371 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 21 Jan 2015 11:58:23 -0800 Subject: [PATCH 8/8] Removed extra debugger statements --- src/node/client.js | 6 +----- src/node/server.js | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/node/client.js b/src/node/client.js index 6649c1ed680..edaa115d0fc 100644 --- a/src/node/client.js +++ b/src/node/client.js @@ -118,11 +118,7 @@ function GrpcClientStream(call, options) { self.emit('status', event.data); }, 0); this.on('finish', function() { - try { - call.writesDone(function() {}); - } catch (e) { - debugger; - } + call.writesDone(function() {}); }); /** * Indicate that reads should start, and start them if the INVOKE_ACCEPTED diff --git a/src/node/server.js b/src/node/server.js index 8f6f7504c0c..e947032b297 100644 --- a/src/node/server.js +++ b/src/node/server.js @@ -193,7 +193,6 @@ function Server(options) { * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW */ function handleNewCall(event) { - debugger; var call = event.call; var data = event.data; if (data == null) {