diff options
Diffstat (limited to 'test/socket')
| -rw-r--r-- | test/socket/test_addrinfo.rb | 6 | ||||
| -rw-r--r-- | test/socket/test_nonblock.rb | 4 | ||||
| -rw-r--r-- | test/socket/test_socket.rb | 123 | ||||
| -rw-r--r-- | test/socket/test_tcp.rb | 42 | ||||
| -rw-r--r-- | test/socket/test_unix.rb | 21 |
5 files changed, 122 insertions, 74 deletions
diff --git a/test/socket/test_addrinfo.rb b/test/socket/test_addrinfo.rb index c61764d76d..0c9529090e 100644 --- a/test/socket/test_addrinfo.rb +++ b/test/socket/test_addrinfo.rb @@ -360,6 +360,12 @@ class TestSocketAddrinfo < Test::Unit::TestCase assert_raise(Socket::ResolutionError) { Addrinfo.tcp("0.0.0.0", 4649).family_addrinfo("::1", 80) } end + def test_ractor_shareable + assert_ractor(<<~'RUBY', require: 'socket', timeout: 60) + Ractor.make_shareable Addrinfo.new "\x10\x02\x14\xE9\xE0\x00\x00\xFB\x00\x00\x00\x00\x00\x00\x00\x00".b + RUBY + end + def random_port # IANA suggests dynamic port for 49152 to 65535 # http://www.iana.org/assignments/port-numbers diff --git a/test/socket/test_nonblock.rb b/test/socket/test_nonblock.rb index 5a4688bac3..68fefc44b3 100644 --- a/test/socket/test_nonblock.rb +++ b/test/socket/test_nonblock.rb @@ -104,7 +104,7 @@ class TestSocketNonblock < Test::Unit::TestCase assert_raise(IO::WaitReadable) { u1.recvfrom_nonblock(100) } u2.send("", 0, u1.getsockname) assert_nothing_raised("cygwin 1.5.19 has a problem to send an empty UDP packet. [ruby-dev:28915]") { - Timeout.timeout(1) { IO.select [u1] } + Timeout.timeout(30) { IO.select [u1] } } mesg, inet_addr = u1.recvfrom_nonblock(100) assert_equal("", mesg) @@ -126,7 +126,7 @@ class TestSocketNonblock < Test::Unit::TestCase assert_raise(IO::WaitReadable) { u1.recv_nonblock(100) } u2.send("", 0, u1.getsockname) assert_nothing_raised("cygwin 1.5.19 has a problem to send an empty UDP packet. [ruby-dev:28915]") { - Timeout.timeout(1) { IO.select [u1] } + Timeout.timeout(30) { IO.select [u1] } } mesg = u1.recv_nonblock(100) assert_equal("", mesg) diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb index b15cf63297..3b5f5b9d74 100644 --- a/test/socket/test_socket.rb +++ b/test/socket/test_socket.rb @@ -173,8 +173,11 @@ class TestSocket < 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 can fail with "Errno::EACCES: Permission denied - bind(2) for 0.0.0.0:49721" + # or "Test::Unit::ProxyError: Permission denied - bind(2) for 0.0.0.0:55333" + if /mswin|mingw/ =~ RUBY_PLATFORM + errs += [Errno::EACCES, Test::Unit::ProxyError] + end errs end @@ -415,12 +418,16 @@ class TestSocket < Test::Unit::TestCase ping_p = false th = Thread.new { - Socket.udp_server_loop_on(sockets) {|msg, msg_src| - break if msg == "exit" - rmsg = Marshal.dump([msg, msg_src.remote_address, msg_src.local_address]) - ping_p = true - msg_src.reply rmsg - } + begin + Socket.udp_server_loop_on(sockets) {|msg, msg_src| + break if msg == "exit" + rmsg = Marshal.dump([msg, msg_src.remote_address, msg_src.local_address]) + ping_p = true + msg_src.reply rmsg + } + rescue Errno::ENOBUFS + # transient OS error on macOS CI, let client timeout and omit + end } ifaddrs.each {|ifa| @@ -478,9 +485,11 @@ class TestSocket < Test::Unit::TestCase } end - def timestamp_retry_rw(s1, s2, t1, type) + def timestamp_retry_rw(s1, type) IO.pipe do |r,w| + t1 = Time.now # UDP may not be reliable, keep sending until recvmsg returns: + s2 = Socket.new(:INET, :DGRAM, 0) th = Thread.new do n = 0 begin @@ -493,80 +502,54 @@ class TestSocket < Test::Unit::TestCase assert_equal([[s1],[],[]], IO.select([s1], nil, nil, timeout)) msg, _, _, stamp = s1.recvmsg assert_equal("a", msg) - assert(stamp.cmsg_is?(:SOCKET, type)) + assert_send([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") - pat = Regexp.union([t1, t2].uniq) - assert_match(pat, stamp.inspect) - t = stamp.timestamp - assert_match(pat, t.strftime("%Y-%m-%d")) + t2 = Time.now + assert_include(t1..t2, stamp.timestamp) stamp ensure if th and !th.join(10) th.kill.join(10) end + s2.close end end def test_timestamp - return if /linux|freebsd|netbsd|openbsd|solaris|darwin/ !~ RUBY_PLATFORM + return if /linux|freebsd|netbsd|openbsd|darwin/ !~ RUBY_PLATFORM return if !defined?(Socket::AncillaryData) || !defined?(Socket::SO_TIMESTAMP) - t1 = Time.now.strftime("%Y-%m-%d") - stamp = nil Addrinfo.udp("127.0.0.1", 0).bind {|s1| - Addrinfo.udp("127.0.0.1", 0).bind {|s2| - s1.setsockopt(:SOCKET, :TIMESTAMP, true) - stamp = timestamp_retry_rw(s1, s2, t1, :TIMESTAMP) - } + s1.setsockopt(:SOCKET, :TIMESTAMP, true) + timestamp_retry_rw(s1, :TIMESTAMP) } - t = stamp.timestamp - pat = /\.#{"%06d" % t.usec}/ - assert_match(pat, stamp.inspect) end def test_timestampns return if /linux/ !~ RUBY_PLATFORM || !defined?(Socket::SO_TIMESTAMPNS) - t1 = Time.now.strftime("%Y-%m-%d") - stamp = nil Addrinfo.udp("127.0.0.1", 0).bind {|s1| - Addrinfo.udp("127.0.0.1", 0).bind {|s2| - begin - s1.setsockopt(:SOCKET, :TIMESTAMPNS, true) - rescue Errno::ENOPROTOOPT - # SO_TIMESTAMPNS is available since Linux 2.6.22 - return - end - stamp = timestamp_retry_rw(s1, s2, t1, :TIMESTAMPNS) - } + begin + s1.setsockopt(:SOCKET, :TIMESTAMPNS, true) + rescue Errno::ENOPROTOOPT + # SO_TIMESTAMPNS is available since Linux 2.6.22 + return + end + timestamp_retry_rw(s1, :TIMESTAMPNS) } - t = stamp.timestamp - pat = /\.#{"%09d" % t.nsec}/ - assert_match(pat, stamp.inspect) end def test_bintime return if /freebsd/ !~ RUBY_PLATFORM - t1 = Time.now.strftime("%Y-%m-%d") - stamp = nil - Addrinfo.udp("127.0.0.1", 0).bind {|s1| - Addrinfo.udp("127.0.0.1", 0).bind {|s2| - s1.setsockopt(:SOCKET, :BINTIME, true) - s2.send "a", 0, s1.local_address - msg, _, _, stamp = s1.recvmsg - assert_equal("a", msg) - assert(stamp.cmsg_is?(:SOCKET, :BINTIME)) - } + stamp = Addrinfo.udp("127.0.0.1", 0).bind {|s1| + s1.setsockopt(:SOCKET, :BINTIME, true) + timestamp_retry_rw(s1, :BINTIME) } - t2 = Time.now.strftime("%Y-%m-%d") - pat = Regexp.union([t1, t2].uniq) - assert_match(pat, stamp.inspect) t = stamp.timestamp - assert_match(pat, t.strftime("%Y-%m-%d")) - assert_equal(stamp.data[-8,8].unpack("Q")[0], t.subsec * 2**64) + data = stamp.data + assert_equal(data.unpack1("Q", offset: data.bytesize-8), t.subsec * 2**64) end def test_closed_read @@ -906,7 +889,7 @@ class TestSocket < Test::Unit::TestCase Addrinfo.define_singleton_method(:getaddrinfo) { |*_| sleep } - assert_raise(Errno::ETIMEDOUT) do + assert_raise(IO::TimeoutError) do Socket.tcp("localhost", port, resolv_timeout: 0.01) end ensure @@ -931,12 +914,38 @@ class TestSocket < Test::Unit::TestCase server.close - assert_raise(Errno::ETIMEDOUT) do + assert_raise(IO::TimeoutError) do Socket.tcp("localhost", port, resolv_timeout: 0.01) end RUBY end + def test_tcp_socket_open_timeout + opts = %w[-rsocket -W1] + assert_separately opts, <<~RUBY + Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_| + if family == Socket::AF_INET6 + sleep + else + [Addrinfo.tcp("127.0.0.1", 12345)] + end + end + + assert_raise(IO::TimeoutError) do + Socket.tcp("localhost", 12345, open_timeout: 0.01) + end + RUBY + end + + def test_tcp_socket_open_timeout_with_other_timeouts + opts = %w[-rsocket -W1] + assert_separately opts, <<~RUBY + assert_raise(ArgumentError) do + Socket.tcp("localhost", 12345, open_timeout: 0.01, resolv_timout: 0.01) + end + RUBY + end + def test_tcp_socket_one_hostname_resolution_succeeded_at_least opts = %w[-rsocket -W1] assert_separately opts, <<~RUBY @@ -982,7 +991,7 @@ class TestSocket < Test::Unit::TestCase 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" + when Socket::AF_INET then sleep(0.01); raise SocketError, "Last hostname resolution error" end end diff --git a/test/socket/test_tcp.rb b/test/socket/test_tcp.rb index e6a41f5660..d689ab2376 100644 --- a/test/socket/test_tcp.rb +++ b/test/socket/test_tcp.rb @@ -18,6 +18,12 @@ class TestSocket_TCPSocket < Test::Unit::TestCase end def test_initialize_failure + assert_raise(Socket::ResolutionError) do + t = TCPSocket.open(nil, nil) + ensure + t&.close + end + # These addresses are chosen from TEST-NET-1, TEST-NET-2, and TEST-NET-3. # [RFC 5737] # They are chosen because probably they are not used as a host address. @@ -43,16 +49,14 @@ class TestSocket_TCPSocket < Test::Unit::TestCase server_addr = '127.0.0.1' server_port = 80 - begin + e = assert_raise_kind_of(SystemCallError) do # Since client_addr is not an IP address of this host, # bind() in TCPSocket.new should fail as EADDRNOTAVAIL. t = TCPSocket.new(server_addr, server_port, client_addr, client_port) - flunk "expected SystemCallError" - rescue SystemCallError => e - assert_match "for \"#{client_addr}\" port #{client_port}", e.message + ensure + t&.close end - ensure - t.close if t && !t.closed? + assert_include e.message, "for \"#{client_addr}\" port #{client_port}" end def test_initialize_resolv_timeout @@ -69,6 +73,30 @@ class TestSocket_TCPSocket < Test::Unit::TestCase end end + def test_tcp_initialize_open_timeout + return if RUBY_PLATFORM =~ /mswin|mingw|cygwin/ + + server = TCPServer.new("127.0.0.1", 0) + port = server.connect_address.ip_port + server.close + + assert_raise(IO::TimeoutError) do + TCPSocket.new( + "localhost", + port, + open_timeout: 0.01, + fast_fallback: true, + test_mode_settings: { delay: { ipv4: 1000 } } + ) + end + end + + def test_initialize_open_timeout_with_other_timeouts + assert_raise(ArgumentError) do + TCPSocket.new("localhost", 12345, open_timeout: 0.01, resolv_timeout: 0.01) + end + end + def test_initialize_connect_timeout assert_raise(IO::TimeoutError, Errno::ENETUNREACH, Errno::EACCES) do TCPSocket.new("192.0.2.1", 80, connect_timeout: 0) @@ -293,7 +321,7 @@ class TestSocket_TCPSocket < Test::Unit::TestCase port = server.connect_address.ip_port server.close - assert_raise(Errno::ETIMEDOUT) do + assert_raise(IO::TimeoutError) do TCPSocket.new( "localhost", port, diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb index 3e7d85befc..e239e3935b 100644 --- a/test/socket/test_unix.rb +++ b/test/socket/test_unix.rb @@ -146,6 +146,7 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase end def test_fd_passing_race_condition + omit 'randomly crashes on macOS' if RUBY_PLATFORM =~ /darwin/ r1, w = IO.pipe s1, s2 = UNIXSocket.pair s1.nonblock = s2.nonblock = true @@ -292,14 +293,18 @@ class TestSocket_UNIXSocket < Test::Unit::TestCase File.unlink path if path && File.socket?(path) end - def test_open_nul_byte - tmpfile = Tempfile.new("s") - path = tmpfile.path - tmpfile.close(true) - assert_raise(ArgumentError) {UNIXServer.open(path+"\0")} - assert_raise(ArgumentError) {UNIXSocket.open(path+"\0")} - ensure - File.unlink path if path && File.socket?(path) + def test_open_argument + assert_raise(TypeError) {UNIXServer.new(nil)} + assert_raise(TypeError) {UNIXServer.new(1)} + Tempfile.create("s") do |s| + path = s.path + s.close + File.unlink(path) + assert_raise(ArgumentError) {UNIXServer.open(path+"\0")} + assert_raise(ArgumentError) {UNIXSocket.open(path+"\0")} + arg = Struct.new(:to_path).new(path) + assert_equal(path, UNIXServer.open(arg) { |server| server.path }) + end end def test_addr |
