uringmachine 0.28.3 → 0.29.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.
data/test/test_stream.rb CHANGED
@@ -1,198 +1,325 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'helper'
4
+ require 'securerandom'
5
+ require 'openssl'
6
+ require 'localhost/authority'
4
7
 
5
8
  class StreamBaseTest < UMBaseTest
9
+ attr_reader :stream
10
+
6
11
  def setup
7
12
  super
8
13
  @rfd, @wfd = UM.pipe
9
14
  @stream = UM::Stream.new(@machine, @rfd)
10
15
  end
11
- end
12
16
 
13
- class StreamTest < StreamBaseTest
14
- def test_stream_machine
15
- assert_equal @machine, @stream.machine
17
+ def teardown
18
+ @stream = nil
19
+ machine.close(@rfd) rescue nil
20
+ machine.close(@wfd) rescue nil
21
+ super
16
22
  end
23
+ end
17
24
 
18
- def test_stream_fd
19
- assert_equal @rfd, @stream.fd
25
+ class StreamTest < StreamBaseTest
26
+ def buffer_metrics
27
+ machine.metrics.fetch_values(
28
+ :buffers_allocated,
29
+ :buffers_free,
30
+ :segments_free,
31
+ :buffer_space_allocated,
32
+ :buffer_space_commited,
33
+ )
20
34
  end
21
35
 
22
- def test_get_line
23
- machine.write(@wfd, "foo\nbar\r\nbaz")
36
+ def test_stream_basic_usage
37
+ assert_equal [0, 0, 0, 0, 0], buffer_metrics
38
+ machine.write(@wfd, "foobar")
24
39
  machine.close(@wfd)
25
40
 
26
- assert_equal 'foo', @stream.get_line(nil, 0)
27
- assert_equal 'bar', @stream.get_line(nil, 0)
28
- assert_nil @stream.get_line(nil, 0)
41
+ buf = stream.get_string(3)
42
+ assert_equal 'foo', buf
43
+
44
+ buf = stream.get_string(-6)
45
+ assert_equal 'bar', buf
46
+ assert stream.eof?
47
+
48
+ stream.clear
49
+ assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 6], buffer_metrics
50
+ assert_equal 0, machine.metrics[:ops_pending]
29
51
  end
30
52
 
31
- def test_get_line_with_buf
32
- machine.write(@wfd, "foo\nbar\r\nbaz")
33
- machine.close(@wfd)
53
+ def test_stream_clear
54
+ rfd, wfd = UM.pipe
55
+ stream = UM::Stream.new(machine, rfd)
34
56
 
35
- buf = +''
36
- ret = @stream.get_line(buf, 0)
57
+ assert_equal [0, 0, 0, 0, 0], buffer_metrics
58
+ machine.write(wfd, "foobar")
59
+
60
+ buf = stream.get_string(3)
37
61
  assert_equal 'foo', buf
38
- assert_equal ret, buf
39
62
 
40
- ret = @stream.get_line(buf, 0)
41
- assert_equal 'bar', buf
42
- assert_equal ret, buf
63
+ assert_equal 1, machine.metrics[:ops_pending]
64
+ assert_equal 255, machine.metrics[:segments_free]
65
+
66
+ stream.clear
67
+ machine.snooze
68
+ assert_equal 0, machine.metrics[:ops_pending]
69
+ assert_equal 256, machine.metrics[:segments_free]
70
+
71
+ assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 6], buffer_metrics
72
+ ensure
73
+ machine.close(rfd) rescue nil
74
+ machine.close(wfd) rescue nil
43
75
  end
44
76
 
45
- def test_get_line_with_positive_maxlen
46
- machine.write(@wfd, "foobar\r\n")
47
- machine.close(@wfd)
77
+ def test_stream_big_read
78
+ s1, s2 = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
79
+ stream = UM::Stream.new(machine, s2)
48
80
 
49
- buf = +''
50
- ret = @stream.get_line(buf, 3)
51
- assert_nil ret
52
- assert_equal '', buf
81
+ msg = '1234567' * 20000
53
82
 
