celluloid 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of celluloid might be problematic. Click here for more details.

Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +333 -0
  3. data/README.md +1 -1
  4. data/culture/CODE_OF_CONDUCT.md +28 -0
  5. data/culture/Gemfile +9 -0
  6. data/culture/README.md +22 -0
  7. data/culture/Rakefile +5 -0
  8. data/culture/SYNC.md +70 -0
  9. data/culture/celluloid-culture.gemspec +18 -0
  10. data/culture/gems/README.md +39 -0
  11. data/culture/gems/dependencies.yml +78 -0
  12. data/culture/gems/loader.rb +101 -0
  13. data/culture/rubocop/README.md +38 -0
  14. data/culture/rubocop/lint.yml +8 -0
  15. data/culture/rubocop/metrics.yml +15 -0
  16. data/culture/rubocop/rubocop.yml +4 -0
  17. data/culture/rubocop/style.yml +48 -0
  18. data/culture/spec/gems_spec.rb +2 -0
  19. data/culture/spec/spec_helper.rb +0 -0
  20. data/culture/spec/sync_spec.rb +2 -0
  21. data/culture/sync.rb +56 -0
  22. data/culture/tasks/rspec.rake +5 -0
  23. data/culture/tasks/rubocop.rake +2 -0
  24. data/examples/basic_usage.rb +49 -0
  25. data/examples/futures.rb +38 -0
  26. data/examples/ring.rb +61 -0
  27. data/examples/simple_pmap.rb +14 -0
  28. data/examples/timers.rb +72 -0
  29. data/lib/celluloid.rb +142 -127
  30. data/lib/celluloid/actor.rb +47 -41
  31. data/lib/celluloid/actor_system.rb +75 -22
  32. data/lib/celluloid/autostart.rb +1 -1
  33. data/lib/celluloid/backported.rb +2 -0
  34. data/lib/celluloid/call/async.rb +16 -0
  35. data/lib/celluloid/call/block.rb +22 -0
  36. data/lib/celluloid/call/sync.rb +70 -0
  37. data/lib/celluloid/calls.rb +25 -114
  38. data/lib/celluloid/cell.rb +32 -20
  39. data/lib/celluloid/condition.rb +3 -3
  40. data/lib/celluloid/core_ext.rb +1 -1
  41. data/lib/celluloid/current.rb +2 -0
  42. data/lib/celluloid/deprecate.rb +18 -0
  43. data/lib/celluloid/exceptions.rb +1 -1
  44. data/lib/celluloid/fiber.rb +3 -3
  45. data/lib/celluloid/future.rb +7 -6
  46. data/lib/celluloid/group.rb +65 -0
  47. data/lib/celluloid/group/manager.rb +27 -0
  48. data/lib/celluloid/group/pool.rb +125 -0
  49. data/lib/celluloid/group/spawner.rb +71 -0
  50. data/lib/celluloid/logging.rb +5 -5
  51. data/lib/celluloid/mailbox.rb +14 -13
  52. data/lib/celluloid/mailbox/evented.rb +76 -0
  53. data/lib/celluloid/notices.rb +15 -0
  54. data/lib/celluloid/proxies.rb +12 -0
  55. data/lib/celluloid/proxy/abstract.rb +24 -0
  56. data/lib/celluloid/proxy/actor.rb +46 -0
  57. data/lib/celluloid/proxy/async.rb +36 -0
  58. data/lib/celluloid/proxy/block.rb +31 -0
  59. data/lib/celluloid/proxy/cell.rb +76 -0
  60. data/lib/celluloid/proxy/future.rb +40 -0
  61. data/lib/celluloid/proxy/sync.rb +44 -0
  62. data/lib/celluloid/rspec.rb +9 -10
  63. data/lib/celluloid/system_events.rb +16 -15
  64. data/lib/celluloid/{tasks.rb → task.rb} +21 -21
  65. data/lib/celluloid/task/fibered.rb +45 -0
  66. data/lib/celluloid/task/threaded.rb +59 -0
  67. data/lib/celluloid/test.rb +1 -1
  68. data/lib/celluloid/thread.rb +6 -1
  69. data/lib/celluloid/version.rb +3 -0
  70. data/spec/celluloid/actor_spec.rb +2 -2
  71. data/spec/celluloid/actor_system_spec.rb +35 -21
  72. data/spec/celluloid/block_spec.rb +3 -5
  73. data/spec/celluloid/calls_spec.rb +33 -11
  74. data/spec/celluloid/condition_spec.rb +16 -13
  75. data/spec/celluloid/evented_mailbox_spec.rb +1 -31
  76. data/spec/celluloid/future_spec.rb +13 -10
  77. data/spec/celluloid/group/elastic_spec.rb +0 -0
  78. data/spec/celluloid/group/manager_spec.rb +0 -0
  79. data/spec/celluloid/group/pool_spec.rb +8 -0
  80. data/spec/celluloid/group/spawner_spec.rb +8 -0
  81. data/spec/celluloid/mailbox/evented_spec.rb +27 -0
  82. data/spec/celluloid/mailbox_spec.rb +1 -3
  83. data/spec/celluloid/misc/leak_spec.rb +73 -0
  84. data/spec/celluloid/task/fibered_spec.rb +5 -0
  85. data/spec/celluloid/task/threaded_spec.rb +5 -0
  86. data/spec/celluloid/timer_spec.rb +14 -16
  87. data/spec/deprecate/actor_system_spec.rb +72 -0
  88. data/spec/deprecate/block_spec.rb +52 -0
  89. data/spec/deprecate/calls_spec.rb +57 -0
  90. data/spec/deprecate/evented_mailbox_spec.rb +34 -0
  91. data/spec/deprecate/future_spec.rb +32 -0
  92. data/spec/deprecate/internal_pool_spec.rb +4 -0
  93. data/spec/shared/actor_examples.rb +1237 -0
  94. data/spec/shared/group_examples.rb +121 -0
  95. data/{lib/celluloid/rspec → spec/shared}/mailbox_examples.rb +20 -17
  96. data/{lib/celluloid/rspec → spec/shared}/task_examples.rb +9 -8
  97. data/spec/spec_helper.rb +72 -16
  98. data/spec/support/coverage.rb +4 -0
  99. data/spec/support/crash_checking.rb +68 -0
  100. data/spec/support/debugging.rb +31 -0
  101. data/spec/support/env.rb +16 -0
  102. data/{lib/celluloid/rspec/example_actor_class.rb → spec/support/examples/actor_class.rb} +21 -2
  103. data/spec/support/examples/evented_mailbox_class.rb +27 -0
  104. data/spec/support/includer.rb +9 -0
  105. data/spec/support/logging.rb +63 -0
  106. data/spec/support/loose_threads.rb +65 -0
  107. data/spec/support/reset_class_variables.rb +27 -0
  108. data/spec/support/sleep_and_wait.rb +14 -0
  109. data/spec/support/split_logs.rb +1 -0
  110. data/spec/support/stubbing.rb +14 -0
  111. metadata +255 -95
  112. data/lib/celluloid/call_chain.rb +0 -13
  113. data/lib/celluloid/cpu_counter.rb +0 -34
  114. data/lib/celluloid/evented_mailbox.rb +0 -73
  115. data/lib/celluloid/fsm.rb +0 -186
  116. data/lib/celluloid/handlers.rb +0 -41
  117. data/lib/celluloid/internal_pool.rb +0 -159
  118. data/lib/celluloid/legacy.rb +0 -9
  119. data/lib/celluloid/links.rb +0 -36
  120. data/lib/celluloid/logger.rb +0 -93
  121. data/lib/celluloid/logging/incident.rb +0 -21
  122. data/lib/celluloid/logging/incident_logger.rb +0 -129
  123. data/lib/celluloid/logging/incident_reporter.rb +0 -48
  124. data/lib/celluloid/logging/log_event.rb +0 -20
  125. data/lib/celluloid/logging/ring_buffer.rb +0 -65
  126. data/lib/celluloid/method.rb +0 -32
  127. data/lib/celluloid/notifications.rb +0 -83
  128. data/lib/celluloid/pool_manager.rb +0 -146
  129. data/lib/celluloid/probe.rb +0 -73
  130. data/lib/celluloid/properties.rb +0 -24
  131. data/lib/celluloid/proxies/abstract_proxy.rb +0 -20
  132. data/lib/celluloid/proxies/actor_proxy.rb +0 -38
  133. data/lib/celluloid/proxies/async_proxy.rb +0 -31
  134. data/lib/celluloid/proxies/block_proxy.rb +0 -29
  135. data/lib/celluloid/proxies/cell_proxy.rb +0 -68
  136. data/lib/celluloid/proxies/future_proxy.rb +0 -35
  137. data/lib/celluloid/proxies/sync_proxy.rb +0 -36
  138. data/lib/celluloid/receivers.rb +0 -63
  139. data/lib/celluloid/registry.rb +0 -57
  140. data/lib/celluloid/responses.rb +0 -44
  141. data/lib/celluloid/rspec/actor_examples.rb +0 -1054
  142. data/lib/celluloid/signals.rb +0 -23
  143. data/lib/celluloid/stack_dump.rb +0 -133
  144. data/lib/celluloid/supervision_group.rb +0 -169
  145. data/lib/celluloid/supervisor.rb +0 -22
  146. data/lib/celluloid/task_set.rb +0 -49
  147. data/lib/celluloid/tasks/task_fiber.rb +0 -43
  148. data/lib/celluloid/tasks/task_thread.rb +0 -53
  149. data/lib/celluloid/thread_handle.rb +0 -50
  150. data/lib/celluloid/uuid.rb +0 -38
  151. data/spec/celluloid/cpu_counter_spec.rb +0 -82
  152. data/spec/celluloid/fsm_spec.rb +0 -107
  153. data/spec/celluloid/internal_pool_spec.rb +0 -52
  154. data/spec/celluloid/links_spec.rb +0 -45
  155. data/spec/celluloid/logging/ring_buffer_spec.rb +0 -38
  156. data/spec/celluloid/notifications_spec.rb +0 -120
  157. data/spec/celluloid/pool_spec.rb +0 -92
  158. data/spec/celluloid/probe_spec.rb +0 -121
  159. data/spec/celluloid/properties_spec.rb +0 -42
  160. data/spec/celluloid/registry_spec.rb +0 -64
  161. data/spec/celluloid/stack_dump_spec.rb +0 -64
  162. data/spec/celluloid/supervision_group_spec.rb +0 -65
  163. data/spec/celluloid/supervisor_spec.rb +0 -103
  164. data/spec/celluloid/tasks/task_fiber_spec.rb +0 -5
  165. data/spec/celluloid/tasks/task_thread_spec.rb +0 -5
  166. data/spec/celluloid/thread_handle_spec.rb +0 -26
  167. data/spec/celluloid/uuid_spec.rb +0 -11
