blob: 98408abb8b6b4febe0fe464bc18a045aa9c75e98 [file] [log] [blame]
Kevin Clark531e0202008-06-18 01:10:17 +00001require File.dirname(__FILE__) + '/spec_helper'
2
3class 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 Clark6c30dbb2008-06-18 01:15:25 +000029
30 it "should alias << to write" do
31 Transport.instance_method(:<<).should == Transport.instance_method(:write)
32 end
Kevin Clark531e0202008-06-18 01:10:17 +000033 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
Kevin Clark4bd89162008-07-08 00:47:49 +000051 it "should pass through everything but write/flush/read" do
Kevin Clark531e0202008-06-18 01:10:17 +000052 trans = mock("Transport")
53 trans.should_receive(:open?).ordered.and_return("+ open?")
54 trans.should_receive(:open).ordered.and_return("+ open")
Kevin Clark091fa952008-06-26 18:10:56 +000055 trans.should_receive(:flush).ordered # from the close
Kevin Clark531e0202008-06-18 01:10:17 +000056 trans.should_receive(:close).ordered.and_return("+ close")
Kevin Clark531e0202008-06-18 01:10:17 +000057 btrans = BufferedTransport.new(trans)
58 btrans.open?.should == "+ open?"
59 btrans.open.should == "+ open"
60 btrans.close.should == "+ close"
Kevin Clark4bd89162008-07-08 00:47:49 +000061 end
62
63 it "should buffer reads in chunks of #{BufferedTransport::DEFAULT_BUFFER}" do
64 trans = mock("Transport")
65 trans.should_receive(:read).with(BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
66 btrans = BufferedTransport.new(trans)
67 btrans.read(6).should == "lorum "
68 btrans.read(6).should == "ipsum "
69 btrans.read(6).should == "dolor "
70 btrans.read(6).should == "emet"
Kevin Clark531e0202008-06-18 01:10:17 +000071 end
72
73 it "should buffer writes and send them on flush" do
74 trans = mock("Transport")
75 btrans = BufferedTransport.new(trans)
76 btrans.write("one/")
77 btrans.write("two/")
78 btrans.write("three/")
79 trans.should_receive(:write).with("one/two/three/").ordered
80 trans.should_receive(:flush).ordered
81 btrans.flush
82 end
83
84 it "should only send buffered data once" do
85 trans = mock("Transport")
86 btrans = BufferedTransport.new(trans)
87 btrans.write("one/")
88 btrans.write("two/")
89 btrans.write("three/")
90 trans.should_receive(:write).with("one/two/three/")
91 trans.stub!(:flush)
92 btrans.flush
Kevin Clark091fa952008-06-26 18:10:56 +000093 # Nothing to flush with no data
94 btrans.flush
95 end
96
97 it "should flush on close" do
98 trans = mock("Transport")
99 trans.should_receive(:close)
100 btrans = BufferedTransport.new(trans)
101 btrans.should_receive(:flush)
102 btrans.close
103 end
104
105 it "should not write to socket if there's no data" do
106 trans = mock("Transport")
107 trans.should_receive(:flush)
108 btrans = BufferedTransport.new(trans)
Kevin Clark531e0202008-06-18 01:10:17 +0000109 btrans.flush
110 end
111 end
112
113 describe BufferedTransportFactory do
114 it "should wrap the given transport in a BufferedTransport" do
115 trans = mock("Transport")
116 btrans = mock("BufferedTransport")
117 BufferedTransport.should_receive(:new).with(trans).and_return(btrans)
118 BufferedTransportFactory.new.get_transport(trans).should == btrans
119 end
120 end
121
122 describe FramedTransport do
123 before(:each) do
124 @trans = mock("Transport")
125 end
126
127 it "should pass through open?/open/close" do
128 ftrans = FramedTransport.new(@trans)
129 @trans.should_receive(:open?).ordered.and_return("+ open?")
130 @trans.should_receive(:open).ordered.and_return("+ open")
131 @trans.should_receive(:close).ordered.and_return("+ close")
132 ftrans.open?.should == "+ open?"
133 ftrans.open.should == "+ open"
134 ftrans.close.should == "+ close"
135 end
136
137 it "should pass through read when read is turned off" do
138 ftrans = FramedTransport.new(@trans, false, true)
139 @trans.should_receive(:read).with(17).ordered.and_return("+ read")
140 ftrans.read(17).should == "+ read"
141 end
142
143 it "should pass through write/flush when write is turned off" do
144 ftrans = FramedTransport.new(@trans, true, false)
145 @trans.should_receive(:write).with("foo").ordered.and_return("+ write")
146 @trans.should_receive(:flush).ordered.and_return("+ flush")
147 ftrans.write("foo").should == "+ write"
148 ftrans.flush.should == "+ flush"
149 end
150
151 it "should return a full frame if asked for >= the frame's length" do
152 frame = "this is a frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000153 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000154 @trans.should_receive(:read_all).with(frame.length).and_return(frame)
155 FramedTransport.new(@trans).read(frame.length + 10).should == frame
156 end
157
158 it "should return slices of the frame when asked for < the frame's length" do
159 frame = "this is a frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000160 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000161 @trans.should_receive(:read_all).with(frame.length).and_return(frame)
162 ftrans = FramedTransport.new(@trans)
163 ftrans.read(4).should == "this"
164 ftrans.read(4).should == " is "
165 ftrans.read(16).should == "a frame"
166 end
167
Kevin Clarkfa4a9582008-06-18 01:13:18 +0000168 it "should return nothing if asked for <= 0" do
169 FramedTransport.new(@trans).read(-2).should == ""
170 end
171
Kevin Clark531e0202008-06-18 01:10:17 +0000172 it "should pull a new frame when the first is exhausted" do
173 frame = "this is a frame"
174 frame2 = "yet another frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000175 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
Kevin Clark531e0202008-06-18 01:10:17 +0000176 @trans.should_receive(:read_all).with(frame.length).and_return(frame)
177 @trans.should_receive(:read_all).with(frame2.length).and_return(frame2)
178 ftrans = FramedTransport.new(@trans)
179 ftrans.read(4).should == "this"
180 ftrans.read(8).should == " is a fr"
181 ftrans.read(6).should == "ame"
182 ftrans.read(4).should == "yet "
183 ftrans.read(16).should == "another frame"
184 end
185
186 it "should buffer writes" do
187 ftrans = FramedTransport.new(@trans)
188 @trans.should_not_receive(:write)
189 ftrans.write("foo")
190 ftrans.write("bar")
191 ftrans.write("this is a frame")
192 end
193
Kevin Clarkfa4a9582008-06-18 01:13:18 +0000194 it "should write slices of the buffer" do
195 ftrans = FramedTransport.new(@trans)
196 ftrans.write("foobar", 3)
197 ftrans.write("barfoo", 1)
198 @trans.stub!(:flush)
199 @trans.should_receive(:write).with("\000\000\000\004foob")
200 ftrans.flush
201 end
202
Kevin Clark531e0202008-06-18 01:10:17 +0000203 it "should flush frames with a 4-byte header" do
204 ftrans = FramedTransport.new(@trans)
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000205 @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
Kevin Clark531e0202008-06-18 01:10:17 +0000206 @trans.should_receive(:flush).ordered
207 ftrans.write("one/")
208 ftrans.write("two/")
209 ftrans.write("three/")
210 ftrans.write("this is a frame")
211 ftrans.flush
212 end
213
214 it "should not flush the same buffered data twice" do
215 ftrans = FramedTransport.new(@trans)
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000216 @trans.should_receive(:write).with("\000\000\000\007foo/bar")
Kevin Clark531e0202008-06-18 01:10:17 +0000217 @trans.stub!(:flush)
218 ftrans.write("foo")
219 ftrans.write("/bar")
220 ftrans.flush
221 @trans.should_receive(:write).with("\000\000\000\000")
222 ftrans.flush
223 end
224 end
225
226 describe FramedTransportFactory do
227 it "should wrap the given transport in a FramedTransport" do
228 trans = mock("Transport")
229 FramedTransport.should_receive(:new).with(trans)
230 FramedTransportFactory.new.get_transport(trans)
231 end
232 end
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000233
234 describe MemoryBuffer do
235 before(:each) do
236 @buffer = MemoryBuffer.new
237 end
238
Kevin Clark6c30dbb2008-06-18 01:15:25 +0000239 it "should accept a buffer on input and use it directly" do
240 s = "this is a test"
241 @buffer = MemoryBuffer.new(s)
242 @buffer.read(4).should == "this"
Kevin Clarkbf2ff242008-07-08 23:20:15 +0000243 s.slice!(-4..-1)
244 @buffer.read(@buffer.available).should == " is a "
Kevin Clark6c30dbb2008-06-18 01:15:25 +0000245 end
246
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000247 it "should always remain open" do
248 @buffer.should be_open
249 @buffer.close
250 @buffer.should be_open
251 end
252
253 it "should respond to peek and available" do
254 @buffer.write "some data"
255 @buffer.peek.should be_true
256 @buffer.available.should == 9
257 @buffer.read(4)
258 @buffer.peek.should be_true
259 @buffer.available.should == 5
260 @buffer.read(16)
261 @buffer.peek.should be_false
262 @buffer.available.should == 0
263 end
264
265 it "should be able to reset the buffer" do
266 @buffer.write "test data"
267 @buffer.reset_buffer("foobar")
268 @buffer.available.should == 6
269 @buffer.read(10).should == "foobar"
270 @buffer.reset_buffer
271 @buffer.available.should == 0
272 end
273
Kevin Clark6c30dbb2008-06-18 01:15:25 +0000274 it "should copy the given string whne resetting the buffer" do
275 s = "this is a test"
276 @buffer.reset_buffer(s)
277 @buffer.available.should == 14
278 @buffer.read(10)
279 @buffer.available.should == 4
280 s.should == "this is a test"
281 end
282
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000283 it "should return from read what was given in write" do
284 @buffer.write "test data"
285 @buffer.read(4).should == "test"
286 @buffer.read(10).should == " data"
287 @buffer.read(10).should == ""
288 @buffer.write "foo"
289 @buffer.write " bar"
290 @buffer.read(10).should == "foo bar"
291 end
292 end
293
294 describe IOStreamTransport do
295 before(:each) do
Kevin Clarkf4e70082008-07-18 22:27:03 +0000296 @input = mock("Input", :closed? => false)
297 @output = mock("Output", :closed? => false)
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000298 @trans = IOStreamTransport.new(@input, @output)
299 end
300
Kevin Clarkf4e70082008-07-18 22:27:03 +0000301 it "should be open as long as both input or output are open" do
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000302 @trans.should be_open
Kevin Clarkf4e70082008-07-18 22:27:03 +0000303 @input.stub!(:closed?).and_return(true)
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000304 @trans.should be_open
Kevin Clarkf4e70082008-07-18 22:27:03 +0000305 @input.stub!(:closed?).and_return(false)
306 @output.stub!(:closed?).and_return(true)
307 @trans.should be_open
308 @input.stub!(:closed?).and_return(true)
309 @trans.should_not be_open
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000310 end
311
312 it "should pass through read/write to input/output" do
313 @input.should_receive(:read).with(17).and_return("+ read")
314 @output.should_receive(:write).with("foobar").and_return("+ write")
315 @trans.read(17).should == "+ read"
316 @trans.write("foobar").should == "+ write"
317 end
Kevin Clarkf4e70082008-07-18 22:27:03 +0000318
319 it "should close both input and output when closed" do
320 @input.should_receive(:close)
321 @output.should_receive(:close)
322 @trans.close
323 end
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000324 end
Kevin Clark531e0202008-06-18 01:10:17 +0000325end