blob: 5d5c92f79af4b75547163e838e185a9887cee0e6 [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")
55 trans.should_receive(:close).ordered.and_return("+ close")
56 trans.should_receive(:read).with(217).ordered.and_return("+ read")
57 btrans = BufferedTransport.new(trans)
58 btrans.open?.should == "+ open?"
59 btrans.open.should == "+ open"
60 btrans.close.should == "+ close"
61 btrans.read(217).should == "+ read"
62 end
63
64 it "should buffer writes and send them on flush" do
65 trans = mock("Transport")
66 btrans = BufferedTransport.new(trans)
67 btrans.write("one/")
68 btrans.write("two/")
69 btrans.write("three/")
70 trans.should_receive(:write).with("one/two/three/").ordered
71 trans.should_receive(:flush).ordered
72 btrans.flush
73 end
74
75 it "should only send buffered data once" do
76 trans = mock("Transport")
77 btrans = BufferedTransport.new(trans)
78 btrans.write("one/")
79 btrans.write("two/")
80 btrans.write("three/")
81 trans.should_receive(:write).with("one/two/three/")
82 trans.stub!(:flush)
83 btrans.flush
84 trans.should_receive(:write).with("")
85 btrans.flush
86 end
87 end
88
89 describe BufferedTransportFactory do
90 it "should wrap the given transport in a BufferedTransport" do
91 trans = mock("Transport")
92 btrans = mock("BufferedTransport")
93 BufferedTransport.should_receive(:new).with(trans).and_return(btrans)
94 BufferedTransportFactory.new.get_transport(trans).should == btrans
95 end
96 end
97
98 describe FramedTransport do
99 before(:each) do
100 @trans = mock("Transport")
101 end
102
103 it "should pass through open?/open/close" do
104 ftrans = FramedTransport.new(@trans)
105 @trans.should_receive(:open?).ordered.and_return("+ open?")
106 @trans.should_receive(:open).ordered.and_return("+ open")
107 @trans.should_receive(:close).ordered.and_return("+ close")
108 ftrans.open?.should == "+ open?"
109 ftrans.open.should == "+ open"
110 ftrans.close.should == "+ close"
111 end
112
113 it "should pass through read when read is turned off" do
114 ftrans = FramedTransport.new(@trans, false, true)
115 @trans.should_receive(:read).with(17).ordered.and_return("+ read")
116 ftrans.read(17).should == "+ read"
117 end
118
119 it "should pass through write/flush when write is turned off" do
120 ftrans = FramedTransport.new(@trans, true, false)
121 @trans.should_receive(:write).with("foo").ordered.and_return("+ write")
122 @trans.should_receive(:flush).ordered.and_return("+ flush")
123 ftrans.write("foo").should == "+ write"
124 ftrans.flush.should == "+ flush"
125 end
126
127 it "should return a full frame if asked for >= the frame's length" do
128 frame = "this is a frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000129 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000130 @trans.should_receive(:read_all).with(frame.length).and_return(frame)
131 FramedTransport.new(@trans).read(frame.length + 10).should == frame
132 end
133
134 it "should return slices of the frame when asked for < the frame's length" do
135 frame = "this is a frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000136 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000137 @trans.should_receive(:read_all).with(frame.length).and_return(frame)
138 ftrans = FramedTransport.new(@trans)
139 ftrans.read(4).should == "this"
140 ftrans.read(4).should == " is "
141 ftrans.read(16).should == "a frame"
142 end
143
Kevin Clarkfa4a9582008-06-18 01:13:18 +0000144 it "should return nothing if asked for <= 0" do
145 FramedTransport.new(@trans).read(-2).should == ""
146 end
147
Kevin Clark531e0202008-06-18 01:10:17 +0000148 it "should pull a new frame when the first is exhausted" do
149 frame = "this is a frame"
150 frame2 = "yet another frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000151 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
Kevin Clark531e0202008-06-18 01:10:17 +0000152 @trans.should_receive(:read_all).with(frame.length).and_return(frame)
153 @trans.should_receive(:read_all).with(frame2.length).and_return(frame2)
154 ftrans = FramedTransport.new(@trans)
155 ftrans.read(4).should == "this"
156 ftrans.read(8).should == " is a fr"
157 ftrans.read(6).should == "ame"
158 ftrans.read(4).should == "yet "
159 ftrans.read(16).should == "another frame"
160 end
161
162 it "should buffer writes" do
163 ftrans = FramedTransport.new(@trans)
164 @trans.should_not_receive(:write)
165 ftrans.write("foo")
166 ftrans.write("bar")
167 ftrans.write("this is a frame")
168 end
169
Kevin Clarkfa4a9582008-06-18 01:13:18 +0000170 it "should write slices of the buffer" do
171 ftrans = FramedTransport.new(@trans)
172 ftrans.write("foobar", 3)
173 ftrans.write("barfoo", 1)
174 @trans.stub!(:flush)
175 @trans.should_receive(:write).with("\000\000\000\004foob")
176 ftrans.flush
177 end
178
Kevin Clark531e0202008-06-18 01:10:17 +0000179 it "should flush frames with a 4-byte header" do
180 ftrans = FramedTransport.new(@trans)
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000181 @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
Kevin Clark531e0202008-06-18 01:10:17 +0000182 @trans.should_receive(:flush).ordered
183 ftrans.write("one/")
184 ftrans.write("two/")
185 ftrans.write("three/")
186 ftrans.write("this is a frame")
187 ftrans.flush
188 end
189
190 it "should not flush the same buffered data twice" do
191 ftrans = FramedTransport.new(@trans)
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000192 @trans.should_receive(:write).with("\000\000\000\007foo/bar")
Kevin Clark531e0202008-06-18 01:10:17 +0000193 @trans.stub!(:flush)
194 ftrans.write("foo")
195 ftrans.write("/bar")
196 ftrans.flush
197 @trans.should_receive(:write).with("\000\000\000\000")
198 ftrans.flush
199 end
200 end
201
202 describe FramedTransportFactory do
203 it "should wrap the given transport in a FramedTransport" do
204 trans = mock("Transport")
205 FramedTransport.should_receive(:new).with(trans)
206 FramedTransportFactory.new.get_transport(trans)
207 end
208 end
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000209
210 describe MemoryBuffer do
211 before(:each) do
212 @buffer = MemoryBuffer.new
213 end
214
Kevin Clark6c30dbb2008-06-18 01:15:25 +0000215 it "should accept a buffer on input and use it directly" do
216 s = "this is a test"
217 @buffer = MemoryBuffer.new(s)
218 @buffer.read(4).should == "this"
219 s.should == " is a test"
220 end
221
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000222 it "should always remain open" do
223 @buffer.should be_open
224 @buffer.close
225 @buffer.should be_open
226 end
227
228 it "should respond to peek and available" do
229 @buffer.write "some data"
230 @buffer.peek.should be_true
231 @buffer.available.should == 9
232 @buffer.read(4)
233 @buffer.peek.should be_true
234 @buffer.available.should == 5
235 @buffer.read(16)
236 @buffer.peek.should be_false
237 @buffer.available.should == 0
238 end
239
240 it "should be able to reset the buffer" do
241 @buffer.write "test data"
242 @buffer.reset_buffer("foobar")
243 @buffer.available.should == 6
244 @buffer.read(10).should == "foobar"
245 @buffer.reset_buffer
246 @buffer.available.should == 0
247 end
248
Kevin Clark6c30dbb2008-06-18 01:15:25 +0000249 it "should copy the given string whne resetting the buffer" do
250 s = "this is a test"
251 @buffer.reset_buffer(s)
252 @buffer.available.should == 14
253 @buffer.read(10)
254 @buffer.available.should == 4
255 s.should == "this is a test"
256 end
257
Kevin Clarkf6aa86a2008-06-18 01:11:07 +0000258 it "should return from read what was given in write" do
259 @buffer.write "test data"
260 @buffer.read(4).should == "test"
261 @buffer.read(10).should == " data"
262 @buffer.read(10).should == ""
263 @buffer.write "foo"
264 @buffer.write " bar"
265 @buffer.read(10).should == "foo bar"
266 end
267 end
268
269 describe IOStreamTransport do
270 before(:each) do
271 @input = mock("Input")
272 @output = mock("Output")
273 @trans = IOStreamTransport.new(@input, @output)
274 end
275
276 it "should always be open" do
277 @trans.should be_open
278 @trans.close
279 @trans.should be_open
280 end
281
282 it "should pass through read/write to input/output" do
283 @input.should_receive(:read).with(17).and_return("+ read")
284 @output.should_receive(:write).with("foobar").and_return("+ write")
285 @trans.read(17).should == "+ read"
286 @trans.write("foobar").should == "+ write"
287 end
288 end
Kevin Clark531e0202008-06-18 01:10:17 +0000289end