@@ -277,8 +277,7 @@ describeSpec('Existence Filters:', [], () => {
277
277
*/
278
278
specTest (
279
279
'Full re-query is skipped when bloom filter can identify documents deleted' ,
280
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
281
- [ 'no-ios' ] ,
280
+ [ ] ,
282
281
( ) => {
283
282
const query1 = query ( 'collection' ) ;
284
283
const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -310,8 +309,7 @@ describeSpec('Existence Filters:', [], () => {
310
309
311
310
specTest (
312
311
'Full re-query is triggered when bloom filter can not identify documents deleted' ,
313
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
314
- [ 'no-ios' ] ,
312
+ [ ] ,
315
313
( ) => {
316
314
const query1 = query ( 'collection' ) ;
317
315
const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -343,8 +341,7 @@ describeSpec('Existence Filters:', [], () => {
343
341
344
342
specTest (
345
343
'Bloom filter can process special characters in document name' ,
346
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
347
- [ 'no-ios' ] ,
344
+ [ ] ,
348
345
( ) => {
349
346
const query1 = query ( 'collection' ) ;
350
347
const docA = doc ( 'collection/ÀÒ∑' , 1000 , { v : 1 } ) ;
@@ -372,8 +369,7 @@ describeSpec('Existence Filters:', [], () => {
372
369
373
370
specTest (
374
371
'Bloom filter fills in default values for undefined padding and hashCount' ,
375
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
376
- [ 'no-ios' ] ,
372
+ [ ] ,
377
373
( ) => {
378
374
const query1 = query ( 'collection' ) ;
379
375
const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -411,7 +407,6 @@ describeSpec('Existence Filters:', [], () => {
411
407
// Skip this test on Android and iOS because those platforms get the raw
412
408
// bytes of the bloom filter and, therefore, are not subject to base64
413
409
// decoding errors.
414
- [ 'no-ios' , 'no-android' ] ,
415
410
( ) => {
416
411
const query1 = query ( 'collection' ) ;
417
412
const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -445,8 +440,7 @@ describeSpec('Existence Filters:', [], () => {
445
440
446
441
specTest (
447
442
'Full re-query is triggered when bloom filter hashCount is invalid' ,
448
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
449
- [ 'no-ios' ] ,
443
+ [ ] ,
450
444
( ) => {
451
445
const query1 = query ( 'collection' ) ;
452
446
const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -478,187 +472,162 @@ describeSpec('Existence Filters:', [], () => {
478
472
}
479
473
) ;
480
474
481
- specTest (
482
- 'Full re-query is triggered when bloom filter is empty' ,
483
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
484
- [ 'no-ios' ] ,
485
- ( ) => {
486
- const query1 = query ( 'collection' ) ;
487
- const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
488
- const docB = doc ( 'collection/b' , 1000 , { v : 1 } ) ;
489
-
490
- //Generate an empty bloom filter.
491
- const bloomFilterProto = generateBloomFilterProto ( {
492
- contains : [ ] ,
493
- notContains : [ ] ,
494
- bitCount : 0 ,
495
- hashCount : 0
496
- } ) ;
497
-
498
- return (
499
- spec ( )
500
- . userListens ( query1 )
501
- . watchAcksFull ( query1 , 1000 , docA , docB )
502
- . expectEvents ( query1 , { added : [ docA , docB ] } )
503
- // DocB is deleted in the next sync.
504
- . watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
505
- . watchSnapshots ( 2000 )
506
- // Re-run query is triggered.
507
- . expectEvents ( query1 , { fromCache : true } )
508
- . expectActiveTargets ( {
509
- query : query1 ,
510
- resumeToken : '' ,
511
- targetPurpose : TargetPurpose . ExistenceFilterMismatch
512
- } )
513
- ) ;
514
- }
515
- ) ;
475
+ specTest ( 'Full re-query is triggered when bloom filter is empty' , [ ] , ( ) => {
476
+ const query1 = query ( 'collection' ) ;
477
+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
478
+ const docB = doc ( 'collection/b' , 1000 , { v : 1 } ) ;
516
479
517
- specTest (
518
- 'Same documents can have different bloom filters' ,
519
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
520
- [ 'no-ios' ] ,
521
- ( ) => {
522
- const query1 = query ( 'collection' , filter ( 'v' , '<=' , 2 ) ) ;
523
- const query2 = query ( 'collection' , filter ( 'v' , '>=' , 2 ) ) ;
480
+ //Generate an empty bloom filter.
481
+ const bloomFilterProto = generateBloomFilterProto ( {
482
+ contains : [ ] ,
483
+ notContains : [ ] ,
484
+ bitCount : 0 ,
485
+ hashCount : 0
486
+ } ) ;
524
487
525
- const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
526
- const docB = doc ( 'collection/b' , 1000 , { v : 2 } ) ;
527
- const docC = doc ( 'collection/c' , 1000 , { v : 3 } ) ;
488
+ return (
489
+ spec ( )
490
+ . userListens ( query1 )
491
+ . watchAcksFull ( query1 , 1000 , docA , docB )
492
+ . expectEvents ( query1 , { added : [ docA , docB ] } )
493
+ // DocB is deleted in the next sync.
494
+ . watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
495
+ . watchSnapshots ( 2000 )
496
+ // Re-run query is triggered.
497
+ . expectEvents ( query1 , { fromCache : true } )
498
+ . expectActiveTargets ( {
499
+ query : query1 ,
500
+ resumeToken : '' ,
501
+ targetPurpose : TargetPurpose . ExistenceFilterMismatch
502
+ } )
503
+ ) ;
504
+ } ) ;
528
505
529
- const bloomFilterProto1 = generateBloomFilterProto ( {
530
- contains : [ docB ] ,
531
- notContains : [ docA , docC ] ,
532
- bitCount : 5 ,
533
- hashCount : 2
534
- } ) ;
535
- const bloomFilterProto2 = generateBloomFilterProto ( {
536
- contains : [ docB ] ,
537
- notContains : [ docA , docC ] ,
538
- bitCount : 4 ,
539
- hashCount : 1
540
- } ) ;
541
- return (
542
- spec ( )
543
- . userListens ( query1 )
544
- . watchAcksFull ( query1 , 1000 , docA , docB )
545
- . expectEvents ( query1 , { added : [ docA , docB ] } )
546
- . userListens ( query2 )
547
- . expectEvents ( query2 , { added : [ docB ] , fromCache : true } )
548
- . watchAcksFull ( query2 , 1001 , docB , docC )
549
- . expectEvents ( query2 , { added : [ docC ] } )
506
+ specTest ( 'Same documents can have different bloom filters' , [ ] , ( ) => {
507
+ const query1 = query ( 'collection' , filter ( 'v' , '<=' , 2 ) ) ;
508
+ const query2 = query ( 'collection' , filter ( 'v' , '>=' , 2 ) ) ;
550
509
551
- // DocA is deleted in the next sync for query1.
552
- . watchFilters ( [ query1 ] , [ docB . key ] , bloomFilterProto1 )
553
- . watchSnapshots ( 2000 )
554
- // BloomFilter identify docA is deleted, skip full query.
555
- . expectEvents ( query1 , { fromCache : true } )
556
- . expectLimboDocs ( docA . key ) // DocA is now in limbo.
557
-
558
- // DocC is deleted in the next sync for query2.
559
- . watchFilters ( [ query2 ] , [ docB . key ] , bloomFilterProto2 )
560
- . watchSnapshots ( 3000 )
561
- // BloomFilter identify docC is deleted, skip full query.
562
- . expectEvents ( query2 , { fromCache : true } )
563
- . expectLimboDocs ( docA . key , docC . key ) // DocC is now in limbo.
564
- ) ;
565
- }
566
- ) ;
510
+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
511
+ const docB = doc ( 'collection/b' , 1000 , { v : 2 } ) ;
512
+ const docC = doc ( 'collection/c' , 1000 , { v : 3 } ) ;
513
+
514
+ const bloomFilterProto1 = generateBloomFilterProto ( {
515
+ contains : [ docB ] ,
516
+ notContains : [ docA , docC ] ,
517
+ bitCount : 5 ,
518
+ hashCount : 2
519
+ } ) ;
520
+ const bloomFilterProto2 = generateBloomFilterProto ( {
521
+ contains : [ docB ] ,
522
+ notContains : [ docA , docC ] ,
523
+ bitCount : 4 ,
524
+ hashCount : 1
525
+ } ) ;
526
+ return (
527
+ spec ( )
528
+ . userListens ( query1 )
529
+ . watchAcksFull ( query1 , 1000 , docA , docB )
530
+ . expectEvents ( query1 , { added : [ docA , docB ] } )
531
+ . userListens ( query2 )
532
+ . expectEvents ( query2 , { added : [ docB ] , fromCache : true } )
533
+ . watchAcksFull ( query2 , 1001 , docB , docC )
534
+ . expectEvents ( query2 , { added : [ docC ] } )
567
535
568
- specTest (
569
- 'Bloom filter is handled at global snapshot' ,
570
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
571
- [ 'no-ios' ] ,
572
- ( ) => {
573
- const query1 = query ( 'collection' ) ;
574
- const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
575
- const docB = doc ( 'collection/b' , 2000 , { v : 2 } ) ;
576
- const docC = doc ( 'collection/c' , 3000 , { v : 3 } ) ;
536
+ // DocA is deleted in the next sync for query1.
537
+ . watchFilters ( [ query1 ] , [ docB . key ] , bloomFilterProto1 )
538
+ . watchSnapshots ( 2000 )
539
+ // BloomFilter identify docA is deleted, skip full query.
540
+ . expectEvents ( query1 , { fromCache : true } )
541
+ . expectLimboDocs ( docA . key ) // DocA is now in limbo.
542
+
543
+ // DocC is deleted in the next sync for query2.
544
+ . watchFilters ( [ query2 ] , [ docB . key ] , bloomFilterProto2 )
545
+ . watchSnapshots ( 3000 )
546
+ // BloomFilter identify docC is deleted, skip full query.
547
+ . expectEvents ( query2 , { fromCache : true } )
548
+ . expectLimboDocs ( docA . key , docC . key ) // DocC is now in limbo.
549
+ ) ;
550
+ } ) ;
577
551
578
- const bloomFilterProto = generateBloomFilterProto ( {
579
- contains : [ docA ] ,
580
- notContains : [ docB ]
581
- } ) ;
552
+ specTest ( 'Bloom filter is handled at global snapshot' , [ ] , ( ) => {
553
+ const query1 = query ( 'collection' ) ;
554
+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
555
+ const docB = doc ( 'collection/b' , 2000 , { v : 2 } ) ;
556
+ const docC = doc ( 'collection/c' , 3000 , { v : 3 } ) ;
582
557
583
- return (
584
- spec ( )
585
- . userListens ( query1 )
586
- . watchAcksFull ( query1 , 1000 , docA , docB )
587
- . expectEvents ( query1 , { added : [ docA , docB ] } )
588
- // Send a mismatching existence filter with one document, but don't
589
- // send a new global snapshot. We should not see an event until we
590
- // receive the snapshot.
591
- . watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
592
- . watchSends ( { affects : [ query1 ] } , docC )
593
- . watchSnapshots ( 2000 )
594
- . expectEvents ( query1 , { added : [ docC ] , fromCache : true } )
595
- // Re-run of the query1 is skipped, docB is in limbo.
596
- . expectLimboDocs ( docB . key )
597
- ) ;
598
- }
599
- ) ;
558
+ const bloomFilterProto = generateBloomFilterProto ( {
559
+ contains : [ docA ] ,
560
+ notContains : [ docB ]
561
+ } ) ;
600
562
601
- specTest (
602
- 'Bloom filter limbo resolution is denied' ,
603
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
604
- [ 'no-ios' ] ,
605
- ( ) => {
606
- const query1 = query ( 'collection' ) ;
607
- const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
608
- const docB = doc ( 'collection/b' , 1000 , { v : 1 } ) ;
609
- const bloomFilterProto = generateBloomFilterProto ( {
610
- contains : [ docA ] ,
611
- notContains : [ docB ]
612
- } ) ;
613
- return spec ( )
563
+ return (
564
+ spec ( )
614
565
. userListens ( query1 )
615
566
. watchAcksFull ( query1 , 1000 , docA , docB )
616
567
. expectEvents ( query1 , { added : [ docA , docB ] } )
568
+ // Send a mismatching existence filter with one document, but don't
569
+ // send a new global snapshot. We should not see an event until we
570
+ // receive the snapshot.
617
571
. watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
572
+ . watchSends ( { affects : [ query1 ] } , docC )
618
573
. watchSnapshots ( 2000 )
619
- . expectEvents ( query1 , { fromCache : true } )
620
- . expectLimboDocs ( docB . key ) // DocB is now in limbo.
621
- . watchRemoves (
622
- newQueryForPath ( docB . key . path ) ,
623
- new RpcError ( Code . PERMISSION_DENIED , 'no' )
624
- )
625
- . expectLimboDocs ( ) // DocB is no longer in limbo.
626
- . expectEvents ( query1 , {
627
- removed : [ docB ]
628
- } ) ;
629
- }
630
- ) ;
631
-
632
- specTest (
633
- 'Bloom filter with large size works as expected' ,
634
- // TODO(b/278759251) Remove 'no-ios' once bloom filter is merged.
635
- [ 'no-ios' ] ,
636
- ( ) => {
637
- const query1 = query ( 'collection' ) ;
638
- const docs = [ ] ;
639
- for ( let i = 0 ; i < 100 ; i ++ ) {
640
- docs . push ( doc ( `collection/doc${ i } ` , 1000 , { v : 1 } ) ) ;
641
- }
642
- const docKeys = docs . map ( item => item . key ) ;
574
+ . expectEvents ( query1 , { added : [ docC ] , fromCache : true } )
575
+ // Re-run of the query1 is skipped, docB is in limbo.
576
+ . expectLimboDocs ( docB . key )
577
+ ) ;
578
+ } ) ;
643
579
644
- const bloomFilterProto = generateBloomFilterProto ( {
645
- contains : docs . slice ( 0 , 50 ) ,
646
- notContains : docs . slice ( 50 ) ,
647
- bitCount : 1000 ,
648
- hashCount : 16
580
+ specTest ( 'Bloom filter limbo resolution is denied' , [ ] , ( ) => {
581
+ const query1 = query ( 'collection' ) ;
582
+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
583
+ const docB = doc ( 'collection/b' , 1000 , { v : 1 } ) ;
584
+ const bloomFilterProto = generateBloomFilterProto ( {
585
+ contains : [ docA ] ,
586
+ notContains : [ docB ]
587
+ } ) ;
588
+ return spec ( )
589
+ . userListens ( query1 )
590
+ . watchAcksFull ( query1 , 1000 , docA , docB )
591
+ . expectEvents ( query1 , { added : [ docA , docB ] } )
592
+ . watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
593
+ . watchSnapshots ( 2000 )
594
+ . expectEvents ( query1 , { fromCache : true } )
595
+ . expectLimboDocs ( docB . key ) // DocB is now in limbo.
596
+ . watchRemoves (
597
+ newQueryForPath ( docB . key . path ) ,
598
+ new RpcError ( Code . PERMISSION_DENIED , 'no' )
599
+ )
600
+ . expectLimboDocs ( ) // DocB is no longer in limbo.
601
+ . expectEvents ( query1 , {
602
+ removed : [ docB ]
649
603
} ) ;
650
- return (
651
- spec ( )
652
- . userListens ( query1 )
653
- . watchAcksFull ( query1 , 1000 , ...docs )
654
- . expectEvents ( query1 , { added : docs } )
655
- // Doc0 to doc49 are deleted in the next sync.
656
- . watchFilters ( [ query1 ] , docKeys . slice ( 0 , 50 ) , bloomFilterProto )
657
- . watchSnapshots ( 2000 )
658
- // BloomFilter correctly identifies docs that deleted, skip full query.
659
- . expectEvents ( query1 , { fromCache : true } )
660
- . expectLimboDocs ( ...docKeys . slice ( 50 ) )
661
- ) ;
604
+ } ) ;
605
+
606
+ specTest ( 'Bloom filter with large size works as expected' , [ ] , ( ) => {
607
+ const query1 = query ( 'collection' ) ;
608
+ const docs = [ ] ;
609
+ for ( let i = 0 ; i < 100 ; i ++ ) {
610
+ docs . push ( doc ( `collection/doc${ i } ` , 1000 , { v : 1 } ) ) ;
662
611
}
663
- ) ;
612
+ const docKeys = docs . map ( item => item . key ) ;
613
+
614
+ const bloomFilterProto = generateBloomFilterProto ( {
615
+ contains : docs . slice ( 0 , 50 ) ,
616
+ notContains : docs . slice ( 50 ) ,
617
+ bitCount : 1000 ,
618
+ hashCount : 16
619
+ } ) ;
620
+ return (
621
+ spec ( )
622
+ . userListens ( query1 )
623
+ . watchAcksFull ( query1 , 1000 , ...docs )
624
+ . expectEvents ( query1 , { added : docs } )
625
+ // Doc0 to doc49 are deleted in the next sync.
626
+ . watchFilters ( [ query1 ] , docKeys . slice ( 0 , 50 ) , bloomFilterProto )
627
+ . watchSnapshots ( 2000 )
628
+ // BloomFilter correctly identifies docs that deleted, skip full query.
629
+ . expectEvents ( query1 , { fromCache : true } )
630
+ . expectLimboDocs ( ...docKeys . slice ( 50 ) )
631
+ ) ;
632
+ } ) ;
664
633
} ) ;
0 commit comments