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.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +300 -81
  3. data/CONDUCT.md +13 -0
  4. data/CONTRIBUTING.md +39 -0
  5. data/README.md +54 -155
  6. data/REFACTOR.md +1 -0
  7. data/architecture.md +120 -0
  8. data/examples/basic_usage.rb +1 -1
  9. data/examples/configurations.rb +78 -0
  10. data/examples/futures.rb +1 -1
  11. data/examples/ring.rb +5 -4
  12. data/examples/simple_pmap.rb +1 -1
  13. data/examples/stack.rb +2 -2
  14. data/examples/supervisors_and_registry.rb +82 -0
  15. data/examples/timers.rb +2 -2
  16. data/lib/celluloid/actor/system.rb +13 -29
  17. data/lib/celluloid/actor.rb +27 -17
  18. data/lib/celluloid/autostart.rb +6 -1
  19. data/lib/celluloid/call/async.rb +2 -0
  20. data/lib/celluloid/call/sync.rb +10 -3
  21. data/lib/celluloid/calls.rb +13 -12
  22. data/lib/celluloid/cell.rb +5 -9
  23. data/lib/celluloid/condition.rb +3 -3
  24. data/lib/celluloid/core_ext.rb +0 -2
  25. data/lib/celluloid/debug.rb +3 -0
  26. data/lib/celluloid/exceptions.rb +2 -2
  27. data/lib/celluloid/future.rb +8 -10
  28. data/lib/celluloid/group/pool.rb +1 -3
  29. data/lib/celluloid/group/spawner.rb +2 -6
  30. data/lib/celluloid/group.rb +12 -8
  31. data/lib/celluloid/internals/call_chain.rb +15 -0
  32. data/lib/celluloid/internals/cpu_counter.rb +62 -0
  33. data/lib/celluloid/internals/handlers.rb +42 -0
  34. data/lib/celluloid/internals/links.rb +38 -0
  35. data/lib/celluloid/internals/logger.rb +104 -0
  36. data/lib/celluloid/internals/method.rb +34 -0
  37. data/lib/celluloid/internals/properties.rb +32 -0
  38. data/lib/celluloid/internals/receivers.rb +64 -0
  39. data/lib/celluloid/internals/registry.rb +102 -0
  40. data/lib/celluloid/internals/responses.rb +46 -0
  41. data/lib/celluloid/internals/signals.rb +24 -0
  42. data/lib/celluloid/internals/stack/dump.rb +12 -0
  43. data/lib/celluloid/internals/stack/states.rb +72 -0
  44. data/lib/celluloid/internals/stack/summary.rb +12 -0
  45. data/lib/celluloid/internals/stack.rb +74 -0
  46. data/lib/celluloid/internals/task_set.rb +51 -0
  47. data/lib/celluloid/internals/thread_handle.rb +52 -0
  48. data/lib/celluloid/internals/uuid.rb +40 -0
  49. data/lib/celluloid/logging/incident.rb +21 -0
  50. data/lib/celluloid/logging/incident_logger.rb +147 -0
  51. data/lib/celluloid/logging/incident_reporter.rb +49 -0
  52. data/lib/celluloid/logging/log_event.rb +20 -0
  53. data/lib/celluloid/logging/ring_buffer.rb +64 -0
  54. data/lib/celluloid/mailbox/evented.rb +13 -5
  55. data/lib/celluloid/mailbox.rb +22 -9
  56. data/lib/celluloid/notifications.rb +95 -0
  57. data/lib/celluloid/pool.rb +6 -0
  58. data/lib/celluloid/probe.rb +81 -0
  59. data/lib/celluloid/proxy/abstract.rb +9 -9
  60. data/lib/celluloid/proxy/async.rb +1 -1
  61. data/lib/celluloid/proxy/block.rb +2 -2
  62. data/lib/celluloid/proxy/cell.rb +1 -1
  63. data/lib/celluloid/proxy/future.rb +2 -4
  64. data/lib/celluloid/proxy/sync.rb +1 -3
  65. data/lib/celluloid/rspec.rb +22 -33
  66. data/lib/celluloid/supervision/configuration/injections.rb +8 -0
  67. data/lib/celluloid/supervision/configuration/instance.rb +113 -0
  68. data/lib/celluloid/supervision/configuration.rb +169 -0
  69. data/lib/celluloid/supervision/constants.rb +123 -0
  70. data/lib/celluloid/supervision/container/behavior/pool.rb +71 -0
  71. data/lib/celluloid/supervision/container/behavior/tree.rb +23 -0
  72. data/lib/celluloid/supervision/container/behavior.rb +89 -0
  73. data/lib/celluloid/supervision/container/injections.rb +8 -0
  74. data/lib/celluloid/supervision/container/instance.rb +116 -0
  75. data/lib/celluloid/supervision/container/pool.rb +210 -0
  76. data/lib/celluloid/supervision/container.rb +144 -0
  77. data/lib/celluloid/supervision/service.rb +27 -0
  78. data/lib/celluloid/supervision/supervise.rb +34 -0
  79. data/lib/celluloid/supervision/validation.rb +40 -0
  80. data/lib/celluloid/supervision/version.rb +5 -0
  81. data/lib/celluloid/supervision.rb +17 -0
  82. data/lib/celluloid/system_events.rb +11 -6
  83. data/lib/celluloid/task/fibered.rb +6 -2
  84. data/lib/celluloid/task/threaded.rb +3 -3
  85. data/lib/celluloid/task.rb +25 -12
  86. data/lib/celluloid/test.rb +5 -2
  87. data/lib/celluloid/thread.rb +0 -2
  88. data/lib/celluloid/version.rb +1 -1
  89. data/lib/celluloid.rb +74 -64
  90. data/spec/celluloid/block_spec.rb +29 -32
  91. data/spec/celluloid/calls_spec.rb +5 -15
  92. data/spec/celluloid/future_spec.rb +7 -1
  93. data/spec/celluloid/internals/cpu_counter_spec.rb +129 -0
  94. data/spec/celluloid/internals/links_spec.rb +43 -0
  95. data/spec/celluloid/internals/properties_spec.rb +40 -0
  96. data/spec/celluloid/internals/registry_spec.rb +62 -0
  97. data/spec/celluloid/internals/stack/dump_spec.rb +4 -0
  98. data/spec/celluloid/internals/stack/summary_spec.rb +4 -0
  99. data/spec/celluloid/internals/thread_handle_spec.rb +60 -0
  100. data/spec/celluloid/internals/uuid_spec.rb +9 -0
  101. data/spec/celluloid/logging/ring_buffer_spec.rb +36 -0
  102. data/spec/celluloid/mailbox/evented_spec.rb +11 -22
  103. data/spec/celluloid/misc/leak_spec.rb +3 -4
  104. data/spec/celluloid/notifications_spec.rb +140 -0
  105. data/spec/celluloid/probe_spec.rb +102 -0
  106. data/spec/celluloid/proxy_spec.rb +30 -30
  107. data/spec/celluloid/supervision/behavior_spec.rb +74 -0
  108. data/spec/celluloid/supervision/configuration_spec.rb +181 -0
  109. data/spec/celluloid/supervision/container_spec.rb +72 -0
  110. data/spec/celluloid/supervision/instance_spec.rb +13 -0
  111. data/spec/celluloid/supervision/root_spec.rb +28 -0
  112. data/spec/celluloid/supervision/supervisor_spec.rb +93 -0
  113. data/spec/celluloid/task/fibered_spec.rb +1 -3
  114. data/spec/celluloid/task/threaded_spec.rb +1 -3
  115. data/spec/shared/actor_examples.rb +58 -33
  116. data/spec/shared/group_examples.rb +2 -2
  117. data/spec/shared/mailbox_examples.rb +1 -1
  118. data/spec/shared/stack_examples.rb +87 -0
  119. data/spec/shared/task_examples.rb +2 -3
  120. data/spec/spec_helper.rb +2 -4
  121. data/spec/support/configure_rspec.rb +2 -3
  122. data/spec/support/coverage.rb +2 -4
  123. data/spec/support/crash_checking.rb +2 -2
  124. data/spec/support/examples/actor_class.rb +3 -8
  125. data/spec/support/examples/call_class.rb +2 -2
  126. data/spec/support/examples/container_class.rb +35 -0
  127. data/spec/support/examples/evented_mailbox_class.rb +1 -2
  128. data/spec/support/examples/stack_classes.rb +58 -0
  129. data/spec/support/examples/stack_methods.rb +23 -0
  130. data/spec/support/examples/subordinate_class.rb +19 -0
  131. data/spec/support/logging.rb +3 -34
  132. data/spec/support/loose_threads.rb +3 -16
  133. data/spec/support/reset_class_variables.rb +5 -1
  134. data/spec/support/stubbing.rb +1 -1
  135. metadata +91 -289
  136. data/culture/CONDUCT.md +0 -28
  137. data/culture/Gemfile +0 -9
  138. data/culture/LICENSE.txt +0 -22
  139. data/culture/README.md +0 -22
  140. data/culture/Rakefile +0 -5
  141. data/culture/SYNC.md +0 -70
  142. data/culture/celluloid-culture.gemspec +0 -18
  143. data/culture/gems/README.md +0 -39
  144. data/culture/gems/dependencies.yml +0 -85
  145. data/culture/gems/loader.rb +0 -101
  146. data/culture/rubocop/README.md +0 -38
  147. data/culture/rubocop/lint.yml +0 -8
  148. data/culture/rubocop/metrics.yml +0 -15
  149. data/culture/rubocop/perf.yml +0 -0
  150. data/culture/rubocop/rubocop.yml +0 -5
  151. data/culture/rubocop/style.yml +0 -57
  152. data/culture/spec/gems_spec.rb +0 -2
  153. data/culture/spec/spec_helper.rb +0 -0
  154. data/culture/spec/sync_spec.rb +0 -2
  155. data/culture/sync.rb +0 -56
  156. data/culture/tasks/rspec.rake +0 -5
  157. data/culture/tasks/rubocop.rake +0 -2
  158. data/lib/celluloid/actor/manager.rb +0 -7
  159. data/lib/celluloid/backported.rb +0 -2
  160. data/lib/celluloid/current.rb +0 -2
  161. data/lib/celluloid/deprecate.rb +0 -21
  162. data/lib/celluloid/fiber.rb +0 -32
  163. data/lib/celluloid/managed.rb +0 -3
  164. data/lib/celluloid/notices.rb +0 -15
  165. data/spec/deprecate/actor_system_spec.rb +0 -72
  166. data/spec/deprecate/block_spec.rb +0 -52
  167. data/spec/deprecate/calls_spec.rb +0 -39
  168. data/spec/deprecate/evented_mailbox_spec.rb +0 -34
  169. data/spec/deprecate/future_spec.rb +0 -32
  170. data/spec/deprecate/internal_pool_spec.rb +0 -4
  171. data/spec/support/env.rb +0 -21
