Subversion Repositories SmartDukaan

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 ashish 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 File.dirname(__FILE__) + '/spec_helper'
21
 
22
class ThriftBaseTransportSpec < Spec::ExampleGroup
23
  include Thrift
24
 
25
  describe TransportException do
26
    it "should make type accessible" do
27
      exc = TransportException.new(TransportException::ALREADY_OPEN, "msg")
28
      exc.type.should == TransportException::ALREADY_OPEN
29
      exc.message.should == "msg"
30
    end
31
  end
32
 
33
  describe BaseTransport do
34
    it "should read the specified size" do
35
      transport = BaseTransport.new
36
      transport.should_receive(:read).with(40).ordered.and_return("10 letters")
37
      transport.should_receive(:read).with(30).ordered.and_return("fifteen letters")
38
      transport.should_receive(:read).with(15).ordered.and_return("more characters")
39
      transport.read_all(40).should == "10 lettersfifteen lettersmore characters"
40
    end
41
 
42
    it "should stub out the rest of the methods" do
43
      # can't test for stubbiness, so just make sure they're defined
44
      [:open?, :open, :close, :read, :write, :flush].each do |sym|
45
        BaseTransport.method_defined?(sym).should be_true
46
      end
47
    end
48
 
49
    it "should alias << to write" do
50
      BaseTransport.instance_method(:<<).should == BaseTransport.instance_method(:write)
51
    end
52
  end
53
 
54
  describe BaseServerTransport do
55
    it "should stub out its methods" do
56
      [:listen, :accept, :close].each do |sym|
57
        BaseServerTransport.method_defined?(sym).should be_true
58
      end
59
    end
60
  end
61
 
62
  describe BaseTransportFactory do
63
    it "should return the transport it's given" do
64
      transport = mock("Transport")
65
      BaseTransportFactory.new.get_transport(transport).should eql(transport)
66
    end
67
  end
68
 
69
  describe BufferedTransport do
70
    it "should pass through everything but write/flush/read" do
71
      trans = mock("Transport")
72
      trans.should_receive(:open?).ordered.and_return("+ open?")
73
      trans.should_receive(:open).ordered.and_return("+ open")
74
      trans.should_receive(:flush).ordered # from the close
75
      trans.should_receive(:close).ordered.and_return("+ close")
76
      btrans = BufferedTransport.new(trans)
77
      btrans.open?.should == "+ open?"
78
      btrans.open.should == "+ open"
79
      btrans.close.should == "+ close"
80
    end
81
 
82
    it "should buffer reads in chunks of #{BufferedTransport::DEFAULT_BUFFER}" do
83
      trans = mock("Transport")
