1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
eregon 2018-08-03 16:19:40 +00:00
parent aeeaadaad0
commit b53cf149ad
246 changed files with 9108 additions and 548 deletions

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket::BasicSocket#close_read" do
@ -15,13 +15,13 @@ describe "Socket::BasicSocket#close_read" do
lambda { @server.read }.should raise_error(IOError)
end
it "it works on sockets with closed ends" do
it 'does not raise when called on a socket already closed for reading' do
@server.close_read
@server.close_read
lambda { @server.close_read }.should_not raise_error(Exception)
lambda { @server.read }.should raise_error(IOError)
end
it "does not close the socket" do
it 'does not fully close the socket' do
@server.close_read
@server.closed?.should be_false
end
@ -32,7 +32,7 @@ describe "Socket::BasicSocket#close_read" do
@server.closed?.should be_true
end
it "raises IOError on closed socket" do
it 'raises IOError when called on a fully closed socket' do
@server.close
lambda { @server.close_read }.should raise_error(IOError)
end

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket::BasicSocket#close_write" do
@ -15,13 +15,13 @@ describe "Socket::BasicSocket#close_write" do
lambda { @server.write("foo") }.should raise_error(IOError)
end
it "works on sockets with closed write ends" do
it 'does not raise when called on a socket already closed for writing' do
@server.close_write
@server.close_write
lambda { @server.close_write }.should_not raise_error(Exception)
lambda { @server.write("foo") }.should raise_error(IOError)
end
it "does not close the socket" do
it 'does not fully close the socket' do
@server.close_write
@server.closed?.should be_false
end
@ -37,7 +37,7 @@ describe "Socket::BasicSocket#close_write" do
@server.closed?.should be_true
end
it "raises IOError on closed socket" do
it 'raises IOError when called on a fully closed socket' do
@server.close
lambda { @server.close_write }.should raise_error(IOError)
end

View file

@ -0,0 +1,150 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'Socket#connect_address' do
describe 'using an unbound socket' do
after do
@sock.close
end
it 'raises SocketError' do
@sock = Socket.new(:INET, :STREAM)
lambda { @sock.connect_address }.should raise_error(SocketError)
end
end
describe 'using a socket bound to 0.0.0.0' do
before do
@sock = Socket.new(:INET, :STREAM)
@sock.bind(Socket.sockaddr_in(0, '0.0.0.0'))
end
after do
@sock.close
end
it 'returns an Addrinfo' do
@sock.connect_address.should be_an_instance_of(Addrinfo)
end
it 'uses 127.0.0.1 as the IP address' do
@sock.connect_address.ip_address.should == '127.0.0.1'
end
it 'uses the correct port number' do
@sock.connect_address.ip_port.should > 0
end
it 'uses AF_INET as the address family' do
@sock.connect_address.afamily.should == Socket::AF_INET
end
it 'uses PF_INET as the address family' do
@sock.connect_address.pfamily.should == Socket::PF_INET
end
it 'uses SOCK_STREAM as the socket type' do
@sock.connect_address.socktype.should == Socket::SOCK_STREAM
end
it 'uses 0 as the protocol' do
@sock.connect_address.protocol.should == 0
end
end
describe 'using a socket bound to ::' do
before do
@sock = Socket.new(:INET6, :STREAM)
@sock.bind(Socket.sockaddr_in(0, '::'))
end
after do
@sock.close
end
it 'returns an Addrinfo' do
@sock.connect_address.should be_an_instance_of(Addrinfo)
end
it 'uses ::1 as the IP address' do
@sock.connect_address.ip_address.should == '::1'
end
it 'uses the correct port number' do
@sock.connect_address.ip_port.should > 0
end
it 'uses AF_INET6 as the address family' do
@sock.connect_address.afamily.should == Socket::AF_INET6
end
it 'uses PF_INET6 as the address family' do
@sock.connect_address.pfamily.should == Socket::PF_INET6
end
it 'uses SOCK_STREAM as the socket type' do
@sock.connect_address.socktype.should == Socket::SOCK_STREAM
end
it 'uses 0 as the protocol' do
@sock.connect_address.protocol.should == 0
end
end
with_feature :unix_socket do
describe 'using an unbound UNIX socket' do
before do
@path = SocketSpecs.socket_path
@server = UNIXServer.new(@path)
@client = UNIXSocket.new(@path)
end
after do
@client.close
@server.close
rm_r(@path)
end
it 'raises SocketError' do
lambda { @client.connect_address }.should raise_error(SocketError)
end
end
describe 'using a bound UNIX socket' do
before do
@path = SocketSpecs.socket_path
@sock = UNIXServer.new(@path)
end
after do
@sock.close
rm_r(@path)
end
it 'returns an Addrinfo' do
@sock.connect_address.should be_an_instance_of(Addrinfo)
end
it 'uses the correct socket path' do
@sock.connect_address.unix_path.should == @path
end
it 'uses AF_UNIX as the address family' do
@sock.connect_address.afamily.should == Socket::AF_UNIX
end
it 'uses PF_UNIX as the protocol family' do
@sock.connect_address.pfamily.should == Socket::PF_UNIX
end
it 'uses SOCK_STREAM as the socket type' do
@sock.connect_address.socktype.should == Socket::SOCK_STREAM
end
it 'uses 0 as the protocol' do
@sock.connect_address.protocol.should == 0
end
end
end
end

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "BasicSocket.do_not_reverse_lookup" do

