tiny_thrift 1.0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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