84
      trans.should_receive(:read).with(BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
85
      btrans = BufferedTransport.new(trans)
86
      btrans.read(6).should == "lorum "
87
      btrans.read(6).should == "ipsum "
88
      btrans.read(6).should == "dolor "
89
      btrans.read(6).should == "emet"
90
    end
91
 
92
    it "should buffer writes and send them on flush" do
93
      trans = mock("Transport")
94
      btrans = BufferedTransport.new(trans)
95
      btrans.write("one/")
96
      btrans.write("two/")
97
      btrans.write("three/")
98
      trans.should_receive(:write).with("one/two/three/").ordered
99
      trans.should_receive(:flush).ordered
100
      btrans.flush
101
    end
102
 
103
    it "should only send buffered data once" do
104
      trans = mock("Transport")
105
      btrans = BufferedTransport.new(trans)
106
      btrans.write("one/")
107
      btrans.write("two/")
108
      btrans.write("three/")
109
      trans.should_receive(:write).with("one/two/three/")
110
      trans.stub!(:flush)
111
      btrans.flush
112
      # Nothing to flush with no data
113
      btrans.flush
114
    end
115
 
116
    it "should flush on close" do
117
      trans = mock("Transport")
118
      trans.should_receive(:close)
119
      btrans = BufferedTransport.new(trans)
120
      btrans.should_receive(:flush)
121
      btrans.close
122
    end
123
 
124
    it "should not write to socket if there's no data" do
125
      trans = mock("Transport")
126
      trans.should_receive(:flush)
127
      btrans = BufferedTransport.new(trans)
128
      btrans.flush
129
    end
130
  end
131
 
132
  describe BufferedTransportFactory do
133
    it "should wrap the given transport in a BufferedTransport" do
134
      trans = mock("Transport")
135
      btrans = mock("BufferedTransport")
136
      BufferedTransport.should_receive(:new).with(trans).and_return(btrans)
137
      BufferedTransportFactory.new.get_transport(trans).should == btrans
138
    end
139
  end
140
 
141
  describe FramedTransport do
142
    before(:each) do
143
      @trans = mock("Transport")
144
    end
145
 
146
    it "should pass through open?/open/close" do
147
      ftrans = FramedTransport.new(@trans)
148
      @trans.should_receive(:open?).ordered.and_return("+ open?")
149
      @trans.should_receive(:open).ordered.and_return("+ open")
150
      @trans.should_receive(:close).ordered.and_return("+ close")
151
      ftrans.open?.should == "+ open?"
152
      ftrans.open.should == "+ open"
153
      ftrans.close.should == "+ close"
154
    end
155
 
156
    it "should pass through read when read is turned off" do
157
      ftrans = FramedTransport.new(@trans, false, true)
158
      @trans.should_receive(:read).with(17).ordered.and_return("+ read")
159
      ftrans.read(17).should == "+ read"
160
    end
161
 
162
    it "should pass through write/flush when write is turned off" do
163
      ftrans = FramedTransport.new(@trans, true, false)
164
      @trans.should_receive(:write).with("foo").ordered.and_return("+ write")
165
      @trans.should_receive(:flush).ordered.and_return("+ flush")
166
      ftrans.write("foo").should == "+ write"
167
      ftrans.flush.should == "+ flush"
168
    end
169
 
170
    it "should return a full frame if asked for >= the frame's length" do
171
      frame = "this is a frame"
172
      @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
173
      @trans.should_receive(:read_all).with(frame.length).and_return(frame)
174
      FramedTransport.new(@trans).read(frame.length + 10).should == frame
175
    end
176
 
177
    it "should return slices of the frame when asked for < the frame's length" do
178
      frame = "this is a frame"
179
      @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
180
      @trans.should_receive(:read_all).with(frame.length).and_return(frame)
181
      ftrans = FramedTransport.new(@trans)
182
      ftrans.read(4).should == "this"
183
      ftrans.read(4).should == " is "
184
      ftrans.read(16).should == "a frame"
185
    end
186
 
187
    it "should return nothing if asked for <= 0" do
188
      FramedTransport.new(@trans).read(-2).should == ""
189
    end
190
 
191
    it "should pull a new frame when the first is exhausted" do
192
      frame = "this is a frame"
193
      frame2 = "yet another frame"
194
      @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
195
      @trans.should_receive(:read_all).with(frame.length).and_return(frame)
196
      @trans.should_receive(:read_all).with(frame2.length).and_return(frame2)
197
      ftrans = FramedTransport.new(@trans)
198
      ftrans.read(4).should == "this"
199
      ftrans.read(8).should == " is a fr"
200
      ftrans.read(6).should == "ame"
201
      ftrans.read(4).should == "yet "
202
      ftrans.read(16).should == "another frame"
203
    end
204
 
205
    it "should buffer writes" do
206
      ftrans = FramedTransport.new(@trans)
207
      @trans.should_not_receive(:write)
208
      ftrans.write("foo")
209
      ftrans.write("bar")
210
      ftrans.write("this is a frame")
211
    end
212
 
213
    it "should write slices of the buffer" do
214
      ftrans = FramedTransport.new(@trans)
215
      ftrans.write("foobar", 3)
216
      ftrans.write("barfoo", 1)
217
      @trans.stub!(:flush)
218
      @trans.should_receive(:write).with("\000\000\000\004foob")
219
      ftrans.flush
220
    end
221
 
222
    it "should flush frames with a 4-byte header" do
223
      ftrans = FramedTransport.new(@trans)
224
      @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
225
      @trans.should_receive(:flush).ordered
226
      ftrans.write("one/")
227
      ftrans.write("two/")
228
      ftrans.write("three/")
229
      ftrans.write("this is a frame")
230
      ftrans.flush
231
    end
232
 
233
    it "should not flush the same buffered data twice" do
234
      ftrans = FramedTransport.new(@trans)
235
      @trans.should_receive(:write).with("\000\000\000\007foo/bar")
236
      @trans.stub!(:flush)
237
      ftrans.write("foo")
238
      ftrans.write("/bar")
239
      ftrans.flush
240
      @trans.should_receive(:write).with("\000\000\000\000")
241
      ftrans.flush
242
    end
243
  end
244
 
245
  describe FramedTransportFactory do
246
    it "should wrap the given transport in a FramedTransport" do
247
      trans = mock("Transport")
248
      FramedTransport.should_receive(:new).with(trans)
249
      FramedTransportFactory.new.get_transport(trans)
250
    end
251
  end
252
 
253
  describe MemoryBufferTransport do
254
    before(:each) do
255
      @buffer = MemoryBufferTransport.new
256
    end
257
 
258
    it "should accept a buffer on input and use it directly" do
259
      s = "this is a test"
260
      @buffer = MemoryBufferTransport.new(s)
261
      @buffer.read(4).should == "this"
262
      s.slice!(-4..-1)
263
      @buffer.read(@buffer.available).should == " is a "
264
    end
265
 
266
    it "should always remain open" do
267
      @buffer.should be_open
268
      @buffer.close
269
      @buffer.should be_open
270
    end
271
 
272
    it "should respond to peek and available" do
273
      @buffer.write "some data"
274
      @buffer.peek.should be_true
275
      @buffer.available.should == 9
276
      @buffer.read(4)
277
      @buffer.peek.should be_true
278
      @buffer.available.should == 5
279
      @buffer.read(5)
280
      @buffer.peek.should be_false
281
      @buffer.available.should == 0
282
    end
283
 
284
    it "should be able to reset the buffer" do
285
      @buffer.write "test data"
286
      @buffer.reset_buffer("foobar")
287
      @buffer.available.should == 6
288
      @buffer.read(@buffer.available).should == "foobar"
289
      @buffer.reset_buffer
290
      @buffer.available.should == 0
291
    end
292
 
293
    it "should copy the given string when resetting the buffer" do
294
      s = "this is a test"
295
      @buffer.reset_buffer(s)
296
      @buffer.available.should == 14
297
      @buffer.read(10)
298
      @buffer.available.should == 4
299
      s.should == "this is a test"
300
    end
301
 
302
    it "should return from read what was given in write" do
303
      @buffer.write "test data"
304
      @buffer.read(4).should == "test"
305
      @buffer.read(@buffer.available).should == " data"
306
      @buffer.write "foo"
307
      @buffer.write " bar"
308
      @buffer.read(@buffer.available).should == "foo bar"
309
    end
310
 
311
    it "should throw an EOFError when there isn't enough data in the buffer" do
312
      @buffer.reset_buffer("")
313
      lambda{@buffer.read(1)}.should raise_error(EOFError)
314
 
315
      @buffer.reset_buffer("1234")
316
      lambda{@buffer.read(5)}.should raise_error(EOFError)
317
    end
318
  end
319
 
320
  describe IOStreamTransport do
321
    before(:each) do
322
      @input = mock("Input", :closed? => false)
323
      @output = mock("Output", :closed? => false)
324
      @trans = IOStreamTransport.new(@input, @output)
325
    end
326
 
327
    it "should be open as long as both input or output are open" do
328
      @trans.should be_open
329
      @input.stub!(:closed?).and_return(true)
330
      @trans.should be_open
331
      @input.stub!(:closed?).and_return(false)
332
      @output.stub!(:closed?).and_return(true)
333
      @trans.should be_open
334
      @input.stub!(:closed?).and_return(true)
335
      @trans.should_not be_open
336
    end
337
 
338
    it "should pass through read/write to input/output" do
339
      @input.should_receive(:read).with(17).and_return("+ read")
340
      @output.should_receive(:write).with("foobar").and_return("+ write")
341
      @trans.read(17).should == "+ read"
342
      @trans.write("foobar").should == "+ write"
343
    end
344
 
345
    it "should close both input and output when closed" do
346
      @input.should_receive(:close)
347
      @output.should_receive(:close)
348
      @trans.close
349
    end
350
  end
351
end