async-io 1.29.0 → 1.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/lib/async/io/host_endpoint.rb +1 -1
  3. data/lib/async/io/trap.rb +4 -3
  4. data/lib/async/io/version.rb +1 -1
  5. metadata +39 -91
  6. data/.editorconfig +0 -6
  7. data/.github/workflows/development.yml +0 -55
  8. data/.gitignore +0 -13
  9. data/.rspec +0 -3
  10. data/.yardopts +0 -2
  11. data/Gemfile +0 -13
  12. data/README.md +0 -171
  13. data/async-io.gemspec +0 -30
  14. data/examples/allocations/byteslice.rb +0 -29
  15. data/examples/allocations/memory.rb +0 -16
  16. data/examples/allocations/read_chunks.rb +0 -18
  17. data/examples/chat/client.rb +0 -58
  18. data/examples/chat/server.rb +0 -83
  19. data/examples/defer/worker.rb +0 -29
  20. data/examples/echo/client.rb +0 -23
  21. data/examples/echo/server.rb +0 -58
  22. data/examples/issues/broken_ssl.rb +0 -15
  23. data/examples/issues/pipes.rb +0 -34
  24. data/examples/millions/client.rb +0 -44
  25. data/examples/millions/server.rb +0 -41
  26. data/examples/udp/client.rb +0 -14
  27. data/examples/udp/server.rb +0 -16
  28. data/gems/nio4r-2.3.gemfile +0 -3
  29. data/spec/addrinfo.rb +0 -16
  30. data/spec/async/io/buffer_spec.rb +0 -48
  31. data/spec/async/io/c10k_spec.rb +0 -138
  32. data/spec/async/io/echo_spec.rb +0 -75
  33. data/spec/async/io/endpoint_spec.rb +0 -105
  34. data/spec/async/io/generic_examples.rb +0 -73
  35. data/spec/async/io/generic_spec.rb +0 -107
  36. data/spec/async/io/notification_spec.rb +0 -46
  37. data/spec/async/io/protocol/line_spec.rb +0 -81
  38. data/spec/async/io/shared_endpoint/server_spec.rb +0 -72
  39. data/spec/async/io/shared_endpoint_spec.rb +0 -65
  40. data/spec/async/io/socket/tcp_spec.rb +0 -101
  41. data/spec/async/io/socket/udp_spec.rb +0 -65
  42. data/spec/async/io/socket_spec.rb +0 -149
  43. data/spec/async/io/ssl_server_spec.rb +0 -133
  44. data/spec/async/io/ssl_socket_spec.rb +0 -96
  45. data/spec/async/io/standard_spec.rb +0 -47
  46. data/spec/async/io/stream_context.rb +0 -30
  47. data/spec/async/io/stream_spec.rb +0 -337
  48. data/spec/async/io/tcp_socket_spec.rb +0 -84
  49. data/spec/async/io/threads_spec.rb +0 -59
  50. data/spec/async/io/trap_spec.rb +0 -52
  51. data/spec/async/io/udp_socket_spec.rb +0 -56
  52. data/spec/async/io/unix_endpoint_spec.rb +0 -106
  53. data/spec/async/io/unix_socket_spec.rb +0 -66
  54. data/spec/async/io/wrap/http_rb_spec.rb +0 -47
  55. data/spec/async/io/wrap/tcp_spec.rb +0 -79
  56. data/spec/spec_helper.rb +0 -15
