thrift_client-adamd 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,136 @@
1
+ require File.expand_path('test_helper.rb', File.dirname(__FILE__))
2
+
3
+ class SimpleTest < Test::Unit::TestCase
4
+
5
+ S = ThriftClient::Simple
6
+ S.make_struct("Example", S::Field.new(:name, S::STRING, 1))
7
+ S.make_struct("Args")
8
+ S.make_struct("Retval", S::Field.new(:rv, S::I32, 0))
9
+
10
+ def test_definition
11
+ assert Struct::ST_Example
12
+ assert Struct::ST_Args
13
+ assert Struct::ST_Retval
14
+ end
15
+
16
+ ## Encoding
17
+
18
+ def test_boolean_encoding
19
+ assert_equal "\001", S.pack_value(S::BOOL, true)
20
+ assert_equal "\000", S.pack_value(S::BOOL, false)
21
+ end
22
+
23
+ def test_byte_encoding
24
+ assert_equal "\xc7", S.pack_value(S::BYTE, 199)
25
+ end
26
+
27
+ def test_i16_encoding
28
+ assert_equal "\x00\x96", S.pack_value(S::I16, 150)
29
+ end
30
+
31
+ def test_i32_encoding
32
+ assert_equal "\x00\x96\xb4\x3f", S.pack_value(S::I32, 9876543)
33
+ end
34
+
35
+ def test_i64_encoding
36
+ assert_equal "\x00\x00\x00\x1c\xbb\xf3\x09\x04", S.pack_value(S::I64, 123412351236)
37
+ end
38
+
39
+ def test_double_encoding
40
+ assert_equal "\x40\x23\x00\x00\x00\x00\x00\x00", S.pack_value(S::DOUBLE, 9.5)
41
+ end
42
+
43
+ def test_string_encoding
44
+ assert_equal "\x00\x00\x00\x05hello", S.pack_value(S::STRING, "hello")
45
+ end
46
+
47
+ def test_list_encoding
48
+ assert_equal "\x08\x00\x00\x00\x03\x00\x00\x00\x17\x00\x00\x00\x16\x00\x00\x00\x15",
49
+ S.pack_value(S::ListType.new(S::I32), [ 23, 22, 21 ])
50
+ end
51
+
52
+ def test_map_encoding
53
+ assert_equal "\x0b\x08\x00\x00\x00\x01\x00\x00\x00\x03cat\x00\x00\x00\x05",
54
+ S.pack_value(S::MapType.new(S::STRING, S::I32), "cat" => 5)
55
+ end
56
+
57
+ def test_set_encoding
58
+ assert_equal "\x08\x00\x00\x00\x01\x00\x00\x00\x04",
59
+ S.pack_value(S::SetType.new(S::I32), [ 4 ])
60
+ end
61
+
62
+ def test_struct_encoding
63
+ assert_equal "\x0b\x00\x01\x00\x00\x00\x06Commie\x00",
64
+ S.pack_value(S::StructType.new(Struct::ST_Example), Struct::ST_Example.new("Commie"))
65
+ end
66
+
67
+ def test_request_encoding
68
+ assert_equal "\x80\x01\x00\x01\x00\x00\x00\x09getHeight\x00\x00\x00\x17\x00",
69
+ S.pack_request("getHeight", Struct::ST_Args.new, 23)
70
+ end
71
+
72
+ ## Decoding
73
+
74
+ def test_boolean_decoding
75
+ assert_equal true, S.read_value(StringIO.new("\x01"), S::BOOL)
76
+ assert_equal false, S.read_value(StringIO.new("\x00"), S::BOOL)
77
+ end
78
+
79
+ def test_byte_decoding
80
+ assert_equal -57, S.read_value(StringIO.new("\xc7"), S::BYTE)
81
+ end
82
+
83
+ def test_i16_decoding
84
+ assert_equal 150, S.read_value(StringIO.new("\x00\x96"), S::I16)
85
+ end
86
+
87
+ def test_i32_decoding
88
+ assert_equal 9876543, S.read_value(StringIO.new("\x00\x96\xb4\x3f"), S::I32)
89
+ end
90
+
91
+ def test_i64_decoding
92
+ assert_equal 123412351236,
93
+ S.read_value(StringIO.new("\x00\x00\x00\x1c\xbb\xf3\x09\x04"), S::I64)
94
+ end
95
+
96
+ def test_double_decoding
97
+ assert_equal 9.5,
98
+ S.read_value(StringIO.new("\x40\x23\x00\x00\x00\x00\x00\x00"), S::DOUBLE)
99
+ end
100
+
101
+ def test_string_decoding
102
+ assert_equal "hello", S.read_value(StringIO.new("\x00\x00\x00\x05hello"), S::STRING)
103
+ end
104
+
105
+ def test_list_decoding
106
+ assert_equal [ 23, 22, 21 ],
107
+ S.read_value(StringIO.new("\x08\x00\x00\x00\x03\x00\x00\x00\x17\x00\x00\x00\x16\x00\x00\x00\x15"),
108
+ S::ListType.new(S::I32))
109
+ end
110
+
111
+ def test_map_decoding
112
+ assert_equal({ "cat" => 5 },
113
+ S.read_value(StringIO.new("\x0b\x08\x00\x00\x00\x01\x00\x00\x00\x03cat\x00\x00\x00\x05"),
114
+ S::MapType.new(S::STRING, S::I32)))
115
+ end
116
+
117
+ def test_set_decoding
118
+ assert_equal [ 4 ],
119
+ S.read_value(StringIO.new("\x08\x00\x00\x00\x01\x00\x00\x00\x04"),
120
+ S::ListType.new(S::I32))
121
+ end
122
+
123
+ def test_struct_decoding
124
+ assert_equal Struct::ST_Example.new("Commie"),
125
+ S.read_value(StringIO.new("\x0b\x00\x01\x00\x00\x00\x06Commie\x00"),
126
+ S::StructType.new(Struct::ST_Example))
127
+ end
128
+
129
+ def test_response_decoding
130
+ assert_equal [ "getHeight", 255, 1 ],
131
+ S.read_response(
132
+ StringIO.new("\x80\x01\x00\x02\x00\x00\x00\x09getHeight\x00\x00\x00\xff\x08\x00\x00\x00\x00\x00\x01\x00"),
133
+ Struct::ST_Retval)
134
+ end
135
+
136
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'benchmark'
4
+ $LOAD_PATH << "#{File.expand_path(File.dirname(__FILE__))}/../lib"
5
+ require 'thrift_client'
6
+ require 'thrift_client/simple'
7
+
8
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
9
+ require 'greeter/greeter'
10
+ require 'greeter/server'
11
+
12
+ begin; require 'ruby-debug'; rescue LoadError; end
@@ -0,0 +1,45 @@
1
+ require File.expand_path('test_helper.rb', File.dirname(__FILE__))
2
+
3
+ class ThriftClientHTTPTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @servers = ["http://127.0.0.1:1461/greeter", "http://127.0.0.1:1462/greeter", "http://127.0.0.1:1463/greeter"]
7
+ @socket = 1461
8
+ @timeout = 0.2
9
+ @options = {:protocol_extra_params => [false]}
10
+ @pid = Process.fork do
11
+ Signal.trap("INT") { exit }
12
+ Greeter::HTTPServer.new(@servers.last).serve
13
+ end
14
+ # Need to give the child process a moment to open the listening socket or
15
+ # we get occasional "could not connect" errors in tests.
16
+ sleep 0.20
17
+ end
18
+
19
+ def teardown
20
+ Process.kill("INT", @pid)
21
+ Process.wait
22
+ end
23
+
24
+ def test_bad_uri
25
+ assert_raises URI::InvalidURIError do
26
+ @options.merge!({ :protocol => Thrift::BinaryProtocol, :transport => Thrift::HTTPClientTransport })
27
+ ThriftClient.new(Greeter::Client, "127.0.0.1:1463", @options).greeting("someone")
28
+ end
29
+ end
30
+
31
+ def test_bad_uri_no_http
32
+ assert_raises ArgumentError do
33
+ @options.merge!({ :protocol => Thrift::BinaryProtocol, :transport => Thrift::HTTPClientTransport })
34
+ ThriftClient.new(Greeter::Client, "//127.0.0.1:1463", @options).greeting("someone")
35
+ end
36
+ end
37
+
38
+ def test_valid_server
39
+ assert_nothing_raised do
40
+ @options.merge!({ :protocol => Thrift::BinaryProtocol, :transport => Thrift::HTTPClientTransport })
41
+ ThriftClient.new(Greeter::Client, "http://127.0.0.1:1463/greeter", @options).greeting("someone")
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,289 @@
1
+ require File.expand_path('test_helper.rb', File.dirname(__FILE__))
2
+
3
+ class ThriftClientTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @servers = ["127.0.0.1:1461", "127.0.0.1:1462", "127.0.0.1:1463"]
7
+ @port = 1461
8
+ @timeout = 0.2
9
+ @options = {:protocol_extra_params => [false]}
10
+ @pid = Process.fork do
11
+ Signal.trap("INT") { exit }
12
+ Greeter::Server.new("1463").serve
13
+ end
14
+ # Need to give the child process a moment to open the listening socket or
15
+ # we get occasional "could not connect" errors in tests.
16
+ sleep 0.05
17
+ end
18
+
19
+ def teardown
20
+ Process.kill("INT", @pid)
21
+ Process.wait
22
+ end
23
+
24
+ def test_inspect
25
+ client = ThriftClient.new(Greeter::Client, @servers.last, @options)
26
+ assert_equal "<ThriftClient(Greeter::Client) @current_server=127.0.0.1:1463>", client.inspect
27
+ end
28
+
29
+ def test_create_wrapped_exception_classes
30
+ client = Module.new
31
+ ThriftClient.create_wrapped_exception_classes(client, [Thrift::TransportException])
32
+ assert client.const_defined?(:TransportException)
33
+ assert client.const_get(:TransportException).new.is_a?(Thrift::TransportException)
34
+ end
35
+
36
+ def test_live_server
37
+ assert_nothing_raised do
38
+ ThriftClient.new(Greeter::Client, @servers.last, @options).greeting("someone")
39
+ end
40
+ end
41
+
42
+ def test_dont_raise
43
+ assert_nothing_raised do
44
+ ThriftClient.new(Greeter::Client, @servers.first, @options.merge(:raise => false)).greeting("someone")
45
+ end
46
+ end
47
+
48
+ def test_retries_correct_number_of_times
49
+ stub_server(@port) do |socket|
50
+ opts = @options.merge(:timeout => @timeout, :retries => 4, :server_retry_period => nil)
51
+ client = ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}", opts)
52
+ times_called = 0
53
+
54
+ singleton_class = (class << client; self end)
55
+
56
+ # disconnect_on_error! is called every time a server related
57
+ # connection error happens. it will be called every try (so, retries + 1)
58
+ singleton_class.send :define_method, :disconnect! do |*args|
59
+ times_called += 1 if args[0]; super *args
60
+ end
61
+
62
+ assert_raises(Greeter::Client::TransportException) { client.greeting("someone") }
63
+ assert_equal opts[:retries] + 1, times_called
64
+ end
65
+ end
66
+
67
+ def test_dont_raise_with_defaults
68
+ client = ThriftClient.new(Greeter::Client, @servers.first, @options.merge(:raise => false, :defaults => {:greeting => 1}))
69
+ assert_equal 1, client.greeting
70
+ end
71
+
72
+ def test_defaults_dont_override_no_method_error
73
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:raise => false, :defaults => {:Missing => 2}))
74
+ assert_raises(NoMethodError) { client.Missing }
75
+ end
76
+
77
+ def test_random_fall_through
78
+ assert_nothing_raised do
79
+ 10.times do
80
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
81
+ client.greeting("someone")
82
+ client.disconnect!
83
+ end
84
+ end
85
+ end
86
+
87
+ def test_lazy_connection
88
+ assert_nothing_raised do
89
+ ThriftClient.new(Greeter::Client, @servers[0,2])
90
+ end
91
+ end
92
+
93
+ def test_post_conn_cb
94
+ calledcnt = 0
95
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
96
+ r = client.add_callback :post_connect do |cl|
97
+ calledcnt += 1
98
+ assert_equal(client, cl)
99
+ end
100
+ assert_equal(client, r)
101
+ assert_nothing_raised do
102
+ client.greeting("someone")
103
+ client.disconnect!
104
+ end
105
+ assert_equal(1, calledcnt)
106
+ end
107
+
108
+ def test_before_method_cb
109
+ before_method_counts = Hash.new { |hash, key| hash[key] = 0 }
110
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
111
+ r = client.add_callback :before_method do |method_name|
112
+ before_method_counts[method_name.to_sym] += 1
113
+ end
114
+ assert_equal(client, r)
115
+ assert_nothing_raised do
116
+ client.greeting("someone")
117
+ client.yo("dude")
118
+ client.yo("dawg")
119
+ client.disconnect!
120
+ end
121
+ assert_equal({:greeting => 1, :yo => 2}, before_method_counts)
122
+ end
123
+
124
+ def test_on_exception_cb
125
+ on_exception_counts = Hash.new { |h1, method_name| h1[method_name] = Hash.new { |h2, clazz| h2[clazz] = 0 }}
126
+ client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:retries => 2))
127
+ r = client.add_callback :on_exception do |error, method_name|
128
+ on_exception_counts[method_name.to_sym][error.class] += 1
129
+ end
130
+ assert_equal(client, r)
131
+ assert_raises(ThriftClient::NoServersAvailable) do
132
+ client.greeting("someone")
133
+ client.disconnect!
134
+ end
135
+ assert_equal({:greeting => {ThriftClient::NoServersAvailable => 1}}, on_exception_counts)
136
+ end
137
+
138
+ def test_unknown_cb
139
+ calledcnt = 0
140
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
141
+ r = client.add_callback :unknown do |cl|
142
+ assert(false)
143
+ end
144
+ assert_equal(nil, r)
145
+ end
146
+
147
+ def test_multiple_cb
148
+ calledcnt = 0
149
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
150
+ 2.times do |i|
151
+ r = client.add_callback :post_connect do |cl|
152
+ calledcnt += 1
153
+ assert_equal(client, cl)
154
+ end
155
+ assert_equal(client, r)
156
+ end
157
+ assert_nothing_raised do
158
+ client.greeting("someone")
159
+ client.disconnect!
160
+ end
161
+ assert_equal(2, calledcnt)
162
+ end
163
+
164
+ def test_no_servers_eventually_raise
165
+ wascalled = false
166
+ client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:retries => 2))
167
+ client.add_callback :post_connect do
168
+ wascalled = true
169
+ end
170
+ assert_raises(ThriftClient::NoServersAvailable) do
171
+ client.greeting("someone")
172
+ client.disconnect!
173
+ end
174
+ assert(!wascalled)
175
+ end
176
+
177
+ def test_socket_timeout
178
+ stub_server(@port) do |socket|
179
+ measurement = Benchmark.measure do
180
+ assert_raises(Greeter::Client::TransportException) do
181
+ ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
182
+ @options.merge(:timeout => 1, :connect_timeout => 0.5)
183
+ ).greeting("someone")
184
+ end
185
+ end
186
+ assert(measurement.real > 0.5 && measurement.real < 1.05)
187
+ end
188
+ end
189
+
190
+ def test_framed_transport_timeout
191
+ stub_server(@port) do |socket|
192
+ measurement = Benchmark.measure do
193
+ assert_raises(Greeter::Client::TransportException) do
194
+ ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
195
+ @options.merge(:timeout => @timeout, :connect_timeout => @timeout)
196
+ ).greeting("someone")
197
+ end
198
+ end
199
+ assert((measurement.real > @timeout), "#{measurement.real} < #{@timeout}")
200
+ end
201
+ end
202
+
203
+ def test_buffered_transport_timeout
204
+ stub_server(@port) do |socket|
205
+ measurement = Benchmark.measure do
206
+ client = ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
207
+ @options.merge(:timeout => @timeout, :transport_wrapper => Thrift::BufferedTransport, :connect_timeout => @timeout)
208
+ )
209
+ assert_raises(Greeter::Client::TransportException) do
210
+ client.greeting("someone")
211
+ end
212
+ end
213
+ assert((measurement.real > @timeout), "#{measurement.real} < #{@timeout}")
214
+ end
215
+ end
216
+
217
+ def test_buffered_transport_timeout_override
218
+ # FIXME Large timeout values always are applied twice for some bizarre reason
219
+ log_timeout = @timeout * 4
220
+ stub_server(@port) do |socket|
221
+ measurement = Benchmark.measure do
222
+ client = ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
223
+ @options.merge(:timeout => @timeout, :timeout_overrides => {:greeting => log_timeout}, :transport_wrapper => Thrift::BufferedTransport)
224
+ )
225
+ assert_raises(Greeter::Client::TransportException) do
226
+ client.greeting("someone")
227
+ end
228
+ end
229
+ assert((measurement.real > log_timeout), "#{measurement.real} < #{log_timeout}")
230
+ end
231
+ end
232
+
233
+ def test_retry_period
234
+ client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:server_retry_period => 1, :retries => 2))
235
+ assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
236
+ sleep 1.1
237
+ assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
238
+ end
239
+
240
+ def test_connect_retry_period
241
+ client = ThriftClient.new(Greeter::Client, @servers[0], @options.merge(:server_retry_period => 0))
242
+ assert_raises(ThriftClient::NoServersAvailable) { client.connect! }
243
+ end
244
+
245
+ def test_client_with_retry_period_drops_servers
246
+ client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:server_retry_period => 1, :retries => 2))
247
+ assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
248
+ sleep 1.1
249
+ assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
250
+ end
251
+
252
+ def test_oneway_method
253
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:server_max_requests => 2, :retries => 2))
254
+ assert_nothing_raised do
255
+ response = client.yo("dude")
256
+ end
257
+ end
258
+
259
+ def test_server_max_requests_with_downed_servers
260
+ client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:server_max_requests => 2, :retries => 2))
261
+ client.greeting("someone")
262
+ last_client = client.last_client
263
+ client.greeting("someone")
264
+ assert_equal last_client, client.last_client
265
+
266
+ # This next call maxes out the requests for that "client" object
267
+ # and moves on to the next.
268
+ client.greeting("someone")
269
+ assert_not_equal last_client, new_client = client.last_client
270
+
271
+ # And here we should still have the same client as the last one...
272
+ client.greeting("someone")
273
+ assert_equal new_client, client.last_client
274
+
275
+ # Until we max it out, too.
276
+ client.greeting("someone")
277
+ assert_not_equal last_client, client.last_client
278
+ end
279
+
280
+ private
281
+
282
+ def stub_server(port)
283
+ socket = TCPServer.new('127.0.0.1', port)
284
+ Thread.new { socket.accept }
285
+ yield socket
286
+ ensure
287
+ socket.close
288
+ end
289
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thrift_client-adamd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.3
5
+ platform: ruby
6
+ authors:
7
+ - Evan Weaver
8
+ - Ryan King
9
+ - Jeff Hodges
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2014-11-04 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thrift-adamd
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ version: 1.0.0.0
29
+ - !ruby/object:Gem::Dependency
30
+ name: rake
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: rack
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: thin
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ description:
72
+ email:
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - lib/thrift_client.rb
78
+ - lib/thrift_client/abstract_thrift_client.rb
79
+ - lib/thrift_client/connection.rb
80
+ - lib/thrift_client/connection/base.rb
81
+ - lib/thrift_client/connection/factory.rb
82
+ - lib/thrift_client/connection/http.rb
83
+ - lib/thrift_client/connection/socket.rb
84
+ - lib/thrift_client/event_machine.rb
85
+ - lib/thrift_client/server.rb
86
+ - lib/thrift_client/simple.rb
87
+ - lib/thrift_client/thrift.rb
88
+ - test/greeter/greeter.rb
89
+ - test/greeter/server.rb
90
+ - test/multiple_working_servers_test.rb
91
+ - test/simple_test.rb
92
+ - test/test_helper.rb
93
+ - test/thrift_client_http_test.rb
94
+ - test/thrift_client_test.rb
95
+ homepage: https://github.com/twitter/thrift_client
96
+ licenses:
97
+ - Apache 2.0
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.2.2
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: A Thrift client wrapper that encapsulates some common failover behavior.
119
+ test_files:
120
+ - test/greeter/greeter.rb
121
+ - test/greeter/server.rb
122
+ - test/multiple_working_servers_test.rb
123
+ - test/simple_test.rb
124
+ - test/test_helper.rb
125
+ - test/thrift_client_http_test.rb
126
+ - test/thrift_client_test.rb
127
+ has_rdoc: