Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"extend": "^3.0.0",
"google-auto-auth": "^0.2.4",
"google-proto-files": "^0.7.0",
"grpc": "^0.14.1",
"grpc": "^1.0.0",
"is": "^3.0.1",
"methmeth": "^1.0.0",
"modelo": "^4.2.0",
Expand Down
41 changes: 26 additions & 15 deletions packages/common/src/grpc-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,21 @@ GrpcService.createDeadline_ = function(timeout) {
return new Date(Date.now() + timeout);
};

/**
* Checks for a grpc status code and extends the error object with additional
* information.
*
* @private
*
* @param {error|object} err - The grpc error.
* @return {error|null}
*/
GrpcService.decorateError_ = function(err) {
var errorObj = is.error(err) ? err : {};

return GrpcService.decorateGrpcResponse_(errorObj, err);
};

/**
* Checks for a grpc status code and extends the supplied object with additional
* information.
Expand All @@ -471,30 +486,26 @@ GrpcService.createDeadline_ = function(timeout) {
GrpcService.decorateGrpcResponse_ = function(obj, response) {
if (response && GRPC_ERROR_CODE_TO_HTTP[response.code]) {
var defaultResponseDetails = GRPC_ERROR_CODE_TO_HTTP[response.code];
var message = defaultResponseDetails.message;

if (response.message) {
// gRPC error messages can be either stringified JSON or strings.
try {
message = JSON.parse(response.message).description;
} catch(e) {
message = response.message;
}
}

return extend(true, obj, response, {
code: defaultResponseDetails.code,
message: response.message || defaultResponseDetails.message
message: message
});
}

return null;
};

/**
* Checks for a grpc status code and extends the error object with additional
* information.
*
* @private
*
* @param {error|object} err - The grpc error.
* @return {error|null}
*/
GrpcService.decorateError_ = function(err) {
var errorObj = is.error(err) ? new Error() : {};
return GrpcService.decorateGrpcResponse_(errorObj, err);
};

/**
* Checks for grpc status code and extends the status object with additional
* information
Expand Down
83 changes: 49 additions & 34 deletions packages/common/test/grpc-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,40 @@ describe('GrpcService', function() {
});
});

describe('decorateError_', function() {
var expectedDecoratedError = new Error('err.');

beforeEach(function() {
sinon.stub(GrpcService, 'decorateGrpcResponse_', function() {
return expectedDecoratedError;
});
});

it('should decorate an Error object', function() {
var grpcError = new Error('Hello');
grpcError.code = 2;

var decoratedError = GrpcService.decorateError_(grpcError);
var decorateArgs = GrpcService.decorateGrpcResponse_.getCall(0).args;

assert.strictEqual(decoratedError, expectedDecoratedError);
assert.strictEqual(decorateArgs[0] instanceof Error, true);
assert.strictEqual(decorateArgs[1], grpcError);
});

it('should decorate a plain object', function() {
var grpcMessage = { code: 2 };

var decoratedError = GrpcService.decorateError_(grpcMessage);
var decorateArgs = GrpcService.decorateGrpcResponse_.getCall(0).args;

assert.strictEqual(decoratedError, expectedDecoratedError);
assert.deepEqual(decorateArgs[0], {});
assert.strictEqual(decorateArgs[0] instanceof Error, false);
assert.strictEqual(decorateArgs[1], grpcMessage);
});
});

describe('decorateGrpcResponse_', function() {
it('should retrieve the HTTP code from the gRPC error map', function() {
var errorMap = GrpcService.GRPC_ERROR_CODE_TO_HTTP;
Expand Down Expand Up @@ -1165,46 +1199,27 @@ describe('GrpcService', function() {
assert.strictEqual(extended.message, errorMessage);
});

it('should return null for unknown errors', function() {
var error = new Error();
var extended = GrpcService.decorateGrpcResponse_(error, { code: 9999 });

assert.strictEqual(extended, null);
});
});

describe('decorateError_', function() {
var fakeError = new Error('err.');

beforeEach(function() {
sinon.stub(GrpcService, 'decorateGrpcResponse_', function() {
return fakeError;
});
});

it('should call decorateGrpcResponse_ with an error object', function() {
var grpcError = new Error('err.');
it('should use a stringified JSON message from the error', function() {
var errorMessage = 'This is an error message.';

grpcError.code = 2;
var err = {
code: 1,
message: JSON.stringify({
description: errorMessage
})
};

var error = GrpcService.decorateError_(grpcError);
var args = GrpcService.decorateGrpcResponse_.getCall(0).args;
var error = new Error();
var extended = GrpcService.decorateGrpcResponse_(error, err);

assert.strictEqual(fakeError, error);
assert(args[0] instanceof Error);
assert.strictEqual(args[1], grpcError);
assert.strictEqual(extended.message, errorMessage);
});

it('should call decorateGrpcResponse_ with a plain object', function() {
var grpcMessage = { code: 2 };

var error = GrpcService.decorateError_(grpcMessage);
var args = GrpcService.decorateGrpcResponse_.getCall(0).args;
it('should return null for unknown errors', function() {
var error = new Error();
var extended = GrpcService.decorateGrpcResponse_(error, { code: 9999 });

assert.strictEqual(fakeError, error);
assert.deepEqual(args[0], {});
assert(!(args[0] instanceof Error));
assert.strictEqual(args[1], grpcMessage);
assert.strictEqual(extended, null);
});
});

Expand Down