@@ -1,68 +0,0 @@
1
- module Celluloid
2
- # A proxy object returned from Celluloid::Actor.new/new_link which converts
3
- # the normal Ruby method protocol into an inter-actor message protocol
4
- class CellProxy < SyncProxy
5
- # Used for reflecting on proxy objects themselves
6
- def __class__; CellProxy; end
7
-
8
- def initialize(actor_proxy, mailbox, klass)
9
- super(mailbox, klass)
10
- @actor_proxy = actor_proxy
11
- @sync_proxy = SyncProxy.new(mailbox, klass)
12
- @async_proxy = AsyncProxy.new(mailbox, klass)
13
- @future_proxy = FutureProxy.new(mailbox, klass)
14
- end
15
-
16
- def _send_(meth, *args, &block)
17
- method_missing :__send__, meth, *args, &block
18
- end
19
-
20
- def inspect
21
- method_missing :inspect
22
- rescue DeadActorError
23
- "#<Celluloid::CellProxy(#{@klass}) dead>"
24
- end
25
-
26
- def method(name)
27
- Method.new(self, name)
28
- end
29
-
30
- alias_method :sync, :method_missing
31
-
32
- # Obtain an async proxy or explicitly invoke a named async method
33
- def async(method_name = nil, *args, &block)
34
- if method_name
35
- @async_proxy.method_missing method_name, *args, &block
36
- else
37
- @async_proxy
38
- end
39
- end
40
-
41
- # Obtain a future proxy or explicitly invoke a named future method
42
- def future(method_name = nil, *args, &block)
43
- if method_name
44
- @future_proxy.method_missing method_name, *args, &block
45
- else
46
- @future_proxy
47
- end
48
- end
49
-
50
- def alive?
51
- @actor_proxy.alive?
52
- end
53
-
54
- def thread
55
- @actor_proxy.thread
56
- end
57
-
58
- # Terminate the associated actor
59
- def terminate
60
- @actor_proxy.terminate
61
- end
62
-
63
- # Terminate the associated actor asynchronously
64
- def terminate!
65
- @actor_proxy.terminate!
66
- end
67
- end
68
- end
@@ -1,35 +0,0 @@
1
- module Celluloid
2
- # A proxy which creates future calls to an actor
3
- class FutureProxy < AbstractProxy
4
- attr_reader :mailbox
5
-
6
- # Used for reflecting on proxy objects themselves
7
- def __class__; FutureProxy; end
8
-
9
- def initialize(mailbox, klass)
10
- @mailbox, @klass = mailbox, klass
11
- end
12
-
13
- def inspect
14
- "#<Celluloid::FutureProxy(#{@klass})>"
15
- end
16
-
17
- def method_missing(meth, *args, &block)
18
- unless @mailbox.alive?
19
- raise DeadActorError, "attempted to call a dead actor"
20
- end
21
-
22
- if block_given?
23
- # FIXME: nicer exception
24
- raise "Cannot use blocks with futures yet"
25
- end
26
-
27
- future = Future.new
28
- call = SyncCall.new(future, meth, args, block)
29
-
30
- @mailbox << call
31
-
32
- future
33
- end
34
- end
35
- end
@@ -1,36 +0,0 @@
1
- module Celluloid
2
- # A proxy which sends synchronous calls to an actor
3
- class SyncProxy < AbstractProxy
4
- attr_reader :mailbox
5
-
6
- # Used for reflecting on proxy objects themselves
7
- def __class__; SyncProxy; end
8
-
9
- def initialize(mailbox, klass)
10
- @mailbox, @klass = mailbox, klass
11
- end
12
-
13
- def inspect
14
- "#<Celluloid::SyncProxy(#{@klass})>"
15
- end
16
-
17
- def respond_to?(meth, include_private = false)
18
- __class__.instance_methods.include?(meth) || method_missing(:respond_to?, meth, include_private)
19
- end
20
-
21
- def method_missing(meth, *args, &block)
22
- unless @mailbox.alive?
23
- raise DeadActorError, "attempted to call a dead actor"
24
- end
25
-
26
- if @mailbox == ::Thread.current[:celluloid_mailbox]
27
- args.unshift meth
28
- meth = :__send__
29
- end
30
-
31
- call = SyncCall.new(::Celluloid.mailbox, meth, args, block)
32
- @mailbox << call
33
- call.value
34
- end
35
- end
36
- end
@@ -1,63 +0,0 @@
1
- require 'set'
2
-
3
- require 'timers'
4
-
5
- module Celluloid
6
- # Allow methods to directly interact with the actor protocol
7
- class Receivers
8
- def initialize(timers)
9
- @receivers = Set.new
10
- @timers = timers
11
- end
12
-
13
- # Receive an asynchronous message
14
- def receive(timeout = nil, &block)
15
- if Celluloid.exclusive?
16
- Celluloid.mailbox.receive(timeout, &block)
17
- else
18
- receiver = Receiver.new block
19
-
20
- if timeout
21
- receiver.timer = @timers.after(timeout) do
22
- @receivers.delete receiver
23
- receiver.resume
24
- end
25
- end
26
-
27
- @receivers << receiver
28
- Task.suspend :receiving
29
- end
30
- end
31
-
32
- # Handle incoming messages
33
- def handle_message(message)
34
- receiver = @receivers.find { |r| r.match(message) }
35
- return unless receiver
36
-
37
- @receivers.delete receiver
38
- receiver.timer.cancel if receiver.timer
39
- receiver.resume message
40
- message
41
- end
42
- end
43
-
44
- # Methods blocking on a call to receive
45
- class Receiver
46
- attr_accessor :timer
47
-
48
- def initialize(block)
49
- @block = block
50
- @task = Task.current
51
- @timer = nil
52
- end
53
-
54
- # Match a message with this receiver's block
55
- def match(message)
56
- @block ? @block.call(message) : true
57
- end
58
-
59
- def resume(message = nil)
60
- @task.resume message
61
- end
62
- end
63
- end
@@ -1,57 +0,0 @@
1
- require 'thread'
2
-
3
- module Celluloid
4
- # The Registry allows us to refer to specific actors by human-meaningful names
5
- class Registry
6
- def initialize
7
- @registry = {}
8
- @registry_lock = Mutex.new
9
- end
10
-
11
- # Register an Actor
12
- def []=(name, actor)
13
- actor_singleton = class << actor; self; end
14
- unless actor_singleton.ancestors.include? AbstractProxy
15
- raise TypeError, "not an actor"
16
- end
17
-
18
- @registry_lock.synchronize do
19
- @registry[name.to_sym] = actor
20
- end
21
-
22
- actor.mailbox << NamingRequest.new(name.to_sym)
23
- end
24
-
25
- # Retrieve an actor by name
26
- def [](name)
27
- @registry_lock.synchronize do
28
- @registry[name.to_sym]
29
- end
30
- end
31
-
32
- alias_method :get, :[]
33
- alias_method :set, :[]=
34
-
35
- def delete(name)
36
- @registry_lock.synchronize do
37
- @registry.delete name.to_sym
38
- end
39
- end
40
-
41
- # List all registered actors by name
42
- def names
43
- @registry_lock.synchronize { @registry.keys }
44
- end
45
-
46
- # removes and returns all registered actors as a hash of `name => actor`
47
- # can be used in testing to clear the registry
48
- def clear
49
- hash = nil
50
- @registry_lock.synchronize do
51
- hash = @registry.dup
52
- @registry.clear
53
- end
54
- hash
55
- end
56
- end
57
- end
@@ -1,44 +0,0 @@
1
- module Celluloid
2
- # Responses to calls
3
- class Response
4
- attr_reader :call, :value
5
-
6
- def initialize(call, value)
7
- @call, @value = call, value
8
- end
9
-
10
- def dispatch
11
- @call.task.resume self
12
- end
13
- end
14
-
15
- # Call completed successfully
16
- class SuccessResponse < Response; end
17
-
18
- # Call was aborted due to sender error
19
- class ErrorResponse < Response
20
- def value
21
- ex = super
22
- ex = ex.cause if ex.is_a? AbortError
23
-
24
- if ex.backtrace
25
- ex.backtrace << "(celluloid):0:in `remote procedure call'"
26
- ex.backtrace.concat(caller)
27
- end
28
-
29
- raise ex
30
- end
31
- end
32
-
33
- class BlockResponse
34
- def initialize(call, result)
35
- @call = call
36
- @result = result
37
- end
38
-
39
- def dispatch
40
- @call.task.resume(@result)
41
- end
42
- end
43
-
44
- end
@@ -1,1054 +0,0 @@
1
- shared_examples "a Celluloid Actor" do |included_module|
2
- describe "using Fibers" do
3
- include_examples "Celluloid::Actor examples", included_module, Celluloid::TaskFiber
4
- end
5
- describe "using Threads" do
6
- include_examples "Celluloid::Actor examples", included_module, Celluloid::TaskThread
7
- end
8
- end
9
-
10
- shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
11
- class ExampleCrash < StandardError
12
- attr_accessor :foo
13
- end
14
-
15
- let(:actor_class) { ExampleActorClass.create(included_module, task_klass) }
16
-
17
- it "returns the actor's class, not the proxy's" do
18
- actor = actor_class.new "Troy McClure"
19
- actor.class.should eq(actor_class)
20
- end
21
-
22
- it "compares with the actor's class in a case statement" do
23
- case actor_class.new("Troy McClure")
24
- when actor_class
25
- true
26
- else
27
- false
28
- end.should be_true
29
- end
30
-
31
- it "can be stored in hashes" do
32
- actor = actor_class.new "Troy McClure"
33
- actor.hash.should_not eq(Kernel.hash)
34
- actor.object_id.should_not eq(Kernel.object_id)
35
- end
36
-
37
- it "implements respond_to? correctly" do
38
- actor = actor_class.new 'Troy McClure'
39
- actor.should respond_to(:alive?)
40
- end
41
-
42
- it "supports synchronous calls" do
43
- actor = actor_class.new "Troy McClure"
44
- actor.greet.should eq("Hi, I'm Troy McClure")
45
- end
46
-
47
- it "supports synchronous calls with blocks" do
48
- actor = actor_class.new "Blocky Ralboa"
49
-
50
- block_executed = false
51
- actor.run { block_executed = true }
52
- block_executed.should be_true
53
- end
54
-
55
- it "supports synchronous calls via #method" do
56
- method = actor_class.new("Troy McClure").method(:greet)
57
- method.call.should eq("Hi, I'm Troy McClure")
58
- end
59
-
60
- it "supports #arity calls via #method" do
61
- method = actor_class.new("Troy McClure").method(:greet)
62
- method.arity.should be(0)
63
-
64
- method = actor_class.new("Troy McClure").method(:change_name)
65
- method.arity.should be(1)
66
- end
67
-
68
- it "supports #name calls via #method" do
69
- method = actor_class.new("Troy McClure").method(:greet)
70
- method.name.should == :greet
71
- end
72
-
73
- it "supports #parameters via #method" do
74
- method = actor_class.new("Troy McClure").method(:greet)
75
- method.parameters.should == []
76
-
77
- method = actor_class.new("Troy McClure").method(:change_name)
78
- method.parameters.should == [[:req, :new_name]]
79
- end
80
-
81
- it "supports future(:method) syntax for synchronous future calls" do
82
- actor = actor_class.new "Troy McClure"
83
- future = actor.future :greet
84
- future.value.should eq("Hi, I'm Troy McClure")
85
- end
86
-
87
- it "supports future.method syntax for synchronous future calls" do
88
- actor = actor_class.new "Troy McClure"
89
- future = actor.future.greet
90
- future.value.should eq("Hi, I'm Troy McClure")
91
- end
92
-
93
- it "handles circular synchronous calls" do
94
- klass = Class.new do
95
- include included_module
96
- task_class task_klass
97
-
98
- def greet_by_proxy(actor)
99
- actor.greet
100
- end
101
-
102
- def to_s
103
- "a ponycopter!"
104
- end
105
- end
106
-
107
- ponycopter = klass.new
108
- actor = actor_class.new ponycopter
109
- ponycopter.greet_by_proxy(actor).should eq("Hi, I'm a ponycopter!")
110
- end
111
-
112
- it "detects recursion" do
113
- klass1 = Class.new do
114
- include included_module
115
- task_class task_klass
116
-
117
- def recursion_test(recurse_through = nil)
118
- if recurse_through
119
- recurse_through.recursion_thunk(Celluloid::Actor.current)
120
- else
121
- Celluloid.detect_recursion
122
- end
123
- end
124
- end
125
-
126
- klass2 = Class.new do
127
- include included_module
128
- task_class task_klass
129
-
130
- def recursion_thunk(other)
131
- other.recursion_test
132
- end
133
- end
134
-
135
- actor1 = klass1.new
136
- actor2 = klass2.new
137
-
138
- actor1.recursion_test.should be_false
139
- actor1.recursion_test(actor2).should be_true
140
- end
141
-
142
- it "properly handles method_missing" do
143
- actor = actor_class.new "Method Missing"
144
- actor.should respond_to(:first)
145
- actor.first.should be :bar
146
- end
147
-
148
- it "properly handles respond_to with include_private" do
149
- actor = actor_class.new "Method missing privates"
150
- actor.respond_to?(:zomg_private).should be_false
151
- actor.respond_to?(:zomg_private, true).should be_true
152
- end
153
-
154
- it "warns about suspending the initialize" do
155
- klass = Class.new do
156
- include included_module
157
- task_class task_klass
158
-
159
- def initialize
160
- sleep 0.1
161
- end
162
- end
163
-
164
- Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:call, meta={:method_name=>:initialize}, status=:sleeping/)
165
-
166
- actor = klass.new
167
- actor.terminate
168
- Celluloid::Actor.join(actor) unless defined?(JRUBY_VERSION)
169
- end
170
-
171
- it "calls the user defined finalizer" do
172
- actor = actor_class.new "Mr. Bean"
173
- actor.wrapped_object.should_receive(:my_finalizer)
174
- actor.terminate
175
- Celluloid::Actor.join(actor)
176
- end
177
-
178
- it "warns about suspending the finalizer" do
179
- klass = Class.new do
180
- include included_module
181
- task_class task_klass
182
-
183
- finalizer :cleanup
184
-
185
- def cleanup
186
- sleep 0.1
187
- end
188
- end
189
-
190
- Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:finalizer, meta={:method_name=>:cleanup}, status=:sleeping/)
191
-
192
- actor = klass.new
193
- actor.terminate
194
- Celluloid::Actor.join(actor)
195
- end
196
-
197
- it "supports async(:method) syntax for asynchronous calls" do
198
- actor = actor_class.new "Troy McClure"
199
- actor.async :change_name, "Charlie Sheen"
200
- actor.greet.should eq("Hi, I'm Charlie Sheen")
201
- end
202
-
203
- it "supports async.method syntax for asynchronous calls" do
204
- actor = actor_class.new "Troy McClure"
205
- actor.async.change_name "Charlie Sheen"
206
- actor.greet.should eq("Hi, I'm Charlie Sheen")
207
- end
208
-
209
- it "supports async.method syntax for asynchronous calls to itself" do
210
- actor = actor_class.new "Troy McClure"
211
- actor.change_name_async "Charlie Sheen"
212
- actor.greet.should eq("Hi, I'm Charlie Sheen")
213
- end
214
-
215
- it "allows an actor to call private methods asynchronously" do
216
- actor = actor_class.new "Troy McClure"
217
- actor.call_private
218
- actor.private_called.should be_true
219
- end
220
-
221
- it "knows if it's inside actor scope" do
222
- Celluloid.should_not be_actor
223
- actor = actor_class.new "Troy McClure"
224
- actor.run do
225
- Celluloid.actor?
226
- end.should be_false
227
- actor.run_on_receiver do
228
- Celluloid.actor?
229
- end.should be_true
230
- actor.should be_actor
231
- end
232
-
233
- it "inspects properly" do
234
- actor = actor_class.new "Troy McClure"
235
- actor.inspect.should match(/Celluloid::CellProxy\(/)
236
- actor.inspect.should match(/#{actor_class}/)
237
- actor.inspect.should include('@name="Troy McClure"')
238
- actor.inspect.should_not include("@celluloid")
239
- end
240
-
241
- it "inspects properly when dead" do
242
- actor = actor_class.new "Troy McClure"
243
- actor.terminate
244
- actor.inspect.should match(/Celluloid::CellProxy\(/)
245
- actor.inspect.should match(/#{actor_class}/)
246
- actor.inspect.should include('dead')
247
- end
248
-
249
- it "supports recursive inspect with other actors" do
250
- klass = Class.new do
251
- include included_module
252
- task_class task_klass
253
-
254
- attr_accessor :other
255
-
256
- def initialize(other = nil)
257
- @other = other
258
- end
259
- end
260
-
261
- itchy = klass.new
262
- scratchy = klass.new(itchy)
263
- itchy.other = scratchy
264
-
265
- inspection = itchy.inspect
266
- inspection.should match(/Celluloid::CellProxy\(/)
267
- inspection.should include("...")
268
- end
269
-
270
- it "allows access to the wrapped object" do
271
- actor = actor_class.new "Troy McClure"
272
- actor.wrapped_object.should be_a actor_class
273
- end
274
-
275
- it "warns about leaked wrapped objects via #inspect" do
276
- actor = actor_class.new "Troy McClure"
277
-
278
- actor.inspect.should_not include Celluloid::BARE_OBJECT_WARNING_MESSAGE
279
- actor.inspect_thunk.should_not include Celluloid::BARE_OBJECT_WARNING_MESSAGE
280
- actor.wrapped_object.inspect.should include Celluloid::BARE_OBJECT_WARNING_MESSAGE
281
- end
282
-
283
- it "can override #send" do
284
- actor = actor_class.new "Troy McClure"
285
- actor.send('foo').should eq('oof')
286
- end
287
-
288
- context "when executing under JRuby" do
289
- let(:klass) {
290
- Class.new do
291
- include included_module
292
- task_class task_klass
293
-
294
- def current_thread_name
295
- java_thread.get_name
296
- end
297
-
298
- def java_thread
299
- Thread.current.to_java.getNativeThread
300
- end
301
- end
302
- }
303
-
304
- it "sets execution info" do
305
- klass.new.current_thread_name.should == "Class#current_thread_name"
306
- end
307
-
308
- it "unsets execution info after task completion" do
309
- klass.new.java_thread.get_name.should == "<unused>"
310
- end
311
- end if RUBY_PLATFORM == "java"
312
-
313
- context "mocking methods" do
314
- let(:actor) { actor_class.new "Troy McClure" }
315
-
316
- before do
317
- actor.wrapped_object.should_receive(:external_hello).once.and_return "World"
318
- end
319
-
320
- it "works externally via the proxy" do
321
- actor.external_hello.should eq("World")
322
- end
323
-
324
- it "works internally when called on self" do
325
- actor.internal_hello.should eq("World")
326
- end
327
- end
328
-
329
- context :exceptions do
330
- it "reraises exceptions which occur during synchronous calls in the sender" do
331
- actor = actor_class.new "James Dean" # is this in bad taste?
332
-
333
- expect do
334
- actor.crash
335
- end.to raise_exception(ExampleCrash)
336
- end
337
-
338
- it "includes both sender and receiver in exception traces" do
339
- example_receiver = Class.new do
340
- include included_module
341
- task_class task_klass
342
-
343
- define_method(:receiver_method) do
344
- raise ExampleCrash, "the spec purposely crashed me :("
345
- end
346
- end
347
-
348
- excample_caller = Class.new do
349
- include included_module
350
- task_class task_klass
351
-
352
- define_method(:sender_method) do
353
- example_receiver.new.receiver_method
354
- end
355
- end
356
-
357
- ex = nil
358
- begin
359
- excample_caller.new.sender_method
360
- rescue => ex
361
- end
362
-
363
- ex.should be_a ExampleCrash
364
- ex.backtrace.grep(/`sender_method'/).should be_true
365
- ex.backtrace.grep(/`receiver_method'/).should be_true
366
- end
367
-
368
- it "raises DeadActorError if methods are synchronously called on a dead actor" do
369
- actor = actor_class.new "James Dean"
370
- actor.crash rescue nil
371
-
372
- sleep 0.1 # hax to prevent a race between exit handling and the next call
373
-
374
- expect do
375
- actor.greet
376
- end.to raise_exception(Celluloid::DeadActorError)
377
- end
378
- end
379
-
380
- context :abort do
381
- it "raises exceptions in the sender but keeps running" do
382
- actor = actor_class.new "Al Pacino"
383
-
384
- expect do
385
- actor.crash_with_abort "You die motherfucker!", :bar
386
- end.to raise_exception(ExampleCrash, "You die motherfucker!")
387
-
388
- actor.should be_alive
389
- end
390
-
391
- it "converts strings to runtime errors" do
392
- actor = actor_class.new "Al Pacino"
393
- expect do
394
- actor.crash_with_abort_raw "foo"
395
- end.to raise_exception(RuntimeError, "foo")
396
- end
397
-
398
- it "crashes the sender if we pass neither String nor Exception" do
399
- actor = actor_class.new "Al Pacino"
400
- expect do
401
- actor.crash_with_abort_raw 10
402
- end.to raise_exception(TypeError, "Exception object/String expected, but Fixnum received")
403
-
404
- Celluloid::Actor.join(actor)
405
- actor.should_not be_alive
406
- end
407
- end
408
-
409
- context :termination do
410
- it "terminates" do
411
- actor = actor_class.new "Arnold Schwarzenegger"
412
- actor.should be_alive
413
- actor.terminate
414
- Celluloid::Actor.join(actor)
415
- actor.should_not be_alive
416
- end
417
-
418
- it "can be terminated by a SyncCall" do
419
- actor = actor_class.new "Arnold Schwarzenegger"
420
- actor.should be_alive
421
- actor.shutdown
422
- Celluloid::Actor.join(actor)
423
- actor.should_not be_alive
424
- end
425
-
426
- it "kills" do # THOU SHALT ALWAYS KILL
427
- actor = actor_class.new "Woody Harrelson"
428
- actor.should be_alive
429
- Celluloid::Actor.kill(actor)
430
- Celluloid::Actor.join(actor)
431
- actor.should_not be_alive
432
- end
433
-
434
- it "raises DeadActorError if called after terminated" do
435
- actor = actor_class.new "Arnold Schwarzenegger"
436
- actor.terminate
437
-
438
- expect do
439
- actor.greet
440
- end.to raise_exception(Celluloid::DeadActorError)
441
- end
442
-
443
- it "terminates cleanly on Celluloid shutdown" do
444
- Celluloid::Actor.stub(:kill).and_call_original
445
-
446
- actor = actor_class.new "Arnold Schwarzenegger"
447
-
448
- Celluloid.shutdown
449
- Celluloid::Actor.should_not have_received(:kill)
450
- end
451
-
452
- it "raises the right DeadActorError if terminate! called after terminated" do
453
- actor = actor_class.new "Arnold Schwarzenegger"
454
- actor.terminate
455
-
456
- expect do
457
- actor.terminate!
458
- end.to raise_exception(Celluloid::DeadActorError, "actor already terminated")
459
- end
460
-
461
- it "logs a warning when terminating tasks" do
462
- Celluloid.logger.should_receive(:warn).with(/^Terminating task: type=:call, meta={:method_name=>:sleepy}, status=:sleeping\n/)
463
-
464
- actor = actor_class.new "Arnold Schwarzenegger"
465
- actor.async.sleepy 10
466
- actor.greet # make sure the actor has started sleeping
467
-
468
- actor.terminate
469
- end
470
- end
471
-
472
- context :current_actor do
473
- it "knows the current actor" do
474
- actor = actor_class.new "Roger Daltrey"
475
- actor.current_actor.should eq actor
476
- end
477
-
478
- it "raises NotActorError if called outside an actor" do
479
- expect do
480
- Celluloid.current_actor
481
- end.to raise_exception(Celluloid::NotActorError)
482
- end
483
- end
484
-
485
- context :linking do
486
- before :each do
487
- @kevin = actor_class.new "Kevin Bacon" # Some six degrees action here
488
- @charlie = actor_class.new "Charlie Sheen"
489
- end
490
-
491
- let(:supervisor_class) do
492
- Class.new do # like a boss
493
- include included_module
494
- task_class task_klass
495
- trap_exit :lambaste_subordinate
496
-
497
- def initialize(name)
498
- @name = name
499
- @subordinate_lambasted = false
500
- end
501
-
502
- def subordinate_lambasted?; @subordinate_lambasted; end
503
-
504
- def lambaste_subordinate(actor, reason)
505
- @subordinate_lambasted = true
506
- end
507
- end
508
- end
509
-
510
- it "links to other actors" do
511
- @kevin.link @charlie
512
- @kevin.monitoring?(@charlie).should be_true
513
- @kevin.linked_to?(@charlie).should be_true
514
- @charlie.monitoring?(@kevin).should be_true
515
- @charlie.linked_to?(@kevin).should be_true
516
- end
517
-
518
- it "unlinks from other actors" do
519
- @kevin.link @charlie
520
- @kevin.unlink @charlie
521
-
522
- @kevin.monitoring?(@charlie).should be_false
523
- @kevin.linked_to?(@charlie).should be_false
524
- @charlie.monitoring?(@kevin).should be_false
525
- @charlie.linked_to?(@kevin).should be_false
526
- end
527
-
528
- it "monitors other actors unidirectionally" do
529
- @kevin.monitor @charlie
530
-
531
- @kevin.monitoring?(@charlie).should be_true
532
- @kevin.linked_to?(@charlie).should be_false
533
- @charlie.monitoring?(@kevin).should be_false
534
- @charlie.linked_to?(@kevin).should be_false
535
- end
536
-
537
- it "unmonitors other actors" do
538
- @kevin.monitor @charlie
539
- @kevin.unmonitor @charlie
540
-
541
- @kevin.monitoring?(@charlie).should be_false
542
- @kevin.linked_to?(@charlie).should be_false
543
- @charlie.monitoring?(@kevin).should be_false
544
- @charlie.linked_to?(@kevin).should be_false
545
- end
546
-
547
- it "traps exit messages from other actors" do
548
- chuck = supervisor_class.new "Chuck Lorre"
549
- chuck.link @charlie
550
-
551
- expect do
552
- @charlie.crash
553
- end.to raise_exception(ExampleCrash)
554
-
555
- sleep 0.1 # hax to prevent a race between exit handling and the next call
556
- chuck.should be_subordinate_lambasted
557
- end
558
-
559
- it "traps exit messages from other actors in subclasses" do
560
- supervisor_subclass = Class.new(supervisor_class)
561
- chuck = supervisor_subclass.new "Chuck Lorre"
562
- chuck.link @charlie
563
-
564
- expect do
565
- @charlie.crash
566
- end.to raise_exception(ExampleCrash)
567
-
568
- sleep 0.1 # hax to prevent a race between exit handling and the next call
569
- chuck.should be_subordinate_lambasted
570
- end
571
-
572
- it "unlinks from a dead linked actor" do
573
- chuck = supervisor_class.new "Chuck Lorre"
574
- chuck.link @charlie
575
-
576
- expect do
577
- @charlie.crash
578
- end.to raise_exception(ExampleCrash)
579
-
580
- sleep 0.1 # hax to prevent a race between exit handling and the next call
581
- chuck.links.count.should be(0)
582
- end
583
- end
584
-
585
- context :signaling do
586
- before do
587
- @signaler = Class.new do
588
- include included_module
589
- task_class task_klass
590
-
591
- def initialize
592
- @waiting = false
593
- @signaled = false
594
- end
595
-
596
- def wait_for_signal
597
- raise "already signaled" if @signaled
598
-
599
- @waiting = true
600
- value = wait :ponycopter
601
-
602
- @waiting = false
603
- @signaled = true
604
- value
605
- end
606
-
607
- def send_signal(value)
608
- signal :ponycopter, value
609
- end
610
-
611
- def waiting?; @waiting end
612
- def signaled?; @signaled end
613
- end
614
- end
615
-
616
- it "allows methods within the same object to signal each other" do
617
- obj = @signaler.new
618
- obj.should_not be_signaled
619
-
620
- obj.async.wait_for_signal
621
- obj.should_not be_signaled
622
- obj.should be_waiting
623
-
624
- obj.send_signal :foobar
625
- obj.should be_signaled
626
- obj.should_not be_waiting
627
- end
628
-
629
- it "sends values along with signals" do
630
- obj = @signaler.new
631
- obj.should_not be_signaled
632
-
633
- future = obj.future(:wait_for_signal)
634
-
635
- obj.should be_waiting
636
- obj.should_not be_signaled
637
-
638
- obj.send_signal(:foobar).should be_true
639
- future.value.should be(:foobar)
640
- end
641
- end
642
-
643
- context :exclusive do
644
- subject do
645
- Class.new do
646
- include included_module
647
- task_class task_klass
648
-
649
- attr_reader :tasks
650
-
651
- def initialize
652
- @tasks = []
653
- end
654
-
655
- def log_task(task)
656
- @tasks << task
657
- end
658
-
659
- def exclusive_with_block_log_task(task)
660
- exclusive do
661
- sleep Celluloid::TIMER_QUANTUM
662
- log_task(task)
663
- end
664
- end
665
-
666
- def exclusive_log_task(task)
667
- sleep Celluloid::TIMER_QUANTUM
668
- log_task(task)
669
- end
670
- exclusive :exclusive_log_task
671
-
672
- def check_not_exclusive
673
- Celluloid.exclusive?
674
- end
675
-
676
- def check_exclusive
677
- exclusive { Celluloid.exclusive? }
678
- end
679
-
680
- def nested_exclusive_example
681
- exclusive { exclusive { nil }; Celluloid.exclusive? }
682
- end
683
- end.new
684
- end
685
-
686
- it "executes methods in the proper order with block form" do
687
- subject.async.exclusive_with_block_log_task(:one)
688
- subject.async.log_task(:two)
689
- sleep Celluloid::TIMER_QUANTUM * 2
690
- subject.tasks.should eq([:one, :two])
691
- end
692
-
693
- it "executes methods in the proper order with a class-level annotation" do
694
- subject.async.exclusive_log_task :one
695
- subject.async.log_task :two
696
- sleep Celluloid::TIMER_QUANTUM * 2
697
- subject.tasks.should eq([:one, :two])
698
- end
699
-
700
- it "knows when it's in exclusive mode" do
701
- subject.check_not_exclusive.should be_false
702
- subject.check_exclusive.should be_true
703
- end
704
-
705
- it "remains in exclusive mode inside nested blocks" do
706
- subject.nested_exclusive_example.should be_true
707
- end
708
- end
709
-
710
- context "exclusive classes" do
711
- subject do
712
- Class.new do
713
- include included_module
714
- task_class task_klass
715
- exclusive
716
-
717
- attr_reader :tasks
718
-
719
- def initialize
720
- @tasks = []
721
- end
722
-
723
- def eat_donuts
724
- sleep Celluloid::TIMER_QUANTUM
725
- @tasks << 'donuts'
726
- end
727
-
728
- def drink_coffee
729
- @tasks << 'coffee'
730
- end
731
- end
732
- end
733
-
734
- it "executes two methods in an exclusive order" do
735
- actor = subject.new
736
- actor.async.eat_donuts
737
- actor.async.drink_coffee
738
- sleep Celluloid::TIMER_QUANTUM * 2
739
- actor.tasks.should eq(['donuts', 'coffee'])
740
- end
741
- end
742
-
743
- context :receiving do
744
- before do
745
- @receiver = Class.new do
746
- include included_module
747
- task_class task_klass
748
- execute_block_on_receiver :signal_myself
749
-
750
- def signal_myself(obj, &block)
751
- current_actor.mailbox << obj
752
- receive(&block)
753
- end
754
- end
755
- end
756
-
757
- let(:receiver) { @receiver.new }
758
- let(:message) { Object.new }
759
-
760
- it "allows unconditional receive" do
761
- receiver.signal_myself(message).should eq(message)
762
- end
763
-
764
- it "allows arbitrary selective receive" do
765
- received_obj = receiver.signal_myself(message) { |o| o == message }
766
- received_obj.should eq(message)
767
- end
768
-
769
- it "times out after the given interval", :pending => ENV['CI'] do
770
- interval = 0.1
771
- started_at = Time.now
772
-
773
- receiver.receive(interval) { false }.should be_nil
774
- (Time.now - started_at).should be_within(Celluloid::TIMER_QUANTUM).of interval
775
- end
776
- end
777
-
778
- context :timers do
779
- before do
780
- @klass = Class.new do
781
- include included_module
782
- task_class task_klass
783
-
784
- def initialize
785
- @sleeping = false
786
- @fired = false
787
- end
788
-
789
- def do_sleep(n)
790
- @sleeping = true
791
- sleep n
792
- @sleeping = false
793
- end
794
-
795
- def sleeping?; @sleeping end
796
-
797
- def fire_after(n)
798
- after(n) { @fired = true }
799
- end
800
-
801
- def fire_every(n)
802
- @fired = 0
803
- every(n) { @fired += 1 }
804
- end
805
-
806
- def fired?; !!@fired end
807
- def fired; @fired end
808
- end
809
- end
810
-
811
- it "suspends execution of a method (but not the actor) for a given time" do
812
- actor = @klass.new
813
-
814
- # Sleep long enough to ensure we're actually seeing behavior when asleep
815
- # but not so long as to delay the test suite unnecessarily
816
- interval = Celluloid::TIMER_QUANTUM * 10
817
- started_at = Time.now
818
-
819
- future = actor.future(:do_sleep, interval)
820
- sleep(interval / 2) # wonky! :/
821
- actor.should be_sleeping
822
-
823
- future.value
824
- (Time.now - started_at).should be_within(Celluloid::TIMER_QUANTUM).of interval
825
- end
826
-
827
- it "schedules timers which fire in the future" do
828
- actor = @klass.new
829
-
830
- interval = Celluloid::TIMER_QUANTUM * 10
831
-
832
- actor.fire_after(interval)
833
- actor.should_not be_fired
834
-
835
- sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
836
- actor.should be_fired
837
- end
838
-
839
- it "schedules recurring timers which fire in the future" do
840
- actor = @klass.new
841
-
842
- interval = Celluloid::TIMER_QUANTUM * 10
843
-
844
- actor.fire_every(interval)
845
- actor.fired.should be_zero
846
-
847
- sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
848
- actor.fired.should be 1
849
-
850
- 2.times { sleep(interval + Celluloid::TIMER_QUANTUM) } # wonky! #/
851
- actor.fired.should be 3
852
- end
853
-
854
- it "cancels timers before they fire" do
855
- actor = @klass.new
856
-
857
- interval = Celluloid::TIMER_QUANTUM * 10
858
-
859
- timer = actor.fire_after(interval)
860
- actor.should_not be_fired
861
- timer.cancel
862
-
863
- sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
864
- actor.should_not be_fired
865
- end
866
-
867
- it "allows delays from outside the actor" do
868
- actor = @klass.new
869
-
870
- interval = Celluloid::TIMER_QUANTUM * 10
871
- fired = false
872
-
873
- actor.after(interval) do
874
- fired = true
875
- end
876
- fired.should be_false
877
-
878
- sleep(interval + Celluloid::TIMER_QUANTUM) # wonky! #/
879
- fired.should be_true
880
- end
881
- end
882
-
883
- context :tasks do
884
- before do
885
- @klass = Class.new do
886
- include included_module
887
- task_class task_klass
888
- attr_reader :blocker
889
-
890
- def initialize
891
- @blocker = Blocker.new
892
- end
893
-
894
- def blocking_call
895
- @blocker.block
896
- end
897
- end
898
-
899
- class Blocker
900
- include Celluloid
901
-
902
- def block
903
- wait :unblock
904
- end
905
-
906
- def unblock
907
- signal :unblock
908
- end
909
- end
910
- end
911
-
912
- it "knows which tasks are waiting on calls to other actors" do
913
- actor = @klass.new
914
-
915
- tasks = actor.tasks
916
- tasks.size.should be 1
917
-
918
- actor.future(:blocking_call)
919
- sleep 0.1 # hax! waiting for ^^^ call to actually start
920
-
921
- tasks = actor.tasks
922
- tasks.size.should be 2
923
-
924
- blocking_task = tasks.find { |t| t.status != :running }
925
- blocking_task.should be_a task_klass
926
- blocking_task.status.should be :callwait
927
-
928
- actor.blocker.unblock
929
- sleep 0.1 # hax again :(
930
- actor.tasks.size.should be 1
931
- end
932
- end
933
-
934
- context :mailbox_class do
935
- class ExampleMailbox < Celluloid::Mailbox; end
936
-
937
- subject do
938
- Class.new do
939
- include included_module
940
- task_class task_klass
941
- mailbox_class ExampleMailbox
942
- end
943
- end
944
-
945
- it "uses user-specified mailboxes" do
946
- subject.new.mailbox.should be_a ExampleMailbox
947
- end
948
-
949
- it "retains custom mailboxes when subclassed" do
950
- subclass = Class.new(subject)
951
- subclass.new.mailbox.should be_a ExampleMailbox
952
- end
953
- end
954
-
955
- context :mailbox_size do
956
- subject do
957
- Class.new do
958
- include included_module
959
- task_class task_klass
960
- mailbox_size 100
961
- end
962
- end
963
-
964
- it "configures the mailbox limit" do
965
- subject.new.mailbox.max_size.should == 100
966
- end
967
- end
968
-
969
- context :proxy_class do
970
- class ExampleProxy < Celluloid::CellProxy
971
- def subclass_proxy?
972
- true
973
- end
974
- end
975
-
976
- subject do
977
- Class.new do
978
- include included_module
979
- task_class task_klass
980
- proxy_class ExampleProxy
981
- end
982
- end
983
-
984
- it "uses user-specified proxy" do
985
- subject.new.should be_subclass_proxy
986
- end
987
-
988
- it "retains custom proxy when subclassed" do
989
- subclass = Class.new(subject)
990
- subclass.new.should be_subclass_proxy
991
- end
992
- end
993
-
994
- context :task_class do
995
- class ExampleTask < Celluloid::TaskFiber; end
996
-
997
- subject do
998
- Class.new do
999
- include included_module
1000
- task_class ExampleTask
1001
- end
1002
- end
1003
-
1004
- it "overrides the task class" do
1005
- subject.new.tasks.first.should be_a ExampleTask
1006
- end
1007
-
1008
- it "retains custom task classes when subclassed" do
1009
- subclass = Class.new(subject)
1010
- subclass.new.tasks.first.should be_a ExampleTask
1011
- end
1012
- end
1013
-
1014
- context :timeouts do
1015
- let :actor_class do
1016
- Class.new do
1017
- include included_module
1018
-
1019
- def name
1020
- sleep 0.5
1021
- :foo
1022
- end
1023
-
1024
- def ask_name_with_timeout(other, duration)
1025
- timeout(duration) { other.name }
1026
- end
1027
- end
1028
- end
1029
-
1030
- it "allows timing out tasks, raising Celluloid::Task::TimeoutError" do
1031
- a1 = actor_class.new
1032
- a2 = actor_class.new
1033
-
1034
- expect { a1.ask_name_with_timeout a2, 0.3 }.to raise_error(Celluloid::Task::TimeoutError)
1035
- end
1036
-
1037
- it "does not raise when it completes in time" do
1038
- a1 = actor_class.new
1039
- a2 = actor_class.new
1040
-
1041
- a1.ask_name_with_timeout(a2, 0.6).should == :foo
1042
- end
1043
- end
1044
-
1045
- context "raw message sends" do
1046
- it "logs on unhandled messages" do
1047
- Celluloid.logger.should_receive(:debug).with("Discarded message (unhandled): first")
1048
-
1049
- actor = actor_class.new "Irma Gladden"
1050
- actor.mailbox << :first
1051
- sleep Celluloid::TIMER_QUANTUM
1052
- end
1053
- end
1054
- end