concurrent-ruby 0.6.0.pre.1 → 0.6.0.pre.2
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 +16 -0
- data/lib/concurrent.rb +9 -29
- data/lib/concurrent/{actor.rb → actor/actor.rb} +3 -3
- data/lib/concurrent/actor/actor_context.rb +77 -0
- data/lib/concurrent/actor/actor_ref.rb +67 -0
- data/lib/concurrent/{postable.rb → actor/postable.rb} +1 -1
- data/lib/concurrent/actor/simple_actor_ref.rb +94 -0
- data/lib/concurrent/actors.rb +5 -0
- data/lib/concurrent/agent.rb +81 -47
- data/lib/concurrent/async.rb +35 -35
- data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +170 -0
- data/lib/concurrent/{condition.rb → atomic/condition.rb} +0 -0
- data/lib/concurrent/{copy_on_notify_observer_set.rb → atomic/copy_on_notify_observer_set.rb} +48 -13
- data/lib/concurrent/{copy_on_write_observer_set.rb → atomic/copy_on_write_observer_set.rb} +41 -20
- data/lib/concurrent/atomic/count_down_latch.rb +116 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
- data/lib/concurrent/atomic/event.rb +103 -0
- data/lib/concurrent/{thread_local_var.rb → atomic/thread_local_var.rb} +0 -0
- data/lib/concurrent/atomics.rb +9 -0
- data/lib/concurrent/channel/buffered_channel.rb +6 -4
- data/lib/concurrent/channel/channel.rb +30 -2
- data/lib/concurrent/channel/unbuffered_channel.rb +2 -2
- data/lib/concurrent/channel/waitable_list.rb +3 -1
- data/lib/concurrent/channels.rb +5 -0
- data/lib/concurrent/{channel → collection}/blocking_ring_buffer.rb +16 -5
- data/lib/concurrent/collection/priority_queue.rb +305 -0
- data/lib/concurrent/{channel → collection}/ring_buffer.rb +6 -1
- data/lib/concurrent/collections.rb +3 -0
- data/lib/concurrent/configuration.rb +68 -19
- data/lib/concurrent/dataflow.rb +9 -9
- data/lib/concurrent/delay.rb +21 -13
- data/lib/concurrent/dereferenceable.rb +40 -33
- data/lib/concurrent/exchanger.rb +3 -0
- data/lib/concurrent/{cached_thread_pool.rb → executor/cached_thread_pool.rb} +8 -9
- data/lib/concurrent/executor/executor.rb +222 -0
- data/lib/concurrent/{fixed_thread_pool.rb → executor/fixed_thread_pool.rb} +6 -7
- data/lib/concurrent/{immediate_executor.rb → executor/immediate_executor.rb} +5 -5
- data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
- data/lib/concurrent/{java_fixed_thread_pool.rb → executor/java_fixed_thread_pool.rb} +7 -11
- data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
- data/lib/concurrent/{java_thread_pool_executor.rb → executor/java_thread_pool_executor.rb} +66 -77
- data/lib/concurrent/executor/one_by_one.rb +65 -0
- data/lib/concurrent/{per_thread_executor.rb → executor/per_thread_executor.rb} +4 -4
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
- data/lib/concurrent/{ruby_fixed_thread_pool.rb → executor/ruby_fixed_thread_pool.rb} +5 -4
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +72 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +282 -0
- data/lib/concurrent/{ruby_thread_pool_worker.rb → executor/ruby_thread_pool_worker.rb} +6 -6
- data/lib/concurrent/{safe_task_executor.rb → executor/safe_task_executor.rb} +20 -13
- data/lib/concurrent/executor/single_thread_executor.rb +35 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
- data/lib/concurrent/executor/timer_set.rb +138 -0
- data/lib/concurrent/executors.rb +9 -0
- data/lib/concurrent/future.rb +39 -40
- data/lib/concurrent/ivar.rb +22 -15
- data/lib/concurrent/mvar.rb +2 -1
- data/lib/concurrent/obligation.rb +9 -3
- data/lib/concurrent/observable.rb +33 -0
- data/lib/concurrent/options_parser.rb +46 -0
- data/lib/concurrent/promise.rb +23 -24
- data/lib/concurrent/scheduled_task.rb +21 -45
- data/lib/concurrent/timer_task.rb +204 -126
- data/lib/concurrent/tvar.rb +1 -1
- data/lib/concurrent/utilities.rb +3 -36
- data/lib/concurrent/{processor_count.rb → utility/processor_count.rb} +1 -1
- data/lib/concurrent/utility/timeout.rb +36 -0
- data/lib/concurrent/utility/timer.rb +21 -0
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.bundle +0 -0
- data/spec/concurrent/{actor_context_spec.rb → actor/actor_context_spec.rb} +0 -8
- data/spec/concurrent/{actor_ref_shared.rb → actor/actor_ref_shared.rb} +9 -59
- data/spec/concurrent/{actor_spec.rb → actor/actor_spec.rb} +43 -41
- data/spec/concurrent/{postable_shared.rb → actor/postable_shared.rb} +0 -0
- data/spec/concurrent/actor/simple_actor_ref_spec.rb +135 -0
- data/spec/concurrent/agent_spec.rb +160 -71
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +172 -0
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +186 -0
- data/spec/concurrent/{condition_spec.rb → atomic/condition_spec.rb} +2 -2
- data/spec/concurrent/{copy_on_notify_observer_set_spec.rb → atomic/copy_on_notify_observer_set_spec.rb} +0 -0
- data/spec/concurrent/{copy_on_write_observer_set_spec.rb → atomic/copy_on_write_observer_set_spec.rb} +0 -0
- data/spec/concurrent/atomic/count_down_latch_spec.rb +151 -0
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +248 -0
- data/spec/concurrent/{event_spec.rb → atomic/event_spec.rb} +18 -3
- data/spec/concurrent/{observer_set_shared.rb → atomic/observer_set_shared.rb} +15 -6
- data/spec/concurrent/{thread_local_var_spec.rb → atomic/thread_local_var_spec.rb} +0 -0
- data/spec/concurrent/channel/buffered_channel_spec.rb +1 -1
- data/spec/concurrent/channel/channel_spec.rb +6 -4
- data/spec/concurrent/channel/probe_spec.rb +37 -9
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +2 -2
- data/spec/concurrent/{channel → collection}/blocking_ring_buffer_spec.rb +0 -0
- data/spec/concurrent/collection/priority_queue_spec.rb +317 -0
- data/spec/concurrent/{channel → collection}/ring_buffer_spec.rb +0 -0
- data/spec/concurrent/configuration_spec.rb +4 -70
- data/spec/concurrent/dereferenceable_shared.rb +5 -4
- data/spec/concurrent/exchanger_spec.rb +10 -5
- data/spec/concurrent/{cached_thread_pool_shared.rb → executor/cached_thread_pool_shared.rb} +15 -37
- data/spec/concurrent/{fixed_thread_pool_shared.rb → executor/fixed_thread_pool_shared.rb} +0 -0
- data/spec/concurrent/{global_thread_pool_shared.rb → executor/global_thread_pool_shared.rb} +10 -8
- data/spec/concurrent/{immediate_executor_spec.rb → executor/immediate_executor_spec.rb} +0 -0
- data/spec/concurrent/{java_cached_thread_pool_spec.rb → executor/java_cached_thread_pool_spec.rb} +1 -21
- data/spec/concurrent/{java_fixed_thread_pool_spec.rb → executor/java_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +21 -0
- data/spec/concurrent/{java_thread_pool_executor_spec.rb → executor/java_thread_pool_executor_spec.rb} +0 -0
- data/spec/concurrent/{per_thread_executor_spec.rb → executor/per_thread_executor_spec.rb} +0 -4
- data/spec/concurrent/{ruby_cached_thread_pool_spec.rb → executor/ruby_cached_thread_pool_spec.rb} +1 -1
- data/spec/concurrent/{ruby_fixed_thread_pool_spec.rb → executor/ruby_fixed_thread_pool_spec.rb} +0 -0
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +18 -0
- data/spec/concurrent/{ruby_thread_pool_executor_spec.rb → executor/ruby_thread_pool_executor_spec.rb} +12 -24
- data/spec/concurrent/executor/safe_task_executor_spec.rb +103 -0
- data/spec/concurrent/{thread_pool_class_cast_spec.rb → executor/thread_pool_class_cast_spec.rb} +12 -0
- data/spec/concurrent/{thread_pool_executor_shared.rb → executor/thread_pool_executor_shared.rb} +0 -0
- data/spec/concurrent/{thread_pool_shared.rb → executor/thread_pool_shared.rb} +84 -119
- data/spec/concurrent/executor/timer_set_spec.rb +183 -0
- data/spec/concurrent/future_spec.rb +12 -0
- data/spec/concurrent/ivar_spec.rb +11 -1
- data/spec/concurrent/observable_shared.rb +173 -0
- data/spec/concurrent/observable_spec.rb +51 -0
- data/spec/concurrent/options_parser_spec.rb +71 -0
- data/spec/concurrent/runnable_shared.rb +6 -0
- data/spec/concurrent/scheduled_task_spec.rb +60 -40
- data/spec/concurrent/timer_task_spec.rb +130 -144
- data/spec/concurrent/{processor_count_spec.rb → utility/processor_count_spec.rb} +0 -0
- data/spec/concurrent/{utilities_spec.rb → utility/timeout_spec.rb} +0 -0
- data/spec/concurrent/utility/timer_spec.rb +52 -0
- metadata +147 -108
- data/lib/concurrent/actor_context.rb +0 -31
- data/lib/concurrent/actor_ref.rb +0 -39
- data/lib/concurrent/atomic.rb +0 -121
- data/lib/concurrent/channel/probe.rb +0 -19
- data/lib/concurrent/count_down_latch.rb +0 -60
- data/lib/concurrent/event.rb +0 -80
- data/lib/concurrent/java_cached_thread_pool.rb +0 -45
- data/lib/concurrent/ruby_cached_thread_pool.rb +0 -37
- data/lib/concurrent/ruby_thread_pool_executor.rb +0 -268
- data/lib/concurrent/simple_actor_ref.rb +0 -124
- data/lib/concurrent/thread_pool_executor.rb +0 -30
- data/spec/concurrent/atomic_spec.rb +0 -201
- data/spec/concurrent/count_down_latch_spec.rb +0 -125
- data/spec/concurrent/safe_task_executor_spec.rb +0 -58
- data/spec/concurrent/simple_actor_ref_spec.rb +0 -219
@@ -1,34 +1,57 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require_relative '
|
3
|
-
require_relative '
|
2
|
+
require_relative 'dereferenceable_shared'
|
3
|
+
require_relative 'observable_shared'
|
4
4
|
|
5
5
|
module Concurrent
|
6
6
|
|
7
7
|
describe TimerTask do
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
sleep(0.1)
|
9
|
+
before(:each) do
|
10
|
+
# suppress deprecation warnings.
|
11
|
+
Concurrent::TimerTask.any_instance.stub(:warn)
|
12
|
+
Concurrent::TimerTask.stub(:warn)
|
14
13
|
end
|
15
14
|
|
16
|
-
context
|
15
|
+
context :dereferenceable do
|
17
16
|
|
18
|
-
|
17
|
+
after(:each) do
|
18
|
+
begin
|
19
|
+
@subject.kill if @subject
|
20
|
+
rescue Exception => ex
|
21
|
+
# prevent exceptions with mocks in tests
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def dereferenceable_subject(value, opts = {})
|
26
|
+
opts = opts.merge(execution_interval: 0.1, run_now: true)
|
27
|
+
@subject = TimerTask.new(opts){ value }.execute.tap{ sleep(0.1) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def dereferenceable_observable(opts = {})
|
31
|
+
opts = opts.merge(execution_interval: 0.1, run_now: true)
|
32
|
+
@subject = TimerTask.new(opts){ 'value' }
|
33
|
+
end
|
19
34
|
|
20
|
-
|
35
|
+
def execute_dereferenceable(subject)
|
36
|
+
subject.execute
|
37
|
+
sleep(0.1)
|
38
|
+
end
|
39
|
+
|
40
|
+
it_should_behave_like :dereferenceable
|
21
41
|
end
|
22
42
|
|
23
|
-
context
|
43
|
+
context :observable do
|
44
|
+
|
45
|
+
subject{ TimerTask.new(execution_interval: 0.1){ nil } }
|
46
|
+
|
47
|
+
after(:each){ subject.kill }
|
24
48
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
task
|
49
|
+
def trigger_observable(observable)
|
50
|
+
observable.execute
|
51
|
+
sleep(0.2)
|
29
52
|
end
|
30
53
|
|
31
|
-
it_should_behave_like :
|
54
|
+
it_should_behave_like :observable
|
32
55
|
end
|
33
56
|
|
34
57
|
context 'created with #new' do
|
@@ -37,188 +60,148 @@ module Concurrent
|
|
37
60
|
|
38
61
|
it 'raises an exception if no block given' do
|
39
62
|
lambda {
|
40
|
-
|
63
|
+
Concurrent::TimerTask.new
|
41
64
|
}.should raise_error(ArgumentError)
|
42
65
|
end
|
43
66
|
|
44
67
|
it 'raises an exception if :execution_interval is not greater than zero' do
|
45
68
|
lambda {
|
46
|
-
|
69
|
+
Concurrent::TimerTask.new(execution_interval: 0){ nil }
|
47
70
|
}.should raise_error(ArgumentError)
|
48
71
|
end
|
49
72
|
|
50
73
|
it 'raises an exception if :execution_interval is not an integer' do
|
51
74
|
lambda {
|
52
|
-
|
75
|
+
Concurrent::TimerTask.new(execution_interval: 'one'){ nil }
|
53
76
|
}.should raise_error(ArgumentError)
|
54
77
|
end
|
55
78
|
|
56
79
|
it 'raises an exception if :timeout_interval is not greater than zero' do
|
57
80
|
lambda {
|
58
|
-
|
81
|
+
Concurrent::TimerTask.new(timeout_interval: 0){ nil }
|
59
82
|
}.should raise_error(ArgumentError)
|
60
83
|
end
|
61
84
|
|
62
85
|
it 'raises an exception if :timeout_interval is not an integer' do
|
63
86
|
lambda {
|
64
|
-
|
87
|
+
Concurrent::TimerTask.new(timeout_interval: 'one'){ nil }
|
65
88
|
}.should raise_error(ArgumentError)
|
66
89
|
end
|
67
90
|
|
68
91
|
it 'uses the default execution interval when no interval is given' do
|
69
|
-
|
70
|
-
|
92
|
+
subject = TimerTask.new{ nil }
|
93
|
+
subject.execution_interval.should eq TimerTask::EXECUTION_INTERVAL
|
71
94
|
end
|
72
95
|
|
73
96
|
it 'uses the default timeout interval when no interval is given' do
|
74
|
-
|
75
|
-
|
97
|
+
subject = TimerTask.new{ nil }
|
98
|
+
subject.timeout_interval.should eq TimerTask::TIMEOUT_INTERVAL
|
76
99
|
end
|
77
100
|
|
78
101
|
it 'uses the given execution interval' do
|
79
|
-
|
80
|
-
|
102
|
+
subject = TimerTask.new(execution_interval: 5){ nil }
|
103
|
+
subject.execution_interval.should eq 5
|
81
104
|
end
|
82
105
|
|
83
106
|
it 'uses the given timeout interval' do
|
84
|
-
|
85
|
-
|
107
|
+
subject = TimerTask.new(timeout_interval: 5){ nil }
|
108
|
+
subject.timeout_interval.should eq 5
|
86
109
|
end
|
87
110
|
end
|
88
111
|
|
89
112
|
context '#kill' do
|
90
113
|
|
91
|
-
it 'kills its threads while sleeping' do
|
92
|
-
Thread.should_receive(:kill).at_least(:once).times.with(any_args)
|
93
|
-
task = TimerTask.new(run_now: false){ nil }
|
94
|
-
task.run!
|
95
|
-
sleep(0.1)
|
96
|
-
task.kill
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'kills its threads once executing' do
|
100
|
-
Thread.should_receive(:kill).at_least(2).times.with(any_args)
|
101
|
-
task = TimerTask.new(run_now: true){ nil }
|
102
|
-
task.run!
|
103
|
-
sleep(0.1)
|
104
|
-
task.kill
|
105
|
-
end
|
106
|
-
|
107
114
|
it 'returns true on success' do
|
108
|
-
task = TimerTask.
|
109
|
-
task.run!
|
115
|
+
task = TimerTask.execute(run_now: false){ nil }
|
110
116
|
sleep(0.1)
|
111
117
|
task.kill.should be_true
|
112
118
|
end
|
113
|
-
|
114
|
-
it 'returns false on exception' do
|
115
|
-
Thread.stub(:kill).with(any_args).and_raise(StandardError)
|
116
|
-
task = TimerTask.new(run_now: false){ nil }
|
117
|
-
task.run!
|
118
|
-
sleep(0.1)
|
119
|
-
task.kill.should be_false
|
120
|
-
end
|
121
119
|
end
|
122
120
|
end
|
123
121
|
|
124
|
-
context '
|
122
|
+
context 'arguments' do
|
125
123
|
|
126
|
-
|
124
|
+
it 'raises an exception if no block given' do
|
125
|
+
lambda {
|
126
|
+
Concurrent::TimerTask.execute
|
127
|
+
}.should raise_error
|
128
|
+
end
|
127
129
|
|
128
|
-
|
129
|
-
lambda {
|
130
|
-
@subject = Concurrent::TimerTask.run
|
131
|
-
}.should raise_error
|
132
|
-
end
|
130
|
+
specify '#execution_interval is writeable' do
|
133
131
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
sleep(0.1)
|
139
|
-
@expected.should be_true
|
132
|
+
latch = CountDownLatch.new(1)
|
133
|
+
subject = TimerTask.new(execution_interval: 1) do |task|
|
134
|
+
task.execution_interval = 3
|
135
|
+
latch.count_down
|
140
136
|
end
|
141
137
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
@subject = TimerTask.run!{ nil }
|
146
|
-
end
|
138
|
+
subject.execution_interval.should == 1
|
139
|
+
subject.execution_interval = 0.1
|
140
|
+
subject.execution_interval.should == 0.1
|
147
141
|
|
148
|
-
|
149
|
-
|
150
|
-
task.execution_interval = 3
|
151
|
-
end
|
152
|
-
@subject.execution_interval.should == 1
|
153
|
-
@subject.execution_interval = 0.1
|
154
|
-
@subject.execution_interval.should == 0.1
|
155
|
-
@thread = Thread.new { @subject.run }
|
156
|
-
sleep(0.2)
|
157
|
-
@subject.execution_interval.should == 3
|
158
|
-
end
|
142
|
+
subject.execute
|
143
|
+
latch.wait(0.2)
|
159
144
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
145
|
+
subject.execution_interval.should == 3
|
146
|
+
subject.kill
|
147
|
+
end
|
148
|
+
|
149
|
+
specify '#execution_interval is writeable' do
|
150
|
+
|
151
|
+
latch = CountDownLatch.new(1)
|
152
|
+
subject = TimerTask.new(timeout_interval: 1, execution_interval: 0.1) do |task|
|
153
|
+
task.timeout_interval = 3
|
154
|
+
latch.count_down
|
170
155
|
end
|
156
|
+
|
157
|
+
subject.timeout_interval.should == 1
|
158
|
+
subject.timeout_interval = 2
|
159
|
+
subject.timeout_interval.should == 2
|
160
|
+
|
161
|
+
subject.execute
|
162
|
+
latch.wait(0.2)
|
163
|
+
|
164
|
+
subject.timeout_interval.should == 3
|
165
|
+
subject.kill
|
171
166
|
end
|
172
167
|
end
|
173
168
|
|
174
169
|
context 'execution' do
|
175
170
|
|
176
171
|
it 'runs the block immediately when the :run_now option is true' do
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
172
|
+
latch = CountDownLatch.new(1)
|
173
|
+
subject = TimerTask.execute(execution: 500, now: true){ latch.count_down }
|
174
|
+
latch.wait(0.1).should be_true
|
175
|
+
subject.kill
|
181
176
|
end
|
182
177
|
|
183
178
|
it 'waits for :execution_interval seconds when the :run_now option is false' do
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
179
|
+
latch = CountDownLatch.new(1)
|
180
|
+
subject = TimerTask.execute(execution: 0.1, now: false){ latch.count_down }
|
181
|
+
latch.count.should eq 1
|
182
|
+
latch.wait(0.2).should be_true
|
183
|
+
subject.kill
|
189
184
|
end
|
190
185
|
|
191
186
|
it 'waits for :execution_interval seconds when the :run_now option is not given' do
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'yields to the execution block' do
|
200
|
-
@expected = false
|
201
|
-
@subject = TimerTask.run!(execution: 1){ @expected = true }
|
202
|
-
sleep(2)
|
203
|
-
@expected.should be_true
|
187
|
+
latch = CountDownLatch.new(1)
|
188
|
+
subject = TimerTask.execute(execution: 0.1, now: false){ latch.count_down }
|
189
|
+
latch.count.should eq 1
|
190
|
+
latch.wait(0.2).should be_true
|
191
|
+
subject.kill
|
204
192
|
end
|
205
193
|
|
206
194
|
it 'passes a "self" reference to the block as the sole argument' do
|
207
|
-
|
208
|
-
|
209
|
-
|
195
|
+
expected = nil
|
196
|
+
latch = CountDownLatch.new(1)
|
197
|
+
subject = TimerTask.new(execution_interval: 1, run_now: true) do |task|
|
198
|
+
expected = task
|
199
|
+
latch.sount_down
|
210
200
|
end
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
it 'kills the worker thread if the timeout is reached' do
|
217
|
-
# the after(:each) block will trigger this expectation
|
218
|
-
Thread.should_receive(:kill).at_least(1).with(any_args())
|
219
|
-
@subject = TimerTask.new(execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
|
220
|
-
@thread = Thread.new { @subject.run }
|
221
|
-
sleep(1.5)
|
201
|
+
subject.execute
|
202
|
+
latch.wait(0.2)
|
203
|
+
expected.should eq subject
|
204
|
+
subject.kill
|
222
205
|
end
|
223
206
|
end
|
224
207
|
|
@@ -229,42 +212,45 @@ module Concurrent
|
|
229
212
|
attr_reader :time
|
230
213
|
attr_reader :value
|
231
214
|
attr_reader :ex
|
215
|
+
attr_reader :latch
|
216
|
+
define_method(:initialize){ @latch = CountDownLatch.new(1) }
|
232
217
|
define_method(:update) do |time, value, ex|
|
233
218
|
@time = time
|
234
219
|
@value = value
|
235
220
|
@ex = ex
|
221
|
+
@latch.count_down
|
236
222
|
end
|
237
223
|
end.new
|
238
224
|
end
|
239
225
|
|
240
226
|
it 'notifies all observers on success' do
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
227
|
+
subject = TimerTask.new(execution: 0.1){ 42 }
|
228
|
+
subject.add_observer(observer)
|
229
|
+
subject.execute
|
230
|
+
observer.latch.wait(1)
|
245
231
|
observer.value.should == 42
|
246
232
|
observer.ex.should be_nil
|
247
|
-
|
233
|
+
subject.kill
|
248
234
|
end
|
249
235
|
|
250
236
|
it 'notifies all observers on timeout' do
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
237
|
+
subject = TimerTask.new(execution: 0.1, timeout: 0.1){ sleep }
|
238
|
+
subject.add_observer(observer)
|
239
|
+
subject.execute
|
240
|
+
observer.latch.wait(1)
|
255
241
|
observer.value.should be_nil
|
256
242
|
observer.ex.should be_a(Concurrent::TimeoutError)
|
257
|
-
|
243
|
+
subject.kill
|
258
244
|
end
|
259
245
|
|
260
246
|
it 'notifies all observers on error' do
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
247
|
+
subject = TimerTask.new(execution: 0.1){ raise ArgumentError }
|
248
|
+
subject.add_observer(observer)
|
249
|
+
subject.execute
|
250
|
+
observer.latch.wait(1)
|
265
251
|
observer.value.should be_nil
|
266
252
|
observer.ex.should be_a(ArgumentError)
|
267
|
-
|
253
|
+
subject.kill
|
268
254
|
end
|
269
255
|
end
|
270
256
|
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe '#timer' do
|
6
|
+
|
7
|
+
it 'raises an exception when no block given' do
|
8
|
+
expect {
|
9
|
+
Concurrent::timer(0.1)
|
10
|
+
}.to raise_error(ArgumentError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'raises an exception if the interval is less than 0 seconds' do
|
14
|
+
expect {
|
15
|
+
Concurrent::timer(-1){ :foo }
|
16
|
+
}.to raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'executes the block after the given number of seconds' do
|
20
|
+
start = Time.now
|
21
|
+
expected = Concurrent::AtomicFixnum.new(0)
|
22
|
+
Concurrent::timer(0.5){ expected.increment }
|
23
|
+
expected.value.should eq 0
|
24
|
+
sleep(0.1)
|
25
|
+
expected.value.should eq 0
|
26
|
+
sleep(0.8)
|
27
|
+
expected.value.should eq 1
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'suppresses exceptions thrown by the block' do
|
31
|
+
expect {
|
32
|
+
Concurrent::timer(0.5){ raise Exception }
|
33
|
+
}.to_not raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'passes all arguments to the block' do
|
37
|
+
expected = nil
|
38
|
+
latch = CountDownLatch.new(1)
|
39
|
+
Concurrent::timer(0, 1, 2, 3) do |*args|
|
40
|
+
expected = args
|
41
|
+
latch.count_down
|
42
|
+
end
|
43
|
+
latch.wait(0.2)
|
44
|
+
expected.should eq [1, 2, 3]
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'runs the task on the global timer pool' do
|
48
|
+
Concurrent.configuration.global_timer_set.should_receive(:post).with(0.1)
|
49
|
+
Concurrent::timer(0.1){ :foo }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|