v1.0.x → master upmerge

Manual changes:

 - Fixed use of Exception.message in _invalid_metadata_test.py

 - Fixed merge of one_failed_as_unavailable in rpc_server_spec.rb

 - Added "set -e" to generate_build_additions.sh
pull/9145/head
Nathaniel Manista 8 years ago
commit 8f7b0b48bf
  1. 6
      gRPC-Core.podspec
  2. 4
      gRPC-ProtoRPC.podspec
  3. 4
      gRPC-RxLibrary.podspec
  4. 4
      gRPC.podspec
  5. 2
      grpc.gemspec
  6. 12
      include/grpc/grpc.h
  7. 13
      src/node/src/client.js
  8. 18
      src/node/src/server.js
  9. 7
      src/objective-c/!ProtoCompiler-gRPCPlugin.podspec
  10. 2
      src/objective-c/GRPCClient/private/GRPCHost.m
  11. 8
      src/python/grpcio/grpc/__init__.py
  12. 128
      src/python/grpcio/grpc/_channel.py
  13. 22
      src/python/grpcio_tests/tests/interop/methods.py
  14. 1
      src/python/grpcio_tests/tests/tests.json
  15. 4
      src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
  16. 175
      src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py
  17. 4
      src/python/grpcio_tests/tests/unit/beta/_utilities_test.py
  18. 1
      src/ruby/ext/grpc/rb_byte_buffer.c
  19. 28
      src/ruby/ext/grpc/rb_server.c
  20. 156
      src/ruby/lib/grpc/errors.rb
  21. 4
      src/ruby/lib/grpc/generic/active_call.rb
  22. 4
      src/ruby/lib/grpc/generic/bidi_call.rb
  23. 3
      src/ruby/lib/grpc/generic/service.rb
  24. 4
      src/ruby/pb/grpc/health/checker.rb
  25. 7
      src/ruby/pb/test/client.rb
  26. 6
      src/ruby/qps/client.rb
  27. 64
      src/ruby/spec/error_sanity_spec.rb
  28. 9
      src/ruby/spec/generic/client_stub_spec.rb
  29. 8
      src/ruby/spec/generic/rpc_server_spec.rb
  30. 8
      src/ruby/spec/pb/health/checker_spec.rb
  31. 2
      src/ruby/spec/spec_helper.rb
  32. 6
      templates/gRPC-Core.podspec.template
  33. 2
      templates/grpc.gemspec.template
  34. 2
      tools/buildgen/generate_build_additions.sh
  35. 2
      tools/run_tests/build_artifact_node.bat
  36. 2
      tools/run_tests/build_artifact_node.sh

@ -35,7 +35,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC-Core' s.name = 'gRPC-Core'
version = '1.0.1' version = '1.0.2'
s.version = version s.version = version
s.summary = 'Core cross-platform gRPC library, written in C' s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -44,7 +44,9 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "v#{version}", # TODO(mxyan): Change back to "v#{version}" for next release
#:tag => "v#{version}",
:tag => "objective-c-v#{version}",
# TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules. # TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules.
:submodules => true, :submodules => true,
} }

@ -30,7 +30,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC-ProtoRPC' s.name = 'gRPC-ProtoRPC'
version = '1.0.1' version = '1.0.2'
s.version = version s.version = version
s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.summary = 'RPC library for Protocol Buffers, based on gRPC'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -39,7 +39,7 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "v#{version}", :tag => "objective-c-v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.1'

@ -30,7 +30,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC-RxLibrary' s.name = 'gRPC-RxLibrary'
version = '1.0.1' version = '1.0.2'
s.version = version s.version = version
s.summary = 'Reactive Extensions library for iOS/OSX.' s.summary = 'Reactive Extensions library for iOS/OSX.'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -39,7 +39,7 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "v#{version}", :tag => "objective-c-v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.1'

@ -30,7 +30,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC' s.name = 'gRPC'
version = '1.0.1' version = '1.0.2'
s.version = version s.version = version
s.summary = 'gRPC client library for iOS/OSX' s.summary = 'gRPC client library for iOS/OSX'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -39,7 +39,7 @@ Pod::Spec.new do |s|
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "v#{version}", :tag => "objective-c-v#{version}",
} }
s.ios.deployment_target = '7.1' s.ios.deployment_target = '7.1'

@ -27,7 +27,7 @@ Gem::Specification.new do |s|
s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb ) s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
s.platform = Gem::Platform::RUBY s.platform = Gem::Platform::RUBY
s.add_dependency 'google-protobuf', '~> 3.0.2' s.add_dependency 'google-protobuf', '~> 3.1.0'
s.add_dependency 'googleauth', '~> 0.5.1' s.add_dependency 'googleauth', '~> 0.5.1'
s.add_development_dependency 'bundler', '~> 1.9' s.add_development_dependency 'bundler', '~> 1.9'

