@@ -366,4 +366,140 @@ public void testDeeplyNestedServerTimestamps() {
366
366
}
367
367
assertThat (error .get ()).isNull ();
368
368
}
369
+
370
+ @ Test
371
+ public void testIndexAutoCreationWorks () {
372
+ Query query = query ("coll" ).filter (filter ("matches" , "==" , true ));
373
+ int targetId = allocateQuery (query );
374
+
375
+ enableIndexAutoCreation ();
376
+
377
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/a" , 10 , map ("matches" , true )), targetId ));
378
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/b" , 10 , map ("matches" , false )), targetId ));
379
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/c" , 10 , map ("matches" , false )), targetId ));
380
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/d" , 10 , map ("matches" , false )), targetId ));
381
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/e" , 10 , map ("matches" , true )), targetId ));
382
+
383
+ // First time query runs without indexes.
384
+ // Based on current heuristic, collection document counts (5) > 2 * resultSize (2).
385
+ // Full matched index should be created.
386
+ executeQuery (query );
387
+ assertRemoteDocumentsRead (/* byKey= */ 0 , /* byCollection= */ 2 );
388
+ assertQueryReturned ("coll/a" , "coll/e" );
389
+
390
+ backfillIndexes ();
391
+
392
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/f" , 20 , map ("matches" , true )), targetId ));
393
+
394
+ executeQuery (query );
395
+ assertRemoteDocumentsRead (/* byKey= */ 2 , /* byCollection= */ 1 );
396
+ assertQueryReturned ("coll/a" , "coll/e" , "coll/f" );
397
+ }
398
+
399
+ @ Test
400
+ public void testIndexAutoCreationWorksWhenBackfillerRunsHalfway () {
401
+ Query query = query ("coll" ).filter (filter ("matches" , "==" , true ));
402
+ int targetId = allocateQuery (query );
403
+
404
+ enableIndexAutoCreation ();
405
+
406
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/a" , 10 , map ("matches" , true )), targetId ));
407
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/b" , 10 , map ("matches" , false )), targetId ));
408
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/c" , 10 , map ("matches" , false )), targetId ));
409
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/d" , 10 , map ("matches" , false )), targetId ));
410
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/e" , 10 , map ("matches" , true )), targetId ));
411
+
412
+ // First time query is running without indexes.
413
+ // Based on current heuristic, collection document counts (5) > 2 * resultSize (2).
414
+ // Full matched index should be created.
415
+ executeQuery (query );
416
+ // Only document a matches the result
417
+ assertRemoteDocumentsRead (/* byKey= */ 0 , /* byCollection= */ 2 );
418
+ assertQueryReturned ("coll/a" , "coll/e" );
419
+
420
+ setBackfillerMaxDocumentsToProcess (2 );
421
+ backfillIndexes ();
422
+
423
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/f" , 20 , map ("matches" , true )), targetId ));
424
+
425
+ executeQuery (query );
426
+ assertRemoteDocumentsRead (/* byKey= */ 1 , /* byCollection= */ 2 );
427
+ assertQueryReturned ("coll/a" , "coll/e" , "coll/f" );
428
+ }
429
+
430
+ @ Test
431
+ public void testIndexCreatedByIndexAutoCreationExistsAfterTurnOffAutoCreation () {
432
+ Query query = query ("coll" ).filter (filter ("matches" , "==" , true ));
433
+ int targetId = allocateQuery (query );
434
+
435
+ enableIndexAutoCreation ();
436
+
437
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/a" , 10 , map ("matches" , true )), targetId ));
438
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/b" , 10 , map ("matches" , false )), targetId ));
439
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/c" , 10 , map ("matches" , false )), targetId ));
440
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/d" , 10 , map ("matches" , false )), targetId ));
441
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/e" , 10 , map ("matches" , true )), targetId ));
442
+
443
+ // First time query runs without indexes.
444
+ // Based on current heuristic, collection document counts (5) > 2 * resultSize (2).
445
+ // Full matched index should be created.
446
+ executeQuery (query );
447
+ assertRemoteDocumentsRead (/* byKey= */ 0 , /* byCollection= */ 2 );
448
+ assertQueryReturned ("coll/a" , "coll/e" );
449
+
450
+ disableIndexAutoCreation ();
451
+
452
+ backfillIndexes ();
453
+
454
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/f" , 20 , map ("matches" , true )), targetId ));
455
+
456
+ executeQuery (query );
457
+ assertRemoteDocumentsRead (/* byKey= */ 2 , /* byCollection= */ 1 );
458
+ assertQueryReturned ("coll/a" , "coll/e" , "coll/f" );
459
+ }
460
+
461
+ @ Test
462
+ public void testDisableIndexAutoCreationWorks () {
463
+ Query query1 = query ("coll" ).filter (filter ("matches" , "==" , true ));
464
+ int targetId1 = allocateQuery (query1 );
465
+
466
+ enableIndexAutoCreation ();
467
+
468
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/a" , 10 , map ("matches" , true )), targetId1 ));
469
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/b" , 10 , map ("matches" , false )), targetId1 ));
470
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/c" , 10 , map ("matches" , false )), targetId1 ));
471
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/d" , 10 , map ("matches" , false )), targetId1 ));
472
+ applyRemoteEvent (addedRemoteEvent (doc ("coll/e" , 10 , map ("matches" , true )), targetId1 ));
473
+
474
+ // First time query is running without indexes.
475
+ // Based on current heuristic, collection document counts (5) > 2 * resultSize (2).
476
+ // Full matched index should be created.
477
+ executeQuery (query1 );
478
+ assertRemoteDocumentsRead (/* byKey= */ 0 , /* byCollection= */ 2 );
479
+ assertQueryReturned ("coll/a" , "coll/e" );
480
+
481
+ disableIndexAutoCreation ();
482
+
483
+ backfillIndexes ();
484
+
485
+ executeQuery (query1 );
486
+ assertRemoteDocumentsRead (/* byKey= */ 2 , /* byCollection= */ 0 );
487
+ assertQueryReturned ("coll/a" , "coll/e" );
488
+
489
+ Query query2 = query ("foo" ).filter (filter ("matches" , "==" , true ));
490
+ int targetId2 = allocateQuery (query2 );
491
+
492
+ applyRemoteEvent (addedRemoteEvent (doc ("foo/a" , 10 , map ("matches" , true )), targetId2 ));
493
+ applyRemoteEvent (addedRemoteEvent (doc ("foo/b" , 10 , map ("matches" , false )), targetId2 ));
494
+ applyRemoteEvent (addedRemoteEvent (doc ("foo/c" , 10 , map ("matches" , false )), targetId2 ));
495
+ applyRemoteEvent (addedRemoteEvent (doc ("foo/d" , 10 , map ("matches" , false )), targetId2 ));
496
+ applyRemoteEvent (addedRemoteEvent (doc ("foo/e" , 10 , map ("matches" , true )), targetId2 ));
497
+
498
+ executeQuery (query2 );
499
+ assertRemoteDocumentsRead (/* byKey= */ 0 , /* byCollection= */ 2 );
500
+
501
+ // Run the query in second time, test index won't be created
502
+ executeQuery (query2 );
503
+ assertRemoteDocumentsRead (/* byKey= */ 0 , /* byCollection= */ 2 );
504
+ }
369
505
}
0 commit comments