mirror of https://github.com/grpc/grpc-node.git
1533 lines
49 KiB
JavaScript
1533 lines
49 KiB
JavaScript
/*
|
|
*
|
|
* Copyright 2015 gRPC authors.
|
|
*
|
|
* Licensed 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.
|
|
*
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var assert = require('assert');
|
|
var _ = require('lodash');
|
|
|
|
var grpc = require('..');
|
|
|
|
var MathClient = grpc.load(
|
|
__dirname + '/../deps/grpc/src/proto/math/math.proto').math.Math;
|
|
var mathServiceAttrs = MathClient.service;
|
|
|
|
/**
|
|
* This is used for testing functions with multiple asynchronous calls that
|
|
* can happen in different orders. This should be passed the number of async
|
|
* function invocations that can occur last, and each of those should call this
|
|
* function's return value
|
|
* @param {function()} done The function that should be called when a test is
|
|
* complete.
|
|
* @param {number} count The number of calls to the resulting function if the
|
|
* test passes.
|
|
* @return {function()} The function that should be called at the end of each
|
|
* sequence of asynchronous functions.
|
|
*/
|
|
function multiDone(done, count) {
|
|
return function() {
|
|
count -= 1;
|
|
if (count <= 0) {
|
|
done();
|
|
}
|
|
};
|
|
}
|
|
|
|
var server_insecure_creds = grpc.ServerCredentials.createInsecure();
|
|
|
|
describe('File loader', function() {
|
|
it('Should load a proto file by default', function() {
|
|
assert.doesNotThrow(function() {
|
|
grpc.load(__dirname + '/test_service.proto');
|
|
});
|
|
});
|
|
it('Should load a proto file with the proto format', function() {
|
|
assert.doesNotThrow(function() {
|
|
grpc.load(__dirname + '/test_service.proto', 'proto');
|
|
});
|
|
});
|
|
it('Should load a json file with the json format', function() {
|
|
assert.doesNotThrow(function() {
|
|
grpc.load(__dirname + '/test_service.json', 'json');
|
|
});
|
|
});
|
|
});
|
|
describe('surface Server', function() {
|
|
var server;
|
|
beforeEach(function() {
|
|
server = new grpc.Server();
|
|
});
|
|
afterEach(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('should error if started twice', function() {
|
|
server.start();
|
|
assert.throws(function() {
|
|
server.start();
|
|
});
|
|
});
|
|
it('should error if a port is bound after the server starts', function() {
|
|
server.start();
|
|
assert.throws(function() {
|
|
server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
|
|
});
|
|
});
|
|
it('should successfully shutdown if tryShutdown is called', function(done) {
|
|
server.start();
|
|
server.tryShutdown(done);
|
|
});
|
|
});
|
|
describe('Server.prototype.addService', function() {
|
|
var server;
|
|
var dummyImpls = {
|
|
'div': function() {},
|
|
'divMany': function() {},
|
|
'fib': function() {},
|
|
'sum': function() {}
|
|
};
|
|
beforeEach(function() {
|
|
server = new grpc.Server();
|
|
});
|
|
afterEach(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('Should succeed with a single service', function() {
|
|
assert.doesNotThrow(function() {
|
|
server.addService(mathServiceAttrs, dummyImpls);
|
|
});
|
|
});
|
|
it('Should fail with conflicting method names', function() {
|
|
server.addService(mathServiceAttrs, dummyImpls);
|
|
assert.throws(function() {
|
|
server.addService(mathServiceAttrs, dummyImpls);
|
|
});
|
|
});
|
|
it('Should allow method names as originally written', function() {
|
|
var altDummyImpls = {
|
|
'Div': function() {},
|
|
'DivMany': function() {},
|
|
'Fib': function() {},
|
|
'Sum': function() {}
|
|
};
|
|
assert.doesNotThrow(function() {
|
|
server.addService(mathServiceAttrs, altDummyImpls);
|
|
});
|
|
});
|
|
it('Should have a conflict between name variations', function() {
|
|
/* This is really testing that both name variations are actually used,
|
|
by checking that the method actually gets registered, for the
|
|
corresponding function, in both cases */
|
|
var altDummyImpls = {
|
|
'Div': function() {},
|
|
'DivMany': function() {},
|
|
'Fib': function() {},
|
|
'Sum': function() {}
|
|
};
|
|
server.addProtoService(mathServiceAttrs, altDummyImpls);
|
|
assert.throws(function() {
|
|
server.addProtoService(mathServiceAttrs, dummyImpls);
|
|
});
|
|
});
|
|
it('Should fail if the server has been started', function() {
|
|
server.start();
|
|
assert.throws(function() {
|
|
server.addService(mathServiceAttrs, dummyImpls);
|
|
});
|
|
});
|
|
describe('Default handlers', function() {
|
|
var client;
|
|
beforeEach(function() {
|
|
server.addService(mathServiceAttrs, {});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new MathClient('localhost:' + port,
|
|
grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
it('should respond to a unary call with UNIMPLEMENTED', function(done) {
|
|
client.div({divisor: 4, dividend: 3}, function(error, response) {
|
|
assert(error);
|
|
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
|
|
done();
|
|
});
|
|
});
|
|
it('should respond to a client stream with UNIMPLEMENTED', function(done) {
|
|
var call = client.sum(function(error, respones) {
|
|
assert(error);
|
|
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
it('should respond to a server stream with UNIMPLEMENTED', function(done) {
|
|
var call = client.fib({limit: 5});
|
|
call.on('data', function(value) {
|
|
assert.fail('No messages expected');
|
|
});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
|
|
done();
|
|
});
|
|
call.on('error', function(status) { /* Do nothing */ });
|
|
});
|
|
it('should respond to a bidi call with UNIMPLEMENTED', function(done) {
|
|
var call = client.divMany();
|
|
call.on('data', function(value) {
|
|
assert.fail('No messages expected');
|
|
});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
|
|
done();
|
|
});
|
|
call.on('error', function(status) { /* Do nothing */ });
|
|
call.end();
|
|
});
|
|
});
|
|
});
|
|
describe('Client constructor building', function() {
|
|
var illegal_service_attrs = {
|
|
$method : {
|
|
path: '/illegal/$method',
|
|
requestStream: false,
|
|
responseStream: false,
|
|
requestSerialize: x => x,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: x => x,
|
|
responseDeserialize: x => x
|
|
}
|
|
};
|
|
it('Should reject method names starting with $', function() {
|
|
assert.throws(function() {
|
|
grpc.makeGenericClientConstructor(illegal_service_attrs);
|
|
}, /\$/);
|
|
});
|
|
it('Should add aliases for original names', function() {
|
|
var Client = grpc.makeGenericClientConstructor(mathServiceAttrs);
|
|
assert.strictEqual(Client.prototype.add, Client.prototype.Add);
|
|
});
|
|
});
|
|
describe('Generic client', function() {
|
|
it('Should construct without error', function() {
|
|
assert.doesNotThrow(() => {
|
|
const client = new grpc.Client('localhost: 50051', grpc.credentials.createInsecure());
|
|
});
|
|
});
|
|
});
|
|
describe('waitForClientReady', function() {
|
|
var server;
|
|
var port;
|
|
var Client = MathClient;
|
|
var client;
|
|
before(function() {
|
|
server = new grpc.Server();
|
|
port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
|
|
server.start();
|
|
});
|
|
beforeEach(function() {
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('should complete when called alone', function(done) {
|
|
grpc.waitForClientReady(client, Infinity, function(error) {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
});
|
|
it('should complete when a call is initiated', function(done) {
|
|
grpc.waitForClientReady(client, Infinity, function(error) {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
var call = client.div({}, function(err, response) {});
|
|
call.cancel();
|
|
});
|
|
it('should complete if called more than once', function(done) {
|
|
done = multiDone(done, 2);
|
|
grpc.waitForClientReady(client, Infinity, function(error) {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
grpc.waitForClientReady(client, Infinity, function(error) {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
});
|
|
it('should complete if called when already ready', function(done) {
|
|
grpc.waitForClientReady(client, Infinity, function(error) {
|
|
assert.ifError(error);
|
|
grpc.waitForClientReady(client, Infinity, function(error) {
|
|
assert.ifError(error);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
it('should time out if the server does not exist', function(done) {
|
|
var bad_client = new Client('nonexistent_hostname',
|
|
grpc.credentials.createInsecure());
|
|
var deadline = new Date();
|
|
deadline.setSeconds(deadline.getSeconds() + 1);
|
|
grpc.waitForClientReady(bad_client, deadline, function(error) {
|
|
assert(error);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('Echo service', function() {
|
|
var server;
|
|
var client;
|
|
before(function() {
|
|
var Client = grpc.load(__dirname + '/echo_service.proto').EchoService;
|
|
server = new grpc.Server();
|
|
server.addService(Client.service, {
|
|
echo: function(call, callback) {
|
|
callback(null, call.request);
|
|
}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('should echo the recieved message directly', function(done) {
|
|
client.echo({value: 'test value', value2: 3}, function(error, response) {
|
|
assert.ifError(error);
|
|
assert.deepEqual(response, {value: 'test value', value2: 3});
|
|
done();
|
|
});
|
|
});
|
|
it('Should convert an undefined argument to default values', function(done) {
|
|
client.echo(undefined, function(error, response) {
|
|
assert.ifError(error);
|
|
assert.deepEqual(response, {value: '', value2: 0});
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('Non-protobuf client and server', function() {
|
|
function toString(val) {
|
|
return val.toString();
|
|
}
|
|
function toBuffer(str) {
|
|
return Buffer.from(str);
|
|
}
|
|
var string_service_attrs = {
|
|
'capitalize' : {
|
|
path: '/string/capitalize',
|
|
requestStream: false,
|
|
responseStream: false,
|
|
requestSerialize: toBuffer,
|
|
requestDeserialize: toString,
|
|
responseSerialize: toBuffer,
|
|
responseDeserialize: toString
|
|
}
|
|
};
|
|
describe('String client and server', function() {
|
|
var client;
|
|
var server;
|
|
before(function() {
|
|
server = new grpc.Server();
|
|
server.addService(string_service_attrs, {
|
|
capitalize: function(call, callback) {
|
|
callback(null, _.capitalize(call.request));
|
|
}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
server.start();
|
|
var Client = grpc.makeGenericClientConstructor(string_service_attrs);
|
|
client = new Client('localhost:' + port,
|
|
grpc.credentials.createInsecure());
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('Should respond with a capitalized string', function(done) {
|
|
client.capitalize('abc', function(err, response) {
|
|
assert.ifError(err);
|
|
assert.strictEqual(response, 'Abc');
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
describe('Server-side getPeer', function() {
|
|
function toString(val) {
|
|
return val.toString();
|
|
}
|
|
function toBuffer(str) {
|
|
return Buffer.from(str);
|
|
}
|
|
var string_service_attrs = {
|
|
'getPeer' : {
|
|
path: '/string/getPeer',
|
|
requestStream: false,
|
|
responseStream: false,
|
|
requestSerialize: toBuffer,
|
|
requestDeserialize: toString,
|
|
responseSerialize: toBuffer,
|
|
responseDeserialize: toString
|
|
}
|
|
};
|
|
var client;
|
|
var server;
|
|
before(function() {
|
|
server = new grpc.Server();
|
|
server.addService(string_service_attrs, {
|
|
getPeer: function(call, callback) {
|
|
try {
|
|
callback(null, call.getPeer());
|
|
} catch (e) {
|
|
call.emit('error', e);
|
|
}
|
|
}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
server.start();
|
|
var Client = grpc.makeGenericClientConstructor(string_service_attrs);
|
|
client = new Client('localhost:' + port,
|
|
grpc.credentials.createInsecure());
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('should respond with a string representing the client', function(done) {
|
|
client.getPeer('', function(err, response) {
|
|
assert.ifError(err);
|
|
// We don't expect a specific value, just that it worked without error
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('Echo metadata', function() {
|
|
var client;
|
|
var server;
|
|
var metadata;
|
|
before(function() {
|
|
var Client = grpc.load(__dirname + '/test_service.proto').TestService;
|
|
server = new grpc.Server();
|
|
server.addService(Client.service, {
|
|
unary: function(call, cb) {
|
|
call.sendMetadata(call.metadata);
|
|
cb(null, {});
|
|
},
|
|
clientStream: function(stream, cb){
|
|
stream.on('data', function(data) {});
|
|
stream.on('end', function() {
|
|
stream.sendMetadata(stream.metadata);
|
|
cb(null, {});
|
|
});
|
|
},
|
|
serverStream: function(stream) {
|
|
stream.sendMetadata(stream.metadata);
|
|
stream.end();
|
|
},
|
|
bidiStream: function(stream) {
|
|
stream.on('data', function(data) {});
|
|
stream.on('end', function() {
|
|
stream.sendMetadata(stream.metadata);
|
|
stream.end();
|
|
});
|
|
}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
metadata = new grpc.Metadata();
|
|
metadata.set('key', 'value');
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('with unary call', function(done) {
|
|
var call = client.unary({}, metadata, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
});
|
|
it('with client stream call', function(done) {
|
|
var call = client.clientStream(metadata, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
it('with server stream call', function(done) {
|
|
var call = client.serverStream({}, metadata);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
});
|
|
it('with bidi stream call', function(done) {
|
|
var call = client.bidiStream(metadata);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
it('shows the correct user-agent string', function(done) {
|
|
var version = require('../package.json').version;
|
|
var call = client.unary({}, metadata,
|
|
function(err, data) { assert.ifError(err); });
|
|
call.on('metadata', function(metadata) {
|
|
assert.strictEqual(0,
|
|
metadata.get('user-agent')[0].indexOf('grpc-node/' + version));
|
|
done();
|
|
});
|
|
});
|
|
it('properly handles duplicate values', function(done) {
|
|
var dup_metadata = metadata.clone();
|
|
dup_metadata.add('key', 'value2');
|
|
var call = client.unary({}, dup_metadata,
|
|
function(err, data) {assert.ifError(err); });
|
|
call.on('metadata', function(resp_metadata) {
|
|
// Two arrays are equal iff their symmetric difference is empty
|
|
assert.deepEqual(_.xor(dup_metadata.get('key'), resp_metadata.get('key')),
|
|
[]);
|
|
done();
|
|
});
|
|
});
|
|
describe('Call argument handling', function() {
|
|
describe('Unary call', function() {
|
|
it('Should handle undefined options', function(done) {
|
|
var call = client.unary({}, metadata, undefined, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
});
|
|
it('Should handle two undefined arguments', function(done) {
|
|
var call = client.unary({}, undefined, undefined, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
});
|
|
it('Should handle one undefined argument', function(done) {
|
|
var call = client.unary({}, undefined, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('Client stream call', function() {
|
|
it('Should handle undefined options', function(done) {
|
|
var call = client.clientStream(metadata, undefined, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
it('Should handle two undefined arguments', function(done) {
|
|
var call = client.clientStream(undefined, undefined, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
it('Should handle one undefined argument', function(done) {
|
|
var call = client.clientStream(undefined, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
});
|
|
describe('Server stream call', function() {
|
|
it('Should handle undefined options', function(done) {
|
|
var call = client.serverStream({}, metadata, undefined);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
});
|
|
it('Should handle two undefined arguments', function(done) {
|
|
var call = client.serverStream({}, undefined, undefined);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
});
|
|
it('Should handle one undefined argument', function(done) {
|
|
var call = client.serverStream({}, undefined);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('Bidi stream call', function() {
|
|
it('Should handle undefined options', function(done) {
|
|
var call = client.bidiStream(metadata, undefined);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
assert.deepEqual(metadata.get('key'), ['value']);
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
it('Should handle two undefined arguments', function(done) {
|
|
var call = client.bidiStream(undefined, undefined);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
it('Should handle one undefined argument', function(done) {
|
|
var call = client.bidiStream(undefined);
|
|
call.on('data', function() {});
|
|
call.on('metadata', function(metadata) {
|
|
done();
|
|
});
|
|
call.end();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
describe('Client malformed response handling', function() {
|
|
var server;
|
|
var client;
|
|
var badArg = Buffer.from([0xFF]);
|
|
before(function() {
|
|
var Client = grpc.load(__dirname + '/test_service.proto').TestService;
|
|
var malformed_test_service = {
|
|
unary: {
|
|
path: '/TestService/Unary',
|
|
requestStream: false,
|
|
responseStream: false,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: x => x
|
|
},
|
|
clientStream: {
|
|
path: '/TestService/ClientStream',
|
|
requestStream: true,
|
|
responseStream: false,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: x => x
|
|
},
|
|
serverStream: {
|
|
path: '/TestService/ServerStream',
|
|
requestStream: false,
|
|
responseStream: true,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: x => x
|
|
},
|
|
bidiStream: {
|
|
path: '/TestService/BidiStream',
|
|
requestStream: true,
|
|
responseStream: true,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: x => x
|
|
}
|
|
};
|
|
server = new grpc.Server();
|
|
server.addService(malformed_test_service, {
|
|
unary: function(call, cb) {
|
|
cb(null, badArg);
|
|
},
|
|
clientStream: function(stream, cb) {
|
|
stream.on('data', function() {/* Ignore requests */});
|
|
stream.on('end', function() {
|
|
cb(null, badArg);
|
|
});
|
|
},
|
|
serverStream: function(stream) {
|
|
stream.write(badArg);
|
|
},
|
|
bidiStream: function(stream) {
|
|
stream.on('data', function() {
|
|
// Ignore requests
|
|
stream.write(badArg);
|
|
});
|
|
}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('should get an INTERNAL status with a unary call', function(done) {
|
|
client.unary({}, function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
});
|
|
it('should get an INTERNAL status with a client stream call', function(done) {
|
|
var call = client.clientStream(function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
call.write({});
|
|
call.end();
|
|
});
|
|
it('should get an INTERNAL status with a server stream call', function(done) {
|
|
var call = client.serverStream({});
|
|
call.on('data', function(){});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
});
|
|
it('should get an INTERNAL status with a bidi stream call', function(done) {
|
|
var call = client.bidiStream();
|
|
call.on('data', function(){});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
call.write({});
|
|
call.end();
|
|
});
|
|
});
|
|
describe('Server serialization failure handling', function() {
|
|
function serializeFail(obj) {
|
|
throw new Error('Serialization failed');
|
|
}
|
|
var client;
|
|
var server;
|
|
before(function() {
|
|
var Client = grpc.load(__dirname + '/test_service.proto').TestService;
|
|
var malformed_test_service = {
|
|
unary: {
|
|
path: '/TestService/Unary',
|
|
requestStream: false,
|
|
responseStream: false,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: serializeFail
|
|
},
|
|
clientStream: {
|
|
path: '/TestService/ClientStream',
|
|
requestStream: true,
|
|
responseStream: false,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: serializeFail
|
|
},
|
|
serverStream: {
|
|
path: '/TestService/ServerStream',
|
|
requestStream: false,
|
|
responseStream: true,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: serializeFail
|
|
},
|
|
bidiStream: {
|
|
path: '/TestService/BidiStream',
|
|
requestStream: true,
|
|
responseStream: true,
|
|
requestDeserialize: x => x,
|
|
responseSerialize: serializeFail
|
|
}
|
|
};
|
|
server = new grpc.Server();
|
|
server.addService(malformed_test_service, {
|
|
unary: function(call, cb) {
|
|
cb(null, {});
|
|
},
|
|
clientStream: function(stream, cb) {
|
|
stream.on('data', function() {/* Ignore requests */});
|
|
stream.on('end', function() {
|
|
cb(null, {});
|
|
});
|
|
},
|
|
serverStream: function(stream) {
|
|
stream.write({});
|
|
stream.end();
|
|
},
|
|
bidiStream: function(stream) {
|
|
stream.on('data', function() {
|
|
// Ignore requests
|
|
stream.write({});
|
|
});
|
|
stream.on('end', function() {
|
|
stream.end();
|
|
});
|
|
}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('should get an INTERNAL status with a unary call', function(done) {
|
|
client.unary({}, function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
});
|
|
it('should get an INTERNAL status with a client stream call', function(done) {
|
|
var call = client.clientStream(function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
call.write({});
|
|
call.end();
|
|
});
|
|
it('should get an INTERNAL status with a server stream call', function(done) {
|
|
var call = client.serverStream({});
|
|
call.on('data', function(){});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
});
|
|
it('should get an INTERNAL status with a bidi stream call', function(done) {
|
|
var call = client.bidiStream();
|
|
call.on('data', function(){});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
call.write({});
|
|
call.end();
|
|
});
|
|
});
|
|
describe('Other conditions', function() {
|
|
var Client;
|
|
var client;
|
|
var server;
|
|
var port;
|
|
before(function() {
|
|
Client = grpc.load(__dirname + '/test_service.proto').TestService;
|
|
server = new grpc.Server();
|
|
var trailer_metadata = new grpc.Metadata();
|
|
trailer_metadata.add('trailer-present', 'yes');
|
|
server.addService(Client.service, {
|
|
unary: function(call, cb) {
|
|
var req = call.request;
|
|
if (req.error) {
|
|
var message = 'Requested error';
|
|
if (req.message) {
|
|
message = req.message;
|
|
}
|
|
cb({code: grpc.status.UNKNOWN,
|
|
details: message}, null, trailer_metadata);
|
|
} else {
|
|
cb(null, {count: 1}, trailer_metadata);
|
|
}
|
|
},
|
|
clientStream: function(stream, cb){
|
|
var count = 0;
|
|
var errored;
|
|
stream.on('data', function(data) {
|
|
if (data.error) {
|
|
var message = 'Requested error';
|
|
if (data.message) {
|
|
message = data.message;
|
|
}
|
|
errored = true;
|
|
cb(new Error(message), null, trailer_metadata);
|
|
} else {
|
|
count += 1;
|
|
}
|
|
});
|
|
stream.on('end', function() {
|
|
if (!errored) {
|
|
cb(null, {count: count}, trailer_metadata);
|
|
}
|
|
});
|
|
},
|
|
serverStream: function(stream) {
|
|
var req = stream.request;
|
|
if (req.error) {
|
|
var message = 'Requested error';
|
|
if (req.message) {
|
|
message = req.message;
|
|
}
|
|
var err = {code: grpc.status.UNKNOWN,
|
|
details: message};
|
|
err.metadata = trailer_metadata;
|
|
stream.emit('error', err);
|
|
} else {
|
|
for (var i = 0; i < 5; i++) {
|
|
stream.write({count: i});
|
|
}
|
|
stream.end(trailer_metadata);
|
|
}
|
|
},
|
|
bidiStream: function(stream) {
|
|
var count = 0;
|
|
stream.on('data', function(data) {
|
|
if (data.error) {
|
|
var message = 'Requested error';
|
|
if (data.message) {
|
|
message = data.message;
|
|
}
|
|
var err = new Error(message);
|
|
err.metadata = trailer_metadata.clone();
|
|
err.metadata.add('count', '' + count);
|
|
stream.emit('error', err);
|
|
} else {
|
|
stream.write({count: count});
|
|
count += 1;
|
|
}
|
|
});
|
|
stream.on('end', function() {
|
|
stream.end(trailer_metadata);
|
|
});
|
|
}
|
|
});
|
|
port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('channel.getTarget should be available', function() {
|
|
assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(),
|
|
'string');
|
|
});
|
|
it('client should be able to pause and resume a stream', function(done) {
|
|
var call = client.bidiStream();
|
|
call.on('data', function(data) {
|
|
assert(data.count < 3);
|
|
call.pause();
|
|
setTimeout(function() {
|
|
call.resume();
|
|
}, 10);
|
|
});
|
|
call.on('end', function() {
|
|
done();
|
|
});
|
|
call.write({});
|
|
call.write({});
|
|
call.write({});
|
|
call.end();
|
|
});
|
|
it('client should wait for a connection with waitForReady on', function(done) {
|
|
/* We have to wait for the client to reach the first connection timeout
|
|
* and go to TRANSIENT_FAILURE to confirm that the waitForReady option
|
|
* makes it end the call instead of continuing to try. A DNS resolution
|
|
* failure makes that transition very fast. */
|
|
this.timeout(15000);
|
|
const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure());
|
|
const metadata = new grpc.Metadata({waitForReady: true});
|
|
const deadline = new Date();
|
|
deadline.setSeconds(deadline.getSeconds() + 10);
|
|
disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{
|
|
assert(error);
|
|
assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED);
|
|
done();
|
|
});
|
|
});
|
|
describe('Server recieving bad input', function() {
|
|
var misbehavingClient;
|
|
var badArg = Buffer.from([0xFF]);
|
|
before(function() {
|
|
var test_service_attrs = {
|
|
unary: {
|
|
path: '/TestService/Unary',
|
|
requestStream: false,
|
|
responseStream: false,
|
|
requestSerialize: x => x,
|
|
responseDeserialize: x => x
|
|
},
|
|
clientStream: {
|
|
path: '/TestService/ClientStream',
|
|
requestStream: true,
|
|
responseStream: false,
|
|
requestSerialize: x => x,
|
|
responseDeserialize: x => x
|
|
},
|
|
serverStream: {
|
|
path: '/TestService/ServerStream',
|
|
requestStream: false,
|
|
responseStream: true,
|
|
requestSerialize: x => x,
|
|
responseDeserialize: x => x
|
|
},
|
|
bidiStream: {
|
|
path: '/TestService/BidiStream',
|
|
requestStream: true,
|
|
responseStream: true,
|
|
requestSerialize: x => x,
|
|
responseDeserialize: x => x
|
|
}
|
|
};
|
|
var Client = grpc.makeGenericClientConstructor(test_service_attrs,
|
|
'TestService');
|
|
misbehavingClient = new Client('localhost:' + port,
|
|
grpc.credentials.createInsecure());
|
|
});
|
|
it('should respond correctly to a unary call', function(done) {
|
|
misbehavingClient.unary(badArg, function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
});
|
|
it('should respond correctly to a client stream', function(done) {
|
|
var call = misbehavingClient.clientStream(function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
call.write(badArg);
|
|
// TODO(mlumish): Remove call.end()
|
|
call.end();
|
|
});
|
|
it('should respond correctly to a server stream', function(done) {
|
|
var call = misbehavingClient.serverStream(badArg);
|
|
call.on('data', function(data) {
|
|
assert.fail(data, null, 'Unexpected data', '===');
|
|
});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
});
|
|
it('should respond correctly to a bidi stream', function(done) {
|
|
var call = misbehavingClient.bidiStream();
|
|
call.on('data', function(data) {
|
|
assert.fail(data, null, 'Unexpected data', '===');
|
|
});
|
|
call.on('error', function(err) {
|
|
assert.strictEqual(err.code, grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
call.write(badArg);
|
|
// TODO(mlumish): Remove call.end()
|
|
call.end();
|
|
});
|
|
});
|
|
describe('Trailing metadata', function() {
|
|
it('should be present when a unary call succeeds', function(done) {
|
|
var call = client.unary({error: false}, function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.on('status', function(status) {
|
|
assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
it('should be present when a unary call fails', function(done) {
|
|
var call = client.unary({error: true}, function(err, data) {
|
|
assert(err);
|
|
});
|
|
call.on('status', function(status) {
|
|
assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
it('should be present when a client stream call succeeds', function(done) {
|
|
var call = client.clientStream(function(err, data) {
|
|
assert.ifError(err);
|
|
});
|
|
call.write({error: false});
|
|
call.write({error: false});
|
|
call.end();
|
|
call.on('status', function(status) {
|
|
assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
it('should be present when a client stream call fails', function(done) {
|
|
var call = client.clientStream(function(err, data) {
|
|
assert(err);
|
|
});
|
|
call.write({error: false});
|
|
call.write({error: true});
|
|
call.end();
|
|
call.on('status', function(status) {
|
|
assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
it('should be present when a server stream call succeeds', function(done) {
|
|
var call = client.serverStream({error: false});
|
|
call.on('data', function(){});
|
|
call.on('status', function(status) {
|
|
assert.strictEqual(status.code, grpc.status.OK);
|
|
assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
it('should be present when a server stream call fails', function(done) {
|
|
var call = client.serverStream({error: true});
|
|
call.on('data', function(){});
|
|
call.on('error', function(error) {
|
|
assert.deepEqual(error.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
it('should be present when a bidi stream succeeds', function(done) {
|
|
var call = client.bidiStream();
|
|
call.write({error: false});
|
|
call.write({error: false});
|
|
call.end();
|
|
call.on('data', function(){});
|
|
call.on('status', function(status) {
|
|
assert.strictEqual(status.code, grpc.status.OK);
|
|
assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
it('should be present when a bidi stream fails', function(done) {
|
|
var call = client.bidiStream();
|
|
call.write({error: false});
|
|
call.write({error: true});
|
|
call.end();
|
|
call.on('data', function(){});
|
|
call.on('error', function(error) {
|
|
assert.deepEqual(error.metadata.get('trailer-present'), ['yes']);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('Error object should contain the status', function() {
|
|
it('for a unary call', function(done) {
|
|
client.unary({error: true}, function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.UNKNOWN);
|
|
assert.strictEqual(err.details, 'Requested error');
|
|
done();
|
|
});
|
|
});
|
|
it('for a client stream call', function(done) {
|
|
var call = client.clientStream(function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.UNKNOWN);
|
|
assert.strictEqual(err.details, 'Requested error');
|
|
done();
|
|
});
|
|
call.write({error: false});
|
|
call.write({error: true});
|
|
call.end();
|
|
});
|
|
it('for a server stream call', function(done) {
|
|
var call = client.serverStream({error: true});
|
|
call.on('data', function(){});
|
|
call.on('error', function(error) {
|
|
assert.strictEqual(error.code, grpc.status.UNKNOWN);
|
|
assert.strictEqual(error.details, 'Requested error');
|
|
done();
|
|
});
|
|
});
|
|
it('for a bidi stream call', function(done) {
|
|
var call = client.bidiStream();
|
|
call.write({error: false});
|
|
call.write({error: true});
|
|
call.end();
|
|
call.on('data', function(){});
|
|
call.on('error', function(error) {
|
|
assert.strictEqual(error.code, grpc.status.UNKNOWN);
|
|
assert.strictEqual(error.details, 'Requested error');
|
|
done();
|
|
});
|
|
});
|
|
it('for a UTF-8 error message', function(done) {
|
|
client.unary({error: true, message: '測試字符串'}, function(err, data) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.UNKNOWN);
|
|
assert.strictEqual(err.details, '測試字符串');
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('call.getPeer should return the peer', function() {
|
|
it('for a unary call', function(done) {
|
|
var call = client.unary({error: false}, function(err, data) {
|
|
assert.ifError(err);
|
|
done();
|
|
});
|
|
assert.strictEqual(typeof call.getPeer(), 'string');
|
|
});
|
|
it('for a client stream call', function(done) {
|
|
var call = client.clientStream(function(err, data) {
|
|
assert.ifError(err);
|
|
done();
|
|
});
|
|
assert.strictEqual(typeof call.getPeer(), 'string');
|
|
call.write({error: false});
|
|
call.end();
|
|
});
|
|
it('for a server stream call', function(done) {
|
|
var call = client.serverStream({error: false});
|
|
assert.strictEqual(typeof call.getPeer(), 'string');
|
|
call.on('data', function(){});
|
|
call.on('status', function(status) {
|
|
assert.strictEqual(status.code, grpc.status.OK);
|
|
done();
|
|
});
|
|
});
|
|
it('for a bidi stream call', function(done) {
|
|
var call = client.bidiStream();
|
|
assert.strictEqual(typeof call.getPeer(), 'string');
|
|
call.write({error: false});
|
|
call.end();
|
|
call.on('data', function(){});
|
|
call.on('status', function(status) {
|
|
done();
|
|
});
|
|
});
|
|
it('after the call has fully completed', function(done) {
|
|
var peer;
|
|
var call = client.unary({error: false}, function(err, data) {
|
|
assert.ifError(err);
|
|
setImmediate(function() {
|
|
assert.strictEqual(peer, call.getPeer());
|
|
done();
|
|
});
|
|
});
|
|
peer = call.getPeer();
|
|
assert.strictEqual(typeof peer, 'string');
|
|
});
|
|
});
|
|
});
|
|
describe('Call propagation', function() {
|
|
var proxy;
|
|
var proxy_impl;
|
|
|
|
var Client;
|
|
var client;
|
|
var server;
|
|
before(function() {
|
|
Client = grpc.load(__dirname + '/test_service.proto').TestService;
|
|
server = new grpc.Server();
|
|
server.addService(Client.service, {
|
|
unary: function(call) {},
|
|
clientStream: function(stream) {},
|
|
serverStream: function(stream) {},
|
|
bidiStream: function(stream) {}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
beforeEach(function() {
|
|
proxy = new grpc.Server();
|
|
proxy_impl = {
|
|
unary: function(call) {},
|
|
clientStream: function(stream) {},
|
|
serverStream: function(stream) {},
|
|
bidiStream: function(stream) {}
|
|
};
|
|
});
|
|
afterEach(function() {
|
|
proxy.forceShutdown();
|
|
});
|
|
describe('Cancellation', function() {
|
|
it('With a unary call', function(done) {
|
|
done = multiDone(done, 2);
|
|
var call;
|
|
proxy_impl.unary = function(parent, callback) {
|
|
client.unary(parent.request, {parent: parent}, function(err, value) {
|
|
try {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.CANCELLED);
|
|
} finally {
|
|
callback(err, value);
|
|
done();
|
|
}
|
|
});
|
|
call.cancel();
|
|
};
|
|
proxy.addService(Client.service, proxy_impl);
|
|
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
|
|
proxy.start();
|
|
var proxy_client = new Client('localhost:' + proxy_port,
|
|
grpc.credentials.createInsecure());
|
|
call = proxy_client.unary({}, function(err, value) { done(); });
|
|
});
|
|
it('With a client stream call', function(done) {
|
|
done = multiDone(done, 2);
|
|
var call;
|
|
proxy_impl.clientStream = function(parent, callback) {
|
|
client.clientStream({parent: parent}, function(err, value) {
|
|
try {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.CANCELLED);
|
|
} finally {
|
|
callback(err, value);
|
|
done();
|
|
}
|
|
});
|
|
call.cancel();
|
|
};
|
|
proxy.addService(Client.service, proxy_impl);
|
|
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
|
|
proxy.start();
|
|
var proxy_client = new Client('localhost:' + proxy_port,
|
|
grpc.credentials.createInsecure());
|
|
call = proxy_client.clientStream(function(err, value) { done(); });
|
|
});
|
|
it('With a server stream call', function(done) {
|
|
done = multiDone(done, 2);
|
|
var call;
|
|
proxy_impl.serverStream = function(parent) {
|
|
var child = client.serverStream(parent.request, {parent: parent});
|
|
child.on('data', function() {});
|
|
child.on('error', function(err) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.CANCELLED);
|
|
done();
|
|
});
|
|
call.cancel();
|
|
};
|
|
proxy.addService(Client.service, proxy_impl);
|
|
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
|
|
proxy.start();
|
|
var proxy_client = new Client('localhost:' + proxy_port,
|
|
grpc.credentials.createInsecure());
|
|
call = proxy_client.serverStream({});
|
|
call.on('data', function() {});
|
|
call.on('error', function(err) {
|
|
done();
|
|
});
|
|
});
|
|
it('With a bidi stream call', function(done) {
|
|
done = multiDone(done, 2);
|
|
var call;
|
|
proxy_impl.bidiStream = function(parent) {
|
|
var child = client.bidiStream({parent: parent});
|
|
child.on('data', function() {});
|
|
child.on('error', function(err) {
|
|
assert(err);
|
|
assert.strictEqual(err.code, grpc.status.CANCELLED);
|
|
done();
|
|
});
|
|
call.cancel();
|
|
};
|
|
proxy.addService(Client.service, proxy_impl);
|
|
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
|
|
proxy.start();
|
|
var proxy_client = new Client('localhost:' + proxy_port,
|
|
grpc.credentials.createInsecure());
|
|
call = proxy_client.bidiStream();
|
|
call.on('data', function() {});
|
|
call.on('error', function(err) {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
describe('Deadline', function() {
|
|
/* jshint bitwise:false */
|
|
var deadline_flags = (grpc.propagate.DEFAULTS &
|
|
~grpc.propagate.CANCELLATION);
|
|
it('With a client stream call', function(done) {
|
|
done = multiDone(done, 2);
|
|
proxy_impl.clientStream = function(parent, callback) {
|
|
var options = {parent: parent, propagate_flags: deadline_flags};
|
|
client.clientStream(options, function(err, value) {
|
|
try {
|
|
assert(err);
|
|
assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
|
|
err.code === grpc.status.INTERNAL);
|
|
} finally {
|
|
callback(err, value);
|
|
done();
|
|
}
|
|
});
|
|
};
|
|
proxy.addService(Client.service, proxy_impl);
|
|
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
|
|
proxy.start();
|
|
var proxy_client = new Client('localhost:' + proxy_port,
|
|
grpc.credentials.createInsecure());
|
|
var deadline = new Date();
|
|
deadline.setSeconds(deadline.getSeconds() + 1);
|
|
proxy_client.clientStream({deadline: deadline}, function(err, value) {
|
|
done();
|
|
});
|
|
});
|
|
it('With a bidi stream call', function(done) {
|
|
done = multiDone(done, 2);
|
|
proxy_impl.bidiStream = function(parent) {
|
|
var child = client.bidiStream(
|
|
{parent: parent, propagate_flags: deadline_flags});
|
|
child.on('data', function() {});
|
|
child.on('error', function(err) {
|
|
assert(err);
|
|
assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
|
|
err.code === grpc.status.INTERNAL);
|
|
done();
|
|
});
|
|
};
|
|
proxy.addService(Client.service, proxy_impl);
|
|
var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
|
|
proxy.start();
|
|
var proxy_client = new Client('localhost:' + proxy_port,
|
|
grpc.credentials.createInsecure());
|
|
var deadline = new Date();
|
|
deadline.setSeconds(deadline.getSeconds() + 1);
|
|
var call = proxy_client.bidiStream({deadline: deadline});
|
|
call.on('data', function() {});
|
|
call.on('error', function(err) {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
describe('Cancelling surface client', function() {
|
|
var client;
|
|
var server;
|
|
before(function() {
|
|
server = new grpc.Server();
|
|
server.addService(mathServiceAttrs, {
|
|
'div': function(stream) {},
|
|
'divMany': function(stream) {},
|
|
'fib': function(stream) {},
|
|
'sum': function(stream) {}
|
|
});
|
|
var port = server.bind('localhost:0', server_insecure_creds);
|
|
var Client = grpc.makeGenericClientConstructor(mathServiceAttrs);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
after(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('Should correctly cancel a unary call', function(done) {
|
|
var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) {
|
|
assert.strictEqual(err.code, grpc.status.CANCELLED);
|
|
done();
|
|
});
|
|
call.cancel();
|
|
});
|
|
it('Should correctly cancel a client stream call', function(done) {
|
|
var call = client.sum(function(err, resp) {
|
|
assert.strictEqual(err.code, grpc.status.CANCELLED);
|
|
done();
|
|
});
|
|
call.cancel();
|
|
});
|
|
it('Should correctly cancel a server stream call', function(done) {
|
|
var call = client.fib({'limit': 5});
|
|
call.on('data', function() {});
|
|
call.on('error', function(error) {
|
|
assert.strictEqual(error.code, grpc.status.CANCELLED);
|
|
done();
|
|
});
|
|
call.cancel();
|
|
});
|
|
it('Should correctly cancel a bidi stream call', function(done) {
|
|
var call = client.divMany();
|
|
call.on('data', function() {});
|
|
call.on('error', function(error) {
|
|
assert.strictEqual(error.code, grpc.status.CANCELLED);
|
|
done();
|
|
});
|
|
call.cancel();
|
|
});
|
|
it('Should be idempotent', function(done) {
|
|
var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) {
|
|
assert.strictEqual(err.code, grpc.status.CANCELLED);
|
|
// Call asynchronously to try cancelling after call is fully completed
|
|
setImmediate(function() {
|
|
assert.doesNotThrow(function() {
|
|
call.cancel();
|
|
});
|
|
done();
|
|
});
|
|
});
|
|
call.cancel();
|
|
});
|
|
});
|
|
describe('Client reconnect', function() {
|
|
var server;
|
|
var Client;
|
|
var client;
|
|
var port;
|
|
beforeEach(function() {
|
|
Client = grpc.load(__dirname + '/echo_service.proto').EchoService;
|
|
server = new grpc.Server();
|
|
server.addService(Client.service, {
|
|
echo: function(call, callback) {
|
|
callback(null, call.request);
|
|
}
|
|
});
|
|
port = server.bind('localhost:0', server_insecure_creds);
|
|
client = new Client('localhost:' + port, grpc.credentials.createInsecure());
|
|
server.start();
|
|
});
|
|
afterEach(function() {
|
|
server.forceShutdown();
|
|
});
|
|
it('should reconnect after server restart', function(done) {
|
|
client.echo({value: 'test value', value2: 3}, function(error, response) {
|
|
assert.ifError(error);
|
|
assert.deepEqual(response, {value: 'test value', value2: 3});
|
|
server.tryShutdown(function() {
|
|
server = new grpc.Server();
|
|
server.addService(Client.service, {
|
|
echo: function(call, callback) {
|
|
callback(null, call.request);
|
|
}
|
|
});
|
|
server.bind('localhost:' + port, server_insecure_creds);
|
|
server.start();
|
|
|
|
/* We create a new client, that will not throw an error if the server
|
|
* is not immediately available. Instead, it will wait for the server
|
|
* to be available, then the call will complete. Once this happens, the
|
|
* original client should be able to make a new call and connect to the
|
|
* restarted server without having the call fail due to connection
|
|
* errors. */
|
|
var client2 = new Client('localhost:' + port,
|
|
grpc.credentials.createInsecure());
|
|
client2.echo({value: 'test', value2: 3}, function(error, response) {
|
|
assert.ifError(error);
|
|
client.echo(undefined, function(error, response) {
|
|
if (error) {
|
|
console.log(error);
|
|
}
|
|
assert.ifError(error);
|
|
assert.deepEqual(response, {value: '', value2: 0});
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|