@@ -18,7 +18,9 @@ module Concurrent
18
18
let! ( :rejected_reason ) { StandardError . new ( 'mojo jojo' ) }
19
19
20
20
let ( :pending_subject ) do
21
- Future . new ( executor : executor ) { sleep ( 0.1 ) ; fulfilled_value } . execute
21
+ executor = Concurrent ::SingleThreadExecutor . new
22
+ executor . post { sleep ( 5 ) }
23
+ Future . execute ( executor : executor ) { fulfilled_value }
22
24
end
23
25
24
26
let ( :fulfilled_subject ) do
@@ -110,8 +112,11 @@ def get_ivar_from_args(opts)
110
112
end
111
113
112
114
it 'sets the state to :pending' do
113
- latch = Concurrent ::CountDownLatch . new ( 1 )
114
- future = Future . new ( executor : executor ) { latch . wait ( 10 ) }
115
+ latch = Concurrent ::CountDownLatch . new
116
+ executor = Concurrent ::SingleThreadExecutor . new
117
+ executor . post { latch . wait ( 2 ) }
118
+
119
+ future = Future . new ( executor : executor ) { 42 }
115
120
future . execute
116
121
expect ( future ) . to be_pending
117
122
latch . count_down
@@ -150,10 +155,29 @@ def get_ivar_from_args(opts)
150
155
151
156
let ( :executor ) { ImmediateExecutor . new }
152
157
158
+ it 'sets the state to :processing while the task is executing' do
159
+ start_latch = Concurrent ::CountDownLatch . new
160
+ continue_latch = Concurrent ::CountDownLatch . new
161
+ executor = Concurrent ::SingleThreadExecutor . new
162
+
163
+ future = Future . execute ( executor : executor ) do
164
+ start_latch . count_down
165
+ continue_latch . wait ( 2 )
166
+ 42
167
+ end
168
+
169
+ start_latch . wait ( 2 )
170
+ state = future . state
171
+ continue_latch . count_down
172
+ future . value
173
+
174
+ expect ( state ) . to eq :processing
175
+ end
176
+
153
177
it 'passes all arguments to handler' do
154
- @ expected = false
155
- Future . new ( executor : executor ) { @ expected = true } . execute
156
- expect ( @ expected) . to be_truthy
178
+ expected = false
179
+ Future . new ( executor : executor ) { expected = true } . execute
180
+ expect ( expected ) . to be_truthy
157
181
end
158
182
159
183
it 'sets the value to the result of the handler' do
@@ -198,6 +222,82 @@ def get_ivar_from_args(opts)
198
222
end
199
223
end
200
224
225
+ context 'cancellation' do
226
+
227
+ context '#cancel' do
228
+
229
+ it 'fails to cancel the task once processing has begun' do
230
+ start_latch = Concurrent ::CountDownLatch . new
231
+ continue_latch = Concurrent ::CountDownLatch . new
232
+ f = Future . execute do
233
+ start_latch . count_down
234
+ continue_latch . wait ( 2 )
235
+ 42
236
+ end
237
+
238
+ start_latch . wait ( 2 )
239
+ cancelled = f . cancel
240
+ continue_latch . count_down
241
+
242
+ expect ( cancelled ) . to be false
243
+ expect ( f . value ) . to eq 42
244
+ expect ( f ) . to be_fulfilled
245
+ end
246
+
247
+ it 'fails to cancel the task once processing is complete' do
248
+ f = Future . execute { 42 }
249
+ f . wait
250
+ cancelled = f . cancel
251
+
252
+ expect ( cancelled ) . to be false
253
+ expect ( f . value ) . to eq 42
254
+ expect ( f ) . to be_fulfilled
255
+ end
256
+
257
+ it 'cancels a pending task' do
258
+ executor = Concurrent ::SingleThreadExecutor . new
259
+ latch = Concurrent ::CountDownLatch . new
260
+ executor . post { latch . wait ( 2 ) }
261
+
262
+ f = Future . execute ( executor : executor ) { 42 }
263
+ cancelled = f . cancel
264
+ latch . count_down
265
+
266
+ expect ( cancelled ) . to be true
267
+ expect ( f . value ) . to be_nil
268
+ expect ( f ) . to be_rejected
269
+ expect ( f . reason ) . to be_a Concurrent ::CancelledOperationError
270
+ end
271
+ end
272
+
273
+ context '#wait_or_cancel' do
274
+
275
+ it 'returns true if the operation completes before timeout' do
276
+ f = Future . execute { 42 }
277
+ success = f . wait_or_cancel ( 1 )
278
+
279
+ expect ( success ) . to be true
280
+ expect ( f . value ) . to eq 42
281
+ expect ( f ) . to be_fulfilled
282
+ end
283
+
284
+ it 'cancels the task on timeout' do
285
+ latch = Concurrent ::CountDownLatch . new
286
+ executor = Concurrent ::SingleThreadExecutor . new
287
+ executor . post { latch . wait ( 2 ) }
288
+
289
+ f = Future . execute ( executor : executor ) { 42 }
290
+ success = f . wait_or_cancel ( 0.1 )
291
+ latch . count_down
292
+
293
+ expect ( success ) . to be false
294
+ expect ( f . value ) . to be_nil
295
+ expect ( f ) . to be_rejected
296
+ expect ( f . reason ) . to be_a Concurrent ::CancelledOperationError
297
+ end
298
+ end
299
+ end
300
+
201
301
context 'observation' do
202
302
203
303
let ( :executor ) { ImmediateExecutor . new }
0 commit comments