celluloid 0.17.4 → 0.18.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/CHANGES.md +300 -81
- data/CONDUCT.md +13 -0
- data/CONTRIBUTING.md +39 -0
- data/README.md +54 -155
- data/REFACTOR.md +1 -0
- data/architecture.md +120 -0
- data/examples/basic_usage.rb +1 -1
- data/examples/configurations.rb +78 -0
- data/examples/futures.rb +1 -1
- data/examples/ring.rb +5 -4
- data/examples/simple_pmap.rb +1 -1
- data/examples/stack.rb +2 -2
- data/examples/supervisors_and_registry.rb +82 -0
- data/examples/timers.rb +2 -2
- data/lib/celluloid/actor/system.rb +13 -29
- data/lib/celluloid/actor.rb +27 -17
- data/lib/celluloid/autostart.rb +6 -1
- data/lib/celluloid/call/async.rb +2 -0
- data/lib/celluloid/call/sync.rb +10 -3
- data/lib/celluloid/calls.rb +13 -12
- data/lib/celluloid/cell.rb +5 -9
- data/lib/celluloid/condition.rb +3 -3
- data/lib/celluloid/core_ext.rb +0 -2
- data/lib/celluloid/debug.rb +3 -0
- data/lib/celluloid/exceptions.rb +2 -2
- data/lib/celluloid/future.rb +8 -10
- data/lib/celluloid/group/pool.rb +1 -3
- data/lib/celluloid/group/spawner.rb +2 -6
- data/lib/celluloid/group.rb +12 -8
- data/lib/celluloid/internals/call_chain.rb +15 -0
- data/lib/celluloid/internals/cpu_counter.rb +62 -0
- data/lib/celluloid/internals/handlers.rb +42 -0
- data/lib/celluloid/internals/links.rb +38 -0
- data/lib/celluloid/internals/logger.rb +104 -0
- data/lib/celluloid/internals/method.rb +34 -0
- data/lib/celluloid/internals/properties.rb +32 -0
- data/lib/celluloid/internals/receivers.rb +64 -0
- data/lib/celluloid/internals/registry.rb +102 -0
- data/lib/celluloid/internals/responses.rb +46 -0
- data/lib/celluloid/internals/signals.rb +24 -0
- data/lib/celluloid/internals/stack/dump.rb +12 -0
- data/lib/celluloid/internals/stack/states.rb +72 -0
- data/lib/celluloid/internals/stack/summary.rb +12 -0
- data/lib/celluloid/internals/stack.rb +74 -0
- data/lib/celluloid/internals/task_set.rb +51 -0
- data/lib/celluloid/internals/thread_handle.rb +52 -0
- data/lib/celluloid/internals/uuid.rb +40 -0
- data/lib/celluloid/logging/incident.rb +21 -0
- data/lib/celluloid/logging/incident_logger.rb +147 -0
- data/lib/celluloid/logging/incident_reporter.rb +49 -0
- data/lib/celluloid/logging/log_event.rb +20 -0
- data/lib/celluloid/logging/ring_buffer.rb +64 -0
- data/lib/celluloid/mailbox/evented.rb +13 -5
- data/lib/celluloid/mailbox.rb +22 -9
- data/lib/celluloid/notifications.rb +95 -0
- data/lib/celluloid/pool.rb +6 -0
- data/lib/celluloid/probe.rb +81 -0
- data/lib/celluloid/proxy/abstract.rb +9 -9
- data/lib/celluloid/proxy/async.rb +1 -1
- data/lib/celluloid/proxy/block.rb +2 -2
- data/lib/celluloid/proxy/cell.rb +1 -1
- data/lib/celluloid/proxy/future.rb +2 -4
- data/lib/celluloid/proxy/sync.rb +1 -3
- data/lib/celluloid/rspec.rb +22 -33
- data/lib/celluloid/supervision/configuration/injections.rb +8 -0
- data/lib/celluloid/supervision/configuration/instance.rb +113 -0
- data/lib/celluloid/supervision/configuration.rb +169 -0
- data/lib/celluloid/supervision/constants.rb +123 -0
- data/lib/celluloid/supervision/container/behavior/pool.rb +71 -0
- data/lib/celluloid/supervision/container/behavior/tree.rb +23 -0
- data/lib/celluloid/supervision/container/behavior.rb +89 -0
- data/lib/celluloid/supervision/container/injections.rb +8 -0
- data/lib/celluloid/supervision/container/instance.rb +116 -0
- data/lib/celluloid/supervision/container/pool.rb +210 -0
- data/lib/celluloid/supervision/container.rb +144 -0
- data/lib/celluloid/supervision/service.rb +27 -0
- data/lib/celluloid/supervision/supervise.rb +34 -0
- data/lib/celluloid/supervision/validation.rb +40 -0
- data/lib/celluloid/supervision/version.rb +5 -0
- data/lib/celluloid/supervision.rb +17 -0
- data/lib/celluloid/system_events.rb +11 -6
- data/lib/celluloid/task/fibered.rb +6 -2
- data/lib/celluloid/task/threaded.rb +3 -3
- data/lib/celluloid/task.rb +25 -12
- data/lib/celluloid/test.rb +5 -2
- data/lib/celluloid/thread.rb +0 -2
- data/lib/celluloid/version.rb +1 -1
- data/lib/celluloid.rb +74 -64
- data/spec/celluloid/block_spec.rb +29 -32
- data/spec/celluloid/calls_spec.rb +5 -15
- data/spec/celluloid/future_spec.rb +7 -1
- data/spec/celluloid/internals/cpu_counter_spec.rb +129 -0
- data/spec/celluloid/internals/links_spec.rb +43 -0
- data/spec/celluloid/internals/properties_spec.rb +40 -0
- data/spec/celluloid/internals/registry_spec.rb +62 -0
- data/spec/celluloid/internals/stack/dump_spec.rb +4 -0
- data/spec/celluloid/internals/stack/summary_spec.rb +4 -0
- data/spec/celluloid/internals/thread_handle_spec.rb +60 -0
- data/spec/celluloid/internals/uuid_spec.rb +9 -0
- data/spec/celluloid/logging/ring_buffer_spec.rb +36 -0
- data/spec/celluloid/mailbox/evented_spec.rb +11 -22
- data/spec/celluloid/misc/leak_spec.rb +3 -4
- data/spec/celluloid/notifications_spec.rb +140 -0
- data/spec/celluloid/probe_spec.rb +102 -0
- data/spec/celluloid/proxy_spec.rb +30 -30
- data/spec/celluloid/supervision/behavior_spec.rb +74 -0
- data/spec/celluloid/supervision/configuration_spec.rb +181 -0
- data/spec/celluloid/supervision/container_spec.rb +72 -0
- data/spec/celluloid/supervision/instance_spec.rb +13 -0
- data/spec/celluloid/supervision/root_spec.rb +28 -0
- data/spec/celluloid/supervision/supervisor_spec.rb +93 -0
- data/spec/celluloid/task/fibered_spec.rb +1 -3
- data/spec/celluloid/task/threaded_spec.rb +1 -3
- data/spec/shared/actor_examples.rb +58 -33
- data/spec/shared/group_examples.rb +2 -2
- data/spec/shared/mailbox_examples.rb +1 -1
- data/spec/shared/stack_examples.rb +87 -0
- data/spec/shared/task_examples.rb +2 -3
- data/spec/spec_helper.rb +2 -4
- data/spec/support/configure_rspec.rb +2 -3
- data/spec/support/coverage.rb +2 -4
- data/spec/support/crash_checking.rb +2 -2
- data/spec/support/examples/actor_class.rb +3 -8
- data/spec/support/examples/call_class.rb +2 -2
- data/spec/support/examples/container_class.rb +35 -0
- data/spec/support/examples/evented_mailbox_class.rb +1 -2
- data/spec/support/examples/stack_classes.rb +58 -0
- data/spec/support/examples/stack_methods.rb +23 -0
- data/spec/support/examples/subordinate_class.rb +19 -0
- data/spec/support/logging.rb +3 -34
- data/spec/support/loose_threads.rb +3 -16
- data/spec/support/reset_class_variables.rb +5 -1
- data/spec/support/stubbing.rb +1 -1
- metadata +91 -289
- data/culture/CONDUCT.md +0 -28
- data/culture/Gemfile +0 -9
- data/culture/LICENSE.txt +0 -22
- data/culture/README.md +0 -22
- data/culture/Rakefile +0 -5
- data/culture/SYNC.md +0 -70
- data/culture/celluloid-culture.gemspec +0 -18
- data/culture/gems/README.md +0 -39
- data/culture/gems/dependencies.yml +0 -85
- data/culture/gems/loader.rb +0 -101
- data/culture/rubocop/README.md +0 -38
- data/culture/rubocop/lint.yml +0 -8
- data/culture/rubocop/metrics.yml +0 -15
- data/culture/rubocop/perf.yml +0 -0
- data/culture/rubocop/rubocop.yml +0 -5
- data/culture/rubocop/style.yml +0 -57
- data/culture/spec/gems_spec.rb +0 -2
- data/culture/spec/spec_helper.rb +0 -0
- data/culture/spec/sync_spec.rb +0 -2
- data/culture/sync.rb +0 -56
- data/culture/tasks/rspec.rake +0 -5
- data/culture/tasks/rubocop.rake +0 -2
- data/lib/celluloid/actor/manager.rb +0 -7
- data/lib/celluloid/backported.rb +0 -2
- data/lib/celluloid/current.rb +0 -2
- data/lib/celluloid/deprecate.rb +0 -21
- data/lib/celluloid/fiber.rb +0 -32
- data/lib/celluloid/managed.rb +0 -3
- data/lib/celluloid/notices.rb +0 -15
- data/spec/deprecate/actor_system_spec.rb +0 -72
- data/spec/deprecate/block_spec.rb +0 -52
- data/spec/deprecate/calls_spec.rb +0 -39
- data/spec/deprecate/evented_mailbox_spec.rb +0 -34
- data/spec/deprecate/future_spec.rb +0 -32
- data/spec/deprecate/internal_pool_spec.rb +0 -4
- data/spec/support/env.rb +0 -21
@@ -0,0 +1,93 @@
|
|
1
|
+
RSpec.describe "Celluloid supervisor", actor_system: :global do
|
2
|
+
let(:logger) { Specs::FakeLogger.current }
|
3
|
+
|
4
|
+
it "restarts actors when they die" do
|
5
|
+
supervisor = Celluloid.supervise(type: Subordinate, args: [:idle])
|
6
|
+
subordinate = supervisor.actors.first
|
7
|
+
expect(subordinate.state).to be(:idle)
|
8
|
+
|
9
|
+
subordinate.crack_the_whip
|
10
|
+
expect(subordinate.state).to be(:working)
|
11
|
+
|
12
|
+
allow(logger).to receive(:crash).with("Actor crashed!", SubordinateDead)
|
13
|
+
|
14
|
+
expect do
|
15
|
+
subordinate.crack_the_whip
|
16
|
+
end.to raise_exception(SubordinateDead)
|
17
|
+
sleep 0.1 # hax to prevent race :(
|
18
|
+
expect(subordinate).not_to be_alive
|
19
|
+
|
20
|
+
new_subordinate = supervisor.actors.first
|
21
|
+
expect(new_subordinate).not_to eq subordinate
|
22
|
+
expect(new_subordinate.state).to eq :idle
|
23
|
+
end
|
24
|
+
|
25
|
+
it "registers actors and reregisters them when they die" do
|
26
|
+
Celluloid.supervise(as: :subordinate, type: Subordinate, args: [:idle])
|
27
|
+
subordinate = Celluloid::Actor[:subordinate]
|
28
|
+
expect(subordinate.state).to be(:idle)
|
29
|
+
|
30
|
+
subordinate.crack_the_whip
|
31
|
+
expect(subordinate.state).to be(:working)
|
32
|
+
|
33
|
+
allow(logger).to receive(:crash).with("Actor crashed!", SubordinateDead)
|
34
|
+
|
35
|
+
expect do
|
36
|
+
subordinate.crack_the_whip
|
37
|
+
end.to raise_exception(SubordinateDead)
|
38
|
+
sleep 0.1 # hax to prevent race :(
|
39
|
+
expect(subordinate).not_to be_alive
|
40
|
+
|
41
|
+
new_subordinate = Celluloid::Actor[:subordinate]
|
42
|
+
expect(new_subordinate).not_to eq subordinate
|
43
|
+
expect(new_subordinate.state).to eq :idle
|
44
|
+
end
|
45
|
+
|
46
|
+
it "creates supervisors via Actor.supervise" do
|
47
|
+
supervisor = Subordinate.supervise(args: [:working])
|
48
|
+
subordinate = supervisor.actors.first
|
49
|
+
expect(subordinate.state).to be(:working)
|
50
|
+
|
51
|
+
allow(logger).to receive(:crash).with("Actor crashed!", SubordinateDead)
|
52
|
+
|
53
|
+
expect do
|
54
|
+
subordinate.crack_the_whip
|
55
|
+
end.to raise_exception(SubordinateDead, "the spec purposely crashed me :(")
|
56
|
+
|
57
|
+
sleep 0.1 # hax to prevent race :(
|
58
|
+
expect(subordinate).not_to be_alive
|
59
|
+
|
60
|
+
new_subordinate = supervisor.actors.first
|
61
|
+
expect(new_subordinate).not_to eq subordinate
|
62
|
+
expect(new_subordinate.state).to eq :working
|
63
|
+
end
|
64
|
+
|
65
|
+
it "creates supervisors and registers actors via Actor.supervise as:" do
|
66
|
+
supervisor = Subordinate.supervise(as: :subordinate, args: [:working])
|
67
|
+
subordinate = Celluloid::Actor[:subordinate]
|
68
|
+
expect(subordinate.state).to be(:working)
|
69
|
+
|
70
|
+
allow(logger).to receive(:crash).with("Actor crashed!", SubordinateDead)
|
71
|
+
|
72
|
+
expect do
|
73
|
+
subordinate.crack_the_whip
|
74
|
+
end.to raise_exception(SubordinateDead)
|
75
|
+
sleep 0.1 # hax to prevent race :(
|
76
|
+
expect(subordinate).not_to be_alive
|
77
|
+
|
78
|
+
new_subordinate = supervisor.actors.first
|
79
|
+
expect(new_subordinate).not_to eq subordinate
|
80
|
+
expect(new_subordinate.state).to be(:working)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "removes an actor if it terminates cleanly" do
|
84
|
+
supervisor = Subordinate.supervise(args: [:working])
|
85
|
+
subordinate = supervisor.actors.first
|
86
|
+
|
87
|
+
expect(supervisor.actors).to eq([subordinate])
|
88
|
+
|
89
|
+
subordinate.terminate
|
90
|
+
|
91
|
+
expect(supervisor.actors).to be_empty
|
92
|
+
end
|
93
|
+
end
|
@@ -2,7 +2,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
2
2
|
around do |ex|
|
3
3
|
Celluloid.boot
|
4
4
|
ex.run
|
5
|
-
Celluloid.shutdown
|
5
|
+
Celluloid.shutdown if Celluloid.running?
|
6
6
|
end
|
7
7
|
|
8
8
|
let(:task_klass) { Celluloid.task_class }
|
@@ -11,6 +11,12 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
11
11
|
|
12
12
|
let(:logger) { Specs::FakeLogger.current }
|
13
13
|
|
14
|
+
it "doesn't raise an error when rebooting" do
|
15
|
+
Celluloid.shutdown
|
16
|
+
|
17
|
+
expect { Celluloid.boot }.to change { Celluloid.running? }.from(false).to(true)
|
18
|
+
end
|
19
|
+
|
14
20
|
it "returns the actor's class, not the proxy's" do
|
15
21
|
expect(actor.class).to eq(actor_class)
|
16
22
|
end
|
@@ -22,24 +28,24 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
22
28
|
true
|
23
29
|
else
|
24
30
|
false
|
25
|
-
end
|
31
|
+
end
|
26
32
|
).to be_truthy
|
27
33
|
end
|
28
34
|
|
29
35
|
it "can be stored in hashes" do
|
30
36
|
expect(actor.hash).not_to eq(Kernel.hash)
|
31
37
|
expect(actor.object_id).not_to eq(Kernel.object_id)
|
32
|
-
expect(actor.eql?
|
38
|
+
expect(actor.eql?(actor)).to be_truthy
|
33
39
|
end
|
34
40
|
|
35
41
|
it "can be stored in hashes even when dead" do
|
36
42
|
actor.terminate
|
37
|
-
|
43
|
+
|
38
44
|
expect(actor.dead?).to be_truthy
|
39
|
-
|
45
|
+
|
40
46
|
expect(actor.hash).not_to eq(Kernel.hash)
|
41
47
|
expect(actor.object_id).not_to eq(Kernel.object_id)
|
42
|
-
expect(actor.eql?
|
48
|
+
expect(actor.eql?(actor)).to be_truthy
|
43
49
|
end
|
44
50
|
|
45
51
|
it "implements respond_to? correctly" do
|
@@ -201,7 +207,9 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
201
207
|
end
|
202
208
|
|
203
209
|
it "warns about suspending the initialize" do
|
210
|
+
# rubocop:disable Metrics/LineLength
|
204
211
|
expect(logger).to receive(:warn).with(/Dangerously suspending task: type=:call, meta={:dangerous_suspend=>true, :method_name=>:initialize}, status=:sleeping/)
|
212
|
+
# rubocop:enable Metrics/LineLength
|
205
213
|
|
206
214
|
actor.terminate
|
207
215
|
Specs.sleep_and_wait_until { !actor.alive? }
|
@@ -232,7 +240,9 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
232
240
|
it "warns about suspending the finalizer" do
|
233
241
|
allow(logger).to receive(:warn)
|
234
242
|
allow(logger).to receive(:crash).with(/finalizer crashed!/, Celluloid::TaskTerminated)
|
243
|
+
# rubocop:disable Metrics/LineLength
|
235
244
|
expect(logger).to receive(:warn).with(/Dangerously suspending task: type=:finalizer, meta={:dangerous_suspend=>true, :method_name=>:cleanup}, status=:sleeping/)
|
245
|
+
# rubocop:enable Metrics/LineLength
|
236
246
|
actor.terminate
|
237
247
|
Specs.sleep_and_wait_until { !actor.alive? }
|
238
248
|
end
|
@@ -418,7 +428,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
418
428
|
include CelluloidSpecs.included_module
|
419
429
|
|
420
430
|
define_method(:receiver_method) do
|
421
|
-
|
431
|
+
raise ExampleCrash, "the spec purposely crashed me :("
|
422
432
|
end
|
423
433
|
end.new
|
424
434
|
|
@@ -430,18 +440,16 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
430
440
|
end
|
431
441
|
end.new
|
432
442
|
|
433
|
-
|
434
|
-
Specs.sleep_and_wait_until { !example_caller.alive? }
|
435
|
-
Specs.sleep_and_wait_until { !example_receiver.alive? }
|
436
|
-
|
437
|
-
expect(ex).to be_a ExampleCrash
|
438
|
-
expect(ex.backtrace.grep(/`sender_method'/)).to be_truthy
|
439
|
-
expect(ex.backtrace.grep(/`receiver_method'/)).to be_truthy
|
443
|
+
expect { example_caller.sender_method }.to raise_error ExampleCrash
|
440
444
|
end
|
441
445
|
|
442
446
|
it "raises DeadActorError if methods are synchronously called on a dead actor" do
|
443
447
|
allow(logger).to receive(:crash).with("Actor crashed!", ExampleCrash)
|
444
|
-
|
448
|
+
begin
|
449
|
+
actor.crash
|
450
|
+
rescue
|
451
|
+
ExampleCrash
|
452
|
+
end
|
445
453
|
|
446
454
|
# TODO: avoid this somehow
|
447
455
|
sleep 0.1 # hax to prevent a race between exit handling and the next call
|
@@ -469,10 +477,11 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
469
477
|
end
|
470
478
|
|
471
479
|
it "crashes the sender if we pass neither String nor Exception" do
|
480
|
+
number = 10
|
472
481
|
allow(logger).to receive(:crash).with("Actor crashed!", TypeError)
|
473
482
|
expect do
|
474
|
-
actor.crash_with_abort_raw
|
475
|
-
end.to raise_exception(TypeError, "Exception object/String expected, but
|
483
|
+
actor.crash_with_abort_raw number
|
484
|
+
end.to raise_exception(TypeError, "Exception object/String expected, but #{number.class} received")
|
476
485
|
|
477
486
|
Specs.sleep_and_wait_until { !actor.alive? }
|
478
487
|
expect(actor).not_to be_alive
|
@@ -550,7 +559,9 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
550
559
|
|
551
560
|
context "when terminated" do
|
552
561
|
it "logs a debug" do
|
562
|
+
# rubocop:disable Metrics/LineLength
|
553
563
|
expect(logger).to receive(:debug).with(/^Terminating task: type=:call, meta={:dangerous_suspend=>false, :method_name=>:sleepy}, status=:sleeping/)
|
564
|
+
# rubocop:enable Metrics/LineLength
|
554
565
|
actor.terminate
|
555
566
|
Specs.sleep_and_wait_until { !actor.alive? }
|
556
567
|
end
|
@@ -594,9 +605,9 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
594
605
|
@subordinate_lambasted
|
595
606
|
end
|
596
607
|
|
597
|
-
def lambaste_subordinate(_actor,
|
608
|
+
def lambaste_subordinate(_actor, reason)
|
598
609
|
@subordinate_lambasted = true
|
599
|
-
@exception =
|
610
|
+
@exception = reason
|
600
611
|
end
|
601
612
|
end
|
602
613
|
end
|
@@ -704,7 +715,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
704
715
|
end
|
705
716
|
|
706
717
|
def wait_for_signal
|
707
|
-
|
718
|
+
raise "already signaled" if @signaled
|
708
719
|
|
709
720
|
@waiting = true
|
710
721
|
value = wait :ponycopter
|
@@ -801,14 +812,14 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
801
812
|
subject.async.exclusive_with_block_log_task(:one)
|
802
813
|
subject.async.log_task(:two)
|
803
814
|
sleep Specs::TIMER_QUANTUM * 2
|
804
|
-
expect(subject.tasks).to eq([
|
815
|
+
expect(subject.tasks).to eq(%i[one two])
|
805
816
|
end
|
806
817
|
|
807
818
|
it "executes methods in the proper order with a class-level annotation" do
|
808
819
|
subject.async.exclusive_log_task :one
|
809
820
|
subject.async.log_task :two
|
810
821
|
sleep Specs::TIMER_QUANTUM * 2
|
811
|
-
expect(subject.tasks).to eq([
|
822
|
+
expect(subject.tasks).to eq(%i[one two])
|
812
823
|
end
|
813
824
|
|
814
825
|
it "knows when it's in exclusive mode" do
|
@@ -854,7 +865,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
854
865
|
end
|
855
866
|
|
856
867
|
it "executes in an exclusive order" do
|
857
|
-
expect(actor.tasks).to eq(%w
|
868
|
+
expect(actor.tasks).to eq(%w[donuts coffee])
|
858
869
|
end
|
859
870
|
end
|
860
871
|
end
|
@@ -949,7 +960,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
949
960
|
expect(actor).to be_sleeping
|
950
961
|
|
951
962
|
future.value
|
952
|
-
# I got 0.558 (in a
|
963
|
+
# I got 0.558 (in a slightly busy MRI) which is outside 0.05 of 0.5, so let's use (0.05 * 2)
|
953
964
|
expect(Time.now - started_at).to be_within(Specs::TIMER_QUANTUM * 2).of interval
|
954
965
|
end
|
955
966
|
|
@@ -1102,7 +1113,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
1102
1113
|
|
1103
1114
|
klass = Class.new(Celluloid::Proxy::Cell) do
|
1104
1115
|
def dividing_3_by(number)
|
1105
|
-
|
1116
|
+
raise ArgumentError, "<facepalm>" if number.zero?
|
1106
1117
|
super
|
1107
1118
|
end
|
1108
1119
|
end
|
@@ -1121,7 +1132,11 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
1121
1132
|
end
|
1122
1133
|
|
1123
1134
|
it "does not crash the actor" do
|
1124
|
-
|
1135
|
+
begin
|
1136
|
+
subject.dividing_3_by(0)
|
1137
|
+
rescue
|
1138
|
+
ArgumentError
|
1139
|
+
end
|
1125
1140
|
expect(subject.dividing_3_by(3)).to eq(1)
|
1126
1141
|
end
|
1127
1142
|
end
|
@@ -1130,7 +1145,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
1130
1145
|
context "when it includes method checking" do
|
1131
1146
|
module MethodChecking
|
1132
1147
|
def method_missing(meth, *args)
|
1133
|
-
return super if [
|
1148
|
+
return super if %i[__send__ respond_to? method class __class__].include? meth
|
1134
1149
|
|
1135
1150
|
unmet_requirement = nil
|
1136
1151
|
|
@@ -1141,7 +1156,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
1141
1156
|
mandatory_args = -arity - 1
|
1142
1157
|
unmet_requirement = "#{mandatory_args}+" if args.size < mandatory_args
|
1143
1158
|
end
|
1144
|
-
|
1159
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for #{unmet_requirement})" if unmet_requirement
|
1145
1160
|
|
1146
1161
|
super
|
1147
1162
|
end
|
@@ -1160,7 +1175,7 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
1160
1175
|
end
|
1161
1176
|
|
1162
1177
|
def this_is_not_madness(word1, word2, word3, *_args)
|
1163
|
-
|
1178
|
+
raise "This is madness!" unless [word1, word2, word3] == %i[this is Sparta]
|
1164
1179
|
end
|
1165
1180
|
|
1166
1181
|
proxy_class klass
|
@@ -1173,7 +1188,11 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
1173
1188
|
end
|
1174
1189
|
|
1175
1190
|
it "does not crash the actor" do
|
1176
|
-
|
1191
|
+
begin
|
1192
|
+
subject.method_to_madness
|
1193
|
+
rescue
|
1194
|
+
NoMethodError
|
1195
|
+
end
|
1177
1196
|
expect(subject.madness).to eq("This is madness!")
|
1178
1197
|
end
|
1179
1198
|
end
|
@@ -1181,18 +1200,24 @@ RSpec.shared_examples "a Celluloid Actor" do
|
|
1181
1200
|
context "when invoking a existing method with incorrect args" do
|
1182
1201
|
context "with too many arguments" do
|
1183
1202
|
it "raises an ArgumentError" do
|
1184
|
-
expect { subject.madness(:Sparta) }
|
1203
|
+
expect { subject.madness(:Sparta) }
|
1204
|
+
.to raise_error(ArgumentError, "wrong number of arguments (1 for 0)")
|
1185
1205
|
end
|
1186
1206
|
|
1187
1207
|
it "does not crash the actor" do
|
1188
|
-
|
1208
|
+
begin
|
1209
|
+
subject.madness(:Sparta)
|
1210
|
+
rescue
|
1211
|
+
ArgumentError
|
1212
|
+
end
|
1189
1213
|
expect(subject.madness).to eq("This is madness!")
|
1190
1214
|
end
|
1191
1215
|
end
|
1192
1216
|
|
1193
1217
|
context "with not enough mandatory arguments" do
|
1194
1218
|
it "raises an ArgumentError" do
|
1195
|
-
expect { subject.this_is_not_madness(:this, :is) }
|
1219
|
+
expect { subject.this_is_not_madness(:this, :is) }
|
1220
|
+
.to raise_error(ArgumentError, "wrong number of arguments (2 for 3+)")
|
1196
1221
|
end
|
1197
1222
|
end
|
1198
1223
|
end
|
@@ -35,7 +35,7 @@ RSpec.shared_examples "a Celluloid Group" do
|
|
35
35
|
subject.get do
|
36
36
|
busy_queue << nil
|
37
37
|
@wait_queue.pop
|
38
|
-
|
38
|
+
raise exception_class, "Error"
|
39
39
|
end
|
40
40
|
|
41
41
|
wait_until_busy(busy_queue)
|
@@ -89,7 +89,7 @@ RSpec.shared_examples "a Celluloid Group" do
|
|
89
89
|
subject.get do
|
90
90
|
thread << Thread.current
|
91
91
|
sleep
|
92
|
-
end
|
92
|
+
end
|
93
93
|
).to be_a(Celluloid::Thread)
|
94
94
|
|
95
95
|
thread.pop # wait for 3rd-party thread to get strated
|
@@ -62,7 +62,7 @@ RSpec.shared_examples "a Celluloid Mailbox" do
|
|
62
62
|
subject << :first
|
63
63
|
subject << :second
|
64
64
|
subject << :third
|
65
|
-
expect(subject.to_a).to match_array([
|
65
|
+
expect(subject.to_a).to match_array(%i[first second])
|
66
66
|
end
|
67
67
|
|
68
68
|
it "logs discarded messages" do
|
@@ -0,0 +1,87 @@
|
|
1
|
+
RSpec.shared_examples "a Celluloid Stack" do
|
2
|
+
let(:actor_system) { Celluloid::Actor::System.new }
|
3
|
+
let(:threads) { Queue.new }
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
items = 0
|
7
|
+
|
8
|
+
[Celluloid::Task::Fibered, Celluloid::Task::Threaded].each do |task_klass|
|
9
|
+
create_async_blocking_actor(task_klass)
|
10
|
+
items += 1
|
11
|
+
end
|
12
|
+
|
13
|
+
@active_thread = create_thread_with_role(threads, :other_thing)
|
14
|
+
items += 1
|
15
|
+
|
16
|
+
@idle_thread = create_thread_with_role(threads, :idle_thing)
|
17
|
+
items += 1
|
18
|
+
|
19
|
+
# StackWaiter for each thread to add itself to the queue
|
20
|
+
tmp = Queue.new
|
21
|
+
items.times do
|
22
|
+
th = Timeout.timeout(4) { threads.pop }
|
23
|
+
tmp << th
|
24
|
+
end
|
25
|
+
|
26
|
+
expect(threads).to be_empty
|
27
|
+
|
28
|
+
# put threads back into the queue for killing
|
29
|
+
threads << tmp.pop until tmp.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
after do
|
33
|
+
StackWaiter.no_longer
|
34
|
+
actor_system.shutdown
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#actors" do
|
38
|
+
it "should include all actors" do
|
39
|
+
expect(subject.actors.size).to eq(2)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#threads" do
|
44
|
+
# TODO: this spec should use mocks because it's non-deterministict
|
45
|
+
it "should include threads that are not actors" do
|
46
|
+
# TODO: Assess need for bypassing StackWaiter.forever's QUEUE.pop after #670 & #678
|
47
|
+
# NOTE: Pool#each doesn't guarantee to contain the newly started thread
|
48
|
+
# because the actor's methods (which create and store the thread handle)
|
49
|
+
# are started asynchronously.
|
50
|
+
#
|
51
|
+
# The mutexes in InternalPool especially can cause additional delay -
|
52
|
+
# causing Pool#get to wait for IPool#each to free the mutex before the
|
53
|
+
# new thread can be stored.
|
54
|
+
#
|
55
|
+
# And, Internals::StackDump#threads is cached, so we have to reconstruct the
|
56
|
+
# Internals::StackDump until it matches reality.
|
57
|
+
#
|
58
|
+
# Also, the actual number of threads and how InternalPool juggles them is
|
59
|
+
# non deterministic to begin with:
|
60
|
+
#
|
61
|
+
# 2 actors
|
62
|
+
# -> *0-1 task threads
|
63
|
+
#
|
64
|
+
# *1 idle thread
|
65
|
+
# *1 active thread
|
66
|
+
#
|
67
|
+
# Together: 3-4 threads
|
68
|
+
|
69
|
+
# Pool somehow doesn't create extra tasks
|
70
|
+
# 5 is on JRuby-head
|
71
|
+
expected = Celluloid.group_class == Celluloid::Group::Pool ? [3, 4] : [3, 4, 5, 6]
|
72
|
+
expect(expected).to include(subject.threads.size)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should include idle threads" do
|
76
|
+
expect(subject.threads.map(&:thread_id)).to include(@idle_thread.object_id)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should include threads checked out of the group for roles other than :actor" do
|
80
|
+
expect(subject.threads.map(&:thread_id)).to include(@active_thread.object_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should have the correct roles" do
|
84
|
+
expect(subject.threads.map(&:role)).to include(:idle_thing, :other_thing)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -5,8 +5,7 @@ class MockActor
|
|
5
5
|
@tasks = []
|
6
6
|
end
|
7
7
|
|
8
|
-
def setup_thread
|
9
|
-
end
|
8
|
+
def setup_thread; end
|
10
9
|
end
|
11
10
|
|
12
11
|
RSpec.shared_examples "a Celluloid Task" do
|
@@ -41,7 +40,7 @@ RSpec.shared_examples "a Celluloid Task" do
|
|
41
40
|
|
42
41
|
it "raises exceptions outside" do
|
43
42
|
task = Celluloid.task_class.new(task_type, {}) do
|
44
|
-
|
43
|
+
raise "failure"
|
45
44
|
end
|
46
45
|
expect do
|
47
46
|
task.resume
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
RSpec.configure do |config|
|
2
|
-
config.filter_run focus: true unless Nenv.ci?
|
3
2
|
config.run_all_when_everything_filtered = true
|
4
3
|
config.disable_monkey_patching!
|
5
4
|
config.profile_examples = 3
|
@@ -19,7 +18,7 @@ RSpec.configure do |config|
|
|
19
18
|
config.before(:suite) do
|
20
19
|
Specs.stub_out_class_method(Celluloid::Internals::Logger, :crash) do |*args|
|
21
20
|
_name, ex = *args
|
22
|
-
|
21
|
+
raise "Unstubbed Logger.crash() was called:\n crash(\n #{args.map(&:inspect).join(",\n ")})"\
|
23
22
|
"\nException backtrace: \n (#{ex.class}) #{ex.backtrace * "\n (#{ex.class}) "}"
|
24
23
|
end
|
25
24
|
end
|
@@ -42,7 +41,7 @@ RSpec.configure do |config|
|
|
42
41
|
"\n** Crash: #{msg.inspect}(#{ex.inspect})\n Backtrace:\n (crash) #{call_stack * "\n (crash) "}"\
|
43
42
|
"\n Exception Backtrace (#{ex.inspect}):\n (ex) #{ex.backtrace * "\n (ex) "}"
|
44
43
|
end.join("\n")
|
45
|
-
|
44
|
+
raise "Actor crashes occurred (please stub/mock if these are expected): #{crashes}"
|
46
45
|
end
|
47
46
|
@fake_logger = nil
|
48
47
|
Specs.assert_no_loose_threads!("after example: #{ex.description}") if Specs::CHECK_LOOSE_THREADS
|
data/spec/support/coverage.rb
CHANGED
@@ -19,7 +19,7 @@ module Specs
|
|
19
19
|
|
20
20
|
def crash(*args)
|
21
21
|
check
|
22
|
-
|
22
|
+
raise "Testing block has already ended!" if @details
|
23
23
|
@crashes << [args, caller.dup]
|
24
24
|
end
|
25
25
|
|
@@ -59,7 +59,7 @@ module Specs
|
|
59
59
|
def check
|
60
60
|
return if self.class.allowed_logger.first == self
|
61
61
|
|
62
|
-
|
62
|
+
raise "Incorrect logger used:"\
|
63
63
|
" active/allowed: \n#{clas.allowed_logger.inspect},\n"\
|
64
64
|
" actual/self: \n#{[self, @example].inspect}\n"\
|
65
65
|
" (maybe an actor from another test is still running?)"
|
@@ -45,7 +45,7 @@ module ExampleActorClass
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def crash
|
48
|
-
|
48
|
+
raise ExampleCrash, "the spec purposely crashed me :("
|
49
49
|
end
|
50
50
|
|
51
51
|
def crash_with_abort(reason, foo = nil)
|
@@ -89,11 +89,7 @@ module ExampleActorClass
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def respond_to?(method_name, include_private = false)
|
92
|
-
|
93
|
-
delegates?(method_name)
|
94
|
-
else
|
95
|
-
super
|
96
|
-
end
|
92
|
+
delegates?(method_name) || super
|
97
93
|
end
|
98
94
|
|
99
95
|
def method(method_name)
|
@@ -114,8 +110,7 @@ module ExampleActorClass
|
|
114
110
|
private :zomg_private
|
115
111
|
attr_reader :private_called
|
116
112
|
|
117
|
-
def my_finalizer
|
118
|
-
end
|
113
|
+
def my_finalizer; end
|
119
114
|
|
120
115
|
private
|
121
116
|
|
@@ -8,7 +8,7 @@ class CallExampleActor
|
|
8
8
|
def actual_method; end
|
9
9
|
|
10
10
|
def inspect
|
11
|
-
|
11
|
+
raise "Don't call!"
|
12
12
|
end
|
13
13
|
|
14
14
|
def chained_call_ids
|
@@ -28,7 +28,7 @@ class DeprecatedCallExampleActor
|
|
28
28
|
def actual_method; end
|
29
29
|
|
30
30
|
def inspect
|
31
|
-
|
31
|
+
raise "Please don't call me! I'm not ready yet!"
|
32
32
|
end
|
33
33
|
|
34
34
|
def chained_call_ids
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class SupervisionContainerHelper
|
2
|
+
@queue = nil
|
3
|
+
class << self
|
4
|
+
def reset!
|
5
|
+
@queue = Queue.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def done!
|
9
|
+
@queue << :done
|
10
|
+
end
|
11
|
+
|
12
|
+
def pop!
|
13
|
+
@queue.pop
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class MyContainerActor
|
19
|
+
include Celluloid
|
20
|
+
|
21
|
+
attr_reader :args
|
22
|
+
|
23
|
+
def initialize(*args)
|
24
|
+
@args = args
|
25
|
+
ready
|
26
|
+
end
|
27
|
+
|
28
|
+
def running?
|
29
|
+
:yep
|
30
|
+
end
|
31
|
+
|
32
|
+
def ready
|
33
|
+
SupervisionContainerHelper.done!
|
34
|
+
end
|
35
|
+
end
|