summaryrefslogtreecommitdiff
path: root/spec/ruby/library/socket/socket/accept_nonblock_spec.rb
blob: 011622988c4dac7e82e66aef6cdc03d39154fda3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
require_relative '../spec_helper'
require_relative '../fixtures/classes'

describe "Socket#accept_nonblock" do
  before :each do
    @hostname = "127.0.0.1"
    @addr = Socket.sockaddr_in(0, @hostname)
    @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
    @socket.bind(@addr)
    @socket.listen(1)
  end

  after :each do
    @socket.close
  end

  it "raises IO::WaitReadable if the connection is not accepted yet" do
    -> {
      @socket.accept_nonblock
    }.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 'returns :wait_readable in exceptionless mode' do
    @socket.accept_nonblock(exception: false).should == :wait_readable
  end
end

describe 'Socket#accept_nonblock' do
  SocketSpecs.each_ip_protocol do |family, ip_address|
    before do
      @server = Socket.new(family, :STREAM, 0)
      @sockaddr = Socket.sockaddr_in(0, ip_address)
    end

    after do
      @server.close unless @server.closed?
    end

    describe 'using an unbound socket' do
      it 'raises Errno::EINVAL' do
        -> { @server.accept_nonblock }.should raise_error(Errno::EINVAL)
        -> { @server.accept_nonblock(exception: false) }.should raise_error(Errno::EINVAL)
      end
    end

    describe "using a bound socket that's not listening" do
      before do
        @server.bind(@sockaddr)
      end

      it 'raises Errno::EINVAL' do
        -> { @server.accept_nonblock }.should raise_error(Errno::EINVAL)
        -> { @server.accept_nonblock(exception: false) }.should raise_error(Errno::EINVAL)
      end
    end

    describe 'using a closed socket' do
      it 'raises IOError' do
        @server.close

        -> { @server.accept_nonblock }.should raise_error(IOError)
        -> { @server.accept_nonblock(exception: false) }.should raise_error(IOError)
      end
    end

    describe "using a bound socket that's listening" do
      before do
        @server.bind(@sockaddr)
        @server.listen(1)
      end

      describe 'without a connected client' do
        it 'raises IO::WaitReadable' do
          -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable)
        end
      end

      platform_is_not :windows do
        describe 'with a connected client' do
          before do
            addr    = Socket.sockaddr_in(@server.local_address.ip_port, ip_address)
            @client = Socket.new(family, :STREAM, 0)

            @client.connect(addr)
          end

          after do
            @socket.close if @socket
            @client.close
          end

          it 'returns an Array containing a Socket and an Addrinfo' do
            IO.select([@server])
            @socket, addrinfo = @server.accept_nonblock

            @socket.should be_an_instance_of(Socket)
            addrinfo.should be_an_instance_of(Addrinfo)
          end

          describe 'the returned Addrinfo' do
            before do
              IO.select([@server])
              @socket, @addr = @server.accept_nonblock
            end

            it 'uses AF_INET as the address family' do
              @addr.afamily.should == family
            end

            it 'uses PF_INET as the protocol family' do
              @addr.pfamily.should == family
            end

            it 'uses SOCK_STREAM as the socket type' do
              @addr.socktype.should == Socket::SOCK_STREAM
            end

            it 'uses 0 as the protocol' do
              @addr.protocol.should == 0
            end

            it 'uses the same IP address as the client Socket' do
              @addr.ip_address.should == @client.local_address.ip_address
            end

            it 'uses the same port as the client Socket' do
              @addr.ip_port.should == @client.local_address.ip_port
            end
          end
        end
      end
    end
  end
end