View file

@ -1,14 +1,14 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "BasicSocket#for_fd" do
describe "BasicSocket.for_fd" do
before :each do
@server = TCPServer.new(0)
@s2 = nil
end
after :each do
@socket1.close if @socket1
@server.close if @server
end
@ -18,4 +18,21 @@ describe "BasicSocket#for_fd" do
@s2.should be_kind_of(TCPServer)
@s2.fileno.should == @server.fileno
end
it 'returns a new socket for a file descriptor' do
@socket1 = Socket.new(:INET, :DGRAM)
socket2 = Socket.for_fd(@socket1.fileno)
socket2.autoclose = false
socket2.should be_an_instance_of(Socket)
socket2.fileno.should == @socket1.fileno
end
it 'sets the socket into binary mode' do
@socket1 = Socket.new(:INET, :DGRAM)
socket2 = Socket.for_fd(@socket1.fileno)
socket2.autoclose = false
socket2.binmode?.should be_true
end
end

View file

@ -0,0 +1,36 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'BasicSocket#getpeereid' do
with_feature :unix_socket do
describe 'using a UNIXSocket' do
before do
@path = SocketSpecs.socket_path
@server = UNIXServer.new(@path)
@client = UNIXSocket.new(@path)
end
after do
@client.close
@server.close
rm_r(@path)
end
it 'returns an Array with the user and group ID' do
@client.getpeereid.should == [Process.euid, Process.egid]
end
end
end
describe 'using an IPSocket' do
after do
@sock.close
end
it 'raises NoMethodError' do
@sock = TCPServer.new('127.0.0.1', 0)
lambda { @sock.getpeereid }.should raise_error(NoMethodError)
end
end
end

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket::BasicSocket#getpeername" do
@ -19,8 +19,7 @@ describe "Socket::BasicSocket#getpeername" do
@client.getpeername.should == server_sockaddr
end
# Catch general exceptions to prevent NotImplementedError
it "raises an error if socket's not connected" do
lambda { @server.getpeername }.should raise_error(Exception)
it 'raises Errno::ENOTCONN for a disconnected socket' do
lambda { @server.getpeername }.should raise_error(Errno::ENOTCONN)
end
end

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket::BasicSocket#getsockname" do
@ -20,7 +20,7 @@ describe "Socket::BasicSocket#getsockname" do
sockaddr[0].should == @socket.addr[1]
end
it "returns empty sockaddr for unbinded sockets" do
it 'returns a default socket address for a disconnected socket' do
@socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
sockaddr = Socket.unpack_sockaddr_in(@socket.getsockname)
sockaddr.should == [0, "0.0.0.0"]

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "BasicSocket#getsockopt" do
@ -43,4 +43,146 @@ describe "BasicSocket#getsockopt" do
it "raises a SystemCallError with an invalid socket option" do
lambda { @sock.getsockopt Socket::SOL_SOCKET, -1 }.should raise_error(Errno::ENOPROTOOPT)
end
it 'returns a Socket::Option using a constant' do
opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE)
opt.should be_an_instance_of(Socket::Option)
end
it 'returns a Socket::Option for a boolean option' do
opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR)
opt.bool.should == false
end
it 'returns a Socket::Option for a numeric option' do
opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)
opt.int.should be_an_instance_of(Fixnum)
end
it 'returns a Socket::Option for a struct option' do
opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER)
opt.linger.should == [false, 0]
end
it 'raises Errno::ENOPROTOOPT when requesting an invalid option' do
lambda { @sock.getsockopt(Socket::SOL_SOCKET, -1) }.should raise_error(Errno::ENOPROTOOPT)
end
describe 'using Symbols as arguments' do
it 'returns a Socket::Option for arguments :SOCKET and :TYPE' do
opt = @sock.getsockopt(:SOCKET, :TYPE)
opt.level.should == Socket::SOL_SOCKET
opt.optname.should == Socket::SO_TYPE
end
it 'returns a Socket::Option for arguments :IP and :TTL' do
opt = @sock.getsockopt(:IP, :TTL)
opt.level.should == Socket::IPPROTO_IP
opt.optname.should == Socket::IP_TTL
end
it 'returns a Socket::Option for arguments :SOCKET and :REUSEADDR' do
opt = @sock.getsockopt(:SOCKET, :REUSEADDR)
opt.level.should == Socket::SOL_SOCKET
opt.optname.should == Socket::SO_REUSEADDR
end
it 'returns a Socket::Option for arguments :SOCKET and :LINGER' do
opt = @sock.getsockopt(:SOCKET, :LINGER)
opt.level.should == Socket::SOL_SOCKET
opt.optname.should == Socket::SO_LINGER
end
with_feature :udp_cork do
it 'returns a Socket::Option for arguments :UDP and :CORK' do
sock = Socket.new(:INET, :DGRAM)
begin
opt = sock.getsockopt(:UDP, :CORK)
opt.level.should == Socket::IPPROTO_UDP
opt.optname.should == Socket::UDP_CORK
ensure
sock.close
end
end
end
end
describe 'using Strings as arguments' do
it 'returns a Socket::Option for arguments "SOCKET" and "TYPE"' do
opt = @sock.getsockopt("SOCKET", "TYPE")
opt.level.should == Socket::SOL_SOCKET
opt.optname.should == Socket::SO_TYPE
end
it 'returns a Socket::Option for arguments "IP" and "TTL"' do
opt = @sock.getsockopt("IP", "TTL")
opt.level.should == Socket::IPPROTO_IP
opt.optname.should == Socket::IP_TTL
end
it 'returns a Socket::Option for arguments "SOCKET" and "REUSEADDR"' do
opt = @sock.getsockopt("SOCKET", "REUSEADDR")
opt.level.should == Socket::SOL_SOCKET
opt.optname.should == Socket::SO_REUSEADDR
end
it 'returns a Socket::Option for arguments "SOCKET" and "LINGER"' do
opt = @sock.getsockopt("SOCKET", "LINGER")
opt.level.should == Socket::SOL_SOCKET
opt.optname.should == Socket::SO_LINGER
end
with_feature :udp_cork do
it 'returns a Socket::Option for arguments "UDP" and "CORK"' do
sock = Socket.new("INET", "DGRAM")
begin
opt = sock.getsockopt("UDP", "CORK")
opt.level.should == Socket::IPPROTO_UDP
opt.optname.should == Socket::UDP_CORK
ensure
sock.close
end
end
end
end
describe 'using a String based option' do
it 'allows unpacking of a boolean option' do
opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR).to_s
opt.unpack('i').should == [0]
end
it 'allows unpacking of a numeric option' do
opt = @sock.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL).to_s
array = opt.unpack('i')
array[0].should be_an_instance_of(Fixnum)
array[0].should > 0
end
it 'allows unpacking of a struct option' do
opt = @sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_LINGER).to_s
if opt.bytesize == 8
opt.unpack('ii').should == [0, 0]
else
opt.unpack('i').should == [0]
end
end
end
end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper'
require 'socket'
require_relative '../spec_helper'
describe "Socket::BasicSocket#ioctl" do
platform_is :linux do

