async-io 1.27.5 → 1.30.0

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/lib/async/io/generic.rb +1 -1
  3. data/lib/async/io/host_endpoint.rb +1 -1
  4. data/lib/async/io/stream.rb +18 -32
  5. data/{spec/async/io/trap_spec.rb → lib/async/io/threads.rb} +37 -26
  6. data/lib/async/io/trap.rb +4 -3
  7. data/lib/async/io/version.rb +1 -1
  8. metadata +45 -95
  9. data/.editorconfig +0 -6
  10. data/.gitignore +0 -13
  11. data/.rspec +0 -3
  12. data/.travis.yml +0 -25
  13. data/.yardopts +0 -2
  14. data/Gemfile +0 -18
  15. data/README.md +0 -171
  16. data/Rakefile +0 -8
  17. data/async-io.gemspec +0 -30
  18. data/examples/allocations/byteslice.rb +0 -29
  19. data/examples/allocations/memory.rb +0 -16
  20. data/examples/allocations/read_chunks.rb +0 -18
  21. data/examples/chat/client.rb +0 -58
  22. data/examples/chat/server.rb +0 -83
  23. data/examples/defer/worker.rb +0 -29
  24. data/examples/echo/client.rb +0 -23
  25. data/examples/echo/server.rb +0 -58
  26. data/examples/issues/broken_ssl.rb +0 -15
  27. data/examples/issues/pipes.rb +0 -34
  28. data/examples/millions/client.rb +0 -44
  29. data/examples/millions/server.rb +0 -41
  30. data/examples/udp/client.rb +0 -14
  31. data/examples/udp/server.rb +0 -16
  32. data/gems/nio4r-2.3.gemfile +0 -3
  33. data/spec/addrinfo.rb +0 -16
  34. data/spec/async/io/buffer_spec.rb +0 -48
  35. data/spec/async/io/c10k_spec.rb +0 -138
  36. data/spec/async/io/echo_spec.rb +0 -75
  37. data/spec/async/io/endpoint_spec.rb +0 -105
  38. data/spec/async/io/generic_examples.rb +0 -73
  39. data/spec/async/io/generic_spec.rb +0 -107
  40. data/spec/async/io/notification_spec.rb +0 -46
  41. data/spec/async/io/protocol/line_spec.rb +0 -81
  42. data/spec/async/io/shared_endpoint/server_spec.rb +0 -72
  43. data/spec/async/io/shared_endpoint_spec.rb +0 -67
  44. data/spec/async/io/socket/tcp_spec.rb +0 -101
  45. data/spec/async/io/socket/udp_spec.rb +0 -65
  46. data/spec/async/io/socket_spec.rb +0 -149
  47. data/spec/async/io/ssl_server_spec.rb +0 -133
  48. data/spec/async/io/ssl_socket_spec.rb +0 -96
  49. data/spec/async/io/standard_spec.rb +0 -47
  50. data/spec/async/io/stream_context.rb +0 -30
  51. data/spec/async/io/stream_spec.rb +0 -318
  52. data/spec/async/io/tcp_socket_spec.rb +0 -84
  53. data/spec/async/io/udp_socket_spec.rb +0 -56
  54. data/spec/async/io/unix_endpoint_spec.rb +0 -106
  55. data/spec/async/io/unix_socket_spec.rb +0 -66
  56. data/spec/async/io/wrap/http_rb_spec.rb +0 -47
  57. data/spec/async/io/wrap/tcp_spec.rb +0 -79
  58. data/spec/spec_helper.rb +0 -15
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2018, 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_socket'
24
- require 'async/io/ssl_endpoint'
25
-
26
- require 'async/rspec/ssl'
27
- require_relative 'generic_examples'
28
-
29
- RSpec.describe Async::IO::SSLServer do
30
- include_context Async::RSpec::Reactor
31
-
32
- context 'single host' do
33
- include_context Async::RSpec::SSL::VerifiedContexts
34
- include_context Async::RSpec::SSL::ValidCertificate
35
-
36
- let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6780, reuse_port: true)}
37
- let(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: server_context)}
38
- let(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: client_context)}
39
-
40
- let(:data) {"What one programmer can do in one month, two programmers can do in two months."}
41
-
42
- it "can see through to address" do
43
- expect(server_endpoint.address).to be == endpoint.address
44
- end
45
-
46
- it 'can accept_each connections' do
47
- # Accept a single incoming connection and then finish.
48
- server_task = reactor.async do |task|
49
- server_endpoint.bind do |server|
50
- server.listen(10)
51
-
52
- server.accept_each do |peer, address|
53
- data = peer.read(512)
54
- peer.write(data)
55
- end
56
- end
57
- end
58
-
59
- reactor.async do
60
- client_endpoint.connect do |client|
61
- client.write(data)
62
- client.close_write
63
-
64
- expect(client.read(512)).to be == data
65
- end
66
-
67
- server_task.stop
68
- end
69
- end
70
- end
71
-
72
- context 'multiple hosts' do
73
- let(:hosts) {['test.com', 'example.com']}
74
-
75
- include_context Async::RSpec::SSL::HostCertificates
76
-
77
- let(:endpoint) {Async::IO::Endpoint.tcp("127.0.0.1", 6782, reuse_port: true)}
78
- let(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: server_context)}
79
- let(:valid_client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, hostname: 'example.com', ssl_context: client_context)}
80
- let(:invalid_client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, hostname: 'fleeb.com', ssl_context: client_context)}
81
-
82
- let(:data) {"What one programmer can do in one month, two programmers can do in two months."}
83
-
84
- it 'can select correct host' do
85
- # Accept a single incoming connection and then finish.
86
- server_task = reactor.async do |task|
87
- server_endpoint.bind do |server|
88
- server.listen(10)
89
-
90
- server.accept_each do |peer, address|
91
- expect(peer.hostname).to be == 'example.com'
92
-
93
- data = peer.read(512)
94
- peer.write(data)
95
- end
96
- end
97
- end
98
-
99
- reactor.async do
100
- valid_client_endpoint.connect do |client|
101
- client.write(data)
102
- client.close_write
103
-
104
- expect(client.read(512)).to be == data
105
- end
106
-
107
- server_task.stop
108
- end
109
- end
110
-
111
- it 'it fails with invalid host' do
112
- # Accept a single incoming connection and then finish.
113
- server_task = reactor.async do |task|
114
- server_endpoint.bind do |server|
115
- server.listen(10)
116
-
117
- server.accept_each do |peer, address|
118
- peer.close
119
- end
120
- end
121
- end
122
-
123
- reactor.async do
124
- expect do
125
- invalid_client_endpoint.connect do |client|
126
- end
127
- end.to raise_exception(OpenSSL::SSL::SSLError, /handshake failure/)
128
-
129
- server_task.stop
130
- end.wait
131
- end
132
- end
133
- end
@@ -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,318 +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
- end
81
-
82
- describe '#close_read' do
83
- subject {described_class.new(sockets.last)}
84
-
85
- it "can close the reading end of the stream" do
86
- expect(subject.io).to receive(:close_read).and_call_original
87
-
88
- subject.close_read
89
-
90
- # Ruby <= 2.4 raises an exception even with exception: false
91
- # expect(stream.read).to be_nil
92
- end
93
-
94
- it "can close the writing end of the stream" do
95
- expect(subject.io).to receive(:close_write).and_call_original
96
-
97
- subject.write("Oh yes!")
98
- subject.close_write
99
-
100
- expect do
101
- subject.write("Oh no!")
102
- subject.flush
103
- end.to raise_error(IOError, /not opened for writing/)
104
- end
105
- end
106
-
107
- describe '#read_exactly' do
108
- it "can read several bytes" do
109
- io.write("hello\nworld\n")
110
-
111
- expect(subject.read_exactly(4)).to be == 'hell'
112
- end
113
-
114
- it "can raise exception if io is eof" do
115
- io.close
116
-
117
- expect do
118
- subject.read_exactly(4)
119
- end.to raise_error(EOFError)
120
- end
121
- end
122
- end
123
-
124
- context "performance (BLOCK_SIZE: #{Async::IO::BLOCK_SIZE} MAXIMUM_READ_SIZE: #{Async::IO::MAXIMUM_READ_SIZE})" do
125
- include_context Async::RSpec::Reactor
126
-
127
- let!(:stream) {described_class.open("/dev/zero")}
128
- after {stream.close}
129
-
130
- it "can read data quickly" do |example|
131
- data = nil
132
-
133
- duration = Async::Clock.measure do
134
- data = stream.read(1024**3)
135
- end
136
-
137
- size = data.bytesize / 1024**2
138
- rate = size / duration
139
-
140
- example.reporter.message "Read #{size.round(2)}MB of data at #{rate.round(2)}MB/s."
141
-
142
- expect(rate).to be > 128
143
- end
144
- end
145
-
146
- context "buffered I/O" do
147
- include_context Async::IO::Stream
148
- include_context Async::RSpec::Memory
149
- include_context Async::RSpec::Reactor
150
-
151
- describe '#read' do
152
- it "should read everything" do
153
- io.write "Hello World"
154
- io.seek(0)
155
-
156
- expect(subject.io).to receive(:read_nonblock).and_call_original.twice
157
-
158
- expect(subject.read).to be == "Hello World"
159
- expect(subject).to be_eof
160
- end
161
-
162
- it "should read only the amount requested" do
163
- io.write "Hello World"
164
- io.seek(0)
165
-
166
- expect(subject.io).to receive(:read_nonblock).and_call_original.once
167
-
168
- expect(subject.read_partial(4)).to be == "Hell"
169
- expect(subject).to_not be_eof
170
-
171
- expect(subject.read_partial(20)).to be == "o World"
172
- expect(subject).to be_eof
173
- end
174
-
175
- context "with large content" do
176
- it "allocates expected amount of bytes" do
177
- io.write("." * 16*1024)
178
- io.seek(0)
179
-
180
- buffer = nil
181
-
182
- expect do
183
- # The read buffer is already allocated, and it will be resized to fit the incoming data. It will be swapped with an empty buffer.
184
- buffer = subject.read(16*1024)
185
- end.to limit_allocations.of(String, count: 1, size: 0)
186
-
187
- expect(buffer.size).to be == 16*1024
188
- end
189
- end
190
- end
191
-
192
- describe '#read_until' do
193
- it "can read a line" do
194
- io.write("hello\nworld\n")
195
- io.seek(0)
196
-
197
- expect(subject.read_until("\n")).to be == 'hello'
198
- expect(subject.read_until("\n")).to be == 'world'
199
- expect(subject.read_until("\n")).to be_nil
200
- end
201
-
202
- context "with 1-byte block size" do
203
- subject! {Async::IO::Stream.new(buffer, block_size: 1)}
204
-
205
- it "can read a line with a multi-byte pattern" do
206
- io.write("hello\r\nworld\r\n")
207
- io.seek(0)
208
-
209
- expect(subject.read_until("\r\n")).to be == 'hello'
210
- expect(subject.read_until("\r\n")).to be == 'world'
211
- expect(subject.read_until("\r\n")).to be_nil
212
- end
213
- end
214
-
215
- context "with large content" do
216
- it "allocates expected amount of bytes" do
217
- subject
218
-
219
- expect do
220
- subject.read_until("b")
221
- end.to limit_allocations.of(String, size: 0, count: 1)
222
- end
223
- end
224
- end
225
-
226
- describe '#flush' do
227
- it "should not call write if write buffer is empty" do
228
- expect(subject.io).to_not receive(:write)
229
-
230
- subject.flush
231
- end
232
-
233
- it "should flush underlying data when it exceeds block size" do
234
- expect(subject.io).to receive(:write).and_call_original.once
235
-
236
- subject.block_size.times do
237
- subject.write("!")
238
- end
239
- end
240
- end
241
-
242
- describe '#read_partial' do
243
- before(:each) do
244
- string = "Hello World!"
245
-
246
- io.write(string * (1 + (Async::IO::BLOCK_SIZE / string.bytesize)))
247
- io.seek(0)
248
- end
249
-
250
- it "should avoid calling read" do
251
- expect(subject.io).to receive(:read_nonblock).and_call_original.once
252
-
253
- expect(subject.read_partial(12)).to be == "Hello World!"
254
- end
255
-
256
- context "with large content" do
257
- it "allocates only the amount required" do
258
- expect do
259
- subject.read(4*1024)
260
- end.to limit_allocations.of(String, count: 2, size: 4*1024+1)
261
- end
262
-
263
- it "allocates exact number of bytes being read" do
264
- expect do
265
- subject.read_partial(subject.block_size * 2)
266
- end.to limit_allocations.of(String, count: 1, size: 0)
267
- end
268
-
269
- it "allocates expected amount of bytes" do
270
- buffer = nil
271
-
272
- expect do
273
- buffer = subject.read_partial
274
- end.to limit_allocations.of(String, count: 1)
275
-
276
- expect(buffer.size).to be == subject.block_size
277
- end
278
- end
279
- end
280
-
281
- describe '#write' do
282
- it "should read one line" do
283
- expect(subject.io).to receive(:write).and_call_original.once
284
-
285
- subject.write "Hello World\n"
286
- subject.flush
287
-
288
- io.seek(0)
289
- expect(subject.read).to be == "Hello World\n"
290
- end
291
- end
292
-
293
- describe '#eof' do
294
- it "should terminate subject" do
295
- expect do
296
- subject.eof!
297
- end.to raise_exception(EOFError)
298
-
299
- expect(subject).to be_eof
300
- end
301
- end
302
-
303
- describe '#close' do
304
- it 'can be closed even if underlying io is closed' do
305
- io.close
306
-
307
- expect(subject.io).to be_closed
308
-
309
- # Put some data in the write buffer
310
- subject.write "."
311
-
312
- expect do
313
- subject.close
314
- end.to_not raise_exception
315
- end
316
- end
317
- end
318
- end