diff options
Diffstat (limited to 'test/socket/test_basicsocket.rb')
| -rw-r--r-- | test/socket/test_basicsocket.rb | 162 |
1 files changed, 151 insertions, 11 deletions
diff --git a/test/socket/test_basicsocket.rb b/test/socket/test_basicsocket.rb index 59b739e813..8c1b434a83 100644 --- a/test/socket/test_basicsocket.rb +++ b/test/socket/test_basicsocket.rb @@ -1,6 +1,9 @@ +# frozen_string_literal: true + begin require "socket" require "test/unit" + require "io/nonblock" rescue LoadError end @@ -9,25 +12,33 @@ class TestSocket_BasicSocket < Test::Unit::TestCase sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) yield sock ensure - assert_raise(IOError) {sock.close} + assert(sock.closed?) end def test_getsockopt inet_stream do |s| - n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE) - assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) + begin + n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE) + assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) - n = s.getsockopt("SOL_SOCKET", "SO_TYPE") - assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) + n = s.getsockopt("SOL_SOCKET", "SO_TYPE") + assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) - n = s.getsockopt(:SOL_SOCKET, :SO_TYPE) - assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) + n = s.getsockopt(:SOL_SOCKET, :SO_TYPE) + assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) - n = s.getsockopt(:SOCKET, :TYPE) - assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) + n = s.getsockopt(:SOCKET, :TYPE) + assert_equal([Socket::SOCK_STREAM].pack("i"), n.data) - n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR) - assert_equal([0].pack("i"), n.data) + n = s.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR) + assert_equal([0].pack("i"), n.data) + rescue Test::Unit::AssertionFailedError + s.close + if /aix/ =~ RUBY_PLATFORM + omit "Known bug in getsockopt(2) on AIX" + end + raise $! + end val = Object.new class << val; self end.send(:define_method, :to_int) { @@ -85,4 +96,133 @@ class TestSocket_BasicSocket < Test::Unit::TestCase } end end + + def socks + sserv = TCPServer.new('localhost', 0) + ssock = nil + t = Thread.new { ssock = sserv.accept } + csock = TCPSocket.new('localhost', sserv.addr[1]) + t.join + yield sserv, ssock, csock + ensure + ssock.close rescue nil + csock.close rescue nil + sserv.close rescue nil + end + + def test_close_read + socks do |sserv, ssock, csock| + + # close_read makes subsequent reads raise IOError + csock.close_read + assert_raise(IOError) { csock.read(5) } + + # close_read ignores any error from shutting down half of still-open socket + assert_nothing_raised { csock.close_read } + + # close_read raises if socket is not open + assert_nothing_raised { csock.close } + assert_raise(IOError) { csock.close_read } + end + end + + def test_close_write + socks do |sserv, ssock, csock| + + # close_write makes subsequent writes raise IOError + csock.close_write + assert_raise(IOError) { csock.write(5) } + + # close_write ignores any error from shutting down half of still-open socket + assert_nothing_raised { csock.close_write } + + # close_write raises if socket is not open + assert_nothing_raised { csock.close } + assert_raise(IOError) { csock.close_write } + end + end + + def test_for_fd + assert_raise(Errno::EBADF, '[ruby-core:72418] [Bug #11854]') do + BasicSocket.for_fd(-1) + end + inet_stream do |sock| + s = BasicSocket.for_fd(sock.fileno) + assert_instance_of BasicSocket, s + s.autoclose = false + sock.close + end + end + + def test_read_write_nonblock + socks do |sserv, ssock, csock| + set_nb = true + buf = String.new + if ssock.respond_to?(:nonblock?) + csock.nonblock = ssock.nonblock = false + + # Linux may use MSG_DONTWAIT to avoid setting O_NONBLOCK + if RUBY_PLATFORM.match?(/linux/) && Socket.const_defined?(:MSG_DONTWAIT) + set_nb = false + end + end + assert_equal :wait_readable, ssock.read_nonblock(1, buf, exception: false) + assert_equal 5, csock.write_nonblock('hello') + IO.select([ssock]) + assert_same buf, ssock.read_nonblock(5, buf, exception: false) + assert_equal 'hello', buf + buf = '*' * 16384 + n = 0 + + case w = csock.write_nonblock(buf, exception: false) + when Integer + n += w + when :wait_writable + break + end while true + + assert_equal :wait_writable, w + assert_raise(IO::WaitWritable) { loop { csock.write_nonblock(buf) } } + assert_operator n, :>, 0 + assert_not_predicate(csock, :nonblock?, '[Feature #13362]') unless set_nb + csock.close + + case r = ssock.read_nonblock(16384, buf, exception: false) + when String + next + when nil + break + when :wait_readable + IO.select([ssock], nil, nil, 10) or + flunk 'socket did not become readable' + else + flunk "unexpected read_nonblock return: #{r.inspect}" + end while true + + assert_raise(EOFError) { ssock.read_nonblock(1) } + + assert_not_predicate(ssock, :nonblock?) unless set_nb + end + end + + def test_read_nonblock_mix_buffered + socks do |sserv, ssock, csock| + ssock.write("hello\nworld\n") + assert_equal "hello\n", csock.gets + IO.select([csock], nil, nil, 10) or + flunk 'socket did not become readable' + assert_equal "world\n", csock.read_nonblock(8) + end + end + + def test_write_nonblock_buffered + socks do |sserv, ssock, csock| + ssock.sync = false + ssock.write("h") + assert_equal :wait_readable, csock.read_nonblock(1, exception: false) + assert_equal 4, ssock.write_nonblock("ello") + ssock.close + assert_equal "hello", csock.read(5) + end + end end if defined?(BasicSocket) |
