blob: 18ea8e8d0fa4029e650f83d9853e62436181416e [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001#
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
David Reiss72754e12008-07-25 21:06:03 +000020require File.dirname(__FILE__) + '/spec_helper'
21
22shared_examples_for 'a binary protocol' do
23 before(:each) do
Bryan Duxburyc0166282009-02-02 00:48:17 +000024 @trans = Thrift::MemoryBuffer.new
David Reiss72754e12008-07-25 21:06:03 +000025 @prot = protocol_class.new(@trans)
26 end
27
Kevin Clarkead33822009-02-04 22:43:59 +000028 it "should define the proper VERSION_1, VERSION_MASK AND TYPE_MASK" do
David Reiss72754e12008-07-25 21:06:03 +000029 protocol_class.const_get(:VERSION_MASK).should == 0xffff0000
30 protocol_class.const_get(:VERSION_1).should == 0x80010000
Kevin Clarkead33822009-02-04 22:43:59 +000031 protocol_class.const_get(:TYPE_MASK).should == 0x000000ff
David Reiss72754e12008-07-25 21:06:03 +000032 end
33
Kevin Clarkead33822009-02-04 22:43:59 +000034 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
David Reiss72754e12008-07-25 21:06:03 +000042 it "should write the message header" do
David Reiss72754e12008-07-25 21:06:03 +000043 @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
Bryan Duxburyc0166282009-02-02 00:48:17 +000044 @trans.read(1000).should == [protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N")
David Reiss72754e12008-07-25 21:06:03 +000045 end
Kevin Clarkead33822009-02-04 22:43:59 +000046
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(1000).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(1000).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021"
57 end
58
David Reiss72754e12008-07-25 21:06:03 +000059
60 # message footer is a noop
61
62 it "should write the field header" do
David Reiss72754e12008-07-25 21:06:03 +000063 @prot.write_field_begin('foo', Thrift::Types::DOUBLE, 3)
Bryan Duxburyc0166282009-02-02 00:48:17 +000064 @trans.read(1000).should == [Thrift::Types::DOUBLE, 3].pack("cn")
David Reiss72754e12008-07-25 21:06:03 +000065 end
Bryan Duxburyc0166282009-02-02 00:48:17 +000066
David Reiss72754e12008-07-25 21:06:03 +000067 # field footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +000068
David Reiss72754e12008-07-25 21:06:03 +000069 it "should write the STOP field" do
David Reiss72754e12008-07-25 21:06:03 +000070 @prot.write_field_stop
Bryan Duxburyc0166282009-02-02 00:48:17 +000071 @trans.read(1).should == "\000"
David Reiss72754e12008-07-25 21:06:03 +000072 end
Bryan Duxburyc0166282009-02-02 00:48:17 +000073
David Reiss72754e12008-07-25 21:06:03 +000074 it "should write the map header" do
David Reiss72754e12008-07-25 21:06:03 +000075 @prot.write_map_begin(Thrift::Types::STRING, Thrift::Types::LIST, 17)
Bryan Duxburyc0166282009-02-02 00:48:17 +000076 @trans.read(1000).should == [Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN");
David Reiss72754e12008-07-25 21:06:03 +000077 end
Bryan Duxburyc0166282009-02-02 00:48:17 +000078
David Reiss72754e12008-07-25 21:06:03 +000079 # map footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +000080
David Reiss72754e12008-07-25 21:06:03 +000081 it "should write the list header" do
David Reiss72754e12008-07-25 21:06:03 +000082 @prot.write_list_begin(Thrift::Types::I16, 42)
Bryan Duxburyc0166282009-02-02 00:48:17 +000083 @trans.read(1000).should == [Thrift::Types::I16, 42].pack("cN")
David Reiss72754e12008-07-25 21:06:03 +000084 end
Bryan Duxburyc0166282009-02-02 00:48:17 +000085
David Reiss72754e12008-07-25 21:06:03 +000086 # list footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +000087
David Reiss72754e12008-07-25 21:06:03 +000088 it "should write the set header" do
Bryan Duxburyc0166282009-02-02 00:48:17 +000089 @prot.write_set_begin(Thrift::Types::I16, 42)
90 @trans.read(1000).should == [Thrift::Types::I16, 42].pack("cN")
David Reiss72754e12008-07-25 21:06:03 +000091 end
Bryan Duxburyc0166282009-02-02 00:48:17 +000092
David Reiss72754e12008-07-25 21:06:03 +000093 it "should write a bool" do
David Reiss72754e12008-07-25 21:06:03 +000094 @prot.write_bool(true)
David Reiss72754e12008-07-25 21:06:03 +000095 @prot.write_bool(false)
Bryan Duxburyc0166282009-02-02 00:48:17 +000096 @trans.read(1000).should == "\001\000"
David Reiss72754e12008-07-25 21:06:03 +000097 end
Bryan Duxburyc0166282009-02-02 00:48:17 +000098
Kevin Clark14fe7912008-08-04 18:46:19 +000099 it "should treat a nil bool as false" do
Kevin Clark14fe7912008-08-04 18:46:19 +0000100 @prot.write_bool(nil)
Bryan Duxburyc0166282009-02-02 00:48:17 +0000101 @trans.read(1).should == "\000"
Kevin Clark14fe7912008-08-04 18:46:19 +0000102 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000103
David Reiss72754e12008-07-25 21:06:03 +0000104 it "should write a byte" do
105 # byte is small enough, let's check -128..127
106 (-128..127).each do |i|
David Reiss72754e12008-07-25 21:06:03 +0000107 @prot.write_byte(i)
Bryan Duxburyc0166282009-02-02 00:48:17 +0000108 @trans.read(1).should == [i].pack('c')
David Reiss72754e12008-07-25 21:06:03 +0000109 end
David Reiss72754e12008-07-25 21:06:03 +0000110 # handing it numbers out of signed range should clip
111 @trans.rspec_verify
112 (128..255).each do |i|
David Reiss72754e12008-07-25 21:06:03 +0000113 @prot.write_byte(i)
Bryan Duxburyc0166282009-02-02 00:48:17 +0000114 @trans.read(1).should == [i].pack('c')
David Reiss72754e12008-07-25 21:06:03 +0000115 end
116 # and lastly, a Bignum is going to error out
117 lambda { @prot.write_byte(2**65) }.should raise_error(RangeError)
118 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000119
Kevin Clark14fe7912008-08-04 18:46:19 +0000120 it "should error gracefully when trying to write a nil byte" do
121 lambda { @prot.write_byte(nil) }.should raise_error
122 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000123
David Reiss72754e12008-07-25 21:06:03 +0000124 it "should write an i16" do
125 # try a random scattering of values
126 # include the signed i16 minimum/maximum
David Reiss72754e12008-07-25 21:06:03 +0000127 [-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
David Reiss72754e12008-07-25 21:06:03 +0000131 @prot.write_i16(2**15 + 5)
Bryan Duxburyc0166282009-02-02 00:48:17 +0000132
133 @trans.read(1000).should == "\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005"
134
David Reiss72754e12008-07-25 21:06:03 +0000135 # a Bignum should error
136 # lambda { @prot.write_i16(2**65) }.should raise_error(RangeError)
137 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000138
Kevin Clark14fe7912008-08-04 18:46:19 +0000139 it "should error gracefully when trying to write a nil i16" do
140 lambda { @prot.write_i16(nil) }.should raise_error
141 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000142
David Reiss72754e12008-07-25 21:06:03 +0000143 it "should write an i32" do
144 # try a random scattering of values
145 # include the signed i32 minimum/maximum
David Reiss72754e12008-07-25 21:06:03 +0000146 [-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
Bryan Duxburyc0166282009-02-02 00:48:17 +0000150 @trans.read(1000).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
David Reiss72754e12008-07-25 21:06:03 +0000154 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000155
Kevin Clark14fe7912008-08-04 18:46:19 +0000156 it "should error gracefully when trying to write a nil i32" do
157 lambda { @prot.write_i32(nil) }.should raise_error
158 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000159
David Reiss72754e12008-07-25 21:06:03 +0000160 it "should write an i64" do
161 # try a random scattering of values
162 # try the signed i64 minimum/maximum
David Reiss72754e12008-07-25 21:06:03 +0000163 [-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
Bryan Duxburyc0166282009-02-02 00:48:17 +0000167 @trans.read(1000).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)
David Reiss72754e12008-07-25 21:06:03 +0000177 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000178
Kevin Clark14fe7912008-08-04 18:46:19 +0000179 it "should error gracefully when trying to write a nil i64" do
180 lambda { @prot.write_i64(nil) }.should raise_error
181 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000182
David Reiss72754e12008-07-25 21:06:03 +0000183 it "should write a double" do
184 # try a random scattering of values, including min/max
Bryan Duxburyc0166282009-02-02 00:48:17 +0000185 values = [Float::MIN,-1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX]
186 values.each do |f|
David Reiss72754e12008-07-25 21:06:03 +0000187 @prot.write_double(f)
Bryan Duxburyc0166282009-02-02 00:48:17 +0000188 @trans.read(1000).should == [f].pack("G")
David Reiss72754e12008-07-25 21:06:03 +0000189 end
190 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000191
Kevin Clark14fe7912008-08-04 18:46:19 +0000192 it "should error gracefully when trying to write a nil double" do
193 lambda { @prot.write_double(nil) }.should raise_error
194 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000195
David Reiss72754e12008-07-25 21:06:03 +0000196 it "should write a string" do
197 str = "hello world"
David Reiss72754e12008-07-25 21:06:03 +0000198 @prot.write_string(str)
Bryan Duxburyc0166282009-02-02 00:48:17 +0000199 @trans.read(1000).should == [str.size].pack("N") + str
David Reiss72754e12008-07-25 21:06:03 +0000200 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000201
Kevin Clark14fe7912008-08-04 18:46:19 +0000202 it "should error gracefully when trying to write a nil string" do
203 lambda { @prot.write_string(nil) }.should raise_error
204 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000205
Bryan Duxbury1adbab02009-03-31 21:09:26 +0000206 it "should read message header correctly" do
207 @trans.write([protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N"))
208 @prot.read_message_begin().should == ['testMessage', Thrift::MessageTypes::CALL, 17]
209 end
210
Bryan Duxburyac002d32009-03-31 23:48:36 +0000211 it "should read the message header without version when writes are not strict" do
212 @prot = protocol_class.new(@trans, false, true) # no strict write
213 @trans.write("\000\000\000\vtestMessage\001\000\000\000\021")
214 @prot.read_message_begin().should == ['testMessage', Thrift::MessageTypes::CALL, 17]
215 end
216
David Reiss72754e12008-07-25 21:06:03 +0000217 # message footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +0000218
David Reiss72754e12008-07-25 21:06:03 +0000219 it "should read a field header" do
Bryan Duxburyc0166282009-02-02 00:48:17 +0000220 @trans.write([Thrift::Types::STRING, 3].pack("cn"))
David Reiss72754e12008-07-25 21:06:03 +0000221 @prot.read_field_begin.should == [nil, Thrift::Types::STRING, 3]
222 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000223
David Reiss72754e12008-07-25 21:06:03 +0000224 # field footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +0000225
David Reiss72754e12008-07-25 21:06:03 +0000226 it "should read a stop field" do
Bryan Duxburyc0166282009-02-02 00:48:17 +0000227 @trans.write([Thrift::Types::STOP].pack("c"));
David Reiss72754e12008-07-25 21:06:03 +0000228 @prot.read_field_begin.should == [nil, Thrift::Types::STOP, 0]
229 end
230
231 it "should read a map header" do
Bryan Duxburyc0166282009-02-02 00:48:17 +0000232 @trans.write([Thrift::Types::DOUBLE, Thrift::Types::I64, 42].pack("ccN"))
David Reiss72754e12008-07-25 21:06:03 +0000233 @prot.read_map_begin.should == [Thrift::Types::DOUBLE, Thrift::Types::I64, 42]
234 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000235
David Reiss72754e12008-07-25 21:06:03 +0000236 # map footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +0000237
David Reiss72754e12008-07-25 21:06:03 +0000238 it "should read a list header" do
Bryan Duxburyc0166282009-02-02 00:48:17 +0000239 @trans.write([Thrift::Types::STRING, 17].pack("cN"))
David Reiss72754e12008-07-25 21:06:03 +0000240 @prot.read_list_begin.should == [Thrift::Types::STRING, 17]
241 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000242
David Reiss72754e12008-07-25 21:06:03 +0000243 # list footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +0000244
David Reiss72754e12008-07-25 21:06:03 +0000245 it "should read a set header" do
Bryan Duxburyc0166282009-02-02 00:48:17 +0000246 @trans.write([Thrift::Types::STRING, 17].pack("cN"))
247 @prot.read_set_begin.should == [Thrift::Types::STRING, 17]
David Reiss72754e12008-07-25 21:06:03 +0000248 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000249
David Reiss72754e12008-07-25 21:06:03 +0000250 # set footer is a noop
Bryan Duxburyc0166282009-02-02 00:48:17 +0000251
David Reiss72754e12008-07-25 21:06:03 +0000252 it "should read a bool" do
Bryan Duxburyc0166282009-02-02 00:48:17 +0000253 @trans.write("\001\000");
David Reiss72754e12008-07-25 21:06:03 +0000254 @prot.read_bool.should == true
255 @prot.read_bool.should == false
256 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000257
David Reiss72754e12008-07-25 21:06:03 +0000258 it "should read a byte" do
David Reiss72754e12008-07-25 21:06:03 +0000259 [-128, -57, -3, 0, 17, 24, 127].each do |i|
Bryan Duxburyc0166282009-02-02 00:48:17 +0000260 @trans.write([i].pack("c"))
David Reiss72754e12008-07-25 21:06:03 +0000261 @prot.read_byte.should == i
262 end
263 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000264
David Reiss72754e12008-07-25 21:06:03 +0000265 it "should read an i16" do
266 # try a scattering of values, including min/max
David Reiss72754e12008-07-25 21:06:03 +0000267 [-2**15, -5237, -353, 0, 1527, 2234, 2**15-1].each do |i|
Bryan Duxburyc0166282009-02-02 00:48:17 +0000268 @trans.write([i].pack("n"));
David Reiss72754e12008-07-25 21:06:03 +0000269 @prot.read_i16.should == i
270 end
271 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000272
David Reiss72754e12008-07-25 21:06:03 +0000273 it "should read an i32" do
274 # try a scattering of values, including min/max
David Reiss72754e12008-07-25 21:06:03 +0000275 [-2**31, -235125, -6236, 0, 2351, 123123, 2**31-1].each do |i|
Bryan Duxburyc0166282009-02-02 00:48:17 +0000276 @trans.write([i].pack("N"))
David Reiss72754e12008-07-25 21:06:03 +0000277 @prot.read_i32.should == i
278 end
279 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000280
David Reiss72754e12008-07-25 21:06:03 +0000281 it "should read an i64" do
282 # try a scattering of values, including min/max
David Reiss72754e12008-07-25 21:06:03 +0000283 [-2**63, -123512312, -6346, 0, 32, 2346322323, 2**63-1].each do |i|
Bryan Duxburyc0166282009-02-02 00:48:17 +0000284 @trans.write([i >> 32, i & 0xFFFFFFFF].pack("NN"))
David Reiss72754e12008-07-25 21:06:03 +0000285 @prot.read_i64.should == i
286 end
287 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000288
David Reiss72754e12008-07-25 21:06:03 +0000289 it "should read a double" do
290 # try a random scattering of values, including min/max
David Reiss72754e12008-07-25 21:06:03 +0000291 [Float::MIN, -231231.12351, -323.233513, 0, 123.2351235, 2351235.12351235, Float::MAX].each do |f|
Bryan Duxburyc0166282009-02-02 00:48:17 +0000292 @trans.write([f].pack("G"));
David Reiss72754e12008-07-25 21:06:03 +0000293 @prot.read_double.should == f
294 end
295 end
Bryan Duxburyc0166282009-02-02 00:48:17 +0000296
David Reiss72754e12008-07-25 21:06:03 +0000297 it "should read a string" do
298 str = "hello world"
Bryan Duxburyc0166282009-02-02 00:48:17 +0000299 @trans.write([str.size].pack("N") + str)
David Reiss72754e12008-07-25 21:06:03 +0000300 @prot.read_string.should == str
301 end
Bryan Duxbury5b8b4842009-04-01 20:10:15 +0000302
303 it "should perform a complete rpc with no args or return" do
304 srv_test(
305 proc {|client| client.send_voidMethod()},
306 proc {|client| client.recv_voidMethod.should == nil}
307 )
308 end
309
310 it "should perform a complete rpc with a primitive return type" do
311 srv_test(
312 proc {|client| client.send_primitiveMethod()},
313 proc {|client| client.recv_primitiveMethod.should == 1}
314 )
315 end
316
317 it "should perform a complete rpc with a struct return type" do
318 srv_test(
319 proc {|client| client.send_structMethod()},
320 proc {|client|
321 result = client.recv_structMethod
322 result.set_byte_map = nil
323 result.map_byte_map = nil
324 result.should == Fixtures::COMPACT_PROTOCOL_TEST_STRUCT
325 }
326 )
327 end
328
329 def get_socket_connection
330 server = Thrift::ServerSocket.new("localhost", 9090)
331 server.listen
332
333 clientside = Thrift::Socket.new("localhost", 9090)
334 clientside.open
335 serverside = server.accept
336 [clientside, serverside, server]
337 end
338
339 def srv_test(firstblock, secondblock)
340 clientside, serverside, server = get_socket_connection
341
342 clientproto = protocol_class.new(clientside)
343 serverproto = protocol_class.new(serverside)
344
345 processor = Srv::Processor.new(SrvHandler.new)
346
347 client = Srv::Client.new(clientproto, clientproto)
348
349 # first block
350 firstblock.call(client)
351
352 processor.process(serverproto, serverproto)
353
354 # second block
355 secondblock.call(client)
356 ensure
357 clientside.close
358 serverside.close
359 server.close
360 end
361
362 class SrvHandler
363 def voidMethod()
364 end
365
366 def primitiveMethod
367 1
368 end
369
370 def structMethod
371 Fixtures::COMPACT_PROTOCOL_TEST_STRUCT
372 end
373 end
374
David Reiss72754e12008-07-25 21:06:03 +0000375end