blob: 44d0508a3abcf93b71fee85a1066eb148e4dda50 [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
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 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")
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 Clark091fa952008-06-26 18:10:56 +000085 # 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 Clark531e0202008-06-18 01:10:17 +0000101 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 Clarkdfe22b32008-06-18 01:13:09 +0000145 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000146 @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 Clarkdfe22b32008-06-18 01:13:09 +0000152 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000153 @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 Clarkfa4a9582008-06-18 01:13:18 +0000160 it "should return nothing if asked for <= 0" do
161 FramedTransport.new(@trans).read(-2).should == ""
162 end
163
Kevin Clark531e0202008-06-18 01:10:17 +0000164 it "should pull a new frame when the first is exhausted" do
165 frame = "this is a frame"
166 frame2 = "yet another frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000167 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
Kevin Clark531e0202008-06-18 01:10:17 +0000168 @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 Clarkfa4a9582008-06-18 01:13:18 +0000186 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 Clark531e0202008-06-18 01:10:17 +0000195 it "should flush frames with a 4-byte header" do
196 ftrans = FramedTransport.new(@trans)
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000197 @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
Kevin Clark531e0202008-06-18 01:10:17 +0000198 @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 Clarkdfe22b32008-06-18 01:13:09 +0000208 @trans.should_receive(:write).with("\000\000\000\007foo/bar")
Kevin Clark531e0202008-06-18 01:10:17 +0000209 @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 Clarkf6aa86a2008-06-18 01:11:07 +0000225
226 describe MemoryBuffer do
227 before(:each) do
228 @buffer = MemoryBuffer.new
229 end
230
Kevin Clark6c30dbb2008-06-18 01:15:25 +0000231 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 Clarkf6aa86a2008-06-18 01:11:07 +0000238 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 Clark6c30dbb2008-06-18 01:15:25 +0000265 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 Clarkf6aa86a2008-06-18 01:11:07 +0000274 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 Clark531e0202008-06-18 01:10:17 +0000305end