54
- # verify that stream pos has not changed
55
- ret = @stream.get_line(buf, 0)
56
- assert_equal 'foobar', buf
57
- assert_equal ret, buf
83
+ f = machine.spin do
84
+ machine.sendv(s1, msg)
85
+ machine.snooze
86
+ machine.shutdown(s1, UM::SHUT_WR)
87
+ end
88
+
89
+ buf = stream.get_string(msg.bytesize)
90
+ assert_equal msg, buf
91
+ ensure
92
+ machine.terminate(f)
93
+ machine.join(f)
58
94
  end
59
95
 
60
- def test_get_line_with_negative_maxlen
61
- machine.write(@wfd, "foobar\r\n")
96
+ def test_stream_buffer_reuse
97
+ s1, s2 = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
98
+ stream = UM::Stream.new(machine, s2)
99
+
100
+ msg = '1234567' * 20000
101
+
102
+ f = machine.spin do
103
+ machine.sendv(s1, msg, msg)
104
+ machine.sleep(0.05)
105
+ machine.sendv(s1, msg, msg)
106
+ machine.shutdown(s1, UM::SHUT_WR)
107
+ end
108
+
109
+ buf = stream.get_string(msg.bytesize)
110
+ assert_equal msg, buf
111
+
112
+ buf = stream.get_string(msg.bytesize)
113
+ assert_equal msg, buf
114
+
115
+ buf = stream.get_string(msg.bytesize)
116
+ assert_equal msg, buf
117
+
118
+ buf = stream.get_string(msg.bytesize)
119
+ assert_equal msg, buf
120
+
121
+ assert_equal 16, machine.metrics[:buffers_allocated]
122
+ assert_equal 11, machine.metrics[:buffers_free]
123
+ assert_equal 256, machine.metrics[:segments_free]
124
+ assert_equal 65536 * 4, machine.metrics[:buffer_space_allocated]
125
+
126
+ ensure
127
+ machine.terminate(f)
128
+ machine.join(f)
129
+ end
130
+
131
+ def test_stream_get_line
132
+ machine.write(@wfd, "foo\nbar\r\nbaz")
62
133
  machine.close(@wfd)
63
134
 
64
- buf = +''
65
- ret = @stream.get_line(buf, -3)
66
- assert_nil ret
67
- assert_equal '', buf
135
+ assert_equal [0, 0, 0, 0, 0], buffer_metrics
68
136
 
69
- # verify that stream pos has not changed
70
- ret = @stream.get_line(buf, 0)
71
- assert_equal 'foobar', buf
72
- assert_equal ret, buf
137
+ assert_equal 'foo', stream.get_line(0)
138
+
139
+ assert_equal [5, 0, 255, 16384 * 5, 16384 * 5 - 12], buffer_metrics
140
+ assert_equal 'bar', stream.get_line(0)
141
+ assert_nil stream.get_line(0)
142
+ assert_equal "baz", stream.get_string(-6)
73
143
  end
74
144
 
75
- def test_get_string
76
- machine.write(@wfd, "foobarbazblahzzz")
145
+ def test_stream_get_line_segmented
146
+ machine.write(@wfd, "foo\n")
147
+ assert_equal 'foo', stream.get_line(0)
148
+
149
+ machine.write(@wfd, "bar")
150
+ machine.write(@wfd, "\r\n")
151
+ machine.write(@wfd, "baz\n")
77
152
  machine.close(@wfd)
78
153
 
79
- assert_equal 'foobar', @stream.get_string(nil, 6)
80
- assert_equal 'baz', @stream.get_string(nil, 3)
81
- assert_equal 'blah', @stream.get_string(nil, 4)
82
- assert_nil @stream.get_string(nil, 4)
154
+ # three segments received
155
+ assert_equal [5, 0, 253, 16384 * 5, 16384 * 5 - 13], buffer_metrics
156
+ assert_equal 'bar', stream.get_line(0)
157
+ assert_equal [5, 0, 255, 16384 * 5, 16384 * 5 - 13], buffer_metrics
158
+ assert_equal 'baz', stream.get_line(0)
159
+ assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 13], buffer_metrics
160
+ assert_nil stream.get_line(0)
83
161
  end
84
162
 
