nio4r 2.7.0 → 2.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -0
- data/changes.md +12 -1
- data/ext/nio4r/org/nio4r/ByteBuffer.java +1 -1
- data/ext/nio4r/org/nio4r/Monitor.java +2 -2
- data/ext/nio4r/org/nio4r/Selector.java +2 -2
- data/lib/nio/version.rb +2 -2
- data/lib/nio4r.rb +2 -0
- data/license.md +5 -2
- data/readme.md +5 -5
- data.tar.gz.sig +0 -0
- metadata +91 -74
- metadata.gz.sig +0 -0
- data/.github/workflows/workflow.yml +0 -61
- data/.gitignore +0 -21
- data/.mailmap +0 -16
- data/.rspec +0 -4
- data/.rubocop.yml +0 -100
- data/Gemfile +0 -19
- data/Rakefile +0 -8
- data/examples/echo_server.rb +0 -54
- data/logo.png +0 -0
- data/nio4r.gemspec +0 -43
- data/rakelib/extension.rake +0 -14
- data/rakelib/rspec.rake +0 -9
- data/rakelib/rubocop.rake +0 -5
- data/spec/nio/acceptables_spec.rb +0 -36
- data/spec/nio/bytebuffer_spec.rb +0 -360
- data/spec/nio/monitor_spec.rb +0 -169
- data/spec/nio/selectables/pipe_spec.rb +0 -53
- data/spec/nio/selectables/ssl_socket_spec.rb +0 -199
- data/spec/nio/selectables/tcp_socket_spec.rb +0 -108
- data/spec/nio/selectables/udp_socket_spec.rb +0 -55
- data/spec/nio/selector_spec.rb +0 -252
- data/spec/spec_helper.rb +0 -23
- data/spec/support/selectable_examples.rb +0 -93
@@ -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
|
data/spec/nio/selector_spec.rb
DELETED
@@ -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
|