@@ -13,15 +13,17 @@ module Concurrent
13
13
let! ( :rejected_reason ) { StandardError . new ( 'mojo jojo' ) }
14
14
15
15
let ( :pending_subject ) do
16
- Promise . new ( executor : executor ) { sleep ( 0.1 ) ; fulfilled_value } . execute
16
+ executor = Concurrent ::SingleThreadExecutor . new
17
+ executor . post { sleep ( 5 ) }
18
+ Promise . execute ( executor : executor ) { fulfilled_value }
17
19
end
18
20
19
21
let ( :fulfilled_subject ) do
20
- Promise . fulfill ( fulfilled_value , executor : executor )
22
+ Promise . new ( executor : executor ) { fulfilled_value } . execute . tap { sleep ( 0.1 ) }
21
23
end
22
24
23
25
let ( :rejected_subject ) do
24
- Promise . reject ( rejected_reason , executor : executor )
26
+ Promise . new ( executor : executor ) { raise rejected_reason } . execute . tap { sleep ( 0.1 ) }
25
27
end
26
28
27
29
it_should_behave_like :ivar do
@@ -97,28 +99,27 @@ def get_ivar_from_args(opts)
97
99
98
100
describe '.new' do
99
101
it 'should return an unscheduled Promise' do
100
- p = Promise . new ( executor : executor ) { nil }
102
+ p = Promise . new ( executor : :immediate ) { nil }
101
103
expect ( p ) . to be_unscheduled
102
104
end
103
105
end
104
106
105
107
describe '.execute' do
106
108
it 'creates a new Promise' do
107
- p = Promise . execute ( executor : executor ) { nil }
109
+ p = Promise . execute ( executor : :immediate ) { nil }
108
110
expect ( p ) . to be_a ( Promise )
109
111
end
110
112
111
113
it 'passes the block to the new Promise' do
112
- p = Promise . execute ( executor : executor ) { 20 }
113
- sleep ( 0.1 )
114
+ p = Promise . execute ( executor : :immediate ) { 20 }
114
115
expect ( p . value ) . to eq 20
115
116
end
116
117
117
118
it 'calls #execute on the new Promise' do
118
119
p = double ( 'promise' )
119
- allow ( Promise ) . to receive ( :new ) . with ( { executor : executor } ) . and_return ( p )
120
+ allow ( Promise ) . to receive ( :new ) . with ( any_args ) . and_return ( p )
120
121
expect ( p ) . to receive ( :execute ) . with ( no_args )
121
- Promise . execute ( executor : executor ) { nil }
122
+ Promise . execute ( executor : :immediate ) { nil }
122
123
end
123
124
end
124
125
end
@@ -128,52 +129,70 @@ def get_ivar_from_args(opts)
128
129
context 'unscheduled' do
129
130
130
131
it 'sets the promise to :pending' do
131
- p = Promise . new ( executor : executor ) { sleep ( 0.1 ) } . execute
132
+ start_latch = CountDownLatch . new
133
+ end_latch = CountDownLatch . new
134
+ p = Promise . new ( executor : executor ) do
135
+ start_latch . count_down
136
+ end_latch . wait ( 1 )
137
+ end
138
+ start_latch . wait ( 1 )
139
+ p . execute
132
140
expect ( p ) . to be_pending
141
+ end_latch . count_down
133
142
end
134
143
135
144
it 'posts the block given in construction' do
136
- expect ( executor ) . to receive ( :post ) . with ( any_args )
145
+ executor = ImmediateExecutor . new
146
+ expect ( executor ) . to receive ( :post ) . with ( any_args ) . and_call_original
137
147
Promise . new ( executor : executor ) { nil } . execute
138
148
end
139
149
end
140
150
141
151
context 'pending' do
142
152
143
153
it 'sets the promise to :pending' do
144
- p = pending_subject . execute
154
+ latch = CountDownLatch . new
155
+ p = Promise . new { latch . wait ( 1 ) } . execute
145
156
expect ( p ) . to be_pending
157
+ latch . count_down
146
158
end
147
159
148
- it 'does not posts again' do
160
+ it 'does not post again' do
161
+ executor = SimpleExecutorService . new
149
162
expect ( executor ) . to receive ( :post ) . with ( any_args ) . once
150
- pending_subject . execute
163
+
164
+ latch = CountDownLatch . new
165
+ p = Promise . new ( executor : executor ) { latch . wait ( 1 ) } . execute
166
+
167
+ 10 . times { p . execute }
168
+ latch . count_down
151
169
end
152
170
end
153
171
154
172
describe 'with children' do
155
173
156
- let ( :root ) { Promise . new ( executor : executor ) { sleep ( 0.1 ) ; nil } }
157
- let ( :c1 ) { root . then { sleep ( 0.1 ) ; nil } }
158
- let ( :c2 ) { root . then { sleep ( 0.1 ) ; nil } }
159
- let ( :c2_1 ) { c2 . then { sleep ( 0.1 ) ; nil } }
174
+ let ( :start_latch ) { CountDownLatch . new ( 4 ) }
175
+ let ( :end_latch ) { CountDownLatch . new ( 1 ) }
176
+ let ( :root ) { Promise . new ( executor : executor ) { start_latch . count_down ; end_latch . wait ( 5 ) } }
177
+ let ( :c1 ) { root . then { start_latch . count_down ; end_latch . wait ( 5 ) } }
178
+ let ( :c2 ) { root . then { start_latch . count_down ; end_latch . wait ( 5 ) } }
179
+ let ( :c2_1 ) { c2 . then { start_latch . count_down ; end_latch . wait ( 5 ) } }
160
180
161
181
context 'when called on the root' do
162
182
it 'should set all promises to :pending' do
163
183
root . execute
164
-
165
- expect ( c1 ) . to be_pending
166
- expect ( c2 ) . to be_pending
167
- expect ( c2_1 ) . to be_pending
184
+ start_latch . wait ( 1 )
168
185
[ root , c1 , c2 , c2_1 ] . each { |p | expect ( p ) . to be_pending }
186
+ end_latch . count_down
169
187
end
170
188
end
171
189
172
190
context 'when called on a child' do
173
191
it 'should set all promises to :pending' do
174
192
c2_1 . execute
175
-
193
+ start_latch . wait ( 1 )
176
194
[ root , c1 , c2 , c2_1 ] . each { |p | expect ( p ) . to be_pending }
195
+ end_latch . count_down
177
196
end
178
197
end
179
198
end
@@ -298,38 +317,38 @@ def get_ivar_from_args(opts)
298
317
end
299
318
300
319
it 'succeeds if both promises succeed' do
301
- child = Promise . new ( executor : executor ) { 1 } .
302
- flat_map { |v | Promise . new ( executor : executor ) { v + 10 } } . execute . wait
320
+ child = Promise . new ( executor : :immediate ) { 1 } .
321
+ flat_map { |v | Promise . new ( executor : :immediate ) { v + 10 } } . execute . wait
303
322
304
323
expect ( child . value! ) . to eq ( 11 )
305
324
end
306
325
307
326
it 'fails if the left promise fails' do
308
- child = Promise . new ( executor : executor ) { fail } .
309
- flat_map { |v | Promise . new ( executor : executor ) { v + 10 } } . execute . wait
327
+ child = Promise . new ( executor : :immediate ) { fail } .
328
+ flat_map { |v | Promise . new ( executor : :immediate ) { v + 10 } } . execute . wait
310
329
311
330
expect ( child ) . to be_rejected
312
331
end
313
332
314
333
it 'fails if the right promise fails' do
315
- child = Promise . new ( executor : executor ) { 1 } .
316
- flat_map { |v | Promise . new ( executor : executor ) { fail } } . execute . wait
334
+ child = Promise . new ( executor : :immediate ) { 1 } .
335
+ flat_map { |v | Promise . new ( executor : :immediate ) { fail } } . execute . wait
317
336
318
337
expect ( child ) . to be_rejected
319
338
end
320
339
321
340
it 'fails if the generating block fails' do
322
- child = Promise . new ( executor : executor ) { } . flat_map { fail } . execute . wait
341
+ child = Promise . new ( executor : :immediate ) { } . flat_map { fail } . execute . wait
323
342
324
343
expect ( child ) . to be_rejected
325
344
end
326
345
327
346
end
328
347
329
348
describe '#zip' do
330
- let ( :promise1 ) { Promise . new ( executor : executor ) { 1 } }
331
- let ( :promise2 ) { Promise . new ( executor : executor ) { 2 } }
332
- let ( :promise3 ) { Promise . new ( executor : executor ) { [ 3 ] } }
349
+ let ( :promise1 ) { Promise . new ( executor : :immediate ) { 1 } }
350
+ let ( :promise2 ) { Promise . new ( executor : :immediate ) { 2 } }
351
+ let ( :promise3 ) { Promise . new ( executor : :immediate ) { [ 3 ] } }
333
352
334
353
it 'yields the results as an array' do
335
354
composite = promise1 . zip ( promise2 , promise3 ) . execute . wait
@@ -345,9 +364,9 @@ def get_ivar_from_args(opts)
345
364
end
346
365
347
366
describe '.zip' do
348
- let ( :promise1 ) { Promise . new ( executor : executor ) { 1 } }
349
- let ( :promise2 ) { Promise . new ( executor : executor ) { 2 } }
350
- let ( :promise3 ) { Promise . new ( executor : executor ) { [ 3 ] } }
367
+ let ( :promise1 ) { Promise . new ( executor : :immediate ) { 1 } }
368
+ let ( :promise2 ) { Promise . new ( executor : :immediate ) { 2 } }
369
+ let ( :promise3 ) { Promise . new ( executor : :immediate ) { [ 3 ] } }
351
370
352
371
it 'yields the results as an array' do
353
372
composite = Promise . zip ( promise1 , promise2 , promise3 ) . execute . wait
@@ -364,9 +383,9 @@ def get_ivar_from_args(opts)
364
383
365
384
describe 'aggregators' do
366
385
367
- let ( :promise1 ) { Promise . new ( executor : executor ) { 1 } }
368
- let ( :promise2 ) { Promise . new ( executor : executor ) { 2 } }
369
- let ( :promise3 ) { Promise . new ( executor : executor ) { [ 3 ] } }
386
+ let ( :promise1 ) { Promise . new ( executor : :immediate ) { 1 } }
387
+ let ( :promise2 ) { Promise . new ( executor : :immediate ) { 2 } }
388
+ let ( :promise3 ) { Promise . new ( executor : :immediate ) { [ 3 ] } }
370
389
371
390
describe '.all?' do
372
391
@@ -386,7 +405,7 @@ def get_ivar_from_args(opts)
386
405
387
406
composite = Promise . all? ( promise1 , promise2 , promise3 ) .
388
407
then { counter . up ; latch . count_down } .
389
- rescue { counter . down ; latch . count_down } .
408
+ rescue { counter . down ; latch . count_down } .
390
409
execute
391
410
392
411
latch . wait ( 1 )
@@ -400,7 +419,7 @@ def get_ivar_from_args(opts)
400
419
401
420
composite = Promise . all? .
402
421
then { counter . up ; latch . count_down } .
403
- rescue { counter . down ; latch . count_down } .
422
+ rescue { counter . down ; latch . count_down } .
404
423
execute
405
424
406
425
latch . wait ( 1 )
@@ -414,7 +433,7 @@ def get_ivar_from_args(opts)
414
433
415
434
composite = Promise . all? ( promise1 , promise2 , rejected_subject , promise3 ) .
416
435
then { counter . up ; latch . count_down } .
417
- rescue { counter . down ; latch . count_down } .
436
+ rescue { counter . down ; latch . count_down } .
418
437
execute
419
438
420
439
latch . wait ( 1 )
@@ -441,7 +460,7 @@ def get_ivar_from_args(opts)
441
460
442
461
composite = Promise . any? ( promise1 , promise2 , rejected_subject , promise3 ) .
443
462
then { counter . up ; latch . count_down } .
444
- rescue { counter . down ; latch . count_down } .
463
+ rescue { counter . down ; latch . count_down } .
445
464
execute
446
465
447
466
latch . wait ( 1 )
@@ -455,7 +474,7 @@ def get_ivar_from_args(opts)
455
474
456
475
composite = Promise . any? .
457
476
then { counter . up ; latch . count_down } .
458
- rescue { counter . down ; latch . count_down } .
477
+ rescue { counter . down ; latch . count_down } .
459
478
execute
460
479
461
480
latch . wait ( 1 )
@@ -469,7 +488,7 @@ def get_ivar_from_args(opts)
469
488
470
489
composite = Promise . any? ( rejected_subject , rejected_subject , rejected_subject , rejected_subject ) .
471
490
then { counter . up ; latch . count_down } .
472
- rescue { counter . down ; latch . count_down } .
491
+ rescue { counter . down ; latch . count_down } .
473
492
execute
474
493
475
494
latch . wait ( 1 )
@@ -500,7 +519,7 @@ def get_ivar_from_args(opts)
500
519
end
501
520
502
521
it 'can be called with a block' do
503
- p = Promise . new ( executor : executor )
522
+ p = Promise . new ( executor : :immediate )
504
523
ch = p . then ( &:to_s )
505
524
p . set { :value }
506
525
@@ -533,46 +552,40 @@ def get_ivar_from_args(opts)
533
552
534
553
it 'passes the result of each block to all its children' do
535
554
expected = nil
536
- Promise . new ( executor : executor ) { 20 } . then { |result | expected = result } . execute
537
- sleep ( 0.1 )
555
+ Promise . new ( executor : :immediate ) { 20 } . then { |result | expected = result } . execute
538
556
expect ( expected ) . to eq 20
539
557
end
540
558
541
559
it 'sets the promise value to the result if its block' do
542
- root = Promise . new ( executor : executor ) { 20 }
560
+ root = Promise . new ( executor : :immediate ) { 20 }
543
561
p = root . then { |result | result * 2 } . execute
544
- sleep ( 0.1 )
545
562
expect ( root . value ) . to eq 20
546
563
expect ( p . value ) . to eq 40
547
564
end
548
565
549
566
it 'sets the promise state to :fulfilled if the block completes' do
550
- p = Promise . new ( executor : executor ) { 10 * 2 } . then { |result | result * 2 } . execute
551
- sleep ( 0.1 )
567
+ p = Promise . new ( executor : :immediate ) { 10 * 2 } . then { |result | result * 2 } . execute
552
568
expect ( p ) . to be_fulfilled
553
569
end
554
570
555
571
it 'passes the last result through when a promise has no block' do
556
572
expected = nil
557
- Promise . new ( executor : executor ) { 20 } . then ( Proc . new { } ) . then { |result | expected = result } . execute
558
- sleep ( 0.1 )
573
+ Promise . new ( executor : :immediate ) { 20 } . then ( Proc . new { } ) . then { |result | expected = result } . execute
559
574
expect ( expected ) . to eq 20
560
575
end
561
576
562
577
it 'uses result as fulfillment value when a promise has no block' do
563
- p = Promise . new ( executor : executor ) { 20 } . then ( Proc . new { } ) . execute
564
- sleep ( 0.1 )
578
+ p = Promise . new ( executor : :immediate ) { 20 } . then ( Proc . new { } ) . execute
565
579
expect ( p . value ) . to eq 20
566
580
end
567
581
568
582
it 'can manage long chain' do
569
- root = Promise . new ( executor : executor ) { 20 }
583
+ root = Promise . new ( executor : :immediate ) { 20 }
570
584
p1 = root . then { |b | b * 3 }
571
585
p2 = root . then { |c | c + 2 }
572
586
p3 = p1 . then { |d | d + 7 }
573
587
574
588
root . execute
575
- sleep ( 0.1 )
576
589
577
590
expect ( root . value ) . to eq 20
578
591
expect ( p1 . value ) . to eq 60
@@ -585,27 +598,24 @@ def get_ivar_from_args(opts)
585
598
586
599
it 'passes the reason to all its children' do
587
600
expected = nil
588
- Promise . new ( executor : executor ) { raise ArgumentError } . then ( Proc . new { |reason | expected = reason } ) . execute
589
- sleep ( 0.1 )
601
+ handler = proc { |reason | expected = reason }
602
+ Promise . new ( executor : :immediate ) { raise ArgumentError } . then ( handler ) . execute
590
603
expect ( expected ) . to be_a ArgumentError
591
604
end
592
605
593
606
it 'sets the promise value to the result if its block' do
594
- root = Promise . new ( executor : executor ) { raise ArgumentError }
607
+ root = Promise . new ( executor : :immediate ) { raise ArgumentError }
595
608
p = root . then ( Proc . new { |reason | 42 } ) . execute
596
- sleep ( 0.1 )
597
609
expect ( p . value ) . to eq 42
598
610
end
599
611
600
612
it 'sets the promise state to :rejected if the block completes' do
601
- p = Promise . new ( executor : executor ) { raise ArgumentError } . execute
602
- sleep ( 0.1 )
613
+ p = Promise . new ( executor : :immediate ) { raise ArgumentError } . execute
603
614
expect ( p ) . to be_rejected
604
615
end
605
616
606
617
it 'uses reason as rejection reason when a promise has no rescue callable' do
607
- p = Promise . new ( executor : ImmediateExecutor . new ) { raise ArgumentError } . then { |val | val } . execute
608
- sleep ( 0.1 )
618
+ p = Promise . new ( executor : :immediate ) { raise ArgumentError } . then { |val | val } . execute
609
619
expect ( p ) . to be_rejected
610
620
expect ( p . reason ) . to be_a ArgumentError
611
621
end
0 commit comments