Add metadata echo functionality to interop server, and corresponding interop test

pull/3099/head
murgatroid99 9 years ago
parent 5390692976
commit 1eb113c61e
  1. 73
      src/node/interop/interop_client.js
  2. 48
      src/node/interop/interop_server.js
  3. 4
      src/node/test/interop_sanity_test.js

@ -49,6 +49,9 @@ var AUTH_USER = ('155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk' +
var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' + var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' +
'@developer.gserviceaccount.com'); '@developer.gserviceaccount.com');
var ECHO_INITIAL_KEY = "x-grpc-test-echo-initial";
var ECHO_TRAILING_KEY = "x-grpc-test-echo-trailing-bin";
/** /**
* Create a buffer filled with size zeroes * Create a buffer filled with size zeroes
* @param {number} size The length of the buffer * @param {number} size The length of the buffer
@ -60,6 +63,27 @@ function zeroBuffer(size) {
return zeros; return zeros;
} }
/**
* 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();
}
};
}
/** /**
* Run the empty_unary test * Run the empty_unary test
* @param {Client} client The client to test against * @param {Client} client The client to test against
@ -271,6 +295,54 @@ function timeoutOnSleepingServer(client, done) {
}); });
} }
function customMetadata(client, done) {
done = multiDone(done, 5);
var metadata = new grpc.Metadata();
metadata.set(ECHO_INITIAL_KEY, 'test_initial_metadata_value');
metadata.set(ECHO_TRAILING_KEY, new Buffer('ababab', 'hex'));
var arg = {
response_type: 'COMPRESSABLE',
response_size: 314159,
payload: {
body: zeroBuffer(271828)
}
};
var streaming_arg = {
payload: {
body: zeroBuffer(271828)
}
};
var unary = client.unaryCall(arg, function(err, resp) {
assert.ifError(err);
done();
}, metadata);
unary.on('metadata', function(metadata) {
assert.deepEqual(metadata.get(ECHO_INITIAL_KEY),
['test_initial_metadata_value']);
done();
});
unary.on('status', function(status) {
var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY);
assert(echo_trailer.length > 0);
assert.strictEqual(echo_trailer.toString('hex'), 'ababab');
done();
});
var stream = client.fullDuplexCall(metadata);
stream.on('metadata', function(metadata) {
assert.deepEqual(metadata.get(ECHO_INITIAL_KEY),
['test_initial_metadata_value']);
done();
});
stream.on('status', function(status) {
var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY);
assert(echo_trailer.length > 0);
assert.strictEqual(echo_trailer.toString('hex'), 'ababab');
done();
});
stream.write(streaming_arg);
stream.end();
}
/** /**
* Run one of the authentication tests. * Run one of the authentication tests.
* @param {string} expected_user The expected username in the response * @param {string} expected_user The expected username in the response
@ -358,6 +430,7 @@ var test_cases = {
cancel_after_begin: cancelAfterBegin, cancel_after_begin: cancelAfterBegin,
cancel_after_first_response: cancelAfterFirstResponse, cancel_after_first_response: cancelAfterFirstResponse,
timeout_on_sleeping_server: timeoutOnSleepingServer, timeout_on_sleeping_server: timeoutOnSleepingServer,
custom_metadata: customMetadata,
compute_engine_creds: _.partial(authTest, COMPUTE_ENGINE_USER, null), compute_engine_creds: _.partial(authTest, COMPUTE_ENGINE_USER, null),
service_account_creds: _.partial(authTest, AUTH_USER, AUTH_SCOPE), service_account_creds: _.partial(authTest, AUTH_USER, AUTH_SCOPE),
jwt_token_creds: _.partial(authTest, AUTH_USER, null), jwt_token_creds: _.partial(authTest, AUTH_USER, null),

@ -39,6 +39,9 @@ var _ = require('lodash');
var grpc = require('..'); var grpc = require('..');
var testProto = grpc.load(__dirname + '/test.proto').grpc.testing; var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
var ECHO_INITIAL_KEY = "x-grpc-test-echo-initial";
var ECHO_TRAILING_KEY = "x-grpc-test-echo-trailing-bin";
/** /**
* Create a buffer filled with size zeroes * Create a buffer filled with size zeroes
* @param {number} size The length of the buffer * @param {number} size The length of the buffer
@ -50,6 +53,34 @@ function zeroBuffer(size) {
return zeros; return zeros;
} }
/**
* Echos a header metadata item as specified in the interop spec.
* @param {Call} call The call to echo metadata on
*/
function echoHeader(call) {
var echo_initial = call.metadata.get(ECHO_INITIAL_KEY);
if (echo_initial.length > 0) {
var response_metadata = new grpc.Metadata();
response_metadata.set(ECHO_INITIAL_KEY, echo_initial[0]);
call.sendMetadata(response_metadata);
}
}
/**
* Gets the trailer metadata that should be echoed when the call is done,
* as specified in the interop spec.
* @param {Call} call The call to get metadata from
* @return {grpc.Metadata} The metadata to send as a trailer
*/
function getEchoTrailer(call) {
var echo_trailer = call.metadata.get(ECHO_TRAILING_KEY);
var response_trailer = new grpc.Metadata();
if (echo_trailer.length > 0) {
response_trailer.set(ECHO_TRAILING_KEY, echo_trailer[0]);
}
return response_trailer;
}
/** /**
* Respond to an empty parameter with an empty response. * Respond to an empty parameter with an empty response.
* NOTE: this currently does not work due to issue #137 * NOTE: this currently does not work due to issue #137
@ -58,7 +89,8 @@ function zeroBuffer(size) {
* or error * or error
*/ */
function handleEmpty(call, callback) { function handleEmpty(call, callback) {
callback(null, {}); echoHeader(call);
callback(null, {}, getEchoTrailer(call));
} }
/** /**
@ -68,6 +100,7 @@ function handleEmpty(call, callback) {
* error * error
*/ */
function handleUnary(call, callback) { function handleUnary(call, callback) {
echoHeader(call);
var req = call.request; var req = call.request;
var zeros = zeroBuffer(req.response_size); var zeros = zeroBuffer(req.response_size);
var payload_type = req.response_type; var payload_type = req.response_type;
@ -75,7 +108,8 @@ function handleUnary(call, callback) {
payload_type = ['COMPRESSABLE', payload_type = ['COMPRESSABLE',
'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1]; 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
} }
callback(null, {payload: {type: payload_type, body: zeros}}); callback(null, {payload: {type: payload_type, body: zeros}},
getEchoTrailer(call));
} }
/** /**
@ -85,12 +119,14 @@ function handleUnary(call, callback) {
* error * error
*/ */
function handleStreamingInput(call, callback) { function handleStreamingInput(call, callback) {
echoHeader(call);
var aggregate_size = 0; var aggregate_size = 0;
call.on('data', function(value) { call.on('data', function(value) {
aggregate_size += value.payload.body.length; aggregate_size += value.payload.body.length;
}); });
call.on('end', function() { call.on('end', function() {
callback(null, {aggregated_payload_size: aggregate_size}); callback(null, {aggregated_payload_size: aggregate_size},
getEchoTrailer(call));
}); });
} }
@ -99,6 +135,7 @@ function handleStreamingInput(call, callback) {
* @param {Call} call Call to handle * @param {Call} call Call to handle
*/ */
function handleStreamingOutput(call) { function handleStreamingOutput(call) {
echoHeader(call);
var req = call.request; var req = call.request;
var payload_type = req.response_type; var payload_type = req.response_type;
if (payload_type === 'RANDOM') { if (payload_type === 'RANDOM') {
@ -113,7 +150,7 @@ function handleStreamingOutput(call) {
} }
}); });
}); });
call.end(); call.end(getEchoTrailer(call));
} }
/** /**
@ -122,6 +159,7 @@ function handleStreamingOutput(call) {
* @param {Call} call Call to handle * @param {Call} call Call to handle
*/ */
function handleFullDuplex(call) { function handleFullDuplex(call) {
echoHeader(call);
call.on('data', function(value) { call.on('data', function(value) {
var payload_type = value.response_type; var payload_type = value.response_type;
if (payload_type === 'RANDOM') { if (payload_type === 'RANDOM') {
@ -138,7 +176,7 @@ function handleFullDuplex(call) {
}); });
}); });
call.on('end', function() { call.on('end', function() {
call.end(); call.end(getEchoTrailer(call));
}); });
} }

@ -90,4 +90,8 @@ describe('Interop tests', function() {
interop_client.runTest(port, name_override, 'timeout_on_sleeping_server', interop_client.runTest(port, name_override, 'timeout_on_sleeping_server',
true, true, done); true, true, done);
}); });
it.only('should pass custom_metadata', function(done) {
interop_client.runTest(port, name_override, 'custom_metadata',
true, true, done);
});
}); });

Loading…
Cancel
Save