Subversion Repositories SmartDukaan

Rev

Rev 30 | Details | Compare with Previous | 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
shared_examples_for 'a binary protocol' do
23
  before(:each) do
24
    @trans = Thrift::MemoryBufferTransport.new
25
    @prot = protocol_class.new(@trans)
26
  end
27
 
28
  it "should define the proper VERSION_1, VERSION_MASK AND TYPE_MASK" do
29
    protocol_class.const_get(:VERSION_MASK).should == 0xffff0000
30
    protocol_class.const_get(:VERSION_1).should == 0x80010000
31
    protocol_class.const_get(:TYPE_MASK).should == 0x000000ff
32
  end
33
 
34
  it "should make strict_read readable" do
35
    @prot.strict_read.should eql(true)
36
  end
37
 
38
  it "should make strict_write readable" do
39
    @prot.strict_write.should eql(true)
40
  end    
41
 
42
  it "should write the message header" do
43
    @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
44
    @trans.read(@trans.available).should == [protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N")
45
  end
46
 
47
  it "should write the message header without version when writes are not strict" do
48
    @prot = protocol_class.new(@trans, true, false) # no strict write
49
    @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
50
    @trans.read(@trans.available).should == "\000\000\000\vtestMessage\001\000\000\000\021"
51
  end
52
 
53
  it "should write the message header with a version when writes are strict" do
54
    @prot = protocol_class.new(@trans) # strict write
55
    @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
56
    @trans.read(@trans.available).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021"
57
  end
58
 
59
 
60
  # message footer is a noop
61
 
62
  it "should write the field header" do
63
    @prot.write_field_begin('foo', Thrift::Types::DOUBLE, 3)
64
    @trans.read(@trans.available).should == [Thrift::Types::DOUBLE, 3].pack("cn")
65
  end
66
 
67
  # field footer is a noop
68
 
69
  it "should write the STOP field" do
70
    @prot.write_field_stop
71
    @trans.read(1).should == "\000"
72
  end
73
 
74
  it "should write the map header" do
75
    @prot.write_map_begin(Thrift::Types::STRING, Thrift::Types::LIST, 17)
76
    @trans.read(@trans.available).should == [Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN");
77
  end
78
 
79
  # map footer is a noop
80
 
81
  it "should write the list header" do
82
    @prot.write_list_begin(Thrift::Types::I16, 42)
83
    @trans.read(@trans.available).should == [Thrift::Types::I16, 42].pack("cN")
84
  end
85
 
86
  # list footer is a noop
87
 
88
  it "should write the set header" do
89
    @prot.write_set_begin(Thrift::Types::I16, 42)
90
    @trans.read(@trans.available).should == [Thrift::Types::I16, 42].pack("cN")
91
  end
92
 
93
  it "should write a bool" do
94
    @prot.write_bool(true)
95
    @prot.write_bool(false)
96
    @trans.read(@trans.available).should == "\001\000"
97
  end
98
 
99
  it "should treat a nil bool as false" do
100
    @prot.write_bool(nil)
101
    @trans.read(1).should == "\000"
102
  end
103
 
104
  it "should write a byte" do
105
    # byte is small enough, let's check -128..127
106
    (-128..127).each do |i|
107
      @prot.write_byte(i)
108
      @trans.read(1).should == [i].pack('c')
109
    end
110
    # handing it numbers out of signed range should clip
111
    @trans.rspec_verify
112
    (128..255).each do |i|
113
      @prot.write_byte(i)
114
      @trans.read(1).should == [i].pack('c')
115
    end
116
    # and lastly, a Bignum is going to error out
117
    lambda { @prot.write_byte(2**65) }.should raise_error(RangeError)
118
  end
119
 
120
  it "should error gracefully when trying to write a nil byte" do
121
    lambda { @prot.write_byte(nil) }.should raise_error
122
  end
123
 
124
  it "should write an i16" do
125
    # try a random scattering of values
126
    # include the signed i16 minimum/maximum
127
    [-2**15, -1024, 17, 0, -10000, 1723, 2**15-1].each do |i|
128
      @prot.write_i16(i)
129
    end
130
    # and try something out of signed range, it should clip
131
    @prot.write_i16(2**15 + 5)
132
 
133
    @trans.read(@trans.available).should == "\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005"
134
 
135
    # a Bignum should error
136
    # lambda { @prot.write_i16(2**65) }.should raise_error(RangeError)
137
  end
138
 
139
  it "should error gracefully when trying to write a nil i16" do
140
    lambda { @prot.write_i16(nil) }.should raise_error
141
  end
142
 
143
  it "should write an i32" do
144
    # try a random scattering of values
145
    # include the signed i32 minimum/maximum
146
    [-2**31, -123123, -2532, -3, 0, 2351235, 12331, 2**31-1].each do |i|
147
      @prot.write_i32(i)
148
    end
149
    # try something out of signed range, it should clip
150
    @trans.read(@trans.available).should == "\200\000\000\000" + "\377\376\037\r" + "\377\377\366\034" + "\377\377\377\375" + "\000\000\000\000" + "\000#\340\203" + "\000\0000+" + "\177\377\377\377"
151
    [2 ** 31 + 5, 2 ** 65 + 5].each do |i|
152
      lambda { @prot.write_i32(i) }.should raise_error(RangeError)  
153
    end
154
  end
155
 
156
  it "should error gracefully when trying to write a nil i32" do
157
    lambda { @prot.write_i32(nil) }.should raise_error
158
  end
159
 
160
  it "should write an i64" do
161
    # try a random scattering of values
162
    # try the signed i64 minimum/maximum
163
    [-2**63, -12356123612323, -23512351, -234, 0, 1231, 2351236, 12361236213, 2**63-1].each do |i|
164
      @prot.write_i64(i)
165
    end
166
    # try something out of signed range, it should clip
167
    @trans.read(@trans.available).should == ["\200\000\000\000\000\000\000\000",
168
      "\377\377\364\303\035\244+]",
169
      "\377\377\377\377\376\231:\341",
170
      "\377\377\377\377\377\377\377\026",
171
      "\000\000\000\000\000\000\000\000",
172
      "\000\000\000\000\000\000\004\317",
173
      "\000\000\000\000\000#\340\204",
174
      "\000\000\000\002\340\311~\365",
175
      "\177\377\377\377\377\377\377\377"].join("")
176
    lambda { @prot.write_i64(2 ** 65 + 5) }.should raise_error(RangeError)
177
  end
178
 
179
  it "should error gracefully when trying to write a nil i64" do
180
    lambda { @prot.write_i64(nil) }.should raise_error
181
  end
182
 
183
  it "should write a double" do
184
    # try a random scattering of values, including min/max
185
    values = [Float::MIN,-1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX]
186
    values.each do |f|
187
      @prot.write_double(f)
188
      @trans.read(@trans.available).should == [f].pack("G")
189
    end
190
  end
191
 
192
  it "should error gracefully when trying to write a nil double" do
193
    lambda { @prot.write_double(nil) }.should raise_error
194
  end
195
 
196
  it "should write a string" do
197
    str = "hello world"
198
    @prot.write_string(str)
199
    @trans.read(@trans.available).should == [str.size].pack("N") + str
200
  end
201
 
202
  it "should error gracefully when trying to write a nil string" do
203
    lambda { @prot.write_string(nil) }.should raise_error
204
  end
205
 
206
  it "should write the message header without version when writes are not strict" do
207
    @prot = protocol_class.new(@trans, true, false) # no strict write
208
    @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
209
    @trans.read(@trans.available).should == "\000\000\000\vtestMessage\001\000\000\000\021"
210
  end
211
 
212
  it "should write the message header with a version when writes are strict" do
213
    @prot = protocol_class.new(@trans) # strict write
214
    @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
215
    @trans.read(@trans.available).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021"
216
  end
217
 
218
  # message footer is a noop
219
 
220
  it "should read a field header" do
221
    @trans.write([Thrift::Types::STRING, 3].pack("cn"))
222
    @prot.read_field_begin.should == [nil, Thrift::Types::STRING, 3]
223
  end
224
 
225
  # field footer is a noop
226
 
227
  it "should read a stop field" do
228
    @trans.write([Thrift::Types::STOP].pack("c"));
229
    @prot.read_field_begin.should == [nil, Thrift::Types::STOP, 0]
230
  end
231
 
232
  it "should read a map header" do
233
    @trans.write([Thrift::Types::DOUBLE, Thrift::Types::I64, 42].pack("ccN"))
234
    @prot.read_map_begin.should == [Thrift::Types::DOUBLE, Thrift::Types::I64, 42]
235
  end
236
 
237
  # map footer is a noop
238
 
239
  it "should read a list header" do
240
    @trans.write([Thrift::Types::STRING, 17].pack("cN"))
241
    @prot.read_list_begin.should == [Thrift::Types::STRING, 17]
242
  end
243
 
244
  # list footer is a noop
245
 
246
  it "should read a set header" do
247
    @trans.write([Thrift::Types::STRING, 17].pack("cN"))
248
    @prot.read_set_begin.should == [Thrift::Types::STRING, 17]
249
  end
250
 
251
  # set footer is a noop
252
 
253
  it "should read a bool" do
254
    @trans.write("\001\000");
255
    @prot.read_bool.should == true
256
    @prot.read_bool.should == false
257
  end
258
 
259
  it "should read a byte" do
260
    [-128, -57, -3, 0, 17, 24, 127].each do |i|
261
      @trans.write([i].pack("c"))
262
      @prot.read_byte.should == i
263
    end
264
  end
265
 
266
  it "should read an i16" do
267
    # try a scattering of values, including min/max
268
    [-2**15, -5237, -353, 0, 1527, 2234, 2**15-1].each do |i|
269
      @trans.write([i].pack("n"));
270
      @prot.read_i16.should == i
271
    end
272
  end
273
 
274
  it "should read an i32" do
275
    # try a scattering of values, including min/max
276
    [-2**31, -235125, -6236, 0, 2351, 123123, 2**31-1].each do |i|
277
      @trans.write([i].pack("N"))
278
      @prot.read_i32.should == i
279
    end
280
  end
281
 
282
  it "should read an i64" do
283
    # try a scattering of values, including min/max
284
    [-2**63, -123512312, -6346, 0, 32, 2346322323, 2**63-1].each do |i|
285
      @trans.write([i >> 32, i & 0xFFFFFFFF].pack("NN"))
286
      @prot.read_i64.should == i
287
    end
288
  end
289
 
290
  it "should read a double" do
291
    # try a random scattering of values, including min/max
292
    [Float::MIN, -231231.12351, -323.233513, 0, 123.2351235, 2351235.12351235, Float::MAX].each do |f|
293
      @trans.write([f].pack("G"));
294
      @prot.read_double.should == f
295
    end
296
  end
297
 
298
  it "should read a string" do
299
    str = "hello world"
300
    @trans.write([str.size].pack("N") + str)
301
    @prot.read_string.should == str
302
  end
303
 
304
  it "should perform a complete rpc with no args or return" do
305
    srv_test(
306
      proc {|client| client.send_voidMethod()},
307
      proc {|client| client.recv_voidMethod.should == nil}
308
    )
309
  end
310
 
311
  it "should perform a complete rpc with a primitive return type" do
312
    srv_test(
313
      proc {|client| client.send_primitiveMethod()},
314
      proc {|client| client.recv_primitiveMethod.should == 1}
315
    )
316
  end
317
 
318
  it "should perform a complete rpc with a struct return type" do
319
    srv_test(
320
      proc {|client| client.send_structMethod()},
321
      proc {|client|
322
        result = client.recv_structMethod
323
        result.set_byte_map = nil
324
        result.map_byte_map = nil
325
        result.should == Fixtures::COMPACT_PROTOCOL_TEST_STRUCT
326
      }
327
    )
328
  end
329
 
330
  def get_socket_connection
331
    server = Thrift::ServerSocket.new("localhost", 9090)
332
    server.listen
333
 
334
    clientside = Thrift::Socket.new("localhost", 9090)
335
    clientside.open
336
    serverside = server.accept
337
    [clientside, serverside, server]
338
  end
339
 
340
  def srv_test(firstblock, secondblock)
341
    clientside, serverside, server = get_socket_connection
342
 
343
    clientproto = protocol_class.new(clientside)
344
    serverproto = protocol_class.new(serverside)
345
 
346
    processor = Srv::Processor.new(SrvHandler.new)
347
 
348
    client = Srv::Client.new(clientproto, clientproto)
349
 
350
    # first block
351
    firstblock.call(client)
352
 
353
    processor.process(serverproto, serverproto)
354
 
355
    # second block
356
    secondblock.call(client)
357
  ensure
358
    clientside.close
359
    serverside.close
360
    server.close
361
  end
362
 
363
  class SrvHandler 
364
    def voidMethod()
365
    end
366
 
367
    def primitiveMethod
368
      1
369
    end
370
 
371
    def structMethod
372
      Fixtures::COMPACT_PROTOCOL_TEST_STRUCT
373
    end
374
  end
375
end