This commit implements suppot for looking up Service descriptors in the global descriptor pool, and from there looking up the associated methods. This is implemented in each of the C extension, JRuby extension, and the FFI implementation. The descriptors can be used to look up the options on the service/methods, and also the request/response types and streaming flags of methods.pull/15817/head
parent
4367d72063
commit
54d7218431
14 changed files with 996 additions and 1 deletions
@ -0,0 +1,114 @@ |
||||
# Protocol Buffers - Google's data interchange format |
||||
# Copyright 2024 Google Inc. All rights reserved. |
||||
# |
||||
# Use of this source code is governed by a BSD-style |
||||
# license that can be found in the LICENSE file or at |
||||
# https://developers.google.com/open-source/licenses/bsd |
||||
|
||||
module Google |
||||
module Protobuf |
||||
class MethodDescriptor |
||||
attr :method_def, :descriptor_pool |
||||
|
||||
include Google::Protobuf::Internal::Convert |
||||
|
||||
# FFI Interface methods and setup |
||||
extend ::FFI::DataConverter |
||||
native_type ::FFI::Type::POINTER |
||||
|
||||
class << self |
||||
prepend Google::Protobuf::Internal::TypeSafety |
||||
include Google::Protobuf::Internal::PointerHelper |
||||
|
||||
# @param value [MethodDescriptor] MethodDescriptor to convert to an FFI native type |
||||
# @param _ [Object] Unused |
||||
def to_native(value, _) |
||||
method_def_ptr = value.nil? ? nil : value.instance_variable_get(:@method_def) |
||||
return ::FFI::Pointer::NULL if method_def_ptr.nil? |
||||
raise "Underlying method_def was null!" if method_def_ptr.null? |
||||
method_def_ptr |
||||
end |
||||
|
||||
## |
||||
# @param service_def [::FFI::Pointer] MethodDef pointer to be wrapped |
||||
# @param _ [Object] Unused |
||||
def from_native(method_def, _ = nil) |
||||
return nil if method_def.nil? or method_def.null? |
||||
service_def = Google::Protobuf::FFI.raw_service_def_by_raw_method_def(method_def) |
||||
file_def = Google::Protobuf::FFI.file_def_by_raw_service_def(service_def) |
||||
descriptor_from_file_def(file_def, method_def) |
||||
end |
||||
end |
||||
|
||||
def self.new(*arguments, &block) |
||||
raise "Descriptor objects may not be created from Ruby." |
||||
end |
||||
|
||||
def to_s |
||||
inspect |
||||
end |
||||
|
||||
def inspect |
||||
"#{self.class.name}: #{name}" |
||||
end |
||||
|
||||
def name |
||||
@name ||= Google::Protobuf::FFI.get_method_name(self) |
||||
end |
||||
|
||||
def options |
||||
@options ||= begin |
||||
size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) |
||||
temporary_arena = Google::Protobuf::FFI.create_arena |
||||
buffer = Google::Protobuf::FFI.method_options(self, size_ptr, temporary_arena) |
||||
Google::Protobuf::MethodOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze |
||||
end |
||||
end |
||||
|
||||
def input_type |
||||
@input_type ||= Google::Protobuf::FFI.method_input_type(self) |
||||
end |
||||
|
||||
def output_type |
||||
@output_type ||= Google::Protobuf::FFI.method_output_type(self) |
||||
end |
||||
|
||||
def client_streaming |
||||
@client_streaming ||= Google::Protobuf::FFI.method_client_streaming(self) |
||||
end |
||||
|
||||
def server_streaming |
||||
@server_streaming ||= Google::Protobuf::FFI.method_server_streaming(self) |
||||
end |
||||
|
||||
private |
||||
|
||||
def initialize(method_def, descriptor_pool) |
||||
@method_def = method_def |
||||
@descriptor_pool = descriptor_pool |
||||
end |
||||
|
||||
def self.private_constructor(method_def, descriptor_pool) |
||||
instance = allocate |
||||
instance.send(:initialize, method_def, descriptor_pool) |
||||
instance |
||||
end |
||||
|
||||
def c_type |
||||
@c_type ||= Google::Protobuf::FFI.get_c_type(self) |
||||
end |
||||
end |
||||
|
||||
class FFI |
||||
# MethodDef |
||||
attach_function :raw_service_def_by_raw_method_def, :upb_MethodDef_Service, [:pointer], :pointer |
||||
attach_function :get_method_name, :upb_MethodDef_Name, [MethodDescriptor], :string |
||||
attach_function :method_options, :MethodDescriptor_serialized_options, [MethodDescriptor, :pointer, Internal::Arena], :pointer |
||||
attach_function :method_input_type, :upb_MethodDef_InputType, [MethodDescriptor], Descriptor |
||||
attach_function :method_output_type, :upb_MethodDef_OutputType, [MethodDescriptor], Descriptor |
||||
attach_function :method_client_streaming, :upb_MethodDef_ClientStreaming, [MethodDescriptor], :bool |
||||
attach_function :method_server_streaming, :upb_MethodDef_ServerStreaming, [MethodDescriptor], :bool |
||||
end |
||||
end |
||||
end |
||||
|
@ -0,0 +1,107 @@ |
||||
# Protocol Buffers - Google's data interchange format |
||||
# Copyright 2024 Google Inc. All rights reserved. |
||||
# |
||||
# Use of this source code is governed by a BSD-style |
||||
# license that can be found in the LICENSE file or at |
||||
# https://developers.google.com/open-source/licenses/bsd |
||||
|
||||
module Google |
||||
module Protobuf |
||||
class ServiceDescriptor |
||||
attr :service_def, :descriptor_pool |
||||
include Enumerable |
||||
|
||||
include Google::Protobuf::Internal::Convert |
||||
|
||||
# FFI Interface methods and setup |
||||
extend ::FFI::DataConverter |
||||
native_type ::FFI::Type::POINTER |
||||
|
||||
class << self |
||||
prepend Google::Protobuf::Internal::TypeSafety |
||||
include Google::Protobuf::Internal::PointerHelper |
||||
|
||||
# @param value [ServiceDescriptor] ServiceDescriptor to convert to an FFI native type |
||||
# @param _ [Object] Unused |
||||
def to_native(value, _) |
||||
service_def_ptr = value.nil? ? nil : value.instance_variable_get(:@service_def) |
||||
return ::FFI::Pointer::NULL if service_def_ptr.nil? |
||||
raise "Underlying service_def was null!" if service_def_ptr.null? |
||||
service_def_ptr |
||||
end |
||||
|
||||
## |
||||
# @param service_def [::FFI::Pointer] ServiceDef pointer to be wrapped |
||||
# @param _ [Object] Unused |
||||
def from_native(service_def, _ = nil) |
||||
return nil if service_def.nil? or service_def.null? |
||||
file_def = Google::Protobuf::FFI.file_def_by_raw_service_def(service_def) |
||||
descriptor_from_file_def(file_def, service_def) |
||||
end |
||||
end |
||||
|
||||
def self.new(*arguments, &block) |
||||
raise "Descriptor objects may not be created from Ruby." |
||||
end |
||||
|
||||
def to_s |
||||
inspect |
||||
end |
||||
|
||||
def inspect |
||||
"#{self.class.name}: #{name}" |
||||
end |
||||
|
||||
def name |
||||
@name ||= Google::Protobuf::FFI.get_service_full_name(self) |
||||
end |
||||
|
||||
def file_descriptor |
||||
@descriptor_pool.send(:get_file_descriptor, Google::Protobuf::FFI.file_def_by_raw_service_def(@service_def)) |
||||
end |
||||
|
||||
def each &block |
||||
n = Google::Protobuf::FFI.method_count(self) |
||||
0.upto(n-1) do |i| |
||||
yield(Google::Protobuf::FFI.get_method_by_index(self, i)) |
||||
end |
||||
nil |
||||
end |
||||
|
||||
def options |
||||
@options ||= begin |
||||
size_ptr = ::FFI::MemoryPointer.new(:size_t, 1) |
||||
temporary_arena = Google::Protobuf::FFI.create_arena |
||||
buffer = Google::Protobuf::FFI.service_options(self, size_ptr, temporary_arena) |
||||
Google::Protobuf::ServiceOptions.decode(buffer.read_string_length(size_ptr.read(:size_t)).force_encoding("ASCII-8BIT").freeze).freeze |
||||
end |
||||
end |
||||
|
||||
private |
||||
|
||||
def initialize(service_def, descriptor_pool) |
||||
@service_def = service_def |
||||
@descriptor_pool = descriptor_pool |
||||
end |
||||
|
||||
def self.private_constructor(service_def, descriptor_pool) |
||||
instance = allocate |
||||
instance.send(:initialize, service_def, descriptor_pool) |
||||
instance |
||||
end |
||||
|
||||
def c_type |
||||
@c_type ||= Google::Protobuf::FFI.get_c_type(self) |
||||
end |
||||
end |
||||
|
||||
class FFI |
||||
# ServiceDef |
||||
attach_function :file_def_by_raw_service_def, :upb_ServiceDef_File, [:pointer], :FileDef |
||||
attach_function :get_service_full_name, :upb_ServiceDef_FullName, [ServiceDescriptor], :string |
||||
attach_function :method_count, :upb_ServiceDef_MethodCount, [ServiceDescriptor], :int |
||||
attach_function :get_method_by_index, :upb_ServiceDef_Method, [ServiceDescriptor, :int], MethodDescriptor |
||||
attach_function :service_options, :ServiceDescriptor_serialized_options, [ServiceDescriptor, :pointer, Internal::Arena], :pointer |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,156 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2024 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
|
||||
import com.google.protobuf.CodedInputStream; |
||||
import com.google.protobuf.Descriptors.MethodDescriptor; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
|
||||
@JRubyClass(name = "MethoDescriptor") |
||||
public class RubyMethodDescriptor extends RubyObject { |
||||
public static void createRubyMethodDescriptor(Ruby runtime) { |
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); |
||||
RubyClass cMethodDescriptor = |
||||
protobuf.defineClassUnder( |
||||
"MethodDescriptor", |
||||
runtime.getObject(), |
||||
new ObjectAllocator() { |
||||
@Override |
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
||||
return new RubyMethodDescriptor(runtime, klazz); |
||||
} |
||||
}); |
||||
cMethodDescriptor.defineAnnotatedMethods(RubyMethodDescriptor.class); |
||||
} |
||||
|
||||
public RubyMethodDescriptor(Ruby runtime, RubyClass klazz) { |
||||
super(runtime, klazz); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MethodDescriptor.name => name |
||||
* |
||||
* Returns the name of this method |
||||
*/ |
||||
@JRubyMethod(name = "name") |
||||
public IRubyObject getName(ThreadContext context) { |
||||
return context.runtime.newString(this.descriptor.getName()); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MethodDescriptor.options |
||||
* |
||||
* Returns the options set on this protobuf rpc method |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject options(ThreadContext context) { |
||||
RubyDescriptorPool pool = (RubyDescriptorPool) RubyDescriptorPool.generatedPool(null, null); |
||||
RubyDescriptor methodOptionsDescriptor = |
||||
(RubyDescriptor) |
||||
pool.lookup(context, context.runtime.newString("google.protobuf.MethodOptions")); |
||||
RubyClass methodOptionsClass = (RubyClass) methodOptionsDescriptor.msgclass(context); |
||||
RubyMessage msg = (RubyMessage) methodOptionsClass.newInstance(context, Block.NULL_BLOCK); |
||||
return msg.decodeBytes( |
||||
context, |
||||
msg, |
||||
CodedInputStream.newInstance( |
||||
descriptor.getOptions().toByteString().toByteArray()), /*freeze*/ |
||||
true); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MethodDescriptor.input_type => Descriptor |
||||
* |
||||
* Returns the `Descriptor` for the request message type of this method |
||||
*/ |
||||
@JRubyMethod(name = "input_type") |
||||
public IRubyObject getInputType(ThreadContext context) { |
||||
return this.pool.lookup(context, context.runtime.newString(this.descriptor.getInputType().getFullName())); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MethodDescriptor.output_type => Descriptor |
||||
* |
||||
* Returns the `Descriptor` for the response message type of this method |
||||
*/ |
||||
@JRubyMethod(name = "output_type") |
||||
public IRubyObject getOutputType(ThreadContext context) { |
||||
return this.pool.lookup(context, context.runtime.newString(this.descriptor.getOutputType().getFullName())); |
||||
} |
||||
|
||||
|
||||
/* |
||||
* call-seq: |
||||
* MethodDescriptor.client_streaming => bool |
||||
* |
||||
* Returns whether or not this is a streaming request method |
||||
*/ |
||||
@JRubyMethod(name = "client_streaming") |
||||
public IRubyObject getClientStreaming(ThreadContext context) { |
||||
return this.descriptor.isClientStreaming() ? context.runtime.getTrue() : context.runtime.getFalse(); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* MethodDescriptor.server_streaming => bool |
||||
* |
||||
* Returns whether or not this is a streaming response method |
||||
*/ |
||||
@JRubyMethod(name = "server_streaming") |
||||
public IRubyObject getServerStreaming(ThreadContext context) { |
||||
return this.descriptor.isServerStreaming() ? context.runtime.getTrue() : context.runtime.getFalse(); |
||||
} |
||||
|
||||
protected void setDescriptor( |
||||
ThreadContext context, MethodDescriptor descriptor, RubyDescriptorPool pool) { |
||||
this.descriptor = descriptor; |
||||
this.pool = pool; |
||||
} |
||||
|
||||
private MethodDescriptor descriptor; |
||||
private IRubyObject name; |
||||
private RubyDescriptorPool pool; |
||||
} |
@ -0,0 +1,157 @@ |
||||
/* |
||||
* Protocol Buffers - Google's data interchange format |
||||
* Copyright 2024 Google Inc. All rights reserved. |
||||
* https://developers.google.com/protocol-buffers/
|
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
package com.google.protobuf.jruby; |
||||
|
||||
|
||||
import com.google.protobuf.CodedInputStream; |
||||
import com.google.protobuf.Descriptors.MethodDescriptor; |
||||
import com.google.protobuf.Descriptors.ServiceDescriptor; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
import org.jruby.*; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
import org.jruby.runtime.Block; |
||||
import org.jruby.runtime.ObjectAllocator; |
||||
import org.jruby.runtime.ThreadContext; |
||||
import org.jruby.runtime.builtin.IRubyObject; |
||||
import org.jruby.anno.JRubyClass; |
||||
import org.jruby.anno.JRubyMethod; |
||||
|
||||
@JRubyClass(name = "ServiceDescriptor") |
||||
public class RubyServiceDescriptor extends RubyObject { |
||||
public static void createRubyServiceDescriptor(Ruby runtime) { |
||||
RubyModule protobuf = runtime.getClassFromPath("Google::Protobuf"); |
||||
RubyClass cServiceDescriptor = |
||||
protobuf.defineClassUnder( |
||||
"ServiceDescriptor", |
||||
runtime.getObject(), |
||||
new ObjectAllocator() { |
||||
@Override |
||||
public IRubyObject allocate(Ruby runtime, RubyClass klazz) { |
||||
return new RubyServiceDescriptor(runtime, klazz); |
||||
} |
||||
}); |
||||
cServiceDescriptor.includeModule(runtime.getEnumerable()); |
||||
cServiceDescriptor.defineAnnotatedMethods(RubyServiceDescriptor.class); |
||||
cMethodDescriptor = (RubyClass) runtime.getClassFromPath("Google::Protobuf::MethodDescriptor"); |
||||
} |
||||
|
||||
public RubyServiceDescriptor(Ruby runtime, RubyClass klazz) { |
||||
super(runtime, klazz); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* ServiceDescriptor.name => name |
||||
* |
||||
* Returns the name of this service type as a fully-qualified string (e.g., |
||||
* My.Package.Service). |
||||
*/ |
||||
@JRubyMethod(name = "name") |
||||
public IRubyObject getName(ThreadContext context) { |
||||
return name; |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* ServiceDescriptor.file_descriptor |
||||
* |
||||
* Returns the FileDescriptor object this service belongs to. |
||||
*/ |
||||
@JRubyMethod(name = "file_descriptor") |
||||
public IRubyObject getFileDescriptor(ThreadContext context) { |
||||
return RubyFileDescriptor.getRubyFileDescriptor(context, descriptor); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* ServiceDescriptor.options |
||||
* |
||||
* Returns the options set on this protobuf service |
||||
*/ |
||||
@JRubyMethod |
||||
public IRubyObject options(ThreadContext context) { |
||||
RubyDescriptorPool pool = (RubyDescriptorPool) RubyDescriptorPool.generatedPool(null, null); |
||||
RubyDescriptor serviceOptionsDescriptor = |
||||
(RubyDescriptor) |
||||
pool.lookup(context, context.runtime.newString("google.protobuf.ServiceOptions")); |
||||
RubyClass serviceOptionsClass = (RubyClass) serviceOptionsDescriptor.msgclass(context); |
||||
RubyMessage msg = (RubyMessage) serviceOptionsClass.newInstance(context, Block.NULL_BLOCK); |
||||
return msg.decodeBytes( |
||||
context, |
||||
msg, |
||||
CodedInputStream.newInstance( |
||||
descriptor.getOptions().toByteString().toByteArray()), /*freeze*/ |
||||
true); |
||||
} |
||||
|
||||
/* |
||||
* call-seq: |
||||
* ServiceDescriptor.each(&block) |
||||
* |
||||
* Iterates over methods in this service, yielding to the block on each one. |
||||
*/ |
||||
@JRubyMethod(name = "each") |
||||
public IRubyObject each(ThreadContext context, Block block) { |
||||
for (Map.Entry<IRubyObject, RubyMethodDescriptor> entry : methodDescriptors.entrySet()) { |
||||
block.yield(context, entry.getValue()); |
||||
} |
||||
return context.nil; |
||||
} |
||||
|
||||
protected void setDescriptor( |
||||
ThreadContext context, ServiceDescriptor descriptor, RubyDescriptorPool pool) { |
||||
this.descriptor = descriptor; |
||||
|
||||
// Populate the methods (and preserve the order by using LinkedHashMap)
|
||||
methodDescriptors = new LinkedHashMap<IRubyObject, RubyMethodDescriptor>(); |
||||
|
||||
for (MethodDescriptor methodDescriptor : descriptor.getMethods()) { |
||||
RubyMethodDescriptor md = |
||||
(RubyMethodDescriptor) cMethodDescriptor.newInstance(context, Block.NULL_BLOCK); |
||||
md.setDescriptor(context, methodDescriptor, pool); |
||||
methodDescriptors.put(context.runtime.newString(methodDescriptor.getName()), md); |
||||
} |
||||
} |
||||
|
||||
protected void setName(IRubyObject name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
private static RubyClass cMethodDescriptor; |
||||
|
||||
private ServiceDescriptor descriptor; |
||||
private Map<IRubyObject, RubyMethodDescriptor> methodDescriptors; |
||||
private IRubyObject name; |
||||
} |
@ -0,0 +1,50 @@ |
||||
syntax = "proto3"; |
||||
import "google/protobuf/descriptor.proto"; |
||||
|
||||
package service_test_protos; |
||||
|
||||
message UnaryRequestType { |
||||
string ping = 1; |
||||
} |
||||
|
||||
message UnaryResponseType { |
||||
string pong = 1; |
||||
} |
||||
|
||||
message StreamRequestType { |
||||
string ping = 1; |
||||
uint32 sequence = 2; |
||||
} |
||||
|
||||
message StreamResponseType { |
||||
string pong = 1; |
||||
uint32 sequence = 2; |
||||
} |
||||
|
||||
message TestOptionsType { |
||||
uint32 int_option_value = 1; |
||||
} |
||||
|
||||
extend google.protobuf.ServiceOptions { |
||||
optional TestOptionsType test_options = 50000; |
||||
} |
||||
|
||||
service TestService { |
||||
option(test_options).int_option_value = 8325; |
||||
|
||||
rpc UnaryOne(UnaryRequestType) returns (UnaryResponseType); |
||||
rpc UnaryTwo(UnaryRequestType) returns (UnaryResponseType); |
||||
|
||||
rpc IdempotentMethod(UnaryRequestType) returns (UnaryResponseType) { |
||||
option idempotency_level = IDEMPOTENT; |
||||
} |
||||
rpc PureMethod(UnaryRequestType) returns (UnaryResponseType) { |
||||
option idempotency_level = NO_SIDE_EFFECTS; |
||||
} |
||||
|
||||
rpc StreamingMethod(stream StreamRequestType) returns (stream StreamResponseType); |
||||
} |
||||
|
||||
service DeprecatedService { |
||||
option deprecated = true; |
||||
} |
@ -0,0 +1,61 @@ |
||||
#!/usr/bin/ruby |
||||
|
||||
require 'google/protobuf' |
||||
require 'service_test_pb' |
||||
require 'test/unit' |
||||
require 'json' |
||||
|
||||
class ServiceTest < Test::Unit::TestCase |
||||
def setup |
||||
@test_service = Google::Protobuf::DescriptorPool.generated_pool.lookup('service_test_protos.TestService') |
||||
@deprecated_service = Google::Protobuf::DescriptorPool.generated_pool.lookup('service_test_protos.DeprecatedService') |
||||
@test_service_methods = @test_service.to_h { |method| [method.name, method] } |
||||
end |
||||
|
||||
def test_lookup_service_descriptor |
||||
assert_kind_of Google::Protobuf::ServiceDescriptor, @test_service |
||||
assert_equal 'service_test_protos.TestService', @test_service.name |
||||
end |
||||
|
||||
def test_file_descriptor |
||||
assert_kind_of Google::Protobuf::FileDescriptor, @test_service.file_descriptor |
||||
assert_equal 'service_test.proto', @test_service.file_descriptor.name |
||||
end |
||||
|
||||
def test_method_iteration |
||||
@test_service.each { |method| assert_kind_of Google::Protobuf::MethodDescriptor, method } |
||||
assert_equal %w(UnaryOne UnaryTwo), @test_service.map { |method| method.name }.first(2) |
||||
end |
||||
|
||||
def test_service_options |
||||
assert @deprecated_service.options.deprecated |
||||
refute @test_service.options.deprecated |
||||
end |
||||
|
||||
def test_service_options_extensions |
||||
extension_field = Google::Protobuf::DescriptorPool.generated_pool.lookup('service_test_protos.test_options') |
||||
assert_equal 8325, extension_field.get(@test_service.options).int_option_value |
||||
end |
||||
|
||||
def test_method_options |
||||
assert_equal :IDEMPOTENT, @test_service_methods['IdempotentMethod'].options.idempotency_level |
||||
assert_equal :NO_SIDE_EFFECTS, @test_service_methods['PureMethod'].options.idempotency_level |
||||
end |
||||
|
||||
def test_method_input_type |
||||
unary_request_type = Google::Protobuf::DescriptorPool.generated_pool.lookup('service_test_protos.UnaryRequestType') |
||||
assert_same unary_request_type, @test_service_methods['UnaryOne'].input_type |
||||
end |
||||
|
||||
def test_method_output_type |
||||
unary_response_type = Google::Protobuf::DescriptorPool.generated_pool.lookup('service_test_protos.UnaryResponseType') |
||||
assert_same unary_response_type, @test_service_methods['UnaryOne'].output_type |
||||
end |
||||
|
||||
def test_method_streaming_flags |
||||
refute @test_service_methods['UnaryOne'].client_streaming |
||||
refute @test_service_methods['UnaryOne'].server_streaming |
||||
assert @test_service_methods['StreamingMethod'].client_streaming |
||||
assert @test_service_methods['StreamingMethod'].server_streaming |
||||
end |
||||
end |
Loading…
Reference in new issue