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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/TODO.md +29 -35
- data/benchmark/common.rb +6 -6
- data/benchmark/gets.rb +49 -0
- data/benchmark/{read_each.rb → output.rb} +27 -24
- data/docs/design/buffer_pool.md +35 -0
- data/docs/um_api.md +2 -0
- data/ext/um/extconf.rb +6 -5
- data/ext/um/um.c +42 -13
- data/ext/um/um.h +103 -31
- data/ext/um/um_buffer_pool.c +246 -0
- data/ext/um/um_class.c +24 -12
- data/ext/um/um_op.c +29 -13
- data/ext/um/um_ssl.c +24 -27
- data/ext/um/um_stream.c +380 -150
- data/ext/um/um_stream_class.c +119 -63
- data/ext/um/um_utils.c +6 -6
- data/grant-2025/tasks.md +12 -7
- data/lib/uringmachine/fiber_scheduler.rb +36 -10
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +60 -19
- data/test/helper.rb +2 -0
- data/test/test_fiber.rb +93 -12
- data/test/test_fiber_scheduler.rb +5 -47
- data/test/test_stream.rb +447 -125
- data/test/test_um.rb +119 -49
- metadata +5 -4
- data/ext/um/um_buffer.c +0 -49
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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
|
|
23
|
-
|
|
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
|
-
|
|
27
|
-
assert_equal '
|
|
28
|
-
|
|
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
|
|
32
|
-
|
|
33
|
-
|
|
53
|
+
def test_stream_clear
|
|
54
|
+
rfd, wfd = UM.pipe
|
|
55
|
+
stream = UM::Stream.new(machine, rfd)
|
|
34
56
|
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
41
|
-
assert_equal
|
|
42
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
50
|
-
ret = @stream.get_line(buf, 3)
|
|
51
|
-
assert_nil ret
|
|
52
|
-
assert_equal '', buf
|
|
81
|
+
msg = '1234567' * 20000
|
|
53
82
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
assert_equal
|
|
72
|
-
assert_equal
|
|
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
|
|
76
|
-
machine.write(@wfd, "
|
|
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
|
-
|
|
80
|
-
assert_equal
|
|
81
|
-
assert_equal '
|
|
82
|
-
|
|
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
|
|
86
|
-
machine.write(@wfd, "
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
assert_equal '
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
assert_equal
|
|
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
|
|
100
|
-
machine.write(@wfd, "
|
|
188
|
+
def test_stream_get_string
|
|
189
|
+
machine.write(@wfd, "foobarbazblahzzz")
|
|
101
190
|
machine.close(@wfd)
|
|
102
191
|
|
|
103
|
-
|
|
104
|
-
assert_equal '
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
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
|
-
|
|
115
|
-
|
|
209
|
+
def test_stream_get_string_negative_len
|
|
210
|
+
machine.write(@wfd, "foobar")
|
|
116
211
|
|
|
117
|
-
|
|
118
|
-
assert_equal
|
|
212
|
+
assert_equal 'foo', stream.get_string(-3)
|
|
213
|
+
assert_equal 'bar', stream.get_string(-6)
|
|
119
214
|
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
124
|
-
|
|
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
|
|
244
|
+
def test_stream_resp_decode
|
|
130
245
|
machine.write(@wfd, "+foo bar\r\n")
|
|
131
|
-
assert_equal "foo bar",
|
|
246
|
+
assert_equal "foo bar", stream.resp_decode
|
|
132
247
|
|
|
133
248
|
machine.write(@wfd, "+baz\r\n")
|
|
134
|
-
assert_equal "baz",
|
|
249
|
+
assert_equal "baz", stream.resp_decode
|
|
135
250
|
|
|
136
251
|
machine.write(@wfd, "-foobar\r\n")
|
|
137
|
-
o =
|
|
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 =
|
|
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,
|
|
262
|
+
assert_equal 123, stream.resp_decode
|
|
148
263
|
|
|
149
264
|
machine.write(@wfd, ":-123\r\n")
|
|
150
|
-
assert_equal(-123,
|
|
265
|
+
assert_equal(-123, stream.resp_decode)
|
|
151
266
|
|
|
152
267
|
machine.write(@wfd, ",123.321\r\n")
|
|
153
|
-
assert_equal 123.321,
|
|
268
|
+
assert_equal 123.321, stream.resp_decode
|
|
154
269
|
|
|
155
270
|
machine.write(@wfd, "_\r\n")
|
|
156
|
-
assert_nil
|
|
271
|
+
assert_nil stream.resp_decode
|
|
157
272
|
|
|
158
273
|
machine.write(@wfd, "#t\r\n")
|
|
159
|
-
assert_equal true,
|
|
274
|
+
assert_equal true, stream.resp_decode
|
|
160
275
|
|
|
161
276
|
machine.write(@wfd, "#f\r\n")
|
|
162
|
-
assert_equal false,
|
|
277
|
+
assert_equal false, stream.resp_decode
|
|
163
278
|
|
|
164
279
|
machine.write(@wfd, "$6\r\nfoobar\r\n")
|
|
165
|
-
assert_equal "foobar",
|
|
280
|
+
assert_equal "foobar", stream.resp_decode
|
|
166
281
|
|
|
167
282
|
machine.write(@wfd, "$3\r\nbaz\r\n")
|
|
168
|
-
assert_equal "baz",
|
|
283
|
+
assert_equal "baz", stream.resp_decode
|
|
169
284
|
|
|
170
285
|
machine.write(@wfd, "=10\r\ntxt:foobar\r\n")
|
|
171
|
-
assert_equal "foobar",
|
|
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'],
|
|
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'],
|
|
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'],
|
|
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 },
|
|
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 },
|
|
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'] },
|
|
304
|
+
assert_equal({ 'a' => 42, 'b' => ['foo', 'bar', 'baz'] }, stream.resp_decode)
|
|
305
|
+
end
|
|
190
306
|
|
|
191
|
-
|
|
192
|
-
|
|
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
|
|
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",
|
|
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
|
-
|
|
219
|
-
|
|
340
|
+
class StreamStressTest < UMBaseTest
|
|
341
|
+
def setup
|
|
342
|
+
super
|
|
220
343
|
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
225
|
-
|
|
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
|
-
|
|
228
|
-
|
|
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
|
-
|
|
231
|
-
|
|
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
|
-
|
|
234
|
-
|
|
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
|
|
239
|
-
def
|
|
240
|
-
machine.
|
|
241
|
-
|
|
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
|
-
|
|
244
|
-
|
|
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
|
-
|
|
247
|
-
|
|
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
|
-
|
|
250
|
-
|
|
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
|