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" |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 125 | @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] | 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" |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 132 | @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] | 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 | |
Kevin Clark | fa4a958 | 2008-06-18 01:13:18 +0000 | [diff] [blame^] | 140 | it "should return nothing if asked for <= 0" do |
| 141 | FramedTransport.new(@trans).read(-2).should == "" |
| 142 | end |
| 143 | |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 144 | it "should pull a new frame when the first is exhausted" do |
| 145 | frame = "this is a frame" |
| 146 | frame2 = "yet another frame" |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 147 | @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] | 148 | @trans.should_receive(:read_all).with(frame.length).and_return(frame) |
| 149 | @trans.should_receive(:read_all).with(frame2.length).and_return(frame2) |
| 150 | ftrans = FramedTransport.new(@trans) |
| 151 | ftrans.read(4).should == "this" |
| 152 | ftrans.read(8).should == " is a fr" |
| 153 | ftrans.read(6).should == "ame" |
| 154 | ftrans.read(4).should == "yet " |
| 155 | ftrans.read(16).should == "another frame" |
| 156 | end |
| 157 | |
| 158 | it "should buffer writes" do |
| 159 | ftrans = FramedTransport.new(@trans) |
| 160 | @trans.should_not_receive(:write) |
| 161 | ftrans.write("foo") |
| 162 | ftrans.write("bar") |
| 163 | ftrans.write("this is a frame") |
| 164 | end |
| 165 | |
Kevin Clark | fa4a958 | 2008-06-18 01:13:18 +0000 | [diff] [blame^] | 166 | it "should write slices of the buffer" do |
| 167 | ftrans = FramedTransport.new(@trans) |
| 168 | ftrans.write("foobar", 3) |
| 169 | ftrans.write("barfoo", 1) |
| 170 | @trans.stub!(:flush) |
| 171 | @trans.should_receive(:write).with("\000\000\000\004foob") |
| 172 | ftrans.flush |
| 173 | end |
| 174 | |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 175 | it "should flush frames with a 4-byte header" do |
| 176 | ftrans = FramedTransport.new(@trans) |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 177 | @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] | 178 | @trans.should_receive(:flush).ordered |
| 179 | ftrans.write("one/") |
| 180 | ftrans.write("two/") |
| 181 | ftrans.write("three/") |
| 182 | ftrans.write("this is a frame") |
| 183 | ftrans.flush |
| 184 | end |
| 185 | |
| 186 | it "should not flush the same buffered data twice" do |
| 187 | ftrans = FramedTransport.new(@trans) |
Kevin Clark | dfe22b3 | 2008-06-18 01:13:09 +0000 | [diff] [blame] | 188 | @trans.should_receive(:write).with("\000\000\000\007foo/bar") |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 189 | @trans.stub!(:flush) |
| 190 | ftrans.write("foo") |
| 191 | ftrans.write("/bar") |
| 192 | ftrans.flush |
| 193 | @trans.should_receive(:write).with("\000\000\000\000") |
| 194 | ftrans.flush |
| 195 | end |
| 196 | end |
| 197 | |
| 198 | describe FramedTransportFactory do |
| 199 | it "should wrap the given transport in a FramedTransport" do |
| 200 | trans = mock("Transport") |
| 201 | FramedTransport.should_receive(:new).with(trans) |
| 202 | FramedTransportFactory.new.get_transport(trans) |
| 203 | end |
| 204 | end |
Kevin Clark | f6aa86a | 2008-06-18 01:11:07 +0000 | [diff] [blame] | 205 | |
| 206 | describe MemoryBuffer do |
| 207 | before(:each) do |
| 208 | @buffer = MemoryBuffer.new |
| 209 | end |
| 210 | |
| 211 | it "should always remain open" do |
| 212 | @buffer.should be_open |
| 213 | @buffer.close |
| 214 | @buffer.should be_open |
| 215 | end |
| 216 | |
| 217 | it "should respond to peek and available" do |
| 218 | @buffer.write "some data" |
| 219 | @buffer.peek.should be_true |
| 220 | @buffer.available.should == 9 |
| 221 | @buffer.read(4) |
| 222 | @buffer.peek.should be_true |
| 223 | @buffer.available.should == 5 |
| 224 | @buffer.read(16) |
| 225 | @buffer.peek.should be_false |
| 226 | @buffer.available.should == 0 |
| 227 | end |
| 228 | |
| 229 | it "should be able to reset the buffer" do |
| 230 | @buffer.write "test data" |
| 231 | @buffer.reset_buffer("foobar") |
| 232 | @buffer.available.should == 6 |
| 233 | @buffer.read(10).should == "foobar" |
| 234 | @buffer.reset_buffer |
| 235 | @buffer.available.should == 0 |
| 236 | end |
| 237 | |
| 238 | it "should return from read what was given in write" do |
| 239 | @buffer.write "test data" |
| 240 | @buffer.read(4).should == "test" |
| 241 | @buffer.read(10).should == " data" |
| 242 | @buffer.read(10).should == "" |
| 243 | @buffer.write "foo" |
| 244 | @buffer.write " bar" |
| 245 | @buffer.read(10).should == "foo bar" |
| 246 | end |
| 247 | end |
| 248 | |
| 249 | describe IOStreamTransport do |
| 250 | before(:each) do |
| 251 | @input = mock("Input") |
| 252 | @output = mock("Output") |
| 253 | @trans = IOStreamTransport.new(@input, @output) |
| 254 | end |
| 255 | |
| 256 | it "should always be open" do |
| 257 | @trans.should be_open |
| 258 | @trans.close |
| 259 | @trans.should be_open |
| 260 | end |
| 261 | |
| 262 | it "should pass through read/write to input/output" do |
| 263 | @input.should_receive(:read).with(17).and_return("+ read") |
| 264 | @output.should_receive(:write).with("foobar").and_return("+ write") |
| 265 | @trans.read(17).should == "+ read" |
| 266 | @trans.write("foobar").should == "+ write" |
| 267 | end |
| 268 | end |
Kevin Clark | 531e020 | 2008-06-18 01:10:17 +0000 | [diff] [blame] | 269 | end |