tiny_thrift 1.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/README +43 -0
  3. data/benchmark/Benchmark.thrift +24 -0
  4. data/benchmark/benchmark.rb +271 -0
  5. data/benchmark/client.rb +74 -0
  6. data/benchmark/server.rb +82 -0
  7. data/benchmark/thin_server.rb +44 -0
  8. data/ext/binary_protocol_accelerated.c +460 -0
  9. data/ext/binary_protocol_accelerated.h +20 -0
  10. data/ext/bytes.c +36 -0
  11. data/ext/bytes.h +31 -0
  12. data/ext/compact_protocol.c +635 -0
  13. data/ext/compact_protocol.h +20 -0
  14. data/ext/constants.h +96 -0
  15. data/ext/extconf.rb +32 -0
  16. data/ext/macros.h +41 -0
  17. data/ext/memory_buffer.c +134 -0
  18. data/ext/memory_buffer.h +20 -0
  19. data/ext/protocol.c +0 -0
  20. data/ext/protocol.h +0 -0
  21. data/ext/strlcpy.c +41 -0
  22. data/ext/strlcpy.h +34 -0
  23. data/ext/struct.c +688 -0
  24. data/ext/struct.h +25 -0
  25. data/ext/thrift_native.c +195 -0
  26. data/lib/thrift.rb +66 -0
  27. data/lib/thrift/bytes.rb +131 -0
  28. data/lib/thrift/client.rb +62 -0
  29. data/lib/thrift/core_ext.rb +23 -0
  30. data/lib/thrift/core_ext/fixnum.rb +29 -0
  31. data/lib/thrift/exceptions.rb +87 -0
  32. data/lib/thrift/processor.rb +57 -0
  33. data/lib/thrift/protocol/base_protocol.rb +377 -0
  34. data/lib/thrift/protocol/binary_protocol.rb +237 -0
  35. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  36. data/lib/thrift/protocol/compact_protocol.rb +434 -0
  37. data/lib/thrift/protocol/json_protocol.rb +769 -0
  38. data/lib/thrift/serializer/deserializer.rb +33 -0
  39. data/lib/thrift/serializer/serializer.rb +34 -0
  40. data/lib/thrift/server/base_server.rb +31 -0
  41. data/lib/thrift/server/mongrel_http_server.rb +60 -0
  42. data/lib/thrift/server/nonblocking_server.rb +305 -0
  43. data/lib/thrift/server/simple_server.rb +43 -0
  44. data/lib/thrift/server/thin_http_server.rb +91 -0
  45. data/lib/thrift/server/thread_pool_server.rb +75 -0
  46. data/lib/thrift/server/threaded_server.rb +47 -0
  47. data/lib/thrift/struct.rb +237 -0
  48. data/lib/thrift/struct_union.rb +192 -0
  49. data/lib/thrift/thrift_native.rb +24 -0
  50. data/lib/thrift/transport/base_server_transport.rb +37 -0
  51. data/lib/thrift/transport/base_transport.rb +109 -0
  52. data/lib/thrift/transport/buffered_transport.rb +114 -0
  53. data/lib/thrift/transport/framed_transport.rb +117 -0
  54. data/lib/thrift/transport/http_client_transport.rb +56 -0
  55. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  56. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  57. data/lib/thrift/transport/server_socket.rb +63 -0
  58. data/lib/thrift/transport/socket.rb +139 -0
  59. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  60. data/lib/thrift/transport/unix_socket.rb +40 -0
  61. data/lib/thrift/types.rb +101 -0
  62. data/lib/thrift/union.rb +179 -0
  63. data/lib/tiny_thrift.rb +1 -0
  64. data/spec/ThriftSpec.thrift +183 -0
  65. data/spec/base_protocol_spec.rb +217 -0
  66. data/spec/base_transport_spec.rb +350 -0
  67. data/spec/binary_protocol_accelerated_spec.rb +42 -0
  68. data/spec/binary_protocol_spec.rb +66 -0
  69. data/spec/binary_protocol_spec_shared.rb +455 -0
  70. data/spec/bytes_spec.rb +160 -0
  71. data/spec/client_spec.rb +99 -0
  72. data/spec/compact_protocol_spec.rb +143 -0
  73. data/spec/exception_spec.rb +141 -0
  74. data/spec/http_client_spec.rb +120 -0
  75. data/spec/json_protocol_spec.rb +513 -0
  76. data/spec/nonblocking_server_spec.rb +263 -0
  77. data/spec/processor_spec.rb +80 -0
  78. data/spec/serializer_spec.rb +67 -0
  79. data/spec/server_socket_spec.rb +79 -0
  80. data/spec/server_spec.rb +147 -0
  81. data/spec/socket_spec.rb +61 -0
  82. data/spec/socket_spec_shared.rb +104 -0
  83. data/spec/spec_helper.rb +61 -0
  84. data/spec/struct_nested_containers_spec.rb +191 -0
  85. data/spec/struct_spec.rb +293 -0
  86. data/spec/thin_http_server_spec.rb +141 -0
  87. data/spec/types_spec.rb +115 -0
  88. data/spec/union_spec.rb +203 -0
  89. data/spec/unix_socket_spec.rb +107 -0
  90. metadata +313 -0