85
- def test_get_string_with_buf
86
- machine.write(@wfd, "foobarbazblahzzz")
163
+ def test_stream_get_line_maxlen
164
+ machine.write(@wfd, "foobar\r\n")
165
+
166
+ assert_nil stream.get_line(3)
167
+ # verify that stream pos has not changed
168
+ assert_equal 'foobar', stream.get_line(0)
169
+
170
+ machine.write(@wfd, "baz")
171
+ machine.write(@wfd, "\n")
172
+ machine.write(@wfd, "bizz")
173
+ machine.write(@wfd, "\n")
87
174
  machine.close(@wfd)
88
175
 
89
- buf = +''
90
- ret = @stream.get_string(buf, 6)
91
- assert_equal 'foobar', buf
92
- assert_equal ret, buf
176
+ assert_nil stream.get_line(2)
177
+ assert_nil stream.get_line(3)
178
+ assert_equal 'baz', stream.get_line(4)
93
179
 
94
- ret = @stream.get_string(buf, 3)
95
- assert_equal 'baz', buf
96
- assert_equal ret, buf
180
+ assert_nil stream.get_line(3)
181
+ assert_nil stream.get_line(4)
182
+ assert_equal 'bizz', stream.get_line(5)
183
+
184
+ assert_nil stream.get_line(8)
185
+ assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 17], buffer_metrics
97
186
  end
98
187
 
99
- def test_get_string_with_negative_len
100
- machine.write(@wfd, "foobar")
188
+ def test_stream_get_string
189
+ machine.write(@wfd, "foobarbazblahzzz")
101
190
  machine.close(@wfd)
102
191
 
103
- ret = @stream.get_string(nil, -12)
104
- assert_equal 'foobar', ret
105
-
106
- ret = @stream.get_string(nil, -4)
107
- assert_nil ret
192
+ assert_equal 'foobar', stream.get_string(6)
193
+ assert_equal 'baz', stream.get_string(3)
194
+ assert_equal 'blah', stream.get_string(4)
195
+ assert_nil stream.get_string(4)
108
196
  end
109
197
 
110
- def test_skip
198
+ def test_stream_get_string_zero_len
111
199
  machine.write(@wfd, "foobar")
200
+
201
+ assert_equal 'foobar', stream.get_string(0)
202
+
203
+ machine.write(@wfd, "bazblah")
112
204
  machine.close(@wfd)
205
+ assert_equal 'bazblah', stream.get_string(0)
206
+ assert_nil stream.get_string(0)
207
+ end
113
208
 
114
- ret = @stream.get_string(nil, 2)
115
- assert_equal 'fo', ret
209
+ def test_stream_get_string_negative_len
210
+ machine.write(@wfd, "foobar")
116
211
 
117
- ret = @stream.skip(2)
118
- assert_equal 2, ret
212
+ assert_equal 'foo', stream.get_string(-3)
213
+ assert_equal 'bar', stream.get_string(-6)
119
214
 
120
- ret = @stream.get_string(nil, 2)
121
- assert_equal 'ar', ret
215
+ machine.write(@wfd, "bazblah")
216
+ machine.close(@wfd)
217
+ assert_equal 'bazblah', stream.get_string(-12)
218
+ assert_nil stream.get_string(-3)
219
+ end
122
220
 
123
- ret = @stream.skip(2)
124
- assert_nil ret
221
+ def test_stream_big_data
222
+ data = SecureRandom.random_bytes(300_000)
223
+ fiber = machine.spin {
224
+ machine.writev(@wfd, data)
225
+ machine.close(@wfd)
226
+ }
227
+
228
+ received = []
229
+ loop {
230
+ msg = stream.get_string(-60_000)
231
+ break if !msg
232
+
233
+ received << msg
234
+ }
235
+ machine.join(fiber)
236
+ # since a pipe is limited to 64KB, we're going to receive 4 pairs of 60000B
237
+ # and 5536B, then the remainder
238
+ assert_equal 9, received.size
239
+ assert_equal data, received.join
125
240
  end
126
241
  end
127
242
 
128
243
  class StreamRespTest < StreamBaseTest
129
- def test_resp_decode
244
+ def test_stream_resp_decode
130
245
  machine.write(@wfd, "+foo bar\r\n")
131
- assert_equal "foo bar", @stream.resp_decode
246
+ assert_equal "foo bar", stream.resp_decode
132
247
 
