libuv 4.0.0 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b07182db4afe88a245218f486d7f29091a6facf5
4
- data.tar.gz: b90adcd03a747e4af99e02befa38901befea1351
3
+ metadata.gz: 7ef6c7e235d9d6e5b37bfc32151c062031ef05dd
4
+ data.tar.gz: 1b16c9c267fd28d6e9a84064d6f6f73de579f678
5
5
  SHA512:
6
- metadata.gz: e1a90d594b27b9d198781340e7ed1478e40fa41bf2e0b83e4bda195b5791445c12726df0d5e76f8318f6b1117ea145692fe9bd034b735004e866163a921186f7
7
- data.tar.gz: 68c23d23198477dee0f5b31c04c8b2589b3af3adc79383a2e8a97a05c0fa3b859990e64147e2445ef6cb6d225ec03151fe5458111accc63f75aa7583584d5234
6
+ metadata.gz: e6b6a4db80a215ad3a4fa9564afe76cff5a629bc6d94ae7f1a31fe012d616d9924e26635077ff99fae6c395db683cb6dde90b225eb5cf7184440155247fffb1d
7
+ data.tar.gz: 8b9e181b51993f082088a97e7d744faf1bf13ac6d3298dd45579f3d68277e0012430d08d974bd5e1ffcbc9adff55d96eb7944143c4b63f15d118afe311616856
@@ -406,17 +406,17 @@ module Libuv
406
406
  promises = promises.flatten
407
407
  if promises.length > 0
408
408
  promises.each_index do |index|