@@ -2,19 +2,20 @@ RSpec.describe "Blocks", actor_system: :global do
2
2
  class MyBlockActor
3
3
  include Celluloid
4
4
 
5
- def initialize(name)
5
+ def initialize(name, data)
6
6
  @name = name
7
+ @data = data
7
8
  end
8
9
  attr_reader :name
9
10
 
10
11
  def ask_for_something(other)
11
12
  sender_actor = current_actor
12
- $data << [:outside, @name, current_actor.name]
13
- other.do_something_and_callback do |value|
14
- $data << [:yielded, @name, current_actor.name]
15
- $data << receive_result(:self)
16
- $data << current_actor.receive_result(:current_actor)
17
- $data << sender_actor.receive_result(:sender)
13
+ @data << [:outside, @name, current_actor.name]
14
+ other.do_something_and_callback do |_value|
15
+ @data << [:yielded, @name, current_actor.name]
16
+ @data << receive_result(:self)
17
+ @data << current_actor.receive_result(:current_actor)
18
+ @data << sender_actor.receive_result(:sender)
18
19
  :pete_the_polyglot_alien
19
20
  end
20
21
  end
@@ -34,20 +35,20 @@ RSpec.describe "Blocks", actor_system: :global do
34
35
  def defer_for_something(other, &_block)