@ -202,9 +202,15 @@ GRPCAPI grpc_call *grpc_channel_create_registered_call(
completion of type 'tag' to the completion queue bound to the call. completion of type 'tag' to the completion queue bound to the call.
The order of ops specified in the batch has no significance. The order of ops specified in the batch has no significance.
Only one operation of each type can be active at once in any given Only one operation of each type can be active at once in any given
batch. You must call grpc_completion_queue_next or batch.
grpc_completion_queue_pluck on the completion queue associated with 'call' If a call to grpc_call_start_batch returns GRPC_CALL_OK you must call
for work to be performed. grpc_completion_queue_next or grpc_completion_queue_pluck on the completion
queue associated with 'call' for work to be performed. If a call to
grpc_call_start_batch returns any value other than GRPC_CALL_OK it is
guaranteed that no state associated with 'call' is changed and it is not
appropriate to call grpc_completion_queue_next or
grpc_completion_queue_pluck consequent to the failed grpc_call_start_batch
call.
THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment
needs to be synchronized. As an optimization, you may synchronize batches needs to be synchronized. As an optimization, you may synchronize batches
containing just send operations independently from batches containing just containing just send operations independently from batches containing just

@ -99,7 +99,18 @@ function ClientWritableStream(call, serialize) {
function _write(chunk, encoding, callback) { function _write(chunk, encoding, callback) {
/* jshint validthis: true */ /* jshint validthis: true */
var batch = {}; var batch = {};
var message = this.serialize(chunk); var message;
try {
message = this.serialize(chunk);
} catch (e) {
/* Sending this error to the server and emitting it immediately on the
client may put the call in a slightly weird state on the client side,
but passing an object that causes a serialization failure is a misuse
of the API anyway, so that's OK. The primary purpose here is to give the
programmer a useful error and to stop the stream properly */
this.call.cancelWithStatus(grpc.status.INTERNAL, "Serialization failure");
callback(e);
}
if (_.isFinite(encoding)) { if (_.isFinite(encoding)) {
/* Attach the encoding if it is a finite number. This is the closest we /* Attach the encoding if it is a finite number. This is the closest we
* can get to checking that it is valid flags */ * can get to checking that it is valid flags */

@ -127,7 +127,14 @@ function sendUnaryResponse(call, value, serialize, metadata, flags) {
(new Metadata())._getCoreRepresentation(); (new Metadata())._getCoreRepresentation();
call.metadataSent = true; call.metadataSent = true;
} }
var message = serialize(value); var message;
try {
message = serialize(value);
} catch (e) {
e.code = grpc.status.INTERNAL;
handleError(e);
return;
}
message.grpcWriteFlags = flags; message.grpcWriteFlags = flags;
end_batch[grpc.opType.SEND_MESSAGE] = message; end_batch[grpc.opType.SEND_MESSAGE] = message;
end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
@ -278,7 +285,14 @@ function _write(chunk, encoding, callback) {
(new Metadata())._getCoreRepresentation(); (new Metadata())._getCoreRepresentation();
this.call.metadataSent = true; this.call.metadataSent = true;
} }
var message = this.serialize(chunk); var message;
try {
message = this.serialize(chunk);
} catch (e) {
e.code = grpc.status.INTERNAL;
callback(e);
return;
}
if (_.isFinite(encoding)) { if (_.isFinite(encoding)) {
/* Attach the encoding if it is a finite number. This is the closest we /* Attach the encoding if it is a finite number. This is the closest we
* can get to checking that it is valid flags */ * can get to checking that it is valid flags */

@ -36,7 +36,7 @@ Pod::Spec.new do |s|
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them. # before them.
s.name = '!ProtoCompiler-gRPCPlugin' s.name = '!ProtoCompiler-gRPCPlugin'
v = '1.0.1' v = '1.0.2'
s.version = v s.version = v
s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
s.description = <<-DESC s.description = <<-DESC
@ -84,7 +84,10 @@ Pod::Spec.new do |s|
repo = 'grpc/grpc' repo = 'grpc/grpc'
file = "grpc_objective_c_plugin-#{v}-macos-x86_64.zip" file = "grpc_objective_c_plugin-#{v}-macos-x86_64.zip"
s.source = { s.source = {
:http => "https://github.com/#{repo}/releases/download/v#{v}/#{file}", # TODO(mxyan): Change back to "https://github.com/#{repo}/releases/download/v#{v}/#{file}" for
# next release
# :http => "https://github.com/#{repo}/releases/download/v#{v}/#{file}",
:http => "https://github.com/#{repo}/releases/download/objective-c-v#{v}/#{file}",
# TODO(jcanizales): Add sha1 or sha256 # TODO(jcanizales): Add sha1 or sha256
# :sha1 => '??', # :sha1 => '??',
} }

@ -50,7 +50,7 @@ NS_ASSUME_NONNULL_BEGIN
// TODO(jcanizales): Generate the version in a standalone header, from templates. Like // TODO(jcanizales): Generate the version in a standalone header, from templates. Like
// templates/src/core/surface/version.c.template . // templates/src/core/surface/version.c.template .
#define GRPC_OBJC_VERSION_STRING @"1.0.1" #define GRPC_OBJC_VERSION_STRING @"1.0.2"
static NSMutableDictionary *kHostCache; static NSMutableDictionary *kHostCache;

@ -768,8 +768,8 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)):
gRPC runtime to determine the status code of the RPC. gRPC runtime to determine the status code of the RPC.
Args: Args:
code: The integer status code of the RPC to be transmitted to the code: A StatusCode value to be transmitted to the invocation side of the
invocation side of the RPC. RPC as the status code of the RPC.
""" """
raise NotImplementedError() raise NotImplementedError()
@ -781,8 +781,8 @@ class ServicerContext(six.with_metaclass(abc.ABCMeta, RpcContext)):
details to transmit. details to transmit.
Args: Args:
details: The details string of the RPC to be transmitted to details: A string to be transmitted to the invocation side of the RPC as
the invocation side of the RPC. the status details of the RPC.
""" """
raise NotImplementedError() raise NotImplementedError()

@ -36,8 +36,8 @@ import time
import grpc import grpc
from grpc import _common from grpc import _common
from grpc import _grpcio_metadata from grpc import _grpcio_metadata
from grpc.framework.foundation import callable_util
from grpc._cython import cygrpc from grpc._cython import cygrpc
from grpc.framework.foundation import callable_util
_USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__) _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
@ -99,6 +99,22 @@ def _wait_once_until(condition, until):
else: else:
condition.wait(timeout=remaining) condition.wait(timeout=remaining)
_INTERNAL_CALL_ERROR_MESSAGE_FORMAT = (
'Internal gRPC call error %d. ' +
'Please report to https://github.com/grpc/grpc/issues')
def _check_call_error(call_error, metadata):
if call_error == cygrpc.CallError.invalid_metadata:
raise ValueError('metadata was invalid: %s' % metadata)
elif call_error != cygrpc.CallError.ok:
raise ValueError(_INTERNAL_CALL_ERROR_MESSAGE_FORMAT % call_error)
def _call_error_set_RPCstate(state, call_error, metadata):
if call_error == cygrpc.CallError.invalid_metadata:
_abort(state, grpc.StatusCode.INTERNAL, 'metadata was invalid: %s' % metadata)
else:
_abort(state, grpc.StatusCode.INTERNAL,
_INTERNAL_CALL_ERROR_MESSAGE_FORMAT % call_error)
class _RPCState(object): class _RPCState(object):
@ -358,7 +374,7 @@ class _Rendezvous(grpc.RpcError, grpc.Future, grpc.Call):
if self._state.callbacks is None: if self._state.callbacks is None:
return False return False
else: else:
self._state.callbacks.append(lambda: callback()) self._state.callbacks.append(callback)
return True return True
def initial_metadata(self): def initial_metadata(self):
@ -435,10 +451,10 @@ def _end_unary_response_blocking(state, with_call, deadline):
class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable): class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
def __init__( def __init__(
self, channel, create_managed_call, method, request_serializer, self, channel, managed_call, method, request_serializer,
response_deserializer): response_deserializer):
self._channel = channel self._channel = channel
self._create_managed_call = create_managed_call self._managed_call = managed_call
self._method = method self._method = method
self._request_serializer = request_serializer self._request_serializer = request_serializer
self._response_deserializer = response_deserializer self._response_deserializer = response_deserializer
@ -472,7 +488,8 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
None, 0, completion_queue, self._method, None, deadline_timespec) None, 0, completion_queue, self._method, None, deadline_timespec)
if credentials is not None: if credentials is not None:
call.set_credentials(credentials._credentials) call.set_credentials(credentials._credentials)
call.start_client_batch(cygrpc.Operations(operations), None) call_error = call.start_client_batch(cygrpc.Operations(operations), None)
_check_call_error(call_error, metadata)
_handle_event(completion_queue.poll(), state, self._response_deserializer) _handle_event(completion_queue.poll(), state, self._response_deserializer)
return state, deadline return state, deadline
@ -490,23 +507,28 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
if rendezvous: if rendezvous:
return rendezvous return rendezvous
else: else:
call = self._create_managed_call( call, drive_call = self._managed_call(
None, 0, self._method, None, deadline_timespec) None, 0, self._method, None, deadline_timespec)
if credentials is not None: if credentials is not None:
call.set_credentials(credentials._credentials) call.set_credentials(credentials._credentials)
event_handler = _event_handler(state, call, self._response_deserializer) event_handler = _event_handler(state, call, self._response_deserializer)
with state.condition: with state.condition:
call.start_client_batch(cygrpc.Operations(operations), event_handler) call_error = call.start_client_batch(cygrpc.Operations(operations),
event_handler)
if call_error != cygrpc.CallError.ok:
_call_error_set_RPCstate(state, call_error, metadata)
return _Rendezvous(state, None, None, deadline)
drive_call()
return _Rendezvous(state, call, self._response_deserializer, deadline) return _Rendezvous(state, call, self._response_deserializer, deadline)
class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable): class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
def __init__( def __init__(
self, channel, create_managed_call, method, request_serializer, self, channel, managed_call, method, request_serializer,
response_deserializer): response_deserializer):
self._channel = channel self._channel = channel
self._create_managed_call = create_managed_call self._managed_call = managed_call
self._method = method self._method = method
self._request_serializer = request_serializer self._request_serializer = request_serializer
self._response_deserializer = response_deserializer self._response_deserializer = response_deserializer
@ -518,7 +540,7 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
raise rendezvous raise rendezvous
else: else:
state = _RPCState(_UNARY_STREAM_INITIAL_DUE, None, None, None, None) state = _RPCState(_UNARY_STREAM_INITIAL_DUE, None, None, None, None)
call = self._create_managed_call( call, drive_call = self._managed_call(
None, 0, self._method, None, deadline_timespec) None, 0, self._method, None, deadline_timespec)
if credentials is not None: if credentials is not None:
call.set_credentials(credentials._credentials) call.set_credentials(credentials._credentials)
@ -535,17 +557,22 @@ class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
cygrpc.operation_send_close_from_client(_EMPTY_FLAGS), cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS), cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
) )
call.start_client_batch(cygrpc.Operations(operations), event_handler) call_error = call.start_client_batch(cygrpc.Operations(operations),
event_handler)
if call_error != cygrpc.CallError.ok:
_call_error_set_RPCstate(state, call_error, metadata)
return _Rendezvous(state, None, None, deadline)
drive_call()
return _Rendezvous(state, call, self._response_deserializer, deadline) return _Rendezvous(state, call, self._response_deserializer, deadline)
class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable): class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
def __init__( def __init__(
self, channel, create_managed_call, method, request_serializer, self, channel, managed_call, method, request_serializer,
response_deserializer): response_deserializer):
self._channel = channel self._channel = channel
self._create_managed_call = create_managed_call self._managed_call = managed_call
self._method = method self._method = method
self._request_serializer = request_serializer self._request_serializer = request_serializer
self._response_deserializer = response_deserializer self._response_deserializer = response_deserializer
@ -569,7 +596,8 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
cygrpc.operation_receive_message(_EMPTY_FLAGS), cygrpc.operation_receive_message(_EMPTY_FLAGS),
cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS), cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
) )
call.start_client_batch(cygrpc.Operations(operations), None) call_error = call.start_client_batch(cygrpc.Operations(operations), None)
_check_call_error(call_error, metadata)
_consume_request_iterator( _consume_request_iterator(
request_iterator, state, call, self._request_serializer) request_iterator, state, call, self._request_serializer)
while True: while True:
@ -597,7 +625,7 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
self, request_iterator, timeout=None, metadata=None, credentials=None): self, request_iterator, timeout=None, metadata=None, credentials=None):
deadline, deadline_timespec = _deadline(timeout) deadline, deadline_timespec = _deadline(timeout)
state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None) state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
call = self._create_managed_call( call, drive_call = self._managed_call(
None, 0, self._method, None, deadline_timespec) None, 0, self._method, None, deadline_timespec)
if credentials is not None: if credentials is not None:
call.set_credentials(credentials._credentials) call.set_credentials(credentials._credentials)
@ -613,7 +641,12 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
cygrpc.operation_receive_message(_EMPTY_FLAGS), cygrpc.operation_receive_message(_EMPTY_FLAGS),
cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS), cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
) )
call.start_client_batch(cygrpc.Operations(operations), event_handler) call_error = call.start_client_batch(cygrpc.Operations(operations),
event_handler)
if call_error != cygrpc.CallError.ok:
_call_error_set_RPCstate(state, call_error, metadata)
return _Rendezvous(state, None, None, deadline)
drive_call()
_consume_request_iterator( _consume_request_iterator(
request_iterator, state, call, self._request_serializer) request_iterator, state, call, self._request_serializer)
return _Rendezvous(state, call, self._response_deserializer, deadline) return _Rendezvous(state, call, self._response_deserializer, deadline)
@ -622,10 +655,10 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable): class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
def __init__( def __init__(
self, channel, create_managed_call, method, request_serializer, self, channel, managed_call, method, request_serializer,
response_deserializer): response_deserializer):
self._channel = channel self._channel = channel
self._create_managed_call = create_managed_call self._managed_call = managed_call
self._method = method self._method = method
self._request_serializer = request_serializer self._request_serializer = request_serializer
self._response_deserializer = response_deserializer self._response_deserializer = response_deserializer
@ -634,7 +667,7 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
self, request_iterator, timeout=None, metadata=None, credentials=None): self, request_iterator, timeout=None, metadata=None, credentials=None):
deadline, deadline_timespec = _deadline(timeout) deadline, deadline_timespec = _deadline(timeout)
state = _RPCState(_STREAM_STREAM_INITIAL_DUE, None, None, None, None) state = _RPCState(_STREAM_STREAM_INITIAL_DUE, None, None, None, None)
call = self._create_managed_call( call, drive_call = self._managed_call(
None, 0, self._method, None, deadline_timespec) None, 0, self._method, None, deadline_timespec)
if credentials is not None: if credentials is not None:
call.set_credentials(credentials._credentials) call.set_credentials(credentials._credentials)
@ -649,7 +682,12 @@ class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
_common.cygrpc_metadata(metadata), _EMPTY_FLAGS), _common.cygrpc_metadata(metadata), _EMPTY_FLAGS),
cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS), cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
) )
call.start_client_batch(cygrpc.Operations(operations), event_handler) call_error = call.start_client_batch(cygrpc.Operations(operations),
event_handler)
if call_error != cygrpc.CallError.ok:
_call_error_set_RPCstate(state, call_error, metadata)
return _Rendezvous(state, None, None, deadline)
drive_call()
_consume_request_iterator( _consume_request_iterator(
request_iterator, state, call, self._request_serializer) request_iterator, state, call, self._request_serializer)
return _Rendezvous(state, call, self._response_deserializer, deadline) return _Rendezvous(state, call, self._response_deserializer, deadline)
@ -687,16 +725,13 @@ def _run_channel_spin_thread(state):
channel_spin_thread.start() channel_spin_thread.start()
def _create_channel_managed_call(state): def _channel_managed_call_management(state):
def create_channel_managed_call(parent, flags, method, host, deadline): def create(parent, flags, method, host, deadline):
"""Creates a managed cygrpc.Call. """Creates a managed cygrpc.Call and a function to call to drive it.
Callers of this function must conduct at least one operation on the returned If operations are successfully added to the returned cygrpc.Call, the
call. The tags associated with operations conducted on the returned call returned function must be called. If operations are not successfully added
must be no-argument callables that return None to indicate that this channel to the returned cygrpc.Call, the returned function must not be called.
should continue polling for events associated with the call and return the
call itself to indicate that no more events associated with the call will be
generated.
Args: Args:
parent: A cygrpc.Call to be used as the parent of the created call. parent: A cygrpc.Call to be used as the parent of the created call.
@ -706,18 +741,22 @@ def _create_channel_managed_call(state):
deadline: A cygrpc.Timespec to be the deadline of the created call. deadline: A cygrpc.Timespec to be the deadline of the created call.
Returns: Returns:
A cygrpc.Call with which to conduct an RPC. A cygrpc.Call with which to conduct an RPC and a function to call if
operations are successfully started on the call.
""" """
with state.lock: call = state.channel.create_call(
call = state.channel.create_call( parent, flags, state.completion_queue, method, host, deadline)
parent, flags, state.completion_queue, method, host, deadline)
if state.managed_calls is None: def drive():
state.managed_calls = set((call,)) with state.lock:
_run_channel_spin_thread(state) if state.managed_calls is None:
else: state.managed_calls = set((call,))
state.managed_calls.add(call) _run_channel_spin_thread(state)
return call else:
return create_channel_managed_call state.managed_calls.add(call)
return call, drive
return create
class _ChannelConnectivityState(object): class _ChannelConnectivityState(object):
@ -847,6 +886,7 @@ def _options(options):
class Channel(grpc.Channel): class Channel(grpc.Channel):
"""A cygrpc.Channel-backed implementation of grpc.Channel."""
def __init__(self, target, options, credentials): def __init__(self, target, options, credentials):
"""Constructor. """Constructor.
@ -871,25 +911,25 @@ class Channel(grpc.Channel):
def unary_unary( def unary_unary(
self, method, request_serializer=None, response_deserializer=None): self, method, request_serializer=None, response_deserializer=None):
return _UnaryUnaryMultiCallable( return _UnaryUnaryMultiCallable(
self._channel, _create_channel_managed_call(self._call_state), self._channel, _channel_managed_call_management(self._call_state),
_common.encode(method), request_serializer, response_deserializer) _common.encode(method), request_serializer, response_deserializer)
def unary_stream( def unary_stream(
self, method, request_serializer=None, response_deserializer=None): self, method, request_serializer=None, response_deserializer=None):
return _UnaryStreamMultiCallable( return _UnaryStreamMultiCallable(
self._channel, _create_channel_managed_call(self._call_state), self._channel, _channel_managed_call_management(self._call_state),
_common.encode(method), request_serializer, response_deserializer) _common.encode(method), request_serializer, response_deserializer)
def stream_unary( def stream_unary(
self, method, request_serializer=None, response_deserializer=None): self, method, request_serializer=None, response_deserializer=None):
return _StreamUnaryMultiCallable( return _StreamUnaryMultiCallable(
self._channel, _create_channel_managed_call(self._call_state), self._channel, _channel_managed_call_management(self._call_state),
_common.encode(method), request_serializer, response_deserializer) _common.encode(method), request_serializer, response_deserializer)
def stream_stream( def stream_stream(
self, method, request_serializer=None, response_deserializer=None): self, method, request_serializer=None, response_deserializer=None):
return _StreamStreamMultiCallable( return _StreamStreamMultiCallable(
self._channel, _create_channel_managed_call(self._call_state), self._channel, _channel_managed_call_management(self._call_state),
_common.encode(method), request_serializer, response_deserializer) _common.encode(method), request_serializer, response_deserializer)
def __del__(self): def __del__(self):