View file

@ -1,7 +1,65 @@
require_relative '../../../spec_helper'
require_relative '../shared/recv_nonblock'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket::BasicSocket#recv_nonblock" do
it_behaves_like :socket_recv_nonblock, :recv_nonblock
SocketSpecs.each_ip_protocol do |family, ip_address|
before :each do
@s1 = Socket.new(family, :DGRAM)
@s2 = Socket.new(family, :DGRAM)
end
after :each do
@s1.close unless @s1.closed?
@s2.close unless @s2.closed?
end
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises an exception extending IO::WaitReadable' do
lambda { @s1.recv_nonblock(1) }.should raise_error(IO::WaitReadable)
end
end
end
it "raises an exception extending IO::WaitReadable if there's no data available" do
@s1.bind(Socket.pack_sockaddr_in(0, ip_address))
lambda {
@s1.recv_nonblock(5)
}.should raise_error(IO::WaitReadable) { |e|
platform_is_not :windows do
e.should be_kind_of(Errno::EAGAIN)
end
platform_is :windows do
e.should be_kind_of(Errno::EWOULDBLOCK)
end
}
end
it "receives data after it's ready" do
@s1.bind(Socket.pack_sockaddr_in(0, ip_address))
@s2.send("aaa", 0, @s1.getsockname)
IO.select([@s1], nil, nil, 2)
@s1.recv_nonblock(5).should == "aaa"
end
it "allows an output buffer as third argument" do
@s1.bind(Socket.pack_sockaddr_in(0, ip_address))
@s2.send("data", 0, @s1.getsockname)
IO.select([@s1], nil, nil, 2)
buf = "foo"
@s1.recv_nonblock(5, 0, buf)
buf.should == "data"
end
it "does not block if there's no data available" do
@s1.bind(Socket.pack_sockaddr_in(0, ip_address))
@s2.send("a", 0, @s1.getsockname)
IO.select([@s1], nil, nil, 2)
@s1.recv_nonblock(1).should == "a"
lambda {
@s1.recv_nonblock(5)
}.should raise_error(IO::WaitReadable)
end
end
end