35
36
  sender_actor = current_actor
36
37
  defer do
37
- $data << [:outside, @name, current_actor.name]
38
- other.do_something_and_callback do |value|
39
- $data << [:yielded, @name, current_actor.name]
40
- $data << receive_result(:self)
41
- $data << current_actor.receive_result(:current_actor)
42
- $data << sender_actor.receive_result(:sender)
38
+ @data << [:outside, @name, current_actor.name]
39
+ other.do_something_and_callback do |_value|
40
+ @data << [:yielded, @name, current_actor.name]
41
+ @data << receive_result(:self)
42
+ @data << current_actor.receive_result(:current_actor)
43
+ @data << sender_actor.receive_result(:sender)
43
44
  :pete_the_polyglot_alien
44
45
  end
45
46
  end
46
47
  end
47
48
 
48
49
  def do_something_and_callback
49
- $data << [:something, @name, current_actor.name]
50
- $data << yield(:foo)
50
+ @data << [:something, @name, current_actor.name]
51
+ @data << yield(:foo)
51
52
  end
52
53
 
53
54
  def receive_result(result)
@@ -56,10 +57,10 @@ RSpec.describe "Blocks", actor_system: :global do
56
57
  end
57
58
 
58
59
  it "work between actors" do
59
- $data = []
60
+ data = []
60
61
 