@ -33,7 +33,6 @@ import enum
import json import json
import os import os
import threading import threading
import time
from oauth2client import client as oauth2client_client from oauth2client import client as oauth2client_client
@ -196,16 +195,6 @@ def _server_streaming(stub):
response, messages_pb2.COMPRESSABLE, sizes[index]) response, messages_pb2.COMPRESSABLE, sizes[index])
def _cancel_after_begin(stub):
sizes = (27182, 8, 1828, 45904,)
payloads = (messages_pb2.Payload(body=b'\x00' * size) for size in sizes)
requests = (messages_pb2.StreamingInputCallRequest(payload=payload)
for payload in payloads)
response_future = stub.StreamingInputCall.future(requests)
response_future.cancel()
if not response_future.cancelled():
raise ValueError('expected call to be cancelled')
class _Pipe(object): class _Pipe(object):
@ -265,6 +254,16 @@ def _ping_pong(stub):
response, messages_pb2.COMPRESSABLE, response_size) response, messages_pb2.COMPRESSABLE, response_size)
def _cancel_after_begin(stub):
with _Pipe() as pipe:
response_future = stub.StreamingInputCall.future(pipe)
response_future.cancel()
if not response_future.cancelled():
raise ValueError('expected cancelled method to return True')
if response_future.code() is not grpc.StatusCode.CANCELLED:
raise ValueError('expected status code CANCELLED')
def _cancel_after_first_response(stub): def _cancel_after_first_response(stub):
request_response_sizes = (31415, 9, 2653, 58979,) request_response_sizes = (31415, 9, 2653, 58979,)
request_payload_sizes = (27182, 8, 1828, 45904,) request_payload_sizes = (27182, 8, 1828, 45904,)
@ -302,7 +301,6 @@ def _timeout_on_sleeping_server(stub):
response_type=messages_pb2.COMPRESSABLE, response_type=messages_pb2.COMPRESSABLE,
payload=messages_pb2.Payload(body=b'\x00' * request_payload_size)) payload=messages_pb2.Payload(body=b'\x00' * request_payload_size))
pipe.add(request) pipe.add(request)
time.sleep(0.1)
try: try:
next(response_iterator) next(response_iterator)
except grpc.RpcError as rpc_error: except grpc.RpcError as rpc_error:

