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 |
Kevin Clark | 6c30dbb | 2008-06-18 01:15:25 +0000 | [diff] [blame] | 29 | |
| 30 | it "should alias << to write" do |
| 31 | Transport.instance_method(:<<).should == Transport.instance_method(:write) |
| 32 | end |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 33 | end |
| 34 | |
| 35 | describe ServerTransport do |
| 36 | it "should stub out its methods" do |
| 37 | [:listen, :accept, :close].each do |sym| |
| 38 | ServerTransport.method_defined?(sym).should be_true |
| 39 | end |
| 40 | end |
| 41 | end |
| 42 | |
| 43 | describe TransportFactory do |
| 44 | it "should return the transport it's given" do |
| 45 | transport = mock("Transport") |
| 46 | TransportFactory.new.get_transport(transport).should eql(transport) |
| 47 | end |
| 48 | end |
| 49 | |
| 50 | describe BufferedTransport do |
| 51 | it "should pass through everything but write/flush" do |
| 52 | trans = mock("Transport") |
| 53 | trans.should_receive(:open?).ordered.and_return("+ open?") |
| 54 | trans.should_receive(:open).ordered.and_return("+ open") |
Kevin Clark | 091fa95 | 2008-06-26 18:10:56 +0000 | [diff] [blame] | 55 | trans.should_receive(:flush).ordered # from the close |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 56 | trans.should_receive(:close).ordered.and_return("+ close") |
| 57 | trans.should_receive(:read).with(217).ordered.and_return("+ read") |
| 58 | btrans = BufferedTransport.new(trans) |
| 59 | btrans.open?.should == "+ open?" |
| 60 | btrans.open.should == "+ open" |
| 61 | btrans.close.should == "+ close" |
| 62 | btrans.read(217).should == "+ read" |
| 63 | end |
| 64 | |
| 65 | it "should buffer writes and send them on flush" do |
| 66 | trans = mock("Transport") |
| 67 | btrans = BufferedTransport.new(trans) |
| 68 | btrans.write("one/") |
| 69 | btrans.write("two/") |
| 70 | btrans.write("three/") |
| 71 | trans.should_receive(:write).with("one/two/three/").ordered |
| 72 | trans.should_receive(:flush).ordered |
| 73 | btrans.flush |
| 74 | end |
| 75 | |
| 76 | it "should only send buffered data once" do |
| 77 | trans = mock("Transport") |
| 78 | btrans = BufferedTransport.new(trans) |
| 79 | btrans.write("one/") |
| 80 | btrans.write("two/") |
| 81 | btrans.write("three/") |
| 82 | trans.should_receive(:write).with("one/two/three/") |
| 83 | trans.stub!(:flush) |
| 84 | btrans.flush |
Kevin Clark | 091fa95 | 2008-06-26 18:10:56 +0000 | [diff] [blame] | 85 | # Nothing to flush with no data |
| 86 | btrans.flush |
| 87 | end |
| 88 | |
| 89 | it "should flush on close" do |
| 90 | trans = mock("Transport") |
| 91 | trans.should_receive(:close) |
| 92 | btrans = BufferedTransport.new(trans) |
| 93 | btrans.should_receive(:flush) |
| 94 | btrans.close |
| 95 | end |
| 96 | |
| 97 | it "should not write to socket if there's no data" do |
| 98 | trans = mock("Transport") |
| 99 | trans.should_receive(:flush) |
| 100 | btrans = BufferedTransport.new(trans) |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 101 | btrans.flush |
| 102 | end |
| 103 | end |
| 104 | |
| 105 | describe BufferedTransportFactory do |
| 106 | it "should wrap the given transport in a BufferedTransport" do |
| 107 | trans = mock("Transport") |
| 108 | btrans = mock("BufferedTransport") |
| 109 | BufferedTransport.should_receive(:new).with(trans).and_return(btrans) |
| 110 | BufferedTransportFactory.new.get_transport(trans).should == btrans |
| 111 | end |
| 112 | end |
| 113 | |
| 114 | describe FramedTransport do |
| 115 | before(:each) do |
| 116 | @trans = mock("Transport") |
| 117 | end |
| 118 | |
| 119 | it "should pass through open?/open/close" do |
| 120 | ftrans = FramedTransport.new(@trans) |
| 121 | @trans.should_receive(:open?).ordered.and_return("+ open?") |
| 122 | @trans.should_receive(:open).ordered.and_return("+ open") |
| 123 | @trans.should_receive(:close).ordered.and_return("+ close") |
| 124 | ftrans.open?.should == "+ open?" |
| 125 | ftrans.open.should == "+ open" |
| 126 | ftrans.close.should == "+ close" |
| 127 | end |
| 128 | |
| 129 | it "should pass through read when read is turned off" do |
| 130 | ftrans = FramedTransport.new(@trans, false, true) |
| 131 | @trans.should_receive(:read).with(17).ordered.and_return("+ read") |
| 132 | ftrans.read(17).should == "+ read" |
| 133 | end |
| 134 | |
| 135 | it "should pass through write/flush when write is turned off" do |
| 136 | ftrans = FramedTransport.new(@trans, true, false) |
| 137 | @trans.should_receive(:write).with("foo").ordered.and_return("+ write") |
| 138 | @trans.should_receive(:flush).ordered.and_return("+ flush") |
| 139 | ftrans.write("foo").should == "+ write" |
| 140 | ftrans.flush.should == "+ flush" |
| 141 | end |
| 142 | |
| 143 | it "should return a full frame if asked for >= the frame's length" do |
| 144 | frame = "this is a frame" |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 145 | @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017") |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 146 | @trans.should_receive(:read_all).with(frame.length).and_return(frame) |
| 147 | FramedTransport.new(@trans).read(frame.length + 10).should == frame |
| 148 | end |
| 149 | |
| 150 | it "should return slices of the frame when asked for < the frame's length" do |
| 151 | frame = "this is a frame" |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 152 | @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017") |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 153 | @trans.should_receive(:read_all).with(frame.length).and_return(frame) |
| 154 | ftrans = FramedTransport.new(@trans) |
| 155 | ftrans.read(4).should == "this" |
| 156 | ftrans.read(4).should == " is " |
| 157 | ftrans.read(16).should == "a frame" |
| 158 | end |
| 159 | |
Kevin Clark | fa4a958 | 2008-06-18 01:13:18 +0000 | [diff] [blame] | 160 | it "should return nothing if asked for <= 0" do |
| 161 | FramedTransport.new(@trans).read(-2).should == "" |
| 162 | end |
| 163 | |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 164 | it "should pull a new frame when the first is exhausted" do |
| 165 | frame = "this is a frame" |
| 166 | frame2 = "yet another frame" |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 167 | @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021") |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 168 | @trans.should_receive(:read_all).with(frame.length).and_return(frame) |
| 169 | @trans.should_receive(:read_all).with(frame2.length).and_return(frame2) |
| 170 | ftrans = FramedTransport.new(@trans) |
| 171 | ftrans.read(4).should == "this" |
| 172 | ftrans.read(8).should == " is a fr" |
| 173 | ftrans.read(6).should == "ame" |
| 174 | ftrans.read(4).should == "yet " |
| 175 | ftrans.read(16).should == "another frame" |
| 176 | end |
| 177 | |
| 178 | it "should buffer writes" do |
| 179 | ftrans = FramedTransport.new(@trans) |
| 180 | @trans.should_not_receive(:write) |
| 181 | ftrans.write("foo") |
| 182 | ftrans.write("bar") |
| 183 | ftrans.write("this is a frame") |
| 184 | end |
| 185 | |
Kevin Clark | fa4a958 | 2008-06-18 01:13:18 +0000 | [diff] [blame] | 186 | it "should write slices of the buffer" do |
| 187 | ftrans = FramedTransport.new(@trans) |
| 188 | ftrans.write("foobar", 3) |
| 189 | ftrans.write("barfoo", 1) |
| 190 | @trans.stub!(:flush) |
| 191 | @trans.should_receive(:write).with("\000\000\000\004foob") |
| 192 | ftrans.flush |
| 193 | end |
| 194 | |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 195 | it "should flush frames with a 4-byte header" do |
| 196 | ftrans = FramedTransport.new(@trans) |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 197 | @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 198 | @trans.should_receive(:flush).ordered |
| 199 | ftrans.write("one/") |
| 200 | ftrans.write("two/") |
| 201 | ftrans.write("three/") |
| 202 | ftrans.write("this is a frame") |
| 203 | ftrans.flush |
| 204 | end |
| 205 | |
| 206 | it "should not flush the same buffered data twice" do |
| 207 | ftrans = FramedTransport.new(@trans) |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 208 | @trans.should_receive(:write).with("\000\000\000\007foo/bar") |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 209 | @trans.stub!(:flush) |
| 210 | ftrans.write("foo") |
| 211 | ftrans.write("/bar") |
| 212 | ftrans.flush |
| 213 | @trans.should_receive(:write).with("\000\000\000\000") |
| 214 | ftrans.flush |
| 215 | end |
| 216 | end |
| 217 | |
| 218 | describe FramedTransportFactory do |
| 219 | it "should wrap the given transport in a FramedTransport" do |
| 220 | trans = mock("Transport") |
| 221 | FramedTransport.should_receive(:new).with(trans) |
| 222 | FramedTransportFactory.new.get_transport(trans) |
| 223 | end |
| 224 | end |
Kevin Clark | f6aa86a | 2008-06-18 01:11:07 +0000 | [diff] [blame] | 225 | |
| 226 | describe MemoryBuffer do |
| 227 | before(:each) do |
| 228 | @buffer = MemoryBuffer.new |
| 229 | end |
| 230 | |
Kevin Clark | 6c30dbb | 2008-06-18 01:15:25 +0000 | [diff] [blame] | 231 | it "should accept a buffer on input and use it directly" do |
| 232 | s = "this is a test" |
| 233 | @buffer = MemoryBuffer.new(s) |
| 234 | @buffer.read(4).should == "this" |
| 235 | s.should == " is a test" |
| 236 | end |
| 237 | |
Kevin Clark | f6aa86a | 2008-06-18 01:11:07 +0000 | [diff] [blame] | 238 | it "should always remain open" do |
| 239 | @buffer.should be_open |
| 240 | @buffer.close |
| 241 | @buffer.should be_open |
| 242 | end |
| 243 | |
| 244 | it "should respond to peek and available" do |
| 245 | @buffer.write "some data" |
| 246 | @buffer.peek.should be_true |
| 247 | @buffer.available.should == 9 |
| 248 | @buffer.read(4) |
| 249 | @buffer.peek.should be_true |
| 250 | @buffer.available.should == 5 |
| 251 | @buffer.read(16) |
| 252 | @buffer.peek.should be_false |
| 253 | @buffer.available.should == 0 |
| 254 | end |
| 255 | |
| 256 | it "should be able to reset the buffer" do |
| 257 | @buffer.write "test data" |
| 258 | @buffer.reset_buffer("foobar") |
| 259 | @buffer.available.should == 6 |
| 260 | @buffer.read(10).should == "foobar" |
| 261 | @buffer.reset_buffer |
| 262 | @buffer.available.should == 0 |
| 263 | end |
| 264 | |
Kevin Clark | 6c30dbb | 2008-06-18 01:15:25 +0000 | [diff] [blame] | 265 | it "should copy the given string whne resetting the buffer" do |
| 266 | s = "this is a test" |
| 267 | @buffer.reset_buffer(s) |
| 268 | @buffer.available.should == 14 |
| 269 | @buffer.read(10) |
| 270 | @buffer.available.should == 4 |
| 271 | s.should == "this is a test" |
| 272 | end |
| 273 | |
Kevin Clark | f6aa86a | 2008-06-18 01:11:07 +0000 | [diff] [blame] | 274 | it "should return from read what was given in write" do |
| 275 | @buffer.write "test data" |
| 276 | @buffer.read(4).should == "test" |
| 277 | @buffer.read(10).should == " data" |
| 278 | @buffer.read(10).should == "" |
| 279 | @buffer.write "foo" |
| 280 | @buffer.write " bar" |
| 281 | @buffer.read(10).should == "foo bar" |
| 282 | end |
| 283 | end |
| 284 | |
| 285 | describe IOStreamTransport do |
| 286 | before(:each) do |
| 287 | @input = mock("Input") |
| 288 | @output = mock("Output") |
| 289 | @trans = IOStreamTransport.new(@input, @output) |
| 290 | end |
| 291 | |
| 292 | it "should always be open" do |
| 293 | @trans.should be_open |
| 294 | @trans.close |
| 295 | @trans.should be_open |
| 296 | end |
| 297 | |
| 298 | it "should pass through read/write to input/output" do |
| 299 | @input.should_receive(:read).with(17).and_return("+ read") |
| 300 | @output.should_receive(:write).with("foobar").and_return("+ write") |
| 301 | @trans.read(17).should == "+ read" |
| 302 | @trans.write("foobar").should == "+ write" |
| 303 | end |
| 304 | end |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 305 | end |