polyphony 0.19 → 0.20
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/.gitignore +1 -1
- data/.rubocop.yml +87 -1
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +17 -6
- data/README.md +200 -139
- data/Rakefile +4 -4
- data/TODO.md +35 -7
- data/bin/poly +11 -0
- data/docs/getting-started/getting-started.md +1 -1
- data/docs/summary.md +3 -0
- data/docs/technical-overview/exception-handling.md +94 -0
- data/docs/technical-overview/fiber-scheduling.md +99 -0
- data/examples/core/cancel.rb +8 -4
- data/examples/core/channel_echo.rb +18 -17
- data/examples/core/defer.rb +12 -0
- data/examples/core/enumerator.rb +4 -4
- data/examples/core/fiber_error.rb +9 -0
- data/examples/core/fiber_error_with_backtrace.rb +73 -0
- data/examples/core/fork.rb +6 -6
- data/examples/core/genserver.rb +16 -8
- data/examples/core/lock.rb +3 -3
- data/examples/core/move_on.rb +4 -3
- data/examples/core/move_on_twice.rb +5 -5
- data/examples/core/move_on_with_ensure.rb +8 -11
- data/examples/core/move_on_with_value.rb +14 -0
- data/examples/core/{multiple_spawn.rb → multiple_spin.rb} +5 -5
- data/examples/core/nested_cancel.rb +5 -5
- data/examples/core/{nested_multiple_spawn.rb → nested_multiple_spin.rb} +6 -6
- data/examples/core/nested_spin.rb +17 -0
- data/examples/core/pingpong.rb +21 -0
- data/examples/core/pulse.rb +4 -5
- data/examples/core/resource.rb +6 -4
- data/examples/core/resource_cancel.rb +6 -9
- data/examples/core/resource_delegate.rb +3 -3
- data/examples/core/sleep.rb +3 -3
- data/examples/core/sleep_spin.rb +19 -0
- data/examples/core/snooze.rb +32 -0
- data/examples/core/spin.rb +14 -0
- data/examples/core/{spawn_cancel.rb → spin_cancel.rb} +6 -7
- data/examples/core/spin_error.rb +17 -0
- data/examples/core/spin_error_backtrace.rb +30 -0
- data/examples/core/spin_uncaught_error.rb +15 -0
- data/examples/core/supervisor.rb +8 -8
- data/examples/core/supervisor_with_cancel_scope.rb +7 -7
- data/examples/core/supervisor_with_error.rb +8 -8
- data/examples/core/supervisor_with_manual_move_on.rb +6 -7
- data/examples/core/suspend.rb +13 -0
- data/examples/core/thread.rb +1 -1
- data/examples/core/thread_cancel.rb +9 -11
- data/examples/core/thread_pool.rb +18 -14
- data/examples/core/throttle.rb +7 -7
- data/examples/core/timeout.rb +3 -3
- data/examples/fs/read.rb +7 -9
- data/examples/http/config.ru +7 -3
- data/examples/http/cuba.ru +22 -0
- data/examples/http/happy_eyeballs.rb +6 -4
- data/examples/http/http_client.rb +1 -1
- data/examples/http/http_get.rb +1 -1
- data/examples/http/http_parse_experiment.rb +21 -16
- data/examples/http/http_proxy.rb +28 -26
- data/examples/http/http_server.rb +10 -10
- data/examples/http/http_server_forked.rb +6 -5
- data/examples/http/http_server_throttled.rb +3 -3
- data/examples/http/http_ws_server.rb +11 -11
- data/examples/http/https_raw_client.rb +1 -1
- data/examples/http/https_server.rb +8 -8
- data/examples/http/https_wss_server.rb +13 -11
- data/examples/http/rack_server.rb +2 -2
- data/examples/http/rack_server_https.rb +4 -4
- data/examples/http/rack_server_https_forked.rb +5 -5
- data/examples/http/websocket_secure_server.rb +6 -6
- data/examples/http/websocket_server.rb +5 -5
- data/examples/interfaces/pg_client.rb +4 -4
- data/examples/interfaces/pg_pool.rb +13 -6
- data/examples/interfaces/pg_transaction.rb +5 -4
- data/examples/interfaces/redis_channels.rb +15 -11
- data/examples/interfaces/redis_client.rb +2 -2
- data/examples/interfaces/redis_pubsub.rb +2 -1
- data/examples/interfaces/redis_pubsub_perf.rb +13 -9
- data/examples/io/backticks.rb +11 -0
- data/examples/io/cat.rb +4 -5
- data/examples/io/echo_client.rb +9 -4
- data/examples/io/echo_client_from_stdin.rb +20 -0
- data/examples/io/echo_pipe.rb +7 -8
- data/examples/io/echo_server.rb +8 -6
- data/examples/io/echo_server_with_timeout.rb +13 -10
- data/examples/io/echo_stdin.rb +3 -3
- data/examples/io/httparty.rb +2 -2
- data/examples/io/httparty_multi.rb +8 -4
- data/examples/io/httparty_threaded.rb +6 -2
- data/examples/io/io_read.rb +2 -2
- data/examples/io/irb.rb +16 -4
- data/examples/io/net-http.rb +3 -3
- data/examples/io/open.rb +17 -0
- data/examples/io/system.rb +3 -3
- data/examples/io/tcpserver.rb +15 -0
- data/examples/io/tcpsocket.rb +6 -5
- data/examples/performance/multi_snooze.rb +29 -0
- data/examples/performance/{perf_snooze.rb → snooze.rb} +7 -5
- data/examples/performance/snooze_raw.rb +39 -0
- data/ext/gyro/async.c +165 -0
- data/ext/gyro/child.c +167 -0
- data/ext/{ev → gyro}/extconf.rb +4 -3
- data/ext/gyro/gyro.c +316 -0
- data/ext/{ev/ev.h → gyro/gyro.h} +12 -7
- data/ext/gyro/gyro_ext.c +23 -0
- data/ext/{ev → gyro}/io.c +65 -57
- data/ext/{ev → gyro}/libev.h +0 -0
- data/ext/gyro/signal.c +117 -0
- data/ext/{ev → gyro}/socket.c +61 -6
- data/ext/gyro/timer.c +199 -0
- data/ext/libev/Changes +35 -0
- data/ext/libev/README +2 -1
- data/ext/libev/ev.c +213 -151
- data/ext/libev/ev.h +95 -88
- data/ext/libev/ev_epoll.c +26 -15
- data/ext/libev/ev_kqueue.c +11 -5
- data/ext/libev/ev_linuxaio.c +642 -0
- data/ext/libev/ev_poll.c +13 -8
- data/ext/libev/ev_port.c +5 -2
- data/ext/libev/ev_vars.h +14 -3
- data/ext/libev/ev_wrap.h +16 -0
- data/lib/ev_ext.bundle +0 -0
- data/lib/polyphony.rb +46 -50
- data/lib/polyphony/auto_run.rb +12 -0
- data/lib/polyphony/core/cancel_scope.rb +11 -7
- data/lib/polyphony/core/channel.rb +16 -9
- data/lib/polyphony/core/coprocess.rb +101 -51
- data/lib/polyphony/core/exceptions.rb +14 -12
- data/lib/polyphony/core/resource_pool.rb +21 -8
- data/lib/polyphony/core/supervisor.rb +10 -5
- data/lib/polyphony/core/sync.rb +7 -6
- data/lib/polyphony/core/thread.rb +4 -4
- data/lib/polyphony/core/thread_pool.rb +4 -4
- data/lib/polyphony/core/throttler.rb +6 -4
- data/lib/polyphony/extensions/core.rb +253 -0
- data/lib/polyphony/extensions/io.rb +28 -16
- data/lib/polyphony/extensions/openssl.rb +2 -1
- data/lib/polyphony/extensions/socket.rb +47 -52
- data/lib/polyphony/http.rb +4 -3
- data/lib/polyphony/http/agent.rb +68 -57
- data/lib/polyphony/http/server.rb +5 -5
- data/lib/polyphony/http/server/http1.rb +268 -0
- data/lib/polyphony/http/server/http2.rb +62 -0
- data/lib/polyphony/http/server/http2_stream.rb +104 -0
- data/lib/polyphony/http/server/rack.rb +64 -0
- data/lib/polyphony/http/server/request.rb +119 -0
- data/lib/polyphony/net.rb +26 -15
- data/lib/polyphony/postgres.rb +17 -13
- data/lib/polyphony/redis.rb +16 -15
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony/websocket.rb +11 -4
- data/polyphony.gemspec +13 -9
- data/test/eg.rb +27 -0
- data/test/helper.rb +25 -0
- data/test/run.rb +5 -0
- data/test/test_async.rb +33 -0
- data/test/test_coprocess.rb +239 -77
- data/test/test_core.rb +95 -61
- data/test/test_gyro.rb +148 -0
- data/test/test_http_server.rb +313 -0
- data/test/test_io.rb +79 -27
- data/test/test_kernel.rb +22 -12
- data/test/test_signal.rb +36 -0
- data/test/test_timer.rb +24 -0
- metadata +89 -33
- data/examples/core/nested_async.rb +0 -17
- data/examples/core/next_tick.rb +0 -12
- data/examples/core/sleep_spawn.rb +0 -19
- data/examples/core/spawn.rb +0 -14
- data/examples/core/spawn_error.rb +0 -28
- data/examples/performance/perf_multi_snooze.rb +0 -21
- data/ext/ev/async.c +0 -168
- data/ext/ev/child.c +0 -169
- data/ext/ev/ev_ext.c +0 -23
- data/ext/ev/ev_module.c +0 -242
- data/ext/ev/signal.c +0 -119
- data/ext/ev/timer.c +0 -197
- data/lib/polyphony/core/fiber_pool.rb +0 -98
- data/lib/polyphony/extensions/kernel.rb +0 -169
- data/lib/polyphony/http/http1_adapter.rb +0 -254
- data/lib/polyphony/http/http2_adapter.rb +0 -157
- data/lib/polyphony/http/rack.rb +0 -25
- data/lib/polyphony/http/request.rb +0 -66
- data/test/test_ev.rb +0 -110
data/polyphony.gemspec
CHANGED
@@ -14,20 +14,24 @@ Gem::Specification.new do |s|
|
|
14
14
|
}
|
15
15
|
s.rdoc_options = ["--title", "polyphony", "--main", "README.md"]
|
16
16
|
s.extra_rdoc_files = ["README.md"]
|
17
|
-
s.extensions = ["ext/
|
17
|
+
s.extensions = ["ext/gyro/extconf.rb"]
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
|
+
s.executables = ['poly']
|
21
|
+
|
20
22
|
s.add_runtime_dependency 'modulation', '~>0.25'
|
21
23
|
|
22
24
|
s.add_runtime_dependency 'http_parser.rb', '0.6.0'
|
23
25
|
s.add_runtime_dependency 'http-2', '0.10.0'
|
26
|
+
s.add_runtime_dependency 'rack'
|
24
27
|
|
25
|
-
s.add_development_dependency 'hiredis',
|
26
|
-
s.add_development_dependency 'httparty',
|
27
|
-
s.add_development_dependency 'localhost',
|
28
|
-
s.add_development_dependency 'minitest',
|
29
|
-
s.add_development_dependency '
|
30
|
-
s.add_development_dependency '
|
31
|
-
s.add_development_dependency '
|
32
|
-
s.add_development_dependency '
|
28
|
+
s.add_development_dependency 'hiredis', '0.6.3'
|
29
|
+
s.add_development_dependency 'httparty', '0.17.0'
|
30
|
+
s.add_development_dependency 'localhost', '1.1.4'
|
31
|
+
s.add_development_dependency 'minitest', '5.11.3'
|
32
|
+
s.add_development_dependency 'minitest-reporters', '1.4.2'
|
33
|
+
s.add_development_dependency 'pg', '1.1.3'
|
34
|
+
s.add_development_dependency 'rake-compiler', '1.0.5'
|
35
|
+
s.add_development_dependency 'redis', '4.1.0'
|
36
|
+
s.add_development_dependency 'websocket', '1.2.8'
|
33
37
|
end
|
data/test/eg.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
RE_CONST = /^[A-Z]/.freeze
|
5
|
+
RE_ATTR = /^@(.+)$/.freeze
|
6
|
+
|
7
|
+
def eg(hash)
|
8
|
+
Module.new.tap do |m|
|
9
|
+
s = m.singleton_class
|
10
|
+
hash.each do |k, v|
|
11
|
+
case k
|
12
|
+
when RE_CONST
|
13
|
+
m.const_set(k, v)
|
14
|
+
when RE_ATTR
|
15
|
+
m.instance_variable_set(k, v)
|
16
|
+
else
|
17
|
+
block = if v.respond_to?(:to_proc)
|
18
|
+
proc { |*args| instance_exec(*args, &v) }
|
19
|
+
else
|
20
|
+
proc { v }
|
21
|
+
end
|
22
|
+
s.define_method(k, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'minitest/reporters'
|
7
|
+
|
8
|
+
require 'polyphony'
|
9
|
+
require 'fileutils'
|
10
|
+
|
11
|
+
require_relative './eg'
|
12
|
+
|
13
|
+
::Exception.__disable_sanitized_backtrace__ = true
|
14
|
+
|
15
|
+
Minitest::Reporters.use! [
|
16
|
+
Minitest::Reporters::SpecReporter.new
|
17
|
+
]
|
18
|
+
|
19
|
+
class MiniTest::Test
|
20
|
+
def teardown
|
21
|
+
# wait for reactor loop to finish running
|
22
|
+
suspend
|
23
|
+
Polyphony.reset!
|
24
|
+
end
|
25
|
+
end
|
data/test/run.rb
ADDED
data/test/test_async.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
class AsyncTest < MiniTest::Test
|
6
|
+
def test_that_async_watcher_receives_signal_across_threads
|
7
|
+
count = 0
|
8
|
+
a = Gyro::Async.new do
|
9
|
+
count += 1
|
10
|
+
a.stop
|
11
|
+
end
|
12
|
+
Thread.new do
|
13
|
+
sync_sleep 0.001
|
14
|
+
a.signal!
|
15
|
+
end
|
16
|
+
suspend
|
17
|
+
assert_equal(1, count)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_that_async_watcher_coalesces_signals
|
21
|
+
count = 0
|
22
|
+
a = Gyro::Async.new do
|
23
|
+
count += 1
|
24
|
+
Gyro::Timer.new(0.01, 0).start { a.stop }
|
25
|
+
end
|
26
|
+
Thread.new do
|
27
|
+
sync_sleep 0.001
|
28
|
+
3.times { a.signal! }
|
29
|
+
end
|
30
|
+
suspend
|
31
|
+
assert_equal(1, count)
|
32
|
+
end
|
33
|
+
end
|
data/test/test_coprocess.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
|
2
|
-
require 'bundler/setup'
|
3
|
-
require 'polyphony'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
STDOUT.sync = true
|
9
6
|
|
10
|
-
|
7
|
+
class CoprocessTest < MiniTest::Test
|
8
|
+
def test_that_root_fiber_has_associated_coprocess
|
11
9
|
assert_equal(Fiber.current, Polyphony::Coprocess.current.fiber)
|
12
10
|
assert_equal(Polyphony::Coprocess.current, Fiber.current.coprocess)
|
13
11
|
end
|
@@ -18,24 +16,35 @@ class CoprocessTest < MiniTest::Test
|
|
18
16
|
assert_nil(result)
|
19
17
|
coproc.await
|
20
18
|
assert_equal(42, result)
|
19
|
+
ensure
|
20
|
+
coproc&.stop
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_that_new_coprocess_runs_on_different_fiber
|
24
24
|
coproc = Polyphony::Coprocess.new { Fiber.current }
|
25
25
|
fiber = coproc.await
|
26
26
|
assert(fiber != Fiber.current)
|
27
|
+
ensure
|
28
|
+
coproc&.stop
|
27
29
|
end
|
28
30
|
|
29
31
|
def test_that_await_blocks_until_coprocess_is_done
|
30
32
|
result = nil
|
31
|
-
coproc = Polyphony::Coprocess.new
|
33
|
+
coproc = Polyphony::Coprocess.new do
|
34
|
+
snooze
|
35
|
+
result = 42
|
36
|
+
end
|
32
37
|
coproc.await
|
33
38
|
assert_equal(42, result)
|
39
|
+
ensure
|
40
|
+
coproc&.stop
|
34
41
|
end
|
35
42
|
|
36
43
|
def test_that_await_returns_the_coprocess_return_value
|
37
|
-
coproc = Polyphony::Coprocess.new { [
|
38
|
-
assert_equal([
|
44
|
+
coproc = Polyphony::Coprocess.new { %i[foo bar] }
|
45
|
+
assert_equal(%i[foo bar], coproc.await)
|
46
|
+
ensure
|
47
|
+
coproc&.stop
|
39
48
|
end
|
40
49
|
|
41
50
|
def test_that_await_raises_error_raised_by_coprocess
|
@@ -43,162 +52,315 @@ class CoprocessTest < MiniTest::Test
|
|
43
52
|
coproc = Polyphony::Coprocess.new { raise 'foo' }
|
44
53
|
begin
|
45
54
|
result = coproc.await
|
46
|
-
rescue => e
|
55
|
+
rescue Exception => e
|
47
56
|
result = { error: e }
|
48
57
|
end
|
49
58
|
assert_kind_of(Hash, result)
|
50
59
|
assert_kind_of(RuntimeError, result[:error])
|
60
|
+
ensure
|
61
|
+
coproc&.stop
|
51
62
|
end
|
52
63
|
|
53
64
|
def test_that_running_coprocess_can_be_cancelled
|
54
65
|
result = []
|
55
|
-
|
66
|
+
error = nil
|
67
|
+
coproc = Polyphony::Coprocess.new do
|
56
68
|
result << 1
|
57
|
-
|
69
|
+
2.times { snooze }
|
58
70
|
result << 2
|
59
|
-
|
60
|
-
|
71
|
+
end.run
|
72
|
+
defer { coproc.cancel! }
|
73
|
+
assert_equal(0, result.size)
|
61
74
|
begin
|
62
75
|
coproc.await
|
63
|
-
rescue
|
64
|
-
|
76
|
+
rescue Polyphony::Cancel => e
|
77
|
+
error = e
|
65
78
|
end
|
66
|
-
assert_equal(
|
79
|
+
assert_equal(1, result.size)
|
67
80
|
assert_equal(1, result[0])
|
68
|
-
assert_kind_of(Polyphony::Cancel,
|
81
|
+
assert_kind_of(Polyphony::Cancel, error)
|
82
|
+
ensure
|
83
|
+
coproc&.stop
|
69
84
|
end
|
70
85
|
|
71
86
|
def test_that_running_coprocess_can_be_interrupted
|
72
87
|
# that is, stopped without exception
|
73
88
|
result = []
|
74
|
-
coproc = Polyphony::Coprocess.new
|
89
|
+
coproc = Polyphony::Coprocess.new do
|
75
90
|
result << 1
|
76
|
-
|
91
|
+
2.times { snooze }
|
77
92
|
result << 2
|
78
93
|
3
|
79
|
-
|
80
|
-
|
94
|
+
end.run
|
95
|
+
defer { coproc.stop(42) }
|
81
96
|
|
82
97
|
await_result = coproc.await
|
83
98
|
assert_equal(1, result.size)
|
84
99
|
assert_equal(42, await_result)
|
100
|
+
ensure
|
101
|
+
coproc&.stop
|
85
102
|
end
|
86
103
|
|
87
104
|
def test_that_coprocess_can_be_awaited
|
88
105
|
result = nil
|
89
|
-
|
90
|
-
|
91
|
-
|
106
|
+
cp2 = nil
|
107
|
+
cp1 = spin do
|
108
|
+
cp2 = Polyphony::Coprocess.new do
|
109
|
+
snooze
|
110
|
+
42
|
111
|
+
end
|
112
|
+
result = cp2.await
|
92
113
|
end
|
93
114
|
suspend
|
94
115
|
assert_equal(42, result)
|
116
|
+
ensure
|
117
|
+
cp1&.stop
|
118
|
+
cp2&.stop
|
95
119
|
end
|
96
120
|
|
97
121
|
def test_that_coprocess_can_be_stopped
|
98
122
|
result = nil
|
99
|
-
|
100
|
-
|
123
|
+
coproc = spin do
|
124
|
+
snooze
|
101
125
|
result = 42
|
102
126
|
end
|
103
|
-
|
127
|
+
defer { coproc.interrupt }
|
104
128
|
suspend
|
105
129
|
assert_nil(result)
|
130
|
+
ensure
|
131
|
+
coproc&.stop
|
106
132
|
end
|
107
133
|
|
108
134
|
def test_that_coprocess_can_be_cancelled
|
109
135
|
result = nil
|
110
|
-
|
111
|
-
|
136
|
+
coproc = spin do
|
137
|
+
snooze
|
112
138
|
result = 42
|
113
139
|
rescue Polyphony::Cancel => e
|
114
140
|
result = e
|
115
141
|
end
|
116
|
-
|
142
|
+
defer { coproc.cancel! }
|
117
143
|
|
118
144
|
suspend
|
119
145
|
|
120
146
|
assert_kind_of(Polyphony::Cancel, result)
|
121
|
-
assert_kind_of(Polyphony::Cancel,
|
122
|
-
assert_nil(
|
147
|
+
assert_kind_of(Polyphony::Cancel, coproc.result)
|
148
|
+
assert_nil(coproc.alive?)
|
149
|
+
ensure
|
150
|
+
coproc&.stop
|
123
151
|
end
|
124
152
|
|
125
153
|
def test_that_inner_coprocess_can_be_interrupted
|
126
154
|
result = nil
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
155
|
+
cp2 = nil
|
156
|
+
cp1 = spin do
|
157
|
+
cp2 = spin do
|
158
|
+
snooze
|
131
159
|
result = 42
|
132
160
|
end
|
133
|
-
|
161
|
+
cp2.await
|
134
162
|
result && result += 1
|
135
163
|
end
|
136
|
-
|
164
|
+
defer { cp1.interrupt }
|
137
165
|
suspend
|
138
166
|
assert_nil(result)
|
139
|
-
assert_nil(
|
140
|
-
assert_nil(
|
167
|
+
assert_nil(cp1.alive?)
|
168
|
+
assert_nil(cp2.alive?)
|
169
|
+
ensure
|
170
|
+
cp1&.stop
|
171
|
+
cp2&.stop
|
141
172
|
end
|
142
173
|
|
143
174
|
def test_that_inner_coprocess_can_interrupt_outer_coprocess
|
144
|
-
result,
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
175
|
+
result, cp2 = nil
|
176
|
+
|
177
|
+
cp1 = spin do
|
178
|
+
cp2 = spin do
|
179
|
+
defer { cp1.interrupt }
|
180
|
+
snooze
|
181
|
+
snooze
|
150
182
|
result = 42
|
151
183
|
end
|
152
|
-
|
184
|
+
cp2.await
|
153
185
|
result && result += 1
|
154
186
|
end
|
155
|
-
|
187
|
+
|
156
188
|
suspend
|
157
|
-
|
189
|
+
|
158
190
|
assert_nil(result)
|
159
|
-
assert_nil(
|
160
|
-
assert_nil(
|
191
|
+
assert_nil(cp1.alive?)
|
192
|
+
assert_nil(cp2.alive?)
|
193
|
+
ensure
|
194
|
+
cp1&.stop
|
195
|
+
cp2&.stop
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_alive?
|
199
|
+
counter = 0
|
200
|
+
coproc = spin do
|
201
|
+
3.times do
|
202
|
+
snooze
|
203
|
+
counter += 1
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
assert(coproc.alive?)
|
208
|
+
snooze
|
209
|
+
assert(coproc.alive?)
|
210
|
+
snooze while counter < 3
|
211
|
+
assert(!coproc.alive?)
|
212
|
+
ensure
|
213
|
+
coproc&.stop
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_coprocess_exception_propagation
|
217
|
+
# error is propagated to calling coprocess
|
218
|
+
raised_error = nil
|
219
|
+
spin do
|
220
|
+
spin do
|
221
|
+
raise 'foo'
|
222
|
+
end
|
223
|
+
snooze # allow nested coprocess to run before finishing
|
224
|
+
end
|
225
|
+
suspend
|
226
|
+
rescue Exception => e
|
227
|
+
raised_error = e
|
228
|
+
ensure
|
229
|
+
assert(raised_error)
|
230
|
+
assert_equal('foo', raised_error.message)
|
161
231
|
end
|
162
232
|
end
|
163
233
|
|
164
|
-
|
165
|
-
|
166
|
-
|
234
|
+
def test_exception_propagation_for_orphan_fiber
|
235
|
+
raised_error = nil
|
236
|
+
spin do
|
237
|
+
spin do
|
238
|
+
snooze
|
239
|
+
raise 'bar'
|
240
|
+
end
|
167
241
|
end
|
242
|
+
suspend
|
243
|
+
rescue Exception => e
|
244
|
+
raised_error = e
|
245
|
+
ensure
|
246
|
+
assert(raised_error)
|
247
|
+
assert_equal('bar', raised_error.message)
|
248
|
+
end
|
168
249
|
|
250
|
+
class MailboxTest < MiniTest::Test
|
169
251
|
def test_that_coprocess_can_receive_messages
|
170
252
|
msgs = []
|
171
|
-
|
172
|
-
loop {
|
173
|
-
msgs << receive
|
174
|
-
}
|
175
|
-
}
|
253
|
+
coproc = spin { loop { msgs << receive } }
|
176
254
|
|
177
|
-
|
178
|
-
|
179
|
-
3.times
|
255
|
+
snooze # allow coproc to start
|
256
|
+
|
257
|
+
3.times do |i|
|
258
|
+
coproc << i
|
259
|
+
snooze
|
260
|
+
end
|
180
261
|
|
181
262
|
assert_equal([0, 1, 2], msgs)
|
182
263
|
ensure
|
183
|
-
|
264
|
+
coproc&.stop
|
184
265
|
end
|
185
266
|
|
186
|
-
def
|
267
|
+
def test_that_multiple_messages_sent_at_once_arrive_in_order
|
187
268
|
msgs = []
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
}
|
192
|
-
}
|
269
|
+
coproc = spin { loop { msgs << receive } }
|
270
|
+
|
271
|
+
snooze # allow coproc to start
|
193
272
|
|
194
|
-
|
195
|
-
|
196
|
-
3.times { |i| coprocess << i }
|
273
|
+
3.times { |i| coproc << i }
|
197
274
|
|
198
|
-
|
275
|
+
snooze
|
199
276
|
|
200
277
|
assert_equal([0, 1, 2], msgs)
|
201
278
|
ensure
|
202
|
-
|
279
|
+
coproc&.stop
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_when_done
|
283
|
+
flag = nil
|
284
|
+
values = []
|
285
|
+
coproc = spin do
|
286
|
+
snooze until flag
|
287
|
+
end
|
288
|
+
coproc.when_done { values << 42 }
|
289
|
+
|
290
|
+
snooze
|
291
|
+
assert values.empty?
|
292
|
+
snooze
|
293
|
+
flag = true
|
294
|
+
assert values.empty?
|
295
|
+
assert coproc.alive?
|
296
|
+
|
297
|
+
snooze
|
298
|
+
assert_equal [42], values
|
299
|
+
assert !coproc.alive?
|
300
|
+
end
|
301
|
+
|
302
|
+
def test_resume
|
303
|
+
values = []
|
304
|
+
coproc = spin do
|
305
|
+
values << 1
|
306
|
+
x = suspend
|
307
|
+
values << x
|
308
|
+
suspend
|
309
|
+
values << 3
|
310
|
+
end
|
311
|
+
snooze
|
312
|
+
assert_equal [1], values
|
313
|
+
|
314
|
+
coproc.resume 2
|
315
|
+
assert_equal [1, 2], values
|
316
|
+
|
317
|
+
coproc.resume
|
318
|
+
assert_equal [1, 2, 3], values
|
319
|
+
|
320
|
+
assert !coproc.alive?
|
321
|
+
end
|
322
|
+
|
323
|
+
def test_interrupt
|
324
|
+
coproc = spin do
|
325
|
+
sleep 1
|
326
|
+
:foo
|
327
|
+
end
|
328
|
+
|
329
|
+
snooze
|
330
|
+
assert coproc.alive?
|
331
|
+
|
332
|
+
coproc.interrupt :bar
|
333
|
+
assert !coproc.alive?
|
334
|
+
|
335
|
+
assert_equal :bar, coproc.result
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_cancel
|
339
|
+
error = nil
|
340
|
+
coproc = spin do
|
341
|
+
sleep 1
|
342
|
+
:foo
|
343
|
+
end
|
344
|
+
|
345
|
+
snooze
|
346
|
+
coproc.cancel!
|
347
|
+
rescue Polyphony::Cancel => e
|
348
|
+
# cancel error should bubble up
|
349
|
+
error = e
|
350
|
+
ensure
|
351
|
+
assert error
|
352
|
+
assert !coproc.alive?
|
353
|
+
end
|
354
|
+
|
355
|
+
def test_current
|
356
|
+
assert_equal Fiber.root.coprocess, Polyphony::Coprocess.current
|
357
|
+
|
358
|
+
value = nil
|
359
|
+
coproc = spin do
|
360
|
+
value = :ok if Polyphony::Coprocess.current == coproc
|
361
|
+
end
|
362
|
+
|
363
|
+
snooze
|
364
|
+
assert_equal :ok, value
|
203
365
|
end
|
204
366
|
end
|