@@ -277,8 +277,7 @@ describeSpec('Existence Filters:', [], () => {
277277 */
278278 specTest (
279279 '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+ [ ] ,
282281 ( ) => {
283282 const query1 = query ( 'collection' ) ;
284283 const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -310,8 +309,7 @@ describeSpec('Existence Filters:', [], () => {
310309
311310 specTest (
312311 '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+ [ ] ,
315313 ( ) => {
316314 const query1 = query ( 'collection' ) ;
317315 const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -343,8 +341,7 @@ describeSpec('Existence Filters:', [], () => {
343341
344342 specTest (
345343 '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+ [ ] ,
348345 ( ) => {
349346 const query1 = query ( 'collection' ) ;
350347 const docA = doc ( 'collection/ÀÒ∑' , 1000 , { v : 1 } ) ;
@@ -372,8 +369,7 @@ describeSpec('Existence Filters:', [], () => {
372369
373370 specTest (
374371 '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+ [ ] ,
377373 ( ) => {
378374 const query1 = query ( 'collection' ) ;
379375 const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -445,8 +441,7 @@ describeSpec('Existence Filters:', [], () => {
445441
446442 specTest (
447443 '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' ] ,
444+ [ ] ,
450445 ( ) => {
451446 const query1 = query ( 'collection' ) ;
452447 const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
@@ -478,187 +473,162 @@ describeSpec('Existence Filters:', [], () => {
478473 }
479474 ) ;
480475
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- ) ;
476+ specTest ( 'Full re-query is triggered when bloom filter is empty' , [ ] , ( ) => {
477+ const query1 = query ( 'collection' ) ;
478+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
479+ const docB = doc ( 'collection/b' , 1000 , { v : 1 } ) ;
516480
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 ) ) ;
481+ //Generate an empty bloom filter.
482+ const bloomFilterProto = generateBloomFilterProto ( {
483+ contains : [ ] ,
484+ notContains : [ ] ,
485+ bitCount : 0 ,
486+ hashCount : 0
487+ } ) ;
524488
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 } ) ;
489+ return (
490+ spec ( )
491+ . userListens ( query1 )
492+ . watchAcksFull ( query1 , 1000 , docA , docB )
493+ . expectEvents ( query1 , { added : [ docA , docB ] } )
494+ // DocB is deleted in the next sync.
495+ . watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
496+ . watchSnapshots ( 2000 )
497+ // Re-run query is triggered.
498+ . expectEvents ( query1 , { fromCache : true } )
499+ . expectActiveTargets ( {
500+ query : query1 ,
501+ resumeToken : '' ,
502+ targetPurpose : TargetPurpose . ExistenceFilterMismatch
503+ } )
504+ ) ;
505+ } ) ;
528506
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 ] } )
507+ specTest ( 'Same documents can have different bloom filters' , [ ] , ( ) => {
508+ const query1 = query ( 'collection' , filter ( 'v' , '<=' , 2 ) ) ;
509+ const query2 = query ( 'collection' , filter ( 'v' , '>=' , 2 ) ) ;
550510
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- ) ;
511+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
512+ const docB = doc ( 'collection/b' , 1000 , { v : 2 } ) ;
513+ const docC = doc ( 'collection/c' , 1000 , { v : 3 } ) ;
514+
515+ const bloomFilterProto1 = generateBloomFilterProto ( {
516+ contains : [ docB ] ,
517+ notContains : [ docA , docC ] ,
518+ bitCount : 5 ,
519+ hashCount : 2
520+ } ) ;
521+ const bloomFilterProto2 = generateBloomFilterProto ( {
522+ contains : [ docB ] ,
523+ notContains : [ docA , docC ] ,
524+ bitCount : 4 ,
525+ hashCount : 1
526+ } ) ;
527+ return (
528+ spec ( )
529+ . userListens ( query1 )
530+ . watchAcksFull ( query1 , 1000 , docA , docB )
531+ . expectEvents ( query1 , { added : [ docA , docB ] } )
532+ . userListens ( query2 )
533+ . expectEvents ( query2 , { added : [ docB ] , fromCache : true } )
534+ . watchAcksFull ( query2 , 1001 , docB , docC )
535+ . expectEvents ( query2 , { added : [ docC ] } )
567536
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 } ) ;
537+ // DocA is deleted in the next sync for query1.
538+ . watchFilters ( [ query1 ] , [ docB . key ] , bloomFilterProto1 )
539+ . watchSnapshots ( 2000 )
540+ // BloomFilter identify docA is deleted, skip full query.
541+ . expectEvents ( query1 , { fromCache : true } )
542+ . expectLimboDocs ( docA . key ) // DocA is now in limbo.
543+
544+ // DocC is deleted in the next sync for query2.
545+ . watchFilters ( [ query2 ] , [ docB . key ] , bloomFilterProto2 )
546+ . watchSnapshots ( 3000 )
547+ // BloomFilter identify docC is deleted, skip full query.
548+ . expectEvents ( query2 , { fromCache : true } )
549+ . expectLimboDocs ( docA . key , docC . key ) // DocC is now in limbo.
550+ ) ;
551+ } ) ;
577552
578- const bloomFilterProto = generateBloomFilterProto ( {
579- contains : [ docA ] ,
580- notContains : [ docB ]
581- } ) ;
553+ specTest ( 'Bloom filter is handled at global snapshot' , [ ] , ( ) => {
554+ const query1 = query ( 'collection' ) ;
555+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
556+ const docB = doc ( 'collection/b' , 2000 , { v : 2 } ) ;
557+ const docC = doc ( 'collection/c' , 3000 , { v : 3 } ) ;
582558
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- ) ;
559+ const bloomFilterProto = generateBloomFilterProto ( {
560+ contains : [ docA ] ,
561+ notContains : [ docB ]
562+ } ) ;
600563
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 ( )
564+ return (
565+ spec ( )
614566 . userListens ( query1 )
615567 . watchAcksFull ( query1 , 1000 , docA , docB )
616568 . expectEvents ( query1 , { added : [ docA , docB ] } )
569+ // Send a mismatching existence filter with one document, but don't
570+ // send a new global snapshot. We should not see an event until we
571+ // receive the snapshot.
617572 . watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
573+ . watchSends ( { affects : [ query1 ] } , docC )
618574 . 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 ) ;
575+ . expectEvents ( query1 , { added : [ docC ] , fromCache : true } )
576+ // Re-run of the query1 is skipped, docB is in limbo.
577+ . expectLimboDocs ( docB . key )
578+ ) ;
579+ } ) ;
643580
644- const bloomFilterProto = generateBloomFilterProto ( {
645- contains : docs . slice ( 0 , 50 ) ,
646- notContains : docs . slice ( 50 ) ,
647- bitCount : 1000 ,
648- hashCount : 16
581+ specTest ( 'Bloom filter limbo resolution is denied' , [ ] , ( ) => {
582+ const query1 = query ( 'collection' ) ;
583+ const docA = doc ( 'collection/a' , 1000 , { v : 1 } ) ;
584+ const docB = doc ( 'collection/b' , 1000 , { v : 1 } ) ;
585+ const bloomFilterProto = generateBloomFilterProto ( {
586+ contains : [ docA ] ,
587+ notContains : [ docB ]
588+ } ) ;
589+ return spec ( )
590+ . userListens ( query1 )
591+ . watchAcksFull ( query1 , 1000 , docA , docB )
592+ . expectEvents ( query1 , { added : [ docA , docB ] } )
593+ . watchFilters ( [ query1 ] , [ docA . key ] , bloomFilterProto )
594+ . watchSnapshots ( 2000 )
595+ . expectEvents ( query1 , { fromCache : true } )
596+ . expectLimboDocs ( docB . key ) // DocB is now in limbo.
597+ . watchRemoves (
598+ newQueryForPath ( docB . key . path ) ,
599+ new RpcError ( Code . PERMISSION_DENIED , 'no' )
600+ )
601+ . expectLimboDocs ( ) // DocB is no longer in limbo.
602+ . expectEvents ( query1 , {
603+ removed : [ docB ]
649604 } ) ;
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- ) ;
605+ } ) ;
606+
607+ specTest ( 'Bloom filter with large size works as expected' , [ ] , ( ) => {
608+ const query1 = query ( 'collection' ) ;
609+ const docs = [ ] ;
610+ for ( let i = 0 ; i < 100 ; i ++ ) {
611+ docs . push ( doc ( `collection/doc${ i } ` , 1000 , { v : 1 } ) ) ;
662612 }
663- ) ;
613+ const docKeys = docs . map ( item => item . key ) ;
614+
615+ const bloomFilterProto = generateBloomFilterProto ( {
616+ contains : docs . slice ( 0 , 50 ) ,
617+ notContains : docs . slice ( 50 ) ,
618+ bitCount : 1000 ,
619+ hashCount : 16
620+ } ) ;
621+ return (
622+ spec ( )
623+ . userListens ( query1 )
624+ . watchAcksFull ( query1 , 1000 , ...docs )
625+ . expectEvents ( query1 , { added : docs } )
626+ // Doc0 to doc49 are deleted in the next sync.
627+ . watchFilters ( [ query1 ] , docKeys . slice ( 0 , 50 ) , bloomFilterProto )
628+ . watchSnapshots ( 2000 )
629+ // BloomFilter correctly identifies docs that deleted, skip full query.
630+ . expectEvents ( query1 , { fromCache : true } )
631+ . expectLimboDocs ( ...docKeys . slice ( 50 ) )
632+ ) ;
633+ } ) ;
664634} ) ;
0 commit comments