409
- ref(reactor, promises[index]).then(proc {|result|
410
- deferred.resolve(true)
411
- result
412
- }, proc {|reason|
413
- deferred.reject(false)
409
+ ref(reactor, promises[index]).then(proc { |result|
410
+ deferred.resolve(result)
411
+ }, proc { |reason|
412
+ deferred.reject(reason)
414
413
  Q.reject(@reactor, reason) # Don't modify result
415
414
  })
416
415
  end
417
416
  else
418
417
  deferred.resolve(true)
419
418
  end
419
+ deferred.promise
420
420
  end
421
421
 
422
422
 
@@ -9,6 +9,7 @@ module Libuv
9
9
 
10
10
 
11
11
  CRITICAL = ::Mutex.new
12
+ THREAD_POOL = ::Concurrent::FixedThreadPool.new(8)
12
13
 
13
14
 
14
15
  module ClassMethods
@@ -425,9 +426,19 @@ module Libuv
425
426
  # @param callback [Proc] the callback to be called in the thread pool
426
427
  # @return [::Libuv::Work]
427
428
  # @raise [ArgumentError] if block is not given
428
- def work(&callback)
429
- assert_block(callback)
430
- Work.new(@reactor, &callback)
429
+ def work
430
+ ref
431
+ d = defer
432
+ THREAD_POOL.post do
433
+ begin
434
+ d.resolve(yield)
435
+ rescue Exception => e
436
+ d.reject(e)
437
+ end
438
+ end
439
+ promise = d.promise
440
+ promise.finally { unref }
441
+ promise
431
442
  end
432
443
 
433
444
  # Lookup a hostname
@@ -199,7 +199,7 @@ module Libuv
199
199
  alias_method :do_shutdown, :shutdown
200
200
  def shutdown
201
201
  if @pending_writes && @pending_writes.length > 0
202
- @pending_writes[-1][0].finally { do_shutdown }
202
+ @pending_writes[-1][0].promise.finally { do_shutdown }
203
203
  else
204
204
  do_shutdown
205
205
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Libuv
4
- VERSION = '4.0.0'
4
+ VERSION = '4.0.1'
5
5
  end
@@ -2,855 +2,905 @@ require 'libuv'
2
2
 
3
3
 
4
4
  describe Libuv::Q do
5
-
6
- before :each do
7
- @reactor = Libuv::Reactor.default
8
- @reactor.notifier {}
9
- @deferred = @reactor.defer
10
- @promise = @deferred.promise
11
- @log = []
12
- @default_fail = proc { |reason|
13
- @reactor.stop
14
- }
15
- end
16
-
17
- after :each do
18
- @reactor.notifier
19
- end
20
-
21
-
22
- describe 'resolve' do
23
-
24
-
25
- it "should call the callback in the next turn" do
26
- @reactor.run {
27
- @promise.then nil, @default_fail do |result|
28
- @log << result
29
- end
30
-
31
- @deferred.resolve(:foo)
32
- }
33
-
34
- expect(@log).to eq([:foo])
35
- end
36
-
37
-
38
-
39
- it "should be able to resolve the callback after it has already been resolved" do
40
- @reactor.run {
41
- @promise.then nil, @default_fail do |result|
42
- @log << result
43
- @promise.then nil, @default_fail do |result|
44
- @log << result
45
- end
46
- end
47
-
48
- @deferred.resolve(:foo)
49
- }
50
- expect(@log).to eq([:foo, :foo])
51
- end
52
-
53
-
54
-
55
- it "should fulfill success callbacks in the registration order" do
56
- @reactor.run {
57
- @promise.then nil, @default_fail do |result|
58
- @log << :first
59
- end
60
-
61
- @promise.then nil, @default_fail do |result|
62
- @log << :second
63
- end
64
-
65
- @deferred.resolve(:foo)
66
- }
67
- expect(@log).to eq([:first, :second])
68
- end
69
-
70
-
71
- it "should do nothing if a promise was previously resolved" do
72
- @reactor.run {
73
- @promise.then nil, @default_fail do |result|
74
- @log << result
75
- expect(@log).to eq([:foo])
76
- @deferred.resolve(:bar)
77
- end
78
-
79
- @deferred.resolve(:foo)
80
- @deferred.reject(:baz)
81
- }
82
- expect(@log).to eq([:foo])
83
- end
84
-
85
-
86
- it "should allow deferred resolution with a new promise" do
87
- deferred2 = @reactor.defer
88
- @reactor.run {
89
- @promise.then nil, @default_fail do |result|
90
- @log << result
91
- @reactor.stop
92
- end
93
-
94
- @deferred.resolve(deferred2.promise)
95
- deferred2.resolve(:foo)
96
- }
97
- expect(@log).to eq([:foo])
98
- end
99
-
100
-
101
- it "should not break if a callbacks registers another callback" do
102
- @reactor.run {
103
- @promise.then nil, @default_fail do |result|
104
- @log << :outer
105
- @promise.then nil, @default_fail do |result|
106
- @log << :inner
107
- end
108
- end
109
-
110
- @deferred.resolve(:foo)
111
- }
112
-
113
- expect(@log).to eq([:outer, :inner])
114
- end
115
-
116
-
117
-
118
- it "can modify the result of a promise before returning" do
119
- @reactor.run {
120
- proc { |name|
121
- @reactor.work { @deferred.resolve("Hello #{name}") }
122
- @promise.then nil, @default_fail do |result|
123
- @log << result
124
- result += "?"
125
- result
126
- end
127
- }.call('Robin Hood').then nil, @default_fail do |greeting|
128
- @log << greeting
129
- @reactor.stop
130
- end
131
- }
132
-
133
- expect(@log).to eq(['Hello Robin Hood', 'Hello Robin Hood?'])
134
- end
135
-
136
- end
137
-
138
-
139
- describe 'reject' do
140
-
141
- it "should reject the promise and execute all error callbacks" do
142
- @reactor.run {
143
- @promise.then(@default_fail, proc {|result|
144
- @log << :first
145
- })
146
- @promise.then(@default_fail, proc {|result|
147
- @log << :second
148
- })
149
-
150
- @deferred.reject(:foo)
151
- }
152
- expect(@log).to eq([:first, :second])
153
- end
154
-
155
-
156
- it "should do nothing if a promise was previously rejected" do
157
- @reactor.run {
158
- @promise.then(@default_fail, proc {|result|
159
- @log << result
160
- @deferred.resolve(:bar)
161
- })
162
-
163
- @deferred.reject(:baz)
164
- @deferred.resolve(:foo)
165
- }
166
- expect(@log).to eq([:baz])
167
- end
168
-
169
-
170
- it "should not defer rejection with a new promise" do
171
- deferred2 = @reactor.defer
172
- @reactor.run {
173
- @promise.then(@default_fail, @default_fail)
174
- begin
175
- @deferred.reject(deferred2.promise)
176
- rescue => e
177
- @log << e.is_a?(ArgumentError)
178
- @reactor.stop
179
- end
180
- }
181
-
182
- expect(@log).to eq([true])
183
- end
184
-
185
- end
186
-
187
-
188
- describe 'notify' do
189
- it "should execute all progress callbacks in the registration order" do
190
- @reactor.run {
191
- @promise.progress do |update|
192
- @log << :first
193
- end
194
-
195
- @promise.progress do |update|
196
- @log << :second
197
- end
198
-
199
- @deferred.notify(:foo)
200
- }
201
-
202
- expect(@log).to eq([:first, :second])
203
- end
204
-
205
- it "should do nothing if a promise was previously resolved" do
206
- @reactor.run {
207
-
208
- @promise.progress do |update|
209
- @log << update
210
- end
211
-
212
- @deferred.resolve(:foo)
213
- @deferred.notify(:baz)
214
- }
215
-
216
- expect(@log).to eq([])
217
- end
218
-
219
- it "should do nothing if a promise was previously rejected" do
220
- @reactor.run {
221
-
222
- @promise.progress do |update|
223
- @log << update
224
- end
225
- @deferred.reject(:foo)
226
- @deferred.notify(:baz)
227
- }
228
-
229
- expect(@log).to eq([])
230
- end
231
-
232
-
233
- it "should not apply any special treatment to promises passed to notify" do
234
- @reactor.run {
235
- deferred2 = @reactor.defer
236
-
237
- @promise.progress do |update|
238
- @log << update.is_a?(::Libuv::Q::Promise)
239
- end
240
- @deferred.notify(deferred2.promise)
241
- }
242
-
243
- expect(@log).to eq([true])
244
- end
245
-
246
-
247
- it "should call the progress callbacks in the next turn" do
248
- @reactor.run {
249
- @promise.progress do |update|
250
- @log << :first
251
- end
252
-
253
- @promise.progress do |update|
254
- @log << :second
255
- end
256
-
257
- @deferred.notify(:foo)
258
-
259
- @log << @log.length # Has notify run in this tick
260
- }
261
-
262
- expect(@log).to eq([0, :first, :second])
263
- end
264
-
265
- it "should ignore notifications sent out in the same turn before listener registration" do
266
- @reactor.run {
267
- @deferred.notify(:foo)
268
-
269
- @promise.progress do |update|
270
- @log << :first
271
- end
272
-
273
- @promise.progress do |update|
274
- @log << :second
275
- end
276
- }
277
-
278
- expect(@log).to eq([])
279
- end
280
- end
281
-
282
-
283
- describe Libuv::Q::Promise do
284
-
285
- describe 'then' do
286
-
287
- it "should allow registration of a success callback without an errback and resolve" do
288
- @reactor.run {
289
- @promise.then do |result|
290
- @log << result
291
- end
292
-
293
- @deferred.resolve(:foo)
294
- }
295
-
296
- expect(@log).to eq([:foo])
297
- end
298
-
299
-
300
- it "should allow registration of a success callback without an errback and reject" do
301
- @reactor.run {
302
- @promise.then do |result|
303
- @log << result
304
- end
305
-
306
- @deferred.reject(:foo)
307
- }
308
-
309
- expect(@log).to eq([])
310
- end
311
-
312
-
313
- it "should allow registration of an errback without a success callback and reject" do
314
- @reactor.run {
315
- @promise.catch { |reason|
316
- @log << reason
317
- }
318
-
319
- @deferred.reject(:foo)
320
- }
321
-
322
- expect(@log).to eq([:foo])
323
- end
324
-
325
-
326
- it "should allow registration of an errback without a success callback and resolve" do
327
- @reactor.run {
328
- @promise.catch { |reason|
329
- @log << reason
330
- }
331
-
332
- @deferred.resolve(:foo)
333
- }
334
-
335
- expect(@log).to eq([])
336
- end
337
-
338
-
339
- it "should resolve all callbacks with the original value" do
340
- @reactor.run {
341
- @promise.then nil, @default_fail do |result|
342
- @log << result
343
- :alt1
344
- end
345
- @promise.then nil, @default_fail do |result|
346
- @log << result
347
- 'ERROR'
348
- end
349
- @promise.then nil, @default_fail do |result|
350
- @log << result
351
- Libuv::Q.reject(@reactor, 'some reason')
352
- end
353
- @promise.then nil, @default_fail do |result|
354
- @log << result
355
- :alt2
356
- end
357
-
358
- @deferred.resolve(:foo)
359
- }
360
-
361
- expect(@log).to eq([:foo, :foo, :foo, :foo])
362
- end
363
-
364
-
365
- it "should notify all callbacks with the original value" do
366
- @reactor.run { |reactor_promise|
367
- @promise.progress do |result|
368
- @log << result
369
- :alt1
370
- end
371
- @promise.progress do |result|
372
- @log << result
373
- 'ERROR'
374
- end
375
- @promise.progress do |result|
376
- @log << result
377
- Libuv::Q.reject(@reactor, 'some reason')
378
- end
379
- @promise.progress do |result|
380
- @log << result
381
- :alt2
382
- end
383
-
384
-
385
- @deferred.notify(:foo)
386
- }
387
-
388
- expect(@log).to eq([:foo, :foo, :foo, :foo])
389
- end
390
-
391
-
392
- it "should reject all callbacks with the original reason" do
393
- @reactor.run {
394
- @promise.then(@default_fail, proc {|result|
395
- @log << result
396
- :alt1
397
- })
398
- @promise.then(@default_fail, proc {|result|
399
- @log << result
400
- 'ERROR'
401
- })
402
- @promise.then(@default_fail, proc {|result|
403
- @log << result
404
- Libuv::Q.reject(@reactor, 'some reason')
405
- })
406
- @promise.then(@default_fail, proc {|result|
407
- @log << result
408
- :alt2
409
- })
410
-
411
- @deferred.reject(:foo)
412
- }
413
-
414
- expect(@log).to eq([:foo, :foo, :foo, :foo])
415
- end
416
-
417
-
418
- it "should propagate resolution and rejection between dependent promises" do
419
- @reactor.run {
420
- @promise.then(proc { |result|
421
- @log << result
422
- :bar
423
- }, @default_fail).then(proc { |result|
424
- @log << result
425
- raise 'baz'
426
- }, @default_fail).then(@default_fail, proc {|result|
427
- @log << result.message
428
- raise 'bob'
429
- }).then(@default_fail, proc {|result|
430
- @log << result.message
431
- :done
432
- }).then(proc { |result|
433
- @log << result
434
- }, @default_fail)
435
-
436
- @deferred.resolve(:foo)
437
- }
438
-
439
- expect(@log).to eq([:foo, :bar, 'baz', 'bob', :done])
440
- end
441
-
442
-
443
- it "should propagate notification between dependent promises" do
444
- @reactor.run { |reactor|
445
- reactor.notifier do |type, id, error|
446
- @log << id
447
- end
448
-
449
-
450
- @promise.progress { |result|
451
- @log << result
452
- :bar
453
- }.progress { |result|
454
- @log << result
455
- result
456
- }.progress { |result|
457
- @log << result
458
- result
459
- }.progress { |result|
460
- @log << result
461
- :done
462
- }.progress { |result|
463
- @log << result
464
- result
465
- }
466
-
467
-
468
- @deferred.notify(:foo)
469
- }
470
-
471
- expect(@log).to eq([:foo, :bar, :bar, :bar, :done])
472
- end
473
-
474
-
475
- it "should stop notification propagation in case of error" do
476
- @reactor.run { |reactor|
477
- reactor.notifier do |error, context|
478
- @log << context
479
- end
480
-
481
-
482
- @promise.progress { |result|
483
- @log << result
484
- :bar
485
- }.progress { |result|
486
- @log << result
487
- raise 'err'
488
- result
489
- }.progress {|result|
490
- @log << result
491
- result
492
- }.progress {|result|
493
- @log << result
494
- :done
495
- }.progress { |result|
496
- @log << result
497
- result
498
- }
499
-
500
-
501
- @deferred.notify(:foo)
502
- }
503
-
504
- expect(@log).to eq([:foo, :bar, "performing promise progress callback"])
505
- end
506
-
507
-
508
- it "should call error callback in the next turn even if promise is already rejected" do
509
- @reactor.run {
510
- @deferred.reject(:foo)
511
-
512
- @promise.catch { |reason|
513
- @log << reason
514
- }
515
-
516
- @reactor.next_tick do
517
- @reactor.stop
518
- end
519
- }
520
-
521
- expect(@log).to eq([:foo])
522
- end
523
-
524
-
525
- end
526
-
527
-
528
- describe 'finally' do
529
-
530
- describe 'when the promise is fulfilled' do
531
-
532
- it "should call the callback" do
533
- @reactor.run {
534
- @promise.finally do
535
- @log << :finally
536
- end
537
-
538
- @deferred.resolve(:foo)
539
- }
540
-
541
- expect(@log).to eq([:finally])
542
- end
543
-
544
- it "should fulfill with the original value" do
545
- @reactor.run {
546
- @promise.finally {
547
- @log << :finally
548
- :finally
549
- }.then do |result|
550
- @log << result
551
- end
552
-
553
-
554
- @deferred.resolve(:foo)
555
- }
556
-
557
- expect(@log).to eq([:finally, :foo])
558
- end
559
-
560
- it "should fulfill with the original value (larger test)" do
561
- @reactor.run {
562
- @promise.then { |result|
563
- @log << result
564
- result
565
- }.finally {
566
- @log << :finally
567
- :finally
568
- }.then { |result|
569
- @log << result
570
- :change
571
- }.then { |result|
572
- @log << result
573
- result
574
- }.finally {
575
- @log << :finally
576
- :finally
577
- }.then { |result|
578
- @log << result
579
- result
580
- }
581
-
582
-
583
- @deferred.resolve(:foo)
584
- }
585
-
586
- expect(@log).to eq([:foo, :finally, :foo, :change, :finally, :change])
587
- end
588
-
589
- describe "when the callback throws an exception" do
590
- it "should reject with this new exception" do
591
- @reactor.run {
592
- @promise.finally {
593
- @log << :finally
594
- raise 'error'
595
- }.catch do |reason|
596
- @log.push reason.is_a?(Exception)
597
- end
598
-
599
- @deferred.resolve(:foo)
600
- }
601
-
602
- expect(@log).to eq([:finally, true])
603
- end
604
- end
605
-
606
- describe "when the callback returns a promise" do
607
- it "should fulfill with the original reason after that promise resolves" do
608
- @reactor.run {
609
- deferred2 = @reactor.defer
610
-
611
- @promise.finally {
612
- @log << :finally
613
- deferred2.promise
614
- }.then do |result|
615
- @log << result
616
- end
617
-
618
- @deferred.resolve(:foo)
619
-
620
- @reactor.next_tick do
621
- @reactor.next_tick do
622
- @reactor.next_tick do
623
- @reactor.next_tick do
624
- @log << :resolving
625
- deferred2.resolve('working')
626
- end
627
- end
628
- end
629
- end
630
- }
631
-
632
- expect(@log).to eq([:finally, :resolving, :foo])
633
- end
634
-
635
-
636
- it "should reject with the new reason when it is rejected" do
637
- @reactor.run {
638
- deferred2 = @reactor.defer
639
-
640
- @promise.finally {
641
- @log << :finally
642
- deferred2.promise
643
- }.catch do |result|
644
- @log << result
645
- end
646
-
647
- @deferred.resolve(:foo)
648
-
649
- @reactor.next_tick do
650
- @reactor.next_tick do
651
- @reactor.next_tick do
652
- @reactor.next_tick do
653
- @log << :rejecting
654
- deferred2.reject(:rejected)
655
- end
656
- end
657
- end
658
- end
659
- }
660
-
661
- expect(@log).to eq([:finally, :rejecting, :rejected])
662
- end
663
- end
664
-
665
- end
666
-
667
- end
668
-
669
-
670
- describe 'value' do
671
- it "should resolve a promise value as a future" do
672
- @reactor.run {
673
- @reactor.next_tick do
674
- @deferred.resolve(:foo)
675
- end
676
- @log << @deferred.promise.value
677
- }
678
-
679
- expect(@log).to eq([:foo])
680
- end
681
-
682
- it "should reject a promise value as a future" do
683
- @reactor.run {
684
- @reactor.next_tick do
685
- @deferred.reject(:foo)
686
- end
687
-
688
- begin
689
- @deferred.promise.value
690
- @log << 'should raise exception'
691
- rescue => e
692
- expect(e.class).to eq(CoroutineRejection)
693
- @log << e.value
694
- end
695
- }
696
-
697
- expect(@log).to eq([:foo])
698
- end
699
-
700
- it "should resolve a deferred value as a future" do
701
- @reactor.run {
702
- @reactor.next_tick do
703
- @deferred.resolve(:foo)
704
- end
705
- @log << @deferred.value
706
- }
707
-
708
- expect(@log).to eq([:foo])
709
- end
710
-
711
- it "should reject a deferred value as a future" do
712
- @reactor.run {
713
- @reactor.next_tick do
714
- @deferred.reject(:foo)
715
- end
716
-
717
- begin
718
- @deferred.value
719
- @log << 'should raise exception'
720
- rescue => e
721
- expect(e.class).to eq(CoroutineRejection)
722
- @log << e.value
723
- end
724
- }
725
-
726
- expect(@log).to eq([:foo])
727
- end
728
-
729
- it "should reject with message when rejection was a string" do
730
- @reactor.run {
731
- @reactor.next_tick do
732
- @deferred.reject('foo')
733
- end
734
-
735
- begin
736
- @deferred.value
737
- @log << 'should raise exception'
738
- rescue => e
739
- expect(e.class).to eq(CoroutineRejection)
740
- @log << e.message
741
- @log << e.value
742
- end
743
- }
744
-
745
- expect(@log).to eq(['foo', 'foo'])
746
- end
747
-
748
- it "should pass through exceptions without modification" do
749
- @reactor.run {
750
- @reactor.next_tick do
751
- @deferred.reject(RuntimeError.new('fail'))
752
- end
753
-
754
- begin
755
- @deferred.value
756
- @log << 'should raise exception'
757
- rescue => e
758
- expect(e.class).to eq(RuntimeError)
759
- @log << e.message
760
- end
761
- }
762
-
763
- expect(@log).to eq(['fail'])
764
- end
765
- end
766
-
767
- end
768
-
769
-
770
-
771
- describe 'reject' do
772
-
773
- it "should package a string into a rejected promise" do
774
- @reactor.run {
775
- rejectedPromise = Libuv::Q.reject(@reactor, 'not gonna happen')
776
-
777
- @promise.then(@default_fail, proc {|reason|
778
- @log << reason
779
- })
780
-
781
- @deferred.resolve(rejectedPromise)
782
- }
783
-
784
- expect(@log).to eq(['not gonna happen'])
785
- end
786
-
787
-
788
- it "should return a promise that forwards callbacks if the callbacks are missing" do
789
- @reactor.run {
790
- rejectedPromise = Libuv::Q.reject(@reactor, 'not gonna happen')
791
-
792
- @promise.then(@default_fail, proc {|reason|
793
- @log << reason
794
- })
795
-
796
- @deferred.resolve(rejectedPromise.then())
797
- }
798
-
799
- expect(@log).to eq(['not gonna happen'])
800
- end
801
-
802
- end
803
-
804
-
805
-
806
- describe 'all' do
807
-
808
- it "should resolve all of nothing" do
809
- @reactor.run {
810
- Libuv::Q.all(@reactor).then nil, @default_fail do |result|
811
- @log << result
812
- end
813
- }
814
-
815
- expect(@log).to eq([[]])
816
- end
817
-
818
- it "should take an array of promises and return a promise for an array of results" do
819
- @reactor.run {
820
- deferred1 = @reactor.defer
821
- deferred2 = @reactor.defer
822
-
823
- Libuv::Q.all(@reactor, @promise, deferred1.promise, deferred2.promise).then nil, @default_fail do |result|
824
- @log = result
825
- @reactor.stop
826
- end
827
-
828
- @reactor.work { @deferred.resolve(:foo) }
829
- @reactor.work { deferred2.resolve(:baz) }
830
- @reactor.work { deferred1.resolve(:bar) }
831
- }
832
-
833
- expect(@log).to eq([:foo, :bar, :baz])
834
- end
835
-
836
-
837
- it "should reject the derived promise if at least one of the promises in the array is rejected" do
838
- @reactor.run {
839
- deferred1 = @reactor.defer
840
- deferred2 = @reactor.defer
841
-
842
- Libuv::Q.all(@reactor, @promise, deferred1.promise, deferred2.promise).then(@default_fail, proc {|reason|
843
- @log << reason
844
- @reactor.stop
845
- })
846
-
847
- @reactor.work { @deferred.resolve(:foo) }
848
- @reactor.work { deferred2.reject(:baz) }
849
- }
850
-
851
- expect(@log).to eq([:baz])
852
- end
853
-
854
- end
5
+
6
+ before :each do
7
+ @reactor = Libuv::Reactor.default
8
+ @reactor.notifier {}
9
+ @deferred = @reactor.defer
10
+ @promise = @deferred.promise
11
+ @log = []
12
+ @default_fail = proc { |reason|
13
+ @reactor.stop
14
+ }
15
+ end
16
+
17
+ after :each do
18
+ @reactor.notifier
19
+ end
20
+
21
+
22
+ describe 'resolve' do
23
+
24
+
25
+ it "should call the callback in the next turn" do
26
+ @reactor.run {
27
+ @promise.then nil, @default_fail do |result|
28
+ @log << result
29
+ end
30
+
31
+ @deferred.resolve(:foo)
32
+ }
33
+
34
+ expect(@log).to eq([:foo])
35
+ end
36
+
37
+
38
+
39
+ it "should be able to resolve the callback after it has already been resolved" do
40
+ @reactor.run {
41
+ @promise.then nil, @default_fail do |result|
42
+ @log << result
43
+ @promise.then nil, @default_fail do |result|
44
+ @log << result
45
+ end
46
+ end
47
+
48
+ @deferred.resolve(:foo)
49
+ }
50
+ expect(@log).to eq([:foo, :foo])
51
+ end
52
+
53
+
54
+
55
+ it "should fulfill success callbacks in the registration order" do
56
+ @reactor.run {
57
+ @promise.then nil, @default_fail do |result|
58
+ @log << :first
59
+ end
60
+
61
+ @promise.then nil, @default_fail do |result|
62
+ @log << :second
63
+ end
64
+
65
+ @deferred.resolve(:foo)
66
+ }
67
+ expect(@log).to eq([:first, :second])
68
+ end
69
+
70
+
71
+ it "should do nothing if a promise was previously resolved" do
72
+ @reactor.run {
73
+ @promise.then nil, @default_fail do |result|
74
+ @log << result
75
+ expect(@log).to eq([:foo])
76
+ @deferred.resolve(:bar)
77
+ end
78
+
79
+ @deferred.resolve(:foo)
80
+ @deferred.reject(:baz)
81
+ }
82
+ expect(@log).to eq([:foo])
83
+ end
84
+
85
+
86
+ it "should allow deferred resolution with a new promise" do
87
+ deferred2 = @reactor.defer
88
+ @reactor.run {
89
+ @promise.then nil, @default_fail do |result|
90
+ @log << result
91
+ @reactor.stop
92
+ end
93
+
94
+ @deferred.resolve(deferred2.promise)
95
+ deferred2.resolve(:foo)
96
+ }
97
+ expect(@log).to eq([:foo])
98
+ end
99
+
100
+
101
+ it "should not break if a callbacks registers another callback" do
102
+ @reactor.run {
103
+ @promise.then nil, @default_fail do |result|
104
+ @log << :outer
105
+ @promise.then nil, @default_fail do |result|
106
+ @log << :inner
107
+ end
108
+ end
109
+
110
+ @deferred.resolve(:foo)
111
+ }
112
+
113
+ expect(@log).to eq([:outer, :inner])
114
+ end
115
+
116
+
117
+
118
+ it "can modify the result of a promise before returning" do
119
+ @reactor.run {
120
+ proc { |name|
121
+ @reactor.work { @deferred.resolve("Hello #{name}") }
122
+ @promise.then nil, @default_fail do |result|
123
+ @log << result
124
+ result += "?"
125
+ result
126
+ end
127
+ }.call('Robin Hood').then nil, @default_fail do |greeting|
128
+ @log << greeting
129
+ @reactor.stop
130
+ end
131
+ }
132
+
133
+ expect(@log).to eq(['Hello Robin Hood', 'Hello Robin Hood?'])
134
+ end
135
+
136
+ end
137
+
138
+
139
+ describe 'reject' do
140
+
141
+ it "should reject the promise and execute all error callbacks" do
142
+ @reactor.run {
143
+ @promise.then(@default_fail, proc {|result|
144
+ @log << :first
145
+ })
146
+ @promise.then(@default_fail, proc {|result|
147
+ @log << :second
148
+ })
149
+
150
+ @deferred.reject(:foo)
151
+ }
152
+ expect(@log).to eq([:first, :second])
153
+ end
154
+
155
+
156
+ it "should do nothing if a promise was previously rejected" do
157
+ @reactor.run {
158
+ @promise.then(@default_fail, proc {|result|
159
+ @log << result
160
+ @deferred.resolve(:bar)
161
+ })
162
+
163
+ @deferred.reject(:baz)
164
+ @deferred.resolve(:foo)
165
+ }
166
+ expect(@log).to eq([:baz])
167
+ end
168
+
169
+
170
+ it "should not defer rejection with a new promise" do
171
+ deferred2 = @reactor.defer
172
+ @reactor.run {
173
+ @promise.then(@default_fail, @default_fail)
174
+ begin
175
+ @deferred.reject(deferred2.promise)
176
+ rescue => e
177
+ @log << e.is_a?(ArgumentError)
178
+ @reactor.stop
179
+ end
180
+ }
181
+
182
+ expect(@log).to eq([true])
183
+ end
184
+
185
+ end
186
+
187
+
188
+ describe 'notify' do
189
+ it "should execute all progress callbacks in the registration order" do
190
+ @reactor.run {
191
+ @promise.progress do |update|
192
+ @log << :first
193
+ end
194
+
195
+ @promise.progress do |update|
196
+ @log << :second
197
+ end
198
+
199
+ @deferred.notify(:foo)
200
+ }
201
+
202
+ expect(@log).to eq([:first, :second])
203
+ end
204
+
205
+ it "should do nothing if a promise was previously resolved" do
206
+ @reactor.run {
207
+
208
+ @promise.progress do |update|
209
+ @log << update
210
+ end
211
+
212
+ @deferred.resolve(:foo)
213
+ @deferred.notify(:baz)
214
+ }
215
+
216
+ expect(@log).to eq([])
217
+ end
218
+
219
+ it "should do nothing if a promise was previously rejected" do
220
+ @reactor.run {
221
+
222
+ @promise.progress do |update|
223
+ @log << update
224
+ end
225
+ @deferred.reject(:foo)
226
+ @deferred.notify(:baz)
227
+ }
228
+
229
+ expect(@log).to eq([])
230
+ end
231
+
232
+
233
+ it "should not apply any special treatment to promises passed to notify" do
234
+ @reactor.run {
235
+ deferred2 = @reactor.defer
236
+
237
+ @promise.progress do |update|
238
+ @log << update.is_a?(::Libuv::Q::Promise)
239
+ end
240
+ @deferred.notify(deferred2.promise)
241
+ }
242
+
243
+ expect(@log).to eq([true])
244
+ end
245
+
246
+
247
+ it "should call the progress callbacks in the next turn" do
248
+ @reactor.run {
249
+ @promise.progress do |update|
250
+ @log << :first
251
+ end
252
+
253
+ @promise.progress do |update|
254
+ @log << :second
255
+ end
256
+
257
+ @deferred.notify(:foo)
258
+
259
+ @log << @log.length # Has notify run in this tick
260
+ }
261
+
262
+ expect(@log).to eq([0, :first, :second])
263
+ end
264
+
265
+ it "should ignore notifications sent out in the same turn before listener registration" do
266
+ @reactor.run {
267
+ @deferred.notify(:foo)
268
+
269
+ @promise.progress do |update|
270
+ @log << :first
271
+ end
272
+
273
+ @promise.progress do |update|
274
+ @log << :second
275
+ end
276
+ }
277
+
278
+ expect(@log).to eq([])
279
+ end
280
+ end
281
+
282
+
283
+ describe Libuv::Q::Promise do
284
+
285
+ describe 'then' do
286
+
287
+ it "should allow registration of a success callback without an errback and resolve" do
288
+ @reactor.run {
289
+ @promise.then do |result|
290
+ @log << result
291
+ end
292
+
293
+ @deferred.resolve(:foo)
294
+ }
295
+
296
+ expect(@log).to eq([:foo])
297
+ end
298
+
299
+
300
+ it "should allow registration of a success callback without an errback and reject" do
301
+ @reactor.run {
302
+ @promise.then do |result|
303
+ @log << result
304
+ end
305
+
306
+ @deferred.reject(:foo)
307
+ }
308
+
309
+ expect(@log).to eq([])
310
+ end
311
+
312
+
313
+ it "should allow registration of an errback without a success callback and reject" do
314
+ @reactor.run {
315
+ @promise.catch { |reason|
316
+ @log << reason
317
+ }
318
+
319
+ @deferred.reject(:foo)
320
+ }
321
+
322
+ expect(@log).to eq([:foo])
323
+ end
324
+
325
+
326
+ it "should allow registration of an errback without a success callback and resolve" do
327
+ @reactor.run {
328
+ @promise.catch { |reason|
329
+ @log << reason
330
+ }
331
+
332
+ @deferred.resolve(:foo)
333
+ }
334
+
335
+ expect(@log).to eq([])
336
+ end
337
+
338
+
339
+ it "should resolve all callbacks with the original value" do
340
+ @reactor.run {
341
+ @promise.then nil, @default_fail do |result|
342
+ @log << result
343
+ :alt1
344
+ end
345
+ @promise.then nil, @default_fail do |result|
346
+ @log << result
347
+ 'ERROR'
348
+ end
349
+ @promise.then nil, @default_fail do |result|
350
+ @log << result
351
+ Libuv::Q.reject(@reactor, 'some reason')
352
+ end
353
+ @promise.then nil, @default_fail do |result|
354
+ @log << result
355
+ :alt2
356
+ end
357
+
358
+ @deferred.resolve(:foo)
359
+ }
360
+
361
+ expect(@log).to eq([:foo, :foo, :foo, :foo])
362
+ end
363
+
364
+
365
+ it "should notify all callbacks with the original value" do
366
+ @reactor.run { |reactor_promise|
367
+ @promise.progress do |result|
368
+ @log << result
369
+ :alt1
370
+ end
371
+ @promise.progress do |result|
372
+ @log << result
373
+ 'ERROR'
374
+ end
375
+ @promise.progress do |result|
376
+ @log << result
377
+ Libuv::Q.reject(@reactor, 'some reason')
378
+ end
379
+ @promise.progress do |result|
380
+ @log << result
381
+ :alt2
382
+ end
383
+
384
+
385
+ @deferred.notify(:foo)
386
+ }
387
+
388
+ expect(@log).to eq([:foo, :foo, :foo, :foo])
389
+ end
390
+
391
+
392
+ it "should reject all callbacks with the original reason" do
393
+ @reactor.run {
394
+ @promise.then(@default_fail, proc {|result|
395
+ @log << result
396
+ :alt1
397
+ })
398
+ @promise.then(@default_fail, proc {|result|
399
+ @log << result
400
+ 'ERROR'
401
+ })
402
+ @promise.then(@default_fail, proc {|result|
403
+ @log << result
404
+ Libuv::Q.reject(@reactor, 'some reason')
405
+ })
406
+ @promise.then(@default_fail, proc {|result|
407
+ @log << result
408
+ :alt2
409
+ })
410
+
411
+ @deferred.reject(:foo)
412
+ }
413
+
414
+ expect(@log).to eq([:foo, :foo, :foo, :foo])
415
+ end
416
+
417
+
418
+ it "should propagate resolution and rejection between dependent promises" do
419
+ @reactor.run {
420
+ @promise.then(proc { |result|
421
+ @log << result
422
+ :bar
423
+ }, @default_fail).then(proc { |result|
424
+ @log << result
425
+ raise 'baz'
426
+ }, @default_fail).then(@default_fail, proc {|result|
427
+ @log << result.message
428
+ raise 'bob'
429
+ }).then(@default_fail, proc {|result|
430
+ @log << result.message
431
+ :done
432
+ }).then(proc { |result|
433
+ @log << result
434
+ }, @default_fail)
435
+
436
+ @deferred.resolve(:foo)
437
+ }
438
+
439
+ expect(@log).to eq([:foo, :bar, 'baz', 'bob', :done])
440
+ end
441
+
442
+
443
+ it "should propagate notification between dependent promises" do
444
+ @reactor.run { |reactor|
445
+ reactor.notifier do |type, id, error|
446
+ @log << id
447
+ end
448
+
449
+
450
+ @promise.progress { |result|
451
+ @log << result
452
+ :bar
453
+ }.progress { |result|
454
+ @log << result
455
+ result
456
+ }.progress { |result|
457
+ @log << result
458
+ result
459
+ }.progress { |result|
460
+ @log << result
461
+ :done
462
+ }.progress { |result|
463
+ @log << result
464
+ result
465
+ }
466
+
467
+
468
+ @deferred.notify(:foo)
469
+ }
470
+
471
+ expect(@log).to eq([:foo, :bar, :bar, :bar, :done])
472
+ end
473
+
474
+
475
+ it "should stop notification propagation in case of error" do
476
+ @reactor.run { |reactor|
477
+ reactor.notifier do |error, context|
478
+ @log << context
479
+ end
480
+
481
+
482
+ @promise.progress { |result|
483
+ @log << result
484
+ :bar
485
+ }.progress { |result|
486
+ @log << result
487
+ raise 'err'
488
+ result
489
+ }.progress {|result|
490
+ @log << result
491
+ result
492
+ }.progress {|result|
493
+ @log << result
494
+ :done
495
+ }.progress { |result|
496
+ @log << result
497
+ result
498
+ }
499
+
500
+
501
+ @deferred.notify(:foo)
502
+ }
503
+
504
+ expect(@log).to eq([:foo, :bar, "performing promise progress callback"])
505
+ end
506
+
507
+
508
+ it "should call error callback in the next turn even if promise is already rejected" do
509
+ @reactor.run {
510
+ @deferred.reject(:foo)
511
+
512
+ @promise.catch { |reason|
513
+ @log << reason
514
+ }
515
+
516
+ @reactor.next_tick do
517
+ @reactor.stop
518
+ end
519
+ }
520
+
521
+ expect(@log).to eq([:foo])
522
+ end
523
+
524
+
525
+ end
526
+
527
+
528
+ describe 'finally' do
529
+
530
+ describe 'when the promise is fulfilled' do
531
+
532
+ it "should call the callback" do
533
+ @reactor.run {
534
+ @promise.finally do
535
+ @log << :finally
536
+ end
537
+
538
+ @deferred.resolve(:foo)
539
+ }
540
+
541
+ expect(@log).to eq([:finally])
542
+ end
543
+
544
+ it "should fulfill with the original value" do
545
+ @reactor.run {
546
+ @promise.finally {
547
+ @log << :finally
548
+ :finally
549
+ }.then do |result|
550
+ @log << result
551
+ end
552
+
553
+
554
+ @deferred.resolve(:foo)
555
+ }
556
+
557
+ expect(@log).to eq([:finally, :foo])
558
+ end
559
+
560
+ it "should fulfill with the original value (larger test)" do
561
+ @reactor.run {
562
+ @promise.then { |result|
563
+ @log << result
564
+ result
565
+ }.finally {
566
+ @log << :finally
567
+ :finally
568
+ }.then { |result|
569
+ @log << result
570
+ :change
571
+ }.then { |result|
572
+ @log << result
573
+ result
574
+ }.finally {
575
+ @log << :finally
576
+ :finally
577
+ }.then { |result|
578
+ @log << result
579
+ result
580
+ }
581
+
582
+
583
+ @deferred.resolve(:foo)
584
+ }
585
+
586
+ expect(@log).to eq([:foo, :finally, :foo, :change, :finally, :change])
587
+ end
588
+
589
+ describe "when the callback throws an exception" do
590
+ it "should reject with this new exception" do
591
+ @reactor.run {
592
+ @promise.finally {
593
+ @log << :finally
594
+ raise 'error'
595
+ }.catch do |reason|
596
+ @log.push reason.is_a?(Exception)
597
+ end
598
+
599
+ @deferred.resolve(:foo)
600
+ }
601
+
602
+ expect(@log).to eq([:finally, true])
603
+ end
604
+ end
605
+
606
+ describe "when the callback returns a promise" do
607
+ it "should fulfill with the original reason after that promise resolves" do
608
+ @reactor.run {
609
+ deferred2 = @reactor.defer
610
+
611
+ @promise.finally {
612
+ @log << :finally
613
+ deferred2.promise
614
+ }.then do |result|
615
+ @log << result
616
+ end
617
+
618
+ @deferred.resolve(:foo)
619
+
620
+ @reactor.next_tick do
621
+ @reactor.next_tick do
622
+ @reactor.next_tick do
623
+ @reactor.next_tick do
624
+ @log << :resolving
625
+ deferred2.resolve('working')
626
+ end
627
+ end
628
+ end
629
+ end
630
+ }
631
+
632
+ expect(@log).to eq([:finally, :resolving, :foo])
633
+ end
634
+
635
+
636
+ it "should reject with the new reason when it is rejected" do
637
+ @reactor.run {
638
+ deferred2 = @reactor.defer
639
+
640
+ @promise.finally {
641
+ @log << :finally
642
+ deferred2.promise
643
+ }.catch do |result|
644
+ @log << result
645
+ end
646
+
647
+ @deferred.resolve(:foo)
648
+
649
+ @reactor.next_tick do
650
+ @reactor.next_tick do
651
+ @reactor.next_tick do
652
+ @reactor.next_tick do
653
+ @log << :rejecting
654
+ deferred2.reject(:rejected)
655
+ end
656
+ end
657
+ end
658
+ end
659
+ }
660
+
661
+ expect(@log).to eq([:finally, :rejecting, :rejected])
662
+ end
663
+ end
664
+
665
+ end
666
+
667
+ end
668
+
669
+
670
+ describe 'value' do
671
+ it "should resolve a promise value as a future" do
672
+ @reactor.run {
673
+ @reactor.next_tick do
674
+ @deferred.resolve(:foo)
675
+ end
676
+ @log << @deferred.promise.value
677
+ }
678
+
679
+ expect(@log).to eq([:foo])
680
+ end
681
+
682
+ it "should reject a promise value as a future" do
683
+ @reactor.run {
684
+ @reactor.next_tick do
685
+ @deferred.reject(:foo)
686
+ end
687
+
688
+ begin
689
+ @deferred.promise.value
690
+ @log << 'should raise exception'
691
+ rescue => e
692
+ expect(e.class).to eq(CoroutineRejection)
693
+ @log << e.value
694
+ end
695
+ }
696
+
697
+ expect(@log).to eq([:foo])
698
+ end
699
+
700
+ it "should resolve a deferred value as a future" do
701
+ @reactor.run {
702
+ @reactor.next_tick do
703
+ @deferred.resolve(:foo)
704
+ end
705
+ @log << @deferred.value
706
+ }
707
+
708
+ expect(@log).to eq([:foo])
709
+ end
710
+
711
+ it "should reject a deferred value as a future" do
712
+ @reactor.run {
713
+ @reactor.next_tick do
714
+ @deferred.reject(:foo)
715
+ end
716
+
717
+ begin
718
+ @deferred.value
719
+ @log << 'should raise exception'
720
+ rescue => e
721
+ expect(e.class).to eq(CoroutineRejection)
722
+ @log << e.value
723
+ end
724
+ }
725
+
726
+ expect(@log).to eq([:foo])
727
+ end
728
+
729
+ it "should reject with message when rejection was a string" do
730
+ @reactor.run {
731
+ @reactor.next_tick do
732
+ @deferred.reject('foo')
733
+ end
734
+
735
+ begin
736
+ @deferred.value
737
+ @log << 'should raise exception'
738
+ rescue => e
739
+ expect(e.class).to eq(CoroutineRejection)
740
+ @log << e.message
741
+ @log << e.value
742
+ end
743
+ }
744
+
745
+ expect(@log).to eq(['foo', 'foo'])
746
+ end
747
+
748
+ it "should pass through exceptions without modification" do
749
+ @reactor.run {
750
+ @reactor.next_tick do
751
+ @deferred.reject(RuntimeError.new('fail'))
752
+ end
753
+
754
+ begin
755
+ @deferred.value
756
+ @log << 'should raise exception'
757
+ rescue => e
758
+ expect(e.class).to eq(RuntimeError)
759
+ @log << e.message
760
+ end
761
+ }
762
+
763
+ expect(@log).to eq(['fail'])
764
+ end
765
+ end
766
+
767
+ end
768
+
769
+
770
+
771
+ describe 'reject' do
772
+
773
+ it "should package a string into a rejected promise" do
774
+ @reactor.run {
775
+ rejectedPromise = Libuv::Q.reject(@reactor, 'not gonna happen')
776
+
777
+ @promise.then(@default_fail, proc {|reason|
778
+ @log << reason
779
+ })
780
+
781
+ @deferred.resolve(rejectedPromise)
782
+ }
783
+
784
+ expect(@log).to eq(['not gonna happen'])
785
+ end
786
+
787
+
788
+ it "should return a promise that forwards callbacks if the callbacks are missing" do
789
+ @reactor.run {
790
+ rejectedPromise = Libuv::Q.reject(@reactor, 'not gonna happen')
791
+
792
+ @promise.then(@default_fail, proc {|reason|
793
+ @log << reason
794
+ })
795
+
796
+ @deferred.resolve(rejectedPromise.then())
797
+ }
798
+
799
+ expect(@log).to eq(['not gonna happen'])
800
+ end
801
+
802
+ end
803
+
804
+
805
+
806
+ describe 'all' do
807
+
808
+ it "should resolve all of nothing" do
809
+ @reactor.run {
810
+ Libuv::Q.all(@reactor).then nil, @default_fail do |result|
811
+ @log << result
812
+ end
813
+ }
814
+
815
+ expect(@log).to eq([[]])
816
+ end
817
+
818
+ it "should take an array of promises and return a promise for an array of results" do
819
+ @reactor.run {
820
+ deferred1 = @reactor.defer
821
+ deferred2 = @reactor.defer
822
+
823
+ Libuv::Q.all(@reactor, @promise, deferred1.promise, deferred2.promise).then nil, @default_fail do |result|
824
+ @log = result
825
+ end
826
+
827
+ @reactor.work { @deferred.resolve(:foo) }
828
+ @reactor.work { deferred2.resolve(:baz) }
829
+ @reactor.work { deferred1.resolve(:bar) }
830
+ }
831
+
832
+ expect(@log).to eq([:foo, :bar, :baz])
833
+ end
834
+
835
+
836
+ it "should reject the derived promise if at least one of the promises in the array is rejected" do
837
+ @reactor.run {
838
+ deferred1 = @reactor.defer
839
+ deferred2 = @reactor.defer
840
+
841
+ Libuv::Q.all(@reactor, @promise, deferred1.promise, deferred2.promise).then(@default_fail, proc {|reason|
842
+ @log << reason
843
+ })
844
+
845
+ @reactor.work { @deferred.resolve(:foo) }
846
+ @reactor.work { deferred2.reject(:baz) }
847
+ }
848
+
849
+ expect(@log).to eq([:baz])
850
+ end
851
+
852
+ end
853
+
854
+ describe 'any' do
855
+
856
+ it "should resolve any of nothing" do
857
+ @reactor.run {
858
+ Libuv::Q.any(@reactor).then nil, @default_fail do |result|
859
+ @log = result
860
+ end
861
+ }
862
+
863
+ expect(@log).to eq(true)
864
+ end
865
+
866
+ it "should take an array of promises and return the first to succeed" do
867
+ @reactor.run {
868
+ deferred1 = @reactor.defer
869
+ deferred2 = @reactor.defer
870
+
871
+ Libuv::Q.any(@reactor, @promise, deferred1.promise, deferred2.promise).then nil, @default_fail do |result|
872
+ @log = result
873
+ end
874
+
875
+ @reactor.work {
876
+ @deferred.resolve(:foo)
877
+ deferred2.resolve(:baz)
878
+ deferred1.resolve(:bar)
879
+ }
880
+ }
881
+
882
+ expect(@log).to eq(:foo)
883
+ end
884
+
885
+
886
+ it "should take an array of promises and return the first to fail" do
887
+ @reactor.run {
888
+ deferred1 = @reactor.defer
889
+ deferred2 = @reactor.defer
890
+
891
+ Libuv::Q.any(@reactor, @promise, deferred1.promise, deferred2.promise).then(@default_fail, proc { |result|
892
+ @log = result
893
+ })
894
+
895
+ @reactor.work {
896
+ @deferred.reject(:foo)
897
+ deferred2.resolve(:baz)
898
+ }
899
+ }
900
+
901
+ expect(@log).to eq(:foo)
902
+ end
903
+
904
+ end
855
905
 
856
906
  end