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,68 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
share_examples_for :runnable do
|
4
|
-
|
5
|
-
after(:each) do
|
6
|
-
subject.stop
|
7
|
-
@thread.kill unless @thread.nil?
|
8
|
-
sleep(0.1)
|
9
|
-
end
|
10
|
-
|
11
|
-
context '#run' do
|
12
|
-
|
13
|
-
it 'starts the (blocking) runner on the current thread when stopped' do
|
14
|
-
@thread = Thread.new { subject.run }
|
15
|
-
@thread.join(0.1).should be_nil
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'raises an exception when already running' do
|
19
|
-
@thread = Thread.new { subject.run }
|
20
|
-
@thread.join(0.1)
|
21
|
-
expect {
|
22
|
-
subject.run
|
23
|
-
}.to raise_error
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'returns true when stopped normally' do
|
27
|
-
@expected = false
|
28
|
-
@thread = Thread.new { @expected = subject.run }
|
29
|
-
@thread.join(0.1)
|
30
|
-
subject.stop
|
31
|
-
@thread.join(1)
|
32
|
-
@expected.should be_true
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context '#stop' do
|
37
|
-
|
38
|
-
it 'returns true when not running' do
|
39
|
-
subject.stop.should be_true
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'returns true when successfully stopped' do
|
43
|
-
@thread = Thread.new { subject.run }
|
44
|
-
@thread.join(0.1)
|
45
|
-
subject.stop.should be_true
|
46
|
-
subject.should_not be_running
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context '#running?' do
|
51
|
-
|
52
|
-
it 'returns true when running' do
|
53
|
-
@thread = Thread.new { subject.run }
|
54
|
-
@thread.join(0.1)
|
55
|
-
subject.should be_running
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'returns false when first created' do
|
59
|
-
subject.should_not be_running
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'returns false when not running' do
|
63
|
-
subject.stop
|
64
|
-
sleep(0.1)
|
65
|
-
subject.should_not be_running
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,235 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require_relative 'runnable_shared'
|
3
|
-
|
4
|
-
module Concurrent
|
5
|
-
|
6
|
-
describe Runnable do
|
7
|
-
|
8
|
-
let(:runnable) do
|
9
|
-
Class.new {
|
10
|
-
include Runnable
|
11
|
-
attr_reader :thread
|
12
|
-
def initialize(*args, &block)
|
13
|
-
yield if block_given?
|
14
|
-
end
|
15
|
-
def on_task
|
16
|
-
@thread = Thread.current
|
17
|
-
sleep(0.1)
|
18
|
-
end
|
19
|
-
def on_run() return true; end
|
20
|
-
def after_run() return true; end
|
21
|
-
def on_stop() return true; end
|
22
|
-
}
|
23
|
-
end
|
24
|
-
|
25
|
-
subject { runnable.new }
|
26
|
-
|
27
|
-
it_should_behave_like :runnable
|
28
|
-
|
29
|
-
after(:each) do
|
30
|
-
subject.stop
|
31
|
-
@thread.kill unless @thread.nil?
|
32
|
-
sleep(0.1)
|
33
|
-
end
|
34
|
-
|
35
|
-
context '#run' do
|
36
|
-
|
37
|
-
it 'calls #on_run when implemented' do
|
38
|
-
subject.should_receive(:on_run).with(no_args())
|
39
|
-
@thread = Thread.new { subject.run }
|
40
|
-
sleep(0.1)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'does not attempt to call #on_run when not implemented' do
|
44
|
-
subject.class.send(:remove_method, :on_run)
|
45
|
-
@thread = Thread.new do
|
46
|
-
expect {
|
47
|
-
subject.run
|
48
|
-
}.not_to raise_error
|
49
|
-
end
|
50
|
-
sleep(0.1)
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'return false when #on_run raises an exception' do
|
54
|
-
@expected = true
|
55
|
-
subject.stub(:on_run).and_raise(StandardError)
|
56
|
-
@thread = Thread.new do
|
57
|
-
@expected = subject.run
|
58
|
-
end
|
59
|
-
sleep(0.1)
|
60
|
-
@expected.should be_false
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'calls #on_task in an infinite loop' do
|
64
|
-
subject.should_receive(:on_task).with(no_args()).at_least(1)
|
65
|
-
@thread = Thread.new { subject.run }
|
66
|
-
@thread.join(1)
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'raises an exception if the #on_task callback is not implemented' do
|
70
|
-
runner = Class.new { include Runnable }.new
|
71
|
-
expect {
|
72
|
-
runner.run
|
73
|
-
}.to raise_error(Concurrent::LifecycleError)
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'returns false when the task loop raises an exception' do
|
77
|
-
@expected = false
|
78
|
-
subject.stub(:on_task).and_raise(StandardError)
|
79
|
-
@thread = Thread.new { @expected = subject.run }
|
80
|
-
@thread.join(0.1)
|
81
|
-
@expected.should be_false
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
context '#stop' do
|
86
|
-
|
87
|
-
it 'calls #on_stop when implemented' do
|
88
|
-
subject.should_receive(:on_stop).with(no_args())
|
89
|
-
@thread = Thread.new { subject.run }
|
90
|
-
sleep(0.1)
|
91
|
-
subject.stop
|
92
|
-
sleep(0.1)
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'does not attempt to call #on_stop when not implemented' do
|
96
|
-
subject.class.send(:remove_method, :on_stop)
|
97
|
-
@thread = Thread.new { subject.run }
|
98
|
-
sleep(0.1)
|
99
|
-
expect {
|
100
|
-
subject.stop
|
101
|
-
sleep(0.1)
|
102
|
-
}.not_to raise_error
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'return false when #on_stop raises an exception' do
|
106
|
-
subject.stub(:on_stop).and_raise(StandardError)
|
107
|
-
@thread = Thread.new { subject.run }
|
108
|
-
sleep(0.1)
|
109
|
-
subject.stop.should be_false
|
110
|
-
subject.should_not be_running
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'calls #after_run when implemented' do
|
114
|
-
subject.should_receive(:after_run).with(no_args())
|
115
|
-
@thread = Thread.new { subject.run }
|
116
|
-
sleep(0.1)
|
117
|
-
subject.stop
|
118
|
-
sleep(0.2)
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'does not attempt to call #after_run when not implemented' do
|
122
|
-
subject.class.send(:remove_method, :after_run)
|
123
|
-
@thread = Thread.new { subject.run }
|
124
|
-
sleep(0.1)
|
125
|
-
expect {
|
126
|
-
subject.stop
|
127
|
-
sleep(0.2)
|
128
|
-
}.not_to raise_error
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
context '#running?' do
|
133
|
-
|
134
|
-
it 'returns false if runner abends' do
|
135
|
-
subject.stub(:on_task).and_raise(StandardError)
|
136
|
-
@thread = Thread.new { subject.run }
|
137
|
-
@thread.join(0.1)
|
138
|
-
subject.should_not be_running
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
context 'instance #run!' do
|
143
|
-
|
144
|
-
after(:each) do
|
145
|
-
@thread.kill if @thread
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'raises an exception when already running' do
|
149
|
-
@thread = Thread.new{ subject.run }
|
150
|
-
@thread.join(0.1)
|
151
|
-
expect {
|
152
|
-
@thread = subject.run!
|
153
|
-
}.to raise_exception(Concurrent::LifecycleError)
|
154
|
-
sleep(0.1)
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'creates a new thread' do
|
158
|
-
t = Thread.new{ nil }
|
159
|
-
Thread.should_receive(:new).with(no_args()).and_return(t)
|
160
|
-
@thread = subject.run!
|
161
|
-
end
|
162
|
-
|
163
|
-
it 'calls the #run method on the new thread' do
|
164
|
-
subject.should_receive(:run)
|
165
|
-
@thread = subject.run!
|
166
|
-
sleep(0.1)
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'returns the new thread' do
|
170
|
-
@thread = subject.run!
|
171
|
-
sleep(0.1)
|
172
|
-
@thread.should be_a(Thread)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
context 'module #run!' do
|
177
|
-
|
178
|
-
let(:clazz) do
|
179
|
-
Class.new { include Runnable }
|
180
|
-
end
|
181
|
-
|
182
|
-
after(:each) do
|
183
|
-
@context.runner.stop if @context && @context.runner
|
184
|
-
@context.thread.kill if @context && @context.thread
|
185
|
-
end
|
186
|
-
|
187
|
-
it 'creates a new runner' do
|
188
|
-
clazz.should_receive(:new).once.with(no_args())
|
189
|
-
@context = clazz.run!
|
190
|
-
sleep(0.1)
|
191
|
-
end
|
192
|
-
|
193
|
-
it 'passes all args to the runner constructor' do
|
194
|
-
args = [1, 2, :three, :four]
|
195
|
-
clazz.should_receive(:new).once.with(*args)
|
196
|
-
@context = clazz.run!(*args)
|
197
|
-
sleep(0.1)
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'passes a block argument to the runner constructor' do
|
201
|
-
@expected = false
|
202
|
-
@context = runnable.run!{ @expected = true }
|
203
|
-
sleep(0.1)
|
204
|
-
@expected.should be_true
|
205
|
-
end
|
206
|
-
|
207
|
-
it 'creates a new thread' do
|
208
|
-
Thread.should_receive(:new).with(any_args()).and_return(nil)
|
209
|
-
@context = runnable.run!
|
210
|
-
sleep(0.1)
|
211
|
-
end
|
212
|
-
|
213
|
-
it 'runs the runner on the new thread' do
|
214
|
-
@context = runnable.run!
|
215
|
-
sleep(0.1)
|
216
|
-
@context.runner.thread.should_not eq Thread.current
|
217
|
-
@context.runner.thread.should eq @context.thread
|
218
|
-
@context.thread.should_not eq Thread.current
|
219
|
-
end
|
220
|
-
|
221
|
-
it 'returns a context object on success' do
|
222
|
-
@context = runnable.run!
|
223
|
-
sleep(0.1)
|
224
|
-
@context.should be_a(Runnable::Context)
|
225
|
-
end
|
226
|
-
|
227
|
-
it 'returns nil on failure' do
|
228
|
-
Thread.stub(:new).with(any_args()).and_raise(StandardError)
|
229
|
-
@context = runnable.run!
|
230
|
-
sleep(0.1)
|
231
|
-
@context.should be_nil
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
@@ -1,340 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'timecop'
|
3
|
-
require_relative 'dereferenceable_shared'
|
4
|
-
require_relative 'obligation_shared'
|
5
|
-
require_relative 'observable_shared'
|
6
|
-
|
7
|
-
module Concurrent
|
8
|
-
|
9
|
-
describe ScheduledTask do
|
10
|
-
context 'behavior' do
|
11
|
-
|
12
|
-
# obligation
|
13
|
-
|
14
|
-
let!(:fulfilled_value) { 10 }
|
15
|
-
let!(:rejected_reason) { StandardError.new('mojo jojo') }
|
16
|
-
|
17
|
-
let(:pending_subject) do
|
18
|
-
ScheduledTask.new(1){ fulfilled_value }.execute
|
19
|
-
end
|
20
|
-
|
21
|
-
let(:fulfilled_subject) do
|
22
|
-
latch = Concurrent::CountDownLatch.new(1)
|
23
|
-
task = ScheduledTask.new(0.1){ latch.count_down; fulfilled_value }.execute
|
24
|
-
latch.wait(1)
|
25
|
-
sleep(0.1)
|
26
|
-
task
|
27
|
-
end
|
28
|
-
|
29
|
-
let(:rejected_subject) do
|
30
|
-
latch = Concurrent::CountDownLatch.new(1)
|
31
|
-
task = ScheduledTask.new(0.1){ latch.count_down; raise rejected_reason }.execute
|
32
|
-
latch.wait(1)
|
33
|
-
sleep(0.1)
|
34
|
-
task
|
35
|
-
end
|
36
|
-
|
37
|
-
it_should_behave_like :obligation
|
38
|
-
|
39
|
-
# dereferenceable
|
40
|
-
|
41
|
-
def dereferenceable_subject(value, opts = {})
|
42
|
-
ScheduledTask.execute(0.1, opts){ value }.tap{ sleep(0.2) }
|
43
|
-
end
|
44
|
-
|
45
|
-
def dereferenceable_observable(opts = {})
|
46
|
-
ScheduledTask.new(0.1, opts){ 'value' }
|
47
|
-
end
|
48
|
-
|
49
|
-
def execute_dereferenceable(subject)
|
50
|
-
subject.execute
|
51
|
-
sleep(0.2)
|
52
|
-
end
|
53
|
-
|
54
|
-
it_should_behave_like :dereferenceable
|
55
|
-
|
56
|
-
# observable
|
57
|
-
|
58
|
-
subject{ ScheduledTask.new(0.1){ nil } }
|
59
|
-
|
60
|
-
def trigger_observable(observable)
|
61
|
-
observable.execute
|
62
|
-
sleep(0.2)
|
63
|
-
end
|
64
|
-
|
65
|
-
it_should_behave_like :observable
|
66
|
-
end
|
67
|
-
|
68
|
-
context '#initialize' do
|
69
|
-
|
70
|
-
it 'accepts a number of seconds (from now) as the schedule time' do
|
71
|
-
Timecop.freeze do
|
72
|
-
now = Time.now
|
73
|
-
task = ScheduledTask.new(60){ nil }.execute
|
74
|
-
task.schedule_time.to_i.should eq now.to_i + 60
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'accepts a time object as the schedule time' do
|
79
|
-
schedule = Time.now + (60*10)
|
80
|
-
task = ScheduledTask.new(schedule){ nil }.execute
|
81
|
-
task.schedule_time.should eq schedule
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'raises an exception when seconds is less than zero' do
|
85
|
-
expect {
|
86
|
-
ScheduledTask.new(-1){ nil }
|
87
|
-
}.to raise_error(ArgumentError)
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'raises an exception when schedule time is in the past' do
|
91
|
-
expect {
|
92
|
-
ScheduledTask.new(Time.now - 60){ nil }
|
93
|
-
}.to raise_error(ArgumentError)
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'raises an exception when no block given' do
|
97
|
-
expect {
|
98
|
-
ScheduledTask.new(1)
|
99
|
-
}.to raise_error(ArgumentError)
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'sets the initial state to :unscheduled' do
|
103
|
-
task = ScheduledTask.new(1){ nil }
|
104
|
-
task.should be_unscheduled
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'sets the #schedule_time to nil prior to execution' do
|
108
|
-
task = ScheduledTask.new(1){ nil }
|
109
|
-
task.schedule_time.should be_nil
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context 'instance #execute' do
|
114
|
-
|
115
|
-
it 'does nothing unless the state is :unscheduled' do
|
116
|
-
Thread.should_not_receive(:new).with(any_args)
|
117
|
-
task = ScheduledTask.new(1){ nil }
|
118
|
-
task.instance_variable_set(:@state, :pending)
|
119
|
-
task.execute
|
120
|
-
task.instance_variable_set(:@state, :rejected)
|
121
|
-
task.execute
|
122
|
-
task.instance_variable_set(:@state, :fulfilled)
|
123
|
-
task.execute
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'calculates the #schedule_time on execution' do
|
127
|
-
Timecop.freeze do
|
128
|
-
now = Time.now
|
129
|
-
task = ScheduledTask.new(5){ nil }
|
130
|
-
Timecop.travel(10)
|
131
|
-
task.execute
|
132
|
-
task.schedule_time.to_i.should eq now.to_i + 15
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
it 'raises an exception if expected schedule time is in the past' do
|
137
|
-
Timecop.freeze do
|
138
|
-
schedule = Time.now + (10)
|
139
|
-
task = ScheduledTask.new(schedule){ nil }
|
140
|
-
Timecop.travel(60)
|
141
|
-
expect {
|
142
|
-
task.execute
|
143
|
-
}.to raise_error(ArgumentError)
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
it 'sets the sate to :pending' do
|
148
|
-
task = ScheduledTask.new(1){ nil }
|
149
|
-
task.execute
|
150
|
-
task.should be_pending
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'returns self' do
|
154
|
-
task = ScheduledTask.new(1){ nil }
|
155
|
-
task.execute.should eq task
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
context 'class #execute' do
|
160
|
-
|
161
|
-
it 'creates a new ScheduledTask' do
|
162
|
-
task = ScheduledTask.execute(1){ nil }
|
163
|
-
task.should be_a(ScheduledTask)
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'passes the block to the new ScheduledTask' do
|
167
|
-
@expected = false
|
168
|
-
task = ScheduledTask.execute(0.1){ @expected = true }
|
169
|
-
task.value(1)
|
170
|
-
@expected.should be_true
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'calls #execute on the new ScheduledTask' do
|
174
|
-
task = ScheduledTask.new(0.1){ nil }
|
175
|
-
ScheduledTask.stub(:new).with(any_args).and_return(task)
|
176
|
-
task.should_receive(:execute).with(no_args)
|
177
|
-
ScheduledTask.execute(0.1){ nil }
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
context '#cancel' do
|
182
|
-
|
183
|
-
it 'returns false if the task has already been performed' do
|
184
|
-
task = ScheduledTask.new(0.1){ 42 }.execute
|
185
|
-
task.value(1)
|
186
|
-
task.cancel.should be_false
|
187
|
-
end
|
188
|
-
|
189
|
-
it 'returns false if the task is already in progress' do
|
190
|
-
latch = Concurrent::CountDownLatch.new(1)
|
191
|
-
task = ScheduledTask.new(0.1) {
|
192
|
-
latch.count_down
|
193
|
-
sleep(1)
|
194
|
-
}.execute
|
195
|
-
latch.wait(1)
|
196
|
-
task.cancel.should be_false
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'cancels the task if it has not yet scheduled' do
|
200
|
-
latch = Concurrent::CountDownLatch.new(1)
|
201
|
-
task = ScheduledTask.new(0.1){ latch.count_down }
|
202
|
-
task.cancel
|
203
|
-
task.execute
|
204
|
-
latch.wait(0.3).should be_false
|
205
|
-
end
|
206
|
-
|
207
|
-
|
208
|
-
it 'cancels the task if it has not yet started' do
|
209
|
-
latch = Concurrent::CountDownLatch.new(1)
|
210
|
-
task = ScheduledTask.new(0.3){ latch.count_down }.execute
|
211
|
-
sleep(0.1)
|
212
|
-
task.cancel
|
213
|
-
latch.wait(0.5).should be_false
|
214
|
-
end
|
215
|
-
|
216
|
-
it 'returns true on success' do
|
217
|
-
task = ScheduledTask.new(10){ nil }.execute
|
218
|
-
sleep(0.1)
|
219
|
-
task.cancel.should be_true
|
220
|
-
end
|
221
|
-
|
222
|
-
it 'sets the state to :cancelled when cancelled' do
|
223
|
-
task = ScheduledTask.new(10){ 42 }.execute
|
224
|
-
sleep(0.1)
|
225
|
-
task.cancel
|
226
|
-
task.should be_cancelled
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
context 'execution' do
|
231
|
-
|
232
|
-
it 'sets the state to :in_progress when the task is running' do
|
233
|
-
latch = Concurrent::CountDownLatch.new(1)
|
234
|
-
task = ScheduledTask.new(0.1) {
|
235
|
-
latch.count_down
|
236
|
-
sleep(1)
|
237
|
-
}.execute
|
238
|
-
latch.wait(1)
|
239
|
-
task.should be_in_progress
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
context 'observation' do
|
244
|
-
|
245
|
-
let(:clazz) do
|
246
|
-
Class.new do
|
247
|
-
attr_reader :value
|
248
|
-
attr_reader :reason
|
249
|
-
attr_reader :count
|
250
|
-
attr_reader :latch
|
251
|
-
def initialize
|
252
|
-
@latch = Concurrent::CountDownLatch.new(1)
|
253
|
-
end
|
254
|
-
def update(time, value, reason)
|
255
|
-
@count = @count.to_i + 1
|
256
|
-
@value = value
|
257
|
-
@reason = reason
|
258
|
-
@latch.count_down
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
let(:observer) { clazz.new }
|
264
|
-
|
265
|
-
it 'returns true for an observer added while :unscheduled' do
|
266
|
-
task = ScheduledTask.new(0.1){ 42 }
|
267
|
-
task.add_observer(observer).should be_true
|
268
|
-
end
|
269
|
-
|
270
|
-
it 'returns true for an observer added while :pending' do
|
271
|
-
task = ScheduledTask.new(0.1){ 42 }.execute
|
272
|
-
task.add_observer(observer).should be_true
|
273
|
-
end
|
274
|
-
|
275
|
-
it 'returns true for an observer added while :in_progress' do
|
276
|
-
task = ScheduledTask.new(0.1){ sleep(1); 42 }.execute
|
277
|
-
sleep(0.2)
|
278
|
-
task.add_observer(observer).should be_true
|
279
|
-
end
|
280
|
-
|
281
|
-
it 'returns false for an observer added once :cancelled' do
|
282
|
-
task = ScheduledTask.new(1){ 42 }
|
283
|
-
task.cancel
|
284
|
-
task.add_observer(observer).should be_false
|
285
|
-
end
|
286
|
-
|
287
|
-
it 'returns false for an observer added once :fulfilled' do
|
288
|
-
task = ScheduledTask.new(0.1){ 42 }.execute
|
289
|
-
task.value(1)
|
290
|
-
task.add_observer(observer).should be_false
|
291
|
-
end
|
292
|
-
|
293
|
-
it 'returns false for an observer added once :rejected' do
|
294
|
-
task = ScheduledTask.new(0.1){ raise StandardError }.execute
|
295
|
-
task.value(0.2)
|
296
|
-
task.add_observer(observer).should be_false
|
297
|
-
end
|
298
|
-
|
299
|
-
it 'notifies all observers on fulfillment' do
|
300
|
-
task = ScheduledTask.new(0.1){ 42 }.execute
|
301
|
-
task.add_observer(observer)
|
302
|
-
observer.latch.wait(1)
|
303
|
-
observer.value.should == 42
|
304
|
-
observer.reason.should be_nil
|
305
|
-
end
|
306
|
-
|
307
|
-
it 'notifies all observers on rejection' do
|
308
|
-
task = ScheduledTask.new(0.1){ raise StandardError }.execute
|
309
|
-
task.add_observer(observer)
|
310
|
-
observer.latch.wait(1)
|
311
|
-
observer.value.should be_nil
|
312
|
-
observer.reason.should be_a(StandardError)
|
313
|
-
end
|
314
|
-
|
315
|
-
it 'does not notify an observer added after fulfillment' do
|
316
|
-
observer.should_not_receive(:update).with(any_args)
|
317
|
-
task = ScheduledTask.new(0.1){ 42 }.execute
|
318
|
-
task.value(1)
|
319
|
-
task.add_observer(observer)
|
320
|
-
sleep(0.1)
|
321
|
-
end
|
322
|
-
|
323
|
-
it 'does not notify an observer added after rejection' do
|
324
|
-
observer.should_not_receive(:update).with(any_args)
|
325
|
-
task = ScheduledTask.new(0.1){ raise StandardError }.execute
|
326
|
-
task.value(1)
|
327
|
-
task.add_observer(observer)
|
328
|
-
sleep(0.1)
|
329
|
-
end
|
330
|
-
|
331
|
-
it 'does not notify an observer added after cancellation' do
|
332
|
-
observer.should_not_receive(:update).with(any_args)
|
333
|
-
task = ScheduledTask.new(0.1){ 42 }.execute
|
334
|
-
task.cancel
|
335
|
-
task.add_observer(observer)
|
336
|
-
task.value(1)
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|