View file

@ -1,5 +1,5 @@
# -*- encoding: binary -*-
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "BasicSocket#recv" do
@ -92,3 +92,68 @@ describe "BasicSocket#recv" do
socket.close
end
end
describe 'BasicSocket#recv' do
SocketSpecs.each_ip_protocol do |family, ip_address|
before do
@server = Socket.new(family, :DGRAM)
@client = Socket.new(family, :DGRAM)
end
after do
@client.close
@server.close
end
describe 'using an unbound socket' do
it 'blocks the caller' do
lambda { @server.recv(4) }.should block_caller
end
end
describe 'using a bound socket' do
before do
@server.bind(Socket.sockaddr_in(0, ip_address))
end
describe 'without any data available' do
it 'blocks the caller' do
lambda { @server.recv(4) }.should block_caller
end
end
describe 'with data available' do
before do
@client.connect(@server.getsockname)
end
it 'reads the given amount of bytes' do
@client.write('hello')
@server.recv(2).should == 'he'
end
it 'reads the given amount of bytes when it exceeds the data size' do
@client.write('he')
@server.recv(6).should == 'he'
end
it 'blocks the caller when called twice without new data being available' do
@client.write('hello')
@server.recv(2).should == 'he'
lambda { @server.recv(4) }.should block_caller
end
it 'takes a peek at the data when using the MSG_PEEK flag' do
@client.write('hello')
@server.recv(2, Socket::MSG_PEEK).should == 'he'
@server.recv(2).should == 'he'
end
end
end
end
end

View file

