uringmachine 0.28.3 → 0.29.1

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