blob: 941df285a234b728a719cbff74cc4e5e3c11875c [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
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 Clarkdfe22b32008-06-18 01:13:09 +0000125 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000126 @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 Clarkdfe22b32008-06-18 01:13:09 +0000132 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
Kevin Clark531e0202008-06-18 01:10:17 +0000133 @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 Clarkfa4a9582008-06-18 01:13:18 +0000140 it "should return nothing if asked for <= 0" do
141 FramedTransport.new(@trans).read(-2).should == ""
142 end
143
Kevin Clark531e0202008-06-18 01:10:17 +0000144 it "should pull a new frame when the first is exhausted" do
145 frame = "this is a frame"
146 frame2 = "yet another frame"
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000147 @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
Kevin Clark531e0202008-06-18 01:10:17 +0000148 @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 Clarkfa4a9582008-06-18 01:13:18 +0000166 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 Clark531e0202008-06-18 01:10:17 +0000175 it "should flush frames with a 4-byte header" do
176 ftrans = FramedTransport.new(@trans)
Kevin Clarkdfe22b32008-06-18 01:13:09 +0000177 @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
Kevin Clark531e0202008-06-18 01:10:17 +0000178 @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 Clarkdfe22b32008-06-18 01:13:09 +0000188 @trans.should_receive(:write).with("\000\000\000\007foo/bar")
Kevin Clark531e0202008-06-18 01:10:17 +0000189 @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 Clarkf6aa86a2008-06-18 01:11:07 +0000205
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 Clark531e0202008-06-18 01:10:17 +0000269end