# frozen_string_literal: true require_relative '../../spec_helper' require 'tempfile' require 'pathname' module Seahorse module Client describe Request do let(:handlers) { HandlerList.new } let(:context) { RequestContext.new } let(:request) { Request.new(handlers, context) } it 'is a HandlerBuilder' do expect(request).to be_kind_of(HandlerBuilder) end describe '#handlers' do it 'returns the handler list' do handlers = HandlerList.new request = Request.new(handlers, context) expect(request.handlers).to be(handlers) end end describe '#context' do it 'returns the request context given the constructor' do context = RequestContext.new request = Request.new(handlers, context) expect(request.context).to be(context) end end describe '#send_request' do it 'contructs a stack from the handler list' do expect(handlers).to receive(:to_stack).and_return(->(context) {}) request.send_request end it 'returns the response from the handler stack #call method' do response = double('response') allow(handlers).to receive(:to_stack).and_return(->(_) { response }) expect(request.send_request).to be(response) end it 'passes the request context to the handler stack' do passed = nil allow(handlers).to receive(:to_stack). and_return(->(context) { passed = context }) request.send_request expect(passed).to be(context) end it 'returns the response from the handler stack' do resp = Response.new allow(handlers).to receive(:to_stack).and_return(->(context) { resp }) expect(Request.new(handlers, context).send_request).to be(resp) end end describe '#send_request with a target' do let(:handler) do Proc.new do context.http_response.signal_headers(200, {'content-length' => '15'}) context.http_response.signal_data('part1') context.http_response.signal_data('part2') context.http_response.signal_data('part3') context.http_response.signal_done Response.new(context: context) end end before(:each) do handlers.add(Plugins::ResponseTarget::Handler, step: :initialize) handlers.add(double('send-handler-class', new: handler)) end describe 'String target' do it 'writes to the file named' do tmpfile = Tempfile.new('tempfile') tmpfile.close request.send_request(target: tmpfile.path) expect(File.read(tmpfile.path)).to eq("part1part2part3") end it 'closes the file before returning the response' do tmpfile = Tempfile.new('tempfile') tmpfile.close resp = request.send_request(target: tmpfile.path) expect(resp.context.http_response.body).to be_closed end end describe 'Pathname target' do it 'writes to the file named' do tmpfile = Tempfile.new('tempfile') tmpfile.close request.send_request(target: Pathname.new(tmpfile.path)) expect(File.read(tmpfile.path)).to eq("part1part2part3") end it 'closes the file before returning the response' do tmpfile = Tempfile.new('tempfile') tmpfile.close resp = request.send_request(target: Pathname.new(tmpfile.path)) expect(resp.context.http_response.body).to be_closed end end describe 'IO object target' do it 'writes to the given object' do buffer = StringIO.new(String.new) request.send_request(target: buffer) expect(buffer.string).to eq("part1part2part3") end end describe 'target from params' do it 'writes the response to the optional :response_target param' do tempfile = Tempfile.new('response-target') tempfile.close context.params[:response_target] = tempfile.path request.send_request expect(File.read(tempfile.path)).to eq('part1part2part3') end end describe 'Block target' do it 'streams data from the handler to the #send_request block' do data = [] request.send_request { |chunk| data << chunk } expect(data).to eq(['part1', 'part2', 'part3']) end it 'counts the bytes yielded' do resp = request.send_request { |chunk| } expect(resp.context.http_response.body.size).to eq(15) end it 'does not buffer the response chunks' do response = request.send_request { |chunk| } body = response.context.http_response.body expect(body.read).to eq('') expect(body).not_to respond_to(:truncate) end it 'passes the headers to the #send_request block' do headers = nil request.send_request { |_chunk, header| headers = header } expect(headers).to be_an_instance_of(Seahorse::Client::Http::Headers) expect(headers['content-length']).to eq('15') end describe '2xx responses, not 200' do let(:handler) do Proc.new do context.http_response.signal_headers(206, {}) context.http_response.signal_data('part1') context.http_response.signal_data('part2') context.http_response.signal_data('part3') context.http_response.signal_done Response.new(context: context) end end it 'streams data from the handler to the #send_request block' do data = [] request.send_request { |chunk| data << chunk } expect(data).to eq(['part1', 'part2', 'part3']) end end end end end end end