133
248
  machine.write(@wfd, "+baz\r\n")
134
- assert_equal "baz", @stream.resp_decode
249
+ assert_equal "baz", stream.resp_decode
135
250
 
136
251
  machine.write(@wfd, "-foobar\r\n")
137
- o = @stream.resp_decode
252
+ o = stream.resp_decode
138
253
  assert_kind_of UM::Stream::RESPError, o
139
254
  assert_equal "foobar", o.message
140
255
 
141
256
  machine.write(@wfd, "!3\r\nbaz\r\n")
142
- o = @stream.resp_decode
257
+ o = stream.resp_decode
143
258
  assert_kind_of UM::Stream::RESPError, o
144
259
  assert_equal "baz", o.message
145
260
 
146
261
  machine.write(@wfd, ":123\r\n")
147
- assert_equal 123, @stream.resp_decode
262
+ assert_equal 123, stream.resp_decode
148
263
 
149
264
  machine.write(@wfd, ":-123\r\n")
150
- assert_equal(-123, @stream.resp_decode)
265
+ assert_equal(-123, stream.resp_decode)
151
266
 
152
267
  machine.write(@wfd, ",123.321\r\n")
153
- assert_equal 123.321, @stream.resp_decode
268
+ assert_equal 123.321, stream.resp_decode
154
269
 
155
270
  machine.write(@wfd, "_\r\n")
156
- assert_nil @stream.resp_decode
271
+ assert_nil stream.resp_decode
157
272
 
158
273
  machine.write(@wfd, "#t\r\n")
159
- assert_equal true, @stream.resp_decode
274
+ assert_equal true, stream.resp_decode
160
275
 
161
276
  machine.write(@wfd, "#f\r\n")
162
- assert_equal false, @stream.resp_decode
277
+ assert_equal false, stream.resp_decode
163
278
 
164
279
  machine.write(@wfd, "$6\r\nfoobar\r\n")
165
- assert_equal "foobar", @stream.resp_decode
280
+ assert_equal "foobar", stream.resp_decode
166
281
 
167
282
  machine.write(@wfd, "$3\r\nbaz\r\n")
168
- assert_equal "baz", @stream.resp_decode
283
+ assert_equal "baz", stream.resp_decode
169
284
 
170
285
  machine.write(@wfd, "=10\r\ntxt:foobar\r\n")
171
- assert_equal "foobar", @stream.resp_decode
286
+ assert_equal "foobar", stream.resp_decode
172
287
 
173
288
  machine.write(@wfd, "*3\r\n+foo\r\n:42\r\n$3\r\nbar\r\n")
174
- assert_equal ['foo', 42, 'bar'], @stream.resp_decode
289
+ assert_equal ['foo', 42, 'bar'], stream.resp_decode
175
290
 
176
291
  machine.write(@wfd, "~3\r\n+foo\r\n:42\r\n$3\r\nbar\r\n")
177
- assert_equal ['foo', 42, 'bar'], @stream.resp_decode
292
+ assert_equal ['foo', 42, 'bar'], stream.resp_decode
178
293
 
179
294
  machine.write(@wfd, ">3\r\n+foo\r\n:42\r\n$3\r\nbar\r\n")
180
- assert_equal ['foo', 42, 'bar'], @stream.resp_decode
295
+ assert_equal ['foo', 42, 'bar'], stream.resp_decode
181
296
 
182
297
  machine.write(@wfd, "%2\r\n+a\r\n:42\r\n+b\r\n:43\r\n")
183
- assert_equal({ 'a' => 42, 'b' => 43 }, @stream.resp_decode)
298
+ assert_equal({ 'a' => 42, 'b' => 43 }, stream.resp_decode)
184
299
 
185
300
  machine.write(@wfd, "|2\r\n+a\r\n:42\r\n+b\r\n:43\r\n")
186
- assert_equal({ 'a' => 42, 'b' => 43 }, @stream.resp_decode)
301
+ assert_equal({ 'a' => 42, 'b' => 43 }, stream.resp_decode)
187
302
 
188
303
  machine.write(@wfd, "%2\r\n+a\r\n:42\r\n+b\r\n*3\r\n+foo\r\n+bar\r\n+baz\r\n")