@ -27,6 +27,7 @@
"unit._cython.cygrpc_test.TypeSmokeTest", "unit._cython.cygrpc_test.TypeSmokeTest",
"unit._empty_message_test.EmptyMessageTest", "unit._empty_message_test.EmptyMessageTest",
"unit._exit_test.ExitTest", "unit._exit_test.ExitTest",
"unit._invalid_metadata_test.InvalidMetadataTest",
"unit._metadata_code_details_test.MetadataCodeDetailsTest", "unit._metadata_code_details_test.MetadataCodeDetailsTest",
"unit._metadata_test.MetadataTest", "unit._metadata_test.MetadataTest",
"unit._rpc_test.RPCTest", "unit._rpc_test.RPCTest",

@ -64,7 +64,7 @@ class ChannelReadyFutureTest(unittest.TestCase):
ready_future = grpc.channel_ready_future(channel) ready_future = grpc.channel_ready_future(channel)
ready_future.add_done_callback(callback.accept_value) ready_future.add_done_callback(callback.accept_value)
with self.assertRaises(grpc.FutureTimeoutError): with self.assertRaises(grpc.FutureTimeoutError):
ready_future.result(test_constants.SHORT_TIMEOUT) ready_future.result(timeout=test_constants.SHORT_TIMEOUT)
self.assertFalse(ready_future.cancelled()) self.assertFalse(ready_future.cancelled())
self.assertFalse(ready_future.done()) self.assertFalse(ready_future.done())
self.assertTrue(ready_future.running()) self.assertTrue(ready_future.running())
@ -85,7 +85,7 @@ class ChannelReadyFutureTest(unittest.TestCase):
ready_future = grpc.channel_ready_future(channel) ready_future = grpc.channel_ready_future(channel)
ready_future.add_done_callback(callback.accept_value) ready_future.add_done_callback(callback.accept_value)
self.assertIsNone(ready_future.result(test_constants.SHORT_TIMEOUT)) self.assertIsNone(ready_future.result(timeout=test_constants.LONG_TIMEOUT))
value_passed_to_callback = callback.block_until_called() value_passed_to_callback = callback.block_until_called()
self.assertIs(ready_future, value_passed_to_callback) self.assertIs(ready_future, value_passed_to_callback)
self.assertFalse(ready_future.cancelled()) self.assertFalse(ready_future.cancelled())