61
- a1 = MyBlockActor.new("one")
62
- a2 = MyBlockActor.new("two")
62
+ a1 = MyBlockActor.new("one", data)
63
+ a2 = MyBlockActor.new("two", data)
63
64
 
64
65
  a1.ask_for_something a2
65
66
 
@@ -70,33 +71,29 @@ RSpec.describe "Blocks", actor_system: :global do
70
71
  [:self, "one", "one"],
71
72
  [:current_actor, "one", "one"],
72
73
  [:sender, "one", "one"],
73
- :pete_the_polyglot_alien,
74
+ :pete_the_polyglot_alien
74
75
  ]
75
76
 
76
- expect($data).to eq(expected)
77
+ expect(data).to eq(expected)
77
78
  end
78
79
 
79
80
  execute_deferred = proc do
80
- a1 = MyBlockActor.new("one")
81
+ a1 = MyBlockActor.new("one", [])
81
82
  expect(a1.deferred_excecution(:pete_the_polyglot_alien) { |v| v })
82
- .to eq(:pete_the_polyglot_alien)
83
+ .to eq(:pete_the_polyglot_alien)
83
84
  end
84
85
 
85
- # unless RUBY_ENGINE == 'jruby'
86
86
  xit("can be deferred", &execute_deferred)
87
- # else
88
- # it("can be deferred", &execute_deferred)
89
- # end
90
87
 
91
88
  xit "can execute deferred blocks referencing current_actor" do
92
- a1 = MyBlockActor.new("one")
89
+ a1 = MyBlockActor.new("one", [])
93
90
  expect(a1.deferred_current_actor { |v| v }).to be("one")
94
91
  end
95
92
 
96
93
  xit "can execute deferred blocks with another actor" do
97
- $data = []
98
- a1 = MyBlockActor.new("one")
99
- a2 = MyBlockActor.new("two")
94
+ data = []
95
+ a1 = MyBlockActor.new("one", data)
96
+ a2 = MyBlockActor.new("two", data)
100
97
  a1.defer_for_something a2
101
98
  expected = [
102
99
  [:outside, "one", "one"],
@@ -105,9 +102,9 @@ RSpec.describe "Blocks", actor_system: :global do
105
102
  [:self, "one", "one"],
106
103
  [:current_actor, "one", "one"],
107
104
  [:sender, "one", "one"],
108
- :pete_the_polyglot_alien,
105
+ :pete_the_polyglot_alien
109
106
  ]
110
107
 
111
- expect($data).to eq(expected)
108
+ expect(data).to eq(expected)
112
109
  end
113
110
  end
@@ -5,27 +5,17 @@ RSpec.describe Celluloid::Call::Sync, actor_system: :global do
5
5
  let(:logger) { Specs::FakeLogger.current }
6
6
 
7
7
  context "when obj does not respond to a method" do
8
- # bypass this until rubinius/rubinius#3373 is resolved
9
- # under Rubinius, `method` calls `inspect` on an object when a method is not found
10
- unless RUBY_ENGINE == "rbx"
11
- it "raises a NoMethodError" do
12
- allow(logger).to receive(:crash).with("Actor crashed!", NoMethodError)
8
+ it "raises a NoMethodError" do
9
+ allow(logger).to receive(:crash).with("Actor crashed!", NoMethodError)
13
10
 
14
- expect do
15
- actor.the_method_that_wasnt_there
16
- end.to raise_exception(NoMethodError)
17
- end
11
+ expect do
12
+ actor.the_method_that_was_not_there
13
+ end.to raise_exception(NoMethodError)
18
14
  end
19
15
 
20
16
  context "when obj raises during inspect" do
21
17
  it "should emulate obj.inspect" do
22
18
  allow(logger).to receive(:crash).with("Actor crashed!", NoMethodError)
23
-
24
- if RUBY_ENGINE == "rbx"
25
- expected = /undefined method `no_such_method' on an instance of CallExampleActor/
26
- else
27
- expected = /undefined method `no_such_method' for #\<CallExampleActor:0x[a-f0-9]+\>/
28
- end
29
19
  end
30
20
  end
31
21
  end
@@ -12,7 +12,7 @@ RSpec.describe Celluloid::Future, actor_system: :global do
12
12
  it "reraises exceptions that occur when the value is retrieved" do