189
- assert_equal({ 'a' => 42, 'b' => ['foo', 'bar', 'baz'] }, @stream.resp_decode)
304
+ assert_equal({ 'a' => 42, 'b' => ['foo', 'bar', 'baz'] }, stream.resp_decode)
305
+ end
190
306
 
191
- machine.write(@wfd, "%2\r\n+a\r\n:42\r\n+b\r\n*3\r\n+foo\r\n+xbar\r\n+yybaz\r\n")
192
- assert_equal({ 'a' => 42, 'b' => ['foo', 'xbar', 'yybaz'] }, @stream.resp_decode)
307
+ def test_stream_resp_decode_segmented
308
+ machine.write(@wfd, "\n")
309
+ assert_equal "", stream.get_line(0)
310
+
311
+ machine.write(@wfd, "+foo")
312
+ machine.write(@wfd, " ")
313
+ machine.write(@wfd, "bar\r")
314
+ machine.write(@wfd, "\n")
315
+ assert_equal "foo bar", stream.resp_decode
316
+ machine.write(@wfd, "$6\r")
317
+ machine.write(@wfd, "\nbazbug")
318
+ machine.write(@wfd, "\r\n")
319
+ assert_equal "bazbug", stream.resp_decode
193
320
  end
194
321
 
195
- def test_resp_encode
322
+ def test_stream_resp_encode
196
323
  s = UM::Stream
197
324
  assert_equal "_\r\n", s.resp_encode(+'', nil)
198
325
  assert_equal "#t\r\n", s.resp_encode(+'', true)
@@ -200,54 +327,249 @@ class StreamRespTest < StreamBaseTest
200
327
  assert_equal ":42\r\n", s.resp_encode(+'', 42)
201
328
  assert_equal ",42.1\r\n", s.resp_encode(+'', 42.1)
202
329
  assert_equal "$6\r\nfoobar\r\n", s.resp_encode(+'', 'foobar')
203
- assert_equal "$10\r\nפובאר\r\n", s.resp_encode(+'', 'פובאר')
204
-
205
- assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
206
- s.resp_encode(+'', ['foo', 'bar'])
330
+ assert_equal "$10\r\nפובאר\r\n", s.resp_encode(+'', 'פובאר')
207
331
 
208
332
  assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
209
333
  s.resp_encode(+'', ['foo', 'bar'])
210
334
 
211
- assert_equal "*2\r\n$3\r\nfoo\r\n$4\r\nxbar\r\n",
212
- s.resp_encode(+'', ['foo', 'xbar'])
213
-
214
335
  assert_equal "%2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$3\r\nbaz\r\n:42\r\n",
215
336
  s.resp_encode(+'', { 'foo' => 'bar', 'baz' => 42 })
216
337
  end
338
+ end
217
339
 
218
- def test_resp_encode_cmd
219
- s = UM::Stream
340
+ class StreamStressTest < UMBaseTest
341
+ def setup
342
+ super
220
343
 
