diff options
author | Jan Tattermusch <jtattermusch@users.noreply.github.com> | 2015-10-09 16:24:44 -0700 |
---|---|---|
committer | Jan Tattermusch <jtattermusch@users.noreply.github.com> | 2015-10-09 16:24:44 -0700 |
commit | abaf47c3a57d5f00c2e75b98ed9a52b35252c4fa (patch) | |
tree | 55581316ee2818990ac31d8f219858ce7698e08f /src | |
parent | 8aad5a07bf1c24239939e14a34b306e26169d9a8 (diff) | |
parent | 5dbbd9178db5a26b9a765534a561cf1e0cba5e94 (diff) |
Merge pull request #3746 from murgatroid99/node_interop_compliance
Made node interop tests maximally compliant with the spec
Diffstat (limited to 'src')
-rw-r--r-- | src/node/interop/interop_client.js | 188 | ||||
-rw-r--r-- | src/node/interop/interop_server.js | 63 | ||||
-rw-r--r-- | src/node/src/server.js | 2 | ||||
-rw-r--r-- | src/node/test/async_test.js | 2 | ||||
-rw-r--r-- | src/node/test/channel_test.js | 2 | ||||
-rw-r--r-- | src/node/test/credentials_test.js | 10 | ||||
-rw-r--r-- | src/node/test/interop_sanity_test.js | 10 |
7 files changed, 175 insertions, 102 deletions
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js index 14cc6c0efe..cb55083d1a 100644 --- a/src/node/interop/interop_client.js +++ b/src/node/interop/interop_client.js @@ -44,12 +44,14 @@ var GoogleAuth = require('google-auth-library'); var assert = require('assert'); -var AUTH_SCOPE = 'https://www.googleapis.com/auth/xapi.zoo'; -var AUTH_SCOPE_RESPONSE = 'xapi.zoo'; -var AUTH_USER = ('155450119199-vefjjaekcc6cmsd5914v6lqufunmh9ue' + - '@developer.gserviceaccount.com'); -var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' + - '@developer.gserviceaccount.com'); +var SERVICE_ACCOUNT_EMAIL; +try { + SERVICE_ACCOUNT_EMAIL = require( + process.env.GOOGLE_APPLICATION_CREDENTIALS).client_email; +} catch (e) { + // This will cause the tests to fail if they need that string + SERVICE_ACCOUNT_EMAIL = null; +} var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; @@ -345,6 +347,41 @@ function customMetadata(client, done) { stream.end(); } +function statusCodeAndMessage(client, done) { + done = multiDone(done, 2); + var arg = { + response_status: { + code: 2, + message: 'test status message' + } + }; + client.unaryCall(arg, function(err, resp) { + assert(err); + assert.strictEqual(err.code, 2); + assert.strictEqual(err.message, 'test status message'); + done(); + }); + var duplex = client.fullDuplexCall(); + duplex.on('status', function(status) { + assert(status); + assert.strictEqual(status.code, 2); + assert.strictEqual(status.details, 'test status message'); + done(); + }); + duplex.on('error', function(){}); + duplex.write(arg); + duplex.end(); +} + +function unimplementedMethod(client, done) { + client.unimplementedCall({}, function(err, resp) { + assert(err); + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + assert(!err.message); + done(); + }); +} + /** * Run one of the authentication tests. * @param {string} expected_user The expected username in the response @@ -369,7 +406,7 @@ function authTest(expected_user, scope, client, done) { assert.strictEqual(resp.payload.body.length, 314159); assert.strictEqual(resp.username, expected_user); if (scope) { - assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); + assert(scope.indexOf(resp.oauth_scope) > -1); } if (done) { done(); @@ -377,56 +414,49 @@ function authTest(expected_user, scope, client, done) { }); } -function oauth2Test(expected_user, scope, per_rpc, client, done) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { +function computeEngineCreds(client, done, extra) { + authTest(extra.service_account, null, client, done); +} + +function serviceAccountCreds(client, done, extra) { + authTest(SERVICE_ACCOUNT_EMAIL, extra.oauth_scope, client, done); +} + +function jwtTokenCreds(client, done, extra) { + authTest(SERVICE_ACCOUNT_EMAIL, null, client, done); +} + +function oauth2Test(client, done, extra) { + var arg = { + fill_username: true, + fill_oauth_scope: true + }; + client.unaryCall(arg, function(err, resp) { assert.ifError(err); - var arg = { - fill_username: true, - fill_oauth_scope: true - }; - credential = credential.createScoped(scope); - credential.getAccessToken(function(err, token) { - assert.ifError(err); - var updateMetadata = function(authURI, metadata, callback) { - metadata.add('authorization', 'Bearer ' + token); - callback(null, metadata); - }; - var makeTestCall = function(error, client_metadata) { - assert.ifError(error); - client.unaryCall(arg, function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.username, expected_user); - assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); - if (done) { - done(); - } - }, client_metadata); - }; - if (per_rpc) { - updateMetadata('', new grpc.Metadata(), makeTestCall); - } else { - client.$updateMetadata = updateMetadata; - makeTestCall(null, new grpc.Metadata()); - } - }); + assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); + assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); + if (done) { + done(); + } }); } -function perRpcAuthTest(expected_user, scope, per_rpc, client, done) { +function perRpcAuthTest(client, done, extra) { (new GoogleAuth()).getApplicationDefault(function(err, credential) { assert.ifError(err); var arg = { fill_username: true, fill_oauth_scope: true }; + var scope = extra.oauth_scope; if (credential.createScopedRequired() && scope) { credential = credential.createScoped(scope); } var creds = grpc.credentials.createFromGoogleCredential(credential); client.unaryCall(arg, function(err, resp) { assert.ifError(err); - assert.strictEqual(resp.username, expected_user); - assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE); + assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); + assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); if (done) { done(); } @@ -473,25 +503,44 @@ function getOauth2Creds(scope, callback) { * Map from test case names to test functions */ var test_cases = { - empty_unary: {run: emptyUnary}, - large_unary: {run: largeUnary}, - client_streaming: {run: clientStreaming}, - server_streaming: {run: serverStreaming}, - ping_pong: {run: pingPong}, - empty_stream: {run: emptyStream}, - cancel_after_begin: {run: cancelAfterBegin}, - cancel_after_first_response: {run: cancelAfterFirstResponse}, - timeout_on_sleeping_server: {run: timeoutOnSleepingServer}, - custom_metadata: {run: customMetadata}, - compute_engine_creds: {run: _.partial(authTest, COMPUTE_ENGINE_USER, null), - getCreds: _.partial(getApplicationCreds, null)}, - service_account_creds: {run: _.partial(authTest, AUTH_USER, AUTH_SCOPE), - getCreds: _.partial(getApplicationCreds, AUTH_SCOPE)}, - jwt_token_creds: {run: _.partial(authTest, AUTH_USER, null), - getCreds: _.partial(getApplicationCreds, null)}, - oauth2_auth_token: {run: _.partial(oauth2Test, AUTH_USER, AUTH_SCOPE, false), - getCreds: _.partial(getOauth2Creds, AUTH_SCOPE)}, - per_rpc_creds: {run: _.partial(perRpcAuthTest, AUTH_USER, AUTH_SCOPE, true)} + empty_unary: {run: emptyUnary, + Client: testProto.TestService}, + large_unary: {run: largeUnary, + Client: testProto.TestService}, + client_streaming: {run: clientStreaming, + Client: testProto.TestService}, + server_streaming: {run: serverStreaming, + Client: testProto.TestService}, + ping_pong: {run: pingPong, + Client: testProto.TestService}, + empty_stream: {run: emptyStream, + Client: testProto.TestService}, + cancel_after_begin: {run: cancelAfterBegin, + Client: testProto.TestService}, + cancel_after_first_response: {run: cancelAfterFirstResponse, + Client: testProto.TestService}, + timeout_on_sleeping_server: {run: timeoutOnSleepingServer, + Client: testProto.TestService}, + custom_metadata: {run: customMetadata, + Client: testProto.TestService}, + status_code_and_message: {run: statusCodeAndMessage, + Client: testProto.TestService}, + unimplemented_method: {run: unimplementedMethod, + Client: testProto.UnimplementedService}, + compute_engine_creds: {run: computeEngineCreds, + Client: testProto.TestService, + getCreds: getApplicationCreds}, + service_account_creds: {run: serviceAccountCreds, + Client: testProto.TestService, + getCreds: getApplicationCreds}, + jwt_token_creds: {run: jwtTokenCreds, + Client: testProto.TestService, + getCreds: getApplicationCreds}, + oauth2_auth_token: {run: oauth2Test, + Client: testProto.TestService, + getCreds: getOauth2Creds}, + per_rpc_creds: {run: perRpcAuthTest, + Client: testProto.TestService} }; /** @@ -504,8 +553,9 @@ var test_cases = { * @param {bool} tls Indicates that a secure channel should be used * @param {function} done Callback to call when the test is completed. Included * primarily for use with mocha + * @param {object=} extra Extra options for some tests */ -function runTest(address, host_override, test_case, tls, test_ca, done) { +function runTest(address, host_override, test_case, tls, test_ca, done, extra) { // TODO(mlumish): enable TLS functionality var options = {}; var creds; @@ -529,12 +579,13 @@ function runTest(address, host_override, test_case, tls, test_ca, done) { var execute = function(err, creds) { assert.ifError(err); - var client = new testProto.TestService(address, creds, options); - test.run(client, done); + var client = new test.Client(address, creds, options); + test.run(client, done, extra); }; if (test.getCreds) { - test.getCreds(function(err, new_creds) { + test.getCreds(extra.oauth_scope, function(err, new_creds) { + assert.ifError(err); execute(err, grpc.credentials.combineChannelCredentials( creds, new_creds)); }); @@ -547,13 +598,18 @@ if (require.main === module) { var parseArgs = require('minimist'); var argv = parseArgs(process.argv, { string: ['server_host', 'server_host_override', 'server_port', 'test_case', - 'use_tls', 'use_test_ca'] + 'use_tls', 'use_test_ca', 'default_service_account', 'oauth_scope', + 'service_account_key_file'] }); + var extra_args = { + service_account: argv.default_service_account, + oauth_scope: argv.oauth_scope + }; runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true', function () { console.log('OK:', argv.test_case); - }); + }, extra_args); } /** diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js index 3e83304faa..5321005c86 100644 --- a/src/node/interop/interop_server.js +++ b/src/node/interop/interop_server.js @@ -44,6 +44,9 @@ var testProto = grpc.load({ var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; +var incompressible_data = fs.readFileSync( + __dirname + '/../../../test/cpp/interop/rnd.dat'); + /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer @@ -83,6 +86,19 @@ function getEchoTrailer(call) { return response_trailer; } +function getPayload(payload_type, size) { + if (payload_type === 'RANDOM') { + payload_type = ['COMPRESSABLE', + 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; + } + var body; + switch (payload_type) { + case 'COMPRESSABLE': body = zeroBuffer(size); break; + case 'UNCOMPRESSABLE': incompressible_data.slice(size); break; + } + return {type: payload_type, body: body}; +} + /** * Respond to an empty parameter with an empty response. * NOTE: this currently does not work due to issue #137 @@ -104,13 +120,14 @@ function handleEmpty(call, callback) { function handleUnary(call, callback) { echoHeader(call); var req = call.request; - var zeros = zeroBuffer(req.response_size); - var payload_type = req.response_type; - if (payload_type === 'RANDOM') { - payload_type = ['COMPRESSABLE', - 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; + if (req.response_status) { + var status = req.response_status; + status.metadata = getEchoTrailer(call); + callback(status); + return; } - callback(null, {payload: {type: payload_type, body: zeros}}, + var payload = getPayload(req.response_type, req.response_size); + callback(null, {payload: payload}, getEchoTrailer(call)); } @@ -139,18 +156,14 @@ function handleStreamingInput(call, callback) { function handleStreamingOutput(call) { echoHeader(call); var req = call.request; - var payload_type = req.response_type; - if (payload_type === 'RANDOM') { - payload_type = ['COMPRESSABLE', - 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; + if (req.response_status) { + var status = req.response_status; + status.metadata = getEchoTrailer(call); + call.emit('error', status); + return; } _.each(req.response_parameters, function(resp_param) { - call.write({ - payload: { - body: zeroBuffer(resp_param.size), - type: payload_type - } - }); + call.write({payload: getPayload(req.response_type, resp_param.size)}); }); call.end(getEchoTrailer(call)); } @@ -163,18 +176,14 @@ function handleStreamingOutput(call) { function handleFullDuplex(call) { echoHeader(call); call.on('data', function(value) { - var payload_type = value.response_type; - if (payload_type === 'RANDOM') { - payload_type = ['COMPRESSABLE', - 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; + if (value.response_status) { + var status = value.response_status; + status.metadata = getEchoTrailer(call); + call.emit('error', status); + return; } _.each(value.response_parameters, function(resp_param) { - call.write({ - payload: { - body: zeroBuffer(resp_param.size), - type: payload_type - } - }); + call.write({payload: getPayload(value.response_type, resp_param.size)}); }); }); call.on('end', function() { @@ -188,7 +197,7 @@ function handleFullDuplex(call) { * @param {Call} call Call to handle */ function handleHalfDuplex(call) { - throw new Error('HalfDuplexCall not yet implemented'); + call.emit('error', Error('HalfDuplexCall not yet implemented')); } /** diff --git a/src/node/src/server.js b/src/node/src/server.js index 87b5b7ad06..a974d593c9 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -629,7 +629,7 @@ function Server(options) { (new Metadata())._getCoreRepresentation(); batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { code: grpc.status.UNIMPLEMENTED, - details: 'This method is not available on this server.', + details: '', metadata: {} }; batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; diff --git a/src/node/test/async_test.js b/src/node/test/async_test.js index ce3ce50a2d..6d71ea24f5 100644 --- a/src/node/test/async_test.js +++ b/src/node/test/async_test.js @@ -57,7 +57,7 @@ describe('Async functionality', function() { grpc.ServerCredentials.createInsecure()); server.start(); math_client = new math.Math('localhost:' + port_num, - grpc.Credentials.createInsecure()); + grpc.credentials.createInsecure()); done(); }); after(function() { diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js index b86f89b8a8..05269f7b6e 100644 --- a/src/node/test/channel_test.js +++ b/src/node/test/channel_test.js @@ -149,7 +149,7 @@ describe('channel', function() { afterEach(function() { channel.close(); }); - it.only('should time out if called alone', function(done) { + it('should time out if called alone', function(done) { var old_state = channel.getConnectivityState(); var deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js index 8eb91ee69e..7fc311a888 100644 --- a/src/node/test/credentials_test.js +++ b/src/node/test/credentials_test.js @@ -130,8 +130,8 @@ describe('client credentials', function() { callback(null, metadata); }; var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineCredentials(client_ssl_creds, - creds); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); var client = new Client('localhost:' + port, combined_creds, client_options); var call = client.unary({}, function(err, data) { @@ -150,8 +150,8 @@ describe('client credentials', function() { callback(null, metadata); }; var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineCredentials(client_ssl_creds, - creds); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); var client = new Client('localhost:' + port, combined_creds, client_options); var call = client.unary({}, function(err, data) { @@ -231,7 +231,7 @@ describe('client credentials', function() { updater_creds, alt_updater_creds); var call = client.unary({}, function(err, data) { assert.ifError(err); - }, null, {credentials: updater_creds}); + }, null, {credentials: combined_updater}); call.on('metadata', function(metadata) { assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); assert.deepEqual(metadata.get('other_plugin_key'), diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index 804c1d45e4..f8c0b14137 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('should pass ping_pong', function(done) { + it.only('should pass ping_pong', function(done) { interop_client.runTest(port, name_override, 'ping_pong', true, true, done); }); it('should pass empty_stream', function(done) { @@ -94,4 +94,12 @@ describe('Interop tests', function() { interop_client.runTest(port, name_override, 'custom_metadata', true, true, done); }); + it('should pass status_code_and_message', function(done) { + interop_client.runTest(port, name_override, 'status_code_and_message', + true, true, done); + }); + it('should pass unimplemented_method', function(done) { + interop_client.runTest(port, name_override, 'unimplemented_method', + true, true, done); + }); }); |