aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/node/index.js50
-rw-r--r--src/node/src/client.js7
-rw-r--r--src/node/src/common.js30
-rw-r--r--src/node/src/server.js7
-rw-r--r--src/node/test/common_test.js52
-rw-r--r--src/node/test/test_messages.proto5
-rw-r--r--tools/run_tests/run_node.bat2
-rwxr-xr-xtools/run_tests/run_node.sh9
-rwxr-xr-xtools/run_tests/run_tests.py4
9 files changed, 135 insertions, 31 deletions
diff --git a/src/node/index.js b/src/node/index.js
index 7eacdc67b1..1c197729d7 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -56,17 +56,18 @@ var grpc = require('./src/grpc_extension');
/**
* Load a gRPC object from an existing ProtoBuf.Reflect object.
* @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
+ * @param {Object=} options Options to apply to the loaded object
* @return {Object<string, *>} The resulting gRPC object
*/
-exports.loadObject = function loadObject(value) {
+exports.loadObject = function loadObject(value, options) {
var result = {};
if (value.className === 'Namespace') {
_.each(value.children, function(child) {
- result[child.name] = loadObject(child);
+ result[child.name] = loadObject(child, options);
});
return result;
} else if (value.className === 'Service') {
- return client.makeProtobufClientConstructor(value);
+ return client.makeProtobufClientConstructor(value, options);
} else if (value.className === 'Message' || value.className === 'Enum') {
return value.build();
} else {
@@ -77,28 +78,45 @@ exports.loadObject = function loadObject(value) {
var loadObject = exports.loadObject;
/**
- * Load a gRPC object from a .proto file.
- * @param {string} filename The file to load
+ * Load a gRPC object from a .proto file. The options object can provide the
+ * following options:
+ * - convertFieldsToCamelCase: Loads this file with that option on protobuf.js
+ * set as specified. See
+ * https://github.com/dcodeIO/protobuf.js/wiki/Advanced-options for details
+ * - binaryAsBase64: deserialize bytes values as base64 strings instead of
+ * Buffers. Defaults to false
+ * - longsAsStrings: deserialize long values as strings instead of objects.
+ * Defaults to true
+ * @param {string|{root: string, file: string}} filename The file to load
* @param {string=} format The file format to expect. Must be either 'proto' or
* 'json'. Defaults to 'proto'
+ * @param {Object=} options Options to apply to the loaded file
* @return {Object<string, *>} The resulting gRPC object
*/
-exports.load = function load(filename, format) {
+exports.load = function load(filename, format, options) {
if (!format) {
format = 'proto';
}
+ var convertFieldsToCamelCaseOriginal = ProtoBuf.convertFieldsToCamelCase;
+ if(options && options.hasOwnProperty('convertFieldsToCamelCase')) {
+ ProtoBuf.convertFieldsToCamelCase = options.convertFieldsToCamelCase;
+ }
var builder;
- switch(format) {
- case 'proto':
- builder = ProtoBuf.loadProtoFile(filename);
- break;
- case 'json':
- builder = ProtoBuf.loadJsonFile(filename);
- break;
- default:
- throw new Error('Unrecognized format "' + format + '"');
+ try {
+ switch(format) {
+ case 'proto':
+ builder = ProtoBuf.loadProtoFile(filename);
+ break;
+ case 'json':
+ builder = ProtoBuf.loadJsonFile(filename);
+ break;
+ default:
+ throw new Error('Unrecognized format "' + format + '"');
+ }
+ } finally {
+ ProtoBuf.convertFieldsToCamelCase = convertFieldsToCamelCaseOriginal;
}
- return loadObject(builder.ns);
+ return loadObject(builder.ns, options);
};
/**
diff --git a/src/node/src/client.js b/src/node/src/client.js
index b5247a69ee..c02c44730e 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -698,13 +698,16 @@ exports.waitForClientReady = function(client, deadline, callback) {
* Creates a constructor for clients for the given service
* @param {ProtoBuf.Reflect.Service} service The service to generate a client
* for
+ * @param {Object=} options Options to apply to the client
* @return {function(string, Object)} New client constructor
*/
-exports.makeProtobufClientConstructor = function(service) {
- var method_attrs = common.getProtobufServiceAttrs(service, service.name);
+exports.makeProtobufClientConstructor = function(service, options) {
+ var method_attrs = common.getProtobufServiceAttrs(service, service.name,
+ options);
var Client = exports.makeClientConstructor(
method_attrs, common.fullyQualifiedName(service));
Client.service = service;
+ Client.service.grpc_options = options;
return Client;
};
diff --git a/src/node/src/common.js b/src/node/src/common.js
index 2e6c01c4d7..e5217608ec 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -44,9 +44,20 @@ var _ = require('lodash');
/**
* Get a function that deserializes a specific type of protobuf.
* @param {function()} cls The constructor of the message type to deserialize
+ * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
+ * instead of Buffers. Defaults to false
+ * @param {bool=} longsAsStrings Deserialize long values as strings instead of
+ * objects. Defaults to true
* @return {function(Buffer):cls} The deserialization function
*/
-exports.deserializeCls = function deserializeCls(cls) {
+exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
+ longsAsStrings) {
+ if (binaryAsBase64 === undefined || binaryAsBase64 === null) {
+ binaryAsBase64 = false;
+ }
+ if (longsAsStrings === undefined || longsAsStrings === null) {
+ longsAsStrings = true;
+ }
/**
* Deserialize a buffer to a message object
* @param {Buffer} arg_buf The buffer to deserialize
@@ -55,7 +66,7 @@ exports.deserializeCls = function deserializeCls(cls) {
return function deserialize(arg_buf) {
// Convert to a native object with binary fields as Buffers (first argument)
// and longs as strings (second argument)
- return cls.decode(arg_buf).toRaw(false, true);
+ return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
};
};
@@ -119,19 +130,28 @@ exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
/**
* Return a map from method names to method attributes for the service.
* @param {ProtoBuf.Reflect.Service} service The service to get attributes for
+ * @param {Object=} options Options to apply to these attributes
* @return {Object} The attributes map
*/
-exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service) {
+exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
+ options) {
var prefix = '/' + fullyQualifiedName(service) + '/';
+ var binaryAsBase64, longsAsStrings;
+ if (options) {
+ binaryAsBase64 = options.binaryAsBase64;
+ longsAsStrings = options.longsAsStrings;
+ }
return _.object(_.map(service.children, function(method) {
return [_.camelCase(method.name), {
path: prefix + method.name,
requestStream: method.requestStream,
responseStream: method.responseStream,
requestSerialize: serializeCls(method.resolvedRequestType.build()),
- requestDeserialize: deserializeCls(method.resolvedRequestType.build()),
+ requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
+ binaryAsBase64, longsAsStrings),
responseSerialize: serializeCls(method.resolvedResponseType.build()),
- responseDeserialize: deserializeCls(method.resolvedResponseType.build())
+ responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
+ binaryAsBase64, longsAsStrings)
}];
}));
};
diff --git a/src/node/src/server.js b/src/node/src/server.js
index e5aadcd565..0cf7ba3424 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -737,7 +737,12 @@ Server.prototype.addService = function(service, implementation) {
* method implementation for the provided service.
*/
Server.prototype.addProtoService = function(service, implementation) {
- this.addService(common.getProtobufServiceAttrs(service), implementation);
+ var options;
+ if (service.grpc_options) {
+ options = service.grpc_options;
+ }
+ this.addService(common.getProtobufServiceAttrs(service, options),
+ implementation);
};
/**
diff --git a/src/node/test/common_test.js b/src/node/test/common_test.js
index 08ba429ed7..66a4205f82 100644
--- a/src/node/test/common_test.js
+++ b/src/node/test/common_test.js
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,7 @@ var ProtoBuf = require('protobufjs');
var messages_proto = ProtoBuf.loadProtoFile(
__dirname + '/test_messages.proto').build();
-describe('Proto message serialize and deserialize', function() {
+describe('Proto message long int serialize and deserialize', function() {
var longSerialize = common.serializeCls(messages_proto.LongValues);
var longDeserialize = common.deserializeCls(messages_proto.LongValues);
var pos_value = '314159265358979';
@@ -87,4 +87,52 @@ describe('Proto message serialize and deserialize', function() {
assert.strictEqual(longDeserialize(serialized).sfixed_64.toString(),
neg_value);
});
+ it('should deserialize as a number with the right option set', function() {
+ var longNumDeserialize = common.deserializeCls(messages_proto.LongValues,
+ false, false);
+ var serialized = longSerialize({int_64: pos_value});
+ assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string');
+ /* With the longsAsStrings option disabled, long values are represented as
+ * objects with 3 keys: low, high, and unsigned */
+ assert.strictEqual(typeof longNumDeserialize(serialized).int_64, 'object');
+ });
+});
+describe('Proto message bytes serialize and deserialize', function() {
+ var sequenceSerialize = common.serializeCls(messages_proto.SequenceValues);
+ var sequenceDeserialize = common.deserializeCls(
+ messages_proto.SequenceValues);
+ var sequenceBase64Deserialize = common.deserializeCls(
+ messages_proto.SequenceValues, true);
+ var buffer_val = new Buffer([0x69, 0xb7]);
+ var base64_val = 'abc=';
+ it('should preserve a buffer', function() {
+ var serialized = sequenceSerialize({bytes_field: buffer_val});
+ var deserialized = sequenceDeserialize(serialized);
+ assert.strictEqual(deserialized.bytes_field.compare(buffer_val), 0);
+ });
+ it('should accept base64 encoded strings', function() {
+ var serialized = sequenceSerialize({bytes_field: base64_val});
+ var deserialized = sequenceDeserialize(serialized);
+ assert.strictEqual(deserialized.bytes_field.compare(buffer_val), 0);
+ });
+ it('should output base64 encoded strings with an option set', function() {
+ var serialized = sequenceSerialize({bytes_field: base64_val});
+ var deserialized = sequenceBase64Deserialize(serialized);
+ assert.strictEqual(deserialized.bytes_field, base64_val);
+ });
+ /* The next two tests are specific tests to verify that issue
+ * https://github.com/grpc/grpc/issues/5174 has been fixed. They are skipped
+ * because they will not pass until a protobuf.js release has been published
+ * with a fix for https://github.com/dcodeIO/protobuf.js/issues/390 */
+ it.skip('should serialize a repeated field as packed by default', function() {
+ var expected_serialize = new Buffer([0x12, 0x01, 0x01, 0x0a]);
+ var serialized = sequenceSerialize({repeated_field: [10]});
+ assert.strictEqual(expected_serialize.compare(serialized), 0);
+ });
+ it.skip('should deserialize packed or unpacked repeated', function() {
+ var serialized = new Buffer([0x12, 0x01, 0x01, 0x0a]);
+ assert.doesNotThrow(function() {
+ sequenceDeserialize(serialized);
+ });
+ });
});
diff --git a/src/node/test/test_messages.proto b/src/node/test/test_messages.proto
index c77a937d3f..9b8cb875ee 100644
--- a/src/node/test/test_messages.proto
+++ b/src/node/test/test_messages.proto
@@ -36,3 +36,8 @@ message LongValues {
fixed64 fixed_64 = 4;
sfixed64 sfixed_64 = 5;
}
+
+message SequenceValues {
+ bytes bytes_field = 1;
+ repeated int32 repeated_field = 2;
+}
diff --git a/tools/run_tests/run_node.bat b/tools/run_tests/run_node.bat
index f5cf01f095..ad9ca14b8b 100644
--- a/tools/run_tests/run_node.bat
+++ b/tools/run_tests/run_node.bat
@@ -29,4 +29,4 @@
set JUNIT_REPORT_PATH=src\node\reports.xml
set JUNIT_REPORT_STACK=1
-.\node_modules\.bin\mocha.cmd --reporter mocha-jenkins-reporter src\node\test \ No newline at end of file
+.\node_modules\.bin\mocha.cmd --reporter mocha-jenkins-reporter --timeout 8000 src\node\test \ No newline at end of file
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh
index 40f61d77cc..178584ae8e 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/run_node.sh
@@ -41,10 +41,13 @@ cd $(dirname $0)/../..
root=`pwd`
+test_directory='src/node/test'
+timeout=8000
+
if [ "$CONFIG" = "gcov" ]
then
./node_modules/.bin/istanbul cover --dir reports/node_coverage \
- -x **/interop/* ./node_modules/.bin/_mocha -- --timeout 8000 src/node/test
+ -x **/interop/* ./node_modules/.bin/_mocha -- --timeout $timeout $test_directory
cd build
gcov Release/obj.target/grpc/ext/*.o
lcov --base-directory . --directory . -c -o coverage.info
@@ -55,5 +58,7 @@ then
echo '<html><head><meta http-equiv="refresh" content="0;URL=lcov-report/index.html"></head></html>' > \
../reports/node_coverage/index.html
else
- JUNIT_REPORT_PATH=src/node/reports.xml JUNIT_REPORT_STACK=1 ./node_modules/.bin/mocha --reporter mocha-jenkins-reporter src/node/test
+ JUNIT_REPORT_PATH=src/node/reports.xml JUNIT_REPORT_STACK=1 \
+ ./node_modules/.bin/mocha --timeout $timeout \
+ --reporter mocha-jenkins-reporter $test_directory
fi
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index de3716bc88..0b3efa29e3 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -334,13 +334,14 @@ class RubyLanguage(object):
def test_specs(self, config, args):
return [config.job_spec(['tools/run_tests/run_ruby.sh'], None,
+ timeout_seconds=10*60,
environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
def pre_build_steps(self):
return [['tools/run_tests/pre_build_ruby.sh']]
def make_targets(self, test_regex):
- return ['static_c']
+ return []
def make_options(self):
return []
@@ -1197,4 +1198,3 @@ else:
if BuildAndRunError.POST_TEST in errors:
exit_code |= 4
sys.exit(exit_code)
-