@@ -1220,109 +1220,104 @@ public void bloomFilterShouldCorrectlyEncodeComplexUnicodeCharacters() throws Ex
1220
1220
testDocs .put (docId , map ("foo" , 42 ));
1221
1221
}
1222
1222
1223
- // Each iteration of the "while" loop below runs a single iteration of the test. The test will
1224
- // be run multiple times only if a bloom filter false positive occurs.
1225
- int attemptNumber = 0 ;
1226
- while (true ) {
1227
- attemptNumber ++;
1228
-
1229
- // Create the documents whose names contain complex Unicode characters in a new collection.
1230
- CollectionReference collection = testCollectionWithDocs (testDocs );
1231
-
1232
- // Run a query to populate the local cache with documents that have names with complex Unicode
1233
- // characters.
1234
- List <DocumentReference > createdDocuments = new ArrayList <>();
1235
- {
1236
- QuerySnapshot querySnapshot1 = waitFor (collection .get ());
1237
- for (DocumentSnapshot documentSnapshot : querySnapshot1 .getDocuments ()) {
1238
- createdDocuments .add (documentSnapshot .getReference ());
1239
- }
1240
- HashSet <String > createdDocumentIds = new HashSet <>();
1241
- for (DocumentSnapshot documentSnapshot : querySnapshot1 .getDocuments ()) {
1242
- createdDocumentIds .add (documentSnapshot .getId ());
1243
- }
1244
- assertWithMessage ("createdDocumentIds" )
1245
- .that (createdDocumentIds )
1246
- .containsExactlyElementsIn (testDocIds );
1247
- }
1248
-
1249
- // Delete one of the documents so that the next call to getDocs() will
1250
- // experience an existence filter mismatch. Do this deletion in a
1251
- // transaction, rather than using deleteDoc(), to avoid affecting the
1252
- // local cache.
1253
- waitFor (
1254
- collection
1255
- .getFirestore ()
1256
- .runTransaction (
1257
- transaction -> {
1258
- DocumentReference documentToDelete = collection .document ("DocumentToDelete" );
1259
- DocumentSnapshot documentToDeleteSnapshot = transaction .get (documentToDelete );
1260
- assertWithMessage ("documentToDeleteSnapshot.exists()" )
1261
- .that (documentToDeleteSnapshot .exists ())
1262
- .isTrue ();
1263
- transaction .delete (documentToDelete );
1264
- return null ;
1265
- }));
1266
-
1267
- // Wait for 10 seconds, during which Watch will stop tracking the query and will send an
1268
- // existence filter rather than "delete" events when the query is resumed.
1269
- Thread .sleep (10000 );
1270
-
1271
- // Resume the query and save the resulting snapshot for verification. Use some internal
1272
- // testing hooks to "capture" the existence filter mismatches.
1273
- AtomicReference <QuerySnapshot > querySnapshot2Ref = new AtomicReference <>();
1274
- ArrayList <ExistenceFilterMismatchInfo > existenceFilterMismatches =
1275
- captureExistenceFilterMismatches (
1276
- () -> {
1277
- QuerySnapshot querySnapshot = waitFor (collection .get ());
1278
- querySnapshot2Ref .set (querySnapshot );
1279
- });
1280
- QuerySnapshot querySnapshot2 = querySnapshot2Ref .get ();
1223
+ // Create the documents whose names contain complex Unicode characters in a new collection.
1224
+ CollectionReference collection = testCollectionWithDocs (testDocs );
1281
1225
1282
- // Verify that the snapshot from the resumed query contains the expected documents; that is,
1283
- // that it contains the documents whose names contain complex Unicode characters and _not_ the
1284
- // document that was deleted.
1285
- HashSet <String > querySnapshot2DocumentIds = new HashSet <>();
1286
- for (DocumentSnapshot documentSnapshot : querySnapshot2 .getDocuments ()) {
1287
- querySnapshot2DocumentIds .add (documentSnapshot .getId ());
1226
+ // Run a query to populate the local cache with documents that have names with complex Unicode
1227
+ // characters.
1228
+ List <DocumentReference > createdDocuments = new ArrayList <>();
1229
+ {
1230
+ QuerySnapshot querySnapshot1 = waitFor (collection .get ());
1231
+ for (DocumentSnapshot documentSnapshot : querySnapshot1 .getDocuments ()) {
1232
+ createdDocuments .add (documentSnapshot .getReference ());
1288
1233
}
1289
- HashSet <String > querySnapshot2ExpectedDocumentIds = new HashSet <>(testDocIds );
1290
- querySnapshot2ExpectedDocumentIds .remove ("DocumentToDelete" );
1291
- assertWithMessage ("querySnapshot2DocumentIds" )
1292
- .that (querySnapshot2DocumentIds )
1293
- .containsExactlyElementsIn (querySnapshot2ExpectedDocumentIds );
1294
-
1295
- // Verify that Watch sent an existence filter with the correct counts.
1296
- assertWithMessage ("Watch should have sent exactly 1 existence filter" )
1297
- .that (existenceFilterMismatches )
1298
- .hasSize (1 );
1299
- ExistenceFilterMismatchInfo existenceFilterMismatchInfo = existenceFilterMismatches .get (0 );
1300
- assertWithMessage ("localCacheCount" )
1301
- .that (existenceFilterMismatchInfo .localCacheCount ())
1302
- .isEqualTo (testDocIds .size ());
1303
- assertWithMessage ("existenceFilterCount" )
1304
- .that (existenceFilterMismatchInfo .existenceFilterCount ())
1305
- .isEqualTo (testDocIds .size () - 1 );
1306
-
1307
- // Verify that Watch sent a valid bloom filter.
1308
- ExistenceFilterBloomFilterInfo bloomFilter = existenceFilterMismatchInfo .bloomFilter ();
1309
- assertWithMessage ("The bloom filter specified in the existence filter" )
1310
- .that (bloomFilter )
1311
- .isNotNull ();
1312
-
1313
- // Verify that the bloom filter was successfully used to avert a full requery. If a false
1314
- // positive occurred, which is statistically rare, but technically possible, then retry the
1315
- // entire test.
1316
- if (attemptNumber == 1 && !bloomFilter .applied ()) {
1317
- continue ;
1234
+ HashSet <String > createdDocumentIds = new HashSet <>();
1235
+ for (DocumentSnapshot documentSnapshot : querySnapshot1 .getDocuments ()) {
1236
+ createdDocumentIds .add (documentSnapshot .getId ());
1318
1237
}
1238
+ assertWithMessage ("createdDocumentIds" )
1239
+ .that (createdDocumentIds )
1240
+ .containsExactlyElementsIn (testDocIds );
1241
+ }
1319
1242
1320
- assertWithMessage ("bloom filter successfully applied with attemptNumber=" + attemptNumber )
1321
- .that (bloomFilter .applied ())
1243
+ // Delete one of the documents so that the next call to getDocs() will experience an existence
1244
+ // filter mismatch. Do this deletion in a transaction, rather than using deleteDoc(), to avoid
1245
+ // affecting the local cache.
1246
+ DocumentReference documentToDelete = collection .document ("DocumentToDelete" );
1247
+ waitFor (
1248
+ collection
1249
+ .getFirestore ()
1250
+ .runTransaction (
1251
+ transaction -> {
1252
+ DocumentSnapshot documentToDeleteSnapshot = transaction .get (documentToDelete );
1253
+ assertWithMessage ("documentToDeleteSnapshot.exists()" )
1254
+ .that (documentToDeleteSnapshot .exists ())
1255
+ .isTrue ();
1256
+ transaction .delete (documentToDelete );
1257
+ return null ;
1258
+ }));
1259
+
1260
+ // Wait for 10 seconds, during which Watch will stop tracking the query and will send an
1261
+ // existence filter rather than "delete" events when the query is resumed.
1262
+ Thread .sleep (10000 );
1263
+
1264
+ // Resume the query and save the resulting snapshot for verification. Use some internal testing
1265
+ // hooks to "capture" the existence filter mismatches.
1266
+ AtomicReference <QuerySnapshot > querySnapshot2Ref = new AtomicReference <>();
1267
+ ArrayList <ExistenceFilterMismatchInfo > existenceFilterMismatches =
1268
+ captureExistenceFilterMismatches (
1269
+ () -> {
1270
+ QuerySnapshot querySnapshot = waitFor (collection .get ());
1271
+ querySnapshot2Ref .set (querySnapshot );
1272
+ });
1273
+ QuerySnapshot querySnapshot2 = querySnapshot2Ref .get ();
1274
+
1275
+ // Verify that the snapshot from the resumed query contains the expected documents; that is,
1276
+ // that it contains the documents whose names contain complex Unicode characters and _not_ the
1277
+ // document that was deleted.
1278
+ HashSet <String > querySnapshot2DocumentIds = new HashSet <>();
1279
+ for (DocumentSnapshot documentSnapshot : querySnapshot2 .getDocuments ()) {
1280
+ querySnapshot2DocumentIds .add (documentSnapshot .getId ());
1281
+ }
1282
+ HashSet <String > querySnapshot2ExpectedDocumentIds = new HashSet <>(testDocIds );
1283
+ querySnapshot2ExpectedDocumentIds .remove ("DocumentToDelete" );
1284
+ assertWithMessage ("querySnapshot2DocumentIds" )
1285
+ .that (querySnapshot2DocumentIds )
1286
+ .containsExactlyElementsIn (querySnapshot2ExpectedDocumentIds );
1287
+
1288
+ // Verify that Watch sent an existence filter with the correct counts.
1289
+ assertWithMessage ("Watch should have sent exactly 1 existence filter" )
1290
+ .that (existenceFilterMismatches )
1291
+ .hasSize (1 );
1292
+ ExistenceFilterMismatchInfo existenceFilterMismatchInfo = existenceFilterMismatches .get (0 );
1293
+ assertWithMessage ("localCacheCount" )
1294
+ .that (existenceFilterMismatchInfo .localCacheCount ())
1295
+ .isEqualTo (testDocIds .size ());
1296
+ assertWithMessage ("existenceFilterCount" )
1297
+ .that (existenceFilterMismatchInfo .existenceFilterCount ())
1298
+ .isEqualTo (testDocIds .size () - 1 );
1299
+
1300
+ // Verify that Watch sent a valid bloom filter.
1301
+ ExistenceFilterBloomFilterInfo bloomFilter = existenceFilterMismatchInfo .bloomFilter ();
1302
+ assertWithMessage ("The bloom filter specified in the existence filter" )
1303
+ .that (bloomFilter )
1304
+ .isNotNull ();
1305
+
1306
+ // The bloom filter application should statistically be successful almost every time; the _only_
1307
+ // time when it would _not_ be successful is if there is a false positive when testing for
1308
+ // 'DocumentToDelete' in the bloom filter. So verify that the bloom filter application is
1309
+ // successful, unless there was a false positive.
1310
+ boolean isFalsePositive = bloomFilter .mightContain (documentToDelete );
1311
+ assertWithMessage ("bloomFilter.applied()" )
1312
+ .that (bloomFilter .applied ())
1313
+ .isEqualTo (!isFalsePositive );
1314
+
1315
+ // Verify that the bloom filter contains the document paths with complex Unicode characters.
1316
+ for (DocumentSnapshot documentSnapshot : querySnapshot2 .getDocuments ()) {
1317
+ DocumentReference documentReference = documentSnapshot .getReference ();
1318
+ assertWithMessage ("bloomFilter.mightContain() for " + documentReference .getPath ())
1319
+ .that (bloomFilter .mightContain (documentReference ))
1322
1320
.isTrue ();
1323
-
1324
- // Break out of the test loop now that the test passes.
1325
- break ;
1326
1321
}
1327
1322
}
1328
1323
0 commit comments