@@ -1,96 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'async/io/ssl_endpoint'
24
-
25
- require 'async/rspec/ssl'
26
- require_relative 'generic_examples'
27
-
28
- RSpec.describe Async::IO::SSLSocket do
29
- include_context Async::RSpec::Reactor
30
- include_context Async::RSpec::SSL::VerifiedContexts
31
-
32
- it_should_behave_like Async::IO::Generic
33
-
34
- # Shared port for localhost network tests.
35
- let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6779, reuse_port: true, timeout: 10)}
36
- let(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: server_context, timeout: 20)}
37
- let(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: client_context, timeout: 20)}
38
-
39
- let(:data) {"The quick brown fox jumped over the lazy dog."}
40
-
41
- let(:server_task) do
42
- # Accept a single incoming connection and then finish.
43
- reactor.async do |task|
44
- server_endpoint.bind do |server|
45
- server.listen(10)
46
-
47
- begin
48
- server.accept do |peer, address|
49
- expect(peer.timeout).to be == 10
50
-
51
- data = peer.read(512)
52
- peer.write(data)
53
- end
54
- rescue OpenSSL::SSL::SSLError
55
- # ignore.
56
- end
57
- end
58
- end
59
- end
60
-
61
- describe "#connect" do
62
- context "with a trusted certificate" do
63
- include_context Async::RSpec::SSL::ValidCertificate
64
-
65
- it "should start server and send data" do
66
- server_task
67
-
68
- reactor.async do
69
- client_endpoint.connect do |client|
70
- expect(client).to be_connected
71
- expect(client.timeout).to be == 10
72
-
73
- client.write(data)
74
- client.close_write
75
-
76
- expect(client.read(512)).to be == data
77
- end
78
- end
79
- end
80
- end
81
-
82
- context "with an untrusted certificate" do
83
- include_context Async::RSpec::SSL::InvalidCertificate
84
-
85
- it "should fail to connect" do
86
- server_task
87
-
88
- reactor.async do
89
- expect do
90
- client_endpoint.connect
91
- end.to raise_exception(OpenSSL::SSL::SSLError)
92
- end.wait
93
- end
94
- end
95
- end
96
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'async/io/standard'
24
-
25
- RSpec.describe Async::IO::STDIN do
26
- include_context Async::RSpec::Reactor
27
-
28
- it "should be able to read" do
29
- expect(subject.read(0)).to be == ""
30
- end
31
- end
32
-
33
- RSpec.describe Async::IO::STDOUT do
34
- include_context Async::RSpec::Reactor
35
-
36
- it "should be able to write" do
37
- expect(subject.write("")).to be == 0
38
- end
39
- end
40
-
41
- RSpec.describe Async::IO::STDERR do
42
- include_context Async::RSpec::Reactor
43
-
44
- it "should be able to write" do
45
- expect(subject.write("")).to be == 0
46
- end
47
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'async/rspec/buffer'
24
- require 'async/io/stream'
25
-
26
- RSpec.shared_context Async::IO::Stream do
27
- include_context Async::RSpec::Buffer
28
- subject {described_class.new(buffer)}
29
- let(:io) {subject.io}
30
- end
@@ -1,337 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require 'async/io/socket'
24
- require 'async/clock'
25
-
26
- require_relative 'generic_examples'
27
- require_relative 'stream_context'
28
-
29
- RSpec.describe Async::IO::Stream do
30
- # This constant is part of the public interface, but was renamed to `Async::IO::BLOCK_SIZE`.
31
- describe "::BLOCK_SIZE" do
32
- it "should exist and be reasonable" do
33
- expect(Async::IO::Stream::BLOCK_SIZE).to be_between(1024, 1024*128)
34
- end
35
- end
36
-
37
- context "socket I/O" do
38
- let(:sockets) do
39
- @sockets = Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
40
- end
41
-
42
- after do
43
- @sockets&.each(&:close)
44
- end
45
-
46
- let(:io) {sockets.first}
47
- subject {described_class.new(sockets.last)}
48
-
49
- it_should_behave_like Async::IO
50
-
51
- describe '#drain_write_buffer' do
52
- include_context Async::RSpec::Reactor
53
- let(:output) {described_class.new(sockets.last)}
54
- subject {described_class.new(sockets.first)}
55
-
56
- let(:buffer_size) {1024*6}
57
-
58
- it "can interleave calls to flush" do
59
- tasks = 2.times.map do |i|
60
- reactor.async do
61
- buffer = i.to_s * buffer_size
62
- 128.times do
63
- output.write(buffer)
64
- output.flush
65
- end
66
- end
67
- end
68
-
69
- reactor.async do
70
- tasks.each(&:wait)
71
- output.close
72
- end
73
-
74
- Async::Task.current.sleep(1)
75
-
76
- while buffer = subject.read(buffer_size)
77
- expect(buffer).to be == (buffer[0] * buffer_size)
78
- end
79
- end
80
-
81
- it "handles write failures" do
82
- subject.close
83
-
84
- task = reactor.async do
85
- output.write("Hello World")
86
- output.flush
87
- end
88
-
89
- expect do
90
- task.wait
91
- end.to raise_error(Errno::EPIPE)
92
-
93
- write_buffer = output.instance_variable_get(:@write_buffer)
94
- drain_buffer = output.instance_variable_get(:@drain_buffer)
95
-
96
- expect(write_buffer).to be_empty
97
- expect(drain_buffer).to be_empty
98
- end
99
- end
100
-
101
- describe '#close_read' do
102
- subject {described_class.new(sockets.last)}
103
-
104
- it "can close the reading end of the stream" do
105
- expect(subject.io).to receive(:close_read).and_call_original
106
-
107
- subject.close_read
108
-
109
- # Ruby <= 2.4 raises an exception even with exception: false
110
- # expect(stream.read).to be_nil
111
- end
112
-
113
- it "can close the writing end of the stream" do
114
- expect(subject.io).to receive(:close_write).and_call_original
115
-
116
- subject.write("Oh yes!")
117
- subject.close_write
118
-
119
- expect do
120
- subject.write("Oh no!")
121
- subject.flush
122
- end.to raise_error(IOError, /not opened for writing/)
123
- end
124
- end
125
-
126
- describe '#read_exactly' do
127
- it "can read several bytes" do
128
- io.write("hello\nworld\n")
129
-
130
- expect(subject.read_exactly(4)).to be == 'hell'
131
- end
132
-
133
- it "can raise exception if io is eof" do
134
- io.close
135
-
136
- expect do
137
- subject.read_exactly(4)
138
- end.to raise_error(EOFError)
139
- end
140
- end
141
- end
142
-
143
- context "performance (BLOCK_SIZE: #{Async::IO::BLOCK_SIZE} MAXIMUM_READ_SIZE: #{Async::IO::MAXIMUM_READ_SIZE})" do
144
- include_context Async::RSpec::Reactor
145
-
146
- let!(:stream) {described_class.open("/dev/zero")}
147
- after {stream.close}
148
-
149
- it "can read data quickly" do |example|
150
- data = nil
151
-
152
- duration = Async::Clock.measure do
153
- data = stream.read(1024**3)
154
- end
155
-
156
- size = data.bytesize / 1024**2
157
- rate = size / duration
158
-
159
- example.reporter.message "Read #{size.round(2)}MB of data at #{rate.round(2)}MB/s."
160
-
161
- expect(rate).to be > 128
162
- end
163
- end
164
-
165
- context "buffered I/O" do
166
- include_context Async::IO::Stream
167
- include_context Async::RSpec::Memory
168
- include_context Async::RSpec::Reactor
169
-
170
- describe '#read' do
171
- it "should read everything" do
172
- io.write "Hello World"
173
- io.seek(0)
174
-
175
- expect(subject.io).to receive(:read_nonblock).and_call_original.twice
176
-
177
- expect(subject.read).to be == "Hello World"
178
- expect(subject).to be_eof
179
- end
180
-
181
- it "should read only the amount requested" do
182
- io.write "Hello World"
183
- io.seek(0)
184
-
185
- expect(subject.io).to receive(:read_nonblock).and_call_original.once
186
-
187
- expect(subject.read_partial(4)).to be == "Hell"
188
- expect(subject).to_not be_eof
189
-
190
- expect(subject.read_partial(20)).to be == "o World"
191
- expect(subject).to be_eof
192
- end
193
-
194
- context "with large content" do
195
- it "allocates expected amount of bytes" do
196
- io.write("." * 16*1024)
197
- io.seek(0)
198
-
199
- buffer = nil
200
-
201
- expect do
202
- # The read buffer is already allocated, and it will be resized to fit the incoming data. It will be swapped with an empty buffer.
203
- buffer = subject.read(16*1024)
204
- end.to limit_allocations.of(String, count: 1, size: 0)
205
-
206
- expect(buffer.size).to be == 16*1024
207
- end
208
- end
209
- end
210
-
211
- describe '#read_until' do
212
- it "can read a line" do
213
- io.write("hello\nworld\n")
214
- io.seek(0)
215
-
216
- expect(subject.read_until("\n")).to be == 'hello'
217
- expect(subject.read_until("\n")).to be == 'world'
218
- expect(subject.read_until("\n")).to be_nil
219
- end
220
-
221
- context "with 1-byte block size" do
222
- subject! {Async::IO::Stream.new(buffer, block_size: 1)}
223
-
224
- it "can read a line with a multi-byte pattern" do
225
- io.write("hello\r\nworld\r\n")
226
- io.seek(0)
227
-
228
- expect(subject.read_until("\r\n")).to be == 'hello'
229
- expect(subject.read_until("\r\n")).to be == 'world'
230
- expect(subject.read_until("\r\n")).to be_nil
231
- end
232
- end
233
-
234
- context "with large content" do
235
- it "allocates expected amount of bytes" do
236
- subject
237
-
238
- expect do
239
- subject.read_until("b")
240
- end.to limit_allocations.of(String, size: 0, count: 1)
241
- end
242
- end
243
- end
244
-
245
- describe '#flush' do
246
- it "should not call write if write buffer is empty" do
247
- expect(subject.io).to_not receive(:write)
248
-
249
- subject.flush
250
- end
251
-
252
- it "should flush underlying data when it exceeds block size" do
253
- expect(subject.io).to receive(:write).and_call_original.once
254
-
255
- subject.block_size.times do
256
- subject.write("!")
257
- end
258
- end
259
- end
260
-
261
- describe '#read_partial' do
262
- before(:each) do
263
- string = "Hello World!"
264
-
265
- io.write(string * (1 + (Async::IO::BLOCK_SIZE / string.bytesize)))
266
- io.seek(0)
267
- end
268
-
269
- it "should avoid calling read" do
270
- expect(subject.io).to receive(:read_nonblock).and_call_original.once
271
-
272
- expect(subject.read_partial(12)).to be == "Hello World!"
273
- end
274
-
275
- context "with large content" do
276
- it "allocates only the amount required" do
277
- expect do
278
- subject.read(4*1024)
279
- end.to limit_allocations.of(String, count: 2, size: 4*1024+1)
280
- end
281
-
282
- it "allocates exact number of bytes being read" do
283
- expect do
284
- subject.read_partial(subject.block_size * 2)
285
- end.to limit_allocations.of(String, count: 1, size: 0)
286
- end
287
-
288
- it "allocates expected amount of bytes" do
289
- buffer = nil
290
-
291
- expect do
292
- buffer = subject.read_partial
293
- end.to limit_allocations.of(String, count: 1)
294
-
295
- expect(buffer.size).to be == subject.block_size
296
- end
297
- end
298
- end
299
-
300
- describe '#write' do
301
- it "should read one line" do
302
- expect(subject.io).to receive(:write).and_call_original.once
303
-
304
- subject.write "Hello World\n"
305
- subject.flush
306
-
307
- io.seek(0)
308
- expect(subject.read).to be == "Hello World\n"
309
- end
310
- end
311
-
312
- describe '#eof' do
313
- it "should terminate subject" do
314
- expect do
315
- subject.eof!
316
- end.to raise_exception(EOFError)
317
-
318
- expect(subject).to be_eof
319
- end
320
- end
321
-
322
- describe '#close' do
323
- it 'can be closed even if underlying io is closed' do
324
- io.close
325
-
326
- expect(subject.io).to be_closed
327
-
328
- # Put some data in the write buffer
329
- subject.write "."
330
-
331
- expect do
332
- subject.close
333
- end.to_not raise_exception
334
- end
335
- end
336
- end
337
- end