@@ -0,0 +1,293 @@
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 'Struct' do
23
+
24
+ describe Thrift::Struct do
25
+ it "should iterate over all fields properly" do
26
+ fields = {}
27
+ SpecNamespace::Foo.new.each_field { |fid,field_info| fields[fid] = field_info }
28
+ fields.should == SpecNamespace::Foo::FIELDS
29
+ end
30
+
31
+ it "should initialize all fields to defaults" do
32
+ validate_default_arguments(SpecNamespace::Foo.new)
33
+ end
34
+
35
+ it "should initialize all fields to defaults and accept a block argument" do
36
+ SpecNamespace::Foo.new do |f|
37
+ validate_default_arguments(f)
38
+ end
39
+ end
40
+
41
+ def validate_default_arguments(object)
42
+ object.simple.should == 53
43
+ object.words.should == "words"
44
+ object.hello.should == SpecNamespace::Hello.new(:greeting => 'hello, world!')
45
+ object.ints.should == [1, 2, 2, 3]
46
+ object.complex.should be_nil
47
+ object.shorts.should == Set.new([5, 17, 239])
48
+ end
49
+
50
+ it "should not share default values between instances" do
51
+ begin
52
+ struct = SpecNamespace::Foo.new
53
+ struct.ints << 17
54
+ SpecNamespace::Foo.new.ints.should == [1,2,2,3]
55
+ ensure
56
+ # ensure no leakage to other tests
57
+ SpecNamespace::Foo::FIELDS[4][:default] = [1,2,2,3]
58
+ end
59
+ end
60
+
61
+ it "should properly initialize boolean values" do
62
+ struct = SpecNamespace::BoolStruct.new(:yesno => false)
63
+ struct.yesno.should be_false
64
+ end
65
+
66
+ it "should have proper == semantics" do
67
+ SpecNamespace::Foo.new.should_not == SpecNamespace::Hello.new
68
+ SpecNamespace::Foo.new.should == SpecNamespace::Foo.new
69
+ SpecNamespace::Foo.new(:simple => 52).should_not == SpecNamespace::Foo.new
70
+ end
71
+
72
+ it "should print enum value names in inspect" do
73
+ SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE).inspect.should == "<SpecNamespace::StructWithSomeEnum some_enum:ONE (0)>"
74
+
75
+ SpecNamespace::StructWithEnumMap.new(:my_map => {SpecNamespace::SomeEnum::ONE => [SpecNamespace::SomeEnum::TWO]}).inspect.should == "<SpecNamespace::StructWithEnumMap my_map:{ONE (0): [TWO (1)]}>"
76
+ end
77
+
78
+ it "should pretty print binary fields" do
79
+ SpecNamespace::Foo2.new(:my_binary => "\001\002\003").inspect.should == "<SpecNamespace::Foo2 my_binary:010203>"
80
+ end
81
+
82
+ it "should offer field? methods" do
83
+ SpecNamespace::Foo.new.opt_string?.should be_false
84
+ SpecNamespace::Foo.new(:simple => 52).simple?.should be_true
85
+ SpecNamespace::Foo.new(:my_bool => false).my_bool?.should be_true
86
+ SpecNamespace::Foo.new(:my_bool => true).my_bool?.should be_true
87
+ end
88
+
89
+ it "should be comparable" do
90
+ s1 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::ONE)
91
+ s2 = SpecNamespace::StructWithSomeEnum.new(:some_enum => SpecNamespace::SomeEnum::TWO)
92
+
93
+ (s1 <=> s2).should == -1
94
+ (s2 <=> s1).should == 1
95
+ (s1 <=> s1).should == 0
96
+ (s1 <=> SpecNamespace::StructWithSomeEnum.new()).should == -1
97
+ end
98
+
99
+ it "should read itself off the wire" do
100
+ struct = SpecNamespace::Foo.new
101
+ prot = Thrift::BaseProtocol.new(mock("transport"))
102
+ prot.should_receive(:read_struct_begin).twice
103
+ prot.should_receive(:read_struct_end).twice
104
+ prot.should_receive(:read_field_begin).and_return(
105
+ ['complex', Thrift::Types::MAP, 5], # Foo
106
+ ['words', Thrift::Types::STRING, 2], # Foo
107
+ ['hello', Thrift::Types::STRUCT, 3], # Foo
108
+ ['greeting', Thrift::Types::STRING, 1], # Hello
109
+ [nil, Thrift::Types::STOP, 0], # Hello
110
+ ['simple', Thrift::Types::I32, 1], # Foo
111
+ ['ints', Thrift::Types::LIST, 4], # Foo
112
+ ['shorts', Thrift::Types::SET, 6], # Foo
113
+ [nil, Thrift::Types::STOP, 0] # Hello
114
+ )
115
+ prot.should_receive(:read_field_end).exactly(7).times
116
+ prot.should_receive(:read_map_begin).and_return(
117
+ [Thrift::Types::I32, Thrift::Types::MAP, 2], # complex
118
+ [Thrift::Types::STRING, Thrift::Types::DOUBLE, 2], # complex/1/value
119
+ [Thrift::Types::STRING, Thrift::Types::DOUBLE, 1] # complex/2/value
120
+ )
121
+ prot.should_receive(:read_map_end).exactly(3).times
122
+ prot.should_receive(:read_list_begin).and_return([Thrift::Types::I32, 4])
123
+ prot.should_receive(:read_list_end)
124
+ prot.should_receive(:read_set_begin).and_return([Thrift::Types::I16, 2])
125
+ prot.should_receive(:read_set_end)
126
+ prot.should_receive(:read_i32).and_return(
127
+ 1, 14, # complex keys
128
+ 42, # simple
129
+ 4, 23, 4, 29 # ints
130
+ )
131
+ prot.should_receive(:read_string).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?")
132
+ prot.should_receive(:read_double).and_return(Math::PI, Math::E, 4.669201609)
133
+ prot.should_receive(:read_i16).and_return(2, 3)
134
+ prot.should_not_receive(:skip)
135
+ struct.read(prot)
136
+
137
+ struct.simple.should == 42
138
+ struct.complex.should == {1 => {"pi" => Math::PI, "e" => Math::E}, 14 => {"feigenbaum" => 4.669201609}}
139
+ struct.hello.should == SpecNamespace::Hello.new(:greeting => "what's up?")
140
+ struct.words.should == "apple banana"
141
+ struct.ints.should == [4, 23, 4, 29]
142
+ struct.shorts.should == Set.new([3, 2])
143
+ end
144
+
145
+ it "should serialize false boolean fields correctly" do
146
+ b = SpecNamespace::BoolStruct.new(:yesno => false)
147
+ prot = Thrift::BinaryProtocol.new(Thrift::MemoryBufferTransport.new)
148
+ prot.should_receive(:write_bool).with(false)
149
+ b.write(prot)
150
+ end
151
+
152
+ it "should skip unexpected fields in structs and use default values" do
153
+ struct = SpecNamespace::Foo.new
154
+ prot = Thrift::BaseProtocol.new(mock("transport"))
155
+ prot.should_receive(:read_struct_begin)
156
+ prot.should_receive(:read_struct_end)
157
+ prot.should_receive(:read_field_begin).and_return(
158
+ ['simple', Thrift::Types::I32, 1],
159
+ ['complex', Thrift::Types::STRUCT, 5],
160
+ ['thinz', Thrift::Types::MAP, 7],
161
+ ['foobar', Thrift::Types::I32, 3],
162
+ ['words', Thrift::Types::STRING, 2],
163
+ [nil, Thrift::Types::STOP, 0]
164
+ )
165
+ prot.should_receive(:read_field_end).exactly(5).times
166
+ prot.should_receive(:read_i32).and_return(42)
167
+ prot.should_receive(:read_string).and_return("foobar")
168
+ prot.should_receive(:skip).with(Thrift::Types::STRUCT)
169
+ prot.should_receive(:skip).with(Thrift::Types::MAP)
170
+ # prot.should_receive(:read_map_begin).and_return([Thrift::Types::I32, Thrift::Types::I32, 0])
171
+ # prot.should_receive(:read_map_end)
172
+ prot.should_receive(:skip).with(Thrift::Types::I32)
173
+ struct.read(prot)
174
+
175
+ struct.simple.should == 42
176
+ struct.complex.should be_nil
177
+ struct.words.should == "foobar"
178
+ struct.hello.should == SpecNamespace::Hello.new(:greeting => 'hello, world!')
179
+ struct.ints.should == [1, 2, 2, 3]
180
+ struct.shorts.should == Set.new([5, 17, 239])
181
+ end
182
+
183
+ it "should write itself to the wire" do
184
+ prot = Thrift::BaseProtocol.new(mock("transport")) #mock("Protocol")
185
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Foo")
186
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Hello")
187
+ prot.should_receive(:write_struct_end).twice
188
+ prot.should_receive(:write_field_begin).with('ints', Thrift::Types::LIST, 4)
189
+ prot.should_receive(:write_i32).with(1)
190
+ prot.should_receive(:write_i32).with(2).twice
191
+ prot.should_receive(:write_i32).with(3)
192
+ prot.should_receive(:write_field_begin).with('complex', Thrift::Types::MAP, 5)
193
+ prot.should_receive(:write_i32).with(5)
194
+ prot.should_receive(:write_string).with('foo')
195
+ prot.should_receive(:write_double).with(1.23)
196
+ prot.should_receive(:write_field_begin).with('shorts', Thrift::Types::SET, 6)
197
+ prot.should_receive(:write_i16).with(5)
198
+ prot.should_receive(:write_i16).with(17)
199
+ prot.should_receive(:write_i16).with(239)
200
+ prot.should_receive(:write_field_stop).twice
201
+ prot.should_receive(:write_field_end).exactly(6).times
202
+ prot.should_receive(:write_field_begin).with('simple', Thrift::Types::I32, 1)
203
+ prot.should_receive(:write_i32).with(53)
204
+ prot.should_receive(:write_field_begin).with('hello', Thrift::Types::STRUCT, 3)
205
+ prot.should_receive(:write_field_begin).with('greeting', Thrift::Types::STRING, 1)
206
+ prot.should_receive(:write_string).with('hello, world!')
207
+ prot.should_receive(:write_map_begin).with(Thrift::Types::I32, Thrift::Types::MAP, 1)
208
+ prot.should_receive(:write_map_begin).with(Thrift::Types::STRING, Thrift::Types::DOUBLE, 1)
209
+ prot.should_receive(:write_map_end).twice
210
+ prot.should_receive(:write_list_begin).with(Thrift::Types::I32, 4)
211
+ prot.should_receive(:write_list_end)
212
+ prot.should_receive(:write_set_begin).with(Thrift::Types::I16, 3)
213
+ prot.should_receive(:write_set_end)
214
+
215
+ struct = SpecNamespace::Foo.new
216
+ struct.words = nil
217
+ struct.complex = {5 => {"foo" => 1.23}}
218
+ struct.write(prot)
219
+ end
220
+
221
+ it "should raise an exception if presented with an unknown container" do
222
+ # yeah this is silly, but I'm going for code coverage here
223
+ struct = SpecNamespace::Foo.new
224
+ lambda { struct.send :write_container, nil, nil, {:type => "foo"} }.should raise_error(StandardError, "Not a container type: foo")
225
+ end
226
+
227
+ it "should support optional type-checking in Thrift::Struct.new" do
228
+ Thrift.type_checking = true
229
+ begin
230
+ lambda { SpecNamespace::Hello.new(:greeting => 3) }.should raise_error(Thrift::TypeError, "Expected Types::STRING, received Fixnum for field greeting")
231
+ ensure
232
+ Thrift.type_checking = false
233
+ end
234
+ lambda { SpecNamespace::Hello.new(:greeting => 3) }.should_not raise_error(Thrift::TypeError)
235
+ end
236
+
237
+ it "should support optional type-checking in field accessors" do
238
+ Thrift.type_checking = true
239
+ begin
240
+ hello = SpecNamespace::Hello.new
241
+ lambda { hello.greeting = 3 }.should raise_error(Thrift::TypeError, "Expected Types::STRING, received Fixnum for field greeting")
242
+ ensure
243
+ Thrift.type_checking = false
244
+ end
245
+ lambda { hello.greeting = 3 }.should_not raise_error(Thrift::TypeError)
246
+ end
247
+
248
+ it "should raise an exception when unknown types are given to Thrift::Struct.new" do
249
+ lambda { SpecNamespace::Hello.new(:fish => 'salmon') }.should raise_error(Exception, "Unknown key given to SpecNamespace::Hello.new: fish")
250
+ end
251
+
252
+ it "should support `raise Xception, 'message'` for Exception structs" do
253
+ begin
254
+ raise SpecNamespace::Xception, "something happened"
255
+ rescue Thrift::Exception => e
256
+ e.message.should == "something happened"
257
+ e.code.should == 1
258
+ # ensure it gets serialized properly, this is the really important part
259
+ prot = Thrift::BaseProtocol.new(mock("trans"))
260
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
261
+ prot.should_receive(:write_struct_end)
262
+ prot.should_receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)#, "something happened")
263
+ prot.should_receive(:write_string).with("something happened")
264
+ prot.should_receive(:write_field_begin).with('code', Thrift::Types::I32, 2)#, 1)
265
+ prot.should_receive(:write_i32).with(1)
266
+ prot.should_receive(:write_field_stop)
267
+ prot.should_receive(:write_field_end).twice
268
+
269
+ e.write(prot)
270
+ end
271
+ end
272
+
273
+ it "should support the regular initializer for exception structs" do
274
+ begin
275
+ raise SpecNamespace::Xception, :message => "something happened", :code => 5
276
+ rescue Thrift::Exception => e
277
+ e.message.should == "something happened"
278
+ e.code.should == 5
279
+ prot = Thrift::BaseProtocol.new(mock("trans"))
280
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
281
+ prot.should_receive(:write_struct_end)
282
+ prot.should_receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)
283
+ prot.should_receive(:write_string).with("something happened")
284
+ prot.should_receive(:write_field_begin).with('code', Thrift::Types::I32, 2)
285
+ prot.should_receive(:write_i32).with(5)
286
+ prot.should_receive(:write_field_stop)
287
+ prot.should_receive(:write_field_end).twice
288
+
289
+ e.write(prot)
290
+ end
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,141 @@
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
+ require 'rack/test'
22
+ require 'thrift/server/thin_http_server'
23
+
24
+ describe Thrift::ThinHTTPServer do
25
+
26
+ let(:processor) { mock('processor') }
27
+
28
+ describe "#initialize" do
29
+
30
+ context "when using the defaults" do
31
+
32
+ it "binds to port 80, with host 0.0.0.0, a path of '/'" do
33
+ Thin::Server.should_receive(:new).with('0.0.0.0', 80, an_instance_of(Rack::Builder))
34
+ Thrift::ThinHTTPServer.new(processor)
35
+ end
36
+
37
+ it 'creates a ThinHTTPServer::RackApplicationContext' do
38
+ Thrift::ThinHTTPServer::RackApplication.should_receive(:for).with("/", processor, an_instance_of(Thrift::BinaryProtocolFactory)).and_return(anything)
39
+ Thrift::ThinHTTPServer.new(processor)
40
+ end
41
+
42
+ it "uses the BinaryProtocolFactory" do
43
+ Thrift::BinaryProtocolFactory.should_receive(:new)
44
+ Thrift::ThinHTTPServer.new(processor)
45
+ end
46
+
47
+ end
48
+
49
+ context "when using the options" do
50
+
51
+ it 'accepts :ip, :port, :path' do
52
+ ip = "192.168.0.1"
53
+ port = 3000
54
+ path = "/thin"
55
+ Thin::Server.should_receive(:new).with(ip, port, an_instance_of(Rack::Builder))
56
+ Thrift::ThinHTTPServer.new(processor,
57
+ :ip => ip,
58
+ :port => port,
59
+ :path => path)
60
+ end
61
+
62
+ it 'creates a ThinHTTPServer::RackApplicationContext with a different protocol factory' do
63
+ Thrift::ThinHTTPServer::RackApplication.should_receive(:for).with("/", processor, an_instance_of(Thrift::JsonProtocolFactory)).and_return(anything)
64
+ Thrift::ThinHTTPServer.new(processor,
65
+ :protocol_factory => Thrift::JsonProtocolFactory.new)
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ describe "#serve" do
73
+
74
+ it 'starts the Thin server' do
75
+ underlying_thin_server = mock('thin server', :start => true)
76
+ Thin::Server.stub(:new).and_return(underlying_thin_server)
77
+
78
+ thin_thrift_server = Thrift::ThinHTTPServer.new(processor)
79
+
80
+ underlying_thin_server.should_receive(:start)
81
+ thin_thrift_server.serve
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ describe Thrift::ThinHTTPServer::RackApplication do
88
+ include Rack::Test::Methods
89
+
90
+ let(:processor) { mock('processor') }
91
+ let(:protocol_factory) { mock('protocol factory') }
92
+
93
+ def app
94
+ Thrift::ThinHTTPServer::RackApplication.for("/", processor, protocol_factory)
95
+ end
96
+
97
+ context "404 response" do
98
+
99
+ it 'receives a non-POST' do
100
+ header('Content-Type', "application/x-thrift")
101
+ get "/"
102
+ last_response.status.should be 404
103
+ end
104
+
105
+ it 'receives a header other than application/x-thrift' do
106
+ header('Content-Type', "application/json")
107
+ post "/"
108
+ last_response.status.should be 404
109
+ end
110
+
111
+ end
112
+
113
+ context "200 response" do
114
+
115
+ before do
116
+ protocol_factory.stub(:get_protocol)
117
+ processor.stub(:process)
118
+ end
119
+
120
+ it 'creates an IOStreamTransport' do
121
+ header('Content-Type', "application/x-thrift")
122
+ Thrift::IOStreamTransport.should_receive(:new).with(an_instance_of(Rack::Lint::InputWrapper), an_instance_of(Rack::Response))
123
+ post "/"
124
+ end
125
+
126
+ it 'fetches the right protocol based on the Transport' do
127
+ header('Content-Type', "application/x-thrift")
128
+ protocol_factory.should_receive(:get_protocol).with(an_instance_of(Thrift::IOStreamTransport))
129
+ post "/"
130
+ end
131
+
132
+ it 'status code 200' do
133
+ header('Content-Type', "application/x-thrift")
134
+ post "/"
135
+ last_response.ok?.should be_true
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+
@@ -0,0 +1,115 @@
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 Thrift::Types do
23
+
24
+ before(:each) do
25
+ Thrift.type_checking = true
26
+ end
27
+
28
+ after(:each) do
29
+ Thrift.type_checking = false
30
+ end
31
+
32
+ context 'type checking' do
33
+ it "should return the proper name for each type" do
34
+ Thrift.type_name(Thrift::Types::I16).should == "Types::I16"
35
+ Thrift.type_name(Thrift::Types::VOID).should == "Types::VOID"
36
+ Thrift.type_name(Thrift::Types::LIST).should == "Types::LIST"
37
+ Thrift.type_name(42).should be_nil
38
+ end
39
+
40
+ it "should check types properly" do
41
+ # lambda { Thrift.check_type(nil, Thrift::Types::STOP) }.should raise_error(Thrift::TypeError)
42
+ lambda { Thrift.check_type(3, {:type => Thrift::Types::STOP}, :foo) }.should raise_error(Thrift::TypeError)
43
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::VOID}, :foo) }.should_not raise_error(Thrift::TypeError)
44
+ lambda { Thrift.check_type(3, {:type => Thrift::Types::VOID}, :foo) }.should raise_error(Thrift::TypeError)
45
+ lambda { Thrift.check_type(true, {:type => Thrift::Types::BOOL}, :foo) }.should_not raise_error(Thrift::TypeError)
46
+ lambda { Thrift.check_type(3, {:type => Thrift::Types::BOOL}, :foo) }.should raise_error(Thrift::TypeError)
47
+ lambda { Thrift.check_type(42, {:type => Thrift::Types::BYTE}, :foo) }.should_not raise_error(Thrift::TypeError)
48
+ lambda { Thrift.check_type(42, {:type => Thrift::Types::I16}, :foo) }.should_not raise_error(Thrift::TypeError)
49
+ lambda { Thrift.check_type(42, {:type => Thrift::Types::I32}, :foo) }.should_not raise_error(Thrift::TypeError)
50
+ lambda { Thrift.check_type(42, {:type => Thrift::Types::I64}, :foo) }.should_not raise_error(Thrift::TypeError)
51
+ lambda { Thrift.check_type(3.14, {:type => Thrift::Types::I32}, :foo) }.should raise_error(Thrift::TypeError)
52
+ lambda { Thrift.check_type(3.14, {:type => Thrift::Types::DOUBLE}, :foo) }.should_not raise_error(Thrift::TypeError)
53
+ lambda { Thrift.check_type(3, {:type => Thrift::Types::DOUBLE}, :foo) }.should raise_error(Thrift::TypeError)
54
+ lambda { Thrift.check_type("3", {:type => Thrift::Types::STRING}, :foo) }.should_not raise_error(Thrift::TypeError)
55
+ lambda { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.should raise_error(Thrift::TypeError)
56
+ hello = SpecNamespace::Hello.new
57
+ lambda { Thrift.check_type(hello, {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}, :foo) }.should_not raise_error(Thrift::TypeError)
58
+ lambda { Thrift.check_type("foo", {:type => Thrift::Types::STRUCT}, :foo) }.should raise_error(Thrift::TypeError)
59
+ lambda { Thrift.check_type({:foo => 1}, {:type => Thrift::Types::MAP}, :foo) }.should_not raise_error(Thrift::TypeError)
60
+ lambda { Thrift.check_type([1], {:type => Thrift::Types::MAP}, :foo) }.should raise_error(Thrift::TypeError)
61
+ lambda { Thrift.check_type([1], {:type => Thrift::Types::LIST}, :foo) }.should_not raise_error(Thrift::TypeError)
62
+ lambda { Thrift.check_type({:foo => 1}, {:type => Thrift::Types::LIST}, :foo) }.should raise_error(Thrift::TypeError)
63
+ lambda { Thrift.check_type(Set.new([1,2]), {:type => Thrift::Types::SET}, :foo) }.should_not raise_error(Thrift::TypeError)
64
+ lambda { Thrift.check_type([1,2], {:type => Thrift::Types::SET}, :foo) }.should raise_error(Thrift::TypeError)
65
+ lambda { Thrift.check_type({:foo => true}, {:type => Thrift::Types::SET}, :foo) }.should raise_error(Thrift::TypeError)
66
+ end
67
+
68
+ it "should error out if nil is passed and skip_types is false" do
69
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::BOOL}, :foo, false) }.should raise_error(Thrift::TypeError)
70
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::BYTE}, :foo, false) }.should raise_error(Thrift::TypeError)
71
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::I16}, :foo, false) }.should raise_error(Thrift::TypeError)
72
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::I32}, :foo, false) }.should raise_error(Thrift::TypeError)
73
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::I64}, :foo, false) }.should raise_error(Thrift::TypeError)
74
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::DOUBLE}, :foo, false) }.should raise_error(Thrift::TypeError)
75
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::STRING}, :foo, false) }.should raise_error(Thrift::TypeError)
76
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::STRUCT}, :foo, false) }.should raise_error(Thrift::TypeError)
77
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::LIST}, :foo, false) }.should raise_error(Thrift::TypeError)
78
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::SET}, :foo, false) }.should raise_error(Thrift::TypeError)
79
+ lambda { Thrift.check_type(nil, {:type => Thrift::Types::MAP}, :foo, false) }.should raise_error(Thrift::TypeError)
80
+ end
81
+
82
+ it "should check element types on containers" do
83
+ field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::I32}}
84
+ lambda { Thrift.check_type([1, 2], field, :foo) }.should_not raise_error(Thrift::TypeError)
85
+ lambda { Thrift.check_type([1, nil, 2], field, :foo) }.should raise_error(Thrift::TypeError)
86
+ field = {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRING}}
87
+ lambda { Thrift.check_type({1 => "one", 2 => "two"}, field, :foo) }.should_not raise_error(Thrift::TypeError)
88
+ lambda { Thrift.check_type({1 => "one", nil => "nil"}, field, :foo) }.should raise_error(Thrift::TypeError)
89
+ lambda { Thrift.check_type({1 => nil, 2 => "two"}, field, :foo) }.should raise_error(Thrift::TypeError)
90
+ field = {:type => Thrift::Types::SET, :element => {:type => Thrift::Types::I32}}
91
+ lambda { Thrift.check_type(Set.new([1, 2]), field, :foo) }.should_not raise_error(Thrift::TypeError)
92
+ lambda { Thrift.check_type(Set.new([1, nil, 2]), field, :foo) }.should raise_error(Thrift::TypeError)
93
+ lambda { Thrift.check_type(Set.new([1, 2.3, 2]), field, :foo) }.should raise_error(Thrift::TypeError)
94
+
95
+ field = {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}
96
+ lambda { Thrift.check_type(SpecNamespace::BoolStruct, field, :foo) }.should raise_error(Thrift::TypeError)
97
+ end
98
+
99
+ it "should give the Thrift::TypeError a readable message" do
100
+ msg = "Expected Types::STRING, received Fixnum for field foo"
101
+ lambda { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.should raise_error(Thrift::TypeError, msg)
102
+ msg = "Expected Types::STRING, received Fixnum for field foo.element"
103
+ field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::STRING}}
104
+ lambda { Thrift.check_type([3], field, :foo) }.should raise_error(Thrift::TypeError, msg)
105
+ msg = "Expected Types::I32, received NilClass for field foo.element.key"
106
+ field = {:type => Thrift::Types::LIST,
107
+ :element => {:type => Thrift::Types::MAP,
108
+ :key => {:type => Thrift::Types::I32},
109
+ :value => {:type => Thrift::Types::I32}}}
110
+ lambda { Thrift.check_type([{nil => 3}], field, :foo) }.should raise_error(Thrift::TypeError, msg)
111
+ msg = "Expected Types::I32, received NilClass for field foo.element.value"
112
+ lambda { Thrift.check_type([{1 => nil}], field, :foo) }.should raise_error(Thrift::TypeError, msg)
113
+ end
114
+ end
115
+ end