@ -0,0 +1,175 @@
# Copyright 2016, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Test of RPCs made against gRPC Python's application-layer API."""
import unittest
import grpc
from tests.unit.framework.common import test_constants
_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2
_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:]
_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3
_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3]
_UNARY_UNARY = '/test/UnaryUnary'
_UNARY_STREAM = '/test/UnaryStream'
_STREAM_UNARY = '/test/StreamUnary'
_STREAM_STREAM = '/test/StreamStream'
def _unary_unary_multi_callable(channel):
return channel.unary_unary(_UNARY_UNARY)
def _unary_stream_multi_callable(channel):
return channel.unary_stream(
_UNARY_STREAM,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)
def _stream_unary_multi_callable(channel):
return channel.stream_unary(
_STREAM_UNARY,
request_serializer=_SERIALIZE_REQUEST,
response_deserializer=_DESERIALIZE_RESPONSE)
def _stream_stream_multi_callable(channel):
return channel.stream_stream(_STREAM_STREAM)
class InvalidMetadataTest(unittest.TestCase):
def setUp(self):
self._channel = grpc.insecure_channel('localhost:8080')
self._unary_unary = _unary_unary_multi_callable(self._channel)
self._unary_stream = _unary_stream_multi_callable(self._channel)
self._stream_unary = _stream_unary_multi_callable(self._channel)
self._stream_stream = _stream_stream_multi_callable(self._channel)
def testUnaryRequestBlockingUnaryResponse(self):
request = b'\x07\x08'
metadata = (('InVaLiD', 'UnaryRequestBlockingUnaryResponse'),)
expected_error_details = "metadata was invalid: %s" % metadata
with self.assertRaises(ValueError) as exception_context:
self._unary_unary(request, metadata=metadata)
self.assertIn(expected_error_details, str(exception_context.exception))
def testUnaryRequestBlockingUnaryResponseWithCall(self):
request = b'\x07\x08'
metadata = (('InVaLiD', 'UnaryRequestBlockingUnaryResponseWithCall'),)
expected_error_details = "metadata was invalid: %s" % metadata
with self.assertRaises(ValueError) as exception_context:
self._unary_unary.with_call(request, metadata=metadata)
self.assertIn(expected_error_details, str(exception_context.exception))
def testUnaryRequestFutureUnaryResponse(self):
request = b'\x07\x08'
metadata = (('InVaLiD', 'UnaryRequestFutureUnaryResponse'),)
expected_error_details = "metadata was invalid: %s" % metadata
response_future = self._unary_unary.future(request, metadata=metadata)
with self.assertRaises(grpc.RpcError) as exception_context:
response_future.result()
self.assertEqual(
exception_context.exception.details(), expected_error_details)
self.assertEqual(
exception_context.exception.code(), grpc.StatusCode.INTERNAL)
self.assertEqual(response_future.details(), expected_error_details)
self.assertEqual(response_future.code(), grpc.StatusCode.INTERNAL)
def testUnaryRequestStreamResponse(self):
request = b'\x37\x58'
metadata = (('InVaLiD', 'UnaryRequestStreamResponse'),)
expected_error_details = "metadata was invalid: %s" % metadata
response_iterator = self._unary_stream(request, metadata=metadata)
with self.assertRaises(grpc.RpcError) as exception_context:
next(response_iterator)
self.assertEqual(
exception_context.exception.details(), expected_error_details)
self.assertEqual(
exception_context.exception.code(), grpc.StatusCode.INTERNAL)
self.assertEqual(response_iterator.details(), expected_error_details)
self.assertEqual(response_iterator.code(), grpc.StatusCode.INTERNAL)
def testStreamRequestBlockingUnaryResponse(self):
request_iterator = (b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
metadata = (('InVaLiD', 'StreamRequestBlockingUnaryResponse'),)
expected_error_details = "metadata was invalid: %s" % metadata
with self.assertRaises(ValueError) as exception_context:
self._stream_unary(request_iterator, metadata=metadata)
self.assertIn(expected_error_details, str(exception_context.exception))
def testStreamRequestBlockingUnaryResponseWithCall(self):
request_iterator = (
b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
metadata = (('InVaLiD', 'StreamRequestBlockingUnaryResponseWithCall'),)
expected_error_details = "metadata was invalid: %s" % metadata
multi_callable = _stream_unary_multi_callable(self._channel)
with self.assertRaises(ValueError) as exception_context:
multi_callable.with_call(request_iterator, metadata=metadata)
self.assertIn(expected_error_details, str(exception_context.exception))
def testStreamRequestFutureUnaryResponse(self):
request_iterator = (
b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
metadata = (('InVaLiD', 'StreamRequestFutureUnaryResponse'),)
expected_error_details = "metadata was invalid: %s" % metadata
response_future = self._stream_unary.future(
request_iterator, metadata=metadata)
with self.assertRaises(grpc.RpcError) as exception_context:
response_future.result()
self.assertEqual(
exception_context.exception.details(), expected_error_details)
self.assertEqual(
exception_context.exception.code(), grpc.StatusCode.INTERNAL)
self.assertEqual(response_future.details(), expected_error_details)
self.assertEqual(response_future.code(), grpc.StatusCode.INTERNAL)
def testStreamRequestStreamResponse(self):
request_iterator = (
b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
metadata = (('InVaLiD', 'StreamRequestStreamResponse'),)
expected_error_details = "metadata was invalid: %s" % metadata
response_iterator = self._stream_stream(request_iterator, metadata=metadata)
with self.assertRaises(grpc.RpcError) as exception_context:
next(response_iterator)
self.assertEqual(
exception_context.exception.details(), expected_error_details)
self.assertEqual(
exception_context.exception.code(), grpc.StatusCode.INTERNAL)
self.assertEqual(response_iterator.details(), expected_error_details)
self.assertEqual(response_iterator.code(), grpc.StatusCode.INTERNAL)
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -66,7 +66,7 @@ class ChannelConnectivityTest(unittest.TestCase):
ready_future = utilities.channel_ready_future(channel) ready_future = utilities.channel_ready_future(channel)
ready_future.add_done_callback(callback.accept_value) ready_future.add_done_callback(callback.accept_value)
with self.assertRaises(future.TimeoutError): with self.assertRaises(future.TimeoutError):
ready_future.result(test_constants.SHORT_TIMEOUT) ready_future.result(timeout=test_constants.SHORT_TIMEOUT)
self.assertFalse(ready_future.cancelled()) self.assertFalse(ready_future.cancelled())
self.assertFalse(ready_future.done()) self.assertFalse(ready_future.done())
self.assertTrue(ready_future.running()) self.assertTrue(ready_future.running())
@ -88,7 +88,7 @@ class ChannelConnectivityTest(unittest.TestCase):
ready_future = utilities.channel_ready_future(channel) ready_future = utilities.channel_ready_future(channel)
ready_future.add_done_callback(callback.accept_value) ready_future.add_done_callback(callback.accept_value)
self.assertIsNone( self.assertIsNone(
ready_future.result(test_constants.SHORT_TIMEOUT)) ready_future.result(timeout=test_constants.LONG_TIMEOUT))
value_passed_to_callback = callback.block_until_called() value_passed_to_callback = callback.block_until_called()
self.assertIs(ready_future, value_passed_to_callback) self.assertIs(ready_future, value_passed_to_callback)
self.assertFalse(ready_future.cancelled()) self.assertFalse(ready_future.cancelled())

@ -65,5 +65,6 @@ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
GRPC_SLICE_LENGTH(next)); GRPC_SLICE_LENGTH(next));
grpc_slice_unref(next); grpc_slice_unref(next);
} }
grpc_byte_buffer_reader_destroy(&reader);
return rb_string; return rb_string;
} }

