Skip to content

Commit b021a94

Browse files
committed
Add Actress specs
1 parent 8217cb4 commit b021a94

22 files changed

+250
-157
lines changed

lib/concurrent/actress/reference.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
module Concurrent
22
module Actress
33

4-
# Reference serves as public interface to send messages to Actors and can freely passed around
4+
# Reference is public interface of Actor instances. It is used for sending messages and can
5+
# be freely passed around the program. It also provides some basic information about the actor
6+
# see {CoreDelegations}
57
class Reference
68
include TypeCheck
79
include CoreDelegations

lib/concurrent/executor/executor.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
module Concurrent
55

66
module Executor
7+
end
8+
9+
module RubyExecutor
10+
include Executor
711

812
# Submit a task to the executor for asynchronous processing.
913
#
@@ -120,6 +124,7 @@ def kill_execution
120124
if RUBY_PLATFORM == 'java'
121125

122126
module JavaExecutor
127+
include Executor
123128

124129
# Submit a task to the executor for asynchronous processing.
125130
#

lib/concurrent/executor/immediate_executor.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Concurrent
22
class ImmediateExecutor
3+
include Executor
34

45
def post(*args, &task)
56
raise ArgumentError.new('no block given') unless block_given?

lib/concurrent/executor/ruby_single_thread_executor.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module Concurrent
44

55
# @!macro single_thread_executor
66
class RubySingleThreadExecutor
7-
include Executor
7+
include RubyExecutor
88

99
# Create a new thread pool.
1010
#

lib/concurrent/executor/ruby_thread_pool_executor.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Concurrent
88

99
# @!macro thread_pool_executor
1010
class RubyThreadPoolExecutor
11-
include Executor
11+
include RubyExecutor
1212

1313
# Default maximum number of threads that will be created in the pool.
1414
DEFAULT_MAX_POOL_SIZE = 2**15 # 32768

lib/concurrent/executor/timer_set.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module Concurrent
1111
# monitors the set and schedules each task for execution at the appropriate
1212
# time. Tasks are run on the global task pool or on the supplied executor.
1313
class TimerSet
14-
include Executor
14+
include RubyExecutor
1515

1616
# Create a new set of timed tasks.
1717
#

lib/concurrent/timer_task.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ module Concurrent
146146
# @see http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
147147
class TimerTask
148148
include Dereferenceable
149-
include Executor
149+
include RubyExecutor
150150
include Concurrent::Observable
151151

152152
# Default `:execution_interval` in seconds.

spec/concurrent/actress_spec.rb

Lines changed: 147 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,163 @@
11
require 'spec_helper'
22
require 'concurrent/actress'
33

4-
EXECUTOR = Concurrent::ThreadPoolExecutor.new(
5-
min_threads: [2, Concurrent.processor_count].max,
6-
max_threads: [20, Concurrent.processor_count * 15].max,
7-
idletime: 2 * 60, # 2 minutes
8-
max_queue: 0, # unlimited
9-
overflow_policy: :abort # raise an exception
10-
)
4+
module Concurrent
5+
module Actress
6+
describe 'Concurrent::Actress' do
117

12-
describe Concurrent::Actress do
8+
class Ping
9+
include Context
1310

14-
class Ping
15-
include Concurrent::Actress::Context
11+
def initialize(queue)
12+
@queue = queue
13+
end
1614

17-
def initialize(queue)
18-
@queue = queue
19-
end
15+
def on_message(message)
16+
case message
17+
when :terminate
18+
terminate!
19+
when :child
20+
AdHoc.spawn(:pong, @queue) { |queue| -> m { queue << m } }
21+
else
22+
@queue << message
23+
message
24+
end
25+
end
26+
end
2027

21-
def on_message(message)
22-
case message
23-
when :terminate
24-
terminate!
25-
when :child
26-
Concurrent::Actress::AdHoc.spawn(name: :pong, executor: EXECUTOR) { -> m { @queue << m } }
27-
else
28-
@queue << message
29-
message
28+
# def trace!
29+
# set_trace_func proc { |event, file, line, id, binding, classname|
30+
# # thread = eval('Thread.current', binding).object_id.to_s(16)
31+
# printf "%8s %20s %20s %s %s:%-2d\n", event, id, classname, nil, file, line
32+
# }
33+
# yield
34+
# ensure
35+
# set_trace_func nil
36+
# end
37+
38+
def assert condition
39+
unless condition
40+
# require 'pry'
41+
# binding.pry
42+
raise
43+
puts "--- \n#{caller.join("\n")}"
44+
end
3045
end
31-
end
32-
end
3346

34-
# def trace!
35-
# set_trace_func proc { |event, file, line, id, binding, classname|
36-
# # thread = eval('Thread.current', binding).object_id.to_s(16)
37-
# printf "%8s %20s %20s %s %s:%-2d\n", event, id, classname, nil, file, line
38-
# }
39-
# yield
40-
# ensure
41-
# set_trace_func nil
42-
# end
43-
44-
def assert condition
45-
unless condition
46-
# require 'pry'
47-
# binding.pry
48-
raise
49-
puts "--- \n#{caller.join("\n")}"
50-
end
51-
end
47+
describe 'stress test' do
48+
1.times do |i|
49+
it format('run %3d', i) do
50+
# puts format('run %3d', i)
51+
Array.new(10).map do
52+
Thread.new do
53+
10.times do
54+
# trace! do
55+
queue = Queue.new
56+
actor = Ping.spawn :ping, queue
57+
58+
# when spawn returns children are set
59+
assert Concurrent::Actress::ROOT.send(:core).instance_variable_get(:@children).include?(actor)
60+
61+
actor << 'a' << 1
62+
assert queue.pop == 'a'
63+
assert actor.ask(2).value == 2
5264

