thrift_client/test/thrift_client_test.rb

290 lines
9.6 KiB
Ruby

require File.expand_path('test_helper.rb', File.dirname(__FILE__))
class ThriftClientTest < Test::Unit::TestCase
def setup
@servers = ["127.0.0.1:1461", "127.0.0.1:1462", "127.0.0.1:1463"]
@port = 1461
@timeout = 0.2
@options = {:protocol_extra_params => [false]}
@pid = Process.fork do
Signal.trap("INT") { exit }
Greeter::Server.new("1463").serve
end
# Need to give the child process a moment to open the listening socket or
# we get occasional "could not connect" errors in tests.
sleep 0.05
end
def teardown
Process.kill("INT", @pid)
Process.wait
end
def test_inspect
client = ThriftClient.new(Greeter::Client, @servers.last, @options)
assert_equal "<ThriftClient(Greeter::Client) @current_server=127.0.0.1:1463>", client.inspect
end
def test_create_wrapped_exception_classes
client = Module.new
ThriftClient.create_wrapped_exception_classes(client, [Thrift::TransportException])
assert client.const_defined?(:TransportException)
assert client.const_get(:TransportException).new.is_a?(Thrift::TransportException)
end
def test_live_server
assert_nothing_raised do
ThriftClient.new(Greeter::Client, @servers.last, @options).greeting("someone")
end
end
def test_dont_raise
assert_nothing_raised do
ThriftClient.new(Greeter::Client, @servers.first, @options.merge(:raise => false)).greeting("someone")
end
end
def test_retries_correct_number_of_times
stub_server(@port) do |socket|
opts = @options.merge(:timeout => @timeout, :retries => 4, :server_retry_period => nil)
client = ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}", opts)
times_called = 0
singleton_class = (class << client; self end)
# disconnect_on_error! is called every time a server related
# connection error happens. it will be called every try (so, retries + 1)
singleton_class.send :define_method, :disconnect! do |*args|
times_called += 1 if args[0]; super *args
end
assert_raises(Greeter::Client::TransportException) { client.greeting("someone") }
assert_equal opts[:retries] + 1, times_called
end
end
def test_dont_raise_with_defaults
client = ThriftClient.new(Greeter::Client, @servers.first, @options.merge(:raise => false, :defaults => {:greeting => 1}))
assert_equal 1, client.greeting
end
def test_defaults_dont_override_no_method_error
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:raise => false, :defaults => {:Missing => 2}))
assert_raises(NoMethodError) { client.Missing }
end
def test_random_fall_through
assert_nothing_raised do
10.times do
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
client.greeting("someone")
client.disconnect!
end
end
end
def test_lazy_connection
assert_nothing_raised do
ThriftClient.new(Greeter::Client, @servers[0,2])
end
end
def test_post_conn_cb
calledcnt = 0
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
r = client.add_callback :post_connect do |cl|
calledcnt += 1
assert_equal(client, cl)
end
assert_equal(client, r)
assert_nothing_raised do
client.greeting("someone")
client.disconnect!
end
assert_equal(1, calledcnt)
end
def test_before_method_cb
before_method_counts = Hash.new { |hash, key| hash[key] = 0 }
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
r = client.add_callback :before_method do |method_name|
before_method_counts[method_name.to_sym] += 1
end
assert_equal(client, r)
assert_nothing_raised do
client.greeting("someone")
client.yo("dude")
client.yo("dawg")
client.disconnect!
end
assert_equal({:greeting => 1, :yo => 2}, before_method_counts)
end
def test_on_exception_cb
on_exception_counts = Hash.new { |h1, method_name| h1[method_name] = Hash.new { |h2, clazz| h2[clazz] = 0 }}
client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:retries => 2))
r = client.add_callback :on_exception do |error, method_name|
on_exception_counts[method_name.to_sym][error.class] += 1
end
assert_equal(client, r)
assert_raises(ThriftClient::NoServersAvailable) do
client.greeting("someone")
client.disconnect!
end
assert_equal({:greeting => {ThriftClient::NoServersAvailable => 1}}, on_exception_counts)
end
def test_unknown_cb
calledcnt = 0
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
r = client.add_callback :unknown do |cl|
assert(false)
end
assert_equal(nil, r)
end
def test_multiple_cb
calledcnt = 0
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:retries => 2))
2.times do |i|
r = client.add_callback :post_connect do |cl|
calledcnt += 1
assert_equal(client, cl)
end
assert_equal(client, r)
end
assert_nothing_raised do
client.greeting("someone")
client.disconnect!
end
assert_equal(2, calledcnt)
end
def test_no_servers_eventually_raise
wascalled = false
client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:retries => 2))
client.add_callback :post_connect do
wascalled = true
end
assert_raises(ThriftClient::NoServersAvailable) do
client.greeting("someone")
client.disconnect!
end
assert(!wascalled)
end
def test_socket_timeout
stub_server(@port) do |socket|
measurement = Benchmark.measure do
assert_raises(Greeter::Client::TransportException) do
ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
@options.merge(:timeout => 1, :connect_timeout => 0.5)
).greeting("someone")
end
end
assert(measurement.real > 0.5 && measurement.real < 1.05)
end
end
def test_framed_transport_timeout
stub_server(@port) do |socket|
measurement = Benchmark.measure do
assert_raises(Greeter::Client::TransportException) do
ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
@options.merge(:timeout => @timeout, :connect_timeout => @timeout)
).greeting("someone")
end
end
assert((measurement.real > @timeout), "#{measurement.real} < #{@timeout}")
end
end
def test_buffered_transport_timeout
stub_server(@port) do |socket|
measurement = Benchmark.measure do
client = ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
@options.merge(:timeout => @timeout, :transport_wrapper => Thrift::BufferedTransport, :connect_timeout => @timeout)
)
assert_raises(Greeter::Client::TransportException) do
client.greeting("someone")
end
end
assert((measurement.real > @timeout), "#{measurement.real} < #{@timeout}")
end
end
def test_buffered_transport_timeout_override
# FIXME Large timeout values always are applied twice for some bizarre reason
log_timeout = @timeout * 4
stub_server(@port) do |socket|
measurement = Benchmark.measure do
client = ThriftClient.new(Greeter::Client, "127.0.0.1:#{@port}",
@options.merge(:timeout => @timeout, :timeout_overrides => {:greeting => log_timeout}, :transport_wrapper => Thrift::BufferedTransport)
)
assert_raises(Greeter::Client::TransportException) do
client.greeting("someone")
end
end
assert((measurement.real > log_timeout), "#{measurement.real} < #{log_timeout}")
end
end
def test_retry_period
client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:server_retry_period => 1, :retries => 2))
assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
sleep 1.1
assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
end
def test_connect_retry_period
client = ThriftClient.new(Greeter::Client, @servers[0], @options.merge(:server_retry_period => 0))
assert_raises(ThriftClient::NoServersAvailable) { client.connect! }
end
def test_client_with_retry_period_drops_servers
client = ThriftClient.new(Greeter::Client, @servers[0,2], @options.merge(:server_retry_period => 1, :retries => 2))
assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
sleep 1.1
assert_raises(ThriftClient::NoServersAvailable) { client.greeting("someone") }
end
def test_oneway_method
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:server_max_requests => 2, :retries => 2))
assert_nothing_raised do
response = client.yo("dude")
end
end
def test_server_max_requests_with_downed_servers
client = ThriftClient.new(Greeter::Client, @servers, @options.merge(:server_max_requests => 2, :retries => 2))
client.greeting("someone")
last_client = client.last_client
client.greeting("someone")
assert_equal last_client, client.last_client
# This next call maxes out the requests for that "client" object
# and moves on to the next.
client.greeting("someone")
assert_not_equal last_client, new_client = client.last_client
# And here we should still have the same client as the last one...
client.greeting("someone")
assert_equal new_client, client.last_client
# Until we max it out, too.
client.greeting("someone")
assert_not_equal last_client, client.last_client
end
private
def stub_server(port)
socket = TCPServer.new('127.0.0.1', port)
Thread.new { socket.accept }
yield socket
ensure
socket.close
end
end