nio4r 2.7.0 → 2.7.4

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