65+
assert actor.parent == Concurrent::Actress::ROOT
66+
assert Concurrent::Actress::ROOT.path == '/'
67+
assert actor.path == '/ping'
68+
child = actor.ask(:child).value
69+
assert child.path == '/ping/pong'
70+
queue.clear
71+
child.ask(3)
72+
assert queue.pop == 3
5373

54-
# FIXME increasing this does not work in Rspec environment
55-
1.times do |i|
56-
it format('run %3d', i) do
57-
# puts format('run %3d', i)
58-
Array.new(10).map do
59-
Thread.new do
60-
10.times do
61-
# trace! do
62-
queue = Queue.new
63-
actor = Ping.spawn name: :ping, executor: EXECUTOR, args: [queue]
64-
65-
# when spawn returns children are set
66-
assert Concurrent::Actress::ROOT.send(:core).instance_variable_get(:@children).include?(actor)
67-
68-
actor << 'a' << 1
69-
assert queue.pop == 'a'
70-
assert actor.ask(2).value == 2
71-
72-
assert actor.parent == Concurrent::Actress::ROOT
73-
assert Concurrent::Actress::ROOT.path == '/'
74-
assert actor.path == '/ping'
75-
child = actor.ask(:child).value
76-
assert child.path == '/ping/pong'
77-
queue.clear
78-
child.ask(3)
79-
assert queue.pop == 3
80-
81-
actor << :terminate
82-
assert actor.ask(:blow_up).wait.rejected?
74+
actor << :terminate
75+
assert actor.ask(:blow_up).wait.rejected?
76+
end
77+
end
78+
end.each(&:join)
8379
end
8480
end
85-
end.each(&:join)
81+
end
82+
83+
describe 'spawning' do
84+
describe 'Actress#spawn' do
85+
behaviour = -> v { -> _ { v } }
86+
subjects = { spawn: -> { Actress.spawn(AdHoc, :ping, 'arg', &behaviour) },
87+
context_spawn: -> { AdHoc.spawn(:ping, 'arg', &behaviour) },
88+
spawn_by_hash: -> { Actress.spawn(class: AdHoc, name: :ping, args: ['arg'], &behaviour) },
89+
context_spawn_by_hash: -> { AdHoc.spawn(name: :ping, args: ['arg'], &behaviour) } }
90+
91+
subjects.each do |desc, subject_definition|
92+
describe desc do
93+
subject &subject_definition
94+
its(:path) { should eq '/ping' }
95+
its(:parent) { should eq ROOT }
96+
its(:name) { should eq 'ping' }
97+
its(:executor) { should eq Concurrent.configuration.global_task_pool }
98+
its(:reference) { should eq subject }
99+
it 'returns ars' do
100+
subject.ask!(:anything).should eq 'arg'
101+
end
102+
end
103+
end
104+
end
105+
106+
it 'terminates on failed initialization' do
107+
a = AdHoc.spawn(name: :fail, logger_level: 4) { raise }
108+
a.ask(nil).wait.rejected?.should be_true
109+
a.terminated?.should be_true
110+
end
111+
112+
it 'terminates on failed message processing' do
113+
a = AdHoc.spawn(name: :fail, logger_level: 4) { -> _ { raise } }
114+
a.ask(nil).wait.rejected?.should be_true
115+
a.terminated?.should be_true
116+
end
117+
end
118+
119+
describe 'messaging' do
120+
subject { AdHoc.spawn(:add) { c = 0; -> v { c = c + v } } }
121+
specify do
122+
subject.tell(1).tell(1)
123+
subject << 1 << 1
124+
subject.ask(0).value!.should eq 4
125+
end
126+
end
127+
128+
describe 'children' do
129+
let(:parent) do
130+
AdHoc.spawn(:parent) do
131+
-> message do
132+
if message == :child
133+
AdHoc.spawn(:child) { -> _ { parent } }
134+
else
135+
children
136+
end
137+
end
138+
end
139+
end
140+
141+
it 'has children set after a child is created' do
142+
child = parent.ask!(:child)
143+
parent.ask!(nil).should include(child)
144+
child.ask!(nil).should eq parent
145+
end
146+
end
147+
148+
describe 'envelope' do
149+
subject { AdHoc.spawn(:subject) { -> _ { envelope } } }
150+
specify do
151+
envelope = subject.ask!('a')
152+
envelope.should be_a_kind_of Envelope
153+
envelope.message.should eq 'a'
154+
envelope.ivar.should be_completed
155+
envelope.ivar.value.should eq envelope
156+
envelope.sender.should eq Thread.current
157+
end
158+
end
86159
end
160+
87161
end
88162
end
163+

spec/concurrent/atomic/atomic_boolean_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ module Concurrent
151151
end
152152
end
153153

154-
if jruby?
154+
if TestHelpers.jruby?
155155

156156
describe JavaAtomicBoolean do
157157
it_should_behave_like :atomic_boolean

spec/concurrent/atomic/atomic_fixnum_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ module Concurrent
165165
end
166166
end
167167

168-
if jruby?
168+
if TestHelpers.jruby?
169169

170170
describe JavaAtomicFixnum do
171171
it_should_behave_like :atomic_fixnum

0 commit comments

Comments
 (0)