| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 | # 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.require 'grpc'require 'spec_helper'include GRPC::Coredef load_test_certs  test_root = File.join(File.dirname(__FILE__), 'testdata')  files = ['ca.pem', 'server1.key', 'server1.pem']  files.map { |f| File.open(File.join(test_root, f)).read }endshared_context 'setup: tags' do  let(:sent_message) { 'sent message' }  let(:reply_text) { 'the reply' }  before(:example) do    @server_finished_tag = Object.new    @client_finished_tag = Object.new    @client_metadata_tag = Object.new    @server_tag = Object.new    @tag = Object.new  end  def deadline    Time.now + 2  end  def server_allows_client_to_proceed    recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)    expect(recvd_rpc).to_not eq nil    server_call = recvd_rpc.call    ops = { CallOps::SEND_INITIAL_METADATA => {} }    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, ops)    expect(svr_batch.send_metadata).to be true    server_call  end  def new_client_call    @ch.create_call(@client_queue, '/method', 'foo.test.google.fr', deadline)  endendshared_examples 'basic GRPC message delivery is OK' do  include GRPC::Core  include_context 'setup: tags'  it 'servers receive requests from clients and can respond' do    call = new_client_call    client_ops = {      CallOps::SEND_INITIAL_METADATA => {},      CallOps::SEND_MESSAGE => sent_message    }    batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                  client_ops)    expect(batch_result.send_metadata).to be true    expect(batch_result.send_message).to be true    # confirm the server can read the inbound message    server_call = server_allows_client_to_proceed    server_ops = {      CallOps::RECV_MESSAGE => nil    }    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,                                      server_ops)    expect(svr_batch.message).to eq(sent_message)  end  it 'responses written by servers are received by the client' do    call = new_client_call    client_ops = {      CallOps::SEND_INITIAL_METADATA => {},      CallOps::SEND_MESSAGE => sent_message    }    batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                  client_ops)    expect(batch_result.send_metadata).to be true    expect(batch_result.send_message).to be true    # confirm the server can read the inbound message    server_call = server_allows_client_to_proceed    server_ops = {      CallOps::RECV_MESSAGE => nil,      CallOps::SEND_MESSAGE => reply_text    }    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,                                      server_ops)    expect(svr_batch.message).to eq(sent_message)    expect(svr_batch.send_message).to be true  end  it 'servers can ignore a client write and send a status' do    call = new_client_call    client_ops = {      CallOps::SEND_INITIAL_METADATA => {},      CallOps::SEND_MESSAGE => sent_message    }    batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                  client_ops)    expect(batch_result.send_metadata).to be true    expect(batch_result.send_message).to be true    # confirm the server can read the inbound message    the_status = Struct::Status.new(StatusCodes::OK, 'OK')    server_call = server_allows_client_to_proceed    server_ops = {      CallOps::SEND_STATUS_FROM_SERVER => the_status    }    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,                                      server_ops)    expect(svr_batch.message).to eq nil    expect(svr_batch.send_status).to be true  end  it 'completes calls by sending status to client and server' do    call = new_client_call    client_ops = {      CallOps::SEND_INITIAL_METADATA => {},      CallOps::SEND_MESSAGE => sent_message    }    batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                  client_ops)    expect(batch_result.send_metadata).to be true    expect(batch_result.send_message).to be true    # confirm the server can read the inbound message and respond    the_status = Struct::Status.new(StatusCodes::OK, 'OK', {})    server_call = server_allows_client_to_proceed    server_ops = {      CallOps::RECV_MESSAGE => nil,      CallOps::SEND_MESSAGE => reply_text,      CallOps::SEND_STATUS_FROM_SERVER => the_status    }    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,                                      server_ops)    expect(svr_batch.message).to eq sent_message    expect(svr_batch.send_status).to be true    expect(svr_batch.send_message).to be true    # confirm the client can receive the server response and status.    client_ops = {      CallOps::SEND_CLOSE_FROM_CLIENT => nil,      CallOps::RECV_MESSAGE => nil,      CallOps::RECV_STATUS_ON_CLIENT => nil    }    batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                  client_ops)    expect(batch_result.send_close).to be true    expect(batch_result.message).to eq reply_text    expect(batch_result.status).to eq the_status    # confirm the server can receive the client close.    server_ops = {      CallOps::RECV_CLOSE_ON_SERVER => nil    }    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,                                      server_ops)    expect(svr_batch.send_close).to be true  endendshared_examples 'GRPC metadata delivery works OK' do  include_context 'setup: tags'  describe 'from client => server' do    before(:example) do      n = 7  # arbitrary number of metadata      diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }      diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]      null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }      null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]      same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }      same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]      symbol_key = { a_key: 'a val' }      @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]      @bad_keys = []      @bad_keys << { Object.new => 'a value' }      @bad_keys << { 1 => 'a value' }    end    it 'raises an exception if a metadata key is invalid' do      @bad_keys.each do |md|        call = new_client_call        client_ops = {          CallOps::SEND_INITIAL_METADATA => md        }        blk = proc do          call.run_batch(@client_queue, @client_tag, deadline,                         client_ops)        end        expect(&blk).to raise_error      end    end    it 'sends all the metadata pairs when keys and values are valid' do      @valid_metadata.each do |md|        call = new_client_call        client_ops = {          CallOps::SEND_INITIAL_METADATA => md        }        batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                      client_ops)        expect(batch_result.send_metadata).to be true        # confirm the server can receive the client metadata        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)        expect(recvd_rpc).to_not eq nil        recvd_md = recvd_rpc.metadata        replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]        expect(recvd_md).to eq(recvd_md.merge(replace_symbols))      end    end  end  describe 'from server => client' do    before(:example) do      n = 7  # arbitrary number of metadata      diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }      diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]      null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }      null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]      same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }      same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]      symbol_key = { a_key: 'a val' }      @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]      @bad_keys = []      @bad_keys << { Object.new => 'a value' }      @bad_keys << { 1 => 'a value' }    end    it 'raises an exception if a metadata key is invalid' do      @bad_keys.each do |md|        call = new_client_call        # client signals that it's done sending metadata to allow server to        # respond        client_ops = {          CallOps::SEND_INITIAL_METADATA => nil        }        call.run_batch(@client_queue, @client_tag, deadline, client_ops)        # server gets the invocation        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)        expect(recvd_rpc).to_not eq nil        server_ops = {          CallOps::SEND_INITIAL_METADATA => md        }        blk = proc do          recvd_rpc.call.run_batch(@server_queue, @server_tag, deadline,                                   server_ops)        end        expect(&blk).to raise_error      end    end    it 'sends an empty hash if no metadata is added' do      call = new_client_call      # client signals that it's done sending metadata to allow server to      # respond      client_ops = {        CallOps::SEND_INITIAL_METADATA => nil      }      call.run_batch(@client_queue, @client_tag, deadline, client_ops)      # server gets the invocation but sends no metadata back      recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)      expect(recvd_rpc).to_not eq nil      server_call = recvd_rpc.call      server_ops = {        CallOps::SEND_INITIAL_METADATA => nil      }      server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)      # client receives nothing as expected      client_ops = {        CallOps::RECV_INITIAL_METADATA => nil      }      batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                    client_ops)      expect(batch_result.metadata).to eq({})    end    it 'sends all the pairs when keys and values are valid' do      @valid_metadata.each do |md|        call = new_client_call        # client signals that it's done sending metadata to allow server to        # respond        client_ops = {          CallOps::SEND_INITIAL_METADATA => nil        }        call.run_batch(@client_queue, @client_tag, deadline, client_ops)        # server gets the invocation but sends no metadata back        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)        expect(recvd_rpc).to_not eq nil        server_call = recvd_rpc.call        server_ops = {          CallOps::SEND_INITIAL_METADATA => md        }        server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)        # client receives nothing as expected        client_ops = {          CallOps::RECV_INITIAL_METADATA => nil        }        batch_result = call.run_batch(@client_queue, @client_tag, deadline,                                      client_ops)        replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]        expect(batch_result.metadata).to eq(replace_symbols)      end    end  endenddescribe 'the http client/server' do  before(:example) do    server_host = '0.0.0.0:0'    @client_queue = GRPC::Core::CompletionQueue.new    @server_queue = GRPC::Core::CompletionQueue.new    @server = GRPC::Core::Server.new(@server_queue, nil)    server_port = @server.add_http2_port(server_host)    @server.start    @ch = Channel.new("0.0.0.0:#{server_port}", nil)  end  after(:example) do    @ch.close    @server.close  end  it_behaves_like 'basic GRPC message delivery is OK' do  end  it_behaves_like 'GRPC metadata delivery works OK' do  endenddescribe 'the secure http client/server' do  before(:example) do    certs = load_test_certs    server_host = '0.0.0.0:0'    @client_queue = GRPC::Core::CompletionQueue.new    @server_queue = GRPC::Core::CompletionQueue.new    server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])    @server = GRPC::Core::Server.new(@server_queue, nil)    server_port = @server.add_http2_port(server_host, server_creds)    @server.start    args = { Channel::SSL_TARGET => 'foo.test.google.fr' }    @ch = Channel.new("0.0.0.0:#{server_port}", args,                      GRPC::Core::Credentials.new(certs[0], nil, nil))  end  after(:example) do    @server.close  end  it_behaves_like 'basic GRPC message delivery is OK' do  end  it_behaves_like 'GRPC metadata delivery works OK' do  endend
 |