/* * * 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 assert = require('assert'); var fs = require('fs'); var path = require('path'); var grpc = require('bindings')('grpc.node'); var Server = require('../src/server'); var client = require('../src/client'); var common = require('../src/common'); var ca_path = path.join(__dirname, 'data/ca.pem'); var key_path = path.join(__dirname, 'data/server1.key'); var pem_path = path.join(__dirname, 'data/server1.pem'); /** * Helper function to return an absolute deadline given a relative timeout in * seconds. * @param {number} timeout_secs The number of seconds to wait before timing out * @return {Date} A date timeout_secs in the future */ function getDeadline(timeout_secs) { var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + timeout_secs); return deadline; } /** * Responds to every request with the same data as a response * @param {Stream} stream */ function echoHandler(stream) { stream.pipe(stream); } /** * Responds to every request with an error status * @param {Stream} stream */ function errorHandler(stream) { throw { 'code' : grpc.status.UNIMPLEMENTED, 'details' : 'error details' }; } /** * Wait for a cancellation instead of responding * @param {Stream} stream */ function cancelHandler(stream) { // do nothing } function metadataHandler(stream, metadata) { stream.end(); } /** * Serialize a string to a Buffer * @param {string} value The string to serialize * @return {Buffer} The serialized value */ function stringSerialize(value) { return new Buffer(value); } /** * Deserialize a Buffer to a string * @param {Buffer} buffer The buffer to deserialize * @return {string} The string value of the buffer */ function stringDeserialize(buffer) { return buffer.toString(); } describe('echo client', function() { var server; var channel; before(function() { server = new Server(function getMetadata(method, metadata) { return {method: [method]}; }); var port_num = server.bind('0.0.0.0:0'); server.register('echo', echoHandler); server.register('error', errorHandler); server.register('cancellation', cancelHandler); server.register('metadata', metadataHandler); server.start(); channel = new grpc.Channel('localhost:' + port_num); }); after(function() { server.shutdown(); }); it('should receive echo responses', function(done) { var messages = ['echo1', 'echo2', 'echo3', 'echo4']; var stream = client.makeRequest( channel, 'echo', stringSerialize, stringDeserialize); for (var i = 0; i < messages.length; i++) { stream.write(messages[i]); } stream.end(); var index = 0; stream.on('data', function(chunk) { assert.equal(messages[index], chunk); index += 1; }); stream.on('status', function(status) { assert.equal(status.code, client.status.OK); }); stream.on('end', function() { assert.equal(index, messages.length); done(); }); }); it('should recieve metadata set by the server', function(done) { var stream = client.makeRequest(channel, 'metadata'); stream.on('metadata', function(metadata) { assert.strictEqual(metadata.method[0].toString(), 'metadata'); }); stream.on('status', function(status) { assert.equal(status.code, client.status.OK); done(); }); stream.end(); }); it('should get an error status that the server throws', function(done) { var stream = client.makeRequest(channel, 'error'); stream.on('data', function() {}); stream.write(new Buffer('test')); stream.end(); stream.on('status', function(status) { assert.equal(status.code, grpc.status.UNIMPLEMENTED); assert.equal(status.details, 'error details'); done(); }); }); it('should be able to cancel a call', function(done) { var stream = client.makeRequest( channel, 'cancellation', null, getDeadline(1)); stream.cancel(); stream.on('status', function(status) { assert.equal(status.code, grpc.status.CANCELLED); done(); }); }); it('should get correct status for unimplemented method', function(done) { var stream = client.makeRequest(channel, 'unimplemented_method'); stream.end(); stream.on('status', function(status) { assert.equal(status.code, grpc.status.UNIMPLEMENTED); done(); }); }); }); /* TODO(mlumish): explore options for reducing duplication between this test * and the insecure echo client test */ describe('secure echo client', function() { var server; var channel; before(function(done) { fs.readFile(ca_path, function(err, ca_data) { assert.ifError(err); fs.readFile(key_path, function(err, key_data) { assert.ifError(err); fs.readFile(pem_path, function(err, pem_data) { assert.ifError(err); var creds = grpc.Credentials.createSsl(ca_data); var server_creds = grpc.ServerCredentials.createSsl(null, key_data, pem_data); server = new Server(null, {'credentials' : server_creds}); var port_num = server.bind('0.0.0.0:0', true); server.register('echo', echoHandler); server.start(); channel = new grpc.Channel('localhost:' + port_num, { 'grpc.ssl_target_name_override' : 'foo.test.google.com', 'credentials' : creds }); done(); }); }); }); }); after(function() { server.shutdown(); }); it('should recieve echo responses', function(done) { var messages = ['echo1', 'echo2', 'echo3', 'echo4']; var stream = client.makeRequest( channel, 'echo', stringSerialize, stringDeserialize); for (var i = 0; i < messages.length; i++) { stream.write(messages[i]); } stream.end(); var index = 0; stream.on('data', function(chunk) { assert.equal(messages[index], chunk); index += 1; }); stream.on('status', function(status) { assert.equal(status.code, client.status.OK); }); stream.on('end', function() { assert.equal(index, messages.length); done(); }); }); });