nio4r 2.7.1 → 2.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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