]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | # |
2 | # Licensed to the Apache Software Foundation (ASF) under one | |
3 | # or more contributor license agreements. See the NOTICE file | |
4 | # distributed with this work for additional information | |
5 | # regarding copyright ownership. The ASF licenses this file | |
6 | # to you under the Apache License, Version 2.0 (the | |
7 | # "License"); you may not use this file except in compliance | |
8 | # with the License. You may obtain a copy of the License at | |
9 | # | |
10 | # http://www.apache.org/licenses/LICENSE-2.0 | |
11 | # | |
12 | # Unless required by applicable law or agreed to in writing, | |
13 | # software distributed under the License is distributed on an | |
14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | # KIND, either express or implied. See the License for the | |
16 | # specific language governing permissions and limitations | |
17 | # under the License. | |
18 | # | |
19 | ||
20 | require 'spec_helper' | |
21 | ||
22 | describe 'BaseTransport' do | |
23 | ||
24 | describe Thrift::TransportException do | |
25 | it "should make type accessible" do | |
26 | exc = Thrift::TransportException.new(Thrift::TransportException::ALREADY_OPEN, "msg") | |
27 | expect(exc.type).to eq(Thrift::TransportException::ALREADY_OPEN) | |
28 | expect(exc.message).to eq("msg") | |
29 | end | |
30 | end | |
31 | ||
32 | describe Thrift::BaseTransport do | |
33 | it "should read the specified size" do | |
34 | transport = Thrift::BaseTransport.new | |
35 | expect(transport).to receive(:read).with(40).ordered.and_return("10 letters") | |
36 | expect(transport).to receive(:read).with(30).ordered.and_return("fifteen letters") | |
37 | expect(transport).to receive(:read).with(15).ordered.and_return("more characters") | |
38 | expect(transport.read_all(40)).to eq("10 lettersfifteen lettersmore characters") | |
39 | end | |
40 | ||
41 | it "should stub out the rest of the methods" do | |
42 | # can't test for stubbiness, so just make sure they're defined | |
43 | [:open?, :open, :close, :read, :write, :flush].each do |sym| | |
44 | expect(Thrift::BaseTransport.method_defined?(sym)).to be_truthy | |
45 | end | |
46 | end | |
47 | ||
48 | it "should alias << to write" do | |
49 | expect(Thrift::BaseTransport.instance_method(:<<)).to eq(Thrift::BaseTransport.instance_method(:write)) | |
50 | end | |
51 | ||
52 | it "should provide a reasonable to_s" do | |
53 | expect(Thrift::BaseTransport.new.to_s).to eq("base") | |
54 | end | |
55 | end | |
56 | ||
57 | describe Thrift::BaseServerTransport do | |
58 | it "should stub out its methods" do | |
59 | [:listen, :accept, :close].each do |sym| | |
60 | expect(Thrift::BaseServerTransport.method_defined?(sym)).to be_truthy | |
61 | end | |
62 | end | |
63 | end | |
64 | ||
65 | describe Thrift::BaseTransportFactory do | |
66 | it "should return the transport it's given" do | |
67 | transport = double("Transport") | |
68 | expect(Thrift::BaseTransportFactory.new.get_transport(transport)).to eql(transport) | |
69 | end | |
70 | ||
71 | it "should provide a reasonable to_s" do | |
72 | expect(Thrift::BaseTransportFactory.new.to_s).to eq("base") | |
73 | end | |
74 | end | |
75 | ||
76 | describe Thrift::BufferedTransport do | |
77 | it "should provide a to_s that describes the encapsulation" do | |
78 | trans = double("Transport") | |
79 | expect(trans).to receive(:to_s).and_return("mock") | |
80 | expect(Thrift::BufferedTransport.new(trans).to_s).to eq("buffered(mock)") | |
81 | end | |
82 | ||
83 | it "should pass through everything but write/flush/read" do | |
84 | trans = double("Transport") | |
85 | expect(trans).to receive(:open?).ordered.and_return("+ open?") | |
86 | expect(trans).to receive(:open).ordered.and_return("+ open") | |
87 | expect(trans).to receive(:flush).ordered # from the close | |
88 | expect(trans).to receive(:close).ordered.and_return("+ close") | |
89 | btrans = Thrift::BufferedTransport.new(trans) | |
90 | expect(btrans.open?).to eq("+ open?") | |
91 | expect(btrans.open).to eq("+ open") | |
92 | expect(btrans.close).to eq("+ close") | |
93 | end | |
94 | ||
95 | it "should buffer reads in chunks of #{Thrift::BufferedTransport::DEFAULT_BUFFER}" do | |
96 | trans = double("Transport") | |
97 | expect(trans).to receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet") | |
98 | btrans = Thrift::BufferedTransport.new(trans) | |
99 | expect(btrans.read(6)).to eq("lorum ") | |
100 | expect(btrans.read(6)).to eq("ipsum ") | |
101 | expect(btrans.read(6)).to eq("dolor ") | |
102 | expect(btrans.read(6)).to eq("emet") | |
103 | end | |
104 | ||
105 | it "should buffer writes and send them on flush" do | |
106 | trans = double("Transport") | |
107 | btrans = Thrift::BufferedTransport.new(trans) | |
108 | btrans.write("one/") | |
109 | btrans.write("two/") | |
110 | btrans.write("three/") | |
111 | expect(trans).to receive(:write).with("one/two/three/").ordered | |
112 | expect(trans).to receive(:flush).ordered | |
113 | btrans.flush | |
114 | end | |
115 | ||
116 | it "should only send buffered data once" do | |
117 | trans = double("Transport") | |
118 | btrans = Thrift::BufferedTransport.new(trans) | |
119 | btrans.write("one/") | |
120 | btrans.write("two/") | |
121 | btrans.write("three/") | |
122 | expect(trans).to receive(:write).with("one/two/three/") | |
123 | allow(trans).to receive(:flush) | |
124 | btrans.flush | |
125 | # Nothing to flush with no data | |
126 | btrans.flush | |
127 | end | |
128 | ||
129 | it "should flush on close" do | |
130 | trans = double("Transport") | |
131 | expect(trans).to receive(:close) | |
132 | btrans = Thrift::BufferedTransport.new(trans) | |
133 | expect(btrans).to receive(:flush) | |
134 | btrans.close | |
135 | end | |
136 | ||
137 | it "should not write to socket if there's no data" do | |
138 | trans = double("Transport") | |
139 | expect(trans).to receive(:flush) | |
140 | btrans = Thrift::BufferedTransport.new(trans) | |
141 | btrans.flush | |
142 | end | |
143 | end | |
144 | ||
145 | describe Thrift::BufferedTransportFactory do | |
146 | it "should wrap the given transport in a BufferedTransport" do | |
147 | trans = double("Transport") | |
148 | btrans = double("BufferedTransport") | |
149 | expect(Thrift::BufferedTransport).to receive(:new).with(trans).and_return(btrans) | |
150 | expect(Thrift::BufferedTransportFactory.new.get_transport(trans)).to eq(btrans) | |
151 | end | |
152 | ||
153 | it "should provide a reasonable to_s" do | |
154 | expect(Thrift::BufferedTransportFactory.new.to_s).to eq("buffered") | |
155 | end | |
156 | end | |
157 | ||
158 | describe Thrift::FramedTransport do | |
159 | before(:each) do | |
160 | @trans = double("Transport") | |
161 | end | |
162 | ||
163 | it "should provide a to_s that describes the encapsulation" do | |
164 | trans = double("Transport") | |
165 | expect(trans).to receive(:to_s).and_return("mock") | |
166 | expect(Thrift::FramedTransport.new(trans).to_s).to eq("framed(mock)") | |
167 | end | |
168 | ||
169 | it "should pass through open?/open/close" do | |
170 | ftrans = Thrift::FramedTransport.new(@trans) | |
171 | expect(@trans).to receive(:open?).ordered.and_return("+ open?") | |
172 | expect(@trans).to receive(:open).ordered.and_return("+ open") | |
173 | expect(@trans).to receive(:close).ordered.and_return("+ close") | |
174 | expect(ftrans.open?).to eq("+ open?") | |
175 | expect(ftrans.open).to eq("+ open") | |
176 | expect(ftrans.close).to eq("+ close") | |
177 | end | |
178 | ||
179 | it "should pass through read when read is turned off" do | |
180 | ftrans = Thrift::FramedTransport.new(@trans, false, true) | |
181 | expect(@trans).to receive(:read).with(17).ordered.and_return("+ read") | |
182 | expect(ftrans.read(17)).to eq("+ read") | |
183 | end | |
184 | ||
185 | it "should pass through write/flush when write is turned off" do | |
186 | ftrans = Thrift::FramedTransport.new(@trans, true, false) | |
187 | expect(@trans).to receive(:write).with("foo").ordered.and_return("+ write") | |
188 | expect(@trans).to receive(:flush).ordered.and_return("+ flush") | |
189 | expect(ftrans.write("foo")).to eq("+ write") | |
190 | expect(ftrans.flush).to eq("+ flush") | |
191 | end | |
192 | ||
193 | it "should return a full frame if asked for >= the frame's length" do | |
194 | frame = "this is a frame" | |
195 | expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017") | |
196 | expect(@trans).to receive(:read_all).with(frame.length).and_return(frame) | |
197 | expect(Thrift::FramedTransport.new(@trans).read(frame.length + 10)).to eq(frame) | |
198 | end | |
199 | ||
200 | it "should return slices of the frame when asked for < the frame's length" do | |
201 | frame = "this is a frame" | |
202 | expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017") | |
203 | expect(@trans).to receive(:read_all).with(frame.length).and_return(frame) | |
204 | ftrans = Thrift::FramedTransport.new(@trans) | |
205 | expect(ftrans.read(4)).to eq("this") | |
206 | expect(ftrans.read(4)).to eq(" is ") | |
207 | expect(ftrans.read(16)).to eq("a frame") | |
208 | end | |
209 | ||
210 | it "should return nothing if asked for <= 0" do | |
211 | expect(Thrift::FramedTransport.new(@trans).read(-2)).to eq("") | |
212 | end | |
213 | ||
214 | it "should pull a new frame when the first is exhausted" do | |
215 | frame = "this is a frame" | |
216 | frame2 = "yet another frame" | |
217 | expect(@trans).to receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021") | |
218 | expect(@trans).to receive(:read_all).with(frame.length).and_return(frame) | |
219 | expect(@trans).to receive(:read_all).with(frame2.length).and_return(frame2) | |
220 | ftrans = Thrift::FramedTransport.new(@trans) | |
221 | expect(ftrans.read(4)).to eq("this") | |
222 | expect(ftrans.read(8)).to eq(" is a fr") | |
223 | expect(ftrans.read(6)).to eq("ame") | |
224 | expect(ftrans.read(4)).to eq("yet ") | |
225 | expect(ftrans.read(16)).to eq("another frame") | |
226 | end | |
227 | ||
228 | it "should buffer writes" do | |
229 | ftrans = Thrift::FramedTransport.new(@trans) | |
230 | expect(@trans).not_to receive(:write) | |
231 | ftrans.write("foo") | |
232 | ftrans.write("bar") | |
233 | ftrans.write("this is a frame") | |
234 | end | |
235 | ||
236 | it "should write slices of the buffer" do | |
237 | ftrans = Thrift::FramedTransport.new(@trans) | |
238 | ftrans.write("foobar", 3) | |
239 | ftrans.write("barfoo", 1) | |
240 | allow(@trans).to receive(:flush) | |
241 | expect(@trans).to receive(:write).with("\000\000\000\004foob") | |
242 | ftrans.flush | |
243 | end | |
244 | ||
245 | it "should flush frames with a 4-byte header" do | |
246 | ftrans = Thrift::FramedTransport.new(@trans) | |
247 | expect(@trans).to receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered | |
248 | expect(@trans).to receive(:flush).ordered | |
249 | ftrans.write("one/") | |
250 | ftrans.write("two/") | |
251 | ftrans.write("three/") | |
252 | ftrans.write("this is a frame") | |
253 | ftrans.flush | |
254 | end | |
255 | ||
256 | it "should not flush the same buffered data twice" do | |
257 | ftrans = Thrift::FramedTransport.new(@trans) | |
258 | expect(@trans).to receive(:write).with("\000\000\000\007foo/bar") | |
259 | allow(@trans).to receive(:flush) | |
260 | ftrans.write("foo") | |
261 | ftrans.write("/bar") | |
262 | ftrans.flush | |
263 | expect(@trans).to receive(:write).with("\000\000\000\000") | |
264 | ftrans.flush | |
265 | end | |
266 | end | |
267 | ||
268 | describe Thrift::FramedTransportFactory do | |
269 | it "should wrap the given transport in a FramedTransport" do | |
270 | trans = double("Transport") | |
271 | expect(Thrift::FramedTransport).to receive(:new).with(trans) | |
272 | Thrift::FramedTransportFactory.new.get_transport(trans) | |
273 | end | |
274 | ||
275 | it "should provide a reasonable to_s" do | |
276 | expect(Thrift::FramedTransportFactory.new.to_s).to eq("framed") | |
277 | end | |
278 | end | |
279 | ||
280 | describe Thrift::MemoryBufferTransport do | |
281 | before(:each) do | |
282 | @buffer = Thrift::MemoryBufferTransport.new | |
283 | end | |
284 | ||
285 | it "should provide a reasonable to_s" do | |
286 | expect(@buffer.to_s).to eq("memory") | |
287 | end | |
288 | ||
289 | it "should accept a buffer on input and use it directly" do | |
290 | s = "this is a test" | |
291 | @buffer = Thrift::MemoryBufferTransport.new(s) | |
292 | expect(@buffer.read(4)).to eq("this") | |
293 | s.slice!(-4..-1) | |
294 | expect(@buffer.read(@buffer.available)).to eq(" is a ") | |
295 | end | |
296 | ||
297 | it "should always remain open" do | |
298 | expect(@buffer).to be_open | |
299 | @buffer.close | |
300 | expect(@buffer).to be_open | |
301 | end | |
302 | ||
303 | it "should respond to peek and available" do | |
304 | @buffer.write "some data" | |
305 | expect(@buffer.peek).to be_truthy | |
306 | expect(@buffer.available).to eq(9) | |
307 | @buffer.read(4) | |
308 | expect(@buffer.peek).to be_truthy | |
309 | expect(@buffer.available).to eq(5) | |
310 | @buffer.read(5) | |
311 | expect(@buffer.peek).to be_falsey | |
312 | expect(@buffer.available).to eq(0) | |
313 | end | |
314 | ||
315 | it "should be able to reset the buffer" do | |
316 | @buffer.write "test data" | |
317 | @buffer.reset_buffer("foobar") | |
318 | expect(@buffer.available).to eq(6) | |
319 | expect(@buffer.read(@buffer.available)).to eq("foobar") | |
320 | @buffer.reset_buffer | |
321 | expect(@buffer.available).to eq(0) | |
322 | end | |
323 | ||
324 | it "should copy the given string when resetting the buffer" do | |
325 | s = "this is a test" | |
326 | @buffer.reset_buffer(s) | |
327 | expect(@buffer.available).to eq(14) | |
328 | @buffer.read(10) | |
329 | expect(@buffer.available).to eq(4) | |
330 | expect(s).to eq("this is a test") | |
331 | end | |
332 | ||
333 | it "should return from read what was given in write" do | |
334 | @buffer.write "test data" | |
335 | expect(@buffer.read(4)).to eq("test") | |
336 | expect(@buffer.read(@buffer.available)).to eq(" data") | |
337 | @buffer.write "foo" | |
338 | @buffer.write " bar" | |
339 | expect(@buffer.read(@buffer.available)).to eq("foo bar") | |
340 | end | |
341 | ||
342 | it "should throw an EOFError when there isn't enough data in the buffer" do | |
343 | @buffer.reset_buffer("") | |
344 | expect{@buffer.read(1)}.to raise_error(EOFError) | |
345 | ||
346 | @buffer.reset_buffer("1234") | |
347 | expect{@buffer.read(5)}.to raise_error(EOFError) | |
348 | end | |
349 | end | |
350 | ||
351 | describe Thrift::IOStreamTransport do | |
352 | before(:each) do | |
353 | @input = double("Input", :closed? => false) | |
354 | @output = double("Output", :closed? => false) | |
355 | @trans = Thrift::IOStreamTransport.new(@input, @output) | |
356 | end | |
357 | ||
358 | it "should provide a reasonable to_s" do | |
359 | expect(@input).to receive(:to_s).and_return("mock_input") | |
360 | expect(@output).to receive(:to_s).and_return("mock_output") | |
361 | expect(@trans.to_s).to eq("iostream(input=mock_input,output=mock_output)") | |
362 | end | |
363 | ||
364 | it "should be open as long as both input or output are open" do | |
365 | expect(@trans).to be_open | |
366 | allow(@input).to receive(:closed?).and_return(true) | |
367 | expect(@trans).to be_open | |
368 | allow(@input).to receive(:closed?).and_return(false) | |
369 | allow(@output).to receive(:closed?).and_return(true) | |
370 | expect(@trans).to be_open | |
371 | allow(@input).to receive(:closed?).and_return(true) | |
372 | expect(@trans).not_to be_open | |
373 | end | |
374 | ||
375 | it "should pass through read/write to input/output" do | |
376 | expect(@input).to receive(:read).with(17).and_return("+ read") | |
377 | expect(@output).to receive(:write).with("foobar").and_return("+ write") | |
378 | expect(@trans.read(17)).to eq("+ read") | |
379 | expect(@trans.write("foobar")).to eq("+ write") | |
380 | end | |
381 | ||
382 | it "should close both input and output when closed" do | |
383 | expect(@input).to receive(:close) | |
384 | expect(@output).to receive(:close) | |
385 | @trans.close | |
386 | end | |
387 | end | |
388 | end |