diff --git a/test/any_grpc.js b/test/any_grpc.js index 59962d59..0c86321f 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -41,5 +41,7 @@ const serverImpl = getImplementation('_server_implementation'); module.exports = { client: clientImpl, - server: serverImpl + server: serverImpl, + clientName: global._client_implementation, + serverName: global._server_implementation }; diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index 622c96d7..042c136b 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -58,64 +58,66 @@ const serviceImpl = { } }; -describe('Reconnection', function() { - let server1; - let server2; - let port; - before(function(done) { - server1 = new serverGrpc.Server(); - server1.addService(TestService, serviceImpl); - server2 = new serverGrpc.Server(); - server2.addService(TestService, serviceImpl); - server1.bindAsync('localhost:0', serverCreds, (err, _port) => { - assert.ifError(err); - server1.start(); - port = _port; - client = new TestServiceClient(`localhost:${port}`, clientCreds); - done(); - }); - }); - after(function() { - client.close(); - server1.forceShutdown(); - server2.forceShutdown(); - }); - it.skip('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { - this.timeout(10000); - let pendingCalls = 0; - let testDone = false; - let callInterval; - function maybeDone() { - if (testDone && pendingCalls === 0) { +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Reconnection', function() { + let server1; + let server2; + let port; + before(function(done) { + server1 = new serverGrpc.Server(); + server1.addService(TestService, serviceImpl); + server2 = new serverGrpc.Server(); + server2.addService(TestService, serviceImpl); + server1.bindAsync('localhost:0', serverCreds, (err, _port) => { + assert.ifError(err); + server1.start(); + port = _port; + client = new TestServiceClient(`localhost:${port}`, clientCreds); done(); - } - }; - client.unary({}, (err, data) => { - assert.ifError(err); - server1.tryShutdown(() => { - server2.bindAsync(`localhost:${port}`, serverCreds, (err) => { - assert.ifError(err); - server2.start(); - const metadata = new clientGrpc.Metadata({ waitForReady: true }); - client.unary({}, metadata, (err, data) => { + }); + }); + after(function() { + client.close(); + server1.forceShutdown(); + server2.forceShutdown(); + }); + it.skip('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { + this.timeout(10000); + let pendingCalls = 0; + let testDone = false; + let callInterval; + function maybeDone() { + if (testDone && pendingCalls === 0) { + done(); + } + }; + client.unary({}, (err, data) => { + assert.ifError(err); + server1.tryShutdown(() => { + server2.bindAsync(`localhost:${port}`, serverCreds, (err) => { assert.ifError(err); - clearInterval(callInterval); - testDone = true; - maybeDone(); + server2.start(); + const metadata = new clientGrpc.Metadata({ waitForReady: true }); + client.unary({}, metadata, (err, data) => { + assert.ifError(err); + clearInterval(callInterval); + testDone = true; + maybeDone(); + }); }); }); + callInterval = setInterval(() => { + assert.strictEqual(testDone, false); + pendingCalls += 1; + client.unary({}, (err, data) => { + pendingCalls -= 1; + if (err) { + assert.strictEqual(err.code, clientGrpc.status.UNAVAILABLE); + } + maybeDone(); + }); + }, 0); }); - callInterval = setInterval(() => { - assert.strictEqual(testDone, false); - pendingCalls += 1; - client.unary({}, (err, data) => { - pendingCalls -= 1; - if (err) { - assert.strictEqual(err.code, clientGrpc.status.UNAVAILABLE); - } - maybeDone(); - }); - }, 0); }); }); }); diff --git a/test/api/error_test.js b/test/api/error_test.js index 8c07c662..23a8d0d8 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -33,524 +33,526 @@ const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestS const clientInsecureCreds = clientGrpc.credentials.createInsecure(); const serverInsecureCreds = serverGrpc.ServerCredentials.createInsecure(); -describe('Client malformed response handling', function() { - var server; - var client; - var badArg = Buffer.from([0xFF]); - before(function(done) { - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity - } - }; - server = new serverGrpc.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); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function() { - // Ignore requests - stream.write(badArg); - }); - stream.on('end', function() { - stream.end(); - }); - } - }); - server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { - assert.ifError(err); - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); - done(); - }); - }); - 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, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.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(done) { - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: serializeFail - } - }; - server = new serverGrpc.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(); - }); - } - }); - server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { - assert.ifError(err); - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); - done(); - }); - }); - 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, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - }); - describe('Other conditions', function() { - var Client; - var client; - var server; - var port; - before(function(done) { - server = new serverGrpc.Server(); - var trailer_metadata = new serverGrpc.Metadata(); - trailer_metadata.add('trailer-present', 'yes'); - server.addService(TestServiceClient.service, { - unary: function(call, cb) { - var req = call.request; - if (req.error) { - var message = 'Requested error'; - if (req.message) { - message = req.message; - } - cb({code: serverGrpc.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: serverGrpc.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); - }); - } - }); - server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { - assert.ifError(err); - port = _port; - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); - done(); - }); - }); - after(function() { - server.forceShutdown(); - }); - describe('Server recieving bad input', function() { - var misbehavingClient; +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Client malformed response handling', function() { + var server; + var client; var badArg = Buffer.from([0xFF]); - before(function() { - var test_service_attrs = { + before(function(done) { + var malformed_test_service = { unary: { path: '/TestService/Unary', requestStream: false, responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity } }; - var Client = clientGrpc.makeGenericClientConstructor(test_service_attrs, - 'TestService'); - misbehavingClient = new Client('localhost:' + port, clientInsecureCreds); + server = new serverGrpc.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); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function() { + // Ignore requests + stream.write(badArg); + }); + stream.on('end', function() { + stream.end(); + }); + } + }); + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + done(); + }); }); - it('should respond correctly to a unary call', function(done) { - misbehavingClient.unary(badArg, function(err, data) { + 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, clientGrpc.status.INTERNAL); done(); }); }); - it('should respond correctly to a client stream', function(done) { - var call = misbehavingClient.clientStream(function(err, data) { + 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, clientGrpc.status.INTERNAL); done(); }); - call.write(badArg); - // TODO(mlumish): Remove call.end() + call.write({}); 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', '==='); - }); + 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, clientGrpc.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', '==='); - }); + 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, clientGrpc.status.INTERNAL); done(); }); - call.write(badArg); - // TODO(mlumish): Remove call.end() + call.write({}); 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) { + describe('Server serialization failure handling', function() { + function serializeFail(obj) { + throw new Error('Serialization failed'); + } + var client; + var server; + before(function(done) { + var malformed_test_service = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + } + }; + server = new serverGrpc.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(); + }); + } + }); + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { assert.ifError(err); - }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); done(); }); }); - it('should be present when a unary call fails', function(done) { - var call = client.unary({error: true}, function(err, data) { + after(function() { + server.forceShutdown(); + }); + it('should get an INTERNAL status with a unary call', function(done) { + client.unary({}, function(err, data) { assert(err); - }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); }); - it('should be present when a client stream call succeeds', function(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, clientGrpc.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, clientGrpc.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, clientGrpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); + }); + describe('Other conditions', function() { + var Client; + var client; + var server; + var port; + before(function(done) { + server = new serverGrpc.Server(); + var trailer_metadata = new serverGrpc.Metadata(); + trailer_metadata.add('trailer-present', 'yes'); + server.addService(TestServiceClient.service, { + unary: function(call, cb) { + var req = call.request; + if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } + cb({code: serverGrpc.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: serverGrpc.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); + }); + } + }); + server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { 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']); + port = _port; + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); done(); }); }); - it('should be present when a client stream call fails', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); + after(function() { + server.forceShutdown(); + }); + 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: _.identity, + responseDeserialize: _.identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + } + }; + var Client = clientGrpc.makeGenericClientConstructor(test_service_attrs, + 'TestService'); + misbehavingClient = new Client('localhost:' + port, clientInsecureCreds); }); - 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 respond correctly to a unary call', function(done) { + misbehavingClient.unary(badArg, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.status.INTERNAL); + done(); + }); + call.write(badArg); + // TODO(mlumish): Remove call.end() + call.end(); }); }); - 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, clientGrpc.status.OK); - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); + 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, clientGrpc.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, clientGrpc.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(); + }); }); }); - 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(); + 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, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, '測試字符串'); + 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, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.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, clientGrpc.status.UNKNOWN); - assert.strictEqual(err.details, '測試字符串'); - done(); - }); - }); - }); -}); + }); +}); \ No newline at end of file diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js new file mode 100644 index 00000000..d0df38e3 --- /dev/null +++ b/test/api/interop_extra_test.js @@ -0,0 +1,139 @@ +/* + * + * Copyright 2019 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'; + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const interopServer = require('../interop/interop_server.js'); +const anyGrpc = require('../any_grpc'); +const grpc = anyGrpc.client; +var protoLoader = require('../../packages/proto-loader'); + +const protoPackage = protoLoader.loadSync( + 'src/proto/grpc/testing/test.proto', + {keepCase: true, + defaults: true, + enums: String, + includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); +const testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; + +function multiDone(done, count) { + return function() { + count -= 1; + if (count <= 0) { + done(); + } + }; +} + +function echoMetadataGenerator(options, callback) { + const metadata = new grpc.Metadata(); + metadata.set('x-grpc-test-echo-initial', 'test_initial_metadata_value'); + console.log('Adding metadata'); + console.log(metadata); + callback(null, metadata); +} + +const credentials = grpc.credentials.createFromMetadataGenerator(echoMetadataGenerator); + +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Interop-adjacent tests', function() { + let server; + let client; + before(function(done) { + interopServer.getServer(0, true, (err, serverObj) => { + if (err) { + done(err); + } else { + server = serverObj.server; + server.start(); + const ca_path = path.join(__dirname, '../data/ca.pem'); + const ca_data = fs.readFileSync(ca_path); + const creds = grpc.credentials.createSsl(ca_data); + const options = { + 'grpc.ssl_target_name_override': 'foo.test.google.fr', + 'grpc.default_authority': 'foo.test.google.fr' + }; + client = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); + done(); + } + }); + }); + after(function() { + server.forceShutdown(); + }); + it('Should be able to start many concurrent calls', function(done) { + const callCount = 100; + done = multiDone(done, callCount); + for (let i = 0; i < callCount; i++) { + client.unaryCall({}, (error, result) => { + assert.ifError(error); + done(); + }); + } + }); + it('Should echo metadata from call credentials', function(done) { + done = multiDone(done, 2); + const call = client.unaryCall({}, {credentials}, (error, result) => { + assert.ifError(error); + done(); + }); + call.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); + }); + it('Should be able to send the same metadata on two calls with call creds', function(done) { + done = multiDone(done, 5); + const metadata = new grpc.Metadata(); + metadata.set('x-grpc-test-echo-trailing-bin', Buffer.from('ababab', 'hex')); + const call1 = client.unaryCall({}, metadata, {credentials}, (error, result) => { + assert.ifError(error); + const call2 = client.unaryCall({}, metadata, {credentials}, (error, result) => { + assert.ifError(error); + done(); + }); + call2.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); + call2.on('status', function(status) { + var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); + assert(echo_trailer.length === 1); + assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); + done(); + }); + }); + call1.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); + call1.on('status', function(status) { + var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); + assert(echo_trailer.length === 1); + assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 27441e96..995650e2 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -19,6 +19,7 @@ 'use strict'; var childProcess = require('child_process'); +const anyGrpc = require('../any_grpc'); var port; @@ -45,60 +46,62 @@ const testCases = [ var childExecArgv = []; -describe('Interop tests', function() { - this.timeout(4000); - before(function(done) { - for (let arg of process.argv) { - if (arg.startsWith('--require=')) { - childExecArgv.push('--require'); - childExecArgv.push(arg.substring('--require='.length)); +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Interop tests', function() { + this.timeout(4000); + before(function(done) { + for (let arg of process.argv) { + if (arg.startsWith('--require=')) { + childExecArgv.push('--require'); + childExecArgv.push(arg.substring('--require='.length)); + } + } + serverProcess = childProcess.fork(`${__dirname}/interop_helper/server.js`, { + execArgv: childExecArgv + }); + serverProcess.on('message', (message) => { + port = message.port; + done(); + }); + serverProcess.on('exit', (code, signal) => { + if (code !== 0) { + if (code !== null) { + throw new Error(`Server exited with error code ${code}`); + } else { + throw new Error(`Server exited with signal ${signal}`); + } + } + }); + }); + after(function() { + serverProcess.send({}); + }); + for (let testName of testCases) { + it(`should pass ${testName}`, function(done) { + /* We need to run a client process per test to most closely match + * how the main interop test suite works */ + let clientProcess = childProcess.fork(`${__dirname}/../interop/interop_client`, [ + '--server_host=localhost', + `--server_port=${port}`, + `--server_host_override=${name_override}`, + `--test_case=${testName}`, + '--use_tls=true', + '--use_test_ca=true' + ], { + execArgv: childExecArgv + }); + clientProcess.on('exit', (code, signal) => { + if (code === 0) { + done(); + } else { + if (code !== null) { + done(new Error(`Client exited with error code ${code}`)); + } else { + done(new Error(`Client exited with signal ${signal}`)); } } - serverProcess = childProcess.fork(`${__dirname}/interop_helper/server.js`, { - execArgv: childExecArgv - }); - serverProcess.on('message', (message) => { - port = message.port; - done(); - }); - serverProcess.on('exit', (code, signal) => { - if (code !== 0) { - if (code !== null) { - throw new Error(`Server exited with error code ${code}`); - } else { - throw new Error(`Server exited with signal ${signal}`); - } - } - }); - }); - after(function() { - serverProcess.send({}); - }); - for (let testName of testCases) { - it(`should pass ${testName}`, function(done) { - /* We need to run a client process per test to most closely match - * how the main interop test suite works */ - let clientProcess = childProcess.fork(`${__dirname}/../interop/interop_client`, [ - '--server_host=localhost', - `--server_port=${port}`, - `--server_host_override=${name_override}`, - `--test_case=${testName}`, - '--use_tls=true', - '--use_test_ca=true' - ], { - execArgv: childExecArgv + }); }); - clientProcess.on('exit', (code, signal) => { - if (code === 0) { - done(); - } else { - if (code !== null) { - done(new Error(`Client exited with error code ${code}`)); - } else { - done(new Error(`Client exited with signal ${signal}`)); - } - } - }); - }); - } -}); + } + }); +}); \ No newline at end of file diff --git a/test/api/metadata_test.js b/test/api/metadata_test.js deleted file mode 100644 index 16d7216b..00000000 --- a/test/api/metadata_test.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2019 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. - * - */ - -const options = { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true -}; -const path = require('path'); -const fs = require('fs'); -const assert = require('assert'); -const _ = require('lodash'); -const anyGrpc = require('../any_grpc'); -const clientGrpc = anyGrpc.client; -const serverGrpc = anyGrpc.server; -const protoLoader = require('../../packages/proto-loader', options); -const testServiceDef = protoLoader.loadSync(__dirname + '/../proto/test_service.proto'); -const TestService = serverGrpc.loadPackageDefinition(testServiceDef).TestService.service; -const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestService; - -const keyPath = path.join(__dirname, '../data/server1.key'); -const pemPath = path.join(__dirname, '../data/server1.pem'); -const caPath = path.join(__dirname, '../data/ca.pem'); -const keyData = fs.readFileSync(keyPath); -const pemData = fs.readFileSync(pemPath); -const caData = fs.readFileSync(caPath); - -const clientCreds = clientGrpc.credentials.createSsl(caData); -const dummyCallCreds = clientGrpc.credentials.createFromMetadataGenerator((options, callback) => { - const metadata = new clientGrpc.Metadata(); - metadata.add('authorization', 'test'); - callback(null, metadata); -}); -const combinedClientCreds = clientGrpc.credentials.combineChannelCredentials(clientCreds, dummyCallCreds); -const serverCreds = serverGrpc.ServerCredentials.createSsl(null, [{private_key: keyData, cert_chain: pemData}]); - -const hostOverride = 'foo.test.google.fr'; -const clientOptions = { - 'grpc.ssl_target_name_override': hostOverride, - 'grpc.default_authority': hostOverride -} - -describe('Sending metadata', function() { - let server; - before(function(done) { - server = new serverGrpc.Server(); - server.addService(TestService, { - unary: function(call, cb) { - cb(null, {}); - }, - clientStream: function(stream, cb){ - stream.on('data', function(data) {}); - stream.on('end', function() { - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.end(); - }); - } - }); - server.bindAsync('localhost:0', serverCreds, (err, port) => { - assert.ifError(err); - server.start(); - client = new TestServiceClient(`localhost:${port}`, combinedClientCreds, clientOptions); - done(); - }); - }); - after(function() { - server.forceShutdown(); - }); - it('Should be able to send the same metadata on two calls with call creds', function(done) { - const metadata = new clientGrpc.Metadata(); - client.unary({}, metadata, (err, data) => { - assert.ifError(err); - client.unary({}, metadata, (err, data) => { - assert.ifError(err); - done(); - }); - }); - }); -});