14
14
* See the License for the specific language governing permissions and
15
15
* limitations under the License.
16
16
*/
17
- import { assert , expect } from 'chai' ;
17
+ import { assert , expect , use } from 'chai' ;
18
18
import { FbsBlob } from '../../src/implementation/blob' ;
19
19
import { Location } from '../../src/implementation/location' ;
20
20
import { Unsubscribe } from '../../src/implementation/observer' ;
@@ -31,8 +31,12 @@ import {
31
31
} from './testshared' ;
32
32
import { injectTestConnection } from '../../src/platform/connection' ;
33
33
import { Deferred } from '@firebase/util' ;
34
- import { retryLimitExceeded } from '../../src/implementation/error' ;
34
+ import { canceled , retryLimitExceeded } from '../../src/implementation/error' ;
35
35
import { SinonFakeTimers , useFakeTimers } from 'sinon' ;
36
+ import * as sinon from 'sinon' ;
37
+ import sinonChai from 'sinon-chai' ;
38
+
39
+ use ( sinonChai ) ;
36
40
37
41
const testLocation = new Location ( 'bucket' , 'object' ) ;
38
42
const smallBlob = new FbsBlob ( new Uint8Array ( [ 97 ] ) ) ;
@@ -361,7 +365,7 @@ describe('Firebase Storage > Upload Task', () => {
361
365
function handleStateChange (
362
366
requestHandler : RequestHandler ,
363
367
blob : FbsBlob
364
- ) : Promise < TotalState > {
368
+ ) : { promise : Promise < TotalState > ; task : UploadTask } {
365
369
const storageService = storageServiceWithHandler ( requestHandler ) ;
366
370
const task = new UploadTask (
367
371
new Reference ( storageService , testLocation ) ,
@@ -410,7 +414,7 @@ describe('Firebase Storage > Upload Task', () => {
410
414
}
411
415
) ;
412
416
413
- return deferred . promise ;
417
+ return { promise : deferred . promise , task } ;
414
418
}
415
419
416
420
it ( 'Calls callback sequences for small uploads correctly' , ( ) => {
@@ -422,7 +426,7 @@ describe('Firebase Storage > Upload Task', () => {
422
426
it ( 'properly times out if large blobs returns a 503 when finalizing' , async ( ) => {
423
427
clock = useFakeTimers ( ) ;
424
428
// Kick off upload
425
- const promise = handleStateChange (
429
+ const { promise } = handleStateChange (
426
430
fake503ForFinalizeServerHandler ( ) ,
427
431
bigBlob
428
432
) ;
@@ -460,7 +464,10 @@ describe('Firebase Storage > Upload Task', () => {
460
464
it ( 'properly times out if large blobs returns a 503 when uploading' , async ( ) => {
461
465
clock = useFakeTimers ( ) ;
462
466
// Kick off upload
463
- const promise = handleStateChange ( fake503ForUploadServerHandler ( ) , bigBlob ) ;
467
+ const { promise } = handleStateChange (
468
+ fake503ForUploadServerHandler ( ) ,
469
+ bigBlob
470
+ ) ;
464
471
// Run all timers
465
472
await clock . runAllAsync ( ) ;
466
473
const { events, progress } = await promise ;
@@ -478,10 +485,112 @@ describe('Firebase Storage > Upload Task', () => {
478
485
} ) ;
479
486
clock . restore ( ) ;
480
487
} ) ;
488
+ function resumeCancelSetup ( ) : any {
489
+ clock = useFakeTimers ( ) ;
490
+ const fakeSetTimeout = clock . setTimeout ;
491
+ let gotFirstEvent = false ;
492
+
493
+ const stub = sinon . stub ( global , 'setTimeout' ) ;
494
+
495
+ const timers : { [ key : number ] : any } = { } ;
496
+ const readyToCancel = new Promise ( resolve => {
497
+ stub . callsFake ( ( fn , timeout ) => {
498
+ // @ts -ignore
499
+ const res = fakeSetTimeout ( fn , timeout ) ;
500
+ //@ts -ignore
501
+ timers [ res . id ] = {
502
+ data : res ,
503
+ timeout
504
+ } ;
505
+ if ( ( ! gotFirstEvent || timeout === 0 ) && timeout !== 600000 ) {
506
+ clock . tick ( timeout as number ) ;
507
+ } else if ( timeout !== 600000 ) {
508
+ resolve ( null ) ;
509
+ }
510
+ return res ;
511
+ } ) ;
512
+ } ) ;
513
+ readyToCancel . then (
514
+ ( ) => stub . restore ( ) ,
515
+ ( ) => { }
516
+ ) ;
517
+ return {
518
+ ...handleStateChange (
519
+ fake503ForUploadServerHandler ( undefined , ( ) => ( gotFirstEvent = true ) ) ,
520
+ bigBlob
521
+ ) ,
522
+ readyToCancel
523
+ } ;
524
+ }
525
+ it ( 'properly errors with a cancel StorageError if a pending timeout remains' , async ( ) => {
526
+ // Kick off upload
527
+ const { readyToCancel, promise, task } = resumeCancelSetup ( ) ;
528
+
529
+ await readyToCancel ;
530
+ task . cancel ( ) ;
531
+
532
+ // Run all timers
533
+ const { events, progress } = await promise ;
534
+ expect ( events . length ) . to . equal ( 2 ) ;
535
+ expect ( events [ 0 ] ) . to . deep . equal ( { type : 'resume' } ) ;
536
+ expect ( events [ 1 ] . type ) . to . deep . equal ( 'error' ) ;
537
+ const canceledError = canceled ( ) ;
538
+ expect ( events [ 1 ] . data ! . name ) . to . deep . equal ( canceledError . name ) ;
539
+ expect ( events [ 1 ] . data ! . message ) . to . deep . equal ( canceledError . message ) ;
540
+ const blobSize = bigBlob . size ( ) ;
541
+ expect ( progress . length ) . to . equal ( 1 ) ;
542
+ expect ( progress [ 0 ] ) . to . deep . equal ( {
543
+ bytesTransferred : 0 ,
544
+ totalBytes : blobSize
545
+ } ) ;
546
+ expect ( clock . countTimers ( ) ) . to . eq ( 0 ) ;
547
+ clock . restore ( ) ;
548
+ } ) ;
549
+ it ( 'properly errors with a pause StorageError if a pending timeout remains' , async ( ) => {
550
+ // Kick off upload
551
+ const { readyToCancel, promise, task } = resumeCancelSetup ( ) ;
552
+
553
+ await readyToCancel ;
554
+
555
+ task . pause ( ) ;
556
+ expect ( clock . countTimers ( ) ) . to . eq ( 0 ) ;
557
+ task . resume ( ) ;
558
+ await clock . runAllAsync ( ) ;
559
+
560
+ // Run all timers
561
+ const { events, progress } = await promise ;
562
+ expect ( events . length ) . to . equal ( 4 ) ;
563
+ expect ( events [ 0 ] ) . to . deep . equal ( { type : 'resume' } ) ;
564
+ expect ( events [ 1 ] ) . to . deep . equal ( { type : 'pause' } ) ;
565
+ expect ( events [ 2 ] ) . to . deep . equal ( { type : 'resume' } ) ;
566
+ expect ( events [ 3 ] . type ) . to . deep . equal ( 'error' ) ;
567
+ const retryError = retryLimitExceeded ( ) ;
568
+ expect ( events [ 3 ] . data ! . name ) . to . deep . equal ( retryError . name ) ;
569
+ expect ( events [ 3 ] . data ! . message ) . to . deep . equal ( retryError . message ) ;
570
+ const blobSize = bigBlob . size ( ) ;
571
+ expect ( progress . length ) . to . equal ( 3 ) ;
572
+ expect ( progress [ 0 ] ) . to . deep . equal ( {
573
+ bytesTransferred : 0 ,
574
+ totalBytes : blobSize
575
+ } ) ;
576
+ expect ( progress [ 1 ] ) . to . deep . equal ( {
577
+ bytesTransferred : 0 ,
578
+ totalBytes : blobSize
579
+ } ) ;
580
+ expect ( progress [ 2 ] ) . to . deep . equal ( {
581
+ bytesTransferred : 0 ,
582
+ totalBytes : blobSize
583
+ } ) ;
584
+ expect ( clock . countTimers ( ) ) . to . eq ( 0 ) ;
585
+ clock . restore ( ) ;
586
+ } ) ;
481
587
it ( 'tests if small requests that respond with 500 retry correctly' , async ( ) => {
482
588
clock = useFakeTimers ( ) ;
483
589
// Kick off upload
484
- const promise = handleStateChange ( fakeOneShot503ServerHandler ( ) , smallBlob ) ;
590
+ const { promise } = handleStateChange (
591
+ fakeOneShot503ServerHandler ( ) ,
592
+ smallBlob
593
+ ) ;
485
594
// Run all timers
486
595
await clock . runAllAsync ( ) ;
487
596
const { events, progress } = await promise ;
0 commit comments