mirror of https://github.com/grpc/grpc-node.git
Native: Add initial metadata options
This commit is contained in:
parent
9bbe7057b5
commit
fe090a089a
|
|
@ -81,8 +81,13 @@ Local<Value> nanErrorWithCode(const char *msg, grpc_call_error code) {
|
||||||
return scope.Escape(err);
|
return scope.Escape(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreateMetadataArray(Local<Object> metadata, grpc_metadata_array *array) {
|
bool CreateMetadataArray(Local<Object> metadata_obj, grpc_metadata_array *array) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
Local<Value> metadata_value = (Nan::Get(metadata_obj, Nan::New("metadata").ToLocalChecked())).ToLocalChecked();
|
||||||
|
if (!metadata_value->IsObject()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Local<Object> metadata = Nan::To<Object>(metadata_value).ToLocalChecked();
|
||||||
Local<Array> keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked();
|
Local<Array> keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked();
|
||||||
for (unsigned int i = 0; i < keys->Length(); i++) {
|
for (unsigned int i = 0; i < keys->Length(); i++) {
|
||||||
Local<String> current_key =
|
Local<String> current_key =
|
||||||
|
|
@ -159,7 +164,10 @@ Local<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
|
||||||
Nan::Set(array, array->Length(), CopyStringFromSlice(elem->value));
|
Nan::Set(array, array->Length(), CopyStringFromSlice(elem->value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return scope.Escape(metadata_object);
|
Local<Object> result = Nan::New<Object>();
|
||||||
|
Nan::Set(result, Nan::New("metadata").ToLocalChecked(), metadata_object);
|
||||||
|
Nan::Set(result, Nan::New("flags").ToLocalChecked(), Nan::New<v8::Uint32>(0));
|
||||||
|
return scope.Escape(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> Op::GetOpType() const {
|
Local<Value> Op::GetOpType() const {
|
||||||
|
|
@ -185,7 +193,17 @@ class SendMetadataOp : public Op {
|
||||||
if (maybe_metadata.IsEmpty()) {
|
if (maybe_metadata.IsEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!CreateMetadataArray(maybe_metadata.ToLocalChecked(), &send_metadata)) {
|
Local<Object> metadata_object = maybe_metadata.ToLocalChecked();
|
||||||
|
MaybeLocal<Value> maybe_flag_value =
|
||||||
|
Nan::Get(metadata_object, Nan::New("flags").ToLocalChecked());
|
||||||
|
if (!maybe_flag_value.IsEmpty()) {
|
||||||
|
Local<Value> flag_value = maybe_flag_value.ToLocalChecked();
|
||||||
|
if (flag_value->IsUint32()) {
|
||||||
|
Maybe<uint32_t> maybe_flag = Nan::To<uint32_t>(flag_value);
|
||||||
|
out->flags |= maybe_flag.FromMaybe(0) & GRPC_INITIAL_METADATA_USED_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!CreateMetadataArray(metadata_object, &send_metadata)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out->data.send_initial_metadata.count = send_metadata.count;
|
out->data.send_initial_metadata.count = send_metadata.count;
|
||||||
|
|
@ -225,7 +243,7 @@ class SendMessageOp : public Op {
|
||||||
Local<Value> flag_value = maybe_flag_value.ToLocalChecked();
|
Local<Value> flag_value = maybe_flag_value.ToLocalChecked();
|
||||||
if (flag_value->IsUint32()) {
|
if (flag_value->IsUint32()) {
|
||||||
Maybe<uint32_t> maybe_flag = Nan::To<uint32_t>(flag_value);
|
Maybe<uint32_t> maybe_flag = Nan::To<uint32_t>(flag_value);
|
||||||
out->flags = maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK;
|
out->flags |= maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
send_message = BufferToByteBuffer(value);
|
send_message = BufferToByteBuffer(value);
|
||||||
|
|
|
||||||
|
|
@ -489,10 +489,29 @@ declare module "grpc" {
|
||||||
type sendUnaryData<ResponseType> =
|
type sendUnaryData<ResponseType> =
|
||||||
(error: ServiceError | null, value: ResponseType | null, trailer?: Metadata, flags?: number) => void;
|
(error: ServiceError | null, value: ResponseType | null, trailer?: Metadata, flags?: number) => void;
|
||||||
|
|
||||||
|
interface MetadataOptions {
|
||||||
|
/* Signal that the request is idempotent. Defaults to false */
|
||||||
|
idempotentRequest?: boolean;
|
||||||
|
/* Signal that the call should not return UNAVAILABLE before it has
|
||||||
|
* started. Defaults to true. */
|
||||||
|
waitForReady?: boolean;
|
||||||
|
/* Signal that the call is cacheable. GRPC is free to use GET verb.
|
||||||
|
* Defaults to false */
|
||||||
|
cacheableRequest?: boolean;
|
||||||
|
/* Signal that the initial metadata should be corked. Defaults to false. */
|
||||||
|
corked?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for storing metadata. Keys are normalized to lowercase ASCII.
|
* A class for storing metadata. Keys are normalized to lowercase ASCII.
|
||||||
*/
|
*/
|
||||||
export class Metadata {
|
export class Metadata {
|
||||||
|
/**
|
||||||
|
* @param options Boolean options for the beginning of the call.
|
||||||
|
* These options only have any effect when passed at the beginning of
|
||||||
|
* a client request.
|
||||||
|
*/
|
||||||
|
constructor(options?: MetadataOptions);
|
||||||
/**
|
/**
|
||||||
* Sets the given value for the given key by replacing any other values
|
* Sets the given value for the given key by replacing any other values
|
||||||
* associated with that key. Normalizes the key.
|
* associated with that key. Normalizes the key.
|
||||||
|
|
@ -536,6 +555,14 @@ declare module "grpc" {
|
||||||
* @return The newly cloned object.
|
* @return The newly cloned object.
|
||||||
*/
|
*/
|
||||||
clone(): Metadata;
|
clone(): Metadata;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set options on the metadata object
|
||||||
|
* @param options Boolean options for the beginning of the call.
|
||||||
|
* These options only have any effect when passed at the beginning of
|
||||||
|
* a client request.
|
||||||
|
*/
|
||||||
|
setOptions(options: MetadataOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MetadataValue = string | Buffer;
|
export type MetadataValue = string | Buffer;
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,36 @@ var clone = require('lodash.clone');
|
||||||
|
|
||||||
var grpc = require('./grpc_extension');
|
var grpc = require('./grpc_extension');
|
||||||
|
|
||||||
|
const IDEMPOTENT_REQUEST_FLAG = 0x10;
|
||||||
|
const WAIT_FOR_READY_FLAG = 0x20;
|
||||||
|
const CACHEABLE_REQUEST_FLAG = 0x40;
|
||||||
|
const WAIT_FOR_READY_EXPLICITLY_SET_FLAG = 0x80;
|
||||||
|
const CORKED_FLAG = 0x100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for storing metadata. Keys are normalized to lowercase ASCII.
|
* Class for storing metadata. Keys are normalized to lowercase ASCII.
|
||||||
* @memberof grpc
|
* @memberof grpc
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @param {Object=} options Boolean options for the beginning of the call.
|
||||||
|
* These options only have any effect when passed at the beginning of
|
||||||
|
* a client request.
|
||||||
|
* @param {boolean=} [options.idempotentRequest=false] Signal that the request
|
||||||
|
* is idempotent
|
||||||
|
* @param {boolean=} [options.waitForReady=true] Signal that the call should
|
||||||
|
* not return UNAVAILABLE before it has started.
|
||||||
|
* @param {boolean=} [options.cacheableRequest=false] Signal that the call is
|
||||||
|
* cacheable. GRPC is free to use GET verb.
|
||||||
|
* @param {boolean=} [options.corked=false] Signal that the initial metadata
|
||||||
|
* should be corked.
|
||||||
* @example
|
* @example
|
||||||
* var metadata = new metadata_module.Metadata();
|
* var metadata = new metadata_module.Metadata();
|
||||||
* metadata.set('key1', 'value1');
|
* metadata.set('key1', 'value1');
|
||||||
* metadata.add('key1', 'value2');
|
* metadata.add('key1', 'value2');
|
||||||
* metadata.get('key1') // returns ['value1', 'value2']
|
* metadata.get('key1') // returns ['value1', 'value2']
|
||||||
*/
|
*/
|
||||||
function Metadata() {
|
function Metadata(options) {
|
||||||
this._internal_repr = {};
|
this._internal_repr = {};
|
||||||
|
this.setOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeKey(key) {
|
function normalizeKey(key) {
|
||||||
|
|
@ -141,34 +159,82 @@ Metadata.prototype.clone = function() {
|
||||||
const value = this._internal_repr[key];
|
const value = this._internal_repr[key];
|
||||||
copy._internal_repr[key] = clone(value);
|
copy._internal_repr[key] = clone(value);
|
||||||
});
|
});
|
||||||
|
copy.flags = this.flags;
|
||||||
return copy;
|
return copy;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set options on the metadata object
|
||||||
|
* @param {Object} options Boolean options for the beginning of the call.
|
||||||
|
* These options only have any effect when passed at the beginning of
|
||||||
|
* a client request.
|
||||||
|
* @param {boolean=} [options.idempotentRequest=false] Signal that the request
|
||||||
|
* is idempotent
|
||||||
|
* @param {boolean=} [options.waitForReady=true] Signal that the call should
|
||||||
|
* not return UNAVAILABLE before it has started.
|
||||||
|
* @param {boolean=} [options.cacheableRequest=false] Signal that the call is
|
||||||
|
* cacheable. GRPC is free to use GET verb.
|
||||||
|
* @param {boolean=} [options.corked=false] Signal that the initial metadata
|
||||||
|
* should be corked.
|
||||||
|
*/
|
||||||
|
Metadata.prototype.setOptions = function(options) {
|
||||||
|
let flags = 0;
|
||||||
|
if (options) {
|
||||||
|
if (options.idempotentRequest) {
|
||||||
|
flags |= IDEMPOTENT_REQUEST_FLAG;
|
||||||
|
}
|
||||||
|
if (options.hasOwnProperty('waitForReady')) {
|
||||||
|
flags |= WAIT_FOR_READY_EXPLICITLY_SET_FLAG;
|
||||||
|
if (options.waitForReady) {
|
||||||
|
flags |= WAIT_FOR_READY_FLAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.cacheableRequest) {
|
||||||
|
flags |= CACHEABLE_REQUEST_FLAG;
|
||||||
|
}
|
||||||
|
if (options.corked) {
|
||||||
|
flags |= CORKED_FLAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata representation as passed to and the native addon
|
||||||
|
* @typedef {object} grpc~CoreMetadata
|
||||||
|
* @param {Object.<String, Array.<String|Buffer>>} metadata The metadata
|
||||||
|
* @param {number} flags Metadata flags
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the metadata in the format used by interal code. Intended for internal
|
* Gets the metadata in the format used by interal code. Intended for internal
|
||||||
* use only. API stability is not guaranteed.
|
* use only. API stability is not guaranteed.
|
||||||
* @private
|
* @private
|
||||||
* @return {Object.<String, Array.<String|Buffer>>} The metadata
|
* @return {grpc~CoreMetadata} The metadata
|
||||||
*/
|
*/
|
||||||
Metadata.prototype._getCoreRepresentation = function() {
|
Metadata.prototype._getCoreRepresentation = function() {
|
||||||
return this._internal_repr;
|
return {
|
||||||
|
metadata: this._internal_repr,
|
||||||
|
flags: this.flags
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Metadata object from a metadata map in the internal format.
|
* Creates a Metadata object from a metadata map in the internal format.
|
||||||
* Intended for internal use only. API stability is not guaranteed.
|
* Intended for internal use only. API stability is not guaranteed.
|
||||||
* @private
|
* @private
|
||||||
* @param {Object.<String, Array.<String|Buffer>>} The metadata
|
* @param {grpc~CoreMetadata} metadata The metadata object from core
|
||||||
* @return {Metadata} The new Metadata object
|
* @return {Metadata} The new Metadata object
|
||||||
*/
|
*/
|
||||||
Metadata._fromCoreRepresentation = function(metadata) {
|
Metadata._fromCoreRepresentation = function(metadata) {
|
||||||
var newMetadata = new Metadata();
|
var newMetadata = new Metadata();
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
Object.keys(metadata).forEach(key => {
|
Object.keys(metadata.metadata).forEach(key => {
|
||||||
const value = metadata[key];
|
const value = metadata.metadata[key];
|
||||||
newMetadata._internal_repr[key] = clone(value);
|
newMetadata._internal_repr[key] = clone(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
newMetadata.flags = metadata.flags;
|
||||||
return newMetadata;
|
return newMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,8 +128,9 @@ describe('call', function() {
|
||||||
var call = channel.createCall('method', getDeadline(1));
|
var call = channel.createCall('method', getDeadline(1));
|
||||||
assert.doesNotThrow(function() {
|
assert.doesNotThrow(function() {
|
||||||
var batch = {};
|
var batch = {};
|
||||||
batch[grpc.opType.SEND_INITIAL_METADATA] = {'key1': ['value1'],
|
batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
||||||
'key2': ['value2']};
|
metadata: {'key1': ['value1'], 'key2': ['value2']}
|
||||||
|
};
|
||||||
call.startBatch(batch, function(err, resp) {
|
call.startBatch(batch, function(err, resp) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.deepEqual(resp, {'send_metadata': true});
|
assert.deepEqual(resp, {'send_metadata': true});
|
||||||
|
|
@ -142,8 +143,10 @@ describe('call', function() {
|
||||||
assert.doesNotThrow(function() {
|
assert.doesNotThrow(function() {
|
||||||
var batch = {};
|
var batch = {};
|
||||||
batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
||||||
|
metadata: {
|
||||||
'key1-bin': [Buffer.from('value1')],
|
'key1-bin': [Buffer.from('value1')],
|
||||||
'key2-bin': [Buffer.from('value2')]
|
'key2-bin': [Buffer.from('value2')]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
call.startBatch(batch, function(err, resp) {
|
call.startBatch(batch, function(err, resp) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
@ -174,6 +177,11 @@ describe('call', function() {
|
||||||
batch[grpc.opType.SEND_INITIAL_METADATA] = 5;
|
batch[grpc.opType.SEND_INITIAL_METADATA] = 5;
|
||||||
call.startBatch(batch, function(){});
|
call.startBatch(batch, function(){});
|
||||||
}, TypeError);
|
}, TypeError);
|
||||||
|
assert.throws(function() {
|
||||||
|
var batch = {};
|
||||||
|
batch[grpc.opType.SEND_INITIAL_METADATA] = {};
|
||||||
|
call.startBatch(batch, function(){});
|
||||||
|
}, TypeError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('startBatch with message', function() {
|
describe('startBatch with message', function() {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ describe('end-to-end', function() {
|
||||||
'dummy_method',
|
'dummy_method',
|
||||||
Infinity);
|
Infinity);
|
||||||
var client_batch = {};
|
var client_batch = {};
|
||||||
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
|
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}};
|
||||||
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||||
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||||
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||||
|
|
@ -74,11 +74,17 @@ describe('end-to-end', function() {
|
||||||
assert.deepEqual(response, {
|
assert.deepEqual(response, {
|
||||||
send_metadata: true,
|
send_metadata: true,
|
||||||
client_close: true,
|
client_close: true,
|
||||||
|
metadata: {
|
||||||
metadata: {},
|
metadata: {},
|
||||||
|
flags: 0
|
||||||
|
},
|
||||||
status: {
|
status: {
|
||||||
code: constants.status.OK,
|
code: constants.status.OK,
|
||||||
details: status_text,
|
details: status_text,
|
||||||
metadata: {}
|
metadata: {
|
||||||
|
metadata: {},
|
||||||
|
flags: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
|
|
@ -90,9 +96,9 @@ describe('end-to-end', function() {
|
||||||
var server_call = new_call.call;
|
var server_call = new_call.call;
|
||||||
assert.notEqual(server_call, null);
|
assert.notEqual(server_call, null);
|
||||||
var server_batch = {};
|
var server_batch = {};
|
||||||
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
|
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}};
|
||||||
server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
||||||
metadata: {},
|
metadata: {metadata: {}},
|
||||||
code: constants.status.OK,
|
code: constants.status.OK,
|
||||||
details: status_text
|
details: status_text
|
||||||
};
|
};
|
||||||
|
|
@ -116,7 +122,9 @@ describe('end-to-end', function() {
|
||||||
Infinity);
|
Infinity);
|
||||||
var client_batch = {};
|
var client_batch = {};
|
||||||
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
||||||
|
metadata: {
|
||||||
client_key: ['client_value']
|
client_key: ['client_value']
|
||||||
|
}
|
||||||
};
|
};
|
||||||
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||||
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||||
|
|
@ -126,10 +134,13 @@ describe('end-to-end', function() {
|
||||||
assert.deepEqual(response,{
|
assert.deepEqual(response,{
|
||||||
send_metadata: true,
|
send_metadata: true,
|
||||||
client_close: true,
|
client_close: true,
|
||||||
metadata: {server_key: ['server_value']},
|
metadata: {metadata: {
|
||||||
|
server_key: ['server_value']},
|
||||||
|
flags: 0
|
||||||
|
},
|
||||||
status: {code: constants.status.OK,
|
status: {code: constants.status.OK,
|
||||||
details: status_text,
|
details: status_text,
|
||||||
metadata: {}}
|
metadata: {metadata: {}, flags: 0}}
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
@ -137,16 +148,18 @@ describe('end-to-end', function() {
|
||||||
server.requestCall(function(err, call_details) {
|
server.requestCall(function(err, call_details) {
|
||||||
var new_call = call_details.new_call;
|
var new_call = call_details.new_call;
|
||||||
assert.notEqual(new_call, null);
|
assert.notEqual(new_call, null);
|
||||||
assert.strictEqual(new_call.metadata.client_key[0],
|
assert.strictEqual(new_call.metadata.metadata.client_key[0],
|
||||||
'client_value');
|
'client_value');
|
||||||
var server_call = new_call.call;
|
var server_call = new_call.call;
|
||||||
assert.notEqual(server_call, null);
|
assert.notEqual(server_call, null);
|
||||||
var server_batch = {};
|
var server_batch = {};
|
||||||
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {
|
||||||
|
metadata: {
|
||||||
server_key: ['server_value']
|
server_key: ['server_value']
|
||||||
|
}
|
||||||
};
|
};
|
||||||
server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
||||||
metadata: {},
|
metadata: {metadata: {}},
|
||||||
code: constants.status.OK,
|
code: constants.status.OK,
|
||||||
details: status_text
|
details: status_text
|
||||||
};
|
};
|
||||||
|
|
@ -171,7 +184,7 @@ describe('end-to-end', function() {
|
||||||
'dummy_method',
|
'dummy_method',
|
||||||
Infinity);
|
Infinity);
|
||||||
var client_batch = {};
|
var client_batch = {};
|
||||||
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
|
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}};
|
||||||
client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(req_text);
|
client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(req_text);
|
||||||
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||||
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||||
|
|
@ -181,12 +194,12 @@ describe('end-to-end', function() {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert(response.send_metadata);
|
assert(response.send_metadata);
|
||||||
assert(response.client_close);
|
assert(response.client_close);
|
||||||
assert.deepEqual(response.metadata, {});
|
assert.deepEqual(response.metadata, {metadata: {}, flags: 0});
|
||||||
assert(response.send_message);
|
assert(response.send_message);
|
||||||
assert.strictEqual(response.read.toString(), reply_text);
|
assert.strictEqual(response.read.toString(), reply_text);
|
||||||
assert.deepEqual(response.status, {code: constants.status.OK,
|
assert.deepEqual(response.status, {code: constants.status.OK,
|
||||||
details: status_text,
|
details: status_text,
|
||||||
metadata: {}});
|
metadata: {metadata: {}, flags: 0}});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -196,7 +209,7 @@ describe('end-to-end', function() {
|
||||||
var server_call = new_call.call;
|
var server_call = new_call.call;
|
||||||
assert.notEqual(server_call, null);
|
assert.notEqual(server_call, null);
|
||||||
var server_batch = {};
|
var server_batch = {};
|
||||||
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
|
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}};
|
||||||
server_batch[grpc.opType.RECV_MESSAGE] = true;
|
server_batch[grpc.opType.RECV_MESSAGE] = true;
|
||||||
server_call.startBatch(server_batch, function(err, response) {
|
server_call.startBatch(server_batch, function(err, response) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
@ -205,7 +218,7 @@ describe('end-to-end', function() {
|
||||||
var response_batch = {};
|
var response_batch = {};
|
||||||
response_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(reply_text);
|
response_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(reply_text);
|
||||||
response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
||||||
metadata: {},
|
metadata: {metadata: {}},
|
||||||
code: constants.status.OK,
|
code: constants.status.OK,
|
||||||
details: status_text
|
details: status_text
|
||||||
};
|
};
|
||||||
|
|
@ -226,7 +239,7 @@ describe('end-to-end', function() {
|
||||||
'dummy_method',
|
'dummy_method',
|
||||||
Infinity);
|
Infinity);
|
||||||
var client_batch = {};
|
var client_batch = {};
|
||||||
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
|
client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}};
|
||||||
client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[0]);
|
client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[0]);
|
||||||
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||||
call.startBatch(client_batch, function(err, response) {
|
call.startBatch(client_batch, function(err, response) {
|
||||||
|
|
@ -234,7 +247,7 @@ describe('end-to-end', function() {
|
||||||
assert.deepEqual(response, {
|
assert.deepEqual(response, {
|
||||||
send_metadata: true,
|
send_metadata: true,
|
||||||
send_message: true,
|
send_message: true,
|
||||||
metadata: {}
|
metadata: {metadata: {}, flags: 0}
|
||||||
});
|
});
|
||||||
var req2_batch = {};
|
var req2_batch = {};
|
||||||
req2_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[1]);
|
req2_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[1]);
|
||||||
|
|
@ -248,7 +261,7 @@ describe('end-to-end', function() {
|
||||||
status: {
|
status: {
|
||||||
code: constants.status.OK,
|
code: constants.status.OK,
|
||||||
details: status_text,
|
details: status_text,
|
||||||
metadata: {}
|
metadata: {metadata: {}, flags: 0}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
|
|
@ -261,7 +274,7 @@ describe('end-to-end', function() {
|
||||||
var server_call = new_call.call;
|
var server_call = new_call.call;
|
||||||
assert.notEqual(server_call, null);
|
assert.notEqual(server_call, null);
|
||||||
var server_batch = {};
|
var server_batch = {};
|
||||||
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
|
server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}};
|
||||||
server_batch[grpc.opType.RECV_MESSAGE] = true;
|
server_batch[grpc.opType.RECV_MESSAGE] = true;
|
||||||
server_call.startBatch(server_batch, function(err, response) {
|
server_call.startBatch(server_batch, function(err, response) {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
|
|
@ -275,7 +288,7 @@ describe('end-to-end', function() {
|
||||||
var end_batch = {};
|
var end_batch = {};
|
||||||
end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
|
end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
|
||||||
end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
|
||||||
metadata: {},
|
metadata: {metadata: {}},
|
||||||
code: constants.status.OK,
|
code: constants.status.OK,
|
||||||
details: status_text
|
details: status_text
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -934,6 +934,19 @@ describe('Other conditions', function() {
|
||||||
call.write({});
|
call.write({});
|
||||||
call.end();
|
call.end();
|
||||||
});
|
});
|
||||||
|
it('client should drop a call if not connected with waitForReady off', 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. */
|
||||||
|
const disconnectedClient = new Client('nothing.invalid:50051', grpc.credentials.createInsecure());
|
||||||
|
const metadata = new grpc.Metadata({waitForReady: false});
|
||||||
|
disconnectedClient.unary({}, metadata, (error, value) =>{
|
||||||
|
assert(error);
|
||||||
|
assert.strictEqual(error.code, grpc.status.UNAVAILABLE);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
describe('Server recieving bad input', function() {
|
describe('Server recieving bad input', function() {
|
||||||
var misbehavingClient;
|
var misbehavingClient;
|
||||||
var badArg = Buffer.from([0xFF]);
|
var badArg = Buffer.from([0xFF]);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue