Adds support for trailing metadata

- removes the status class, replacing it with a Struct
- adds support for trailing metadata, merging into the call's initial metadata

- tracks []
	Change on 2014/12/15 by temiola <temiola@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=82193372
pull/1/merge
temiola 10 years ago committed by Nicolas Noble
parent d8fd853cba
commit 5832791292
  1. 21
      src/ruby/ext/grpc/rb_call.c
  2. 23
      src/ruby/ext/grpc/rb_event.c
  3. 3
      src/ruby/ext/grpc/rb_event.h
  4. 36
      src/ruby/ext/grpc/rb_grpc.c
  5. 244
      src/ruby/ext/grpc/rb_status.c
  6. 53
      src/ruby/ext/grpc/rb_status.h
  7. 16
      src/ruby/lib/grpc/generic/active_call.rb
  8. 19
      src/ruby/spec/call_spec.rb
  9. 9
      src/ruby/spec/client_server_spec.rb
  10. 166
      src/ruby/spec/status_spec.rb

@ -38,8 +38,8 @@
#include <grpc/grpc.h>
#include "rb_byte_buffer.h"
#include "rb_completion_queue.h"
#include "rb_event.h"
#include "rb_metadata.h"
#include "rb_status.h"
#include "rb_grpc.h"
/* id_cq is the name of the hidden ivar that preserves a reference to a
@ -270,8 +270,8 @@ static VALUE grpc_rb_call_get_status(VALUE self) {
Saves a status object on the call. */
static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
if (!NIL_P(status) && rb_obj_class(status) != rb_cStatus) {
rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Status>",
if (!NIL_P(status) && rb_obj_class(status) != rb_sStatus) {
rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Struct::Status>",
rb_obj_classname(status));
return Qnil;
}
@ -344,6 +344,11 @@ static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
}
/* Queue a status for writing.
call-seq:
tag = Object.new
call.write_status(200, "OK", tag)
REQUIRES: No other writes are pending on the call. It is only safe to
start the next write after the corresponding write_accepted event
is received.
@ -352,13 +357,13 @@ static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
Only callable on the server.
Produces a GRPC_FINISHED event when the status is sent and the stream is
fully closed */
static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE status,
VALUE tag) {
static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE code,
VALUE status, VALUE tag) {
grpc_call *call = NULL;
grpc_status *sts = grpc_rb_get_wrapped_status(status);
grpc_call_error err;
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_write_status(call, *sts, ROBJECT(tag));
err = grpc_call_start_write_status(call, NUM2UINT(code),
StringValueCStr(status), ROBJECT(tag));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "start write status: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@ -522,7 +527,7 @@ void Init_google_rpc_call() {
rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1);
rb_define_method(rb_cCall, "start_write", grpc_rb_call_start_write, -1);
rb_define_method(rb_cCall, "start_write_status",
grpc_rb_call_start_write_status, 2);
grpc_rb_call_start_write_status, 3);
rb_define_method(rb_cCall, "writes_done", grpc_rb_call_writes_done, 1);
rb_define_method(rb_cCall, "status", grpc_rb_call_get_status, 0);
rb_define_method(rb_cCall, "status=", grpc_rb_call_set_status, 1);

@ -40,7 +40,6 @@
#include "rb_byte_buffer.h"
#include "rb_call.h"
#include "rb_metadata.h"
#include "rb_status.h"
/* rb_mCompletionType is a ruby module that holds the completion type values */
VALUE rb_mCompletionType = Qnil;
@ -132,6 +131,11 @@ static VALUE grpc_rb_event_metadata(VALUE self) {
metadata = event->data.client_metadata_read.elements;
break;
case GRPC_FINISHED:
count = event->data.finished.metadata_count;
metadata = event->data.finished.metadata_elements;
break;
case GRPC_SERVER_RPC_NEW:
count = event->data.server_rpc_new.metadata_count;
metadata = event->data.server_rpc_new.metadata_elements;
@ -139,8 +143,9 @@ static VALUE grpc_rb_event_metadata(VALUE self) {
default:
rb_raise(rb_eRuntimeError,
"bug: bad event type reading server metadata. got %d; want %d",
event->type, GRPC_SERVER_RPC_NEW);
"bug: bad event type metadata. got %d; want %d|%d:%d",
event->type, GRPC_CLIENT_METADATA_READ, GRPC_FINISHED,
GRPC_SERVER_RPC_NEW);
return Qnil;
}
@ -212,7 +217,13 @@ static VALUE grpc_rb_event_result(VALUE self) {
return grpc_rb_event_metadata(self);
case GRPC_FINISHED:
return grpc_rb_status_create_with_mark(self, &event->data.finished);
return rb_struct_new(
rb_sStatus,
UINT2NUM(event->data.finished.status),
(event->data.finished.details == NULL ?
Qnil : rb_str_new2(event->data.finished.details)),
grpc_rb_event_metadata(self),
NULL);
break;
case GRPC_SERVER_RPC_NEW:
@ -237,6 +248,9 @@ static VALUE grpc_rb_event_result(VALUE self) {
/* rb_sNewServerRpc is the struct that holds new server rpc details. */
VALUE rb_sNewServerRpc = Qnil;
/* rb_sStatus is the struct that holds status details. */
VALUE rb_sStatus = Qnil;
/* rb_cEvent is the Event class whose instances proxy grpc_event */
VALUE rb_cEvent = Qnil;
@ -250,6 +264,7 @@ void Init_google_rpc_event() {
rb_cEvent = rb_define_class_under(rb_mGoogleRpcCore, "Event", rb_cObject);
rb_sNewServerRpc = rb_struct_define("NewServerRpc", "method", "host",
"deadline", "metadata", NULL);
rb_sStatus = rb_struct_define("Status", "code", "details", "metadata", NULL);
/* Prevent allocation or inialization from ruby. */
rb_define_alloc_func(rb_cEvent, grpc_rb_cannot_alloc);

@ -39,6 +39,9 @@
/* rb_sNewServerRpc is the struct that holds new server rpc details. */
extern VALUE rb_sNewServerRpc;
/* rb_sStruct is the struct that holds status details. */
extern VALUE rb_sStatus;
/* rb_cEvent is the Event class whose instances proxy grpc_event. */
extern VALUE rb_cEvent;

@ -48,7 +48,6 @@
#include "rb_server.h"
#include "rb_credentials.h"
#include "rb_server_credentials.h"
#include "rb_status.h"
/* Define common vars and funcs declared in rb.h */
const RUBY_DATA_FUNC GC_NOT_MARKED = NULL;
@ -157,6 +156,39 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
return t;
}
void Init_google_status_codes() {
/* Constants representing the status codes or grpc_status_code in status.h */
VALUE rb_mStatusCodes = rb_define_module_under(rb_mGoogleRpcCore,
"StatusCodes");
rb_define_const(rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
rb_define_const(rb_mStatusCodes, "CANCELLED", INT2NUM(GRPC_STATUS_CANCELLED));
rb_define_const(rb_mStatusCodes, "UNKNOWN", INT2NUM(GRPC_STATUS_UNKNOWN));
rb_define_const(rb_mStatusCodes, "INVALID_ARGUMENT",
INT2NUM(GRPC_STATUS_INVALID_ARGUMENT));
rb_define_const(rb_mStatusCodes, "DEADLINE_EXCEEDED",
INT2NUM(GRPC_STATUS_DEADLINE_EXCEEDED));
rb_define_const(rb_mStatusCodes, "NOT_FOUND", INT2NUM(GRPC_STATUS_NOT_FOUND));
rb_define_const(rb_mStatusCodes, "ALREADY_EXISTS",
INT2NUM(GRPC_STATUS_ALREADY_EXISTS));
rb_define_const(rb_mStatusCodes, "PERMISSION_DENIED",
INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
rb_define_const(rb_mStatusCodes, "UNAUTHENTICATED",
INT2NUM(GRPC_STATUS_UNAUTHENTICATED));
rb_define_const(rb_mStatusCodes, "RESOURCE_EXHAUSTED",
INT2NUM(GRPC_STATUS_RESOURCE_EXHAUSTED));
rb_define_const(rb_mStatusCodes, "FAILED_PRECONDITION",
INT2NUM(GRPC_STATUS_FAILED_PRECONDITION));
rb_define_const(rb_mStatusCodes, "ABORTED", INT2NUM(GRPC_STATUS_ABORTED));
rb_define_const(rb_mStatusCodes, "OUT_OF_RANGE",
INT2NUM(GRPC_STATUS_OUT_OF_RANGE));
rb_define_const(rb_mStatusCodes, "UNIMPLEMENTED",
INT2NUM(GRPC_STATUS_UNIMPLEMENTED));
rb_define_const(rb_mStatusCodes, "INTERNAL", INT2NUM(GRPC_STATUS_INTERNAL));
rb_define_const(rb_mStatusCodes, "UNAVAILABLE",
INT2NUM(GRPC_STATUS_UNAVAILABLE));
rb_define_const(rb_mStatusCodes, "DATA_LOSS", INT2NUM(GRPC_STATUS_DATA_LOSS));
}
/* id_at is the constructor method of the ruby standard Time class. */
static ID id_at;
@ -233,6 +265,6 @@ void Init_grpc() {
Init_google_rpc_metadata();
Init_google_rpc_server();
Init_google_rpc_server_credentials();
Init_google_rpc_status();
Init_google_status_codes();
Init_google_time_consts();
}

@ -1,244 +0,0 @@
/*
*
* Copyright 2014, 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.
*
*/
#include "rb_status.h"
#include <ruby.h>
#include <string.h>
#include <grpc/grpc.h>
#include <grpc/status.h>
#include "rb_grpc.h"
/* grpc_rb_status wraps a grpc_status. It provides a peer ruby object, 'mark'
* to minimize copying when a status is created from ruby. */
typedef struct grpc_rb_status {
/* Holder of ruby objects involved in constructing the status */
VALUE mark;
/* The actual status */
grpc_status *wrapped;
} grpc_rb_status;
/* Destroys Status instances. */
static void grpc_rb_status_free(void *p) {
grpc_rb_status *status = NULL;
if (p == NULL) {
return;
};
status = (grpc_rb_status *)p;
/* Delete the wrapped object if the mark object is Qnil, which indicates that
* no other object is the actual owner. */
if (status->wrapped != NULL && status->mark == Qnil) {
status->mark = Qnil;
if (status->wrapped->details) {
xfree(status->wrapped->details);
}
xfree(status->wrapped);
}
xfree(p);
}
/* Protects the mark object from GC */
static void grpc_rb_status_mark(void *p) {
grpc_rb_status *status = NULL;
if (p == NULL) {
return;
}
status = (grpc_rb_status *)p;
/* If it's not already cleaned up, mark the mark object */
if (status->mark != Qnil) {
rb_gc_mark(status->mark);
}
}
/* Allocates Status instances.
Provides safe initial defaults for the instance fields. */
static VALUE grpc_rb_status_alloc(VALUE cls) {
grpc_rb_status *wrapper = ALLOC(grpc_rb_status);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
return Data_Wrap_Struct(cls, grpc_rb_status_mark, grpc_rb_status_free,
wrapper);
}
/* The name of the attribute used on the mark object to hold the details. */
static ID id_details;
/* Initializes Status instances. */
static VALUE grpc_rb_status_init(VALUE self, VALUE code, VALUE details) {
grpc_rb_status *wrapper = NULL;
grpc_status *status = NULL;
Data_Get_Struct(self, grpc_rb_status, wrapper);
/* Use a direct pointer to the original detail value to avoid copying. Assume
* that details is null-terminated. */
status = ALLOC(grpc_status);
status->details = StringValueCStr(details);
status->code = NUM2INT(code);
wrapper->wrapped = status;
/* Create the mark and add the original details object to it. */
wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
rb_ivar_set(wrapper->mark, id_details, details);
return self;
}
/* Clones Status instances.
Gives Status a consistent implementation of Ruby's object copy/dup
protocol. */
static VALUE grpc_rb_status_init_copy(VALUE copy, VALUE orig) {
grpc_rb_status *orig_status = NULL;
grpc_rb_status *copy_status = NULL;
if (copy == orig) {
return copy;
}
/* Raise an error if orig is not a Status object or a subclass. */
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_status_free) {
rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cStatus));
}
Data_Get_Struct(orig, grpc_rb_status, orig_status);
Data_Get_Struct(copy, grpc_rb_status, copy_status);
MEMCPY(copy_status, orig_status, grpc_rb_status, 1);
return copy;
}
/* Gets the Status code. */
static VALUE grpc_rb_status_code(VALUE self) {
grpc_rb_status *status = NULL;
Data_Get_Struct(self, grpc_rb_status, status);
return INT2NUM(status->wrapped->code);
}
/* Gets the Status details. */
static VALUE grpc_rb_status_details(VALUE self) {
VALUE from_ruby;
grpc_rb_status *wrapper = NULL;
grpc_status *status;
Data_Get_Struct(self, grpc_rb_status, wrapper);
if (wrapper->mark != Qnil) {
from_ruby = rb_ivar_get(wrapper->mark, id_details);
if (from_ruby != Qnil) {
return from_ruby;
}
}
status = wrapper->wrapped;
if (status == NULL || status->details == NULL) {
return Qnil;
}
return rb_str_new2(status->details);
}
void Init_google_status_codes() {
/* Constants representing the status codes or grpc_status_code in status.h */
VALUE rb_mStatusCodes = rb_define_module_under(rb_mGoogleRpcCore,
"StatusCodes");
rb_define_const(rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
rb_define_const(rb_mStatusCodes, "CANCELLED", INT2NUM(GRPC_STATUS_CANCELLED));
rb_define_const(rb_mStatusCodes, "UNKNOWN", INT2NUM(GRPC_STATUS_UNKNOWN));
rb_define_const(rb_mStatusCodes, "INVALID_ARGUMENT",
INT2NUM(GRPC_STATUS_INVALID_ARGUMENT));
rb_define_const(rb_mStatusCodes, "DEADLINE_EXCEEDED",
INT2NUM(GRPC_STATUS_DEADLINE_EXCEEDED));
rb_define_const(rb_mStatusCodes, "NOT_FOUND", INT2NUM(GRPC_STATUS_NOT_FOUND));
rb_define_const(rb_mStatusCodes, "ALREADY_EXISTS",
INT2NUM(GRPC_STATUS_ALREADY_EXISTS));
rb_define_const(rb_mStatusCodes, "PERMISSION_DENIED",
INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
rb_define_const(rb_mStatusCodes, "UNAUTHENTICATED",
INT2NUM(GRPC_STATUS_UNAUTHENTICATED));
rb_define_const(rb_mStatusCodes, "RESOURCE_EXHAUSTED",
INT2NUM(GRPC_STATUS_RESOURCE_EXHAUSTED));
rb_define_const(rb_mStatusCodes, "FAILED_PRECONDITION",
INT2NUM(GRPC_STATUS_FAILED_PRECONDITION));
rb_define_const(rb_mStatusCodes, "ABORTED", INT2NUM(GRPC_STATUS_ABORTED));
rb_define_const(rb_mStatusCodes, "OUT_OF_RANGE",
INT2NUM(GRPC_STATUS_OUT_OF_RANGE));
rb_define_const(rb_mStatusCodes, "UNIMPLEMENTED",
INT2NUM(GRPC_STATUS_UNIMPLEMENTED));
rb_define_const(rb_mStatusCodes, "INTERNAL", INT2NUM(GRPC_STATUS_INTERNAL));
rb_define_const(rb_mStatusCodes, "UNAVAILABLE",
INT2NUM(GRPC_STATUS_UNAVAILABLE));
rb_define_const(rb_mStatusCodes, "DATA_LOSS", INT2NUM(GRPC_STATUS_DATA_LOSS));
}
/* rb_cStatus is the Status class whose instances proxy grpc_status. */
VALUE rb_cStatus = Qnil;
/* Initializes the Status class. */
void Init_google_rpc_status() {
rb_cStatus = rb_define_class_under(rb_mGoogleRpcCore, "Status", rb_cObject);
/* Allocates an object whose memory is managed by the Ruby. */
rb_define_alloc_func(rb_cStatus, grpc_rb_status_alloc);
/* Provides a ruby constructor and support for dup/clone. */
rb_define_method(rb_cStatus, "initialize", grpc_rb_status_init, 2);
rb_define_method(rb_cStatus, "initialize_copy", grpc_rb_status_init_copy, 1);
/* Provides accessors for the code and details. */
rb_define_method(rb_cStatus, "code", grpc_rb_status_code, 0);
rb_define_method(rb_cStatus, "details", grpc_rb_status_details, 0);
id_details = rb_intern("__details");
Init_google_status_codes();
}
VALUE grpc_rb_status_create_with_mark(VALUE mark, grpc_status* s) {
grpc_rb_status *status = NULL;
if (s == NULL) {
return Qnil;
}
status = ALLOC(grpc_rb_status);
status->wrapped = s;
status->mark = mark;
return Data_Wrap_Struct(rb_cStatus, grpc_rb_status_mark, grpc_rb_status_free,
status);
}
/* Gets the wrapped status from the ruby wrapper */
grpc_status* grpc_rb_get_wrapped_status(VALUE v) {
grpc_rb_status *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_status, wrapper);
return wrapper->wrapped;
}

@ -1,53 +0,0 @@
/*
*
* Copyright 2014, 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.
*
*/
#ifndef GRPC_RB_STATUS_H_
#define GRPC_RB_STATUS_H_
#include <grpc/grpc.h>
#include <ruby.h>
/* rb_cStatus is the Status class whose instances proxy grpc_status. */
extern VALUE rb_cStatus;
/* grpc_rb_status_create_with_mark creates a grpc_rb_status with a ruby mark
* object that will be kept alive while the status is alive. */
extern VALUE grpc_rb_status_create_with_mark(VALUE mark, grpc_status *s);
/* Gets the wrapped status from the ruby wrapper object */
grpc_status* grpc_rb_get_wrapped_status(VALUE v);
/* Initializes the Status class. */
void Init_google_rpc_status();
#endif /* GRPC_RB_STATUS_H_ */

@ -207,6 +207,12 @@ module Google::RPC
def finished
ev = @cq.pluck(@finished_tag, INFINITE_FUTURE)
raise "unexpected event: #{ev.inspect}" unless ev.type == FINISHED
if @call.metadata.nil?
@call.metadata = ev.result.metadata
else
@call.metadata.merge!(ev.result.metadata)
end
if ev.result.code != Core::StatusCodes::OK
raise BadStatus.new(ev.result.code, ev.result.details)
end
@ -252,7 +258,7 @@ module Google::RPC
# FINISHED.
def send_status(code=OK, details='', assert_finished=false)
assert_queue_is_ready
@call.start_write_status(Core::Status.new(code, details), self)
@call.start_write_status(code, details, self)
ev = @cq.pluck(self, INFINITE_FUTURE)
assert_event_type(ev, FINISH_ACCEPTED)
logger.debug("Status sent: #{code}:'#{details}'")
@ -310,7 +316,7 @@ module Google::RPC
return enum_for(:each_remote_read) if !block_given?
loop do
resp = remote_read()
break if resp.is_a?Core::Status # is an OK status, bad statii raise
break if resp.is_a?Struct::Status # is an OK status, bad statii raise
break if resp.nil? # the last response was received
yield resp
end
@ -340,7 +346,7 @@ module Google::RPC
return enum_for(:each_remote_read_then_finish) if !block_given?
loop do
resp = remote_read
break if resp.is_a?Core::Status # is an OK status, bad statii raise
break if resp.is_a?Struct::Status # is an OK status, bad statii raise
if resp.nil? # the last response was received, but not finished yet
finished
break
@ -363,7 +369,7 @@ module Google::RPC
remote_send(req)
writes_done(false)
response = remote_read
if !response.is_a?(Core::Status) # finish if status not yet received
if !response.is_a?(Struct::Status) # finish if status not yet received
finished
end
response
@ -388,7 +394,7 @@ module Google::RPC
requests.each { |r| remote_send(r) }
writes_done(false)
response = remote_read
if !response.is_a?(Core::Status) # finish if status not yet received
if !response.is_a?(Struct::Status) # finish if status not yet received
finished
end
response

@ -88,29 +88,30 @@ describe GRPC::Core::Call do
describe '#start_read' do
it 'should fail if called immediately' do
expect { make_test_call.start_read(@tag) }.to raise_error GRPC::Core::CallError
blk = Proc.new { make_test_call.start_read(@tag) }
expect(&blk).to raise_error GRPC::Core::CallError
end
end
describe '#start_write' do
it 'should fail if called immediately' do
bytes = GRPC::Core::ByteBuffer.new('test string')
expect { make_test_call.start_write(bytes, @tag) }
.to raise_error GRPC::Core::CallError
blk = Proc.new { make_test_call.start_write(bytes, @tag) }
expect(&blk).to raise_error GRPC::Core::CallError
end
end
describe '#start_write_status' do
it 'should fail if called immediately' do
sts = GRPC::Core::Status.new(153, 'test detail')
expect { make_test_call.start_write_status(sts, @tag) }
.to raise_error GRPC::Core::CallError
blk = Proc.new { make_test_call.start_write_status(153, 'x', @tag) }
expect(&blk).to raise_error GRPC::Core::CallError
end
end
describe '#writes_done' do
it 'should fail if called immediately' do
expect { make_test_call.writes_done(@tag) }.to raise_error GRPC::Core::CallError
blk = Proc.new { make_test_call.writes_done(Object.new) }
expect(&blk).to raise_error GRPC::Core::CallError
end
end
@ -153,9 +154,9 @@ describe GRPC::Core::Call do
describe '#status' do
it 'can save the status and read it back' do
call = make_test_call
sts = GRPC::Core::Status.new(OK, 'OK')
sts = Struct::Status.new(OK, 'OK')
expect { call.status = sts }.not_to raise_error
expect(call.status).to be(sts)
expect(call.status).to eq(sts)
end
it 'must be set to a status' do

@ -154,8 +154,8 @@ shared_examples 'basic GRPC message delivery is OK' do
server_call = ev.call
server_call.server_accept(@server_queue, @server_finished_tag)
server_call.server_end_initial_metadata()
sts = Status.new(StatusCodes::NOT_FOUND, 'not found')
server_call.start_write_status(sts, @server_tag)
server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found',
@server_tag)
# client gets an empty response for the read, preceeded by some metadata.
call.start_read(@tag)
@ -175,8 +175,7 @@ shared_examples 'basic GRPC message delivery is OK' do
call = new_client_call
client_sends(call)
server_call = server_receives_and_responds_with('server_response')
sts = Status.new(10101, 'status code is 10101')
server_call.start_write_status(sts, @server_tag)
server_call.start_write_status(10101, 'status code is 10101', @server_tag)
# first the client says writes are done
call.start_read(@tag)
@ -187,7 +186,7 @@ shared_examples 'basic GRPC message delivery is OK' do
# but nothing happens until the server sends a status
expect_next_event_on(@server_queue, FINISH_ACCEPTED, @server_tag)
ev = expect_next_event_on(@server_queue, FINISHED, @server_finished_tag)
expect(ev.result).to be_a(Status)
expect(ev.result).to be_a(Struct::Status)
# client gets FINISHED
expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)

