Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame^] | 1 | require File.dirname(__FILE__) + '/spec_helper' |
| 2 | |
| 3 | class ThriftTransportSpec < Spec::ExampleGroup |
| 4 | include Thrift |
| 5 | |
| 6 | describe TransportException do |
| 7 | it "should make type accessible" do |
| 8 | exc = TransportException.new(TransportException::ALREADY_OPEN, "msg") |
| 9 | exc.type.should == TransportException::ALREADY_OPEN |
| 10 | exc.message.should == "msg" |
| 11 | end |
| 12 | end |
| 13 | |
| 14 | describe Transport do |
| 15 | it "should read the specified size" do |
| 16 | transport = Transport.new |
| 17 | transport.should_receive(:read).with(40).ordered.and_return("10 letters") |
| 18 | transport.should_receive(:read).with(30).ordered.and_return("fifteen letters") |
| 19 | transport.should_receive(:read).with(15).ordered.and_return("more characters") |
| 20 | transport.read_all(40).should == "10 lettersfifteen lettersmore characters" |
| 21 | end |
| 22 | |
| 23 | it "should stub out the rest of the methods" do |
| 24 | # can't test for stubbiness, so just make sure they're defined |
| 25 | [:open?, :open, :close, :read, :write, :flush].each do |sym| |
| 26 | Transport.method_defined?(sym).should be_true |
| 27 | end |
| 28 | end |
| 29 | end |
| 30 | |
| 31 | describe ServerTransport do |
| 32 | it "should stub out its methods" do |
| 33 | [:listen, :accept, :close].each do |sym| |
| 34 | ServerTransport.method_defined?(sym).should be_true |
| 35 | end |
| 36 | end |
| 37 | end |
| 38 | |
| 39 | describe TransportFactory do |
| 40 | it "should return the transport it's given" do |
| 41 | transport = mock("Transport") |
| 42 | TransportFactory.new.get_transport(transport).should eql(transport) |
| 43 | end |
| 44 | end |
| 45 | |
| 46 | describe BufferedTransport do |
| 47 | it "should pass through everything but write/flush" do |
| 48 | trans = mock("Transport") |
| 49 | trans.should_receive(:open?).ordered.and_return("+ open?") |
| 50 | trans.should_receive(:open).ordered.and_return("+ open") |
| 51 | trans.should_receive(:close).ordered.and_return("+ close") |
| 52 | trans.should_receive(:read).with(217).ordered.and_return("+ read") |
| 53 | btrans = BufferedTransport.new(trans) |
| 54 | btrans.open?.should == "+ open?" |
| 55 | btrans.open.should == "+ open" |
| 56 | btrans.close.should == "+ close" |
| 57 | btrans.read(217).should == "+ read" |
| 58 | end |
| 59 | |
| 60 | it "should buffer writes and send them on flush" do |
| 61 | trans = mock("Transport") |
| 62 | btrans = BufferedTransport.new(trans) |
| 63 | btrans.write("one/") |
| 64 | btrans.write("two/") |
| 65 | btrans.write("three/") |
| 66 | trans.should_receive(:write).with("one/two/three/").ordered |
| 67 | trans.should_receive(:flush).ordered |
| 68 | btrans.flush |
| 69 | end |
| 70 | |
| 71 | it "should only send buffered data once" do |
| 72 | trans = mock("Transport") |
| 73 | btrans = BufferedTransport.new(trans) |
| 74 | btrans.write("one/") |
| 75 | btrans.write("two/") |
| 76 | btrans.write("three/") |
| 77 | trans.should_receive(:write).with("one/two/three/") |
| 78 | trans.stub!(:flush) |
| 79 | btrans.flush |
| 80 | trans.should_receive(:write).with("") |
| 81 | btrans.flush |
| 82 | end |
| 83 | end |
| 84 | |
| 85 | describe BufferedTransportFactory do |
| 86 | it "should wrap the given transport in a BufferedTransport" do |
| 87 | trans = mock("Transport") |
| 88 | btrans = mock("BufferedTransport") |
| 89 | BufferedTransport.should_receive(:new).with(trans).and_return(btrans) |
| 90 | BufferedTransportFactory.new.get_transport(trans).should == btrans |
| 91 | end |
| 92 | end |
| 93 | |
| 94 | describe FramedTransport do |
| 95 | before(:each) do |
| 96 | @trans = mock("Transport") |
| 97 | end |
| 98 | |
| 99 | it "should pass through open?/open/close" do |
| 100 | ftrans = FramedTransport.new(@trans) |
| 101 | @trans.should_receive(:open?).ordered.and_return("+ open?") |
| 102 | @trans.should_receive(:open).ordered.and_return("+ open") |
| 103 | @trans.should_receive(:close).ordered.and_return("+ close") |
| 104 | ftrans.open?.should == "+ open?" |
| 105 | ftrans.open.should == "+ open" |
| 106 | ftrans.close.should == "+ close" |
| 107 | end |
| 108 | |
| 109 | it "should pass through read when read is turned off" do |
| 110 | ftrans = FramedTransport.new(@trans, false, true) |
| 111 | @trans.should_receive(:read).with(17).ordered.and_return("+ read") |
| 112 | ftrans.read(17).should == "+ read" |
| 113 | end |
| 114 | |
| 115 | it "should pass through write/flush when write is turned off" do |
| 116 | ftrans = FramedTransport.new(@trans, true, false) |
| 117 | @trans.should_receive(:write).with("foo").ordered.and_return("+ write") |
| 118 | @trans.should_receive(:flush).ordered.and_return("+ flush") |
| 119 | ftrans.write("foo").should == "+ write" |
| 120 | ftrans.flush.should == "+ flush" |
| 121 | end |
| 122 | |
| 123 | it "should return a full frame if asked for >= the frame's length" do |
| 124 | frame = "this is a frame" |
| 125 | @trans.should_receive(:read_all).with(4).and_return([frame.length].pack('N')) |
| 126 | @trans.should_receive(:read_all).with(frame.length).and_return(frame) |
| 127 | FramedTransport.new(@trans).read(frame.length + 10).should == frame |
| 128 | end |
| 129 | |
| 130 | it "should return slices of the frame when asked for < the frame's length" do |
| 131 | frame = "this is a frame" |
| 132 | @trans.should_receive(:read_all).with(4).and_return([frame.length].pack('N')) |
| 133 | @trans.should_receive(:read_all).with(frame.length).and_return(frame) |
| 134 | ftrans = FramedTransport.new(@trans) |
| 135 | ftrans.read(4).should == "this" |
| 136 | ftrans.read(4).should == " is " |
| 137 | ftrans.read(16).should == "a frame" |
| 138 | end |
| 139 | |
| 140 | it "should pull a new frame when the first is exhausted" do |
| 141 | frame = "this is a frame" |
| 142 | frame2 = "yet another frame" |
| 143 | @trans.should_receive(:read_all).with(4).and_return([frame.length].pack('N'), |
| 144 | [frame2.length].pack('N')) |
| 145 | @trans.should_receive(:read_all).with(frame.length).and_return(frame) |
| 146 | @trans.should_receive(:read_all).with(frame2.length).and_return(frame2) |
| 147 | ftrans = FramedTransport.new(@trans) |
| 148 | ftrans.read(4).should == "this" |
| 149 | ftrans.read(8).should == " is a fr" |
| 150 | ftrans.read(6).should == "ame" |
| 151 | ftrans.read(4).should == "yet " |
| 152 | ftrans.read(16).should == "another frame" |
| 153 | end |
| 154 | |
| 155 | it "should buffer writes" do |
| 156 | ftrans = FramedTransport.new(@trans) |
| 157 | @trans.should_not_receive(:write) |
| 158 | ftrans.write("foo") |
| 159 | ftrans.write("bar") |
| 160 | ftrans.write("this is a frame") |
| 161 | end |
| 162 | |
| 163 | it "should flush frames with a 4-byte header" do |
| 164 | ftrans = FramedTransport.new(@trans) |
| 165 | frame = "one/two/three/this is a frame" |
| 166 | out = [frame.length].pack('N') |
| 167 | out << frame |
| 168 | @trans.should_receive(:write).with(out).ordered |
| 169 | @trans.should_receive(:flush).ordered |
| 170 | ftrans.write("one/") |
| 171 | ftrans.write("two/") |
| 172 | ftrans.write("three/") |
| 173 | ftrans.write("this is a frame") |
| 174 | ftrans.flush |
| 175 | end |
| 176 | |
| 177 | it "should not flush the same buffered data twice" do |
| 178 | ftrans = FramedTransport.new(@trans) |
| 179 | frame = "foo/bar" |
| 180 | out = [frame.length].pack('N') |
| 181 | out << frame |
| 182 | @trans.should_receive(:write).with(out) |
| 183 | @trans.stub!(:flush) |
| 184 | ftrans.write("foo") |
| 185 | ftrans.write("/bar") |
| 186 | ftrans.flush |
| 187 | @trans.should_receive(:write).with("\000\000\000\000") |
| 188 | ftrans.flush |
| 189 | end |
| 190 | end |
| 191 | |
| 192 | describe FramedTransportFactory do |
| 193 | it "should wrap the given transport in a FramedTransport" do |
| 194 | trans = mock("Transport") |
| 195 | FramedTransport.should_receive(:new).with(trans) |
| 196 | FramedTransportFactory.new.get_transport(trans) |
| 197 | end |
| 198 | end |
| 199 | end |