concurrent-ruby 0.6.1 → 0.7.0.rc0
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/README.md +1 -1
- data/lib/concurrent.rb +3 -4
- data/lib/concurrent/atomic.rb +46 -0
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
- data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
- data/lib/concurrent/atomic_reference/jruby.rb +8 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
- data/lib/concurrent/atomic_reference/rbx.rb +16 -0
- data/lib/concurrent/atomic_reference/ruby.rb +16 -0
- data/lib/concurrent/atomics.rb +1 -1
- data/lib/concurrent/configuration.rb +1 -1
- data/lib/concurrent/supervisor.rb +1 -1
- data/lib/concurrent/timer_task.rb +0 -36
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.so +0 -0
- data/lib/extension_helper.rb +9 -0
- metadata +16 -148
- data/lib/concurrent/actor/actor.rb +0 -270
- data/lib/concurrent/actor/postable.rb +0 -102
- data/lib/concurrent/actors.rb +0 -2
- data/lib/concurrent/atomic/atomic.rb +0 -48
- data/lib/concurrent/runnable.rb +0 -90
- data/lib/concurrent/stoppable.rb +0 -20
- data/spec/concurrent/actor/actor_spec.rb +0 -376
- data/spec/concurrent/actor/postable_shared.rb +0 -218
- data/spec/concurrent/actress_spec.rb +0 -211
- data/spec/concurrent/agent_spec.rb +0 -500
- data/spec/concurrent/async_spec.rb +0 -352
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
- data/spec/concurrent/atomic/atomic_spec.rb +0 -133
- data/spec/concurrent/atomic/condition_spec.rb +0 -171
- data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
- data/spec/concurrent/atomic/event_spec.rb +0 -200
- data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
- data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
- data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
- data/spec/concurrent/channel/channel_spec.rb +0 -39
- data/spec/concurrent/channel/probe_spec.rb +0 -77
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
- data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
- data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
- data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
- data/spec/concurrent/configuration_spec.rb +0 -69
- data/spec/concurrent/dataflow_spec.rb +0 -242
- data/spec/concurrent/delay_spec.rb +0 -91
- data/spec/concurrent/dereferenceable_shared.rb +0 -146
- data/spec/concurrent/exchanger_spec.rb +0 -66
- data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
- data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
- data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
- data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
- data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
- data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
- data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
- data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
- data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
- data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
- data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
- data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
- data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
- data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
- data/spec/concurrent/executor/thread_pool_shared.rb +0 -269
- data/spec/concurrent/executor/timer_set_spec.rb +0 -183
- data/spec/concurrent/future_spec.rb +0 -329
- data/spec/concurrent/ivar_spec.rb +0 -215
- data/spec/concurrent/mvar_spec.rb +0 -380
- data/spec/concurrent/obligation_shared.rb +0 -102
- data/spec/concurrent/obligation_spec.rb +0 -282
- data/spec/concurrent/observable_shared.rb +0 -177
- data/spec/concurrent/observable_spec.rb +0 -56
- data/spec/concurrent/options_parser_spec.rb +0 -71
- data/spec/concurrent/promise_spec.rb +0 -367
- data/spec/concurrent/runnable_shared.rb +0 -68
- data/spec/concurrent/runnable_spec.rb +0 -235
- data/spec/concurrent/scheduled_task_spec.rb +0 -340
- data/spec/concurrent/stoppable_shared.rb +0 -37
- data/spec/concurrent/supervisor_spec.rb +0 -1149
- data/spec/concurrent/timer_task_spec.rb +0 -256
- data/spec/concurrent/tvar_spec.rb +0 -137
- data/spec/concurrent/utility/processor_count_spec.rb +0 -20
- data/spec/concurrent/utility/timeout_spec.rb +0 -50
- data/spec/concurrent/utility/timer_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -41
- data/spec/support/example_group_extensions.rb +0 -52
- data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
@@ -1,211 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'concurrent/actress'
|
3
|
-
|
4
|
-
module Concurrent
|
5
|
-
module Actress
|
6
|
-
i_know_it_is_experimental!
|
7
|
-
|
8
|
-
class Reference
|
9
|
-
def backdoor(&block)
|
10
|
-
core.send :schedule_execution do
|
11
|
-
core.instance_eval &block
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe 'Concurrent::Actress' do
|
17
|
-
prepend_before do
|
18
|
-
do_no_reset!
|
19
|
-
end
|
20
|
-
|
21
|
-
def terminate_actors(*actors)
|
22
|
-
actors.each do |actor|
|
23
|
-
actor.backdoor { terminate! }
|
24
|
-
actor.terminated.wait
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Ping
|
29
|
-
include Context
|
30
|
-
|
31
|
-
def initialize(queue)
|
32
|
-
@queue = queue
|
33
|
-
end
|
34
|
-
|
35
|
-
def on_message(message)
|
36
|
-
case message
|
37
|
-
when :terminate
|
38
|
-
terminate!
|
39
|
-
when :child
|
40
|
-
AdHoc.spawn(:pong, @queue) { |queue| -> m { queue << m } }
|
41
|
-
else
|
42
|
-
@queue << message
|
43
|
-
message
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# def trace!
|
49
|
-
# set_trace_func proc { |event, file, line, id, binding, classname|
|
50
|
-
# # thread = eval('Thread.current', binding).object_id.to_s(16)
|
51
|
-
# printf "%8s %20s %20s %s %s:%-2d\n", event, id, classname, nil, file, line
|
52
|
-
# }
|
53
|
-
# yield
|
54
|
-
# ensure
|
55
|
-
# set_trace_func nil
|
56
|
-
# end
|
57
|
-
|
58
|
-
describe 'stress test' do
|
59
|
-
1.times do |i|
|
60
|
-
it format('run %3d', i) do
|
61
|
-
# puts format('run %3d', i)
|
62
|
-
Array.new(10).map do
|
63
|
-
Thread.new do
|
64
|
-
10.times do
|
65
|
-
# trace! do
|
66
|
-
queue = Queue.new
|
67
|
-
actor = Ping.spawn :ping, queue
|
68
|
-
|
69
|
-
# when spawn returns children are set
|
70
|
-
Concurrent::Actress::ROOT.send(:core).instance_variable_get(:@children).should include(actor)
|
71
|
-
|
72
|
-
actor << 'a' << 1
|
73
|
-
queue.pop.should eq 'a'
|
74
|
-
actor.ask(2).value.should eq 2
|
75
|
-
|
76
|
-
actor.parent.should eq Concurrent::Actress::ROOT
|
77
|
-
Concurrent::Actress::ROOT.path.should eq '/'
|
78
|
-
actor.path.should eq '/ping'
|
79
|
-
child = actor.ask(:child).value
|
80
|
-
child.path.should eq '/ping/pong'
|
81
|
-
queue.clear
|
82
|
-
child.ask(3)
|
83
|
-
queue.pop.should eq 3
|
84
|
-
|
85
|
-
actor << :terminate
|
86
|
-
actor.ask(:blow_up).wait.should be_rejected
|
87
|
-
terminate_actors actor, child
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end.each(&:join)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
describe 'spawning' do
|
96
|
-
describe 'Actress#spawn' do
|
97
|
-
behaviour = -> v { -> _ { v } }
|
98
|
-
subjects = { spawn: -> { Actress.spawn(AdHoc, :ping, 'arg', &behaviour) },
|
99
|
-
context_spawn: -> { AdHoc.spawn(:ping, 'arg', &behaviour) },
|
100
|
-
spawn_by_hash: -> { Actress.spawn(class: AdHoc, name: :ping, args: ['arg'], &behaviour) },
|
101
|
-
context_spawn_by_hash: -> { AdHoc.spawn(name: :ping, args: ['arg'], &behaviour) } }
|
102
|
-
|
103
|
-
subjects.each do |desc, subject_definition|
|
104
|
-
describe desc do
|
105
|
-
subject &subject_definition
|
106
|
-
after { terminate_actors subject }
|
107
|
-
its(:path) { should eq '/ping' }
|
108
|
-
its(:parent) { should eq ROOT }
|
109
|
-
its(:name) { should eq 'ping' }
|
110
|
-
it('executor should be global') { subject.executor.should eq Concurrent.configuration.global_task_pool }
|
111
|
-
its(:reference) { should eq subject }
|
112
|
-
it 'returns ars' do
|
113
|
-
subject.ask!(:anything).should eq 'arg'
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'terminates on failed initialization' do
|
120
|
-
a = AdHoc.spawn(name: :fail, logger: Concurrent.configuration.no_logger) { raise }
|
121
|
-
a.ask(nil).wait.rejected?.should be_true
|
122
|
-
a.terminated?.should be_true
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'terminates on failed initialization and raises with spawn!' do
|
126
|
-
expect do
|
127
|
-
AdHoc.spawn!(name: :fail, logger: Concurrent.configuration.no_logger) { raise 'm' }
|
128
|
-
end.to raise_error(StandardError, 'm')
|
129
|
-
end
|
130
|
-
|
131
|
-
it 'terminates on failed message processing' do
|
132
|
-
a = AdHoc.spawn(name: :fail, logger: Concurrent.configuration.no_logger) { -> _ { raise } }
|
133
|
-
a.ask(nil).wait.rejected?.should be_true
|
134
|
-
a.terminated?.should be_true
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
describe 'messaging' do
|
139
|
-
subject { AdHoc.spawn(:add) { c = 0; -> v { c = c + v } } }
|
140
|
-
specify do
|
141
|
-
subject.tell(1).tell(1)
|
142
|
-
subject << 1 << 1
|
143
|
-
subject.ask(0).value!.should eq 4
|
144
|
-
end
|
145
|
-
after { terminate_actors subject }
|
146
|
-
end
|
147
|
-
|
148
|
-
describe 'children' do
|
149
|
-
let(:parent) do
|
150
|
-
AdHoc.spawn(:parent) do
|
151
|
-
-> message do
|
152
|
-
if message == :child
|
153
|
-
AdHoc.spawn(:child) { -> _ { parent } }
|
154
|
-
else
|
155
|
-
children
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
it 'has children set after a child is created' do
|
162
|
-
child = parent.ask!(:child)
|
163
|
-
parent.ask!(nil).should include(child)
|
164
|
-
child.ask!(nil).should eq parent
|
165
|
-
|
166
|
-
terminate_actors parent, child
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
describe 'envelope' do
|
171
|
-
subject { AdHoc.spawn(:subject) { -> _ { envelope } } }
|
172
|
-
specify do
|
173
|
-
envelope = subject.ask!('a')
|
174
|
-
envelope.should be_a_kind_of Envelope
|
175
|
-
envelope.message.should eq 'a'
|
176
|
-
envelope.ivar.should be_completed
|
177
|
-
envelope.ivar.value.should eq envelope
|
178
|
-
envelope.sender.should eq Thread.current
|
179
|
-
terminate_actors subject
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
describe 'termination' do
|
184
|
-
subject do
|
185
|
-
AdHoc.spawn(:parent) do
|
186
|
-
child = AdHoc.spawn(:child) { -> v { v } }
|
187
|
-
-> v do
|
188
|
-
if v == :terminate
|
189
|
-
terminate!
|
190
|
-
else
|
191
|
-
child
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
it 'terminates with all its children' do
|
198
|
-
child = subject.ask! :child
|
199
|
-
subject.terminated?.should be_false
|
200
|
-
subject.ask(:terminate).wait
|
201
|
-
subject.terminated?.should be_true
|
202
|
-
child.terminated.wait
|
203
|
-
child.terminated?.should be_true
|
204
|
-
|
205
|
-
terminate_actors subject, child
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
@@ -1,500 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require_relative 'dereferenceable_shared'
|
3
|
-
require_relative 'observable_shared'
|
4
|
-
|
5
|
-
module Concurrent
|
6
|
-
|
7
|
-
describe Agent do
|
8
|
-
|
9
|
-
let(:executor) { PerThreadExecutor.new }
|
10
|
-
|
11
|
-
subject { Agent.new(0, executor: executor) }
|
12
|
-
|
13
|
-
let(:observer) do
|
14
|
-
Class.new do
|
15
|
-
attr_reader :value
|
16
|
-
define_method(:update) do |time, value|
|
17
|
-
@value = value
|
18
|
-
end
|
19
|
-
end.new
|
20
|
-
end
|
21
|
-
|
22
|
-
context '#send_off' do
|
23
|
-
subject { Agent.new 2, executor: executor }
|
24
|
-
|
25
|
-
it 'executes post and post-off in order' do
|
26
|
-
subject.post { |v| v + 2 }
|
27
|
-
subject.post_off { |v| v * 3 }
|
28
|
-
subject.await
|
29
|
-
subject.value.should eq 12
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context 'behavior' do
|
34
|
-
|
35
|
-
# dereferenceable
|
36
|
-
|
37
|
-
def dereferenceable_subject(value, opts = {})
|
38
|
-
opts = opts.merge(executor: executor)
|
39
|
-
Agent.new(value, opts)
|
40
|
-
end
|
41
|
-
|
42
|
-
def dereferenceable_observable(opts = {})
|
43
|
-
opts = opts.merge(executor: executor)
|
44
|
-
Agent.new(0, opts)
|
45
|
-
end
|
46
|
-
|
47
|
-
def execute_dereferenceable(subject)
|
48
|
-
subject.post { |value| 10 }
|
49
|
-
sleep(0.1)
|
50
|
-
end
|
51
|
-
|
52
|
-
it_should_behave_like :dereferenceable
|
53
|
-
|
54
|
-
# observable
|
55
|
-
|
56
|
-
subject { Agent.new(0) }
|
57
|
-
|
58
|
-
def trigger_observable(observable)
|
59
|
-
observable.post { nil }
|
60
|
-
sleep(0.1)
|
61
|
-
end
|
62
|
-
|
63
|
-
it_should_behave_like :observable
|
64
|
-
end
|
65
|
-
|
66
|
-
context '#initialize' do
|
67
|
-
|
68
|
-
let(:executor) { ImmediateExecutor.new }
|
69
|
-
|
70
|
-
it 'sets the value to the given initial state' do
|
71
|
-
Agent.new(10).value.should eq 10
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'sets the timeout to the given value' do
|
75
|
-
Agent.new(0, timeout: 5).timeout.should eq 5
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'sets the timeout to the default when nil' do
|
79
|
-
Agent.new(0).timeout.should eq Agent::TIMEOUT
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'uses the executor given with the :executor option' do
|
83
|
-
executor.should_receive(:post).with(any_args).and_return(0)
|
84
|
-
agent = Agent.new(0, executor: executor)
|
85
|
-
agent.post { |value| 0 }
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'uses the global operation pool when :operation is true' do
|
89
|
-
Concurrent.configuration.should_receive(:global_operation_pool).and_return(executor)
|
90
|
-
agent = Agent.new(0, operation: true)
|
91
|
-
agent.post { |value| 0 }
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'uses the global task pool when :task is true' do
|
95
|
-
Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
|
96
|
-
agent = Agent.new(0, task: true)
|
97
|
-
agent.post { |value| 0 }
|
98
|
-
end
|
99
|
-
|
100
|
-
it 'uses the global task pool by default' do
|
101
|
-
Concurrent.configuration.should_receive(:global_task_pool).and_return(executor)
|
102
|
-
agent = Agent.new(0)
|
103
|
-
agent.post { |value| 0 }
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
context '#rescue' do
|
108
|
-
|
109
|
-
it 'returns self when a block is given' do
|
110
|
-
a1 = subject
|
111
|
-
a2 = a1.rescue {}
|
112
|
-
|
113
|
-
a2.should be a1
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'returns self when no block is given' do
|
117
|
-
a1 = subject
|
118
|
-
a2 = a1.rescue
|
119
|
-
|
120
|
-
a2.should be a1
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'accepts an exception class as the first parameter' do
|
124
|
-
lambda {
|
125
|
-
subject.rescue(StandardError) {}
|
126
|
-
}.should_not raise_error
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'ignores rescuers without a block' do
|
130
|
-
subject.rescue
|
131
|
-
subject.instance_variable_get(:@rescuers).should be_empty
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
context '#validate' do
|
136
|
-
|
137
|
-
it 'returns self when a block is given' do
|
138
|
-
a1 = subject
|
139
|
-
a2 = a1.validate {}
|
140
|
-
|
141
|
-
a2.should be a1
|
142
|
-
end
|
143
|
-
|
144
|
-
it 'returns self when no block is given' do
|
145
|
-
a1 = subject
|
146
|
-
a2 = a1.validate
|
147
|
-
|
148
|
-
a2.should be a1
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'ignores validators without a block' do
|
152
|
-
default_validator = subject.instance_variable_get(:@validator)
|
153
|
-
subject.validate
|
154
|
-
subject.instance_variable_get(:@validator).should be default_validator
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
context '#post' do
|
159
|
-
|
160
|
-
it 'adds the given block to the queue' do
|
161
|
-
executor.should_receive(:post).with(no_args).exactly(1).times
|
162
|
-
subject.post { sleep(1) }
|
163
|
-
subject.post { nil }
|
164
|
-
subject.post { nil }
|
165
|
-
sleep(0.1)
|
166
|
-
subject.
|
167
|
-
instance_variable_get(:@serialized_execution).
|
168
|
-
instance_variable_get(:@stash).
|
169
|
-
size.should eq 2
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'does not add to the queue when no block is given' do
|
173
|
-
executor.should_receive(:post).with(no_args).exactly(0).times
|
174
|
-
subject.post
|
175
|
-
sleep(0.1)
|
176
|
-
end
|
177
|
-
|
178
|
-
it 'works with ImmediateExecutor' do
|
179
|
-
agent = Agent.new(0, executor: ImmediateExecutor.new)
|
180
|
-
agent.post { |old| old + 1 }
|
181
|
-
agent.post { |old| old + 1 }
|
182
|
-
agent.value.should eq 2
|
183
|
-
end
|
184
|
-
|
185
|
-
end
|
186
|
-
|
187
|
-
context '#await' do
|
188
|
-
|
189
|
-
it 'waits until already sent updates are done' do
|
190
|
-
fn = false
|
191
|
-
subject.post { fn = true; sleep 0.1 }
|
192
|
-
subject.await
|
193
|
-
fn.should be_true
|
194
|
-
end
|
195
|
-
|
196
|
-
it 'does not waits until updates sent after are done' do
|
197
|
-
fn = false
|
198
|
-
subject.await
|
199
|
-
subject.post { fn = true; sleep 0.1 }
|
200
|
-
fn.should be_false
|
201
|
-
end
|
202
|
-
|
203
|
-
it 'does not alter the value' do
|
204
|
-
subject.post { |v| v + 1 }
|
205
|
-
subject.await
|
206
|
-
subject.value.should eq 1
|
207
|
-
end
|
208
|
-
|
209
|
-
end
|
210
|
-
|
211
|
-
context 'fulfillment' do
|
212
|
-
|
213
|
-
it 'process each block in the queue' do
|
214
|
-
@expected = []
|
215
|
-
subject.post { @expected << 1 }
|
216
|
-
subject.post { @expected << 2 }
|
217
|
-
subject.post { @expected << 3 }
|
218
|
-
sleep(0.1)
|
219
|
-
@expected.sort.should eq [1, 2, 3]
|
220
|
-
end
|
221
|
-
|
222
|
-
it 'passes the current value to the handler' do
|
223
|
-
@expected = nil
|
224
|
-
Agent.new(10, executor: executor).post { |i| @expected = i }
|
225
|
-
sleep(0.1)
|
226
|
-
@expected.should eq 10
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'sets the value to the handler return value on success' do
|
230
|
-
subject.post { 100 }
|
231
|
-
sleep(0.1)
|
232
|
-
subject.value.should eq 100
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'rejects the handler after timeout reached' do
|
236
|
-
agent = Agent.new(0, timeout: 0.1, executor: executor)
|
237
|
-
agent.post { sleep(1); 10 }
|
238
|
-
agent.value.should eq 0
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
context 'validation' do
|
243
|
-
|
244
|
-
it 'processes the validator when present' do
|
245
|
-
@expected = nil
|
246
|
-
subject.validate { @expected = 10; true }
|
247
|
-
subject.post { nil }
|
248
|
-
sleep(0.1)
|
249
|
-
@expected.should eq 10
|
250
|
-
end
|
251
|
-
|
252
|
-
it 'passes the new value to the validator' do
|
253
|
-
@expected = nil
|
254
|
-
subject.validate { |v| @expected = v; true }
|
255
|
-
subject.post { 10 }
|
256
|
-
sleep(0.1)
|
257
|
-
@expected.should eq 10
|
258
|
-
end
|
259
|
-
|
260
|
-
it 'sets the new value when the validator returns true' do
|
261
|
-
agent = Agent.new(0, executor: executor).validate { true }
|
262
|
-
agent.post { 10 }
|
263
|
-
sleep(0.1)
|
264
|
-
agent.value.should eq 10
|
265
|
-
end
|
266
|
-
|
267
|
-
it 'does not change the value when the validator returns false' do
|
268
|
-
agent = Agent.new(0, executor: executor).validate { false }
|
269
|
-
agent.post { 10 }
|
270
|
-
sleep(0.1)
|
271
|
-
agent.value.should eq 0
|
272
|
-
end
|
273
|
-
|
274
|
-
it 'does not change the value when the validator raises an exception' do
|
275
|
-
agent = Agent.new(0, executor: executor).validate { raise StandardError }
|
276
|
-
agent.post { 10 }
|
277
|
-
sleep(0.1)
|
278
|
-
agent.value.should eq 0
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
context 'rejection' do
|
283
|
-
|
284
|
-
it 'calls the first exception block with a matching class' do
|
285
|
-
@expected = nil
|
286
|
-
subject.
|
287
|
-
rescue(StandardError) { |ex| @expected = 1 }.
|
288
|
-
rescue(StandardError) { |ex| @expected = 2 }.
|
289
|
-
rescue(StandardError) { |ex| @expected = 3 }
|
290
|
-
subject.post { raise StandardError }
|
291
|
-
sleep(0.1)
|
292
|
-
@expected.should eq 1
|
293
|
-
end
|
294
|
-
|
295
|
-
it 'matches all with a rescue with no class given' do
|
296
|
-
@expected = nil
|
297
|
-
subject.
|
298
|
-
rescue(LoadError) { |ex| @expected = 1 }.
|
299
|
-
rescue { |ex| @expected = 2 }.
|
300
|
-
rescue(StandardError) { |ex| @expected = 3 }
|
301
|
-
subject.post { raise NoMethodError }
|
302
|
-
sleep(0.1)
|
303
|
-
@expected.should eq 2
|
304
|
-
end
|
305
|
-
|
306
|
-
it 'searches associated rescue handlers in order' do
|
307
|
-
@expected = nil
|
308
|
-
subject.
|
309
|
-
rescue(ArgumentError) { |ex| @expected = 1 }.
|
310
|
-
rescue(LoadError) { |ex| @expected = 2 }.
|
311
|
-
rescue(StandardError) { |ex| @expected = 3 }
|
312
|
-
subject.post { raise ArgumentError }
|
313
|
-
sleep(0.1)
|
314
|
-
@expected.should eq 1
|
315
|
-
|
316
|
-
@expected = nil
|
317
|
-
subject.
|
318
|
-
rescue(ArgumentError) { |ex| @expected = 1 }.
|
319
|
-
rescue(LoadError) { |ex| @expected = 2 }.
|
320
|
-
rescue(StandardError) { |ex| @expected = 3 }
|
321
|
-
subject.post { raise LoadError }
|
322
|
-
sleep(0.1)
|
323
|
-
@expected.should eq 2
|
324
|
-
|
325
|
-
@expected = nil
|
326
|
-
subject.
|
327
|
-
rescue(ArgumentError) { |ex| @expected = 1 }.
|
328
|
-
rescue(LoadError) { |ex| @expected = 2 }.
|
329
|
-
rescue(StandardError) { |ex| @expected = 3 }
|
330
|
-
subject.post { raise StandardError }
|
331
|
-
sleep(0.1)
|
332
|
-
@expected.should eq 3
|
333
|
-
end
|
334
|
-
|
335
|
-
it 'passes the exception object to the matched block' do
|
336
|
-
@expected = nil
|
337
|
-
subject.
|
338
|
-
rescue(ArgumentError) { |ex| @expected = ex }.
|
339
|
-
rescue(LoadError) { |ex| @expected = ex }.
|
340
|
-
rescue(StandardError) { |ex| @expected = ex }
|
341
|
-
subject.post { raise StandardError }
|
342
|
-
sleep(0.1)
|
343
|
-
@expected.should be_a(StandardError)
|
344
|
-
end
|
345
|
-
|
346
|
-
it 'ignores rescuers without a block' do
|
347
|
-
@expected = nil
|
348
|
-
subject.
|
349
|
-
rescue(StandardError).
|
350
|
-
rescue(StandardError) { |ex| @expected = ex }
|
351
|
-
subject.post { raise StandardError }
|
352
|
-
sleep(0.1)
|
353
|
-
@expected.should be_a(StandardError)
|
354
|
-
end
|
355
|
-
|
356
|
-
it 'supresses the exception if no rescue matches' do
|
357
|
-
lambda {
|
358
|
-
subject.
|
359
|
-
rescue(ArgumentError) { |ex| @expected = ex }.
|
360
|
-
rescue(NotImplementedError) { |ex| @expected = ex }.
|
361
|
-
rescue(NoMethodError) { |ex| @expected = ex }
|
362
|
-
subject.post { raise StandardError }
|
363
|
-
sleep(0.1)
|
364
|
-
}.should_not raise_error
|
365
|
-
end
|
366
|
-
|
367
|
-
it 'suppresses exceptions thrown from rescue handlers' do
|
368
|
-
lambda {
|
369
|
-
subject.rescue(StandardError) { raise StandardError }
|
370
|
-
subject.post { raise ArgumentError }
|
371
|
-
sleep(0.1)
|
372
|
-
}.should_not raise_error
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
context 'observation' do
|
377
|
-
|
378
|
-
it 'notifies all observers when the value changes' do
|
379
|
-
agent = Agent.new(0, executor: executor)
|
380
|
-
agent.add_observer(observer)
|
381
|
-
agent.post { 10 }
|
382
|
-
sleep(0.1)
|
383
|
-
observer.value.should eq 10
|
384
|
-
end
|
385
|
-
|
386
|
-
it 'does not notify removed observers when the value changes' do
|
387
|
-
agent = Agent.new(0, executor: executor)
|
388
|
-
agent.add_observer(observer)
|
389
|
-
agent.delete_observer(observer)
|
390
|
-
agent.post { 10 }
|
391
|
-
sleep(0.1)
|
392
|
-
observer.value.should be_nil
|
393
|
-
end
|
394
|
-
|
395
|
-
it 'does not notify observers when validation fails' do
|
396
|
-
agent = Agent.new(0, executor: executor)
|
397
|
-
agent.validate { false }
|
398
|
-
agent.add_observer(observer)
|
399
|
-
agent.post { 10 }
|
400
|
-
sleep(0.1)
|
401
|
-
observer.value.should be_nil
|
402
|
-
end
|
403
|
-
|
404
|
-
it 'does not notify observers when the handler raises an exception' do
|
405
|
-
agent = Agent.new(0, executor: executor)
|
406
|
-
agent.add_observer(observer)
|
407
|
-
agent.post { raise StandardError }
|
408
|
-
sleep(0.1)
|
409
|
-
observer.value.should be_nil
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
context 'clojure-like behaviour' do
|
414
|
-
it 'does not block dereferencing when updating the value' do
|
415
|
-
continue = IVar.new
|
416
|
-
agent = Agent.new(0, executor: executor)
|
417
|
-
agent.post { |old| old + continue.value }
|
418
|
-
sleep 0.1
|
419
|
-
Concurrent.timeout(0.2) { agent.value.should eq 0 }
|
420
|
-
continue.set 1
|
421
|
-
sleep 0.1
|
422
|
-
end
|
423
|
-
|
424
|
-
it 'does not allow to execute two updates at the same time' do
|
425
|
-
agent = Agent.new(0, executor: executor)
|
426
|
-
continue1 = IVar.new
|
427
|
-
continue2 = IVar.new
|
428
|
-
f1 = f2 = false
|
429
|
-
agent.post { |old| f1 = true; old + continue1.value }
|
430
|
-
agent.post { |old| f2 = true; old + continue2.value }
|
431
|
-
|
432
|
-
sleep 0.1
|
433
|
-
f1.should eq true
|
434
|
-
f2.should eq false
|
435
|
-
agent.value.should eq 0
|
436
|
-
|
437
|
-
continue1.set 1
|
438
|
-
sleep 0.1
|
439
|
-
f1.should eq true
|
440
|
-
f2.should eq true
|
441
|
-
agent.value.should eq 1
|
442
|
-
|
443
|
-
continue2.set 1
|
444
|
-
sleep 0.1
|
445
|
-
f1.should eq true
|
446
|
-
f2.should eq true
|
447
|
-
agent.value.should eq 2
|
448
|
-
end
|
449
|
-
|
450
|
-
it 'waits with sending functions to other agents until update is done'
|
451
|
-
end
|
452
|
-
|
453
|
-
context 'aliases' do
|
454
|
-
|
455
|
-
it 'aliases #deref for #value' do
|
456
|
-
Agent.new(10, executor: executor).deref.should eq 10
|
457
|
-
end
|
458
|
-
|
459
|
-
it 'aliases #validates for :validate' do
|
460
|
-
@expected = nil
|
461
|
-
subject.validates { |v| @expected = v }
|
462
|
-
subject.post { 10 }
|
463
|
-
sleep(0.1)
|
464
|
-
@expected.should eq 10
|
465
|
-
end
|
466
|
-
|
467
|
-
it 'aliases #validate_with for :validate' do
|
468
|
-
@expected = nil
|
469
|
-
subject.validate_with { |v| @expected = v }
|
470
|
-
subject.post { 10 }
|
471
|
-
sleep(0.1)
|
472
|
-
@expected.should eq 10
|
473
|
-
end
|
474
|
-
|
475
|
-
it 'aliases #validates_with for :validate' do
|
476
|
-
@expected = nil
|
477
|
-
subject.validates_with { |v| @expected = v }
|
478
|
-
subject.post { 10 }
|
479
|
-
sleep(0.1)
|
480
|
-
@expected.should eq 10
|
481
|
-
end
|
482
|
-
|
483
|
-
it 'aliases #catch for #rescue' do
|
484
|
-
@expected = nil
|
485
|
-
subject.catch { @expected = true }
|
486
|
-
subject.post { raise StandardError }
|
487
|
-
sleep(0.1)
|
488
|
-
@expected.should be_true
|
489
|
-
end
|
490
|
-
|
491
|
-
it 'aliases #on_error for #rescue' do
|
492
|
-
@expected = nil
|
493
|
-
subject.on_error { @expected = true }
|
494
|
-
subject.post { raise StandardError }
|
495
|
-
sleep(0.1)
|
496
|
-
@expected.should be_true
|
497
|
-
end
|
498
|
-
end
|
499
|
-
end
|
500
|
-
end
|