@ -1,166 +0,0 @@
# Copyright 2014, 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'
describe GRPC::Core::StatusCodes do
StatusCodes = GRPC::Core::StatusCodes
before(:each) do
@known_types = {
:OK => 0,
:CANCELLED => 1,
:UNKNOWN => 2,
:INVALID_ARGUMENT => 3,
:DEADLINE_EXCEEDED => 4,
:NOT_FOUND => 5,
:ALREADY_EXISTS => 6,
:PERMISSION_DENIED => 7,
:RESOURCE_EXHAUSTED => 8,
:FAILED_PRECONDITION => 9,
:ABORTED => 10,
:OUT_OF_RANGE => 11,
:UNIMPLEMENTED => 12,
:INTERNAL => 13,
:UNAVAILABLE => 14,
:DATA_LOSS => 15,
:UNAUTHENTICATED => 16
}
end
it 'should have symbols for all the known status codes' do
m = StatusCodes
syms_and_codes = m.constants.collect { |c| [c, m.const_get(c)] }
expect(Hash[syms_and_codes]).to eq(@known_types)
end
end
describe GRPC::Core::Status do
Status = GRPC::Core::Status
describe '#new' do
it 'should create new instances' do
expect { Status.new(142, 'test details') }.to_not raise_error
end
end
describe '#details' do
it 'return the detail' do
sts = Status.new(142, 'test details')
expect(sts.details).to eq('test details')
end
end
describe '#code' do
it 'should return the code' do
sts = Status.new(142, 'test details')
expect(sts.code).to eq(142)
end
end
describe '#dup' do
it 'should create a copy that returns the correct details' do
sts = Status.new(142, 'test details')
expect(sts.dup.code).to eq(142)
end
it 'should create a copy that returns the correct code' do
sts = Status.new(142, 'test details')
expect(sts.dup.details).to eq('test details')
end
end
end
describe GRPC::BadStatus do
BadStatus = GRPC::BadStatus
describe '#new' do
it 'should create new instances' do
expect { BadStatus.new(142, 'test details') }.to_not raise_error
end
end
describe '#details' do
it 'return the detail' do
err = BadStatus.new(142, 'test details')
expect(err.details).to eq('test details')
end
end
describe '#code' do
it 'should return the code' do
err = BadStatus.new(142, 'test details')
expect(err.code).to eq(142)
end
end
describe '#dup' do
it 'should create a copy that returns the correct details' do
err = BadStatus.new(142, 'test details')
expect(err.dup.code).to eq(142)
end
it 'should create a copy that returns the correct code' do
err = BadStatus.new(142, 'test details')
expect(err.dup.details).to eq('test details')
end
end
describe '#to_status' do
it 'should create a Status with the same code and details' do
err = BadStatus.new(142, 'test details')
sts = err.to_status
expect(sts.code).to eq(142)
expect(sts.details).to eq('test details')
end
it 'should create a copy that returns the correct code' do
err = BadStatus.new(142, 'test details')
expect(err.dup.details).to eq('test details')
end
end
describe 'as an exception' do
it 'can be raised' do
blk = Proc.new { raise BadStatus.new(343, 'status 343') }
expect(&blk).to raise_error(BadStatus)
end
end
end
Loading…
Cancel
Save