require 'libuv' require 'thread' describe Libuv::TCP do before :each do @log = [] @general_failure = [] @reactor = Libuv::Reactor.new @server = @reactor.tcp @client = @reactor.tcp @timeout = @reactor.timer do @reactor.stop @reactor2.stop if @reactor2 @general_failure << "test timed out" end @timeout.start(5000) @reactor.all(@server, @client, @timeout).catch do |reason| @general_failure << reason.inspect end @pipefile = "/tmp/test-pipe.pipe" @reactor.notifier do |error, context| begin @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n" rescue Exception => e @general_failure << "error in logger #{e.inspect}" end end begin File.unlink(@pipefile) rescue end end describe 'basic client server' do it "should send a ping and return a pong", :network => true do @reactor.run { |reactor| @server.bind('127.0.0.1', 34567) do |client| client.progress do |data| @log << data client.write('pong') end client.start_read end # catch errors @server.catch do |reason| @general_failure << reason.inspect end # start listening @server.listen(1024) # connect client to server @client.connect('127.0.0.1', 34567) do |client| client.progress do |data| @log << data @client.shutdown end @client.start_read @client.write('ping') end # catch errors @client.catch do |reason| @general_failure << reason.inspect end # close the handle @client.finally do @server.close @reactor.stop end } expect(@general_failure).to eq([]) expect(@log).to eq(['ping', 'pong']) end it "should work with coroutines", :network => true do @reactor.run { |reactor| @server.bind('127.0.0.1', 34567) do |client| client.progress do |data| @log << data client.write('pong') end client.start_read end # catch errors @server.catch do |reason| @general_failure << reason.inspect end # start listening @server.listen(1024) # connect client to server @client.progress do |data| @log << data addrinfo = @reactor.lookup('127.0.0.1') @log << addrinfo[0][0] @client.shutdown end # catch errors @client.catch do |reason| @general_failure << reason.inspect end # close the handle @client.finally do @server.close @reactor.stop end @client.connect('127.0.0.1', 34567) @client.start_read @client.write('ping') } expect(@general_failure).to eq([]) expect(@log).to eq(['ping', 'pong', '127.0.0.1']) end it "should quack a bit like an IO object", :network => true do @reactor.run { |reactor| @server.bind('127.0.0.1', 34567) do |client| @log << client.read(4) client.write('pong') end # catch errors @server.catch do |reason| @general_failure << reason.inspect end # start listening @server.listen(1024) # catch errors @client.catch do |reason| @general_failure << reason.inspect end # close the handle @client.finally do @server.close @reactor.stop end @client.connect('127.0.0.1', 34567) @client.write('ping') @log << @client.read(4) addrinfo = @reactor.lookup('127.0.0.1') @log << addrinfo[0][0] @client.shutdown } expect(@general_failure).to eq([]) expect(@log).to eq(['ping', 'pong', '127.0.0.1']) end end it "should handle requests on different threads", :network => true do @sync = Mutex.new @reactor.run { |reactor| @remote = nil @server.bind('127.0.0.1', 45678) do |client| @remote.write2(client) end # catch errors @server.catch do |reason| @general_failure << reason.inspect end @pipeserve = @reactor.pipe(true) @pipeserve.bind(@pipefile) do |client| @remote = client # start listening on TCP server @server.listen(1024) # connect client to server @client.connect('127.0.0.1', 45678) do |client| client.progress do |data| @sync.synchronize { @log << data } @client.shutdown end @client.start_read @client.write('ping') end @pipeserve.getsockname end # start listening @pipeserve.listen(1024) # catch errors @client.catch do |reason| @general_failure << reason.inspect end # close the handle @client.finally do @server.close @pipeserve.close end Thread.new do @reactor2 = Libuv::Reactor.new @reactor2.notifier do |error, context| begin @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n" rescue Exception @general_failure << "error in logger #{e.inspect}" end end @pipeclient = @reactor2.pipe(true) @reactor2.run do |reactor| # connect client to server @pipeclient.connect(@pipefile) do |client| @pipeclient.progress do |data| connection = @pipeclient.check_pending connection.progress do |data| @sync.synchronize { @log << data } connection.write('pong') end connection.start_read connection.finally do @pipeclient.close @reactor2.stop @reactor.stop end end @pipeclient.start_read end end end } expect(@general_failure).to eq([]) expect(@log).to eq(['ping', 'pong']) end describe 'basic TLS client and server' do it "should send a ping and return a pong", :network => true do @reactor.run { |reactor| @server.bind('127.0.0.1', 56789) do |client| client.start_tls(server: true) client.progress do |data| @log << data client.write('pong') end client.start_read end # catch errors @server.catch do |reason| @general_failure << reason.inspect end # start listening @server.listen(1024) # connect client to server @client.connect('127.0.0.1', 56789) do |client| client.start_tls client.progress do |data| @log << data @client.shutdown end @client.start_read @client.write('ping') end # catch errors @client.catch do |reason| @general_failure << reason.inspect end # close the handle @client.finally do @server.close @reactor.stop end } expect(@general_failure).to eq([]) expect(@log).to eq(['ping', 'pong']) end end end