Index: third_party/grpc/src/ruby/pb/test/server.rb |
diff --git a/third_party/grpc/src/ruby/pb/test/server.rb b/third_party/grpc/src/ruby/pb/test/server.rb |
new file mode 100755 |
index 0000000000000000000000000000000000000000..851e8152224188fa6b7eaeaf65b54b01a568c353 |
--- /dev/null |
+++ b/third_party/grpc/src/ruby/pb/test/server.rb |
@@ -0,0 +1,253 @@ |
+#!/usr/bin/env ruby |
+ |
+# 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. |
+ |
+# interop_server is a Testing app that runs a gRPC interop testing server. |
+# |
+# It helps validate interoperation b/w gRPC in different environments |
+# |
+# Helps validate interoperation b/w different gRPC implementations. |
+# |
+# Usage: $ path/to/interop_server.rb --port |
+ |
+this_dir = File.expand_path(File.dirname(__FILE__)) |
+lib_dir = File.join(File.dirname(File.dirname(this_dir)), 'lib') |
+pb_dir = File.dirname(File.dirname(this_dir)) |
+$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) |
+$LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir) |
+$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) |
+ |
+require 'forwardable' |
+require 'logger' |
+require 'optparse' |
+ |
+require 'grpc' |
+ |
+require 'test/proto/empty' |
+require 'test/proto/messages' |
+require 'test/proto/test_services' |
+ |
+# DebugIsTruncated extends the default Logger to truncate debug messages |
+class DebugIsTruncated < Logger |
+ def debug(s) |
+ super(truncate(s, 1024)) |
+ end |
+ |
+ # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>: |
+ # |
+ # 'Once upon a time in a world far far away'.truncate(27) |
+ # # => "Once upon a time in a wo..." |
+ # |
+ # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break: |
+ # |
+ # 'Once upon a time in a world far far away'.truncate(27, separator: ' ') |
+ # # => "Once upon a time in a..." |
+ # |
+ # 'Once upon a time in a world far far away'.truncate(27, separator: /\s/) |
+ # # => "Once upon a time in a..." |
+ # |
+ # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...") |
+ # for a total length not exceeding <tt>length</tt>: |
+ # |
+ # 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)') |
+ # # => "And they f... (continued)" |
+ def truncate(s, truncate_at, options = {}) |
+ return s unless s.length > truncate_at |
+ omission = options[:omission] || '...' |
+ with_extra_room = truncate_at - omission.length |
+ stop = \ |
+ if options[:separator] |
+ rindex(options[:separator], with_extra_room) || with_extra_room |
+ else |
+ with_extra_room |
+ end |
+ "#{s[0, stop]}#{omission}" |
+ end |
+end |
+ |
+# RubyLogger defines a logger for gRPC based on the standard ruby logger. |
+module RubyLogger |
+ def logger |
+ LOGGER |
+ end |
+ |
+ LOGGER = DebugIsTruncated.new(STDOUT) |
+ LOGGER.level = Logger::WARN |
+end |
+ |
+# GRPC is the general RPC module |
+module GRPC |
+ # Inject the noop #logger if no module-level logger method has been injected. |
+ extend RubyLogger |
+end |
+ |
+# loads the certificates by the test server. |
+def load_test_certs |
+ this_dir = File.expand_path(File.dirname(__FILE__)) |
+ data_dir = File.join(File.dirname(File.dirname(this_dir)), 'spec/testdata') |
+ files = ['ca.pem', 'server1.key', 'server1.pem'] |
+ files.map { |f| File.open(File.join(data_dir, f)).read } |
+end |
+ |
+# creates a ServerCredentials from the test certificates. |
+def test_server_creds |
+ certs = load_test_certs |
+ GRPC::Core::ServerCredentials.new( |
+ nil, [{private_key: certs[1], cert_chain: certs[2]}], false) |
+end |
+ |
+# produces a string of null chars (\0) of length l. |
+def nulls(l) |
+ fail 'requires #{l} to be +ve' if l < 0 |
+ [].pack('x' * l).force_encoding('ascii-8bit') |
+end |
+ |
+# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item. |
+class EnumeratorQueue |
+ extend Forwardable |
+ def_delegators :@q, :push |
+ |
+ def initialize(sentinel) |
+ @q = Queue.new |
+ @sentinel = sentinel |
+ end |
+ |
+ def each_item |
+ return enum_for(:each_item) unless block_given? |
+ loop do |
+ r = @q.pop |
+ break if r.equal?(@sentinel) |
+ fail r if r.is_a? Exception |
+ yield r |
+ end |
+ end |
+end |
+ |
+# A runnable implementation of the schema-specified testing service, with each |
+# service method implemented as required by the interop testing spec. |
+class TestTarget < Grpc::Testing::TestService::Service |
+ include Grpc::Testing |
+ include Grpc::Testing::PayloadType |
+ |
+ def empty_call(_empty, _call) |
+ Empty.new |
+ end |
+ |
+ def unary_call(simple_req, _call) |
+ req_size = simple_req.response_size |
+ SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE, |
+ body: nulls(req_size))) |
+ end |
+ |
+ def streaming_input_call(call) |
+ sizes = call.each_remote_read.map { |x| x.payload.body.length } |
+ sum = sizes.inject(0) { |s, x| s + x } |
+ StreamingInputCallResponse.new(aggregated_payload_size: sum) |
+ end |
+ |
+ def streaming_output_call(req, _call) |
+ cls = StreamingOutputCallResponse |
+ req.response_parameters.map do |p| |
+ cls.new(payload: Payload.new(type: req.response_type, |
+ body: nulls(p.size))) |
+ end |
+ end |
+ |
+ def full_duplex_call(reqs) |
+ # reqs is a lazy Enumerator of the requests sent by the client. |
+ q = EnumeratorQueue.new(self) |
+ cls = StreamingOutputCallResponse |
+ Thread.new do |
+ begin |
+ GRPC.logger.info('interop-server: started receiving') |
+ reqs.each do |req| |
+ resp_size = req.response_parameters[0].size |
+ GRPC.logger.info("read a req, response size is #{resp_size}") |
+ resp = cls.new(payload: Payload.new(type: req.response_type, |
+ body: nulls(resp_size))) |
+ q.push(resp) |
+ end |
+ GRPC.logger.info('interop-server: finished receiving') |
+ q.push(self) |
+ rescue StandardError => e |
+ GRPC.logger.info('interop-server: failed') |
+ GRPC.logger.warn(e) |
+ q.push(e) # share the exception with the enumerator |
+ end |
+ end |
+ q.each_item |
+ end |
+ |
+ def half_duplex_call(reqs) |
+ # TODO: update with unique behaviour of the half_duplex_call if that's |
+ # ever required by any of the tests. |
+ full_duplex_call(reqs) |
+ end |
+end |
+ |
+# validates the the command line options, returning them as a Hash. |
+def parse_options |
+ options = { |
+ 'port' => nil, |
+ 'secure' => false |
+ } |
+ OptionParser.new do |opts| |
+ opts.banner = 'Usage: --port port' |
+ opts.on('--port PORT', 'server port') do |v| |
+ options['port'] = v |
+ end |
+ opts.on('--use_tls USE_TLS', ['false', 'true'], |
+ 'require a secure connection?') do |v| |
+ options['secure'] = v == 'true' |
+ end |
+ end.parse! |
+ |
+ if options['port'].nil? |
+ fail(OptionParser::MissingArgument, 'please specify --port') |
+ end |
+ options |
+end |
+ |
+def main |
+ opts = parse_options |
+ host = "0.0.0.0:#{opts['port']}" |
+ s = GRPC::RpcServer.new |
+ if opts['secure'] |
+ s.add_http2_port(host, test_server_creds) |
+ GRPC.logger.info("... running securely on #{host}") |
+ else |
+ s.add_http2_port(host, :this_port_is_insecure) |
+ GRPC.logger.info("... running insecurely on #{host}") |
+ end |
+ s.handle(TestTarget) |
+ s.run_till_terminated |
+end |
+ |
+main |