diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index b63e294f9a332ee46a0ca0fad2d15a8fa6950de9..fcad62261fb730f8fca477e4aa0697440e46bbc1 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -712,7 +712,11 @@ NAN_METHOD(Call::CancelWithStatus) { Call *call = ObjectWrap::Unwrap<Call>(info.This()); grpc_status_code code = static_cast<grpc_status_code>( Nan::To<uint32_t>(info[0]).FromJust()); - Utf8String details(info[0]); + if (code == GRPC_STATUS_OK) { + return Nan::ThrowRangeError( + "cancelWithStatus cannot be called with OK status"); + } + Utf8String details(info[1]); grpc_call_cancel_with_status(call->wrapped_call, code, *details, NULL); } diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index cb55083d1ae188ded69cce3976d8bd79e5497234..b5061895cfae0eae19e7d86eb6399c48ab0a8565 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -35,7 +35,6 @@ var fs = require('fs'); var path = require('path'); -var _ = require('lodash'); var grpc = require('..'); var testProto = grpc.load({ root: __dirname + '/../../..', diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js index ddc094f89684de28988a9633efaca44f5d02f848..ff10a22e6a9ae650eedc97a5d57ab546a379d7d2 100644 --- a/src/node/src/credentials.js +++ b/src/node/src/credentials.js @@ -99,6 +99,9 @@ exports.createFromMetadataGenerator = function(metadata_generator) { if (error.hasOwnProperty('code')) { code = error.code; } + if (!metadata) { + metadata = new Metadata(); + } } callback(code, message, metadata._getCoreRepresentation()); }); diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js index c316fe7f10d85ae0aec2c89070c49aeae86a005a..b7f4f5651053ad4d730fbecc9fdce12101a27c4c 100644 --- a/src/node/test/call_test.js +++ b/src/node/test/call_test.js @@ -108,6 +108,17 @@ describe('call', function() { }, TypeError); }); }); + describe('deadline', function() { + it('should time out immediately with negative deadline', function(done) { + var call = new grpc.Call(channel, 'method', -Infinity); + var batch = {}; + batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; + call.startBatch(batch, function(err, response) { + assert.strictEqual(response.status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + }); describe('startBatch', function() { it('should fail without an object and a function', function() { var call = new grpc.Call(channel, 'method', getDeadline(1)); @@ -192,6 +203,43 @@ describe('call', function() { }); }); }); + describe('cancelWithStatus', function() { + it('should reject anything other than an integer and a string', function() { + assert.doesNotThrow(function() { + var call = new grpc.Call(channel, 'method', getDeadline(1)); + call.cancelWithStatus(1, 'details'); + }); + assert.throws(function() { + var call = new grpc.Call(channel, 'method', getDeadline(1)); + call.cancelWithStatus(); + }); + assert.throws(function() { + var call = new grpc.Call(channel, 'method', getDeadline(1)); + call.cancelWithStatus(''); + }); + assert.throws(function() { + var call = new grpc.Call(channel, 'method', getDeadline(1)); + call.cancelWithStatus(5, {}); + }); + }); + it('should reject the OK status code', function() { + assert.throws(function() { + var call = new grpc.Call(channel, 'method', getDeadline(1)); + call.cancelWithStatus(0, 'details'); + }); + }); + it('should result in the call ending with a status', function(done) { + var call = new grpc.Call(channel, 'method', getDeadline(1)); + var batch = {}; + batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; + call.startBatch(batch, function(err, response) { + assert.strictEqual(response.status.code, 5); + assert.strictEqual(response.status.details, 'details'); + done(); + }); + call.cancelWithStatus(5, 'details'); + }); + }); describe('getPeer', function() { it('should return a string', function() { var call = new grpc.Call(channel, 'method', getDeadline(1)); diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js index 05269f7b6e4ef808d7d023e5baa9046af813fcb3..5bcf63ee50bc7a4b62b645770b99e26e5196f480 100644 --- a/src/node/test/channel_test.js +++ b/src/node/test/channel_test.js @@ -155,7 +155,6 @@ describe('channel', function() { deadline.setSeconds(deadline.getSeconds() + 1); channel.watchConnectivityState(old_state, deadline, function(err, value) { assert(err); - console.log('Callback from watchConnectivityState'); done(); }); }); diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js index 7fc311a888dc0f139ecca1d7efb4e352c5f17536..960405ab3b9642262793c47644de825cf77b8800 100644 --- a/src/node/test/credentials_test.js +++ b/src/node/test/credentials_test.js @@ -169,6 +169,24 @@ describe('client credentials', function() { done(); }); }); + it.skip('should propagate errors that the updater emits', function(done) { + var metadataUpdater = function(service_url, callback) { + var error = new Error('Authentication error'); + error.code = grpc.status.UNAUTHENTICATED; + callback(error); + }; + var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); + var client = new Client('localhost:' + port, combined_creds, + client_options); + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.message, 'Authentication error'); + assert.strictEqual(err.code, grpc.status.UNAUTHENTICATED); + done(); + }); + }); describe('Per-rpc creds', function() { var client; var updater_creds; diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js index a4dc24cf4671e0e085f99e25dd4e7802f82fb657..c93b528d42f2a6d259ac95ef408a47a2258cef5e 100644 --- a/src/node/test/health_test.js +++ b/src/node/test/health_test.js @@ -45,11 +45,13 @@ describe('Health Checking', function() { 'grpc.test.TestServiceNotServing': 'NOT_SERVING', 'grpc.test.TestServiceServing': 'SERVING' }; - var healthServer = new grpc.Server(); - healthServer.addProtoService(health.service, - new health.Implementation(statusMap)); + var healthServer; + var healthImpl; var healthClient; before(function() { + healthServer = new grpc.Server(); + healthImpl = new health.Implementation(statusMap); + healthServer.addProtoService(health.service, healthImpl); var port_num = healthServer.bind('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); healthServer.start(); @@ -89,4 +91,16 @@ describe('Health Checking', function() { done(); }); }); + it('should get a different response if the status changes', function(done) { + healthClient.check({service: 'transient'}, function(err, response) { + assert(err); + assert.strictEqual(err.code, grpc.status.NOT_FOUND); + healthImpl.setStatus('transient', 'SERVING'); + healthClient.check({service: 'transient'}, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.status, 'SERVING'); + done(); + }); + }); + }); }); diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index f8c0b14137796063457096d34047452cd820018f..f008a87585cbc9776116b0a032c5f738b181595e 100644 --- a/src/node/test/interop_sanity_test.js +++ b/src/node/test/interop_sanity_test.js @@ -71,7 +71,7 @@ describe('Interop tests', function() { interop_client.runTest(port, name_override, 'server_streaming', true, true, done); }); - it.only('should pass ping_pong', function(done) { + it('should pass ping_pong', function(done) { interop_client.runTest(port, name_override, 'ping_pong', true, true, done); }); it('should pass empty_stream', function(done) { diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 395ea887ecb833f733e98b53b3ee649c0649978d..71801c38dd17871d15b567f0ccd0240b4ffd26e9 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -382,7 +382,8 @@ describe('Other conditions', function() { unary: function(call, cb) { var req = call.request; if (req.error) { - cb(new Error('Requested error'), null, trailer_metadata); + cb({code: grpc.status.UNKNOWN, + details: 'Requested error'}, null, trailer_metadata); } else { cb(null, {count: 1}, trailer_metadata); } @@ -407,7 +408,8 @@ describe('Other conditions', function() { serverStream: function(stream) { var req = stream.request; if (req.error) { - var err = new Error('Requested error'); + var err = {code: grpc.status.UNKNOWN, + details: 'Requested error'}; err.metadata = trailer_metadata; stream.emit('error', err); } else { diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh index 0a11e87c37a7cfd023ae93cf84f3c0a60a4abde9..85e3a38f844e750f11fdf3b2f9a12ecb7f1140ed 100755 --- a/tools/run_tests/run_node.sh +++ b/tools/run_tests/run_node.sh @@ -45,7 +45,8 @@ then gcov Release/obj.target/grpc/ext/*.o lcov --base-directory . --directory . -c -o coverage.info genhtml -o ../reports/node_ext_coverage --num-spaces 2 \ - -t 'Node gRPC test coverage' coverage.info + -t 'Node gRPC test coverage' coverage.info --rc genhtml_hi_limit=95 \ + --rc genhtml_med_limit=80 echo '<html><head><meta http-equiv="refresh" content="0;URL=lcov-report/index.html"></head></html>' > \ ../reports/node_coverage/index.html else