celluloid 0.16.0 → 0.17.3
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/CHANGES.md +394 -0
- data/LICENSE.txt +1 -1
- data/README.md +28 -15
- data/culture/CONDUCT.md +28 -0
- data/culture/Gemfile +9 -0
- data/culture/LICENSE.txt +22 -0
- data/culture/README.md +22 -0
- data/culture/Rakefile +5 -0
- data/culture/SYNC.md +70 -0
- data/culture/celluloid-culture.gemspec +18 -0
- data/culture/gems/README.md +39 -0
- data/culture/gems/dependencies.yml +85 -0
- data/culture/gems/loader.rb +101 -0
- data/culture/rubocop/README.md +38 -0
- data/culture/rubocop/lint.yml +8 -0
- data/culture/rubocop/metrics.yml +15 -0
- data/culture/rubocop/perf.yml +0 -0
- data/culture/rubocop/rubocop.yml +5 -0
- data/culture/rubocop/style.yml +57 -0
- data/culture/spec/gems_spec.rb +2 -0
- data/culture/spec/spec_helper.rb +0 -0
- data/culture/spec/sync_spec.rb +2 -0
- data/culture/sync.rb +56 -0
- data/culture/tasks/rspec.rake +5 -0
- data/culture/tasks/rubocop.rake +2 -0
- data/examples/basic_usage.rb +49 -0
- data/examples/futures.rb +38 -0
- data/examples/ring.rb +61 -0
- data/examples/simple_pmap.rb +14 -0
- data/examples/stack.rb +47 -0
- data/examples/timers.rb +72 -0
- data/lib/celluloid/actor/manager.rb +7 -0
- data/lib/celluloid/actor/system.rb +163 -0
- data/lib/celluloid/actor.rb +53 -71
- data/lib/celluloid/autostart.rb +1 -1
- data/lib/celluloid/backported.rb +2 -0
- data/lib/celluloid/call/async.rb +16 -0
- data/lib/celluloid/call/block.rb +22 -0
- data/lib/celluloid/call/sync.rb +70 -0
- data/lib/celluloid/calls.rb +24 -114
- data/lib/celluloid/cell.rb +32 -20
- data/lib/celluloid/condition.rb +5 -6
- data/lib/celluloid/core_ext.rb +1 -1
- data/lib/celluloid/current.rb +2 -0
- data/lib/celluloid/debug.rb +1 -0
- data/lib/celluloid/deprecate.rb +21 -0
- data/lib/celluloid/exceptions.rb +22 -16
- data/lib/celluloid/fiber.rb +3 -3
- data/lib/celluloid/future.rb +46 -8
- data/lib/celluloid/group/pool.rb +125 -0
- data/lib/celluloid/group/spawner.rb +68 -0
- data/lib/celluloid/group.rb +61 -0
- data/lib/celluloid/logging.rb +5 -5
- data/lib/celluloid/mailbox/evented.rb +74 -0
- data/lib/celluloid/mailbox.rb +15 -14
- data/lib/celluloid/managed.rb +3 -0
- data/lib/celluloid/notices.rb +15 -0
- data/lib/celluloid/proxies.rb +11 -0
- data/lib/celluloid/proxy/abstract.rb +50 -0
- data/lib/celluloid/proxy/actor.rb +37 -0
- data/lib/celluloid/proxy/async.rb +15 -0
- data/lib/celluloid/proxy/block.rb +28 -0
- data/lib/celluloid/proxy/cell.rb +66 -0
- data/lib/celluloid/proxy/future.rb +20 -0
- data/lib/celluloid/proxy/sync.rb +24 -0
- data/lib/celluloid/rspec.rb +67 -9
- data/lib/celluloid/system_events.rb +69 -14
- data/lib/celluloid/task/fibered.rb +45 -0
- data/lib/celluloid/task/threaded.rb +59 -0
- data/lib/celluloid/{tasks.rb → task.rb} +30 -38
- data/lib/celluloid/test.rb +1 -1
- data/lib/celluloid/thread.rb +6 -1
- data/lib/celluloid/version.rb +3 -0
- data/lib/celluloid.rb +151 -130
- data/spec/celluloid/actor/system_spec.rb +83 -0
- data/spec/celluloid/actor_spec.rb +2 -2
- data/spec/celluloid/block_spec.rb +67 -8
- data/spec/celluloid/calls_spec.rb +28 -23
- data/spec/celluloid/condition_spec.rb +23 -14
- data/spec/celluloid/evented_mailbox_spec.rb +1 -31
- data/spec/celluloid/future_spec.rb +15 -12
- data/spec/celluloid/group/elastic_spec.rb +0 -0
- data/spec/celluloid/group/pool_spec.rb +8 -0
- data/spec/celluloid/group/spawner_spec.rb +17 -0
- data/spec/celluloid/mailbox/evented_spec.rb +40 -0
- data/spec/celluloid/mailbox_spec.rb +1 -3
- data/spec/celluloid/misc/leak_spec.rb +73 -0
- data/spec/celluloid/proxy_spec.rb +33 -0
- data/spec/celluloid/task/fibered_spec.rb +5 -0
- data/spec/celluloid/task/threaded_spec.rb +5 -0
- data/spec/celluloid/timer_spec.rb +14 -16
- data/spec/deprecate/actor_system_spec.rb +72 -0
- data/spec/deprecate/block_spec.rb +52 -0
- data/spec/deprecate/calls_spec.rb +39 -0
- data/spec/deprecate/evented_mailbox_spec.rb +34 -0
- data/spec/deprecate/future_spec.rb +32 -0
- data/spec/deprecate/internal_pool_spec.rb +4 -0
- data/spec/shared/actor_examples.rb +1259 -0
- data/spec/shared/group_examples.rb +121 -0
- data/spec/shared/mailbox_examples.rb +87 -0
- data/{lib/celluloid/rspec → spec/shared}/task_examples.rb +9 -8
- data/spec/spec_helper.rb +5 -42
- data/spec/support/configure_rspec.rb +77 -0
- data/spec/support/coverage.rb +4 -0
- data/spec/support/crash_checking.rb +68 -0
- data/spec/support/debugging.rb +31 -0
- data/spec/support/env.rb +21 -0
- data/{lib/celluloid/rspec/example_actor_class.rb → spec/support/examples/actor_class.rb} +21 -2
- data/spec/support/examples/call_class.rb +37 -0
- data/spec/support/examples/evented_mailbox_class.rb +27 -0
- data/spec/support/includer.rb +6 -0
- data/spec/support/logging.rb +55 -0
- data/spec/support/loose_threads.rb +68 -0
- data/spec/support/reset_class_variables.rb +27 -0
- data/spec/support/sleep_and_wait.rb +14 -0
- data/spec/support/stubbing.rb +14 -0
- metadata +276 -78
- data/lib/celluloid/actor_system.rb +0 -107
- data/lib/celluloid/call_chain.rb +0 -13
- data/lib/celluloid/cpu_counter.rb +0 -34
- data/lib/celluloid/evented_mailbox.rb +0 -73
- data/lib/celluloid/fsm.rb +0 -186
- data/lib/celluloid/handlers.rb +0 -41
- data/lib/celluloid/internal_pool.rb +0 -159
- data/lib/celluloid/legacy.rb +0 -9
- data/lib/celluloid/links.rb +0 -36
- data/lib/celluloid/logger.rb +0 -93
- data/lib/celluloid/logging/incident.rb +0 -21
- data/lib/celluloid/logging/incident_logger.rb +0 -129
- data/lib/celluloid/logging/incident_reporter.rb +0 -48
- data/lib/celluloid/logging/log_event.rb +0 -20
- data/lib/celluloid/logging/ring_buffer.rb +0 -65
- data/lib/celluloid/method.rb +0 -32
- data/lib/celluloid/notifications.rb +0 -83
- data/lib/celluloid/pool_manager.rb +0 -146
- data/lib/celluloid/probe.rb +0 -73
- data/lib/celluloid/properties.rb +0 -24
- data/lib/celluloid/proxies/abstract_proxy.rb +0 -20
- data/lib/celluloid/proxies/actor_proxy.rb +0 -38
- data/lib/celluloid/proxies/async_proxy.rb +0 -31
- data/lib/celluloid/proxies/block_proxy.rb +0 -29
- data/lib/celluloid/proxies/cell_proxy.rb +0 -68
- data/lib/celluloid/proxies/future_proxy.rb +0 -35
- data/lib/celluloid/proxies/sync_proxy.rb +0 -36
- data/lib/celluloid/receivers.rb +0 -63
- data/lib/celluloid/registry.rb +0 -57
- data/lib/celluloid/responses.rb +0 -44
- data/lib/celluloid/rspec/actor_examples.rb +0 -1054
- data/lib/celluloid/rspec/mailbox_examples.rb +0 -84
- data/lib/celluloid/signals.rb +0 -23
- data/lib/celluloid/stack_dump.rb +0 -133
- data/lib/celluloid/supervision_group.rb +0 -169
- data/lib/celluloid/supervisor.rb +0 -22
- data/lib/celluloid/task_set.rb +0 -49
- data/lib/celluloid/tasks/task_fiber.rb +0 -43
- data/lib/celluloid/tasks/task_thread.rb +0 -53
- data/lib/celluloid/thread_handle.rb +0 -50
- data/lib/celluloid/uuid.rb +0 -38
- data/spec/celluloid/actor_system_spec.rb +0 -69
- data/spec/celluloid/cpu_counter_spec.rb +0 -82
- data/spec/celluloid/fsm_spec.rb +0 -107
- data/spec/celluloid/internal_pool_spec.rb +0 -52
- data/spec/celluloid/links_spec.rb +0 -45
- data/spec/celluloid/logging/ring_buffer_spec.rb +0 -38
- data/spec/celluloid/notifications_spec.rb +0 -120
- data/spec/celluloid/pool_spec.rb +0 -92
- data/spec/celluloid/probe_spec.rb +0 -121
- data/spec/celluloid/properties_spec.rb +0 -42
- data/spec/celluloid/registry_spec.rb +0 -64
- data/spec/celluloid/stack_dump_spec.rb +0 -64
- data/spec/celluloid/supervision_group_spec.rb +0 -65
- data/spec/celluloid/supervisor_spec.rb +0 -103
- data/spec/celluloid/tasks/task_fiber_spec.rb +0 -5
- data/spec/celluloid/tasks/task_thread_spec.rb +0 -5
- data/spec/celluloid/thread_handle_spec.rb +0 -26
- data/spec/celluloid/uuid_spec.rb +0 -11
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
RSpec.shared_examples "a Celluloid Group" do
|
|
2
|
+
let!(:queue) { Queue.new }
|
|
3
|
+
let!(:busy_queue) { Queue.new }
|
|
4
|
+
|
|
5
|
+
let(:logger) { Specs::FakeLogger.current }
|
|
6
|
+
|
|
7
|
+
def wait_until_busy(busy_queue = nil)
|
|
8
|
+
return busy_queue.pop if busy_queue
|
|
9
|
+
Specs.sleep_and_wait_until { subject.busy? }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def wait_until_idle
|
|
13
|
+
Specs.sleep_and_wait_until { subject.idle? }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
before { subject }
|
|
17
|
+
|
|
18
|
+
after do
|
|
19
|
+
subject.shutdown
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "gets threads" do
|
|
23
|
+
expect(subject.get { queue.pop }).to be_a Thread
|
|
24
|
+
queue << nil
|
|
25
|
+
wait_until_idle
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
[::StandardError, ::Exception].each do |exception_class|
|
|
29
|
+
context "with an #{exception_class} in the thread" do
|
|
30
|
+
before do
|
|
31
|
+
@wait_queue = Queue.new # doesn't work if in a let()
|
|
32
|
+
|
|
33
|
+
allow(logger).to receive(:crash)
|
|
34
|
+
|
|
35
|
+
subject.get do
|
|
36
|
+
busy_queue << nil
|
|
37
|
+
@wait_queue.pop
|
|
38
|
+
fail exception_class, "Error"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
wait_until_busy(busy_queue)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "logs the crash" do
|
|
45
|
+
expect(logger).to receive(:crash).with("thread crashed", exception_class)
|
|
46
|
+
@wait_queue << nil # let the thread fail
|
|
47
|
+
wait_until_idle
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "puts error'd threads back" do
|
|
51
|
+
@wait_queue << nil # let the thread fail
|
|
52
|
+
wait_until_idle
|
|
53
|
+
expect(subject.idle?).to be_truthy
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "when a thread has local variables" do
|
|
59
|
+
before do
|
|
60
|
+
@thread = subject.get do
|
|
61
|
+
Thread.current[:foo] = :bar
|
|
62
|
+
queue.pop
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
wait_until_busy
|
|
66
|
+
|
|
67
|
+
queue << nil # let the thread finish
|
|
68
|
+
if Celluloid.group_class == Celluloid::Group::Pool
|
|
69
|
+
# Wait until we get the same thread for a different proc
|
|
70
|
+
Specs.sleep_and_wait_until { subject.get { sleep 0.1 } == @thread }
|
|
71
|
+
else
|
|
72
|
+
wait_until_idle
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Cleaning not necessary for Spawner
|
|
77
|
+
unless Celluloid.group_class == Celluloid::Group::Spawner
|
|
78
|
+
it "cleans thread locals from old threads" do
|
|
79
|
+
expect(@thread[:foo]).to be_nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "shuts down" do
|
|
85
|
+
subject
|
|
86
|
+
thread = Queue.new
|
|
87
|
+
|
|
88
|
+
expect(
|
|
89
|
+
subject.get do
|
|
90
|
+
thread << Thread.current
|
|
91
|
+
sleep
|
|
92
|
+
end,
|
|
93
|
+
).to be_a(Celluloid::Thread)
|
|
94
|
+
|
|
95
|
+
thread.pop # wait for 3rd-party thread to get strated
|
|
96
|
+
|
|
97
|
+
expect(subject.active?).to eq true
|
|
98
|
+
subject.shutdown
|
|
99
|
+
expect(subject.active?).to eq false
|
|
100
|
+
expect(subject.group.length).to eq 0
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context "with a dead thread" do
|
|
104
|
+
before do
|
|
105
|
+
if Celluloid.group_class == Celluloid::Group::Pool
|
|
106
|
+
subject.max_idle = 0 # Instruct the pool to immediately shut down the thread.
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
subject.get { queue.pop }
|
|
110
|
+
wait_until_busy
|
|
111
|
+
queue << nil
|
|
112
|
+
wait_until_idle
|
|
113
|
+
|
|
114
|
+
subject.shutdown if Celluloid.group_class == Celluloid::Group::Spawner
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "doesn't leak dead threads" do
|
|
118
|
+
expect(subject.to_a.size).to eq(0)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
RSpec.shared_examples "a Celluloid Mailbox" do
|
|
2
|
+
after do
|
|
3
|
+
allow(Celluloid.logger).to receive(:debug)
|
|
4
|
+
subject.shutdown if subject.alive?
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
it "receives messages" do
|
|
8
|
+
message = :ohai
|
|
9
|
+
|
|
10
|
+
subject << message
|
|
11
|
+
expect(subject.receive).to eq(message)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "prioritizes system events over other messages" do
|
|
15
|
+
subject << :dummy1
|
|
16
|
+
subject << :dummy2
|
|
17
|
+
|
|
18
|
+
subject << Celluloid::SystemEvent.new
|
|
19
|
+
expect(subject.receive).to be_a(Celluloid::SystemEvent)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "selectively receives messages with a block" do
|
|
23
|
+
class Foo; end
|
|
24
|
+
class Bar; end
|
|
25
|
+
class Baz; end
|
|
26
|
+
|
|
27
|
+
foo = Foo.new
|
|
28
|
+
bar = Bar.new
|
|
29
|
+
baz = Baz.new
|
|
30
|
+
|
|
31
|
+
subject << baz
|
|
32
|
+
subject << foo
|
|
33
|
+
subject << bar
|
|
34
|
+
|
|
35
|
+
expect(subject.receive { |msg| msg.is_a? Foo }).to eq(foo)
|
|
36
|
+
expect(subject.receive { |msg| msg.is_a? Bar }).to eq(bar)
|
|
37
|
+
expect(subject.receive).to eq(baz)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "waits for a given timeout interval" do
|
|
41
|
+
interval = 0.1
|
|
42
|
+
started_at = Time.now
|
|
43
|
+
|
|
44
|
+
expect do
|
|
45
|
+
subject.receive(interval) { false }
|
|
46
|
+
end.to raise_exception(Celluloid::TaskTimeout)
|
|
47
|
+
|
|
48
|
+
# Just check to make sure it didn't return earlier
|
|
49
|
+
expect(Time.now - started_at).to be >= interval
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "has a size" do
|
|
53
|
+
expect(subject).to respond_to(:size)
|
|
54
|
+
expect(subject.size).to be_zero
|
|
55
|
+
subject << :foo
|
|
56
|
+
subject << :foo
|
|
57
|
+
expect(subject.entries.size).to eq(2)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "discards messages received when when full" do
|
|
61
|
+
subject.max_size = 2
|
|
62
|
+
subject << :first
|
|
63
|
+
subject << :second
|
|
64
|
+
subject << :third
|
|
65
|
+
expect(subject.to_a).to match_array([:first, :second])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "logs discarded messages" do
|
|
69
|
+
expect(Celluloid.logger).to receive(:debug).with("Discarded message (mailbox is dead): third")
|
|
70
|
+
|
|
71
|
+
subject.max_size = 2
|
|
72
|
+
subject << :first
|
|
73
|
+
subject << :second
|
|
74
|
+
subject << :third
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "discard messages when dead" do
|
|
78
|
+
expect(Celluloid.logger).to receive(:debug).with("Discarded message (mailbox is dead): first")
|
|
79
|
+
expect(Celluloid.logger).to receive(:debug).with("Discarded message (mailbox is dead): second")
|
|
80
|
+
expect(Celluloid.logger).to receive(:debug).with("Discarded message (mailbox is dead): third")
|
|
81
|
+
|
|
82
|
+
subject << :first
|
|
83
|
+
subject << :second
|
|
84
|
+
subject.shutdown
|
|
85
|
+
subject << :third
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -9,12 +9,12 @@ class MockActor
|
|
|
9
9
|
end
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
RSpec.shared_examples "a Celluloid Task" do
|
|
13
13
|
let(:task_type) { :foobar }
|
|
14
14
|
let(:suspend_state) { :doing_something }
|
|
15
15
|
let(:actor) { MockActor.new }
|
|
16
16
|
|
|
17
|
-
subject { task_class.new(task_type, {}) { Celluloid::Task.suspend(suspend_state) } }
|
|
17
|
+
subject { Celluloid.task_class.new(task_type, {}) { Celluloid::Task.suspend(suspend_state) } }
|
|
18
18
|
|
|
19
19
|
before :each do
|
|
20
20
|
Thread.current[:celluloid_actor_system] = Celluloid.actor_system
|
|
@@ -22,25 +22,26 @@ shared_context "a Celluloid Task" do |task_class|
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
after :each do
|
|
25
|
+
Thread.current[:celluloid_actor_system].shutdown
|
|
25
26
|
Thread.current[:celluloid_actor] = nil
|
|
26
27
|
Thread.current[:celluloid_actor_system] = nil
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
it "begins with status :new" do
|
|
30
|
-
subject.status.
|
|
31
|
+
expect(subject.status).to be :new
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
it "resumes" do
|
|
34
|
-
subject.
|
|
35
|
+
expect(subject).to be_running
|
|
35
36
|
subject.resume
|
|
36
|
-
subject.status.
|
|
37
|
+
expect(subject.status).to eq(suspend_state)
|
|
37
38
|
subject.resume
|
|
38
|
-
subject.
|
|
39
|
+
expect(subject).not_to be_running
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
it "raises exceptions outside" do
|
|
42
|
-
task = task_class.new(task_type, {}) do
|
|
43
|
-
|
|
43
|
+
task = Celluloid.task_class.new(task_type, {}) do
|
|
44
|
+
fail "failure"
|
|
44
45
|
end
|
|
45
46
|
expect do
|
|
46
47
|
task.resume
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,44 +1,7 @@
|
|
|
1
|
-
require
|
|
2
|
-
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "bundler/setup"
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require 'celluloid/rspec'
|
|
7
|
-
require 'celluloid/probe'
|
|
4
|
+
require "celluloid/rspec"
|
|
5
|
+
require "celluloid/essentials"
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
logfile.sync = true
|
|
11
|
-
|
|
12
|
-
Celluloid.logger = Logger.new(logfile)
|
|
13
|
-
|
|
14
|
-
Celluloid.shutdown_timeout = 1
|
|
15
|
-
|
|
16
|
-
Dir['./spec/support/*.rb'].map {|f| require f }
|
|
17
|
-
|
|
18
|
-
RSpec.configure do |config|
|
|
19
|
-
config.filter_run :focus => true
|
|
20
|
-
config.run_all_when_everything_filtered = true
|
|
21
|
-
|
|
22
|
-
config.around do |ex|
|
|
23
|
-
Celluloid.actor_system = nil
|
|
24
|
-
Thread.list.each do |thread|
|
|
25
|
-
next if thread == Thread.current
|
|
26
|
-
thread.kill
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
ex.run
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
config.around actor_system: :global do |ex|
|
|
33
|
-
Celluloid.boot
|
|
34
|
-
ex.run
|
|
35
|
-
Celluloid.shutdown
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
config.around actor_system: :within do |ex|
|
|
39
|
-
Celluloid::ActorSystem.new.within do
|
|
40
|
-
ex.run
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
end
|
|
7
|
+
Dir[*Specs::INCLUDE_PATHS].map { |f| require f }
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
RSpec.configure do |config|
|
|
2
|
+
config.filter_run focus: true unless Nenv.ci?
|
|
3
|
+
config.run_all_when_everything_filtered = true
|
|
4
|
+
config.disable_monkey_patching!
|
|
5
|
+
config.profile_examples = 3
|
|
6
|
+
config.filter_gems_from_backtrace(*Specs::BACKTRACE_OMITTED)
|
|
7
|
+
|
|
8
|
+
config.verbose_retry = true
|
|
9
|
+
config.default_retry_count = Specs::ALLOW_RETRIES
|
|
10
|
+
config.display_try_failure_messages = true
|
|
11
|
+
config.default_sleep_interval = 1
|
|
12
|
+
config.exceptions_to_retry = [Timeout::Error, Celluloid::ThreadLeak]
|
|
13
|
+
|
|
14
|
+
config.mock_with :rspec do |mocks|
|
|
15
|
+
mocks.verify_doubled_constant_names = true
|
|
16
|
+
mocks.verify_partial_doubles = true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
config.before(:suite) do
|
|
20
|
+
Specs.stub_out_class_method(Celluloid::Internals::Logger, :crash) do |*args|
|
|
21
|
+
_name, ex = *args
|
|
22
|
+
fail "Unstubbed Logger.crash() was called:\n crash(\n #{args.map(&:inspect).join(",\n ")})"\
|
|
23
|
+
"\nException backtrace: \n (#{ex.class}) #{ex.backtrace * "\n (#{ex.class}) "}"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
config.before(:each) do |example|
|
|
28
|
+
@fake_logger = Specs::FakeLogger.new(Celluloid.logger, example.description)
|
|
29
|
+
stub_const("Celluloid::Internals::Logger", @fake_logger)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
config.around do |ex|
|
|
33
|
+
# Needed because some specs mock/stub/expect on the logger
|
|
34
|
+
Celluloid.logger = Specs.logger
|
|
35
|
+
Celluloid.actor_system = nil
|
|
36
|
+
Specs.reset_class_variables(ex.description) do
|
|
37
|
+
Timeout.timeout(Specs::MAX_EXECUTION) { ex.run }
|
|
38
|
+
end
|
|
39
|
+
if @fake_logger.crashes?
|
|
40
|
+
crashes = @fake_logger.crashes.map do |args, call_stack|
|
|
41
|
+
msg, ex = *args
|
|
42
|
+
"\n** Crash: #{msg.inspect}(#{ex.inspect})\n Backtrace:\n (crash) #{call_stack * "\n (crash) "}"\
|
|
43
|
+
"\n Exception Backtrace (#{ex.inspect}):\n (ex) #{ex.backtrace * "\n (ex) "}"
|
|
44
|
+
end.join("\n")
|
|
45
|
+
fail "Actor crashes occured (please stub/mock if these are expected): #{crashes}"
|
|
46
|
+
end
|
|
47
|
+
@fake_logger = nil
|
|
48
|
+
Specs.assert_no_loose_threads!("after example: #{ex.description}") if Specs::CHECK_LOOSE_THREADS
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
config.around :each, library: :IO do |ex|
|
|
52
|
+
Celluloid.init
|
|
53
|
+
FileUtils.rm("/tmp/cell_sock") if File.exist?("/tmp/cell_sock")
|
|
54
|
+
ex.run
|
|
55
|
+
Celluloid.shutdown
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
config.around :each, library: :ZMQ do |ex|
|
|
59
|
+
Celluloid::ZMQ.init(1) unless ex.metadata[:no_init]
|
|
60
|
+
Celluloid.boot
|
|
61
|
+
ex.run
|
|
62
|
+
Celluloid.shutdown
|
|
63
|
+
Celluloid::ZMQ.terminate
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
config.around :each, actor_system: :global do |ex|
|
|
67
|
+
Celluloid.boot
|
|
68
|
+
ex.run
|
|
69
|
+
Celluloid.shutdown
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
config.around :each, actor_system: :within do |ex|
|
|
73
|
+
Celluloid::Actor::System.new.within do
|
|
74
|
+
ex.run
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Specs
|
|
2
|
+
class FakeLogger
|
|
3
|
+
class << self
|
|
4
|
+
def current
|
|
5
|
+
allowed_logger.first
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
attr_accessor :allowed_logger
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(real_logger, example)
|
|
12
|
+
@mutex = Mutex.new
|
|
13
|
+
@real_logger = real_logger
|
|
14
|
+
@crashes = Queue.new
|
|
15
|
+
@details = nil
|
|
16
|
+
@example = example
|
|
17
|
+
self.class.allowed_logger = [self, example]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def crash(*args)
|
|
21
|
+
check
|
|
22
|
+
fail "Testing block has already ended!" if @details
|
|
23
|
+
@crashes << [args, caller.dup]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def debug(*args)
|
|
27
|
+
check
|
|
28
|
+
@real_logger.debug(*args)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def warn(*args)
|
|
32
|
+
check
|
|
33
|
+
@real_logger.warn(*args)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def with_backtrace(_backtrace)
|
|
37
|
+
check
|
|
38
|
+
yield self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def crashes
|
|
42
|
+
check
|
|
43
|
+
@mutex.synchronize do
|
|
44
|
+
return @details if @details
|
|
45
|
+
@details = []
|
|
46
|
+
@details << @crashes.pop until @crashes.empty?
|
|
47
|
+
@crashes = nil
|
|
48
|
+
@details
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def crashes?
|
|
53
|
+
check
|
|
54
|
+
!crashes.empty?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def check
|
|
60
|
+
return if self.class.allowed_logger.first == self
|
|
61
|
+
|
|
62
|
+
fail "Incorrect logger used:"\
|
|
63
|
+
" active/allowed: \n#{clas.allowed_logger.inspect},\n"\
|
|
64
|
+
" actual/self: \n#{[self, @example].inspect}\n"\
|
|
65
|
+
" (maybe an actor from another test is still running?)"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Debugging
|
|
2
|
+
# Attempt to safely convert an object to a useful string (without side
|
|
3
|
+
# effects if possible)
|
|
4
|
+
#
|
|
5
|
+
# Feel free to add support for more objects/responses/etc.
|
|
6
|
+
def self.dump(obj)
|
|
7
|
+
case obj
|
|
8
|
+
when ::Symbol
|
|
9
|
+
obj.inspect
|
|
10
|
+
when ::String
|
|
11
|
+
obj
|
|
12
|
+
when ::Regexp
|
|
13
|
+
obj.inspect
|
|
14
|
+
when ::IO
|
|
15
|
+
obj.inspect
|
|
16
|
+
when ::Array
|
|
17
|
+
obj.map { |a| Debugging.dump(a) }.to_s
|
|
18
|
+
when ::Celluloid::Response::Success
|
|
19
|
+
"SuccessResponse(#{dump(obj.value)}) (#{dump(obj.call)})"
|
|
20
|
+
when ::Celluloid::Call
|
|
21
|
+
args = obj.arguments.map { |a| Debugging.dump(a) }
|
|
22
|
+
"Call: #{obj}-> #{obj.method.inspect}(#{args.join(', ')})"
|
|
23
|
+
else
|
|
24
|
+
begin
|
|
25
|
+
obj.__send__(:__class__).to_s
|
|
26
|
+
rescue NoMethodError
|
|
27
|
+
obj.__send__(:class).to_s
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/spec/support/env.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "nenv"
|
|
2
|
+
require "dotenv"
|
|
3
|
+
|
|
4
|
+
# Default to `pwd`/.env-* ( whatever is in the current directory )
|
|
5
|
+
# Otherwise take the `.env-*` from the gem itself.
|
|
6
|
+
unless env = Nenv("celluloid").config_file
|
|
7
|
+
env = Nenv.ci? ? ".env-ci" : ".env-dev"
|
|
8
|
+
unless File.exist?(env)
|
|
9
|
+
env = File.expand_path("../../../#{env}", __FILE__)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Dotenv.load!(env) rescue nil # If for some reason no .env-* files are available at all, use defaults.
|
|
14
|
+
|
|
15
|
+
module Specs
|
|
16
|
+
class << self
|
|
17
|
+
def env
|
|
18
|
+
@env ||= Nenv("celluloid_specs")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
class ExampleCrash < Celluloid::Error
|
|
2
|
+
attr_accessor :foo
|
|
3
|
+
end
|
|
4
|
+
|
|
1
5
|
module ExampleActorClass
|
|
2
6
|
def self.create(included_module, task_klass)
|
|
3
7
|
Class.new do
|
|
@@ -41,7 +45,7 @@ module ExampleActorClass
|
|
|
41
45
|
end
|
|
42
46
|
|
|
43
47
|
def crash
|
|
44
|
-
|
|
48
|
+
fail ExampleCrash, "the spec purposely crashed me :("
|
|
45
49
|
end
|
|
46
50
|
|
|
47
51
|
def crash_with_abort(reason, foo = nil)
|
|
@@ -74,6 +78,8 @@ module ExampleActorClass
|
|
|
74
78
|
terminate
|
|
75
79
|
end
|
|
76
80
|
|
|
81
|
+
# Ideally, this class should implement "fake methods"
|
|
82
|
+
# consistently, including :methods, :public_methods, etc.
|
|
77
83
|
def method_missing(method_name, *args, &block)
|
|
78
84
|
if delegates?(method_name)
|
|
79
85
|
@delegate.send method_name, *args, &block
|
|
@@ -83,7 +89,19 @@ module ExampleActorClass
|
|
|
83
89
|
end
|
|
84
90
|
|
|
85
91
|
def respond_to?(method_name, include_private = false)
|
|
86
|
-
|
|
92
|
+
if delegates?(method_name)
|
|
93
|
+
delegates?(method_name)
|
|
94
|
+
else
|
|
95
|
+
super
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def method(method_name)
|
|
100
|
+
if delegates?(method_name)
|
|
101
|
+
@delegate.method(method_name)
|
|
102
|
+
else
|
|
103
|
+
super
|
|
104
|
+
end
|
|
87
105
|
end
|
|
88
106
|
|
|
89
107
|
def call_private
|
|
@@ -102,6 +120,7 @@ module ExampleActorClass
|
|
|
102
120
|
private
|
|
103
121
|
|
|
104
122
|
def delegates?(method_name)
|
|
123
|
+
return false unless @delegate ||= nil
|
|
105
124
|
@delegate.respond_to?(method_name)
|
|
106
125
|
end
|
|
107
126
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
class CallExampleActor
|
|
2
|
+
include Celluloid
|
|
3
|
+
|
|
4
|
+
def initialize(next_actor = nil)
|
|
5
|
+
@next = next_actor
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def actual_method; end
|
|
9
|
+
|
|
10
|
+
def inspect
|
|
11
|
+
fail "Don't call!"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def chained_call_ids
|
|
15
|
+
[call_chain_id, @next.call_chain_id]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# de DEPRECATE:
|
|
20
|
+
|
|
21
|
+
class DeprecatedCallExampleActor
|
|
22
|
+
include Celluloid
|
|
23
|
+
|
|
24
|
+
def initialize(next_actor = nil)
|
|
25
|
+
@next = next_actor
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def actual_method; end
|
|
29
|
+
|
|
30
|
+
def inspect
|
|
31
|
+
fail "Please don't call me! I'm not ready yet!"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def chained_call_ids
|
|
35
|
+
[call_chain_id, @next.call_chain_id]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class TestEventedMailbox < Celluloid::Mailbox::Evented
|
|
2
|
+
class Reactor
|
|
3
|
+
def initialize
|
|
4
|
+
@condition = ConditionVariable.new
|
|
5
|
+
@mutex = Mutex.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def wakeup
|
|
9
|
+
@mutex.synchronize do
|
|
10
|
+
@condition.signal
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run_once(timeout)
|
|
15
|
+
@mutex.synchronize do
|
|
16
|
+
@condition.wait(@mutex, timeout)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def shutdown
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
super(Reactor)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Specs
|
|
2
|
+
class << self
|
|
3
|
+
def log
|
|
4
|
+
# Setup ENV variable handling with sane defaults
|
|
5
|
+
@log ||= Nenv("celluloid_specs_log") do |env|
|
|
6
|
+
env.create_method(:file) { |f| f || "log/default.log" }
|
|
7
|
+
env.create_method(:sync?) { |s| s || !Nenv.ci? }
|
|
8
|
+
|
|
9
|
+
env.create_method(:strategy) do |strategy|
|
|
10
|
+
strategy || default_strategy
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
env.create_method(:level) { |level| default_level_for(env, level) }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def logger
|
|
18
|
+
@logger ||= default_logger.tap { |logger| logger.level = log.level }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
attr_writer :logger
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def default_logger
|
|
26
|
+
case log.strategy
|
|
27
|
+
when "stderr"
|
|
28
|
+
Logger.new(STDERR)
|
|
29
|
+
when "single"
|
|
30
|
+
Logger.new(open_logfile(log.file, log.sync?))
|
|
31
|
+
else
|
|
32
|
+
fail "Unknown logger strategy: #{strategy.inspect}."\
|
|
33
|
+
" Expected 'single' or 'stderr'."
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def open_logfile(rel_path, sync)
|
|
38
|
+
root = Pathname(__FILE__).dirname.dirname.dirname
|
|
39
|
+
log_path = root + rel_path
|
|
40
|
+
logfile = File.open(log_path.to_s, "a")
|
|
41
|
+
logfile.sync if sync
|
|
42
|
+
logfile
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def default_strategy
|
|
46
|
+
(Nenv.ci? ? "stderr" : "single")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def default_level_for(env, level)
|
|
50
|
+
Integer(level)
|
|
51
|
+
rescue
|
|
52
|
+
env.strategy == "stderr" ? Logger::WARN : Logger::DEBUG
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|