nio4r 2.5.9 → 2.7.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,192 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
- require "openssl"
5
-
6
- RSpec.describe OpenSSL::SSL::SSLSocket do
7
- before(:all) do
8
- @tls = []
9
- end
10
-
11
- let(:addr) { "127.0.0.1" }
12
-
13
- let(:ssl_key) { OpenSSL::PKey::RSA.new(2048) }
14
-
15
- let(:ssl_cert) do
16
- name = OpenSSL::X509::Name.new([%w[CN 127.0.0.1]])
17
- OpenSSL::X509::Certificate.new.tap do |cert|
18
- cert.version = 2
19
- cert.serial = 1
20
- cert.issuer = name
21
- cert.subject = name
22
- cert.not_before = Time.now
23
- cert.not_after = Time.now + (7 * 24 * 60 * 60)
24
- cert.public_key = ssl_key.public_key
25
-
26
- cert.sign(ssl_key, OpenSSL::Digest::SHA256.new)
27
- end
28
- end
29
-
30
- let(:ssl_server_context) do
31
- OpenSSL::SSL::SSLContext.new.tap do |ctx|
32
- ctx.cert = ssl_cert
33
- ctx.key = ssl_key
34
- unless @tls.empty?
35
- if ctx.respond_to? :set_minmax_proto_version, true
36
- ctx.max_version = @tls[0]
37
- else
38
- ctx.ssl_version = @tls[1]
39
- end
40
- end
41
- end
42
- end
43
-
44
- let :readable_subject do
45
- server = TCPServer.new(addr, 0)
46
- client = TCPSocket.open(addr, server.local_address.ip_port)
47
- peer = server.accept
48
-
49
- ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
50
- ssl_peer.sync_close = true
51
-
52
- ssl_client = OpenSSL::SSL::SSLSocket.new(client)
53
- ssl_client.sync_close = true
54
-
55
- # SSLSocket#connect and #accept are blocking calls.
56
- thread = Thread.new { ssl_client.connect }
57
-
58
- ssl_peer.accept
59
- ssl_peer << "data"
60
- ssl_peer.flush
61
-
62
- thread.join
63
-
64
- pending "Failed to produce a readable socket" unless select([ssl_client], [], [], 10)
65
- ssl_client
66
- end
67
-
68
- let :unreadable_subject do
69
- server = TCPServer.new(addr, 0)
70
- client = TCPSocket.new(addr, server.local_address.ip_port)
71
- peer = server.accept
72
-
73
- ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
74
- ssl_peer.sync_close = true
75
-
76
- ssl_client = OpenSSL::SSL::SSLSocket.new(client)
77
- ssl_client.sync_close = true
78
-
79
- # SSLSocket#connect and #accept are blocking calls.
80
- thread = Thread.new { ssl_client.connect }
81
- ssl_peer.accept
82
- thread.join
83
-
84
- if ssl_client.ssl_version == "TLSv1.3"
85
- expect(ssl_client.read_nonblock(1, exception: false)).to eq(:wait_readable)
86
- end
87
-
88
- pending "Failed to produce an unreadable socket" if select([ssl_client], [], [], 0)
89
- ssl_client
90
- end
91
-
92
- let :writable_subject do
93
- server = TCPServer.new(addr, 0)
94
- client = TCPSocket.new(addr, server.local_address.ip_port)
95
- peer = server.accept
96
-
97
- ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
98
- ssl_peer.sync_close = true
99
-
100
- ssl_client = OpenSSL::SSL::SSLSocket.new(client)
101
- ssl_client.sync_close = true
102
-
103
- # SSLSocket#connect and #accept are blocking calls.
104
- thread = Thread.new { ssl_client.connect }
105
-
106
- ssl_peer.accept
107
- thread.join
108
-
109
- ssl_client
110
- end
111
-
112
- let :unwritable_subject do
113
- server = TCPServer.new(addr, 0)
114
- client = TCPSocket.new(addr, server.local_address.ip_port)
115
- peer = server.accept
116
-
117
- ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
118
- ssl_peer.sync_close = true
119
-
120
- ssl_client = OpenSSL::SSL::SSLSocket.new(client)
121
- ssl_client.sync_close = true
122
-
123
- # SSLSocket#connect and #accept are blocking calls.
124
- thread = Thread.new { ssl_client.connect }
125
-
126
- ssl_peer.accept
127
- thread.join
128
-
129
- cntr = 0
130
- begin
131
- count = ssl_client.write_nonblock "X" * 1024
132
- expect(count).not_to eq(0)
133
- cntr += 1
134
- t = select [], [ssl_client], [], 0
135
- rescue IO::WaitReadable, IO::WaitWritable
136
- pending "SSL will report writable but not accept writes"
137
- end while t && t[1].include?(ssl_client) && cntr < 30
138
-
139
- # I think the kernel might manage to drain its buffer a bit even after
140
- # the socket first goes unwritable. Attempt to sleep past this and then
141
- # attempt to write again
142
- sleep 0.1
143
-
144
- # Once more for good measure!
145
- begin
146
- # ssl_client.write_nonblock "X" * 1024
147
- loop { ssl_client.write_nonblock "X" * 1024 }
148
- rescue OpenSSL::SSL::SSLError
149
- end
150
-
151
- # Sanity check to make sure we actually produced an unwritable socket
152
- if select([], [ssl_client], [], 0)
153
- pending "Failed to produce an unwritable socket"
154
- end
155
-
156
- ssl_client
157
- end
158
-
159
- let :pair do
160
- server = TCPServer.new(addr, 0)
161
- client = TCPSocket.new(addr, server.local_address.ip_port)
162
- peer = server.accept
163
-
164
- ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
165
- ssl_peer.sync_close = true
166
-
167
- ssl_client = OpenSSL::SSL::SSLSocket.new(client)
168
- ssl_client.sync_close = true
169
-
170
- # SSLSocket#connect and #accept are blocking calls.
171
- thread = Thread.new { ssl_client.connect }
172
- ssl_peer.accept
173
-
174
- [thread.value, ssl_peer]
175
- end
176
-
177
- describe "using TLS 1.2" do
178
- before(:all) do
179
- @tls = %i[TLS1_2 TLSv1_2]
180
- end
181
- it_behaves_like "an NIO selectable"
182
- it_behaves_like "an NIO selectable stream"
183
- end
184
-
185
- describe "using TLS 1.3", if: OpenSSL::SSL.const_defined?(:TLS1_3_VERSION) do
186
- before(:all) do
187
- @tls = %i[TLS1_3 TLSv1_3]
188
- end
189
- it_behaves_like "an NIO selectable"
190
- it_behaves_like "an NIO selectable stream", true
191
- end
192
- end
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe TCPSocket do
6
- let(:addr) { "127.0.0.1" }
7
-
8
- let :readable_subject do
9
- server = TCPServer.new(addr, 0)
10
- sock = TCPSocket.new(addr, server.local_address.ip_port)
11
- peer = server.accept
12
-
13
- peer << "Xdata"
14
- peer.flush
15
- sock.read(1)
16
-
17
- sock
18
- end
19
-
20
- let :unreadable_subject do
21
- server = TCPServer.new(addr, 0)
22
- sock = TCPSocket.new(addr, server.local_address.ip_port)
23
-
24
- # Sanity check to make sure we actually produced an unreadable socket
25
- pending "Failed to produce an unreadable socket" if select([sock], [], [], 0)
26
-
27
- sock
28
- end
29
-
30
- let :writable_subject do
31
- server = TCPServer.new(addr, 0)
32
- TCPSocket.new(addr, server.local_address.ip_port)
33
- end
34
-
35
- let :unwritable_subject do
36
- server = TCPServer.new(addr, 0)
37
- sock = TCPSocket.new(addr, server.local_address.ip_port)
38
-
39
- # TODO: close this socket
40
- _peer = server.accept
41
-
42
- loop do
43
- sock.write_nonblock "X" * 1024
44
- _, writers = Kernel.select([], [sock], [], 0)
45
-
46
- break unless writers && writers.include?(sock)
47
- end
48
-
49
- # HAX: I think the kernel might manage to drain its buffer a bit even after
50
- # the socket first goes unwritable. Attempt to sleep past this and then
51
- # attempt to write again
52
- sleep 0.1
53
-
54
- # Once more for good measure!
55
- begin
56
- sock.write_nonblock "X" * 1024
57
- rescue Errno::EWOULDBLOCK
58
- end
59
-
60
- # Sanity check to make sure we actually produced an unwritable socket
61
- pending "Failed to produce an unwritable socket" if select([], [sock], [], 0)
62
-
63
- sock
64
- end
65
-
66
- let :pair do
67
- server = TCPServer.new(addr, 0)
68
- client = TCPSocket.new(addr, server.local_address.ip_port)
69
- [client, server.accept]
70
- end
71
-
72
- it_behaves_like "an NIO selectable"
73
- it_behaves_like "an NIO selectable stream"
74
- it_behaves_like "an NIO bidirectional stream"
75
-
76
- context :connect do
77
- include_context NIO::Selector
78
-
79
- it "selects writable when connected" do
80
- begin
81
- server = TCPServer.new(addr, 0)
82
-
83
- client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
84
- monitor = selector.register(client, :w)
85
-
86
- expect do
87
- client.connect_nonblock server.local_address
88
- end.to raise_exception Errno::EINPROGRESS
89
-
90
- ready = selector.select(1)
91
-
92
- expect(ready).to include monitor
93
- result = client.getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_ERROR)
94
- expect(result.unpack("i").first).to be_zero
95
- ensure
96
- server.close rescue nil
97
- selector.close rescue nil
98
- end
99
- end
100
- end
101
- end
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe UDPSocket, if: !defined?(JRUBY_VERSION) do
6
- let(:udp_port) { 23_456 }
7
-
8
- let :readable_subject do
9
- server = UDPSocket.new
10
- server.bind("127.0.0.1", 0)
11
-
12
- peer = UDPSocket.new
13
- peer.send("hi there", 0, "127.0.0.1", server.local_address.ip_port)
14
-
15
- server
16
- end
17
-
18
- let :unreadable_subject do
19
- sock = UDPSocket.new
20
- sock.bind("127.0.0.1", 0)
21
- sock
22
- end
23
-
24
- let :writable_subject do
25
- server = UDPSocket.new
26
- server.bind("127.0.0.1", 0)
27
-
28
- peer = UDPSocket.new
29
- peer.connect("127.0.0.1", server.local_address.ip_port)
30
-
31
- cntr = 0
32
- begin
33
- peer.send("X" * 1024, 0)
34
- cntr += 1
35
- t = select [], [peer], [], 0
36
- rescue Errno::ECONNREFUSED => e
37
- skip "Couldn't make writable UDPSocket subject: #{e.class}: #{e}"
38
- end while t && t[1].include?(peer) && cntr < 5
39
-
40
- peer
41
- end
42
-
43
- let :unwritable_subject do
44
- pending "come up with a UDPSocket that's blocked on writing"
45
- end
46
-
47
- it_behaves_like "an NIO selectable"
48
- end
@@ -1,240 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
- require "timeout"
5
-
6
- RSpec.describe NIO::Selector do
7
- let(:pair) { IO.pipe }
8
- let(:reader) { pair.first }
9
- let(:writer) { pair.last }
10
-
11
- context ".backends" do
12
- it "knows all supported backends" do
13
- expect(described_class.backends).to be_a Array
14
- expect(described_class.backends.first).to be_a Symbol
15
- end
16
- end
17
-
18
- context "#initialize" do
19
- it "allows explicitly specifying a backend" do |example|
20
- backend = described_class.backends.first
21
- selector = described_class.new(backend)
22
- expect(selector.backend).to eq backend
23
-
24
- example.reporter.message "Supported backends: #{described_class.backends}"
25
- end
26
-
27
- it "automatically selects a backend if none or nil is specified" do
28
- expect(described_class.new.backend).to eq described_class.new(nil).backend
29
- end
30
-
31
- it "raises ArgumentError if given an invalid backend" do
32
- expect { described_class.new(:derp) }.to raise_error ArgumentError
33
- end
34
-
35
- it "raises TypeError if given a non-Symbol parameter" do
36
- expect { described_class.new(42).to raise_error TypeError }
37
- end
38
- end
39
-
40
- context "backend" do
41
- it "knows its backend" do |example|
42
- expect(subject.backend).to be_a Symbol
43
-
44
- example.reporter.message "Current backend: #{subject.backend}"
45
- end
46
- end
47
-
48
- context "register" do
49
- it "registers IO objects" do
50
- monitor = subject.register(reader, :r)
51
- expect(monitor).not_to be_closed
52
- end
53
-
54
- it "raises TypeError if asked to register non-IO objects" do
55
- expect { subject.register(42, :r) }.to raise_exception TypeError
56
- end
57
-
58
- it "raises when asked to register after closing" do
59
- subject.close
60
- expect { subject.register(reader, :r) }.to raise_exception IOError
61
- end
62
- end
63
-
64
- it "knows which IO objects are registered" do
65
- subject.register(reader, :r)
66
- expect(subject).to be_registered(reader)
67
- expect(subject).not_to be_registered(writer)
68
- end
69
-
70
- it "deregisters IO objects" do
71
- subject.register(reader, :r)
72
-
73
- monitor = subject.deregister(reader)
74
- expect(subject).not_to be_registered(reader)
75
- expect(monitor).to be_closed
76
- end
77
-
78
- it "allows deregistering closed IO objects" do
79
- subject.register(reader, :r)
80
- reader.close
81
-
82
- expect do
83
- subject.deregister(reader)
84
- end.not_to raise_error
85
- end
86
-
87
- it "reports if it is empty" do
88
- expect(subject).to be_empty
89
- subject.register(reader, :r)
90
- expect(subject).not_to be_empty
91
- end
92
-
93
- # This spec might seem a bit silly, but this actually something the
94
- # Java NIO API specifically precludes that we need to work around
95
- it "allows reregistration of the same IO object across select calls" do
96
- monitor = subject.register(reader, :r)
97
- writer << "ohai"
98
-
99
- expect(subject.select).to include monitor
100
- expect(reader.read(4)).to eq("ohai")
101
- subject.deregister(reader)
102
-
103
- new_monitor = subject.register(reader, :r)
104
- writer << "thar"
105
- expect(subject.select).to include new_monitor
106
- expect(reader.read(4)).to eq("thar")
107
- end
108
-
109
- context "timeouts" do
110
- let(:select_precision) {0.2}
111
- let(:timeout) {2.0}
112
- let(:payload) {"hi there"}
113
-
114
- it "waits for timeout when selecting from empty selector" do
115
- started_at = Time.now
116
- expect(subject.select(timeout)).to be_nil
117
- expect(Time.now - started_at).to be_within(select_precision).of(timeout)
118
- end
119
-
120
- it "waits for a timeout when selecting with reader" do
121
- monitor = subject.register(reader, :r)
122
-
123
- writer << payload
124
-
125
- started_at = Time.now
126
- expect(subject.select(timeout)).to include monitor
127
- expect(Time.now - started_at).to be_within(select_precision).of(0)
128
- reader.read_nonblock(payload.size)
129
-
130
- started_at = Time.now
131
- expect(subject.select(timeout)).to be_nil
132
- expect(Time.now - started_at).to be_within(select_precision).of(timeout)
133
- end
134
-
135
- it "raises ArgumentError if given a negative timeout" do
136
- subject.register(reader, :r)
137
-
138
- expect do
139
- subject.select(-1)
140
- end.to raise_exception(ArgumentError)
141
- end
142
- end
143
-
144
- context "wakeup" do
145
- let(:select_precision) {0.2}
146
-
147
- it "wakes up if signaled to from another thread" do
148
- subject.register(reader, :r)
149
-
150
- thread = Thread.new do
151
- started_at = Time.now
152
- expect(subject.select).to eq []
153
- Time.now - started_at
154
- end
155
-
156
- timeout = 0.1
157
- sleep timeout
158
- subject.wakeup
159
-
160
- expect(thread.value).to be_within(select_precision).of(timeout)
161
- end
162
-
163
- it "raises IOError if asked to wake up a closed selector" do
164
- subject.close
165
- expect(subject).to be_closed
166
-
167
- expect { subject.wakeup }.to raise_exception IOError
168
- end
169
- end
170
-
171
- context "select" do
172
- it "does not block on super small precision intervals" do
173
- wait_interval = 1e-4
174
-
175
- expect do
176
- Timeout.timeout(2) do
177
- subject.select(wait_interval)
178
- end
179
- end.not_to raise_error
180
- end
181
-
182
- it "selects IO objects" do
183
- writer << "ohai"
184
- unready = IO.pipe.first
185
-
186
- reader_monitor = subject.register(reader, :r)
187
- unready_monitor = subject.register(unready, :r)
188
-
189
- selected = subject.select(0)
190
- expect(selected.size).to eq(1)
191
- expect(selected).to include reader_monitor
192
- expect(selected).not_to include unready_monitor
193
- end
194
-
195
- it "selects closed IO objects" do
196
- monitor = subject.register(reader, :r)
197
- expect(subject.select(0)).to be_nil
198
-
199
- thread = Thread.new { subject.select }
200
- Thread.pass while thread.status && thread.status != "sleep"
201
-
202
- writer.close
203
- selected = thread.value
204
- expect(selected).to include monitor
205
- end
206
-
207
- it "iterates across selected objects with a block" do
208
- readable1, writer = IO.pipe
209
- writer << "ohai"
210
-
211
- readable2, writer = IO.pipe
212
- writer << "ohai"
213
-
214
- unreadable = IO.pipe.first
215
-
216
- monitor1 = subject.register(readable1, :r)
217
- monitor2 = subject.register(readable2, :r)
218
- monitor3 = subject.register(unreadable, :r)
219
-
220
- readables = []
221
- result = subject.select { |monitor| readables << monitor }
222
- expect(result).to eq(2)
223
-
224
- expect(readables).to include monitor1
225
- expect(readables).to include monitor2
226
- expect(readables).not_to include monitor3
227
- end
228
-
229
- it "raises IOError if asked to select on a closed selector" do
230
- subject.close
231
-
232
- expect { subject.select(0) }.to raise_exception IOError
233
- end
234
- end
235
-
236
- it "closes" do
237
- subject.close
238
- expect(subject).to be_closed
239
- end
240
- end
data/spec/spec_helper.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "nio"
4
- require "support/selectable_examples"
5
-
6
- RSpec.configure do |config|
7
- config.disable_monkey_patching!
8
-
9
- # Enable flags like --only-failures and --next-failure
10
- config.example_status_persistence_file_path = ".rspec_status"
11
-
12
- config.filter_run_when_matching :focus
13
-
14
- config.expect_with :rspec do |c|
15
- c.syntax = :expect
16
- end
17
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.shared_context NIO::Selector do
4
- let(:selector) {@selector = NIO::Selector.new}
5
-
6
- after(:each) do
7
- if defined?(@selector)
8
- @selector.close
9
- end
10
- end
11
- end
12
-
13
- RSpec.shared_context "an NIO selectable" do
14
- include_context NIO::Selector
15
-
16
- it "selects readable objects" do
17
- monitor = selector.register(readable_subject, :r)
18
- ready = selector.select(1)
19
- expect(ready).to be_an Enumerable
20
- expect(ready).to include monitor
21
- end
22
-
23
- it "does not select unreadable objects" do
24
- selector.register(unreadable_subject, :r)
25
- expect(selector.select(0)).to be_nil
26
- end
27
-
28
- it "selects writable objects" do
29
- monitor = selector.register(writable_subject, :w)
30
- ready = selector.select(1)
31
- expect(ready).to be_an Enumerable
32
- expect(ready).to include monitor
33
- end
34
-
35
- it "does not select unwritable objects" do
36
- selector.register(unwritable_subject, :w)
37
- ready = selector.select(0)
38
- expect(ready).to be_nil
39
- end
40
- end
41
-
42
- RSpec.shared_context "an NIO selectable stream" do |is_tls13|
43
- include_context NIO::Selector
44
-
45
- let(:stream) { pair.first }
46
- let(:peer) { pair.last }
47
-
48
- it "selects readable when the other end closes" do
49
- monitor = selector.register(stream, :r)
50
- unless is_tls13
51
- expect(selector.select(1)).to be_nil
52
- end
53
-
54
- peer.close
55
- # Wait and give the TCP session time to close
56
- expect(selector.select(0.1)).to include monitor
57
- end
58
- end
59
-
60
- RSpec.shared_context "an NIO bidirectional stream" do
61
- include_context NIO::Selector
62
-
63
- let(:stream) {pair.first}
64
- let(:peer) {pair.last}
65
-
66
- it "selects readable and writable" do
67
- selector.register(readable_subject, :rw)
68
-
69
- selector.select(1) do |monitor|
70
- expect(monitor.readiness).to eq(:rw)
71
- end
72
-
73
- readable_subject.close
74
- end
75
-
76
- it "keeps readiness after the selectable has been closed" do
77
- selector.register(readable_subject, :rw)
78
-
79
- selector.select(1) do |monitor|
80
- expect(monitor.readiness).to eq(:rw)
81
- readable_subject.close
82
- expect(monitor.readiness).to eq(:rw)
83
- end
84
- end
85
- end