diff options
Diffstat (limited to 'test/socket')
-rw-r--r-- | test/socket/test_addrinfo.rb | 10 | ||||
-rw-r--r-- | test/socket/test_basicsocket.rb | 2 | ||||
-rw-r--r-- | test/socket/test_nonblock.rb | 12 | ||||
-rw-r--r-- | test/socket/test_socket.rb | 287 | ||||
-rw-r--r-- | test/socket/test_sockopt.rb | 2 | ||||
-rw-r--r-- | test/socket/test_tcp.rb | 2 | ||||
-rw-r--r-- | test/socket/test_udp.rb | 2 | ||||
-rw-r--r-- | test/socket/test_unix.rb | 215 |
8 files changed, 455 insertions, 77 deletions
diff --git a/test/socket/test_addrinfo.rb b/test/socket/test_addrinfo.rb index 5bd34cd5eb..c61764d76d 100644 --- a/test/socket/test_addrinfo.rb +++ b/test/socket/test_addrinfo.rb @@ -103,7 +103,7 @@ class TestSocketAddrinfo < Test::Unit::TestCase end def test_error_message - e = assert_raise_with_message(SocketError, /getaddrinfo/) do + e = assert_raise_with_message(Socket::ResolutionError, /getaddrinfo/) do Addrinfo.ip("...") end m = e.message @@ -357,7 +357,7 @@ class TestSocketAddrinfo < Test::Unit::TestCase ai = Addrinfo.unix("/testdir/sock").family_addrinfo("/testdir/sock2") assert_equal("/testdir/sock2", ai.unix_path) assert_equal(Socket::SOCK_STREAM, ai.socktype) - assert_raise(SocketError) { Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("::1", 80) } + assert_raise(Socket::ResolutionError) { Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("::1", 80) } end def random_port @@ -373,8 +373,8 @@ class TestSocketAddrinfo < Test::Unit::TestCase def errors_addrinuse errs = [Errno::EADDRINUSE] - # MinGW fails with "Errno::EACCES: Permission denied - bind(2) for 0.0.0.0:49721" - errs << Errno::EACCES if /mingw/ =~ RUBY_PLATFORM + # Windows fails with "Errno::EACCES: Permission denied - bind(2) for 0.0.0.0:49721" + errs << Errno::EACCES if /mingw|mswin/ =~ RUBY_PLATFORM errs end @@ -588,7 +588,7 @@ class TestSocketAddrinfo < Test::Unit::TestCase assert(ai.ipv4? || ai.send(meth), "ai=#{addr_exp}; ai.ipv4? || .#{meth}") rescue Test::Unit::AssertionFailedError if /aix/ =~ RUBY_PLATFORM - skip "Known bug in IN6_IS_ADDR_V4COMPAT and IN6_IS_ADDR_V4MAPPED on AIX" + omit "Known bug in IN6_IS_ADDR_V4COMPAT and IN6_IS_ADDR_V4MAPPED on AIX" end raise $! end diff --git a/test/socket/test_basicsocket.rb b/test/socket/test_basicsocket.rb index 02e393d4e8..8c1b434a83 100644 --- a/test/socket/test_basicsocket.rb +++ b/test/socket/test_basicsocket.rb @@ -35,7 +35,7 @@ class TestSocket_BasicSocket < Test::Unit::TestCase rescue Test::Unit::AssertionFailedError s.close if /aix/ =~ RUBY_PLATFORM - skip "Known bug in getsockopt(2) on AIX" + omit "Known bug in getsockopt(2) on AIX" end raise $! end diff --git a/test/socket/test_nonblock.rb b/test/socket/test_nonblock.rb index 5d45593439..5a4688bac3 100644 --- a/test/socket/test_nonblock.rb +++ b/test/socket/test_nonblock.rb @@ -279,7 +279,7 @@ class TestSocketNonblock < Test::Unit::TestCase s1.sendmsg_nonblock("a" * 100000) } rescue NotImplementedError, Errno::ENOSYS - skip "sendmsg not implemented on this platform: #{$!}" + omit "sendmsg not implemented on this platform: #{$!}" rescue Errno::EMSGSIZE # UDP has 64K limit (if no Jumbograms). No problem. rescue Errno::EWOULDBLOCK @@ -307,11 +307,13 @@ class TestSocketNonblock < Test::Unit::TestCase loop { s1.sendmsg_nonblock(buf) } end end - rescue NotImplementedError, Errno::ENOSYS, Errno::EPROTONOSUPPORT - skip "UNIXSocket.pair(:SEQPACKET) not implemented on this platform: #{$!}" + rescue NotImplementedError, Errno::ENOSYS, Errno::EPROTONOSUPPORT, Errno::EPROTOTYPE + omit "UNIXSocket.pair(:SEQPACKET) not implemented on this platform: #{$!}" end def test_sendmsg_nonblock_no_exception + omit "AF_UNIX + SEQPACKET is not supported on windows" if /mswin|mingw/ =~ RUBY_PLATFORM + buf = '*' * 4096 UNIXSocket.pair(:SEQPACKET) do |s1, s2| n = 0 @@ -329,7 +331,7 @@ class TestSocketNonblock < Test::Unit::TestCase end end rescue NotImplementedError, Errno::ENOSYS, Errno::EPROTONOSUPPORT - skip "UNIXSocket.pair(:SEQPACKET) not implemented on this platform: #{$!}" + omit "UNIXSocket.pair(:SEQPACKET) not implemented on this platform: #{$!}" end end @@ -338,7 +340,7 @@ class TestSocketNonblock < Test::Unit::TestCase begin s1.recvmsg_nonblock(4096) rescue NotImplementedError - skip "recvmsg not implemented on this platform." + omit "recvmsg not implemented on this platform." rescue Errno::EWOULDBLOCK assert_kind_of(IO::WaitReadable, $!) end diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb index 9807db3674..6a057e866f 100644 --- a/test/socket/test_socket.rb +++ b/test/socket/test_socket.rb @@ -1,9 +1,5 @@ # frozen_string_literal: true -# tentatively disabled due to IPv6 configuration issue on Solaris CI -# http://rubyci.s3.amazonaws.com/solaris10-gcc/ruby-master/log/20210729T040002Z.fail.html.gz -return if /solaris/ =~ RUBY_PLATFORM - begin require "socket" require "tmpdir" @@ -95,20 +91,20 @@ class TestSocket < Test::Unit::TestCase def test_getaddrinfo # This should not send a DNS query because AF_UNIX. - assert_raise(SocketError) { Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX") } + assert_raise(Socket::ResolutionError) { Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX") } end def test_getaddrinfo_raises_no_errors_on_port_argument_of_0 # [ruby-core:29427] assert_nothing_raised('[ruby-core:29427]'){ Socket.getaddrinfo('localhost', 0, Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) } assert_nothing_raised('[ruby-core:29427]'){ Socket.getaddrinfo('localhost', '0', Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) } assert_nothing_raised('[ruby-core:29427]'){ Socket.getaddrinfo('localhost', '00', Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) } - assert_raise(SocketError, '[ruby-core:29427]'){ Socket.getaddrinfo(nil, nil, Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) } + assert_raise(Socket::ResolutionError, '[ruby-core:29427]'){ Socket.getaddrinfo(nil, nil, Socket::AF_INET, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) } assert_nothing_raised('[ruby-core:29427]'){ TCPServer.open('localhost', 0) {} } end def test_getnameinfo - assert_raise(SocketError) { Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"]) } + assert_raise(Socket::ResolutionError) { Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"]) } assert_raise(ArgumentError) {Socket.getnameinfo(["AF_INET", "http\0", "example.net"])} assert_raise(ArgumentError) {Socket.getnameinfo(["AF_INET", "http", "example.net\0"])} end @@ -344,10 +340,14 @@ class TestSocket < Test::Unit::TestCase end def test_udp_server + # http://rubyci.s3.amazonaws.com/rhel_zlinux/ruby-master/log/20230312T023302Z.fail.html.gz + # Errno::EHOSTUNREACH: No route to host - recvmsg(2) + omit if 'rhel_zlinux' == ENV['RUBYCI_NICKNAME'] + begin ifaddrs = Socket.getifaddrs rescue NotImplementedError - skip "Socket.getifaddrs not implemented" + omit "Socket.getifaddrs not implemented" end ifconfig = nil @@ -441,19 +441,18 @@ class TestSocket < Test::Unit::TestCase } rescue NotImplementedError, Errno::ENOSYS skipped = true - skip "need sendmsg and recvmsg: #{$!}" + omit "need sendmsg and recvmsg: #{$!}" rescue RuntimeError skipped = true - skip "UDP server is no response: #{$!}" + omit "UDP server is no response: #{$!}" ensure if th - if skipped - Thread.kill th unless th.join(10) - else + unless skipped Addrinfo.udp("127.0.0.1", port).connect {|s| s.sendmsg "exit" } - unless th.join(10) - Thread.kill th - th.join(10) + end + unless th.join(10) + th.kill.join(10) + unless skipped raise "thread killed" end end @@ -490,13 +489,14 @@ class TestSocket < Test::Unit::TestCase end while IO.select([r], nil, nil, 0.1).nil? n end - timeout = (defined?(RubyVM::JIT) && RubyVM::JIT.enabled? ? 120 : 30) # for --jit-wait + timeout = (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? ? 120 : 30) # for --jit-wait assert_equal([[s1],[],[]], IO.select([s1], nil, nil, timeout)) msg, _, _, stamp = s1.recvmsg assert_equal("a", msg) assert(stamp.cmsg_is?(:SOCKET, type)) w.close # stop th n = th.value + th = nil n > 1 and warn "UDP packet loss for #{type} over loopback, #{n} tries needed" t2 = Time.now.strftime("%Y-%m-%d") @@ -505,6 +505,10 @@ class TestSocket < Test::Unit::TestCase t = stamp.timestamp assert_match(pat, t.strftime("%Y-%m-%d")) stamp + ensure + if th and !th.join(10) + th.kill.join(10) + end end end @@ -587,7 +591,7 @@ class TestSocket < Test::Unit::TestCase ensure serv_thread.value.close server.close - end + end unless RUBY_PLATFORM.include?("freebsd") def test_connect_timeout host = "127.0.0.1" @@ -766,4 +770,251 @@ class TestSocket < Test::Unit::TestCase s2.close end + def test_resolurion_error_error_code + begin + Socket.getaddrinfo("example.com", 80, "AF_UNIX") + rescue => e + assert_include([Socket::EAI_FAMILY, Socket::EAI_FAIL], e.error_code) + end + end + + def test_tcp_socket_v6_hostname_resolved_earlier + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + begin + server = TCPServer.new("::1", 0) + rescue Errno::EADDRNOTAVAIL # IPv6 is not supported + exit + end + + server_thread = Thread.new { server.accept } + port = server.addr[1] + + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + case family + when Socket::AF_INET6 then [Addrinfo.tcp("::1", port)] + when Socket::AF_INET then sleep(10); [Addrinfo.tcp("127.0.0.1", port)] + end + end + + socket = Socket.tcp("localhost", port) + assert_true(socket.remote_address.ipv6?) + server_thread.value.close + server.close + socket.close if socket && !socket.closed? + end; + end + + def test_tcp_socket_v4_hostname_resolved_earlier + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + server = TCPServer.new("127.0.0.1", 0) + port = server.addr[1] + + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + case family + when Socket::AF_INET6 then sleep(10); [Addrinfo.tcp("::1", port)] + when Socket::AF_INET then [Addrinfo.tcp("127.0.0.1", port)] + end + end + + server_thread = Thread.new { server.accept } + socket = Socket.tcp("localhost", port) + assert_true(socket.remote_address.ipv4?) + server_thread.value.close + server.close + socket.close if socket && !socket.closed? + end; + end + + def test_tcp_socket_v6_hostname_resolved_in_resolution_delay + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + begin + server = TCPServer.new("::1", 0) + rescue Errno::EADDRNOTAVAIL # IPv6 is not supported + exit + end + + port = server.addr[1] + delay_time = 0.025 # Socket::RESOLUTION_DELAY (private) is 0.05 + + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + case family + when Socket::AF_INET6 then sleep(delay_time); [Addrinfo.tcp("::1", port)] + when Socket::AF_INET then [Addrinfo.tcp("127.0.0.1", port)] + end + end + + server_thread = Thread.new { server.accept } + socket = Socket.tcp("localhost", port) + assert_true(socket.remote_address.ipv6?) + server_thread.value.close + server.close + socket.close if socket && !socket.closed? + end; + end + + def test_tcp_socket_v6_hostname_resolved_earlier_and_v6_server_is_not_listening + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + ipv4_address = "127.0.0.1" + ipv4_server = Socket.new(Socket::AF_INET, :STREAM) + ipv4_server.bind(Socket.pack_sockaddr_in(0, ipv4_address)) + port = ipv4_server.connect_address.ip_port + + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + case family + when Socket::AF_INET6 then [Addrinfo.tcp("::1", port)] + when Socket::AF_INET then sleep(0.001); [Addrinfo.tcp(ipv4_address, port)] + end + end + + ipv4_server_thread = Thread.new { ipv4_server.listen(1); ipv4_server.accept } + socket = Socket.tcp("localhost", port) + assert_equal(ipv4_address, socket.remote_address.ip_address) + + accepted, _ = ipv4_server_thread.value + accepted.close + ipv4_server.close + socket.close if socket && !socket.closed? + end; + end + + def test_tcp_socket_resolv_timeout + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + Addrinfo.define_singleton_method(:getaddrinfo) { |*_| sleep } + port = TCPServer.new("localhost", 0).addr[1] + + assert_raise(Errno::ETIMEDOUT) do + Socket.tcp("localhost", port, resolv_timeout: 0.01) + end + end; + end + + def test_tcp_socket_resolv_timeout_with_connection_failure + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + server = TCPServer.new("127.0.0.1", 12345) + _, port, = server.addr + + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + if family == Socket::AF_INET6 + sleep + else + [Addrinfo.tcp("127.0.0.1", port)] + end + end + + server.close + + assert_raise(Errno::ETIMEDOUT) do + Socket.tcp("localhost", port, resolv_timeout: 0.01) + end + end; + end + + def test_tcp_socket_one_hostname_resolution_succeeded_at_least + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + begin + server = TCPServer.new("::1", 0) + rescue Errno::EADDRNOTAVAIL # IPv6 is not supported + exit + end + + port = server.addr[1] + + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + case family + when Socket::AF_INET6 then [Addrinfo.tcp("::1", port)] + when Socket::AF_INET then sleep(0.001); raise SocketError + end + end + + server_thread = Thread.new { server.accept } + socket = nil + + assert_nothing_raised do + socket = Socket.tcp("localhost", port) + end + + server_thread.value.close + server.close + socket.close if socket && !socket.closed? + end; + end + + def test_tcp_socket_all_hostname_resolution_failed + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + case family + when Socket::AF_INET6 then raise SocketError + when Socket::AF_INET then sleep(0.001); raise SocketError, "Last hostname resolution error" + end + end + port = TCPServer.new("localhost", 0).addr[1] + + assert_raise_with_message(SocketError, "Last hostname resolution error") do + Socket.tcp("localhost", port) + end + end; + end + + def test_tcp_socket_v6_address_passed + opts = %w[-rsocket -W1] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + + begin; + begin + server = TCPServer.new("::1", 0) + rescue Errno::EADDRNOTAVAIL # IPv6 is not supported + exit + end + + _, port, = server.addr + + Addrinfo.define_singleton_method(:getaddrinfo) do |*_| + [Addrinfo.tcp("::1", port)] + end + + server_thread = Thread.new { server.accept } + socket = Socket.tcp("::1", port) + + assert_true(socket.remote_address.ipv6?) + server_thread.value.close + server.close + socket.close if socket && !socket.closed? + end; + end + + def test_tcp_socket_fast_fallback_is_false + server = TCPServer.new("127.0.0.1", 0) + _, port, = server.addr + server_thread = Thread.new { server.accept } + socket = Socket.tcp("127.0.0.1", port, fast_fallback: false) + + assert_true(socket.remote_address.ipv4?) + server_thread.value.close + server.close + socket.close if socket && !socket.closed? + end end if defined?(Socket) diff --git a/test/socket/test_sockopt.rb b/test/socket/test_sockopt.rb index f166027d26..7e343e8c36 100644 --- a/test/socket/test_sockopt.rb +++ b/test/socket/test_sockopt.rb @@ -34,7 +34,7 @@ class TestSocketOption < Test::Unit::TestCase } rescue TypeError if /aix/ =~ RUBY_PLATFORM - skip "Known bug in getsockopt(2) on AIX" + omit "Known bug in getsockopt(2) on AIX" end raise $! end diff --git a/test/socket/test_tcp.rb b/test/socket/test_tcp.rb index 9aa716f7ec..7f9dc53cae 100644 --- a/test/socket/test_tcp.rb +++ b/test/socket/test_tcp.rb @@ -70,7 +70,7 @@ class TestSocket_TCPSocket < Test::Unit::TestCase end def test_initialize_connect_timeout - assert_raise(Errno::ETIMEDOUT) do + assert_raise(IO::TimeoutError, Errno::ENETUNREACH) do TCPSocket.new("192.0.2.1", 80, connect_timeout: 0) end end diff --git a/test/socket/test_udp.rb b/test/socket/test_udp.rb index f060b65f2c..4b2b7ab976 100644 --- a/test/socket/test_udp.rb +++ b/test/socket/test_udp.rb @@ -25,7 +25,7 @@ class TestSocket_UDPSocket < Test::Unit::TestCase assert_match(/AF_INET6\b/, sock.inspect) } rescue Errno::EAFNOSUPPORT - skip 'AF_INET6 not supported by kernel' + omit 'AF_INET6 not supported by kernel' end end end diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb index 8c74d0c939..3e7d85befc 100644 --- a/test/socket/test_unix.rb +++ b/test/socket/test_unix.rb @@ -60,6 +60,8 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase assert_not_equal s1.fileno, r.fileno r.close end + rescue NotImplementedError => error + omit error.message end def test_fd_passing_n @@ -150,7 +152,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase lock = Thread::Mutex.new nr = 0 x = 2 - y = 1000 + y = 400 begin s1.send_io(nil) rescue NotImplementedError @@ -334,62 +336,70 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase end def test_noname_path - s1, s2 = UNIXSocket.pair - assert_equal("", s1.path) - assert_equal("", s2.path) - ensure - s1.close - s2.close + if /mswin|mingw/ =~ RUBY_PLATFORM + omit "unnamed pipe is emulated on windows" + end + + UNIXSocket.pair do |s1, s2| + assert_equal("", s1.path) + assert_equal("", s2.path) + end end def test_noname_addr - s1, s2 = UNIXSocket.pair - assert_equal(["AF_UNIX", ""], s1.addr) - assert_equal(["AF_UNIX", ""], s2.addr) - ensure - s1.close - s2.close + if /mswin|mingw/ =~ RUBY_PLATFORM + omit "unnamed pipe is emulated on windows" + end + + UNIXSocket.pair do |s1, s2| + assert_equal(["AF_UNIX", ""], s1.addr) + assert_equal(["AF_UNIX", ""], s2.addr) + end end def test_noname_peeraddr - s1, s2 = UNIXSocket.pair - assert_equal(["AF_UNIX", ""], s1.peeraddr) - assert_equal(["AF_UNIX", ""], s2.peeraddr) - ensure - s1.close - s2.close + if /mswin|mingw/ =~ RUBY_PLATFORM + omit "unnamed pipe is emulated on windows" + end + + UNIXSocket.pair do |s1, s2| + assert_equal(["AF_UNIX", ""], s1.peeraddr) + assert_equal(["AF_UNIX", ""], s2.peeraddr) + end end def test_noname_unpack_sockaddr_un - s1, s2 = UNIXSocket.pair - n = nil - assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != "" - assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != "" - assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getsockname) != "" - assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getpeername) != "" - assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getpeername) != "" - ensure - s1.close - s2.close + if /mswin|mingw/ =~ RUBY_PLATFORM + omit "unnamed pipe is emulated on windows" + end + + UNIXSocket.pair do |s1, s2| + n = nil + assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != "" + assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getsockname) != "" + assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getsockname) != "" + assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s1.getpeername) != "" + assert_equal("", Socket.unpack_sockaddr_un(n)) if (n = s2.getpeername) != "" + end end def test_noname_recvfrom - s1, s2 = UNIXSocket.pair - s2.write("a") - assert_equal(["a", ["AF_UNIX", ""]], s1.recvfrom(10)) - ensure - s1.close - s2.close + if /mswin|mingw/ =~ RUBY_PLATFORM + omit "unnamed pipe is emulated on windows" + end + + UNIXSocket.pair do |s1, s2| + s2.write("a") + assert_equal(["a", ["AF_UNIX", ""]], s1.recvfrom(10)) + end end def test_noname_recv_nonblock - s1, s2 = UNIXSocket.pair - s2.write("a") - IO.select [s1] - assert_equal("a", s1.recv_nonblock(10)) - ensure - s1.close - s2.close + UNIXSocket.pair do |s1, s2| + s2.write("a") + IO.select [s1] + assert_equal("a", s1.recv_nonblock(10)) + end end def test_too_long_path @@ -410,9 +420,10 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase s1.recv_nonblock(10) fail rescue => e - assert(IO::EAGAINWaitReadable === e) - assert(IO::WaitReadable === e) + assert_kind_of(IO::EWOULDBLOCKWaitReadable, e) + assert_kind_of(IO::WaitReadable, e) end + s2.send("", 0) s2.send("haha", 0) s2.send("", 0) @@ -429,12 +440,79 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase rv = s1.recv(100, 0, buf) assert_equal buf.object_id, rv.object_id assert_equal "BBBBBB", rv + rescue Errno::EPROTOTYPE => error + omit error.message + ensure + s1.close if s1 + s2.close if s2 + end + + def test_stream_pair + s1, s2 = UNIXSocket.pair(Socket::SOCK_STREAM) + begin + s1.recv_nonblock(10) + fail + rescue => e + assert_kind_of(IO::EWOULDBLOCKWaitReadable, e) + assert_kind_of(IO::WaitReadable, e) + end + + s2.send("", 0) + s2.send("haha", 0) + assert_equal("haha", s1.recv(10)) + assert_raise(IO::EWOULDBLOCKWaitReadable) { s1.recv_nonblock(10) } + + buf = "".dup + s2.send("BBBBBB", 0) + IO.select([s1]) + rv = s1.recv(100, 0, buf) + assert_equal buf.object_id, rv.object_id + assert_equal "BBBBBB", rv + + s2.close + assert_nil(s1.recv(10)) + rescue Errno::EPROTOTYPE => error + omit error.message + ensure + s1.close if s1 + s2.close if s2 + end + + def test_seqpacket_pair + s1, s2 = UNIXSocket.pair(Socket::SOCK_SEQPACKET) + begin + s1.recv_nonblock(10) + fail + rescue => e + assert_kind_of(IO::EWOULDBLOCKWaitReadable, e) + assert_kind_of(IO::WaitReadable, e) + end + + s2.send("haha", 0) + assert_equal("haha", s1.recv(10)) + assert_raise(IO::EWOULDBLOCKWaitReadable) { s1.recv_nonblock(10) } + + buf = "".dup + s2.send("BBBBBB", 0) + IO.select([s1]) + rv = s1.recv(100, 0, buf) + assert_equal buf.object_id, rv.object_id + assert_equal "BBBBBB", rv + + s2.close + assert_nil(s1.recv(10)) + rescue Errno::EPROTOTYPE, Errno::EPROTONOSUPPORT => error + omit error.message ensure s1.close if s1 s2.close if s2 end def test_dgram_pair_sendrecvmsg_errno_set + if /mswin|mingw/ =~ RUBY_PLATFORM + omit("AF_UNIX + SOCK_DGRAM is not supported on windows") + end + s1, s2 = to_close = UNIXSocket.pair(Socket::SOCK_DGRAM) pipe = IO.pipe to_close.concat(pipe) @@ -457,9 +535,17 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase end def test_epipe # [ruby-dev:34619] + # This is a good example of why reporting the exact `errno` is a terrible + # idea for platform abstractions. + if RUBY_PLATFORM =~ /mswin|mingw/ + error = Errno::ESHUTDOWN + else + error = Errno::EPIPE + end + UNIXSocket.pair {|s1, s2| s1.shutdown(Socket::SHUT_WR) - assert_raise(Errno::EPIPE) { s1.write "a" } + assert_raise(error) { s1.write "a" } assert_equal(nil, s2.read(1)) s2.write "a" assert_equal("a", s1.read(1)) @@ -493,6 +579,45 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase } end + if /mingw|mswin/ =~ RUBY_PLATFORM + + def test_unix_socket_with_encoding + Dir.mktmpdir do |tmpdir| + path = "#{tmpdir}/sockäöü".encode("cp850") + UNIXServer.open(path) do |serv| + assert File.socket?(path) + assert File.stat(path).socket? + assert File.lstat(path).socket? + assert_equal path.encode("utf-8"), serv.path + UNIXSocket.open(path) do |s1| + s2 = serv.accept + s2.close + end + end + end + end + + def test_windows_unix_socket_pair_with_umlaut + otmp = ENV['TMP'] + ENV['TMP'] = File.join(Dir.tmpdir, "äöü€") + FileUtils.mkdir_p ENV['TMP'] + + s1, = UNIXSocket.pair + assert !s1.path.empty? + assert !File.exist?(s1.path) + ensure + FileUtils.rm_rf ENV['TMP'] + ENV['TMP'] = otmp + end + + def test_windows_unix_socket_pair_paths + s1, s2 = UNIXSocket.pair + assert !s1.path.empty? + assert s2.path.empty? + assert !File.exist?(s1.path) + end + end + def test_initialize Dir.mktmpdir {|d| Socket.open(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) {|s| |