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
@@ -0,0 +1,46 @@
|
|
1
|
+
namespace rb SpecNamespace
|
2
|
+
|
3
|
+
struct Hello {
|
4
|
+
1: string greeting = "hello world"
|
5
|
+
}
|
6
|
+
|
7
|
+
struct Foo {
|
8
|
+
1: i32 simple = 53,
|
9
|
+
2: string words = "words",
|
10
|
+
3: Hello hello = {'greeting' : "hello, world!"},
|
11
|
+
4: list<i32> ints = [1, 2, 2, 3],
|
12
|
+
5: map<i32, map<string, double>> complex,
|
13
|
+
6: set<i16> shorts = [5, 17, 239],
|
14
|
+
7: optional string opt_string
|
15
|
+
}
|
16
|
+
|
17
|
+
struct BoolStruct {
|
18
|
+
1: bool yesno = 1
|
19
|
+
}
|
20
|
+
|
21
|
+
struct SimpleList {
|
22
|
+
1: list<bool> bools,
|
23
|
+
2: list<byte> bytes,
|
24
|
+
3: list<i16> i16s,
|
25
|
+
4: list<i32> i32s,
|
26
|
+
5: list<i64> i64s,
|
27
|
+
6: list<double> doubles,
|
28
|
+
7: list<string> strings,
|
29
|
+
8: list<map<i16, i16>> maps,
|
30
|
+
9: list<list<i16>> lists,
|
31
|
+
10: list<set<i16>> sets,
|
32
|
+
11: list<Hello> hellos
|
33
|
+
}
|
34
|
+
|
35
|
+
exception Xception {
|
36
|
+
1: string message,
|
37
|
+
2: i32 code = 1
|
38
|
+
}
|
39
|
+
|
40
|
+
service NonblockingService {
|
41
|
+
Hello greeting(1:bool english)
|
42
|
+
bool block()
|
43
|
+
async void unblock(1:i32 n)
|
44
|
+
async void shutdown()
|
45
|
+
void sleep(1:double seconds)
|
46
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'thrift/protocol/binaryprotocol'
|
3
|
+
require 'thrift/server/httpserver'
|
4
|
+
require 'thrift/transport/httpclient'
|
5
|
+
|
6
|
+
context "Backwards compatibility" do
|
7
|
+
specify "old class names should map to new classes" do
|
8
|
+
Thrift::DeprecationProxy.reset_deprecation_warnings
|
9
|
+
# use an Array because a Hash will call #hash and trigger deprecation warnings
|
10
|
+
klasses = [
|
11
|
+
[:module, :ThriftClient, Thrift::Client],
|
12
|
+
[:class, :TException, Thrift::Exception],
|
13
|
+
[:class, :TApplicationException, Thrift::ApplicationException],
|
14
|
+
[:module, :TProcessor, Thrift::Processor],
|
15
|
+
[:class, :TProtocolException, Thrift::ProtocolException],
|
16
|
+
[:class, :TProtocol, Thrift::Protocol],
|
17
|
+
[:class, :TProtocolFactory, Thrift::ProtocolFactory],
|
18
|
+
[:class, :TBinaryProtocol, Thrift::BinaryProtocol],
|
19
|
+
[:class, :TBinaryProtocolFactory, Thrift::BinaryProtocolFactory],
|
20
|
+
[:class, :TSimpleMongrelHTTPServer, Thrift::SimpleMongrelHTTPServer],
|
21
|
+
[:class, :TServer, Thrift::Server],
|
22
|
+
[:class, :TSimpleServer, Thrift::SimpleServer],
|
23
|
+
[:class, :TThreadedServer, Thrift::ThreadedServer],
|
24
|
+
[:class, :TThreadPoolServer, Thrift::ThreadPoolServer],
|
25
|
+
[:module, :ThriftStruct, Thrift::Struct],
|
26
|
+
[:class, :THttpClient, Thrift::HTTPClient],
|
27
|
+
[:class, :TSocket, Thrift::Socket],
|
28
|
+
[:class, :TServerSocket, Thrift::ServerSocket],
|
29
|
+
[:class, :TTransportException, Thrift::TransportException],
|
30
|
+
[:class, :TTransport, Thrift::Transport],
|
31
|
+
[:class, :TServerTransport, Thrift::ServerTransport],
|
32
|
+
[:class, :TTransportFactory, Thrift::TransportFactory],
|
33
|
+
[:class, :TBufferedTransport, Thrift::BufferedTransport],
|
34
|
+
[:class, :TBufferedTransportFactory, Thrift::BufferedTransportFactory],
|
35
|
+
[:class, :TFramedTransport, Thrift::FramedTransport],
|
36
|
+
[:class, :TFramedTransportFactory, Thrift::FramedTransportFactory],
|
37
|
+
[:class, :TMemoryBuffer, Thrift::MemoryBuffer],
|
38
|
+
[:class, :TIOStreamTransport, Thrift::IOStreamTransport],
|
39
|
+
[:module, :TType, Thrift::Types],
|
40
|
+
[:module, :TMessageType, Thrift::MessageTypes]
|
41
|
+
]
|
42
|
+
klasses.each do |(type, oldname, newklass)|
|
43
|
+
oldklass = Object.const_get(oldname)
|
44
|
+
STDERR.should_receive(:puts).with("Warning: #{type} #{oldname} is deprecated").ordered
|
45
|
+
STDERR.should_receive(:puts).with(" from #{__FILE__}:#{__LINE__+1}").ordered
|
46
|
+
oldklass.should eql(newklass)
|
47
|
+
STDERR.rspec_verify
|
48
|
+
STDERR.rspec_reset
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
specify "old method names should map to new method names" do
|
53
|
+
mapping = {
|
54
|
+
Thrift::Protocol => {
|
55
|
+
:writeMessageBegin => :write_message_begin,
|
56
|
+
:writeMessageEnd => :write_message_end,
|
57
|
+
:writeStructBegin => :write_struct_begin,
|
58
|
+
:writeStructEnd => :write_struct_end,
|
59
|
+
:writeFieldBegin => :write_field_begin,
|
60
|
+
:writeFieldEnd => :write_field_end,
|
61
|
+
:writeFieldStop => :write_field_stop,
|
62
|
+
:writeMapBegin => :write_map_begin,
|
63
|
+
:writeMapEnd => :write_map_end,
|
64
|
+
:writeListBegin => :write_list_begin,
|
65
|
+
:writeListEnd => :write_list_end,
|
66
|
+
:writeSetBegin => :write_set_begin,
|
67
|
+
:writeSetEnd => :write_set_end,
|
68
|
+
:writeBool => :write_bool,
|
69
|
+
:writeByte => :write_byte,
|
70
|
+
:writeI16 => :write_i16,
|
71
|
+
:writeI32 => :write_i32,
|
72
|
+
:writeI64 => :write_i64,
|
73
|
+
:writeDouble => :write_double,
|
74
|
+
:writeString => :write_string,
|
75
|
+
:readMessageBegin => :read_message_begin,
|
76
|
+
:readMessageEnd => :read_message_end,
|
77
|
+
:readStructBegin => :read_struct_begin,
|
78
|
+
:readStructEnd => :read_struct_end,
|
79
|
+
:readFieldBegin => :read_field_begin,
|
80
|
+
:readFieldEnd => :read_field_end,
|
81
|
+
:readMapBegin => :read_map_begin,
|
82
|
+
:readMapEnd => :read_map_end,
|
83
|
+
:readListBegin => :read_list_begin,
|
84
|
+
:readListEnd => :read_list_end,
|
85
|
+
:readSetBegin => :read_set_begin,
|
86
|
+
:readSetEnd => :read_set_end,
|
87
|
+
:readBool => :read_bool,
|
88
|
+
:readByte => :read_byte,
|
89
|
+
:readI16 => :read_i16,
|
90
|
+
:readI32 => :read_i32,
|
91
|
+
:readI64 => :read_i64,
|
92
|
+
:readDouble => :read_double,
|
93
|
+
:readString => :read_string
|
94
|
+
},
|
95
|
+
Thrift::ProtocolFactory => {
|
96
|
+
:getProtocol => :get_protocol
|
97
|
+
},
|
98
|
+
Thrift::Transport => {
|
99
|
+
:isOpen => :open?,
|
100
|
+
:is_open? => :open?,
|
101
|
+
:readAll => :read_all
|
102
|
+
},
|
103
|
+
Thrift::TransportFactory => {
|
104
|
+
:getTransport => :get_transport
|
105
|
+
}
|
106
|
+
}
|
107
|
+
STDERR.stub!(:puts) # stub the deprecation warnings
|
108
|
+
mapping.each_pair do |klass, methods|
|
109
|
+
# save these so they can be used after being mocked up
|
110
|
+
defn_method = klass.method(:define_method)
|
111
|
+
inst_method = klass.method(:instance_method)
|
112
|
+
methods.each_pair do |oldmeth, newmeth|
|
113
|
+
# ensure that calling the old method will call the new method
|
114
|
+
# and then redefine the old method to be the new one
|
115
|
+
klass.should be_method_defined(oldmeth)
|
116
|
+
klass.should be_method_defined(newmeth)
|
117
|
+
orig_method = inst_method.call(:initialize)
|
118
|
+
defn_method.call(:initialize, proc {} ) # stub out initialize
|
119
|
+
begin
|
120
|
+
mockmeth = mock("UnboundMethod: #{newmeth}")
|
121
|
+
mockmeth.should_receive(:bind).and_return do
|
122
|
+
mock("Method: #{newmeth}").tee do |meth|
|
123
|
+
meth.should_receive(:call)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
klass.should_receive(:instance_method).with(newmeth).twice.and_return(mockmeth)
|
127
|
+
klass.should_receive(:define_method).with(oldmeth, mockmeth)
|
128
|
+
klass.new.send oldmeth
|
129
|
+
klass.rspec_verify
|
130
|
+
ensure
|
131
|
+
defn_method.call(:initialize, orig_method)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'thrift/protocol/binaryprotocol'
|
3
|
+
require File.dirname(__FILE__) + '/binaryprotocol_spec_shared'
|
4
|
+
|
5
|
+
class ThriftBinaryProtocolSpec < Spec::ExampleGroup
|
6
|
+
include Thrift
|
7
|
+
|
8
|
+
describe BinaryProtocol do
|
9
|
+
it_should_behave_like 'a binary protocol'
|
10
|
+
|
11
|
+
def protocol_class
|
12
|
+
BinaryProtocol
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should read a message header" do
|
16
|
+
@trans.should_receive(:read_all).exactly(2).times.and_return(
|
17
|
+
[protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::REPLY].pack('N'),
|
18
|
+
[42].pack('N')
|
19
|
+
)
|
20
|
+
@prot.should_receive(:read_string).and_return('testMessage')
|
21
|
+
@prot.read_message_begin.should == ['testMessage', Thrift::MessageTypes::REPLY, 42]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should raise an exception if the message header has the wrong version" do
|
25
|
+
@prot.should_receive(:read_i32).and_return(-1)
|
26
|
+
lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e|
|
27
|
+
e.type == Thrift::ProtocolException::BAD_VERSION
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should raise an exception if the message header does not exist and strict_read is enabled" do
|
32
|
+
@prot.should_receive(:read_i32).and_return(42)
|
33
|
+
@prot.should_receive(:strict_read).and_return(true)
|
34
|
+
lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'No version identifier, old protocol client?') do |e|
|
35
|
+
e.type == Thrift::ProtocolException::BAD_VERSION
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe BinaryProtocolFactory do
|
41
|
+
it "should create a BinaryProtocol" do
|
42
|
+
BinaryProtocolFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(BinaryProtocol)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for 'a binary protocol' do
|
4
|
+
before(:each) do
|
5
|
+
@trans = Thrift::MemoryBuffer.new
|
6
|
+
@prot = protocol_class.new(@trans)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should define the proper VERSION_1, VERSION_MASK AND TYPE_MASK" do
|
10
|
+
protocol_class.const_get(:VERSION_MASK).should == 0xffff0000
|
11
|
+
protocol_class.const_get(:VERSION_1).should == 0x80010000
|
12
|
+
protocol_class.const_get(:TYPE_MASK).should == 0x000000ff
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should make strict_read readable" do
|
16
|
+
@prot.strict_read.should eql(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should make strict_write readable" do
|
20
|
+
@prot.strict_write.should eql(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should write the message header" do
|
24
|
+
@prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
|
25
|
+
@trans.read(1000).should == [protocol_class.const_get(:VERSION_1) | Thrift::MessageTypes::CALL, "testMessage".size, "testMessage", 17].pack("NNa11N")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should write the message header without version when writes are not strict" do
|
29
|
+
@prot = protocol_class.new(@trans, true, false) # no strict write
|
30
|
+
@prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
|
31
|
+
@trans.read(1000).should == "\000\000\000\vtestMessage\001\000\000\000\021"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should write the message header with a version when writes are strict" do
|
35
|
+
@prot = protocol_class.new(@trans) # strict write
|
36
|
+
@prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 17)
|
37
|
+
@trans.read(1000).should == "\200\001\000\001\000\000\000\vtestMessage\000\000\000\021"
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# message footer is a noop
|
42
|
+
|
43
|
+
it "should write the field header" do
|
44
|
+
@prot.write_field_begin('foo', Thrift::Types::DOUBLE, 3)
|
45
|
+
@trans.read(1000).should == [Thrift::Types::DOUBLE, 3].pack("cn")
|
46
|
+
end
|
47
|
+
|
48
|
+
# field footer is a noop
|
49
|
+
|
50
|
+
it "should write the STOP field" do
|
51
|
+
@prot.write_field_stop
|
52
|
+
@trans.read(1).should == "\000"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should write the map header" do
|
56
|
+
@prot.write_map_begin(Thrift::Types::STRING, Thrift::Types::LIST, 17)
|
57
|
+
@trans.read(1000).should == [Thrift::Types::STRING, Thrift::Types::LIST, 17].pack("ccN");
|
58
|
+
end
|
59
|
+
|
60
|
+
# map footer is a noop
|
61
|
+
|
62
|
+
it "should write the list header" do
|
63
|
+
@prot.write_list_begin(Thrift::Types::I16, 42)
|
64
|
+
@trans.read(1000).should == [Thrift::Types::I16, 42].pack("cN")
|
65
|
+
end
|
66
|
+
|
67
|
+
# list footer is a noop
|
68
|
+
|
69
|
+
it "should write the set header" do
|
70
|
+
@prot.write_set_begin(Thrift::Types::I16, 42)
|
71
|
+
@trans.read(1000).should == [Thrift::Types::I16, 42].pack("cN")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should write a bool" do
|
75
|
+
@prot.write_bool(true)
|
76
|
+
@prot.write_bool(false)
|
77
|
+
@trans.read(1000).should == "\001\000"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should treat a nil bool as false" do
|
81
|
+
@prot.write_bool(nil)
|
82
|
+
@trans.read(1).should == "\000"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should write a byte" do
|
86
|
+
# byte is small enough, let's check -128..127
|
87
|
+
(-128..127).each do |i|
|
88
|
+
@prot.write_byte(i)
|
89
|
+
@trans.read(1).should == [i].pack('c')
|
90
|
+
end
|
91
|
+
(-128..127).each do |i|
|
92
|
+
end
|
93
|
+
# handing it numbers out of signed range should clip
|
94
|
+
@trans.rspec_verify
|
95
|
+
(128..255).each do |i|
|
96
|
+
@prot.write_byte(i)
|
97
|
+
@trans.read(1).should == [i].pack('c')
|
98
|
+
end
|
99
|
+
# and lastly, a Bignum is going to error out
|
100
|
+
lambda { @prot.write_byte(2**65) }.should raise_error(RangeError)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should error gracefully when trying to write a nil byte" do
|
104
|
+
lambda { @prot.write_byte(nil) }.should raise_error
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should write an i16" do
|
108
|
+
# try a random scattering of values
|
109
|
+
# include the signed i16 minimum/maximum
|
110
|
+
[-2**15, -1024, 17, 0, -10000, 1723, 2**15-1].each do |i|
|
111
|
+
@prot.write_i16(i)
|
112
|
+
end
|
113
|
+
# and try something out of signed range, it should clip
|
114
|
+
@prot.write_i16(2**15 + 5)
|
115
|
+
|
116
|
+
@trans.read(1000).should == "\200\000\374\000\000\021\000\000\330\360\006\273\177\377\200\005"
|
117
|
+
|
118
|
+
# a Bignum should error
|
119
|
+
# lambda { @prot.write_i16(2**65) }.should raise_error(RangeError)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should error gracefully when trying to write a nil i16" do
|
123
|
+
lambda { @prot.write_i16(nil) }.should raise_error
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should write an i32" do
|
127
|
+
# try a random scattering of values
|
128
|
+
# include the signed i32 minimum/maximum
|
129
|
+
[-2**31, -123123, -2532, -3, 0, 2351235, 12331, 2**31-1].each do |i|
|
130
|
+
@prot.write_i32(i)
|
131
|
+
end
|
132
|
+
# try something out of signed range, it should clip
|
133
|
+
@trans.read(1000).should == "\200\000\000\000" + "\377\376\037\r" + "\377\377\366\034" + "\377\377\377\375" + "\000\000\000\000" + "\000#\340\203" + "\000\0000+" + "\177\377\377\377"
|
134
|
+
[2 ** 31 + 5, 2 ** 65 + 5].each do |i|
|
135
|
+
lambda { @prot.write_i32(i) }.should raise_error(RangeError)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should error gracefully when trying to write a nil i32" do
|
140
|
+
lambda { @prot.write_i32(nil) }.should raise_error
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should write an i64" do
|
144
|
+
# try a random scattering of values
|
145
|
+
# try the signed i64 minimum/maximum
|
146
|
+
[-2**63, -12356123612323, -23512351, -234, 0, 1231, 2351236, 12361236213, 2**63-1].each do |i|
|
147
|
+
@prot.write_i64(i)
|
148
|
+
end
|
149
|
+
# try something out of signed range, it should clip
|
150
|
+
@trans.read(1000).should == ["\200\000\000\000\000\000\000\000",
|
151
|
+
"\377\377\364\303\035\244+]",
|
152
|
+
"\377\377\377\377\376\231:\341",
|
153
|
+
"\377\377\377\377\377\377\377\026",
|
154
|
+
"\000\000\000\000\000\000\000\000",
|
155
|
+
"\000\000\000\000\000\000\004\317",
|
156
|
+
"\000\000\000\000\000#\340\204",
|
157
|
+
"\000\000\000\002\340\311~\365",
|
158
|
+
"\177\377\377\377\377\377\377\377"].join("")
|
159
|
+
lambda { @prot.write_i64(2 ** 65 + 5) }.should raise_error(RangeError)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should error gracefully when trying to write a nil i64" do
|
163
|
+
lambda { @prot.write_i64(nil) }.should raise_error
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should write a double" do
|
167
|
+
# try a random scattering of values, including min/max
|
168
|
+
values = [Float::MIN,-1231.15325, -123123.23, -23.23515123, 0, 12351.1325, 523.23, Float::MAX]
|
169
|
+
values.each do |f|
|
170
|
+
@prot.write_double(f)
|
171
|
+
@trans.read(1000).should == [f].pack("G")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should error gracefully when trying to write a nil double" do
|
176
|
+
lambda { @prot.write_double(nil) }.should raise_error
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should write a string" do
|
180
|
+
str = "hello world"
|
181
|
+
@prot.write_string(str)
|
182
|
+
@trans.read(1000).should == [str.size].pack("N") + str
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should error gracefully when trying to write a nil string" do
|
186
|
+
lambda { @prot.write_string(nil) }.should raise_error
|
187
|
+
end
|
188
|
+
|
189
|
+
# message footer is a noop
|
190
|
+
|
191
|
+
it "should read a field header" do
|
192
|
+
@trans.write([Thrift::Types::STRING, 3].pack("cn"))
|
193
|
+
@prot.read_field_begin.should == [nil, Thrift::Types::STRING, 3]
|
194
|
+
end
|
195
|
+
|
196
|
+
# field footer is a noop
|
197
|
+
|
198
|
+
it "should read a stop field" do
|
199
|
+
@trans.write([Thrift::Types::STOP].pack("c"));
|
200
|
+
@prot.read_field_begin.should == [nil, Thrift::Types::STOP, 0]
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should read a map header" do
|
204
|
+
@trans.write([Thrift::Types::DOUBLE, Thrift::Types::I64, 42].pack("ccN"))
|
205
|
+
@prot.read_map_begin.should == [Thrift::Types::DOUBLE, Thrift::Types::I64, 42]
|
206
|
+
end
|
207
|
+
|
208
|
+
# map footer is a noop
|
209
|
+
|
210
|
+
it "should read a list header" do
|
211
|
+
@trans.write([Thrift::Types::STRING, 17].pack("cN"))
|
212
|
+
@prot.read_list_begin.should == [Thrift::Types::STRING, 17]
|
213
|
+
end
|
214
|
+
|
215
|
+
# list footer is a noop
|
216
|
+
|
217
|
+
it "should read a set header" do
|
218
|
+
@trans.write([Thrift::Types::STRING, 17].pack("cN"))
|
219
|
+
@prot.read_set_begin.should == [Thrift::Types::STRING, 17]
|
220
|
+
end
|
221
|
+
|
222
|
+
# set footer is a noop
|
223
|
+
|
224
|
+
it "should read a bool" do
|
225
|
+
@trans.write("\001\000");
|
226
|
+
@prot.read_bool.should == true
|
227
|
+
@prot.read_bool.should == false
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should read a byte" do
|
231
|
+
[-128, -57, -3, 0, 17, 24, 127].each do |i|
|
232
|
+
@trans.write([i].pack("c"))
|
233
|
+
@prot.read_byte.should == i
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should read an i16" do
|
238
|
+
# try a scattering of values, including min/max
|
239
|
+
[-2**15, -5237, -353, 0, 1527, 2234, 2**15-1].each do |i|
|
240
|
+
@trans.write([i].pack("n"));
|
241
|
+
@prot.read_i16.should == i
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should read an i32" do
|
246
|
+
# try a scattering of values, including min/max
|
247
|
+
[-2**31, -235125, -6236, 0, 2351, 123123, 2**31-1].each do |i|
|
248
|
+
@trans.write([i].pack("N"))
|
249
|
+
@prot.read_i32.should == i
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should read an i64" do
|
254
|
+
# try a scattering of values, including min/max
|
255
|
+
[-2**63, -123512312, -6346, 0, 32, 2346322323, 2**63-1].each do |i|
|
256
|
+
@trans.write([i >> 32, i & 0xFFFFFFFF].pack("NN"))
|
257
|
+
@prot.read_i64.should == i
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should read a double" do
|
262
|
+
# try a random scattering of values, including min/max
|
263
|
+
[Float::MIN, -231231.12351, -323.233513, 0, 123.2351235, 2351235.12351235, Float::MAX].each do |f|
|
264
|
+
@trans.write([f].pack("G"));
|
265
|
+
@prot.read_double.should == f
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should read a string" do
|
270
|
+
str = "hello world"
|
271
|
+
@trans.write([str.size].pack("N") + str)
|
272
|
+
@prot.read_string.should == str
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'thrift/protocol/binaryprotocolaccelerated'
|
3
|
+
require File.dirname(__FILE__) + '/binaryprotocol_spec_shared'
|
4
|
+
require File.dirname(__FILE__) + '/gen-rb/ThriftSpec_types'
|
5
|
+
|
6
|
+
class ThriftBinaryProtocolAcceleratedSpec < Spec::ExampleGroup
|
7
|
+
include Thrift
|
8
|
+
|
9
|
+
describe Thrift::BinaryProtocolAccelerated do
|
10
|
+
# since BinaryProtocolAccelerated should be directly equivalent to
|
11
|
+
# BinaryProtocol, we don't need any custom specs!
|
12
|
+
it_should_behave_like 'a binary protocol'
|
13
|
+
|
14
|
+
def protocol_class
|
15
|
+
BinaryProtocolAccelerated
|
16
|
+
end
|
17
|
+
|
18
|
+
# before(:each) do
|
19
|
+
# @buffer = ""
|
20
|
+
# @trans.stub!(:borrow).and_return { @buffer }
|
21
|
+
# @trans.stub!(:consume!).and_return do |*args|
|
22
|
+
# n = args.first || 0
|
23
|
+
# @buffer.slice!(0,n)
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
#
|
28
|
+
# it "should raise an exception if the message header has the wrong version" do
|
29
|
+
# @buffer = "\000\000\000\v"
|
30
|
+
# # @prot.should_receive(:read_i32).and_return(42)
|
31
|
+
# lambda { @prot.read_message_begin }.should raise_error(Thrift::ProtocolException, 'Missing version identifier') do |e|
|
32
|
+
# e.type == Thrift::ProtocolException::BAD_VERSION
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# it "should encode a string with null bytes in it" do
|
37
|
+
# foo = SpecNamespace::Hello.new(:greeting => "Hello\000World!")
|
38
|
+
# @prot.encode_binary(foo).should == "\v\000\001\000\000\000\fHello\000World!\000"
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# it "should decode a string with null bytes in it" do
|
42
|
+
# trans = Thrift::MemoryBuffer.new("\v\000\001\000\000\000\fHello\000World!\000")
|
43
|
+
# @prot.decode_binary(SpecNamespace::Hello.new, trans).should == SpecNamespace::Hello.new(:greeting => "Hello\000World!")
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# it "should error when encoding a struct with a nil value in a list" do
|
47
|
+
# Thrift.type_checking = false
|
48
|
+
# sl = SpecNamespace::SimpleList
|
49
|
+
# hello = SpecNamespace::Hello
|
50
|
+
# # nil counts as false for bools
|
51
|
+
# # lambda { @prot.encode_binary(sl.new(:bools => [true, false, nil, false])) }.should raise_error
|
52
|
+
# lambda { @prot.encode_binary(sl.new(:bytes => [1, 2, nil, 3])) }.should raise_error
|
53
|
+
# lambda { @prot.encode_binary(sl.new(:i16s => [1, 2, nil, 3])) }.should raise_error
|
54
|
+
# lambda { @prot.encode_binary(sl.new(:i32s => [1, 2, nil, 3])) }.should raise_error
|
55
|
+
# lambda { @prot.encode_binary(sl.new(:i64s => [1, 2, nil, 3])) }.should raise_error
|
56
|
+
# lambda { @prot.encode_binary(sl.new(:doubles => [1.0, 2.0, nil, 3.0])) }.should raise_error
|
57
|
+
# lambda { @prot.encode_binary(sl.new(:strings => ["one", "two", nil, "three"])) }.should raise_error
|
58
|
+
# lambda { @prot.encode_binary(sl.new(:lists => [[1, 2], nil, [3, 4]])) }.should raise_error
|
59
|
+
# lambda { @prot.encode_binary(sl.new(:maps => [{1 => 2}, nil, {3 => 4}])) }.should raise_error
|
60
|
+
# lambda { @prot.encode_binary(sl.new(:sets => [Set.new([1, 2]), nil, Set.new([3, 4])])) }.should raise_error
|
61
|
+
# lambda { @prot.encode_binary(sl.new(:structs => [hello.new, nil, hello.new(:greeting => "hi")])) }.should raise_error
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# it "should error when encoding a non-nil, non-correctly-typed value in a list" do
|
65
|
+
# Thrift.type_checking = false
|
66
|
+
# sl = SpecNamespace::SimpleList
|
67
|
+
# hello = SpecNamespace::Hello
|
68
|
+
# # bool should accept any value
|
69
|
+
# # lambda { @prot.encode_binary(sl.new(:bools => [true, false, 3])) }.should raise_error
|
70
|
+
# lambda { @prot.encode_binary(sl.new(:bytes => [1, 2, "3", 5])) }.should raise_error
|
71
|
+
# lambda { @prot.encode_binary(sl.new(:i16s => ["one", 2, 3])) }.should raise_error
|
72
|
+
# lambda { @prot.encode_binary(sl.new(:i32s => [[1,2], 3, 4])) }.should raise_error
|
73
|
+
# lambda { @prot.encode_binary(sl.new(:i64s => [{1 => 2}, 3, 4])) }.should raise_error
|
74
|
+
# lambda { @prot.encode_binary(sl.new(:doubles => ["one", 2.3, 3.4])) }.should raise_error
|
75
|
+
# lambda { @prot.encode_binary(sl.new(:strings => ["one", "two", 3, 4])) }.should raise_error
|
76
|
+
# lambda { @prot.encode_binary(sl.new(:lists => [{1 => 2}, [3, 4]])) }.should raise_error
|
77
|
+
# lambda { @prot.encode_binary(sl.new(:maps => [{1 => 2}, [3, 4]])) }.should raise_error
|
78
|
+
# lambda { @prot.encode_binary(sl.new(:sets => [Set.new([1, 2]), 3, 4])) }.should raise_error
|
79
|
+
# lambda { @prot.encode_binary(sl.new(:structs => [3, "four"])) }.should raise_error
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# it "should error when encoding an improper object where a container is expected" do
|
83
|
+
# Thrift.type_checking = false
|
84
|
+
# sl = SpecNamespace::SimpleList
|
85
|
+
# lambda { @prot.encode_binary(sl.new(:strings => {"one" => "two", nil => "three"})) }.should raise_error
|
86
|
+
# lambda { @prot.encode_binary(sl.new(:maps => [[1, 2]])) }.should raise_error
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# it "should accept arrays and hashes as sets" do
|
90
|
+
# Thrift.type_checking = false
|
91
|
+
# sl = SpecNamespace::SimpleList
|
92
|
+
# lambda { @prot.encode_binary(sl.new(:sets => [[1, 2], {3 => true, 4 => true}])) }.should_not raise_error
|
93
|
+
# end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe BinaryProtocolAcceleratedFactory do
|
97
|
+
it "should create a BinaryProtocolAccelerated" do
|
98
|
+
BinaryProtocolAcceleratedFactory.new.get_protocol(mock("MockTransport")).should be_instance_of(BinaryProtocolAccelerated)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
class ThriftClientSpec < Spec::ExampleGroup
|
4
|
+
include Thrift
|
5
|
+
|
6
|
+
class ClientSpec
|
7
|
+
include Thrift::Client
|
8
|
+
end
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@prot = mock("MockProtocol")
|
12
|
+
@client = ClientSpec.new(@prot)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Client do
|
16
|
+
it "should re-use iprot for oprot if not otherwise specified" do
|
17
|
+
@client.instance_variable_get(:'@iprot').should eql(@prot)
|
18
|
+
@client.instance_variable_get(:'@oprot').should eql(@prot)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should send a test message" do
|
22
|
+
@prot.should_receive(:write_message_begin).with('testMessage', MessageTypes::CALL, 0)
|
23
|
+
mock_args = mock('#<TestMessage_args:mock>')
|
24
|
+
mock_args.should_receive(:foo=).with('foo')
|
25
|
+
mock_args.should_receive(:bar=).with(42)
|
26
|
+
mock_args.should_receive(:write).with(@prot)
|
27
|
+
@prot.should_receive(:write_message_end)
|
28
|
+
@prot.should_receive(:trans) do
|
29
|
+
mock('trans').tee do |trans|
|
30
|
+
trans.should_receive(:flush)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
klass = stub("TestMessage_args", :new => mock_args)
|
34
|
+
@client.send_message('testMessage', klass, :foo => 'foo', :bar => 42)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should increment the sequence id when sending messages" do
|
38
|
+
pending "it seems sequence ids are completely ignored right now" do
|
39
|
+
@prot.should_receive(:write_message_begin).with('testMessage', MessageTypes::CALL, 0).ordered
|
40
|
+
@prot.should_receive(:write_message_begin).with('testMessage2', MessageTypes::CALL, 1).ordered
|
41
|
+
@prot.should_receive(:write_message_begin).with('testMessage3', MessageTypes::CALL, 2).ordered
|
42
|
+
@prot.stub!(:write_message_end)
|
43
|
+
@prot.stub!(:trans).and_return stub_everything("trans")
|
44
|
+
@client.send_message('testMessage', stub_everything("args class"))
|
45
|
+
@client.send_message('testMessage2', stub_everything("args class"))
|
46
|
+
@client.send_message('testMessage3', stub_everything("args class"))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should receive a test message" do
|
51
|
+
@prot.should_receive(:read_message_begin).and_return [nil, MessageTypes::CALL, 0]
|
52
|
+
@prot.should_receive(:read_message_end)
|
53
|
+
mock_klass = mock("#<MockClass:mock>")
|
54
|
+
mock_klass.should_receive(:read).with(@prot)
|
55
|
+
@client.receive_message(stub("MockClass", :new => mock_klass))
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should handle received exceptions" do
|
59
|
+
@prot.should_receive(:read_message_begin).and_return [nil, MessageTypes::EXCEPTION, 0]
|
60
|
+
@prot.should_receive(:read_message_end)
|
61
|
+
ApplicationException.should_receive(:new).and_return do
|
62
|
+
StandardError.new.tee do |mock_exc|
|
63
|
+
mock_exc.should_receive(:read).with(@prot)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
lambda { @client.receive_message(nil) }.should raise_error(StandardError)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should close the transport if an error occurs while sending a message" do
|
70
|
+
@prot.stub!(:write_message_begin)
|
71
|
+
@prot.should_not_receive(:write_message_end)
|
72
|
+
mock_args = mock("#<TestMessage_args:mock>")
|
73
|
+
mock_args.should_receive(:write).with(@prot).and_raise(StandardError)
|
74
|
+
trans = mock("MockTransport")
|
75
|
+
@prot.stub!(:trans).and_return(trans)
|
76
|
+
trans.should_receive(:close)
|
77
|
+
klass = mock("TestMessage_args", :new => mock_args)
|
78
|
+
lambda { @client.send_message("testMessage", klass) }.should raise_error(StandardError)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|