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.
- data/CHANGELOG +2 -0
- data/COPYING +14 -0
- data/LICENSE +14 -0
- data/Makefile.am +15 -0
- data/Manifest +78 -0
- data/README +30 -0
- data/Rakefile +102 -0
- data/benchmark/Benchmark.thrift +5 -0
- data/benchmark/benchmark.rb +254 -0
- data/benchmark/client.rb +56 -0
- data/benchmark/gen-rb/BenchmarkService.rb +81 -0
- data/benchmark/gen-rb/Benchmark_constants.rb +11 -0
- data/benchmark/gen-rb/Benchmark_types.rb +10 -0
- data/benchmark/server.rb +64 -0
- data/benchmark/thin_server.rb +26 -0
- data/ext/binary_protocol_accelerated.c +463 -0
- data/ext/binary_protocol_accelerated.h +1 -0
- data/ext/constants.h +77 -0
- data/ext/extconf.rb +7 -0
- data/ext/memory_buffer.c +52 -0
- data/ext/memory_buffer.h +1 -0
- data/ext/protocol.c +166 -0
- data/ext/protocol.h +1 -0
- data/ext/struct.c +574 -0
- data/ext/struct.h +48 -0
- data/ext/thrift_native.c +173 -0
- data/lib/thrift/client.rb +44 -0
- data/lib/thrift/deprecation.rb +155 -0
- data/lib/thrift/exceptions.rb +65 -0
- data/lib/thrift/processor.rb +39 -0
- data/lib/thrift/protocol/binaryprotocol.rb +213 -0
- data/lib/thrift/protocol/binaryprotocolaccelerated.rb +19 -0
- data/lib/thrift/protocol/tbinaryprotocol.rb +2 -0
- data/lib/thrift/protocol/tprotocol.rb +2 -0
- data/lib/thrift/protocol.rb +270 -0
- data/lib/thrift/serializer.rb +27 -0
- data/lib/thrift/server/httpserver.rb +44 -0
- data/lib/thrift/server/nonblockingserver.rb +278 -0
- data/lib/thrift/server/thttpserver.rb +2 -0
- data/lib/thrift/server/tserver.rb +2 -0
- data/lib/thrift/server.rb +135 -0
- data/lib/thrift/struct.rb +272 -0
- data/lib/thrift/thrift.rb +14 -0
- data/lib/thrift/transport/httpclient.rb +29 -0
- data/lib/thrift/transport/socket.rb +167 -0
- data/lib/thrift/transport/thttpclient.rb +2 -0
- data/lib/thrift/transport/tsocket.rb +2 -0
- data/lib/thrift/transport/ttransport.rb +2 -0
- data/lib/thrift/transport/unixsocket.rb +58 -0
- data/lib/thrift/transport.rb +319 -0
- data/lib/thrift/types.rb +83 -0
- data/lib/thrift.rb +28 -0
- data/setup.rb +1585 -0
- data/spec/ThriftSpec.thrift +46 -0
- data/spec/backwards_compatibility_spec.rb +136 -0
- data/spec/binaryprotocol_spec.rb +45 -0
- data/spec/binaryprotocol_spec_shared.rb +274 -0
- data/spec/binaryprotocolaccelerated_spec.rb +101 -0
- data/spec/client_spec.rb +81 -0
- data/spec/deprecation_spec.rb +443 -0
- data/spec/exception_spec.rb +123 -0
- data/spec/gen-rb/NonblockingService.rb +268 -0
- data/spec/gen-rb/ThriftSpec_constants.rb +11 -0
- data/spec/gen-rb/ThriftSpec_types.rb +134 -0
- data/spec/httpclient_spec.rb +31 -0
- data/spec/httpserver_spec.rb +98 -0
- data/spec/nonblockingserver_spec.rb +245 -0
- data/spec/processor_spec.rb +64 -0
- data/spec/protocol_spec.rb +142 -0
- data/spec/serializer_spec.rb +52 -0
- data/spec/server_spec.rb +141 -0
- data/spec/socket_spec.rb +97 -0
- data/spec/socket_spec_shared.rb +85 -0
- data/spec/spec_helper.rb +35 -0
- data/spec/struct_spec.rb +244 -0
- data/spec/transport_spec.rb +359 -0
- data/spec/types_spec.rb +98 -0
- data/spec/unixsocket_spec.rb +90 -0
- data/thrift.gemspec +33 -0
- data.tar.gz.sig +0 -0
- metadata +200 -0
- metadata.gz.sig +0 -0
data/spec/socket_spec.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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"
|
data/spec/struct_spec.rb
ADDED
@@ -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
|