blob: d2f60aaea0cd5af2fd1b225878fe294e414f79a1 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
require 'spec_helper'
describe 'BaseTransport' do
describe Thrift::TransportException do
it "should make type accessible" do
exc = Thrift::TransportException.new(Thrift::TransportException::ALREADY_OPEN, "msg")
expect(exc.type).to eq(Thrift::TransportException::ALREADY_OPEN)
expect(exc.message).to eq("msg")
end
end
describe Thrift::BaseTransport do
it "should read the specified size" do
transport = Thrift::BaseTransport.new
expect(transport).to receive(:read).with(40).ordered.and_return("10 letters")
expect(transport).to receive(:read).with(30).ordered.and_return("fifteen letters")
expect(transport).to receive(:read).with(15).ordered.and_return("more characters")
expect(transport.read_all(40)).to eq("10 lettersfifteen lettersmore characters")
end
it "should stub out the rest of the methods" do
# can't test for stubbiness, so just make sure they're defined
[:open?, :open, :close, :read, :write, :flush].each do |sym|
expect(Thrift::BaseTransport.method_defined?(sym)).to be_truthy
end
end
it "should alias << to write" do
expect(Thrift::BaseTransport.instance_method(:<<)).to eq(Thrift::BaseTransport.instance_method(:write))
end
it "should provide a reasonable to_s" do
expect(Thrift::BaseTransport.new.to_s).to eq("base")
end
end
describe Thrift::BaseServerTransport do
it "should stub out its methods" do
[:listen, :accept, :close].each do |sym|
expect(Thrift::BaseServerTransport.method_defined?(sym)).to be_truthy
end
end
end
describe Thrift::BaseTransportFactory do
it "should return the transport it's given" do
transport = double("Transport")
expect(Thrift::BaseTransportFactory.new.get_transport(transport)).to eql(transport)
end
it "should provide a reasonable to_s" do
expect(Thrift::BaseTransportFactory.new.to_s).to eq("base")
end
end
describe Thrift::BufferedTransport do
it "should provide a to_s that describes the encapsulation" do
trans = double("Transport")
expect(trans).to receive(:to_s).and_return("mock")
expect(Thrift::BufferedTransport.new(trans).to_s).to eq("buffered(mock)")
end
it "should pass through everything but write/flush/read" do
trans = double("Transport")
expect(trans).to receive(:open?).ordered.and_return("+ open?")
expect(trans).to receive(:open).ordered.and_return("+ open")
expect(trans).to receive(:flush).ordered # from the close
expect(trans).to receive(:close).ordered.and_return("+ close")
btrans = Thrift::BufferedTransport.new(trans)
expect(btrans.open?).to eq("+ open?")
expect(btrans.open).to eq("+ open")
expect(btrans.close).to eq("+ close")
end
it "should buffer reads in chunks of #{Thrift::BufferedTransport::DEFAULT_BUFFER}" do
trans = double("Transport")
expect(trans).to receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
btrans = Thrift::BufferedTransport.new(trans)
expect(btrans.read(6)).to eq("lorum ")
expect(btrans.read(6)).to eq("ipsum ")
expect(btrans.read(6)).to eq("dolor ")
expect(btrans.read(6)).to eq("emet")
end
it "should buffer writes and send them on flush" do
trans = double("Transport")
btrans = Thrift::BufferedTransport.new(trans)
btrans.write("one/")
btrans.write("two/")
btrans.write("three/")
expect(trans).to receive(:write).with("one/two/three/").ordered
expect(trans).to receive(:flush).ordered
btrans.flush
end
it "should only send buffered data once" do
trans = double("Transport")
btrans = Thrift::BufferedTransport.new(trans)
btrans.write("one/")
btrans.write("two/")
btrans.write("three/")
expect(trans).to receive(:write).with("one/two/three/")
allow(trans).to receive(:flush)
btrans.flush
# Nothing to flush with no data
btrans.flush
end
it "should flush on close" do
trans = double("Transport")
expect(trans).to receive(:close)
btrans = Thrift::BufferedTransport.new(trans)
expect(btrans).to receive(:flush)
btrans.close
end
it "should not write to socket if there's no data" do
trans = double("Transport")
expect(trans).to receive(:flush)
btrans = Thrift::BufferedTransport.new(trans)
btrans.flush
end
end
describe Thrift::BufferedTransportFactory do
it "should wrap the given transport in a BufferedTransport" do
trans = double("Transport")
btrans = double("BufferedTransport")
expect(Thrift::BufferedTransport).to receive(:new).with(trans).and_return(btrans)
expect(Thrift::BufferedTransportFactory.new.get_transport(trans)).to eq(btrans)
end
it "should provide a reasonable to_s" do
expect(Thrift::BufferedTransportFactory.new.to_s).to eq("buffered")
end
end
describe Thrift::FramedTransport do
before(:each) do
@trans = double("Transport")
end
it "should provide a to_s that describes the encapsulation" do
trans = double("Transport")
expect(trans).to receive(:to_s).and_return("mock")
expect(Thrift::FramedTransport.new(trans).to_s).to eq("framed(mock)")
end
it "should pass through open?/open/close" do
ftrans = Thrift::FramedTransport.new(@trans)
expect(@trans).to receive(:open?).ordered.and_return("+ open?")
expect(@trans).to receive(:open).ordered.and_return("+ open")
expect(@trans).to receive(:close).ordered.and_return("+ close")
expect(ftrans.open?).to eq("+ open?")
expect(ftrans.open).to eq("+ open")
expect(ftrans.close).to eq("+ close")
end
it "should pass through read when read is turned off" do
ftrans = Thrift::FramedTransport.new(@trans, false, true)
expect(@trans).to receive(:read).with(17).ordered.and_return("+ read")
expect(ftrans.read(17)).to eq("+ read")
end
it "should pass through write/flush when write is turned off" do
ftrans = Thrift::FramedTransport.new(@trans, true, false)
expect(@trans).to receive(:write).with("foo").ordered.and_return("+ write")
expect(@trans).to receive(:flush).ordered.and_return("+ flush")
expect(ftrans.write("foo")).to eq("+ write")
expect(ftrans.flush).to eq("+ flush")
end
it "should return a full frame if asked for >= the frame's length" do
frame = "this is a frame"
expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017")
expect(@trans).to receive(:read_all).with(frame.length).and_return(frame)
expect(Thrift::FramedTransport.new(@trans).read(frame.length + 10)).to eq(frame)
end
it "should return slices of the frame when asked for < the frame's length" do
frame = "this is a frame"
expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017")
expect(@trans).to receive(:read_all).with(frame.length).and_return(frame)
ftrans = Thrift::FramedTransport.new(@trans)
expect(ftrans.read(4)).to eq("this")
expect(ftrans.read(4)).to eq(" is ")
expect(ftrans.read(16)).to eq("a frame")
end
it "should return nothing if asked for <= 0" do
expect(Thrift::FramedTransport.new(@trans).read(-2)).to eq("")
end
it "should pull a new frame when the first is exhausted" do
frame = "this is a frame"
frame2 = "yet another frame"
expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
expect(@trans).to receive(:read_all).with(frame.length).and_return(frame)
expect(@trans).to receive(:read_all).with(frame2.length).and_return(frame2)
ftrans = Thrift::FramedTransport.new(@trans)
expect(ftrans.read(4)).to eq("this")
expect(ftrans.read(8)).to eq(" is a fr")
expect(ftrans.read(6)).to eq("ame")
expect(ftrans.read(4)).to eq("yet ")
expect(ftrans.read(16)).to eq("another frame")
end
it "should buffer writes" do
ftrans = Thrift::FramedTransport.new(@trans)
expect(@trans).not_to receive(:write)
ftrans.write("foo")
ftrans.write("bar")
ftrans.write("this is a frame")
end
it "should write slices of the buffer" do
ftrans = Thrift::FramedTransport.new(@trans)
ftrans.write("foobar", 3)
ftrans.write("barfoo", 1)
allow(@trans).to receive(:flush)
expect(@trans).to receive(:write).with("\000\000\000\004foob")
ftrans.flush
end
it "should flush frames with a 4-byte header" do
ftrans = Thrift::FramedTransport.new(@trans)
expect(@trans).to receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
expect(@trans).to receive(:flush).ordered
ftrans.write("one/")
ftrans.write("two/")
ftrans.write("three/")
ftrans.write("this is a frame")
ftrans.flush
end
it "should not flush the same buffered data twice" do
ftrans = Thrift::FramedTransport.new(@trans)
expect(@trans).to receive(:write).with("\000\000\000\007foo/bar")
allow(@trans).to receive(:flush)
ftrans.write("foo")
ftrans.write("/bar")
ftrans.flush
expect(@trans).to receive(:write).with("\000\000\000\000")
ftrans.flush
end
end
describe Thrift::FramedTransportFactory do
it "should wrap the given transport in a FramedTransport" do
trans = double("Transport")
expect(Thrift::FramedTransport).to receive(:new).with(trans)
Thrift::FramedTransportFactory.new.get_transport(trans)
end
it "should provide a reasonable to_s" do
expect(Thrift::FramedTransportFactory.new.to_s).to eq("framed")
end
end
describe Thrift::MemoryBufferTransport do
before(:each) do
@buffer = Thrift::MemoryBufferTransport.new
end
it "should provide a reasonable to_s" do
expect(@buffer.to_s).to eq("memory")
end
it "should accept a buffer on input and use it directly" do
s = "this is a test"
@buffer = Thrift::MemoryBufferTransport.new(s)
expect(@buffer.read(4)).to eq("this")
s.slice!(-4..-1)
expect(@buffer.read(@buffer.available)).to eq(" is a ")
end
it "should always remain open" do
expect(@buffer).to be_open
@buffer.close
expect(@buffer).to be_open
end
it "should respond to peek and available" do
@buffer.write "some data"
expect(@buffer.peek).to be_truthy
expect(@buffer.available).to eq(9)
@buffer.read(4)
expect(@buffer.peek).to be_truthy
expect(@buffer.available).to eq(5)
@buffer.read(5)
expect(@buffer.peek).to be_falsey
expect(@buffer.available).to eq(0)
end
it "should be able to reset the buffer" do
@buffer.write "test data"
@buffer.reset_buffer("foobar")
expect(@buffer.available).to eq(6)
expect(@buffer.read(@buffer.available)).to eq("foobar")
@buffer.reset_buffer
expect(@buffer.available).to eq(0)
end
it "should copy the given string when resetting the buffer" do
s = "this is a test"
@buffer.reset_buffer(s)
expect(@buffer.available).to eq(14)
@buffer.read(10)
expect(@buffer.available).to eq(4)
expect(s).to eq("this is a test")
end
it "should return from read what was given in write" do
@buffer.write "test data"
expect(@buffer.read(4)).to eq("test")
expect(@buffer.read(@buffer.available)).to eq(" data")
@buffer.write "foo"
@buffer.write " bar"
expect(@buffer.read(@buffer.available)).to eq("foo bar")
end
it "should throw an EOFError when there isn't enough data in the buffer" do
@buffer.reset_buffer("")
expect{@buffer.read(1)}.to raise_error(EOFError)
@buffer.reset_buffer("1234")
expect{@buffer.read(5)}.to raise_error(EOFError)
end
end
describe Thrift::IOStreamTransport do
before(:each) do
@input = double("Input", :closed? => false)
@output = double("Output", :closed? => false)
@trans = Thrift::IOStreamTransport.new(@input, @output)
end
it "should provide a reasonable to_s" do
expect(@input).to receive(:to_s).and_return("mock_input")
expect(@output).to receive(:to_s).and_return("mock_output")
expect(@trans.to_s).to eq("iostream(input=mock_input,output=mock_output)")
end
it "should be open as long as both input or output are open" do
expect(@trans).to be_open
allow(@input).to receive(:closed?).and_return(true)
expect(@trans).to be_open
allow(@input).to receive(:closed?).and_return(false)
allow(@output).to receive(:closed?).and_return(true)
expect(@trans).to be_open
allow(@input).to receive(:closed?).and_return(true)
expect(@trans).not_to be_open
end
it "should pass through read/write to input/output" do
expect(@input).to receive(:read).with(17).and_return("+ read")
expect(@output).to receive(:write).with("foobar").and_return("+ write")
expect(@trans.read(17)).to eq("+ read")
expect(@trans.write("foobar")).to eq("+ write")
end
it "should close both input and output when closed" do
expect(@input).to receive(:close)
expect(@output).to receive(:close)
@trans.close
end
end
end