thrift 0.0.751142

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 (82) hide show
  1. data/CHANGELOG +2 -0
  2. data/COPYING +14 -0
  3. data/LICENSE +14 -0
  4. data/Makefile.am +15 -0
  5. data/Manifest +78 -0
  6. data/README +30 -0
  7. data/Rakefile +102 -0
  8. data/benchmark/Benchmark.thrift +5 -0
  9. data/benchmark/benchmark.rb +254 -0
  10. data/benchmark/client.rb +56 -0
  11. data/benchmark/gen-rb/BenchmarkService.rb +81 -0
  12. data/benchmark/gen-rb/Benchmark_constants.rb +11 -0
  13. data/benchmark/gen-rb/Benchmark_types.rb +10 -0
  14. data/benchmark/server.rb +64 -0
  15. data/benchmark/thin_server.rb +26 -0
  16. data/ext/binary_protocol_accelerated.c +463 -0
  17. data/ext/binary_protocol_accelerated.h +1 -0
  18. data/ext/constants.h +77 -0
  19. data/ext/extconf.rb +7 -0
  20. data/ext/memory_buffer.c +52 -0
  21. data/ext/memory_buffer.h +1 -0
  22. data/ext/protocol.c +166 -0
  23. data/ext/protocol.h +1 -0
  24. data/ext/struct.c +574 -0
  25. data/ext/struct.h +48 -0
  26. data/ext/thrift_native.c +173 -0
  27. data/lib/thrift/client.rb +44 -0
  28. data/lib/thrift/deprecation.rb +155 -0
  29. data/lib/thrift/exceptions.rb +65 -0
  30. data/lib/thrift/processor.rb +39 -0
  31. data/lib/thrift/protocol/binaryprotocol.rb +213 -0
  32. data/lib/thrift/protocol/binaryprotocolaccelerated.rb +19 -0
  33. data/lib/thrift/protocol/tbinaryprotocol.rb +2 -0
  34. data/lib/thrift/protocol/tprotocol.rb +2 -0
  35. data/lib/thrift/protocol.rb +270 -0
  36. data/lib/thrift/serializer.rb +27 -0
  37. data/lib/thrift/server/httpserver.rb +44 -0
  38. data/lib/thrift/server/nonblockingserver.rb +278 -0
  39. data/lib/thrift/server/thttpserver.rb +2 -0
  40. data/lib/thrift/server/tserver.rb +2 -0
  41. data/lib/thrift/server.rb +135 -0
  42. data/lib/thrift/struct.rb +272 -0
  43. data/lib/thrift/thrift.rb +14 -0
  44. data/lib/thrift/transport/httpclient.rb +29 -0
  45. data/lib/thrift/transport/socket.rb +167 -0
  46. data/lib/thrift/transport/thttpclient.rb +2 -0
  47. data/lib/thrift/transport/tsocket.rb +2 -0
  48. data/lib/thrift/transport/ttransport.rb +2 -0
  49. data/lib/thrift/transport/unixsocket.rb +58 -0
  50. data/lib/thrift/transport.rb +319 -0
  51. data/lib/thrift/types.rb +83 -0
  52. data/lib/thrift.rb +28 -0
  53. data/setup.rb +1585 -0
  54. data/spec/ThriftSpec.thrift +46 -0
  55. data/spec/backwards_compatibility_spec.rb +136 -0
  56. data/spec/binaryprotocol_spec.rb +45 -0
  57. data/spec/binaryprotocol_spec_shared.rb +274 -0
  58. data/spec/binaryprotocolaccelerated_spec.rb +101 -0
  59. data/spec/client_spec.rb +81 -0
  60. data/spec/deprecation_spec.rb +443 -0
  61. data/spec/exception_spec.rb +123 -0
  62. data/spec/gen-rb/NonblockingService.rb +268 -0
  63. data/spec/gen-rb/ThriftSpec_constants.rb +11 -0
  64. data/spec/gen-rb/ThriftSpec_types.rb +134 -0
  65. data/spec/httpclient_spec.rb +31 -0
  66. data/spec/httpserver_spec.rb +98 -0
  67. data/spec/nonblockingserver_spec.rb +245 -0
  68. data/spec/processor_spec.rb +64 -0
  69. data/spec/protocol_spec.rb +142 -0
  70. data/spec/serializer_spec.rb +52 -0
  71. data/spec/server_spec.rb +141 -0
  72. data/spec/socket_spec.rb +97 -0
  73. data/spec/socket_spec_shared.rb +85 -0
  74. data/spec/spec_helper.rb +35 -0
  75. data/spec/struct_spec.rb +244 -0
  76. data/spec/transport_spec.rb +359 -0
  77. data/spec/types_spec.rb +98 -0
  78. data/spec/unixsocket_spec.rb +90 -0
  79. data/thrift.gemspec +33 -0
  80. data.tar.gz.sig +0 -0
  81. metadata +200 -0
  82. metadata.gz.sig +0 -0
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + "/socket_spec_shared"
3
+
4
+ class ThriftSocketSpec < Spec::ExampleGroup
5
+ include Thrift
6
+
7
+ describe Socket do
8
+ before(:each) do
9
+ @socket = Socket.new
10
+ @handle = mock("Handle", :closed? => false)
11
+ @handle.stub!(:close)
12
+ @handle.stub!(:connect_nonblock)
13
+ ::Socket.stub!(:new).and_return(@handle)
14
+ end
15
+
16
+ it_should_behave_like "a socket"
17
+
18
+ it "should raise a TransportException when it cannot open a socket" do
19
+ ::Socket.should_receive(:new).and_raise(StandardError)
20
+ lambda { @socket.open }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN }
21
+ end
22
+
23
+ it "should open a ::Socket with default args" do
24
+ ::Socket.should_receive(:new).and_return(mock("Handle", :connect_nonblock => true))
25
+ ::Socket.should_receive(:getaddrinfo).with("localhost", 9090).and_return([[]])
26
+ ::Socket.should_receive(:sockaddr_in)
27
+ @socket.open
28
+ end
29
+
30
+ it "should accept host/port options" do
31
+ ::Socket.should_receive(:new).and_return(mock("Handle", :connect_nonblock => true))
32
+ ::Socket.should_receive(:getaddrinfo).with("my.domain", 1234).and_return([[]])
33
+ ::Socket.should_receive(:sockaddr_in)
34
+ Socket.new('my.domain', 1234).open
35
+ end
36
+
37
+ it "should accept an optional timeout" do
38
+ ::Socket.stub!(:new)
39
+ Socket.new('localhost', 8080, 5).timeout.should == 5
40
+ end
41
+ end
42
+
43
+ describe ServerSocket do
44
+ before(:each) do
45
+ @socket = ServerSocket.new(1234)
46
+ end
47
+
48
+ it "should create a handle when calling listen" do
49
+ TCPServer.should_receive(:new).with(nil, 1234)
50
+ @socket.listen
51
+ end
52
+
53
+ it "should accept an optional host argument" do
54
+ @socket = ServerSocket.new('localhost', 1234)
55
+ TCPServer.should_receive(:new).with('localhost', 1234)
56
+ @socket.listen
57
+ end
58
+
59
+ it "should create a Thrift::Socket to wrap accepted sockets" do
60
+ handle = mock("TCPServer")
61
+ TCPServer.should_receive(:new).with(nil, 1234).and_return(handle)
62
+ @socket.listen
63
+ sock = mock("sock")
64
+ handle.should_receive(:accept).and_return(sock)
65
+ trans = mock("Socket")
66
+ Socket.should_receive(:new).and_return(trans)
67
+ trans.should_receive(:handle=).with(sock)
68
+ @socket.accept.should == trans
69
+ end
70
+
71
+ it "should close the handle when closed" do
72
+ handle = mock("TCPServer", :closed? => false)
73
+ TCPServer.should_receive(:new).with(nil, 1234).and_return(handle)
74
+ @socket.listen
75
+ handle.should_receive(:close)
76
+ @socket.close
77
+ end
78
+
79
+ it "should return nil when accepting if there is no handle" do
80
+ @socket.accept.should be_nil
81
+ end
82
+
83
+ it "should return true for closed? when appropriate" do
84
+ handle = mock("TCPServer", :closed? => false)
85
+ TCPServer.stub!(:new).and_return(handle)
86
+ @socket.listen
87
+ @socket.should_not be_closed
88
+ handle.stub!(:close)
89
+ @socket.close
90
+ @socket.should be_closed
91
+ @socket.listen
92
+ @socket.should_not be_closed
93
+ handle.stub!(:closed?).and_return(true)
94
+ @socket.should be_closed
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ shared_examples_for "a socket" do
4
+ it "should open a socket" do
5
+ @socket.open.should == @handle
6
+ end
7
+
8
+ it "should be open whenever it has a handle" do
9
+ @socket.should_not be_open
10
+ @socket.open
11
+ @socket.should be_open
12
+ @socket.handle = nil
13
+ @socket.should_not be_open
14
+ @socket.handle = @handle
15
+ @socket.close
16
+ @socket.should_not be_open
17
+ end
18
+
19
+ it "should write data to the handle" do
20
+ @socket.open
21
+ @handle.should_receive(:write).with("foobar")
22
+ @socket.write("foobar")
23
+ @handle.should_receive(:write).with("fail").and_raise(StandardError)
24
+ lambda { @socket.write("fail") }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN }
25
+ end
26
+
27
+ it "should raise an error when it cannot read from the handle" do
28
+ @socket.open
29
+ @handle.should_receive(:readpartial).with(17).and_raise(StandardError)
30
+ lambda { @socket.read(17) }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::NOT_OPEN }
31
+ end
32
+
33
+ it "should return the data read when reading from the handle works" do
34
+ @socket.open
35
+ @handle.should_receive(:readpartial).with(17).and_return("test data")
36
+ @socket.read(17).should == "test data"
37
+ end
38
+
39
+ it "should declare itself as closed when it has an error" do
40
+ @socket.open
41
+ @handle.should_receive(:write).with("fail").and_raise(StandardError)
42
+ @socket.should be_open
43
+ lambda { @socket.write("fail") }.should raise_error
44
+ @socket.should_not be_open
45
+ end
46
+
47
+ it "should raise an error when the stream is closed" do
48
+ @socket.open
49
+ @handle.stub!(:closed?).and_return(true)
50
+ @socket.should_not be_open
51
+ lambda { @socket.write("fail") }.should raise_error(IOError, "closed stream")
52
+ lambda { @socket.read(10) }.should raise_error(IOError, "closed stream")
53
+ end
54
+
55
+ it "should support the timeout accessor for read" do
56
+ @socket.timeout = 3
57
+ @socket.open
58
+ IO.should_receive(:select).with([@handle], nil, nil, 3).and_return([[@handle], [], []])
59
+ @handle.should_receive(:readpartial).with(17).and_return("test data")
60
+ @socket.read(17).should == "test data"
61
+ end
62
+
63
+ it "should support the timeout accessor for write" do
64
+ @socket.timeout = 3
65
+ @socket.open
66
+ IO.should_receive(:select).with(nil, [@handle], nil, 3).twice.and_return([[], [@handle], []])
67
+ @handle.should_receive(:write_nonblock).with("test data").and_return(4)
68
+ @handle.should_receive(:write_nonblock).with(" data").and_return(5)
69
+ @socket.write("test data").should == 9
70
+ end
71
+
72
+ it "should raise an error when read times out" do
73
+ @socket.timeout = 0.5
74
+ @socket.open
75
+ IO.should_receive(:select).with([@handle], nil, nil, 0.5).at_least(1).times.and_return(nil)
76
+ lambda { @socket.read(17) }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::TIMED_OUT }
77
+ end
78
+
79
+ it "should raise an error when write times out" do
80
+ @socket.timeout = 0.5
81
+ @socket.open
82
+ IO.should_receive(:select).with(nil, [@handle], nil, 0.5).any_number_of_times.and_return(nil)
83
+ lambda { @socket.write("test data") }.should raise_error(Thrift::TransportException) { |e| e.type.should == Thrift::TransportException::TIMED_OUT }
84
+ end
85
+ end
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ # require at least 1.1.4 to fix a bug with describing Modules
3
+ gem 'rspec', '>= 1.1.4'
4
+ require 'spec'
5
+
6
+ $:.unshift File.join(File.dirname(__FILE__), *%w[.. ext])
7
+
8
+ # pretend we already loaded fastthread, otherwise the nonblockingserver_spec
9
+ # will get screwed up
10
+ # $" << 'fastthread.bundle'
11
+
12
+ # turn on deprecation so we can test it
13
+ module Thrift
14
+ # squelch any warnings if we happen to get required twice
15
+ remove_const(:DEPRECATION) if const_defined? :DEPRECATION
16
+ DEPRECATION = true
17
+ end
18
+
19
+ require File.dirname(__FILE__) + '/../lib/thrift'
20
+
21
+ class Object
22
+ # tee is a useful method, so let's let our tests have it
23
+ def tee(&block)
24
+ block.call(self)
25
+ self
26
+ end
27
+ end
28
+
29
+ Spec::Runner.configure do |configuration|
30
+ configuration.before(:each) do
31
+ Thrift.type_checking = true
32
+ end
33
+ end
34
+
35
+ require "thrift_native"
@@ -0,0 +1,244 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require File.dirname(__FILE__) + '/gen-rb/ThriftSpec_types'
3
+
4
+ # require "binaryprotocolaccelerated"
5
+
6
+ class ThriftStructSpec < Spec::ExampleGroup
7
+ include Thrift
8
+ include SpecNamespace
9
+
10
+ describe Struct do
11
+ it "should iterate over all fields properly" do
12
+ fields = {}
13
+ Foo.new.each_field { |fid,type,name,default,optional| fields[fid] = [type,name,default,optional] }
14
+ fields.should == {
15
+ 1 => [Types::I32, 'simple', 53, nil],
16
+ 2 => [Types::STRING, 'words', "words", nil],
17
+ 3 => [Types::STRUCT, 'hello', Hello.new(:greeting => 'hello, world!'), nil],
18
+ 4 => [Types::LIST, 'ints', [1, 2, 2, 3], nil],
19
+ 5 => [Types::MAP, 'complex', nil, nil],
20
+ 6 => [Types::SET, 'shorts', Set.new([5, 17, 239]), nil],
21
+ 7 => [Types::STRING, 'opt_string', nil, true]
22
+ }
23
+ end
24
+
25
+ it "should initialize all fields to defaults" do
26
+ struct = Foo.new
27
+ struct.simple.should == 53
28
+ struct.words.should == "words"
29
+ struct.hello.should == Hello.new(:greeting => 'hello, world!')
30
+ struct.ints.should == [1, 2, 2, 3]
31
+ struct.complex.should be_nil
32
+ struct.shorts.should == Set.new([5, 17, 239])
33
+ end
34
+
35
+ it "should not share default values between instances" do
36
+ begin
37
+ struct = Foo.new
38
+ struct.ints << 17
39
+ Foo.new.ints.should == [1,2,2,3]
40
+ ensure
41
+ # ensure no leakage to other tests
42
+ Foo::FIELDS[4][:default] = [1,2,2,3]
43
+ end
44
+ end
45
+
46
+ it "should properly initialize boolean values" do
47
+ struct = BoolStruct.new(:yesno => false)
48
+ struct.yesno.should be_false
49
+ end
50
+
51
+ it "should have proper == semantics" do
52
+ Foo.new.should_not == Hello.new
53
+ Foo.new.should == Foo.new
54
+ Foo.new(:simple => 52).should_not == Foo.new
55
+ end
56
+
57
+ it "should read itself off the wire" do
58
+ struct = Foo.new
59
+ prot = Protocol.new(mock("transport"))
60
+ prot.should_receive(:read_struct_begin).twice
61
+ prot.should_receive(:read_struct_end).twice
62
+ prot.should_receive(:read_field_begin).and_return(
63
+ ['complex', Types::MAP, 5], # Foo
64
+ ['words', Types::STRING, 2], # Foo
65
+ ['hello', Types::STRUCT, 3], # Foo
66
+ ['greeting', Types::STRING, 1], # Hello
67
+ [nil, Types::STOP, 0], # Hello
68
+ ['simple', Types::I32, 1], # Foo
69
+ ['ints', Types::LIST, 4], # Foo
70
+ ['shorts', Types::SET, 6], # Foo
71
+ [nil, Types::STOP, 0] # Hello
72
+ )
73
+ prot.should_receive(:read_field_end).exactly(7).times
74
+ prot.should_receive(:read_map_begin).and_return(
75
+ [Types::I32, Types::MAP, 2], # complex
76
+ [Types::STRING, Types::DOUBLE, 2], # complex/1/value
77
+ [Types::STRING, Types::DOUBLE, 1] # complex/2/value
78
+ )
79
+ prot.should_receive(:read_map_end).exactly(3).times
80
+ prot.should_receive(:read_list_begin).and_return([Types::I32, 4])
81
+ prot.should_receive(:read_list_end)
82
+ prot.should_receive(:read_set_begin).and_return([Types::I16, 2])
83
+ prot.should_receive(:read_set_end)
84
+ prot.should_receive(:read_i32).and_return(
85
+ 1, 14, # complex keys
86
+ 42, # simple
87
+ 4, 23, 4, 29 # ints
88
+ )
89
+ prot.should_receive(:read_string).and_return("pi", "e", "feigenbaum", "apple banana", "what's up?")
90
+ prot.should_receive(:read_double).and_return(Math::PI, Math::E, 4.669201609)
91
+ prot.should_receive(:read_i16).and_return(2, 3)
92
+ prot.should_not_receive(:skip)
93
+ struct.read(prot)
94
+
95
+ struct.simple.should == 42
96
+ struct.complex.should == {1 => {"pi" => Math::PI, "e" => Math::E}, 14 => {"feigenbaum" => 4.669201609}}
97
+ struct.hello.should == Hello.new(:greeting => "what's up?")
98
+ struct.words.should == "apple banana"
99
+ struct.ints.should == [4, 23, 4, 29]
100
+ struct.shorts.should == Set.new([3, 2])
101
+ end
102
+
103
+ it "should skip unexpected fields in structs and use default values" do
104
+ struct = Foo.new
105
+ prot = Protocol.new(mock("transport"))
106
+ prot.should_receive(:read_struct_begin)
107
+ prot.should_receive(:read_struct_end)
108
+ prot.should_receive(:read_field_begin).and_return(
109
+ ['simple', Types::I32, 1],
110
+ ['complex', Types::STRUCT, 5],
111
+ ['thinz', Types::MAP, 7],
112
+ ['foobar', Types::I32, 3],
113
+ ['words', Types::STRING, 2],
114
+ [nil, Types::STOP, 0]
115
+ )
116
+ prot.should_receive(:read_field_end).exactly(5).times
117
+ prot.should_receive(:read_i32).and_return(42)
118
+ prot.should_receive(:read_string).and_return("foobar")
119
+ prot.should_receive(:skip).with(Types::STRUCT)
120
+ prot.should_receive(:skip).with(Types::MAP)
121
+ # prot.should_receive(:read_map_begin).and_return([Types::I32, Types::I32, 0])
122
+ # prot.should_receive(:read_map_end)
123
+ prot.should_receive(:skip).with(Types::I32)
124
+ struct.read(prot)
125
+
126
+ struct.simple.should == 42
127
+ struct.complex.should be_nil
128
+ struct.words.should == "foobar"
129
+ struct.hello.should == Hello.new(:greeting => 'hello, world!')
130
+ struct.ints.should == [1, 2, 2, 3]
131
+ struct.shorts.should == Set.new([5, 17, 239])
132
+ end
133
+
134
+ it "should write itself to the wire" do
135
+ prot = Protocol.new(mock("transport")) #mock("Protocol")
136
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Foo")
137
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Hello")
138
+ prot.should_receive(:write_struct_end).twice
139
+ prot.should_receive(:write_field_begin).with('ints', Types::LIST, 4)
140
+ prot.should_receive(:write_i32).with(1)
141
+ prot.should_receive(:write_i32).with(2).twice
142
+ prot.should_receive(:write_i32).with(3)
143
+ prot.should_receive(:write_field_begin).with('complex', Types::MAP, 5)
144
+ prot.should_receive(:write_i32).with(5)
145
+ prot.should_receive(:write_string).with('foo')
146
+ prot.should_receive(:write_double).with(1.23)
147
+ prot.should_receive(:write_field_begin).with('shorts', Types::SET, 6)
148
+ prot.should_receive(:write_i16).with(5)
149
+ prot.should_receive(:write_i16).with(17)
150
+ prot.should_receive(:write_i16).with(239)
151
+ prot.should_receive(:write_field_stop).twice
152
+ prot.should_receive(:write_field_end).exactly(6).times
153
+ prot.should_receive(:write_field_begin).with('simple', Types::I32, 1)
154
+ prot.should_receive(:write_i32).with(53)
155
+ prot.should_receive(:write_field_begin).with('hello', Types::STRUCT, 3)
156
+ prot.should_receive(:write_field_begin).with('greeting', Types::STRING, 1)
157
+ prot.should_receive(:write_string).with('hello, world!')
158
+ prot.should_receive(:write_map_begin).with(Types::I32, Types::MAP, 1)
159
+ prot.should_receive(:write_map_begin).with(Types::STRING, Types::DOUBLE, 1)
160
+ prot.should_receive(:write_map_end).twice
161
+ prot.should_receive(:write_list_begin).with(Types::I32, 4)
162
+ prot.should_receive(:write_list_end)
163
+ prot.should_receive(:write_set_begin).with(Types::I16, 3)
164
+ prot.should_receive(:write_set_end)
165
+
166
+ struct = Foo.new
167
+ struct.words = nil
168
+ struct.complex = {5 => {"foo" => 1.23}}
169
+ struct.write(prot)
170
+ end
171
+
172
+ it "should raise an exception if presented with an unknown container" do
173
+ # yeah this is silly, but I'm going for code coverage here
174
+ struct = Foo.new
175
+ lambda { struct.send :write_container, nil, nil, {:type => "foo"} }.should raise_error(StandardError, "Not a container type: foo")
176
+ end
177
+
178
+ it "should support optional type-checking in Thrift::Struct.new" do
179
+ Thrift.type_checking = true
180
+ begin
181
+ lambda { Hello.new(:greeting => 3) }.should raise_error(TypeError, "Expected Types::STRING, received Fixnum for field greeting")
182
+ ensure
183
+ Thrift.type_checking = false
184
+ end
185
+ lambda { Hello.new(:greeting => 3) }.should_not raise_error(TypeError)
186
+ end
187
+
188
+ it "should support optional type-checking in field accessors" do
189
+ Thrift.type_checking = true
190
+ begin
191
+ hello = Hello.new
192
+ lambda { hello.greeting = 3 }.should raise_error(TypeError, "Expected Types::STRING, received Fixnum for field greeting")
193
+ ensure
194
+ Thrift.type_checking = false
195
+ end
196
+ lambda { hello.greeting = 3 }.should_not raise_error(TypeError)
197
+ end
198
+
199
+ it "should raise an exception when unknown types are given to Thrift::Struct.new" do
200
+ lambda { Hello.new(:fish => 'salmon') }.should raise_error(Exception, "Unknown key given to SpecNamespace::Hello.new: fish")
201
+ end
202
+
203
+ it "should support `raise Xception, 'message'` for Exception structs" do
204
+ begin
205
+ raise Xception, "something happened"
206
+ rescue Thrift::Exception => e
207
+ e.message.should == "something happened"
208
+ e.code.should == 1
209
+ # ensure it gets serialized properly, this is the really important part
210
+ prot = Protocol.new(mock("trans"))
211
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
212
+ prot.should_receive(:write_struct_end)
213
+ prot.should_receive(:write_field_begin).with('message', Types::STRING, 1)#, "something happened")
214
+ prot.should_receive(:write_string).with("something happened")
215
+ prot.should_receive(:write_field_begin).with('code', Types::I32, 2)#, 1)
216
+ prot.should_receive(:write_i32).with(1)
217
+ prot.should_receive(:write_field_stop)
218
+ prot.should_receive(:write_field_end).twice
219
+
220
+ e.write(prot)
221
+ end
222
+ end
223
+
224
+ it "should support the regular initializer for exception structs" do
225
+ begin
226
+ raise Xception, :message => "something happened", :code => 5
227
+ rescue Thrift::Exception => e
228
+ e.message.should == "something happened"
229
+ e.code.should == 5
230
+ prot = Protocol.new(mock("trans"))
231
+ prot.should_receive(:write_struct_begin).with("SpecNamespace::Xception")
232
+ prot.should_receive(:write_struct_end)
233
+ prot.should_receive(:write_field_begin).with('message', Types::STRING, 1)
234
+ prot.should_receive(:write_string).with("something happened")
235
+ prot.should_receive(:write_field_begin).with('code', Types::I32, 2)
236
+ prot.should_receive(:write_i32).with(5)
237
+ prot.should_receive(:write_field_stop)
238
+ prot.should_receive(:write_field_end).twice
239
+
240
+ e.write(prot)
241
+ end
242
+ end
243
+ end
244
+ end