@ -37,6 +37,7 @@
#include "rb_server.h" #include "rb_server.h"
#include <grpc/grpc.h> #include <grpc/grpc.h>
#include <grpc/support/atm.h>
#include <grpc/grpc_security.h> #include <grpc/grpc_security.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "rb_call.h" #include "rb_call.h"
@ -59,22 +60,26 @@ typedef struct grpc_rb_server {
/* The actual server */ /* The actual server */
grpc_server *wrapped; grpc_server *wrapped;
grpc_completion_queue *queue; grpc_completion_queue *queue;
gpr_atm shutdown_started;
} grpc_rb_server; } grpc_rb_server;
static void destroy_server(grpc_rb_server *server, gpr_timespec deadline) { static void destroy_server(grpc_rb_server *server, gpr_timespec deadline) {
grpc_event ev; grpc_event ev;
if (server->wrapped != NULL) { // This can be started by app or implicitly by GC. Avoid a race between these.
grpc_server_shutdown_and_notify(server->wrapped, server->queue, NULL); if (gpr_atm_full_fetch_add(&server->shutdown_started, (gpr_atm)1) == 0) {
ev = rb_completion_queue_pluck(server->queue, NULL, deadline, NULL); if (server->wrapped != NULL) {
if (ev.type == GRPC_QUEUE_TIMEOUT) { grpc_server_shutdown_and_notify(server->wrapped, server->queue, NULL);
grpc_server_cancel_all_calls(server->wrapped); ev = rb_completion_queue_pluck(server->queue, NULL, deadline, NULL);
rb_completion_queue_pluck(server->queue, NULL, if (ev.type == GRPC_QUEUE_TIMEOUT) {
gpr_inf_future(GPR_CLOCK_REALTIME), NULL); grpc_server_cancel_all_calls(server->wrapped);
rb_completion_queue_pluck(server->queue, NULL,
gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
}
grpc_server_destroy(server->wrapped);
grpc_rb_completion_queue_destroy(server->queue);
server->wrapped = NULL;
server->queue = NULL;
} }
grpc_server_destroy(server->wrapped);
grpc_rb_completion_queue_destroy(server->queue);
server->wrapped = NULL;
server->queue = NULL;
} }
} }
@ -115,6 +120,7 @@ static const rb_data_type_t grpc_rb_server_data_type = {
static VALUE grpc_rb_server_alloc(VALUE cls) { static VALUE grpc_rb_server_alloc(VALUE cls) {
grpc_rb_server *wrapper = ALLOC(grpc_rb_server); grpc_rb_server *wrapper = ALLOC(grpc_rb_server);
wrapper->wrapped = NULL; wrapper->wrapped = NULL;
wrapper->shutdown_started = (gpr_atm)0;
return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper); return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper);
} }

