diff options
Diffstat (limited to 'spec/ruby/library/socket/udpsocket')
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/bind_spec.rb | 83 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/connect_spec.rb | 35 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/initialize_spec.rb | 53 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/inspect_spec.rb | 17 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/local_address_spec.rb | 80 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/new_spec.rb | 40 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/open_spec.rb | 13 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb | 111 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/remote_address_spec.rb | 79 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/send_spec.rb | 154 | ||||
| -rw-r--r-- | spec/ruby/library/socket/udpsocket/write_spec.rb | 21 |
11 files changed, 686 insertions, 0 deletions
diff --git a/spec/ruby/library/socket/udpsocket/bind_spec.rb b/spec/ruby/library/socket/udpsocket/bind_spec.rb new file mode 100644 index 0000000000..08b386e941 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/bind_spec.rb @@ -0,0 +1,83 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe "UDPSocket#bind" do + before :each do + @socket = UDPSocket.new + end + + after :each do + @socket.close unless @socket.closed? + end + + it "binds the socket to a port" do + @socket.bind(SocketSpecs.hostname, 0) + @socket.addr[1].should be_kind_of(Integer) + end + + it "raises Errno::EINVAL when already bound" do + @socket.bind(SocketSpecs.hostname, 0) + + -> { + @socket.bind(SocketSpecs.hostname, @socket.addr[1]) + }.should raise_error(Errno::EINVAL) + end + + it "receives a hostname and a port" do + @socket.bind(SocketSpecs.hostname, 0) + + port, host = Socket.unpack_sockaddr_in(@socket.getsockname) + + host.should == "127.0.0.1" + port.should == @socket.addr[1] + end + + it "binds to INADDR_ANY if the hostname is empty" do + @socket.bind("", 0).should == 0 + port, host = Socket.unpack_sockaddr_in(@socket.getsockname) + host.should == "0.0.0.0" + port.should == @socket.addr[1] + end +end + +describe 'UDPSocket#bind' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @socket = UDPSocket.new(family) + end + + after do + @socket.close + end + + it 'binds to an address and port' do + @socket.bind(ip_address, 0).should == 0 + + @socket.local_address.ip_address.should == ip_address + @socket.local_address.ip_port.should > 0 + end + + it 'binds to an address and port using String arguments' do + @socket.bind(ip_address, '0').should == 0 + + @socket.local_address.ip_address.should == ip_address + @socket.local_address.ip_port.should > 0 + end + + it 'can receive data after being bound to an address' do + @socket.bind(ip_address, 0) + + addr = @socket.connect_address + client = UDPSocket.new(family) + + client.connect(addr.ip_address, addr.ip_port) + client.write('hello') + + begin + @socket.recv(6).should == 'hello' + ensure + client.close + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/connect_spec.rb b/spec/ruby/library/socket/udpsocket/connect_spec.rb new file mode 100644 index 0000000000..d92bdeb981 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/connect_spec.rb @@ -0,0 +1,35 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#connect' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @socket = UDPSocket.new(family) + end + + after do + @socket.close + end + + it 'connects to an address even when it is not used' do + @socket.connect(ip_address, 9996).should == 0 + end + + it 'can send data after connecting' do + receiver = UDPSocket.new(family) + + receiver.bind(ip_address, 0) + + addr = receiver.connect_address + + @socket.connect(addr.ip_address, addr.ip_port) + @socket.write('hello') + + begin + receiver.recv(6).should == 'hello' + ensure + receiver.close + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb new file mode 100644 index 0000000000..ecf0043c10 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb @@ -0,0 +1,53 @@ +require_relative '../spec_helper' + +describe 'UDPSocket#initialize' do + after do + @socket.close if @socket + end + + it 'initializes a new UDPSocket' do + @socket = UDPSocket.new + @socket.should be_an_instance_of(UDPSocket) + end + + it 'initializes a new UDPSocket using an Integer' do + @socket = UDPSocket.new(Socket::AF_INET) + @socket.should be_an_instance_of(UDPSocket) + end + + it 'initializes a new UDPSocket using a Symbol' do + @socket = UDPSocket.new(:INET) + @socket.should be_an_instance_of(UDPSocket) + end + + it 'initializes a new UDPSocket using a String' do + @socket = UDPSocket.new('INET') + @socket.should be_an_instance_of(UDPSocket) + end + + it 'sets the socket to binmode' do + @socket = UDPSocket.new(:INET) + @socket.binmode?.should be_true + end + + platform_is_not :windows do + it 'sets the socket to nonblock' do + require 'io/nonblock' + @socket = UDPSocket.new(:INET) + @socket.should.nonblock? + end + end + + it 'sets the socket to close on exec' do + @socket = UDPSocket.new(:INET) + @socket.should.close_on_exec? + end + + it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT when given an invalid address family' do + -> { + UDPSocket.new(666) + }.should raise_error(SystemCallError) { |e| + [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class) + } + end +end diff --git a/spec/ruby/library/socket/udpsocket/inspect_spec.rb b/spec/ruby/library/socket/udpsocket/inspect_spec.rb new file mode 100644 index 0000000000..e212120b14 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/inspect_spec.rb @@ -0,0 +1,17 @@ +require_relative '../spec_helper' + +describe 'UDPSocket#inspect' do + before do + @socket = UDPSocket.new + @socket.bind('127.0.0.1', 0) + end + + after do + @socket.close + end + + it 'returns a String with the fd, family, address and port' do + port = @socket.addr[1] + @socket.inspect.should == "#<UDPSocket:fd #{@socket.fileno}, AF_INET, 127.0.0.1, #{port}>" + end +end diff --git a/spec/ruby/library/socket/udpsocket/local_address_spec.rb b/spec/ruby/library/socket/udpsocket/local_address_spec.rb new file mode 100644 index 0000000000..92e4cc10c7 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/local_address_spec.rb @@ -0,0 +1,80 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#local_address' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :DGRAM, Socket::IPPROTO_UDP) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + + @host = @server.connect_address.ip_address + @port = @server.connect_address.ip_port + end + + after do + @server.close + end + + describe 'using an explicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(@host, @port) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.local_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses the correct address family' do + @sock.local_address.afamily.should == family + end + + it 'uses the correct protocol family' do + @sock.local_address.pfamily.should == family + end + + it 'uses SOCK_DGRAM as the socket type' do + @sock.local_address.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses the correct IP address' do + @sock.local_address.ip_address.should == @host + end + + it 'uses a randomly assigned local port' do + @sock.local_address.ip_port.should > 0 + @sock.local_address.ip_port.should_not == @port + end + + it 'uses 0 as the protocol' do + @sock.local_address.protocol.should == 0 + end + end + end + + describe 'using an implicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(nil, @port) + end + + after do + @sock.close + end + + describe 'the returned Addrinfo' do + it 'uses the correct IP address' do + @sock.local_address.ip_address.should == @host + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/new_spec.rb b/spec/ruby/library/socket/udpsocket/new_spec.rb new file mode 100644 index 0000000000..79bfcb624d --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/new_spec.rb @@ -0,0 +1,40 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket.new' do + after :each do + @socket.close if @socket && !@socket.closed? + end + + it 'without arguments' do + @socket = UDPSocket.new + @socket.should be_an_instance_of(UDPSocket) + end + + it 'using Integer argument' do + @socket = UDPSocket.new(Socket::AF_INET) + @socket.should be_an_instance_of(UDPSocket) + end + + it 'using Symbol argument' do + @socket = UDPSocket.new(:INET) + @socket.should be_an_instance_of(UDPSocket) + end + + it 'using String argument' do + @socket = UDPSocket.new('INET') + @socket.should be_an_instance_of(UDPSocket) + end + + it "does not use the given block and warns to use UDPSocket::open" do + -> { + @socket = UDPSocket.new { raise } + }.should complain(/warning: UDPSocket::new\(\) does not take block; use UDPSocket::open\(\) instead/) + end + + it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT if unsupported family passed' do + -> { UDPSocket.new(-1) }.should raise_error(SystemCallError) { |e| + [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class) + } + end +end diff --git a/spec/ruby/library/socket/udpsocket/open_spec.rb b/spec/ruby/library/socket/udpsocket/open_spec.rb new file mode 100644 index 0000000000..e4dbb2ee2a --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/open_spec.rb @@ -0,0 +1,13 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe "UDPSocket.open" do + after :each do + @socket.close if @socket && !@socket.closed? + end + + it "allows calls to open without arguments" do + @socket = UDPSocket.open + @socket.should be_kind_of(UDPSocket) + end +end diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb new file mode 100644 index 0000000000..b804099589 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb @@ -0,0 +1,111 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#recvfrom_nonblock' do + SocketSpecs.each_ip_protocol do |family, ip_address, family_name| + before do + @server = UDPSocket.new(family) + @client = UDPSocket.new(family) + end + + after do + @client.close + @server.close + end + + platform_is_not :windows do + describe 'using an unbound socket' do + it 'raises IO::WaitReadable' do + -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable) + end + end + end + + describe 'using a bound socket' do + before do + @server.bind(ip_address, 0) + + addr = @server.connect_address + + @client.connect(addr.ip_address, addr.ip_port) + end + + describe 'without any data available' do + it 'raises IO::WaitReadable' do + -> { @server.recvfrom_nonblock(1) }.should raise_error(IO::WaitReadable) + end + + it 'returns :wait_readable with exception: false' do + @server.recvfrom_nonblock(1, exception: false).should == :wait_readable + end + end + + platform_is_not :windows do + describe 'with data available' do + before do + @client.write('hello') + end + + it 'returns an Array containing the data and an Array' do + IO.select([@server]) + @server.recvfrom_nonblock(1).should be_an_instance_of(Array) + end + + it 'writes the data to the buffer when one is present' do + buffer = "".b + IO.select([@server]) + @server.recvfrom_nonblock(1, 0, buffer) + buffer.should == 'h' + end + + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) + IO.select([@server]) + message, = @server.recvfrom_nonblock(1, 0, buffer) + + message.should.equal?(buffer) + buffer.encoding.should == Encoding::ISO_8859_1 + end + + describe 'the returned Array' do + before do + IO.select([@server]) + @array = @server.recvfrom_nonblock(1) + end + + it 'contains the data at index 0' do + @array[0].should == 'h' + end + + it 'contains an Array at index 1' do + @array[1].should be_an_instance_of(Array) + end + end + + describe 'the returned address Array' do + before do + IO.select([@server]) + @addr = @server.recvfrom_nonblock(1)[1] + end + + it 'uses the correct address family' do + @addr[0].should == family_name + end + + it 'uses the port of the client' do + @addr[1].should == @client.local_address.ip_port + end + + it 'uses the hostname of the client' do + @addr[2].should == ip_address + end + + it 'uses the IP address of the client' do + @addr[3].should == ip_address + end + end + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/remote_address_spec.rb b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb new file mode 100644 index 0000000000..94889ce560 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/remote_address_spec.rb @@ -0,0 +1,79 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe 'UDPSocket#remote_address' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = Socket.new(family, :DGRAM, Socket::IPPROTO_UDP) + + @server.bind(Socket.sockaddr_in(0, ip_address)) + + @host = @server.connect_address.ip_address + @port = @server.connect_address.ip_port + end + + after do + @server.close + end + + describe 'using an explicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(@host, @port) + end + + after do + @sock.close + end + + it 'returns an Addrinfo' do + @sock.remote_address.should be_an_instance_of(Addrinfo) + end + + describe 'the returned Addrinfo' do + it 'uses the correct address family' do + @sock.remote_address.afamily.should == family + end + + it 'uses the correct protocol family' do + @sock.remote_address.pfamily.should == family + end + + it 'uses SOCK_DGRAM as the socket type' do + @sock.remote_address.socktype.should == Socket::SOCK_DGRAM + end + + it 'uses the correct IP address' do + @sock.remote_address.ip_address.should == @host + end + + it 'uses the correct port' do + @sock.remote_address.ip_port.should == @port + end + + it 'uses 0 as the protocol' do + @sock.remote_address.protocol.should == 0 + end + end + end + + describe 'using an implicit hostname' do + before do + @sock = UDPSocket.new(family) + + @sock.connect(nil, @port) + end + + after do + @sock.close + end + + describe 'the returned Addrinfo' do + it 'uses the correct IP address' do + @sock.remote_address.ip_address.should == @host + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/send_spec.rb b/spec/ruby/library/socket/udpsocket/send_spec.rb new file mode 100644 index 0000000000..6dd5f67bea --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/send_spec.rb @@ -0,0 +1,154 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe "UDPSocket#send" do + before :each do + @port = nil + @server_thread = Thread.new do + @server = UDPSocket.open + begin + @server.bind(nil, 0) + @port = @server.addr[1] + begin + @msg = @server.recvfrom_nonblock(64) + rescue IO::WaitReadable + IO.select([@server]) + retry + end + ensure + @server.close if !@server.closed? + end + end + Thread.pass while @server_thread.status and !@port + end + + after :each do + @server_thread.join + end + + it "sends data in ad hoc mode" do + @socket = UDPSocket.open + @socket.send("ad hoc", 0, SocketSpecs.hostname, @port) + @socket.close + @server_thread.join + + @msg[0].should == "ad hoc" + @msg[1][0].should == "AF_INET" + @msg[1][1].should be_kind_of(Integer) + @msg[1][3].should == "127.0.0.1" + end + + it "sends data in ad hoc mode (with port given as a String)" do + @socket = UDPSocket.open + @socket.send("ad hoc", 0, SocketSpecs.hostname, @port.to_s) + @socket.close + @server_thread.join + + @msg[0].should == "ad hoc" + @msg[1][0].should == "AF_INET" + @msg[1][1].should be_kind_of(Integer) + @msg[1][3].should == "127.0.0.1" + end + + it "sends data in connection mode" do + @socket = UDPSocket.open + @socket.connect(SocketSpecs.hostname, @port) + @socket.send("connection-based", 0) + @socket.close + @server_thread.join + + @msg[0].should == "connection-based" + @msg[1][0].should == "AF_INET" + @msg[1][1].should be_kind_of(Integer) + @msg[1][3].should == "127.0.0.1" + end + + it "raises EMSGSIZE if data is too big" do + @socket = UDPSocket.open + begin + -> do + @socket.send('1' * 100_000, 0, SocketSpecs.hostname, @port.to_s) + end.should raise_error(Errno::EMSGSIZE) + ensure + @socket.send("ad hoc", 0, SocketSpecs.hostname, @port) + @socket.close + @server_thread.join + end + end +end + +describe 'UDPSocket#send' do + SocketSpecs.each_ip_protocol do |family, ip_address| + before do + @server = UDPSocket.new(family) + @client = UDPSocket.new(family) + + @server.bind(ip_address, 0) + + @addr = @server.connect_address + end + + after do + @server.close + @client.close + end + + describe 'using a disconnected socket' do + describe 'without a destination address' do + it "raises #{SocketSpecs.dest_addr_req_error}" do + -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + + describe 'with a destination address as separate arguments' do + it 'returns the amount of sent bytes' do + @client.send('hello', 0, @addr.ip_address, @addr.ip_port).should == 5 + end + + it 'does not persist the connection after sending data' do + @client.send('hello', 0, @addr.ip_address, @addr.ip_port) + + -> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error) + end + end + + describe 'with a destination address as a single String argument' do + it 'returns the amount of sent bytes' do + @client.send('hello', 0, @server.getsockname).should == 5 + end + end + end + + describe 'using a connected socket' do + describe 'without an explicit destination address' do + before do + @client.connect(@addr.ip_address, @addr.ip_port) + end + + it 'returns the amount of bytes written' do + @client.send('hello', 0).should == 5 + end + end + + describe 'with an explicit destination address' do + before do + @alt_server = UDPSocket.new(family) + + @alt_server.bind(ip_address, 0) + end + + after do + @alt_server.close + end + + it 'sends the data to the given address instead' do + @client.send('hello', 0, @alt_server.getsockname).should == 5 + + -> { @server.recv(5) }.should block_caller + + @alt_server.recv(5).should == 'hello' + end + end + end + end +end diff --git a/spec/ruby/library/socket/udpsocket/write_spec.rb b/spec/ruby/library/socket/udpsocket/write_spec.rb new file mode 100644 index 0000000000..c971f29b62 --- /dev/null +++ b/spec/ruby/library/socket/udpsocket/write_spec.rb @@ -0,0 +1,21 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' + +describe "UDPSocket#write" do + it "raises EMSGSIZE if msg is too long" do + begin + host = SocketSpecs.hostname + s1 = UDPSocket.new + s1.bind(host, 0) + s2 = UDPSocket.new + s2.connect(host, s1.addr[1]) + + -> do + s2.write('1' * 100_000) + end.should raise_error(Errno::EMSGSIZE) + ensure + s1.close if s1 && !s1.closed? + s2.close if s2 && !s2.closed? + end + end +end |
