@@ -13,15 +13,17 @@ module Concurrent
1313 let! ( :rejected_reason ) { StandardError . new ( 'mojo jojo' ) }
1414
1515 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 }
1719 end
1820
1921 let ( :fulfilled_subject ) do
20- Promise . fulfill ( fulfilled_value , executor : executor )
22+ Promise . new ( executor : executor ) { fulfilled_value } . execute . tap { sleep ( 0.1 ) }
2123 end
2224
2325 let ( :rejected_subject ) do
24- Promise . reject ( rejected_reason , executor : executor )
26+ Promise . new ( executor : executor ) { raise rejected_reason } . execute . tap { sleep ( 0.1 ) }
2527 end
2628
2729 it_should_behave_like :ivar do
@@ -97,28 +99,27 @@ def get_ivar_from_args(opts)
9799
98100 describe '.new' do
99101 it 'should return an unscheduled Promise' do
100- p = Promise . new ( executor : executor ) { nil }
102+ p = Promise . new ( executor : :immediate ) { nil }
101103 expect ( p ) . to be_unscheduled
102104 end
103105 end
104106
105107 describe '.execute' do
106108 it 'creates a new Promise' do
107- p = Promise . execute ( executor : executor ) { nil }
109+ p = Promise . execute ( executor : :immediate ) { nil }
108110 expect ( p ) . to be_a ( Promise )
109111 end
110112
111113 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 }
114115 expect ( p . value ) . to eq 20
115116 end
116117
117118 it 'calls #execute on the new Promise' do
118119 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 )
120121 expect ( p ) . to receive ( :execute ) . with ( no_args )
121- Promise . execute ( executor : executor ) { nil }
122+ Promise . execute ( executor : :immediate ) { nil }
122123 end
123124 end
124125 end
@@ -128,52 +129,70 @@ def get_ivar_from_args(opts)
128129 context 'unscheduled' do
129130
130131 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
132140 expect ( p ) . to be_pending
141+ end_latch . count_down
133142 end
134143
135144 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
137147 Promise . new ( executor : executor ) { nil } . execute
138148 end
139149 end
140150
141151 context 'pending' do
142152
143153 it 'sets the promise to :pending' do
144- p = pending_subject . execute
154+ latch = CountDownLatch . new
155+ p = Promise . new { latch . wait ( 1 ) } . execute
145156 expect ( p ) . to be_pending
157+ latch . count_down
146158 end
147159
148- it 'does not posts again' do
160+ it 'does not post again' do
161+ executor = SimpleExecutorService . new
149162 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
151169 end
152170 end
153171
154172 describe 'with children' do
155173
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 ) } }
160180
161181 context 'when called on the root' do
162182 it 'should set all promises to :pending' do
163183 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 )
168185 [ root , c1 , c2 , c2_1 ] . each { |p | expect ( p ) . to be_pending }
186+ end_latch . count_down
169187 end
170188 end
171189
172190 context 'when called on a child' do
173191 it 'should set all promises to :pending' do
174192 c2_1 . execute
175-
193+ start_latch . wait ( 1 )
176194 [ root , c1 , c2 , c2_1 ] . each { |p | expect ( p ) . to be_pending }
195+ end_latch . count_down
177196 end
178197 end
179198 end
@@ -298,38 +317,38 @@ def get_ivar_from_args(opts)
298317 end
299318
300319 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
303322
304323 expect ( child . value! ) . to eq ( 11 )
305324 end
306325
307326 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
310329
311330 expect ( child ) . to be_rejected
312331 end
313332
314333 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
317336
318337 expect ( child ) . to be_rejected
319338 end
320339
321340 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
323342
324343 expect ( child ) . to be_rejected
325344 end
326345
327346 end
328347
329348 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 ] } }
333352
334353 it 'yields the results as an array' do
335354 composite = promise1 . zip ( promise2 , promise3 ) . execute . wait
@@ -345,9 +364,9 @@ def get_ivar_from_args(opts)
345364 end
346365
347366 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 ] } }
351370
352371 it 'yields the results as an array' do
353372 composite = Promise . zip ( promise1 , promise2 , promise3 ) . execute . wait
@@ -364,9 +383,9 @@ def get_ivar_from_args(opts)
364383
365384 describe 'aggregators' do
366385
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 ] } }
370389
371390 describe '.all?' do
372391
@@ -386,7 +405,7 @@ def get_ivar_from_args(opts)
386405
387406 composite = Promise . all? ( promise1 , promise2 , promise3 ) .
388407 then { counter . up ; latch . count_down } .
389- rescue { counter . down ; latch . count_down } .
408+ rescue { counter . down ; latch . count_down } .
390409 execute
391410
392411 latch . wait ( 1 )
@@ -400,7 +419,7 @@ def get_ivar_from_args(opts)
400419
401420 composite = Promise . all? .
402421 then { counter . up ; latch . count_down } .
403- rescue { counter . down ; latch . count_down } .
422+ rescue { counter . down ; latch . count_down } .
404423 execute
405424
406425 latch . wait ( 1 )
@@ -414,7 +433,7 @@ def get_ivar_from_args(opts)
414433
415434 composite = Promise . all? ( promise1 , promise2 , rejected_subject , promise3 ) .
416435 then { counter . up ; latch . count_down } .
417- rescue { counter . down ; latch . count_down } .
436+ rescue { counter . down ; latch . count_down } .
418437 execute
419438
420439 latch . wait ( 1 )
@@ -441,7 +460,7 @@ def get_ivar_from_args(opts)
441460
442461 composite = Promise . any? ( promise1 , promise2 , rejected_subject , promise3 ) .
443462 then { counter . up ; latch . count_down } .
444- rescue { counter . down ; latch . count_down } .
463+ rescue { counter . down ; latch . count_down } .
445464 execute
446465
447466 latch . wait ( 1 )
@@ -455,7 +474,7 @@ def get_ivar_from_args(opts)
455474
456475 composite = Promise . any? .
457476 then { counter . up ; latch . count_down } .
458- rescue { counter . down ; latch . count_down } .
477+ rescue { counter . down ; latch . count_down } .
459478 execute
460479
461480 latch . wait ( 1 )
@@ -469,7 +488,7 @@ def get_ivar_from_args(opts)
469488
470489 composite = Promise . any? ( rejected_subject , rejected_subject , rejected_subject , rejected_subject ) .
471490 then { counter . up ; latch . count_down } .
472- rescue { counter . down ; latch . count_down } .
491+ rescue { counter . down ; latch . count_down } .
473492 execute
474493
475494 latch . wait ( 1 )
@@ -500,7 +519,7 @@ def get_ivar_from_args(opts)
500519 end
501520
502521 it 'can be called with a block' do
503- p = Promise . new ( executor : executor )
522+ p = Promise . new ( executor : :immediate )
504523 ch = p . then ( &:to_s )
505524 p . set { :value }
506525
@@ -533,46 +552,40 @@ def get_ivar_from_args(opts)
533552
534553 it 'passes the result of each block to all its children' do
535554 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
538556 expect ( expected ) . to eq 20
539557 end
540558
541559 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 }
543561 p = root . then { |result | result * 2 } . execute
544- sleep ( 0.1 )
545562 expect ( root . value ) . to eq 20
546563 expect ( p . value ) . to eq 40
547564 end
548565
549566 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
552568 expect ( p ) . to be_fulfilled
553569 end
554570
555571 it 'passes the last result through when a promise has no block' do
556572 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
559574 expect ( expected ) . to eq 20
560575 end
561576
562577 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
565579 expect ( p . value ) . to eq 20
566580 end
567581
568582 it 'can manage long chain' do
569- root = Promise . new ( executor : executor ) { 20 }
583+ root = Promise . new ( executor : :immediate ) { 20 }
570584 p1 = root . then { |b | b * 3 }
571585 p2 = root . then { |c | c + 2 }
572586 p3 = p1 . then { |d | d + 7 }
573587
574588 root . execute
575- sleep ( 0.1 )
576589
577590 expect ( root . value ) . to eq 20
578591 expect ( p1 . value ) . to eq 60
@@ -585,27 +598,24 @@ def get_ivar_from_args(opts)
585598
586599 it 'passes the reason to all its children' do
587600 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
590603 expect ( expected ) . to be_a ArgumentError
591604 end
592605
593606 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 }
595608 p = root . then ( Proc . new { |reason | 42 } ) . execute
596- sleep ( 0.1 )
597609 expect ( p . value ) . to eq 42
598610 end
599611
600612 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
603614 expect ( p ) . to be_rejected
604615 end
605616
606617 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
609619 expect ( p ) . to be_rejected
610620 expect ( p . reason ) . to be_a ArgumentError
611621 end
0 commit comments