13
13
  class ExampleError < StandardError; end
14
14
 
15
- future = Celluloid::Future.new { fail ExampleError, "oh noes crash!" }
15
+ future = Celluloid::Future.new { raise ExampleError, "oh noes crash!" }
16
16
  expect { future.value }.to raise_exception(ExampleError)
17
17
  end
18
18
 
@@ -32,4 +32,10 @@ RSpec.describe Celluloid::Future, actor_system: :global do
32
32
  future = Celluloid::Future.new { sleep 2 }
33
33
  expect { future.value(1) }.to raise_exception(Celluloid::TaskTimeout)
34
34
  end
35
+
36
+ it "cancels future" do
37
+ future = Celluloid::Future.new { sleep 3600 }
38
+ future.cancel(StandardError.new("cancelled"))
39
+ expect { future.value }.to raise_exception(StandardError, "cancelled")
40
+ end
35
41
  end
@@ -0,0 +1,129 @@
1
+ RSpec.describe Celluloid::Internals::CPUCounter do
2
+ describe "#cores" do
3
+ subject { described_class.cores }
4
+
5
+ let(:num_cores) { 1024 }
6
+
7
+ before do
8
+ allow(described_class).to receive(:`) { raise "backtick stub called" }
9
+ allow(::IO).to receive(:open).and_raise("IO.open stub called!")
10
+ described_class.instance_variable_set(:@cores, nil)
11
+ end
12
+
13
+ after do
14
+ ENV["NUMBER_OF_PROCESSORS"] = nil
15
+ described_class.instance_variable_set(:@cores, nil)
16
+ end
17
+
18
+ context "with from_env" do
19
+ context "valid env value" do
20
+ before { ENV["NUMBER_OF_PROCESSORS"] = num_cores.to_s }
21
+ it { is_expected.to eq num_cores }
22
+ end
23
+
24
+ context "invalid env value" do
25
+ before { ENV["NUMBER_OF_PROCESSORS"] = "" }
26
+ subject { described_class.from_env }
27
+ it { is_expected.to be nil }
28
+ end
29
+ end
30
+
31
+ context "with from_sysdev" do
32
+ subject { described_class.from_sysdev }
33
+
34
+ context "when /sys/devices/system/cpu/present exists" do
35
+ before do
36
+ expect(::IO).to receive(:read).with("/sys/devices/system/cpu/present")
37
+ .and_return("dunno-whatever-#{num_cores - 1}")
38
+ end
39
+ it { is_expected.to eq num_cores }
40
+ end
41
+
42
+ context "when /sys/devices/system/cpu/present does NOT exist" do
43
+ before do
44
+ expect(::IO).to receive(:read).with("/sys/devices/system/cpu/present")
45
+ .and_raise(Errno::ENOENT)
46
+ end
47
+
48
+ context "when /sys/devices/system/cpu/cpu* files exist" do
49
+ before do
50
+ cpu_entries = (1..num_cores).map { |n| "cpu#{n}" }
51
+ cpu_entries << "non-cpu-entry-to-ignore"
52
+ expect(Dir).to receive(:[]).with("/sys/devices/system/cpu/cpu*")
53
+ .and_return(cpu_entries)
54
+ end
55
+ it { is_expected.to eq num_cores }
56
+ end
57
+ end
58
+
59
+ context "when /sys/devices/system/cpu/cpu* files DO NOT exist" do
60
+ before do
61
+ expect(Dir).to receive(:[]).with("/sys/devices/system/cpu/cpu*")
62
+ .and_return([])
63
+ end
64
+ end
65
+ end
66
+
67
+ context "with from_java" do
68
+ subject { described_class.from_java }
69
+
70
+ xit "not yet tested" do
71
+ end
72
+ end
73
+
74
+ context "with from_proc" do
75
+ subject { described_class.from_proc }
76
+
77
+ xit "not yet tested" do
78
+ end
79
+ end
80
+
81
+ context "with from_win32ole" do
82
+ subject { described_class.from_win32ole }
83
+
84
+ xit "not yet tested" do
85
+ end
86
+ end
87
+
88
+ context "with from_sysctl" do
89
+ subject { described_class.from_sysctl }
90
+
91
+ context "when sysctl blows up" do
92
+ before { allow(described_class).to receive(:`).and_raise(Errno::EINTR) }
93
+ it { is_expected.to be nil }
94
+ end
95
+
96
+ context "when sysctl fails" do
97
+ before { allow(described_class).to receive(:`).and_return(`false`) }
98
+ it { is_expected.to be nil }
99
+ end
100
+
101
+ context "when sysctl succeeds" do
102
+ before do
103
+ expect(described_class).to receive(:`).with("sysctl -n hw.ncpu 2>/dev/null")
104
+ .and_return(num_cores.to_s)
105
+ `true`
106
+ end
107
+ it { is_expected.to eq num_cores }
108
+ end
109
+ end
110
+
111
+ xit "when all guesses fail" do
112
+ end
113
+
114
+ context "with from_result" do
115
+ context "when passed a symbol" do
116
+ subject { described_class.from_result(:foo) }
117
+ it { is_expected.to be nil }
118
+ end
119
+ context "when passed 0" do
120
+ subject { described_class.from_result(:foo) }
121
+ it { is_expected.to be nil }
122
+ end
123
+ context "when passed valid integer" do
124
+ subject { described_class.from_result(num_cores) }
125
+ it { is_expected.to be num_cores }
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,43 @@
1
+ RSpec.describe Celluloid::Internals::Links do
2
+ subject { Celluloid::Internals::Links.new }
3
+
4
+ let(:mailbox_mock) do
5
+ Class.new(Array) do
6
+ attr_reader :address
7
+ def initialize(address)
8
+ @address = address
9
+ end
10
+ end
11
+ end
12
+
13
+ let(:first_actor) do
14
+ Struct.new(:mailbox).new(mailbox_mock.new("foo123"))
15
+ end
16
+
17
+ let(:second_actor) do
18
+ Struct.new(:mailbox).new(mailbox_mock.new("bar456"))
19
+ end
20
+
21
+ it "is Enumerable" do
22
+ expect(subject).to be_an(Enumerable)
23
+ end
24
+
25
+ it "adds actors by their mailbox address" do
26
+ expect(subject.include?(first_actor)).to be_falsey
27
+ subject << first_actor
28
+ expect(subject.include?(first_actor)).to be_truthy
29
+ end
30
+
31
+ it "removes actors by their mailbox address" do
32
+ subject << first_actor
33
+ expect(subject.include?(first_actor)).to be_truthy
34
+ subject.delete first_actor
35
+ expect(subject.include?(first_actor)).to be_falsey
36
+ end
37
+
38
+ it "iterates over all actors" do
39
+ subject << first_actor
40
+ subject << second_actor
41
+ expect(subject.inject([]) { |all, a| all << a }).to eq([first_actor, second_actor])
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ RSpec.describe Celluloid::Internals::Properties do
2
+ let(:default_value) { 42 }
3
+ let(:changed_value) { 43 }
4
+
5
+ let(:example_class) do
6
+ Class.new do
7
+ extend Celluloid::Internals::Properties
8
+ property :baz, default: 42
9
+ end
10
+ end
11
+
12
+ let(:example_subclass) do
13
+ Class.new(example_class)
14
+ end
15
+
16
+ let(:example_subclass_subclass) do
17
+ Class.new(example_subclass)
18
+ end
19
+
20
+ it "adds properties to classes" do
21
+ expect(example_class.baz).to eq default_value
22
+ example_class.baz changed_value
23
+ expect(example_class.baz).to eq changed_value
24
+ end
25
+
26
+ it "allows properties to be inherited" do
27
+ expect(example_subclass.baz).to eq default_value
28
+ example_subclass.baz changed_value
29
+ expect(example_subclass.baz).to eq changed_value
30
+ expect(example_class.baz).to eq default_value
31
+ end
32
+
33
+ it "allows properties to be deeply inherited" do
34
+ expect(example_subclass_subclass.baz).to eq default_value
35
+ example_subclass_subclass.baz changed_value
36
+ expect(example_subclass_subclass.baz).to eq changed_value
37
+ expect(example_subclass.baz).to eq default_value
38
+ expect(example_class.baz).to eq default_value
39
+ end
40
+ end
@@ -0,0 +1,62 @@
1
+ RSpec.describe Celluloid::Internals::Registry, actor_system: :global do
2
+ class Marilyn
3
+ include Celluloid
4
+
5
+ def sing_for(person)
6
+ "o/~ Happy birthday, #{person}"
7
+ end
8
+ end
9
+
10
+ it "registers Actors" do
11
+ Celluloid::Actor[:marilyn] = Marilyn.new
12
+ expect(Celluloid::Actor[:marilyn].sing_for("Mr. President")).to eq("o/~ Happy birthday, Mr. President")
13
+ end
14
+
15
+ it "refuses to register non-Actors" do
16
+ expect do
17
+ Celluloid::Actor[:impostor] = Object.new
18
+ end.to raise_error TypeError
19
+ end
20
+
21
+ it "lists all registered actors" do
22
+ Celluloid::Actor[:marilyn] = Marilyn.new
23
+ expect(Celluloid::Actor.registered).to include :marilyn
24
+ end
25
+
26
+ it "knows its name once registered" do
27
+ Celluloid::Actor[:marilyn] = Marilyn.new
28
+ expect(Celluloid::Actor[:marilyn].registered_name).to eq(:marilyn)
29
+ end
30
+
31
+ describe :delete do
32
+ before do
33
+ Celluloid::Actor[:marilyn] ||= Marilyn.new
34
+ end
35
+
36
+ it "removes reference to actors' name from the registry" do
37
+ Celluloid::Actor.delete(:marilyn)
38
+ expect(Celluloid::Actor.registered).not_to include :marilyn
39
+ end
40
+
41
+ it "returns actor removed from the registry" do
42
+ rval = Celluloid::Actor.delete(:marilyn)
43
+ expect(rval).to be_kind_of(Marilyn)
44
+ end
45
+ end
46
+
47
+ describe :clear do
48
+ it "should return a hash of registered actors and remove them from the registry" do
49
+ Celluloid::Actor[:marilyn] ||= Marilyn.new
50
+ rval = Celluloid::Actor.clear_registry
51
+ begin
52
+ expect(rval).to be_kind_of(Hash)
53
+ expect(rval).to have_key(:marilyn)
54
+ expect(rval[:marilyn].wrapped_object).to be_instance_of(Marilyn)
55
+ expect(Celluloid::Actor.registered).to be_empty
56
+ ensure
57
+ # Repopulate the registry once we're done
58
+ rval.each { |key, actor| Celluloid::Actor[key] = actor }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ RSpec.describe Celluloid::Internals::Stack::Dump do
2
+ subject { actor_system.stack_dump }
3
+ it_behaves_like "a Celluloid Stack"
4
+ end
@@ -0,0 +1,4 @@
1
+ RSpec.describe Celluloid::Internals::Stack::Summary do
2
+ subject { actor_system.stack_summary }
3
+ it_behaves_like "a Celluloid Stack"
4
+ end
@@ -0,0 +1,60 @@
1
+ RSpec.describe Celluloid::Internals::ThreadHandle do
2
+ let(:actor_system) { Celluloid::Actor::System.new }
3
+ after { actor_system.shutdown }
4
+
5
+ context "given a living thread" do
6
+ let(:args) { [actor_system] }
7
+
8
+ before do
9
+ @thread = nil
10
+ @thread_info_queue = Queue.new
11
+ @handle = Celluloid::Internals::ThreadHandle.new(*args) do
12
+ @thread_info_queue << Thread.current
13
+ sleep
14
+ end
15
+ @thread = Timeout.timeout(2) { @thread_info_queue.pop }
16
+ end
17
+
18
+ it "knows the thread is alive" do
19
+ alive = @handle.alive?
20
+ if @thread
21
+ @thread.kill
22
+ @thread.join
23
+ else
24
+ STDERR.puts "NOTE: something failed - thread missing"
25
+ end
26
+ expect(alive).to be(true)
27
+ end
28
+
29
+ context "when a role is provided" do
30
+ let(:args) { [actor_system, :useful] }
31
+
32
+ it "can be retrieved from thread directly" do
33
+ role = @thread.role
34
+ if @thread
35
+ @thread.kill
36
+ @thread.join
37
+ else
38
+ STDERR.puts "NOTE: something failed - thread missing"
39
+ end
40
+ expect(role).to eq(:useful)
41
+ end
42
+ end
43
+ end
44
+
45
+ context "given a finished thread" do
46
+ before do
47
+ thread_info_queue = Queue.new
48
+ @handle = Celluloid::Internals::ThreadHandle.new(actor_system) do
49
+ thread_info_queue << Thread.current
50
+ end
51
+ thread = thread_info_queue.pop
52
+ thread.kill
53
+ Specs.sleep_and_wait_until { !thread.alive? }
54
+ end
55
+
56
+ it "knows the thread is no longer alive" do
57
+ expect(@handle).not_to be_alive
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.describe Celluloid::Internals::UUID do
2
+ U = Celluloid::Internals::UUID
3
+
4
+ it "generates unique IDs across the BLOCK_SIZE boundary" do
5
+ upper_bound = U::BLOCK_SIZE * 2 + 10
6
+ uuids = (1..upper_bound).map { U.generate }
7
+ expect(uuids.size).to eq(uuids.uniq.size)
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ RSpec.describe Celluloid::RingBuffer do
2
+ subject { Celluloid::RingBuffer.new(2) }
3
+
4
+ it { is_expected.to be_empty }
5
+ it { is_expected.not_to be_full }
6
+
7
+ it "should push and shift" do
8
+ subject.push("foo")
9
+ subject.push("foo2")
10
+ expect(subject.shift).to eq("foo")
11
+ expect(subject.shift).to eq("foo2")
12
+ end
13
+
14
+ it "should push past the end" do
15
+ subject.push("foo")
16
+ subject.push("foo2")
17
+ subject.push("foo3")
18
+ expect(subject).to be_full
19
+ end
20
+
21
+ it "should shift the most recent" do
22
+ (1..5).each { |i| subject.push(i) }
23
+ expect(subject.shift).to be 4
24
+ expect(subject.shift).to be 5
25
+ expect(subject.shift).to be_nil
26
+ end
27
+
28
+ it "should return nil when shifting empty" do
29
+ expect(subject).to be_empty
30
+ expect(subject.shift).to be_nil
31
+ end
32
+
33
+ it "should be thread-safe" do
34
+ # TODO: how to test?
35
+ end
36
+ end
@@ -2,36 +2,25 @@ RSpec.describe Celluloid::Mailbox::Evented do
2
2
  subject { TestEventedMailbox.new }
3
3
  it_behaves_like "a Celluloid Mailbox"
4
4
 
5
- # NOTE: this example seems too exotic to "have to" succeed on RBX, though I
6
- # don't know why it hangs on subject.receive and the timeout never occurs
7
- #
8
- # Other than
9
- #
10
- # Links:
11
- # https://github.com/celluloid/celluloid-io/pull/98
12
- # https://github.com/celluloid/celluloid-io/issues/56
13
- #
14
- unless RUBY_ENGINE == "rbx"
15
- it "recovers from timeout exceeded to process mailbox message" do
16
- timeout_interval = Specs::TIMER_QUANTUM + 0.1
17
- started_at = Time.now
18
- expect do
19
- Kernel.send(:timeout, timeout_interval) do
20
- subject.receive { false }
21
- end
22
- end.to raise_exception(Timeout::Error)
5
+ it "recovers from timeout exceeded to process mailbox message" do
6
+ timeout_interval = Specs::TIMER_QUANTUM + 0.1
7
+ started_at = Time.now
8
+ expect do
9
+ ::Timeout.timeout(timeout_interval) do
10
+ subject.receive { false }
11
+ end
12
+ end.to raise_exception(Timeout::Error)
23
13
 
24
- expect(Time.now - started_at).to be_within(Specs::TIMER_QUANTUM).of timeout_interval
25
- end
14
+ expect(Time.now - started_at).to be_within(Specs::TIMER_QUANTUM).of timeout_interval
26
15
  end
27
16
 
28
17
  it "discard messages when reactor wakeup fails" do
29
- expect(Celluloid::Internals::Logger).to receive(:crash).with('reactor crashed', RuntimeError)
18
+ expect(Celluloid::Internals::Logger).to receive(:crash).with("reactor crashed", RuntimeError)
30
19
  expect(Celluloid.logger).to receive(:debug).with("Discarded message (mailbox is dead): first")
31
20
 
32
21
  bad_reactor = Class.new do
33
22
  def wakeup
34
- fail
23
+ raise
35
24
  end
36
25
  end
37
26
  mailbox = Celluloid::Mailbox::Evented.new(bad_reactor)
@@ -13,11 +13,10 @@ RSpec.describe "Leaks", actor_system: :global, leaktest: true,
13
13
  []
14
14
  end
15
15
 
16
- def terminate
17
- end
16
+ def terminate; end
18
17
  end
19
18
 
20
- def wait_for_release(weak, _what, count=1000)
19
+ def wait_for_release(weak, _what, count = 1000)
21
20
  trash = []
22
21
  count.times do |step|
23
22
  GC.start
@@ -43,7 +42,7 @@ RSpec.describe "Leaks", actor_system: :global, leaktest: true,
43
42
  end
44
43
 
45
44
  context "celluloid actor" do
46
- it "is properly destroyed upon termination" do
45
+ xit "is properly destroyed upon termination" do
47
46
  actor_life("actor") do |actor|
48
47
  WeakRef.new actor
49
48
  end