1# 2# Licensed to the Apache Software Foundation (ASF) under one 3# or more contributor license agreements. See the NOTICE file 4# distributed with this work for additional information 5# regarding copyright ownership. The ASF licenses this file 6# to you under the Apache License, Version 2.0 (the 7# "License"); you may not use this file except in compliance 8# with the License. You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, 13# software distributed under the License is distributed on an 14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15# KIND, either express or implied. See the License for the 16# specific language governing permissions and limitations 17# under the License. 18# 19require 'spec_helper' 20 21describe 'Server' do 22 23 describe Thrift::BaseServer do 24 before(:each) do 25 @processor = double("Processor") 26 @serverTrans = double("ServerTransport") 27 @trans = double("BaseTransport") 28 @prot = double("BaseProtocol") 29 @server = described_class.new(@processor, @serverTrans, @trans, @prot) 30 end 31 32 it "should default to BaseTransportFactory and BinaryProtocolFactory when not specified" do 33 @server = Thrift::BaseServer.new(double("Processor"), double("BaseServerTransport")) 34 expect(@server.instance_variable_get(:'@transport_factory')).to be_an_instance_of(Thrift::BaseTransportFactory) 35 expect(@server.instance_variable_get(:'@protocol_factory')).to be_an_instance_of(Thrift::BinaryProtocolFactory) 36 end 37 38 it "should not serve" do 39 expect { @server.serve()}.to raise_error(NotImplementedError) 40 end 41 42 it "should provide a reasonable to_s" do 43 expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans") 44 expect(@trans).to receive(:to_s).once.and_return("trans") 45 expect(@prot).to receive(:to_s).once.and_return("prot") 46 expect(@server.to_s).to eq("server(prot(trans(serverTrans)))") 47 end 48 end 49 50 describe Thrift::SimpleServer do 51 before(:each) do 52 @processor = double("Processor") 53 @serverTrans = double("ServerTransport") 54 @trans = double("BaseTransport") 55 @prot = double("BaseProtocol") 56 @client = double("Client") 57 @server = described_class.new(@processor, @serverTrans, @trans, @prot) 58 end 59 60 it "should provide a reasonable to_s" do 61 expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans") 62 expect(@trans).to receive(:to_s).once.and_return("trans") 63 expect(@prot).to receive(:to_s).once.and_return("prot") 64 expect(@server.to_s).to eq("simple(server(prot(trans(serverTrans))))") 65 end 66 67 it "should serve in the main thread" do 68 expect(@serverTrans).to receive(:listen).ordered 69 expect(@serverTrans).to receive(:accept).exactly(3).times.and_return(@client) 70 expect(@trans).to receive(:get_transport).exactly(3).times.with(@client).and_return(@trans) 71 expect(@prot).to receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot) 72 x = 0 73 expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do 74 case (x += 1) 75 when 1 then raise Thrift::TransportException 76 when 2 then raise Thrift::ProtocolException 77 when 3 then throw :stop 78 end 79 end 80 expect(@trans).to receive(:close).exactly(3).times 81 expect(@serverTrans).to receive(:close).ordered 82 expect { @server.serve }.to throw_symbol(:stop) 83 end 84 end 85 86 describe Thrift::ThreadedServer do 87 before(:each) do 88 @processor = double("Processor") 89 @serverTrans = double("ServerTransport") 90 @trans = double("BaseTransport") 91 @prot = double("BaseProtocol") 92 @client = double("Client") 93 @server = described_class.new(@processor, @serverTrans, @trans, @prot) 94 end 95 96 it "should provide a reasonable to_s" do 97 expect(@serverTrans).to receive(:to_s).once.and_return("serverTrans") 98 expect(@trans).to receive(:to_s).once.and_return("trans") 99 expect(@prot).to receive(:to_s).once.and_return("prot") 100 expect(@server.to_s).to eq("threaded(server(prot(trans(serverTrans))))") 101 end 102 103 it "should serve using threads" do 104 expect(@serverTrans).to receive(:listen).ordered 105 expect(@serverTrans).to receive(:accept).exactly(3).times.and_return(@client) 106 expect(@trans).to receive(:get_transport).exactly(3).times.with(@client).and_return(@trans) 107 expect(@prot).to receive(:get_protocol).exactly(3).times.with(@trans).and_return(@prot) 108 expect(Thread).to receive(:new).with(@prot, @trans).exactly(3).times.and_yield(@prot, @trans) 109 x = 0 110 expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do 111 case (x += 1) 112 when 1 then raise Thrift::TransportException 113 when 2 then raise Thrift::ProtocolException 114 when 3 then throw :stop 115 end 116 end 117 expect(@trans).to receive(:close).exactly(3).times 118 expect(@serverTrans).to receive(:close).ordered 119 expect { @server.serve }.to throw_symbol(:stop) 120 end 121 end 122 123 describe Thrift::ThreadPoolServer do 124 before(:each) do 125 @processor = double("Processor") 126 @server_trans = double("ServerTransport") 127 @trans = double("BaseTransport") 128 @prot = double("BaseProtocol") 129 @client = double("Client") 130 @server = described_class.new(@processor, @server_trans, @trans, @prot) 131 sleep(0.15) 132 end 133 134 it "should provide a reasonable to_s" do 135 expect(@server_trans).to receive(:to_s).once.and_return("server_trans") 136 expect(@trans).to receive(:to_s).once.and_return("trans") 137 expect(@prot).to receive(:to_s).once.and_return("prot") 138 expect(@server.to_s).to eq("threadpool(server(prot(trans(server_trans))))") 139 end 140 141 it "should serve inside a thread" do 142 exception_q = @server.instance_variable_get(:@exception_q) 143 expect_any_instance_of(described_class).to receive(:serve) do 144 exception_q.push(StandardError.new('ERROR')) 145 end 146 expect { @server.rescuable_serve }.to(raise_error('ERROR')) 147 sleep(0.15) 148 end 149 150 it "should avoid running the server twice when retrying rescuable_serve" do 151 exception_q = @server.instance_variable_get(:@exception_q) 152 expect_any_instance_of(described_class).to receive(:serve) do 153 exception_q.push(StandardError.new('ERROR1')) 154 exception_q.push(StandardError.new('ERROR2')) 155 end 156 expect { @server.rescuable_serve }.to(raise_error('ERROR1')) 157 expect { @server.rescuable_serve }.to(raise_error('ERROR2')) 158 end 159 160 it "should serve using a thread pool" do 161 thread_q = double("SizedQueue") 162 exception_q = double("Queue") 163 @server.instance_variable_set(:@thread_q, thread_q) 164 @server.instance_variable_set(:@exception_q, exception_q) 165 expect(@server_trans).to receive(:listen).ordered 166 expect(thread_q).to receive(:push).with(:token) 167 expect(thread_q).to receive(:pop) 168 expect(Thread).to receive(:new).and_yield 169 expect(@server_trans).to receive(:accept).exactly(3).times.and_return(@client) 170 expect(@trans).to receive(:get_transport).exactly(3).times.and_return(@trans) 171 expect(@prot).to receive(:get_protocol).exactly(3).times.and_return(@prot) 172 x = 0 173 error = RuntimeError.new("Stopped") 174 expect(@processor).to receive(:process).exactly(3).times.with(@prot, @prot) do 175 case (x += 1) 176 when 1 then raise Thrift::TransportException 177 when 2 then raise Thrift::ProtocolException 178 when 3 then raise error 179 end 180 end 181 expect(@trans).to receive(:close).exactly(3).times 182 expect(exception_q).to receive(:push).with(error).and_throw(:stop) 183 expect(@server_trans).to receive(:close) 184 expect { @server.serve }.to(throw_symbol(:stop)) 185 end 186 end 187end 188