221
- assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
222
- s.resp_encode_cmd(+'', 'foo', 'bar')
344
+ @port = assign_port
345
+ @listen_fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
346
+ machine.setsockopt(@listen_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
347
+ machine.setsockopt(@listen_fd, UM::SOL_SOCKET, UM::SO_REUSEPORT, true)
348
+ machine.bind(@listen_fd, '127.0.0.1', @port)
349
+ machine.listen(@listen_fd, 128)
223
350
 
224
- assert_equal "*2\r\n$3\r\nfoo\r\n$4\r\nxbar\r\n",
225
- s.resp_encode_cmd(+'', 'foo', 'xbar')
351
+ @received = []
352
+ @response_body = "Hello, world!"
353
+ @response_headers = "HTTP/1.1 200\r\nContent-Length: #{@response_body.bytesize}\r\n\r\n"
354
+ end
226
355
 
227
- assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
228
- s.resp_encode_cmd(+'', 'foo', :bar)
356
+ def start_connection_fiber(fd)
357
+ machine.spin do
358
+ stream = UM::Stream.new(machine, fd)
359
+ while (msg = stream.get_line(0))
360
+ @received << msg
361
+ end
362
+ machine.sendv(fd, @response_headers, @response_body)
363
+ machine.close(fd)
364
+ rescue => e
365
+ p e
366
+ p e.backtrace
367
+ end
368
+ end
229
369
 
230
- assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\n123\r\n",
231
- s.resp_encode_cmd(+'', 'foo', 123)
370
+ def test_stream_server_big_lines
371
+ server_fibers = []
372
+ server_fibers << machine.spin do
373
+ machine.accept_each(@listen_fd) { |fd|
374
+ server_fibers << start_connection_fiber(fd)
375
+ }
376
+ rescue Errno::EINVAL
377
+ ignore
378
+ rescue => e
379
+ p e
380
+ p e.backtrace
381
+ end
382
+
383
+ client_count = 1000
384
+ msg_count = 100
385
+ length = 100
386
+
387
+ total_msgs = client_count * msg_count
388
+ msg = "#{SecureRandom.hex(length / 2)}\n" * msg_count
389
+ client_fibers = client_count.times.map {
390
+ machine.snooze
391
+ machine.spin do
392
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
393
+ machine.connect(fd, '127.0.0.1', @port)
394
+ machine.sleep(0.05)
395
+ machine.send(fd, msg, msg.bytesize, UM::MSG_WAITALL)
396
+ machine.sleep(0.05)
397
+ machine.close(fd)
398
+ rescue => e
399
+ p e
400
+ p e.backtrace
401
+ end
402
+ }
403
+
404
+ machine.await(client_fibers)
405
+ machine.shutdown(@listen_fd, UM::SHUT_RD)
406
+ machine.await(server_fibers)
407
+ machine.snooze
408
+
409
+ assert_equal total_msgs, @received.size
410
+ assert_equal msg * client_count, @received.map { it + "\n" }.join
411
+ end
232
412
 
233
- assert_equal "*4\r\n$3\r\nset\r\n$6\r\nfoobar\r\n$2\r\nnx\r\n$2\r\nxx\r\n",
234
- s.resp_encode_cmd(+'', :set, 'foobar', :nx, :xx)
413
+ def test_stream_server_http
414
+ server_fibers = []
415
+ server_fibers << machine.spin do
416
+ machine.accept_each(@listen_fd) { |fd|
417
+ server_fibers << start_connection_fiber(fd)
418
+ }
419
+ rescue Errno::EINVAL
420
+ # ignore
421
+ rescue => e
422
+ p e
423
+ p e.backtrace
424
+ end
425
+
426
+ client_count = 1000
427
+ msg_count = 16
428
+ msg = "GET http://127.0.0.1:1234/ HTTP/1.1\r\nhost: 127.0.0.1\r\n\r\n"
429
+ client_fibers = client_count.times.map {
430
+ machine.snooze
431
+ machine.spin do
432
+ fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
433
+ machine.connect(fd, '127.0.0.1', @port)
434
+ msg_count.times {
435
+ machine.send(fd, msg, msg.bytesize, UM::MSG_WAITALL)
436
+ }
437
+ machine.close(fd)
438
+ rescue => e
439
+ p e
440
+ p e.backtrace
441
+ end
442
+ }
443
+
444
+ machine.await(client_fibers)
445
+ machine.shutdown(@listen_fd, UM::SHUT_RD)
446
+ machine.await(server_fibers)
447
+ machine.snooze
448
+ # assert_equal total_msgs, @received.size
449
+ assert_equal msg * msg_count * client_count, @received.map { it + "\r\n" }.join
235
450
  end
236
451
  end
237
452
 
238
- class StreamHTTPTest < StreamBaseTest
239
- def test_stream_http_etc
240
- machine.write(@wfd, "GET / HTTP/1.1\r\n\r\nblahblah")
241
- machine.close(@wfd)
453
+ class StreamDevRandomTest < UMBaseTest
454
+ def test_stream_dev_random_get_line
455
+ fd = machine.open('/dev/random', UM::O_RDONLY)
456
+ stream = UM::Stream.new(machine, fd)
457
+
458
+ n = 100000
459
+ lines = []
460
+ n.times {
461
+ lines << stream.get_line(0)
462
+ }
463
+
464
+ assert_equal n, lines.size
465
+ ensure
466
+ stream.clear rescue nil
467
+ machine.close(fd) rescue nil
468
+ end
242
469
 
243
- l = @stream.get_line(nil, 0)
244
- assert_equal "GET / HTTP/1.1", l
470
+ def test_stream_dev_random_get_string
471
+ fd = machine.open('/dev/random', UM::O_RDONLY)
472
+ stream = UM::Stream.new(machine, fd)
473
+
474
+ n = 256
475
+ size = 65536 * 8
476
+ count = 0
477
+ # lines = []
478
+ n.times {
479
+ l = stream.get_string(size)
480
+ refute_nil l
481
+ assert_equal size, l.bytesize
482
+
483
+ count += 1
484
+ }
485
+
486
+ assert_equal n, count
487
+ ensure
488
+ stream.clear rescue nil
489
+ end
490
+ end
245
491
 
246
- l = @stream.get_line(nil, 0)
247
- assert_equal '', l
492
+ class StreamModeTest < UMBaseTest
493
+ def test_stream_default_mode
494
+ r, w = UM.pipe
495
+ stream = UM::Stream.new(machine, r)
496
+ assert_equal :bp_read, stream.mode
497
+ ensure
498
+ machine.close(r) rescue nil
499
+ machine.close(w) rescue nil
500
+ end
248
501
 
249
- l = @stream.get_string(nil, -50)
250
- assert_equal 'blahblah', l
502
+ def test_stream_recv_mode_non_socket
503
+ r, w = UM.pipe
504
+ machine.write(w, 'foobar')
505
+ machine.close(w)
506
+
507
+ stream = UM::Stream.new(machine, r, :bp_recv)
508
+ assert_equal :bp_recv, stream.mode
509
+ # assert :bp_recv, stream.mode
510
+ assert_raises(Errno::ENOTSOCK) { stream.get_string(0) }
511
+ ensure
512
+ machine.close(r) rescue nil
513
+ machine.close(w) rescue nil
251
514
  end
252
- end
253
515
 
516
+ def test_stream_recv_mode_socket
517
+ r, w = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
518
+ machine.write(w, 'foobar')
519
+ machine.close(w)
520
+
521
+ stream = UM::Stream.new(machine, r, :bp_recv)
522
+ assert_equal :bp_recv, stream.mode
523
+ buf = stream.get_string(0)
524
+ assert_equal 'foobar', buf
525
+ ensure
526
+ machine.close(r) rescue nil
527
+ machine.close(w) rescue nil
528
+ end
529
+
530
+ def test_stream_ssl_mode
531
+ authority = Localhost::Authority.fetch
532
+ @server_ctx = authority.server_context
533
+ sock1, sock2 = UNIXSocket.pair
534
+
535
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1, @server_ctx)
536
+ s1.sync_close = true
537
+ s2 = OpenSSL::SSL::SSLSocket.new(sock2, OpenSSL::SSL::SSLContext.new)
538
+ s2.sync_close = true
539
+
540
+ @machine.ssl_set_bio(s1)
541
+ @machine.ssl_set_bio(s2)
542
+ assert_equal true, s1.instance_variable_get(:@__um_bio__)
543
+ assert_equal true, s2.instance_variable_get(:@__um_bio__)
544
+
545
+ f = machine.spin { s1.accept rescue nil }
546
+
547
+ s2.connect
548
+ refute_equal 0, @machine.metrics[:total_ops]
549
+
550
+ buf = "foobar\nbaz"
551
+ assert_equal 10, @machine.ssl_write(s1, buf, buf.bytesize)
552
+ buf = +''
553
+
554
+ stream = UM::Stream.new(machine, s2, :ssl)
555
+ assert_equal "foobar", stream.get_line(0)
556
+
557
+ buf = "buh"
558
+ @machine.ssl_write(s1, buf, buf.bytesize)
559
+
560
+ assert_equal "baz", stream.get_string(0)
561
+ assert_equal "buh", stream.get_string(0)
562
+
563
+ s1.close
564
+
565
+ assert_nil stream.get_string(0)
566
+ rescue => e
567
+ p e
568
+ p e.backtrace
569
+ exit!
570
+ ensure
571
+ machine.join(f)
572
+ sock1&.close rescue nil
573
+ sock2&.close rescue nil
574
+ end
575
+ end