@ -0,0 +1,204 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'BasicSocket#recvmsg_nonblock' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'using a disconnected socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
end
after do
@client.close
@server.close
end
platform_is_not :windows do
describe 'using an unbound socket' do
it 'raises an exception extending IO::WaitReadable' do
lambda { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable)
end
end
end
describe 'using a bound socket' do
before do
@server.bind(Socket.sockaddr_in(0, ip_address))
end
describe 'without any data available' do
it 'raises an exception extending IO::WaitReadable' do
lambda { @server.recvmsg_nonblock }.should raise_error(IO::WaitReadable)
end
end
describe 'with data available' do
before do
@client.connect(@server.getsockname)
@client.write('hello')
IO.select([@server], nil, nil, 5)
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
@server.recvmsg_nonblock.should be_an_instance_of(Array)
end
describe 'without a maximum message length' do
it 'reads all the available data' do
@server.recvmsg_nonblock[0].should == 'hello'
end
end
describe 'with a maximum message length' do
platform_is_not :windows do
it 'reads up to the maximum amount of bytes' do
@server.recvmsg_nonblock(2)[0].should == 'he'
end
end
end
describe 'the returned Array' do
before do
@array = @server.recvmsg_nonblock
end
it 'stores the message at index 0' do
@array[0].should == 'hello'
end
it 'stores an Addrinfo at index 1' do
@array[1].should be_an_instance_of(Addrinfo)
end
platform_is_not :windows do
it 'stores the flags at index 2' do
@array[2].should be_an_instance_of(Fixnum)
end
end
describe 'the returned Addrinfo' do
before do
@addr = @array[1]
end
it 'uses the IP address of the client' do
@addr.ip_address.should == @client.local_address.ip_address
end
it 'uses the correct address family' do
@addr.afamily.should == family
end
it 'uses the correct protocol family' do
@addr.pfamily.should == family
end
it 'uses the correct socket type' do
@addr.socktype.should == Socket::SOCK_DGRAM
end
it 'uses the port number of the client' do
@addr.ip_port.should == @client.local_address.ip_port
end
end
end
end
end
end
platform_is_not :windows do
describe 'using a connected socket' do
before do
@client = Socket.new(family, :STREAM)
@server = Socket.new(family, :STREAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
@server.listen(1)
@client.connect(@server.getsockname)
end
after do
@client.close
@server.close
end
describe 'without any data available' do
it 'raises IO::WaitReadable' do
lambda {
socket, _ = @server.accept
begin
socket.recvmsg_nonblock
ensure
socket.close
end
}.should raise_error(IO::WaitReadable)
end
end
describe 'with data available' do
before do
@client.write('hello')
@socket, _ = @server.accept
end
after do
@socket.close
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
@socket.recvmsg_nonblock.should be_an_instance_of(Array)
end
describe 'the returned Array' do
before do
@array = @socket.recvmsg_nonblock
end
it 'stores the message at index 0' do
@array[0].should == 'hello'
end
it 'stores an Addrinfo at index 1' do
@array[1].should be_an_instance_of(Addrinfo)
end
it 'stores the flags at index 2' do
@array[2].should be_an_instance_of(Fixnum)
end
describe 'the returned Addrinfo' do
before do
@addr = @array[1]
end
it 'raises when receiving the ip_address message' do
lambda { @addr.ip_address }.should raise_error(SocketError)
end
it 'uses the correct address family' do
@addr.afamily.should == Socket::AF_UNSPEC
end
it 'uses 0 for the protocol family' do
@addr.pfamily.should == 0
end
it 'uses the correct socket type' do
@addr.socktype.should == Socket::SOCK_STREAM
end
it 'raises when receiving the ip_port message' do
lambda { @addr.ip_port }.should raise_error(SocketError)
end
end
end
end
end
end
end
end

View file

@ -0,0 +1,197 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'BasicSocket#recvmsg' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'using a disconnected socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
end
after do
@client.close
@server.close
end
platform_is_not :windows do
describe 'using an unbound socket' do
it 'blocks the caller' do
lambda { @server.recvmsg }.should block_caller
end
end
end
describe 'using a bound socket' do
before do
@server.bind(Socket.sockaddr_in(0, ip_address))
end
describe 'without any data available' do
it 'blocks the caller' do
lambda { @server.recvmsg }.should block_caller
end
end
describe 'with data available' do
before do
@client.connect(@server.getsockname)
@client.write('hello')
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
@server.recvmsg.should be_an_instance_of(Array)
end
describe 'without a maximum message length' do
it 'reads all the available data' do
@server.recvmsg[0].should == 'hello'
end
end
describe 'with a maximum message length' do
it 'reads up to the maximum amount of bytes' do
@server.recvmsg(2)[0].should == 'he'
end
end
describe 'the returned Array' do
before do
@array = @server.recvmsg
end
it 'stores the message at index 0' do
@array[0].should == 'hello'
end
it 'stores an Addrinfo at index 1' do
@array[1].should be_an_instance_of(Addrinfo)
end
platform_is_not :windows do
it 'stores the flags at index 2' do
@array[2].should be_an_instance_of(Fixnum)
end
end
describe 'the returned Addrinfo' do
before do
@addr = @array[1]
end
it 'uses the IP address of the client' do
@addr.ip_address.should == @client.local_address.ip_address
end
it 'uses the correct address family' do
@addr.afamily.should == family
end
it 'uses the correct protocol family' do
@addr.pfamily.should == family
end
it 'uses the correct socket type' do
@addr.socktype.should == Socket::SOCK_DGRAM
end
it 'uses the port number of the client' do
@addr.ip_port.should == @client.local_address.ip_port
end
end
end
end
end
end
platform_is_not :windows do
describe 'using a connected socket' do
before do
@client = Socket.new(family, :STREAM)
@server = Socket.new(family, :STREAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
@server.listen(1)
@client.connect(@server.getsockname)
end
after do
@client.close
@server.close
end
describe 'without any data available' do
it 'blocks the caller' do
socket, _ = @server.accept
begin
lambda { socket.recvmsg }.should block_caller
ensure
socket.close
end
end
end
describe 'with data available' do
before do
@client.write('hello')
@socket, _ = @server.accept
end
after do
@socket.close
end
it 'returns an Array containing the data, an Addrinfo and the flags' do
@socket.recvmsg.should be_an_instance_of(Array)
end
describe 'the returned Array' do
before do
@array = @socket.recvmsg
end
it 'stores the message at index 0' do
@array[0].should == 'hello'
end
it 'stores an Addrinfo at index 1' do
@array[1].should be_an_instance_of(Addrinfo)
end
it 'stores the flags at index 2' do
@array[2].should be_an_instance_of(Fixnum)
end
describe 'the returned Addrinfo' do
before do
@addr = @array[1]
end
it 'raises when receiving the ip_address message' do
lambda { @addr.ip_address }.should raise_error(SocketError)
end
it 'uses the correct address family' do
@addr.afamily.should == Socket::AF_UNSPEC
end
it 'returns 0 for the protocol family' do
@addr.pfamily.should == 0
end
it 'uses the correct socket type' do
@addr.socktype.should == Socket::SOCK_STREAM
end
it 'raises when receiving the ip_port message' do
lambda { @addr.ip_port }.should raise_error(SocketError)
end
end
end
end
end
end
end
end

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "BasicSocket#send" do
@ -83,3 +83,132 @@ describe "BasicSocket#send" do
data.should == 'hello'
end
end
describe 'BasicSocket#send' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'using a disconnected socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@client.close
@server.close
end
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
lambda { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
end
end
describe 'with a destination address as a String' do
it 'returns the amount of sent bytes' do
@client.send('hello', 0, @server.getsockname).should == 5
end
it 'does not persist the connection after writing to the socket' do
@client.send('hello', 0, @server.getsockname)
lambda { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
end
end
describe 'with a destination address as an Addrinfo' do
it 'returns the amount of sent bytes' do
@client.send('hello', 0, @server.connect_address).should == 5
end
end
end
describe 'using a connected UDP socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@client.close
@server.close
end
describe 'without a destination address argument' do
before do
@client.connect(@server.getsockname)
end
it 'returns the amount of bytes written' do
@client.send('hello', 0).should == 5
end
end
describe 'with a destination address argument' do
before do
@alt_server = Socket.new(family, :DGRAM)
@alt_server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@alt_server.close
end
it 'sends the message to the given address instead' do
@client.send('hello', 0, @alt_server.getsockname).should == 5
lambda { @server.recv(5) }.should block_caller
@alt_server.recv(5).should == 'hello'
end
it 'does not persist the alternative connection after writing to the socket' do
@client.send('hello', 0, @alt_server.getsockname)
@client.connect(@server.getsockname)
@client.send('world', 0)
@server.recv(5).should == 'world'
end
end
end
platform_is_not :windows do
describe 'using a connected TCP socket' do
before do
@client = Socket.new(family, :STREAM)
@server = Socket.new(family, :STREAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
@server.listen(1)
@client.connect(@server.getsockname)
end
after do
@client.close
@server.close
end
describe 'using the MSG_OOB flag' do
it 'sends an out-of-band message' do
@server.setsockopt(:SOCKET, :OOBINLINE, true)
@client.send('a', Socket::MSG_OOB).should == 1
socket, _ = @server.accept
begin
socket.recv(1, Socket::MSG_OOB).should == 'a'
ensure
socket.close
end
end
end
end
end
end
end

View file

@ -0,0 +1,104 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'BasicSocket#sendmsg_nonblock' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'using a disconnected socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@client.close
@server.close
end
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
lambda { @client.sendmsg_nonblock('hello') }.should raise_error(SocketSpecs.dest_addr_req_error)
end
end
describe 'with a destination address as a String' do
it 'returns the amount of sent bytes' do
@client.sendmsg_nonblock('hello', 0, @server.getsockname).should == 5
end
end
describe 'with a destination address as an Addrinfo' do
it 'returns the amount of sent bytes' do
@client.sendmsg_nonblock('hello', 0, @server.connect_address).should == 5
end
end
end
describe 'using a connected UDP socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@client.close
@server.close
end
describe 'without a destination address argument' do
before do
@client.connect(@server.getsockname)
end
it 'returns the amount of bytes written' do
@client.sendmsg_nonblock('hello').should == 5
end
end
describe 'with a destination address argument' do
before do
@alt_server = Socket.new(family, :DGRAM)
@alt_server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@alt_server.close
end
it 'sends the message to the given address instead' do
@client.sendmsg_nonblock('hello', 0, @alt_server.getsockname).should == 5
lambda { @server.recv(5) }.should block_caller
@alt_server.recv(5).should == 'hello'
end
end
end
platform_is_not :windows do
describe 'using a connected TCP socket' do
before do
@client = Socket.new(family, :STREAM)
@server = Socket.new(family, :STREAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
@server.listen(1)
@client.connect(@server.getsockname)
end
after do
@client.close
@server.close
end
it 'raises IO::WaitWritable when the underlying buffer is full' do
lambda {
10.times { @client.sendmsg_nonblock('hello' * 1_000_000) }
}.should raise_error(IO::WaitWritable)
end
end
end
end
end

View file

@ -0,0 +1,111 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'BasicSocket#sendmsg' do
SocketSpecs.each_ip_protocol do |family, ip_address|
describe 'using a disconnected socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@client.close
@server.close
end
platform_is_not :windows do
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
lambda { @client.sendmsg('hello') }.should raise_error(SocketSpecs.dest_addr_req_error)
end
end
end
describe 'with a destination address as a String' do
it 'returns the amount of sent bytes' do
@client.sendmsg('hello', 0, @server.getsockname).should == 5
end
end
describe 'with a destination address as an Addrinfo' do
it 'returns the amount of sent bytes' do
@client.sendmsg('hello', 0, @server.connect_address).should == 5
end
end
end
describe 'using a connected UDP socket' do
before do
@client = Socket.new(family, :DGRAM)
@server = Socket.new(family, :DGRAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@client.close
@server.close
end
describe 'without a destination address argument' do
before do
@client.connect(@server.getsockname)
end
it 'returns the amount of bytes written' do
@client.sendmsg('hello').should == 5
end
end
describe 'with a destination address argument' do
before do
@alt_server = Socket.new(family, :DGRAM)
@alt_server.bind(Socket.sockaddr_in(0, ip_address))
end
after do
@alt_server.close
end
it 'sends the message to the given address instead' do
@client.sendmsg('hello', 0, @alt_server.getsockname).should == 5
lambda { @server.recv(5) }.should block_caller
@alt_server.recv(5).should == 'hello'
end
end
end
platform_is_not :windows do # spurious
describe 'using a connected TCP socket' do
before do
@client = Socket.new(family, :STREAM)
@server = Socket.new(family, :STREAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
@server.listen(1)
@client.connect(@server.getsockname)
end
after do
@client.close
@server.close
end
it 'blocks when the underlying buffer is full' do
# Buffer sizes may differ per platform, so sadly this is the only
# reliable way of testing blocking behaviour.
lambda do
10.times { @client.sendmsg('hello' * 1_000_000) }
end.should block_caller
end
end
end
end
end

View file

@ -1,4 +1,4 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "BasicSocket#setsockopt" do
@ -211,3 +211,124 @@ describe "BasicSocket#setsockopt" do
end
end
end
describe 'BasicSocket#setsockopt' do
describe 'using a STREAM socket' do
before do
@socket = Socket.new(:INET, :STREAM)
end
after do
@socket.close
end
describe 'using separate arguments with Symbols' do
it 'raises TypeError when the first argument is nil' do
lambda { @socket.setsockopt(nil, :REUSEADDR, true) }.should raise_error(TypeError)
end
it 'sets a boolean option' do
@socket.setsockopt(:SOCKET, :REUSEADDR, true).should == 0
@socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
end
it 'sets an integer option' do
@socket.setsockopt(:IP, :TTL, 255).should == 0
@socket.getsockopt(:IP, :TTL).int.should == 255
end
it 'sets an IPv6 boolean option' do
socket = Socket.new(:INET6, :STREAM)
begin
socket.setsockopt(:IPV6, :V6ONLY, true).should == 0
socket.getsockopt(:IPV6, :V6ONLY).bool.should == true
ensure
socket.close
end
end
platform_is_not :windows do
it 'raises Errno::EINVAL when setting an invalid option value' do
lambda { @socket.setsockopt(:SOCKET, :OOBINLINE, 'bla') }.should raise_error(Errno::EINVAL)
end
end
end
describe 'using separate arguments with Symbols' do
it 'sets a boolean option' do
@socket.setsockopt('SOCKET', 'REUSEADDR', true).should == 0
@socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
end
it 'sets an integer option' do
@socket.setsockopt('IP', 'TTL', 255).should == 0
@socket.getsockopt(:IP, :TTL).int.should == 255
end
end
describe 'using separate arguments with constants' do
it 'sets a boolean option' do
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true).should == 0
@socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
end
it 'sets an integer option' do
@socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, 255).should == 0
@socket.getsockopt(:IP, :TTL).int.should == 255
end
end
describe 'using separate arguments with custom objects' do
it 'sets a boolean option' do
level = mock(:level)
name = mock(:name)
level.stub!(:to_str).and_return('SOCKET')
name.stub!(:to_str).and_return('REUSEADDR')
@socket.setsockopt(level, name, true).should == 0
end
end
describe 'using a Socket::Option as the first argument' do
it 'sets a boolean option' do
@socket.setsockopt(Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)).should == 0
@socket.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
end
it 'sets an integer option' do
@socket.setsockopt(Socket::Option.int(:INET, :IP, :TTL, 255)).should == 0
@socket.getsockopt(:IP, :TTL).int.should == 255
end
it 'raises ArgumentError when passing 2 arguments' do
option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)
lambda { @socket.setsockopt(option, :REUSEADDR) }.should raise_error(ArgumentError)
end
it 'raises TypeError when passing 3 arguments' do
option = Socket::Option.bool(:INET, :SOCKET, :REUSEADDR, true)
lambda { @socket.setsockopt(option, :REUSEADDR, true) }.should raise_error(TypeError)
end
end
end
with_feature :unix_socket do
describe 'using a UNIX socket' do
before do
@path = SocketSpecs.socket_path
@server = UNIXServer.new(@path)
end
after do
@server.close
rm_r @path
end
it 'sets a boolean option' do
@server.setsockopt(:SOCKET, :REUSEADDR, true)
@server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true
end
end
end
end

View file

@ -1,6 +1,155 @@
require_relative '../../../spec_helper'
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket::BasicSocket#shutdown" do
platform_is_not :windows do # hangs
describe "Socket::BasicSocket#shutdown" do
SocketSpecs.each_ip_protocol do |family, ip_address|
before do
@server = Socket.new(family, :STREAM)
@client = Socket.new(family, :STREAM)
@server.bind(Socket.sockaddr_in(0, ip_address))
@server.listen(1)
@client.connect(@server.getsockname)
end
after do
@client.close
@server.close
end
describe 'using a Fixnum' do
it 'shuts down a socket for reading' do
@client.shutdown(Socket::SHUT_RD)
@client.recv(1).should be_empty
end
it 'shuts down a socket for writing' do
@client.shutdown(Socket::SHUT_WR)
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
it 'shuts down a socket for reading and writing' do
@client.shutdown(Socket::SHUT_RDWR)
@client.recv(1).should be_empty
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
lambda { @server.shutdown(666) }.should raise_error(ArgumentError)
end
end
describe 'using a Symbol' do
it 'shuts down a socket for reading using :RD' do
@client.shutdown(:RD)
@client.recv(1).should be_empty
end
it 'shuts down a socket for reading using :SHUT_RD' do
@client.shutdown(:SHUT_RD)
@client.recv(1).should be_empty
end
it 'shuts down a socket for writing using :WR' do
@client.shutdown(:WR)
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
it 'shuts down a socket for writing using :SHUT_WR' do
@client.shutdown(:SHUT_WR)
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
it 'shuts down a socket for reading and writing' do
@client.shutdown(:RDWR)
@client.recv(1).should be_empty
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
lambda { @server.shutdown(:Nope) }.should raise_error(SocketError)
end
end
describe 'using a String' do
it 'shuts down a socket for reading using "RD"' do
@client.shutdown('RD')
@client.recv(1).should be_empty
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@client.shutdown('SHUT_RD')
@client.recv(1).should be_empty
end
it 'shuts down a socket for writing using "WR"' do
@client.shutdown('WR')
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
it 'shuts down a socket for writing using "SHUT_WR"' do
@client.shutdown('SHUT_WR')
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
it 'raises ArgumentError when using an invalid option' do
lambda { @server.shutdown('Nope') }.should raise_error(SocketError)
end
end
describe 'using an object that responds to #to_str' do
before do
@dummy = mock(:dummy)
end
it 'shuts down a socket for reading using "RD"' do
@dummy.stub!(:to_str).and_return('RD')
@client.shutdown(@dummy)
@client.recv(1).should be_empty
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@dummy.stub!(:to_str).and_return('SHUT_RD')
@client.shutdown(@dummy)
@client.recv(1).should be_empty
end
it 'shuts down a socket for reading and writing' do
@dummy.stub!(:to_str).and_return('RDWR')
@client.shutdown(@dummy)
@client.recv(1).should be_empty
lambda { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
end
describe 'using an object that does not respond to #to_str' do
it 'raises TypeError' do
lambda { @server.shutdown(mock(:dummy)) }.should raise_error(TypeError)
end
end
end
end
end