1#!/usr/bin/env ruby 2 3# Copyright 2015 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17this_dir = File.expand_path(File.dirname(__FILE__)) 18protos_lib_dir = File.join(this_dir, 'lib') 19grpc_lib_dir = File.join(File.dirname(this_dir), 'lib') 20$LOAD_PATH.unshift(grpc_lib_dir) unless $LOAD_PATH.include?(grpc_lib_dir) 21$LOAD_PATH.unshift(protos_lib_dir) unless $LOAD_PATH.include?(protos_lib_dir) 22$LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir) 23 24require 'grpc' 25require 'echo_services_pb' 26require 'client_control_services_pb' 27require 'socket' 28require 'optparse' 29require 'thread' 30require 'timeout' 31require 'English' # see https://github.com/bbatsov/rubocop/issues/1747 32require_relative '../spec/support/helpers' 33 34include GRPC::Spec::Helpers 35 36# Useful to update a value within a do block 37class MutableValue 38 attr_accessor :value 39 40 def initialize(value) 41 @value = value 42 end 43end 44 45# GreeterServer is simple server that implements the Helloworld Greeter server. 46# This service also has a mechanism to wait for a timeout until the first 47# RPC has been received, which is useful for synchronizing between parent 48# and child processes. 49class EchoServerImpl < Echo::EchoServer::Service 50 def initialize 51 @first_rpc_received_mu = Mutex.new 52 @first_rpc_received_cv = ConditionVariable.new 53 @first_rpc_received = MutableValue.new(false) 54 end 55 56 # say_hello implements the SayHello rpc method. 57 def echo(echo_req, _) 58 @first_rpc_received_mu.synchronize do 59 @first_rpc_received.value = true 60 @first_rpc_received_cv.broadcast 61 end 62 Echo::EchoReply.new(response: echo_req.request) 63 end 64 65 def wait_for_first_rpc_received(timeout_seconds) 66 Timeout.timeout(timeout_seconds) do 67 @first_rpc_received_mu.synchronize do 68 until @first_rpc_received.value 69 @first_rpc_received_cv.wait(@first_rpc_received_mu) 70 end 71 end 72 end 73 rescue => e 74 fail "Received error:|#{e}| while waiting for #{timeout_seconds} " \ 75 'seconds to receive the first RPC' 76 end 77end 78 79# ServerRunner starts an "echo server" that test clients can make calls to 80class ServerRunner 81 attr_accessor :server_creds 82 83 def initialize(service_impl, rpc_server_args: {}) 84 @service_impl = service_impl 85 @rpc_server_args = rpc_server_args 86 @server_creds = :this_port_is_insecure 87 end 88 89 def run 90 @srv = new_rpc_server_for_testing(@rpc_server_args) 91 port = @srv.add_http2_port('0.0.0.0:0', @server_creds) 92 @srv.handle(@service_impl) 93 94 @thd = Thread.new do 95 @srv.run 96 end 97 @srv.wait_till_running 98 port 99 end 100 101 def stop 102 @srv.stop 103 @thd.join 104 fail 'server not stopped' unless @srv.stopped? 105 end 106end 107 108def start_client(client_main, server_port) 109 this_dir = File.expand_path(File.dirname(__FILE__)) 110 111 tmp_server = TCPServer.new(0) 112 client_control_port = tmp_server.local_address.ip_port 113 tmp_server.close 114 115 client_path = File.join(this_dir, client_main) 116 client_pid = Process.spawn(RbConfig.ruby, 117 client_path, 118 "--client_control_port=#{client_control_port}", 119 "--server_port=#{server_port}") 120 control_stub = ClientControl::ClientController::Stub.new( 121 "localhost:#{client_control_port}", :this_channel_is_insecure) 122 [control_stub, client_pid] 123end 124 125def cleanup(control_stub, client_pid, server_runner) 126 control_stub.shutdown(ClientControl::Void.new) 127 Process.wait(client_pid) 128 129 client_exit_code = $CHILD_STATUS 130 131 if client_exit_code != 0 132 fail "term sig test failure: client exit code: #{client_exit_code}" 133 end 134 135 server_runner.stop 136end 137