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' 16 17include GRPC::Core 18 19shared_context 'setup: tags' do 20 let(:sent_message) { 'sent message' } 21 let(:reply_text) { 'the reply' } 22 23 def deadline 24 Time.now + 5 25 end 26 27 def server_allows_client_to_proceed(metadata = {}) 28 recvd_rpc = @server.request_call 29 expect(recvd_rpc).to_not eq nil 30 server_call = recvd_rpc.call 31 ops = { CallOps::SEND_INITIAL_METADATA => metadata } 32 server_batch = server_call.run_batch(ops) 33 expect(server_batch.send_metadata).to be true 34 server_call 35 end 36 37 def new_client_call 38 @ch.create_call(nil, nil, '/method', nil, deadline) 39 end 40 41 def ok_status 42 Struct::Status.new(StatusCodes::OK, 'OK') 43 end 44end 45 46shared_examples 'basic GRPC message delivery is OK' do 47 include GRPC::Core 48 include_context 'setup: tags' 49 50 context 'the test channel' do 51 it 'should have a target' do 52 expect(@ch.target).to be_a(String) 53 end 54 end 55 56 context 'a client call' do 57 it 'should have a peer' do 58 expect(new_client_call.peer).to be_a(String) 59 end 60 end 61 62 it 'calls have peer info' do 63 call = new_client_call 64 expect(call.peer).to be_a(String) 65 end 66 67 it 'servers receive requests from clients and can respond' do 68 call = new_client_call 69 server_call = nil 70 71 server_thread = Thread.new do 72 server_call = server_allows_client_to_proceed 73 end 74 75 client_ops = { 76 CallOps::SEND_INITIAL_METADATA => {}, 77 CallOps::SEND_MESSAGE => sent_message, 78 CallOps::SEND_CLOSE_FROM_CLIENT => nil 79 } 80 client_batch = call.run_batch(client_ops) 81 expect(client_batch.send_metadata).to be true 82 expect(client_batch.send_message).to be true 83 expect(client_batch.send_close).to be true 84 85 # confirm the server can read the inbound message 86 server_thread.join 87 server_ops = { 88 CallOps::RECV_MESSAGE => nil, 89 CallOps::RECV_CLOSE_ON_SERVER => nil, 90 CallOps::SEND_STATUS_FROM_SERVER => ok_status 91 } 92 server_batch = server_call.run_batch(server_ops) 93 expect(server_batch.message).to eq(sent_message) 94 expect(server_batch.send_close).to be true 95 expect(server_batch.send_status).to be true 96 97 # finish the call 98 final_client_batch = call.run_batch( 99 CallOps::RECV_INITIAL_METADATA => nil, 100 CallOps::RECV_STATUS_ON_CLIENT => nil) 101 expect(final_client_batch.metadata).to eq({}) 102 expect(final_client_batch.status.code).to eq(0) 103 end 104 105 it 'responses written by servers are received by the client' do 106 call = new_client_call 107 server_call = nil 108 109 server_thread = Thread.new do 110 server_call = server_allows_client_to_proceed 111 end 112 113 client_ops = { 114 CallOps::SEND_INITIAL_METADATA => {}, 115 CallOps::SEND_MESSAGE => sent_message, 116 CallOps::SEND_CLOSE_FROM_CLIENT => nil 117 } 118 client_batch = call.run_batch(client_ops) 119 expect(client_batch.send_metadata).to be true 120 expect(client_batch.send_message).to be true 121 expect(client_batch.send_close).to be true 122 123 # confirm the server can read the inbound message 124 server_thread.join 125 server_ops = { 126 CallOps::RECV_MESSAGE => nil, 127 CallOps::RECV_CLOSE_ON_SERVER => nil, 128 CallOps::SEND_MESSAGE => reply_text, 129 CallOps::SEND_STATUS_FROM_SERVER => ok_status 130 } 131 server_batch = server_call.run_batch(server_ops) 132 expect(server_batch.message).to eq(sent_message) 133 expect(server_batch.send_close).to be true 134 expect(server_batch.send_message).to be true 135 expect(server_batch.send_status).to be true 136 137 # finish the call 138 final_client_batch = call.run_batch( 139 CallOps::RECV_INITIAL_METADATA => nil, 140 CallOps::RECV_MESSAGE => nil, 141 CallOps::RECV_STATUS_ON_CLIENT => nil) 142 expect(final_client_batch.metadata).to eq({}) 143 expect(final_client_batch.message).to eq(reply_text) 144 expect(final_client_batch.status.code).to eq(0) 145 end 146 147 it 'compressed messages can be sent and received' do 148 call = new_client_call 149 server_call = nil 150 long_request_str = '0' * 2000 151 long_response_str = '1' * 2000 152 md = { 'grpc-internal-encoding-request' => 'gzip' } 153 154 server_thread = Thread.new do 155 server_call = server_allows_client_to_proceed(md) 156 end 157 158 client_ops = { 159 CallOps::SEND_INITIAL_METADATA => md, 160 CallOps::SEND_MESSAGE => long_request_str, 161 CallOps::SEND_CLOSE_FROM_CLIENT => nil 162 } 163 client_batch = call.run_batch(client_ops) 164 expect(client_batch.send_metadata).to be true 165 expect(client_batch.send_message).to be true 166 expect(client_batch.send_close).to be true 167 168 # confirm the server can read the inbound message 169 server_thread.join 170 server_ops = { 171 CallOps::RECV_MESSAGE => nil, 172 CallOps::RECV_CLOSE_ON_SERVER => nil, 173 CallOps::SEND_MESSAGE => long_response_str, 174 CallOps::SEND_STATUS_FROM_SERVER => ok_status 175 } 176 server_batch = server_call.run_batch(server_ops) 177 expect(server_batch.message).to eq(long_request_str) 178 expect(server_batch.send_close).to be true 179 expect(server_batch.send_message).to be true 180 expect(server_batch.send_status).to be true 181 182 client_ops = { 183 CallOps::RECV_INITIAL_METADATA => nil, 184 CallOps::RECV_MESSAGE => nil, 185 CallOps::RECV_STATUS_ON_CLIENT => nil 186 } 187 final_client_batch = call.run_batch(client_ops) 188 expect(final_client_batch.metadata).to eq({}) 189 expect(final_client_batch.message).to eq long_response_str 190 expect(final_client_batch.status.code).to eq(0) 191 end 192 193 it 'servers can ignore a client write and send a status' do 194 call = new_client_call 195 server_call = nil 196 197 server_thread = Thread.new do 198 server_call = server_allows_client_to_proceed 199 end 200 201 client_ops = { 202 CallOps::SEND_INITIAL_METADATA => {}, 203 CallOps::SEND_MESSAGE => sent_message, 204 CallOps::SEND_CLOSE_FROM_CLIENT => nil 205 } 206 client_batch = call.run_batch(client_ops) 207 expect(client_batch.send_metadata).to be true 208 expect(client_batch.send_message).to be true 209 expect(client_batch.send_close).to be true 210 211 # confirm the server can read the inbound message 212 the_status = Struct::Status.new(StatusCodes::OK, 'OK') 213 server_thread.join 214 server_ops = { 215 CallOps::SEND_STATUS_FROM_SERVER => the_status 216 } 217 server_batch = server_call.run_batch(server_ops) 218 expect(server_batch.message).to eq nil 219 expect(server_batch.send_status).to be true 220 221 final_client_batch = call.run_batch( 222 CallOps::RECV_INITIAL_METADATA => nil, 223 CallOps::RECV_STATUS_ON_CLIENT => nil) 224 expect(final_client_batch.metadata).to eq({}) 225 expect(final_client_batch.status.code).to eq(0) 226 end 227 228 it 'completes calls by sending status to client and server' do 229 call = new_client_call 230 server_call = nil 231 232 server_thread = Thread.new do 233 server_call = server_allows_client_to_proceed 234 end 235 236 client_ops = { 237 CallOps::SEND_INITIAL_METADATA => {}, 238 CallOps::SEND_MESSAGE => sent_message 239 } 240 client_batch = call.run_batch(client_ops) 241 expect(client_batch.send_metadata).to be true 242 expect(client_batch.send_message).to be true 243 244 # confirm the server can read the inbound message and respond 245 the_status = Struct::Status.new(StatusCodes::OK, 'OK', {}) 246 server_thread.join 247 server_ops = { 248 CallOps::RECV_MESSAGE => nil, 249 CallOps::SEND_MESSAGE => reply_text, 250 CallOps::SEND_STATUS_FROM_SERVER => the_status 251 } 252 server_batch = server_call.run_batch(server_ops) 253 expect(server_batch.message).to eq sent_message 254 expect(server_batch.send_status).to be true 255 expect(server_batch.send_message).to be true 256 257 # confirm the client can receive the server response and status. 258 client_ops = { 259 CallOps::SEND_CLOSE_FROM_CLIENT => nil, 260 CallOps::RECV_INITIAL_METADATA => nil, 261 CallOps::RECV_MESSAGE => nil, 262 CallOps::RECV_STATUS_ON_CLIENT => nil 263 } 264 final_client_batch = call.run_batch(client_ops) 265 expect(final_client_batch.send_close).to be true 266 expect(final_client_batch.message).to eq reply_text 267 expect(final_client_batch.status).to eq the_status 268 269 # confirm the server can receive the client close. 270 server_ops = { 271 CallOps::RECV_CLOSE_ON_SERVER => nil 272 } 273 final_server_batch = server_call.run_batch(server_ops) 274 expect(final_server_batch.send_close).to be true 275 end 276 277 def client_cancel_test(cancel_proc, expected_code, 278 expected_details) 279 call = new_client_call 280 server_call = nil 281 282 server_thread = Thread.new do 283 server_call = server_allows_client_to_proceed 284 end 285 286 client_ops = { 287 CallOps::SEND_INITIAL_METADATA => {}, 288 CallOps::RECV_INITIAL_METADATA => nil 289 } 290 client_batch = call.run_batch(client_ops) 291 expect(client_batch.send_metadata).to be true 292 expect(client_batch.metadata).to eq({}) 293 294 cancel_proc.call(call) 295 296 server_thread.join 297 server_ops = { 298 CallOps::RECV_CLOSE_ON_SERVER => nil 299 } 300 server_batch = server_call.run_batch(server_ops) 301 expect(server_batch.send_close).to be true 302 303 client_ops = { 304 CallOps::RECV_STATUS_ON_CLIENT => {} 305 } 306 client_batch = call.run_batch(client_ops) 307 308 expect(client_batch.status.code).to be expected_code 309 expect(client_batch.status.details).to eq expected_details 310 end 311 312 it 'clients can cancel a call on the server' do 313 expected_code = StatusCodes::CANCELLED 314 expected_details = 'Cancelled' 315 cancel_proc = proc { |call| call.cancel } 316 client_cancel_test(cancel_proc, expected_code, expected_details) 317 end 318 319 it 'cancel_with_status unknown status' do 320 code = StatusCodes::UNKNOWN 321 details = 'test unknown reason' 322 cancel_proc = proc { |call| call.cancel_with_status(code, details) } 323 client_cancel_test(cancel_proc, code, details) 324 end 325 326 it 'cancel_with_status unknown status' do 327 code = StatusCodes::FAILED_PRECONDITION 328 details = 'test failed precondition reason' 329 cancel_proc = proc { |call| call.cancel_with_status(code, details) } 330 client_cancel_test(cancel_proc, code, details) 331 end 332end 333 334shared_examples 'GRPC metadata delivery works OK' do 335 include_context 'setup: tags' 336 337 describe 'from client => server' do 338 before(:example) do 339 n = 7 # arbitrary number of metadata 340 diff_keys_fn = proc { |i| [format('k%d', i), format('v%d', i)] } 341 diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }] 342 null_vals_fn = proc { |i| [format('k%d', i), format('v\0%d', i)] } 343 null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }] 344 same_keys_fn = proc { |i| [format('k%d', i), [format('v%d', i)] * n] } 345 same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }] 346 symbol_key = { a_key: 'a val' } 347 @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key] 348 @bad_keys = [] 349 @bad_keys << { Object.new => 'a value' } 350 @bad_keys << { 1 => 'a value' } 351 end 352 353 it 'raises an exception if a metadata key is invalid' do 354 @bad_keys.each do |md| 355 call = new_client_call 356 client_ops = { 357 CallOps::SEND_INITIAL_METADATA => md 358 } 359 blk = proc do 360 call.run_batch(client_ops) 361 end 362 expect(&blk).to raise_error 363 end 364 end 365 366 it 'sends all the metadata pairs when keys and values are valid' do 367 @valid_metadata.each do |md| 368 recvd_rpc = nil 369 rcv_thread = Thread.new do 370 recvd_rpc = @server.request_call 371 end 372 373 call = new_client_call 374 client_ops = { 375 CallOps::SEND_INITIAL_METADATA => md, 376 CallOps::SEND_CLOSE_FROM_CLIENT => nil 377 } 378 client_batch = call.run_batch(client_ops) 379 expect(client_batch.send_metadata).to be true 380 381 # confirm the server can receive the client metadata 382 rcv_thread.join 383 expect(recvd_rpc).to_not eq nil 384 recvd_md = recvd_rpc.metadata 385 replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }] 386 expect(recvd_md).to eq(recvd_md.merge(replace_symbols)) 387 388 # finish the call 389 final_server_batch = recvd_rpc.call.run_batch( 390 CallOps::RECV_CLOSE_ON_SERVER => nil, 391 CallOps::SEND_INITIAL_METADATA => nil, 392 CallOps::SEND_STATUS_FROM_SERVER => ok_status) 393 expect(final_server_batch.send_close).to be(true) 394 expect(final_server_batch.send_metadata).to be(true) 395 expect(final_server_batch.send_status).to be(true) 396 397 final_client_batch = call.run_batch( 398 CallOps::RECV_INITIAL_METADATA => nil, 399 CallOps::RECV_STATUS_ON_CLIENT => nil) 400 expect(final_client_batch.metadata).to eq({}) 401 expect(final_client_batch.status.code).to eq(0) 402 end 403 end 404 end 405 406 describe 'from server => client' do 407 before(:example) do 408 n = 7 # arbitrary number of metadata 409 diff_keys_fn = proc { |i| [format('k%d', i), format('v%d', i)] } 410 diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }] 411 null_vals_fn = proc { |i| [format('k%d', i), format('v\0%d', i)] } 412 null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }] 413 same_keys_fn = proc { |i| [format('k%d', i), [format('v%d', i)] * n] } 414 same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }] 415 symbol_key = { a_key: 'a val' } 416 @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key] 417 @bad_keys = [] 418 @bad_keys << { Object.new => 'a value' } 419 @bad_keys << { 1 => 'a value' } 420 end 421 422 it 'raises an exception if a metadata key is invalid' do 423 @bad_keys.each do |md| 424 recvd_rpc = nil 425 rcv_thread = Thread.new do 426 recvd_rpc = @server.request_call 427 end 428 429 call = new_client_call 430 # client signals that it's done sending metadata to allow server to 431 # respond 432 client_ops = { 433 CallOps::SEND_INITIAL_METADATA => nil 434 } 435 call.run_batch(client_ops) 436 437 # server gets the invocation 438 rcv_thread.join 439 expect(recvd_rpc).to_not eq nil 440 server_ops = { 441 CallOps::SEND_INITIAL_METADATA => md 442 } 443 blk = proc do 444 recvd_rpc.call.run_batch(server_ops) 445 end 446 expect(&blk).to raise_error 447 448 # cancel the call so the server can shut down immediately 449 call.cancel 450 end 451 end 452 453 it 'sends an empty hash if no metadata is added' do 454 recvd_rpc = nil 455 rcv_thread = Thread.new do 456 recvd_rpc = @server.request_call 457 end 458 459 call = new_client_call 460 # client signals that it's done sending metadata to allow server to 461 # respond 462 client_ops = { 463 CallOps::SEND_INITIAL_METADATA => nil, 464 CallOps::SEND_CLOSE_FROM_CLIENT => nil 465 } 466 client_batch = call.run_batch(client_ops) 467 expect(client_batch.send_metadata).to be true 468 expect(client_batch.send_close).to be true 469 470 # server gets the invocation but sends no metadata back 471 rcv_thread.join 472 expect(recvd_rpc).to_not eq nil 473 server_call = recvd_rpc.call 474 server_ops = { 475 # receive close and send status to finish the call 476 CallOps::RECV_CLOSE_ON_SERVER => nil, 477 CallOps::SEND_INITIAL_METADATA => nil, 478 CallOps::SEND_STATUS_FROM_SERVER => ok_status 479 } 480 srv_batch = server_call.run_batch(server_ops) 481 expect(srv_batch.send_close).to be true 482 expect(srv_batch.send_metadata).to be true 483 expect(srv_batch.send_status).to be true 484 485 # client receives nothing as expected 486 client_ops = { 487 CallOps::RECV_INITIAL_METADATA => nil, 488 # receive status to finish the call 489 CallOps::RECV_STATUS_ON_CLIENT => nil 490 } 491 final_client_batch = call.run_batch(client_ops) 492 expect(final_client_batch.metadata).to eq({}) 493 expect(final_client_batch.status.code).to eq(0) 494 end 495 496 it 'sends all the pairs when keys and values are valid' do 497 @valid_metadata.each do |md| 498 recvd_rpc = nil 499 rcv_thread = Thread.new do 500 recvd_rpc = @server.request_call 501 end 502 503 call = new_client_call 504 # client signals that it's done sending metadata to allow server to 505 # respond 506 client_ops = { 507 CallOps::SEND_INITIAL_METADATA => nil, 508 CallOps::SEND_CLOSE_FROM_CLIENT => nil 509 } 510 client_batch = call.run_batch(client_ops) 511 expect(client_batch.send_metadata).to be true 512 expect(client_batch.send_close).to be true 513 514 # server gets the invocation but sends no metadata back 515 rcv_thread.join 516 expect(recvd_rpc).to_not eq nil 517 server_call = recvd_rpc.call 518 server_ops = { 519 CallOps::RECV_CLOSE_ON_SERVER => nil, 520 CallOps::SEND_INITIAL_METADATA => md, 521 CallOps::SEND_STATUS_FROM_SERVER => ok_status 522 } 523 srv_batch = server_call.run_batch(server_ops) 524 expect(srv_batch.send_close).to be true 525 expect(srv_batch.send_metadata).to be true 526 expect(srv_batch.send_status).to be true 527 528 # client receives nothing as expected 529 client_ops = { 530 CallOps::RECV_INITIAL_METADATA => nil, 531 CallOps::RECV_STATUS_ON_CLIENT => nil 532 } 533 final_client_batch = call.run_batch(client_ops) 534 replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }] 535 expect(final_client_batch.metadata).to eq(replace_symbols) 536 expect(final_client_batch.status.code).to eq(0) 537 end 538 end 539 end 540end 541 542describe 'the http client/server' do 543 before(:example) do 544 server_host = '0.0.0.0:0' 545 @server = new_core_server_for_testing(nil) 546 server_port = @server.add_http2_port(server_host, :this_port_is_insecure) 547 @server.start 548 @ch = Channel.new("0.0.0.0:#{server_port}", nil, :this_channel_is_insecure) 549 end 550 551 after(:example) do 552 @ch.close 553 @server.shutdown_and_notify(deadline) 554 @server.close 555 end 556 557 it_behaves_like 'basic GRPC message delivery is OK' do 558 end 559 560 it_behaves_like 'GRPC metadata delivery works OK' do 561 end 562end 563 564describe 'the secure http client/server' do 565 include_context 'setup: tags' 566 567 def load_test_certs 568 test_root = File.join(File.dirname(__FILE__), 'testdata') 569 files = ['ca.pem', 'server1.key', 'server1.pem'] 570 files.map { |f| File.open(File.join(test_root, f)).read } 571 end 572 573 before(:example) do 574 certs = load_test_certs 575 server_host = '0.0.0.0:0' 576 server_creds = GRPC::Core::ServerCredentials.new( 577 nil, [{ private_key: certs[1], cert_chain: certs[2] }], false) 578 @server = new_core_server_for_testing(nil) 579 server_port = @server.add_http2_port(server_host, server_creds) 580 @server.start 581 args = { Channel::SSL_TARGET => 'foo.test.google.fr' } 582 @ch = Channel.new("0.0.0.0:#{server_port}", args, 583 GRPC::Core::ChannelCredentials.new(certs[0], nil, nil)) 584 end 585 586 after(:example) do 587 @server.shutdown_and_notify(deadline) 588 @server.close 589 end 590 591 it_behaves_like 'basic GRPC message delivery is OK' do 592 end 593 594 it_behaves_like 'GRPC metadata delivery works OK' do 595 end 596 597 def credentials_update_test(creds_update_md) 598 auth_proc = proc { creds_update_md } 599 call_creds = GRPC::Core::CallCredentials.new(auth_proc) 600 601 initial_md_key = 'k2' 602 initial_md_val = 'v2' 603 initial_md = { initial_md_key => initial_md_val } 604 expected_md = creds_update_md.clone 605 fail 'bad test param' unless expected_md[initial_md_key].nil? 606 expected_md[initial_md_key] = initial_md_val 607 608 recvd_rpc = nil 609 rcv_thread = Thread.new do 610 recvd_rpc = @server.request_call 611 end 612 613 call = new_client_call 614 call.set_credentials! call_creds 615 616 client_batch = call.run_batch( 617 CallOps::SEND_INITIAL_METADATA => initial_md, 618 CallOps::SEND_CLOSE_FROM_CLIENT => nil) 619 expect(client_batch.send_metadata).to be true 620 expect(client_batch.send_close).to be true 621 622 # confirm the server can receive the client metadata 623 rcv_thread.join 624 expect(recvd_rpc).to_not eq nil 625 recvd_md = recvd_rpc.metadata 626 replace_symbols = Hash[expected_md.each_pair.collect { |x, y| [x.to_s, y] }] 627 expect(recvd_md).to eq(recvd_md.merge(replace_symbols)) 628 629 credentials_update_test_finish_call(call, recvd_rpc.call) 630 end 631 632 def credentials_update_test_finish_call(client_call, server_call) 633 final_server_batch = server_call.run_batch( 634 CallOps::RECV_CLOSE_ON_SERVER => nil, 635 CallOps::SEND_INITIAL_METADATA => nil, 636 CallOps::SEND_STATUS_FROM_SERVER => ok_status) 637 expect(final_server_batch.send_close).to be(true) 638 expect(final_server_batch.send_metadata).to be(true) 639 expect(final_server_batch.send_status).to be(true) 640 641 final_client_batch = client_call.run_batch( 642 CallOps::RECV_INITIAL_METADATA => nil, 643 CallOps::RECV_STATUS_ON_CLIENT => nil) 644 expect(final_client_batch.metadata).to eq({}) 645 expect(final_client_batch.status.code).to eq(0) 646 end 647 648 it 'modifies metadata with CallCredentials' do 649 credentials_update_test('k1' => 'updated-v1') 650 end 651 652 it 'modifies large metadata with CallCredentials' do 653 val_array = %w( 654 '00000000000000000000000000000000000000000000000000000000000000', 655 '11111111111111111111111111111111111111111111111111111111111111', 656 ) 657 md = { 658 k3: val_array, 659 k4: '0000000000000000000000000000000000000000000000000000000000', 660 keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey5: 'v1' 661 } 662 credentials_update_test(md) 663 end 664end 665