@ -35,9 +35,18 @@ module GRPC
# either end of a GRPC connection. When raised, it indicates that a status # either end of a GRPC connection. When raised, it indicates that a status
# error should be returned to the other end of a GRPC connection; when # error should be returned to the other end of a GRPC connection; when
# caught it means that this end received a status error. # caught it means that this end received a status error.
#
# There is also subclass of BadStatus in this module for each GRPC status.
# E.g., the GRPC::Cancelled class corresponds to status CANCELLED.
#
# See
# https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/status.h
# for detailed descriptions of each status code.
class BadStatus < StandardError class BadStatus < StandardError
attr_reader :code, :details, :metadata attr_reader :code, :details, :metadata
include GRPC::Core::StatusCodes
# @param code [Numeric] the status code # @param code [Numeric] the status code
# @param details [String] the details of the exception # @param details [String] the details of the exception
# @param metadata [Hash] the error's metadata # @param metadata [Hash] the error's metadata
@ -55,9 +64,152 @@ module GRPC
def to_status def to_status
Struct::Status.new(code, details, @metadata) Struct::Status.new(code, details, @metadata)
end end
def self.new_status_exception(code, details = 'unkown cause', metadata = {})
codes = {}
codes[OK] = Ok
codes[CANCELLED] = Cancelled
codes[UNKNOWN] = Unknown
codes[INVALID_ARGUMENT] = InvalidArgument
codes[DEADLINE_EXCEEDED] = DeadlineExceeded
codes[NOT_FOUND] = NotFound
codes[ALREADY_EXISTS] = AlreadyExists
codes[PERMISSION_DENIED] = PermissionDenied
codes[UNAUTHENTICATED] = Unauthenticated
codes[RESOURCE_EXHAUSTED] = ResourceExhausted
codes[FAILED_PRECONDITION] = FailedPrecondition
codes[ABORTED] = Aborted
codes[OUT_OF_RANGE] = OutOfRange
codes[UNIMPLEMENTED] = Unimplemented
codes[INTERNAL] = Internal
codes[UNIMPLEMENTED] = Unimplemented
codes[UNAVAILABLE] = Unavailable
codes[DATA_LOSS] = DataLoss
if codes[code].nil?
BadStatus.new(code, details, metadata)
else
codes[code].new(details, metadata)
end
end
end
# GRPC status code corresponding to status OK
class Ok < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::OK, details, metadata)
end
end end
# Cancelled is an exception class that indicates that an rpc was cancelled. # GRPC status code corresponding to status CANCELLED
class Cancelled < StandardError class Cancelled < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::CANCELLED, details, metadata)
end
end
# GRPC status code corresponding to status UNKNOWN
class Unknown < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::UNKNOWN, details, metadata)
end
end
# GRPC status code corresponding to status INVALID_ARGUMENT
class InvalidArgument < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::INVALID_ARGUMENT, details, metadata)
end
end
# GRPC status code corresponding to status DEADLINE_EXCEEDED
class DeadlineExceeded < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::DEADLINE_EXCEEDED, details, metadata)
end
end
# GRPC status code corresponding to status NOT_FOUND
class NotFound < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::NOT_FOUND, details, metadata)
end
end
# GRPC status code corresponding to status ALREADY_EXISTS
class AlreadyExists < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::ALREADY_EXISTS, details, metadata)
end
end
# GRPC status code corresponding to status PERMISSION_DENIED
class PermissionDenied < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::PERMISSION_DENIED, details, metadata)
end
end
# GRPC status code corresponding to status UNAUTHENTICATED
class Unauthenticated < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::UNAUTHENTICATED, details, metadata)
end
end
# GRPC status code corresponding to status RESOURCE_EXHAUSTED
class ResourceExhausted < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::RESOURCE_EXHAUSTED, details, metadata)
end
end
# GRPC status code corresponding to status FAILED_PRECONDITION
class FailedPrecondition < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::FAILED_PRECONDITION, details, metadata)
end
end
# GRPC status code corresponding to status ABORTED
class Aborted < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::ABORTED, details, metadata)
end
end
# GRPC status code corresponding to status OUT_OF_RANGE
class OutOfRange < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::OUT_OF_RANGE, details, metadata)
end
end
# GRPC status code corresponding to status UNIMPLEMENTED
class Unimplemented < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::UNIMPLEMENTED, details, metadata)
end
end
# GRPC status code corresponding to status INTERNAL
class Internal < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::INTERNAL, details, metadata)
end
end
# GRPC status code corresponding to status UNAVAILABLE
class Unavailable < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::UNAVAILABLE, details, metadata)
end
end
# GRPC status code corresponding to status DATA_LOSS
class DataLoss < BadStatus
def initialize(details = 'unknown cause', metadata = {})
super(Core::StatusCodes::DATA_LOSS, details, metadata)
end
end end
end end

@ -43,8 +43,8 @@ class Struct
GRPC.logger.debug("Failing with status #{status}") GRPC.logger.debug("Failing with status #{status}")
# raise BadStatus, propagating the metadata if present. # raise BadStatus, propagating the metadata if present.
md = status.metadata md = status.metadata
fail GRPC::BadStatus.new(status.code, status.details, md), fail GRPC::BadStatus.new_status_exception(
"status code: #{status.code}, details: #{status.details}" status.code, status.details, md)
end end
status status
end end

@ -219,6 +219,10 @@ module GRPC
GRPC.logger.debug('bidi-read-loop: finished') GRPC.logger.debug('bidi-read-loop: finished')
@reads_complete = true @reads_complete = true
finished finished
# Make sure that the write loop is done done before finishing the call.
# Note that blocking is ok at this point because we've already received
# a status
@enq_th.join if is_client
end end
end end
end end

@ -111,7 +111,8 @@ module GRPC
marshal_class_method, marshal_class_method,
unmarshal_class_method) unmarshal_class_method)
define_method(GenericService.underscore(name.to_s).to_sym) do define_method(GenericService.underscore(name.to_s).to_sym) do
fail GRPC::BadStatus, GRPC::Core::StatusCodes::UNIMPLEMENTED fail GRPC::BadStatus.new_status_exception(
GRPC::Core::StatusCodes::UNIMPLEMENTED)
end end
end end

@ -52,7 +52,9 @@ module Grpc
@status_mutex.synchronize do @status_mutex.synchronize do
status = @statuses["#{req.service}"] status = @statuses["#{req.service}"]
end end
fail GRPC::BadStatus, StatusCodes::NOT_FOUND if status.nil? if status.nil?
fail GRPC::BadStatus.new_status_exception(StatusCodes::NOT_FOUND)
end
HealthCheckResponse.new(status: status) HealthCheckResponse.new(status: status)
end end

@ -459,11 +459,8 @@ class NamedTests
deadline = GRPC::Core::TimeConsts::from_relative_time(1) deadline = GRPC::Core::TimeConsts::from_relative_time(1)
resps = @stub.full_duplex_call(enum.each_item, deadline: deadline) resps = @stub.full_duplex_call(enum.each_item, deadline: deadline)
resps.each { } # wait to receive each request (or timeout) resps.each { } # wait to receive each request (or timeout)
fail 'Should have raised GRPC::BadStatus(DEADLINE_EXCEEDED)' fail 'Should have raised GRPC::DeadlineExceeded'
rescue GRPC::BadStatus => e rescue GRPC::DeadlineExceeded
assert("#{__callee__}: status was wrong") do
e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
end
end end
def empty_stream def empty_stream

