1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15require 'spec_helper' 16require 'English' 17 18def load_test_certs 19 test_root = File.join(File.dirname(__FILE__), 'testdata') 20 files = ['ca.pem', 'server1.key', 'server1.pem'] 21 files.map { |f| File.open(File.join(test_root, f)).read } 22end 23 24describe GRPC::Core::Channel do 25 let(:fake_host) { 'localhost:0' } 26 27 def create_test_cert 28 GRPC::Core::ChannelCredentials.new(load_test_certs[0]) 29 end 30 31 def fork_with_propagated_error_message 32 pipe_read, pipe_write = IO.pipe 33 pid = fork do 34 pipe_read.close 35 begin 36 yield 37 rescue => exc 38 pipe_write.syswrite(exc.message) 39 end 40 pipe_write.close 41 end 42 pipe_write.close 43 44 exc_message = pipe_read.read 45 Process.wait(pid) 46 47 unless $CHILD_STATUS.success? 48 raise "forked process failed with #{$CHILD_STATUS}" 49 end 50 raise exc_message unless exc_message.empty? 51 end 52 53 shared_examples '#new' do 54 it 'take a host name without channel args' do 55 blk = proc do 56 GRPC::Core::Channel.new('dummy_host', nil, :this_channel_is_insecure) 57 end 58 expect(&blk).not_to raise_error 59 end 60 61 it 'does not take a hash with bad keys as channel args' do 62 blk = construct_with_args(Object.new => 1) 63 expect(&blk).to raise_error TypeError 64 blk = construct_with_args(1 => 1) 65 expect(&blk).to raise_error TypeError 66 end 67 68 it 'does not take a hash with bad values as channel args' do 69 blk = construct_with_args(symbol: Object.new) 70 expect(&blk).to raise_error TypeError 71 blk = construct_with_args('1' => {}) 72 expect(&blk).to raise_error TypeError 73 end 74 75 it 'can take a hash with a symbol key as channel args' do 76 blk = construct_with_args(a_symbol: 1) 77 expect(&blk).to_not raise_error 78 end 79 80 it 'can take a hash with a string key as channel args' do 81 blk = construct_with_args('a_symbol' => 1) 82 expect(&blk).to_not raise_error 83 end 84 85 it 'can take a hash with a string value as channel args' do 86 blk = construct_with_args(a_symbol: '1') 87 expect(&blk).to_not raise_error 88 end 89 90 it 'can take a hash with a symbol value as channel args' do 91 blk = construct_with_args(a_symbol: :another_symbol) 92 expect(&blk).to_not raise_error 93 end 94 95 it 'can take a hash with a numeric value as channel args' do 96 blk = construct_with_args(a_symbol: 1) 97 expect(&blk).to_not raise_error 98 end 99 100 it 'can take a hash with many args as channel args' do 101 args = Hash[127.times.collect { |x| [x.to_s, x] }] 102 blk = construct_with_args(args) 103 expect(&blk).to_not raise_error 104 end 105 106 it 'raises if grpc was initialized in another process' do 107 blk = construct_with_args({}) 108 expect(&blk).not_to raise_error 109 expect do 110 fork_with_propagated_error_message(&blk) 111 end.to raise_error(RuntimeError, 'grpc cannot be used before and after forking') 112 end 113 end 114 115 describe '#new for secure channels' do 116 def construct_with_args(a) 117 proc { GRPC::Core::Channel.new('dummy_host', a, create_test_cert) } 118 end 119 120 it_behaves_like '#new' 121 end 122 123 describe '#new for insecure channels' do 124 it_behaves_like '#new' 125 126 def construct_with_args(a) 127 proc do 128 GRPC::Core::Channel.new('dummy_host', a, :this_channel_is_insecure) 129 end 130 end 131 end 132 133 describe '#create_call' do 134 it 'creates a call OK' do 135 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 136 137 deadline = Time.now + 5 138 139 blk = proc do 140 ch.create_call(nil, nil, 'dummy_method', nil, deadline) 141 end 142 expect(&blk).to_not raise_error 143 end 144 145 it 'raises an error if called on a closed channel' do 146 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 147 ch.close 148 149 deadline = Time.now + 5 150 blk = proc do 151 ch.create_call(nil, nil, 'dummy_method', nil, deadline) 152 end 153 expect(&blk).to raise_error(RuntimeError) 154 end 155 156 it 'raises if grpc was initialized in another process' do 157 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 158 159 deadline = Time.now + 5 160 161 blk = proc do 162 fork_with_propagated_error_message do 163 ch.create_call(nil, nil, 'dummy_method', nil, deadline) 164 end 165 end 166 expect(&blk).to raise_error(RuntimeError, 'grpc cannot be used before and after forking') 167 end 168 end 169 170 describe '#destroy' do 171 it 'destroys a channel ok' do 172 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 173 blk = proc { ch.destroy } 174 expect(&blk).to_not raise_error 175 end 176 177 it 'can be called more than once without error' do 178 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 179 blk = proc { ch.destroy } 180 blk.call 181 expect(&blk).to_not raise_error 182 end 183 end 184 185 describe '#connectivity_state' do 186 it 'returns an enum' do 187 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 188 valid_states = [ 189 GRPC::Core::ConnectivityStates::IDLE, 190 GRPC::Core::ConnectivityStates::CONNECTING, 191 GRPC::Core::ConnectivityStates::READY, 192 GRPC::Core::ConnectivityStates::TRANSIENT_FAILURE, 193 GRPC::Core::ConnectivityStates::FATAL_FAILURE 194 ] 195 196 expect(valid_states).to include(ch.connectivity_state) 197 end 198 199 it 'returns an enum when trying to connect' do 200 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 201 ch.connectivity_state(true) 202 valid_states = [ 203 GRPC::Core::ConnectivityStates::IDLE, 204 GRPC::Core::ConnectivityStates::CONNECTING, 205 GRPC::Core::ConnectivityStates::READY, 206 GRPC::Core::ConnectivityStates::TRANSIENT_FAILURE, 207 GRPC::Core::ConnectivityStates::FATAL_FAILURE 208 ] 209 210 expect(valid_states).to include(ch.connectivity_state) 211 end 212 end 213 214 describe '::SSL_TARGET' do 215 it 'is a symbol' do 216 expect(GRPC::Core::Channel::SSL_TARGET).to be_a(Symbol) 217 end 218 end 219 220 describe '#close' do 221 it 'closes a channel ok' do 222 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 223 blk = proc { ch.close } 224 expect(&blk).to_not raise_error 225 end 226 227 it 'can be called more than once without error' do 228 ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure) 229 blk = proc { ch.close } 230 blk.call 231 expect(&blk).to_not raise_error 232 end 233 end 234end 235