@ -134,6 +134,7 @@ class BenchmarkClient
resp = stub.streaming_call(q.each_item) resp = stub.streaming_call(q.each_item)
start = Time.now start = Time.now
q.push(req) q.push(req)
pushed_sentinal = false
resp.each do |r| resp.each do |r|
@histogram.add((Time.now-start)*1e9) @histogram.add((Time.now-start)*1e9)
if !@done if !@done
@ -141,8 +142,9 @@ class BenchmarkClient
start = Time.now start = Time.now
q.push(req) q.push(req)
else else
q.push(self) q.push(self) unless pushed_sentinal
break # Continue polling on the responses to consume and release resources
pushed_sentinal = true
end end
end end
end end

@ -0,0 +1,64 @@
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc'
StatusCodes = GRPC::Core::StatusCodes
describe StatusCodes do
# convert upper snake-case to camel case.
# e.g., DEADLINE_EXCEEDED -> DeadlineExceeded
def upper_snake_to_camel(name)
name.to_s.split('_').map(&:downcase).map(&:capitalize).join('')
end
StatusCodes.constants.each do |status_name|
it 'there is a subclass of BadStatus corresponding to StatusCode: ' \
"#{status_name} that has code: #{StatusCodes.const_get(status_name)}" do
camel_case = upper_snake_to_camel(status_name)
error_class = GRPC.const_get(camel_case)
# expect the error class to be a subclass of BadStatus
expect(error_class < GRPC::BadStatus)
error_object = error_class.new
# check that the code matches the int value of the error's constant
status_code = StatusCodes.const_get(status_name)
expect(error_object.code).to eq(status_code)
# check default parameters
expect(error_object.details).to eq('unknown cause')
expect(error_object.metadata).to eq({})
# check that the BadStatus factory for creates the correct
# exception too
from_factory = GRPC::BadStatus.new_status_exception(status_code)
expect(from_factory.is_a?(error_class)).to be(true)
end
end
end

@ -190,15 +190,14 @@ describe 'ClientStub' do
end end
creds = GRPC::Core::CallCredentials.new(failing_auth) creds = GRPC::Core::CallCredentials.new(failing_auth)
error_occured = false unauth_error_occured = false
begin begin
get_response(stub, credentials: creds) get_response(stub, credentials: creds)
rescue GRPC::BadStatus => e rescue GRPC::Unauthenticated => e
error_occured = true unauth_error_occured = true
expect(e.code).to eq(GRPC::Core::StatusCodes::UNAUTHENTICATED)
expect(e.details.include?(error_message)).to be true expect(e.details.include?(error_message)).to be true
end end
expect(error_occured).to eq(true) expect(unauth_error_occured).to eq(true)
# Kill the server thread so tests can complete # Kill the server thread so tests can complete
th.kill th.kill

@ -408,21 +408,21 @@ describe GRPC::RpcServer do
req = EchoMsg.new req = EchoMsg.new
n = 20 # arbitrary, use as many to ensure the server pool is exceeded n = 20 # arbitrary, use as many to ensure the server pool is exceeded
threads = [] threads = []
bad_status_code = nil one_failed_as_unavailable = false
n.times do n.times do
threads << Thread.new do threads << Thread.new do
stub = SlowStub.new(alt_host, :this_channel_is_insecure) stub = SlowStub.new(alt_host, :this_channel_is_insecure)
begin begin
stub.an_rpc(req) stub.an_rpc(req)
rescue GRPC::BadStatus => e rescue GRPC::ResourceExhausted
bad_status_code = e.code one_failed_as_unavailable = true
end end
end end
end end
threads.each(&:join) threads.each(&:join)
alt_srv.stop alt_srv.stop
t.join t.join
expect(bad_status_code).to be(StatusCodes::RESOURCE_EXHAUSTED) expect(one_failed_as_unavailable).to be(true)
end end
end end

@ -122,7 +122,7 @@ describe Grpc::Health::Checker do
checker.check(HCReq.new(service: t[:service]), nil) checker.check(HCReq.new(service: t[:service]), nil)
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::NotFound, expected_msg
end end
end end
end end
@ -141,7 +141,7 @@ describe Grpc::Health::Checker do
checker.check(HCReq.new(service: t[:service]), nil) checker.check(HCReq.new(service: t[:service]), nil)
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::NotFound, expected_msg
end end
end end
end end
@ -163,7 +163,7 @@ describe Grpc::Health::Checker do
checker.check(HCReq.new(service: t[:service]), nil) checker.check(HCReq.new(service: t[:service]), nil)
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::NotFound, expected_msg
end end
end end
end end
@ -214,7 +214,7 @@ describe Grpc::Health::Checker do
stub.check(HCReq.new(service: 'unknown')) stub.check(HCReq.new(service: 'unknown'))
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::NotFound, expected_msg
@srv.stop @srv.stop
t.join t.join
end end

@ -67,3 +67,5 @@ RSpec.configure do |config|
end end
RSpec::Expectations.configuration.warn_about_potential_false_positives = false RSpec::Expectations.configuration.warn_about_potential_false_positives = false
Thread.abort_on_exception = true

@ -62,7 +62,7 @@
%> %>
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'gRPC-Core' s.name = 'gRPC-Core'
version = '1.0.1' version = '1.0.2'
s.version = version s.version = version
s.summary = 'Core cross-platform gRPC library, written in C' s.summary = 'Core cross-platform gRPC library, written in C'
s.homepage = 'http://www.grpc.io' s.homepage = 'http://www.grpc.io'
@ -71,7 +71,9 @@
s.source = { s.source = {
:git => 'https://github.com/grpc/grpc.git', :git => 'https://github.com/grpc/grpc.git',
:tag => "v#{version}", # TODO(mxyan): Change back to "v#{version}" for next release
#:tag => "v#{version}",
:tag => "objective-c-v#{version}",
# TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules. # TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules.
:submodules => true, :submodules => true,
} }

@ -29,7 +29,7 @@
s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb ) s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
s.platform = Gem::Platform::RUBY s.platform = Gem::Platform::RUBY
s.add_dependency 'google-protobuf', '~> 3.0.2' s.add_dependency 'google-protobuf', '~> 3.1.0'
s.add_dependency 'googleauth', '~> 0.5.1' s.add_dependency 'googleauth', '~> 0.5.1'
s.add_development_dependency 'bundler', '~> 1.9' s.add_development_dependency 'bundler', '~> 1.9'

@ -28,6 +28,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
gen_build_yaml_dirs=" \ gen_build_yaml_dirs=" \
src/boringssl \ src/boringssl \
src/benchmark \ src/benchmark \

@ -27,7 +27,7 @@
@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE @rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set node_versions=0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 set node_versions=0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0
set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm

@ -42,7 +42,7 @@ mkdir -p artifacts
npm update npm update
node_versions=( 0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 ) node_versions=( 0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0 )
for version in ${node_versions[@]} for version in ${node_versions[@]}
do do

Loading…
Cancel
Save