Skip to content

Firestore: Increase test coverage for persistent cache indexing #7613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ apiDescribe('PersistentCacheIndexManager', persistence => {
return;
}

it(
'getPersistentCacheIndexManager() should return distinct instances ' +
'for distinct Firestore objects',
() =>
withTestDb(persistence, db1 =>
withTestDb(persistence, async db2 => {
const indexManager1 = getPersistentCacheIndexManager(db1);
const indexManager2 = getPersistentCacheIndexManager(db2);
expect(indexManager1).to.not.equal(indexManager2);
})
)
);

describe('enable/disable persistent index auto creation', () => {
it('enable on new instance should succeed', () =>
withTestDb(persistence, async db => {
Expand Down
99 changes: 84 additions & 15 deletions packages/firestore/test/unit/local/local_store_indexeddb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
filter,
key,
orderBy,
orFilter,
query,
setMutation,
version
Expand Down Expand Up @@ -534,20 +535,63 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {
test.assertQueryReturned('coll/a', 'coll/e', 'coll/f');
});

it('can auto-create indexes works with or query', async () => {
const query_ = query(
'coll',
orFilter(filter('a', '==', 3), filter('b', '==', true))
);
const targetId = await test.allocateQuery(query_);
test.configureIndexAutoCreation({
isEnabled: true,
indexAutoCreationMinCollectionSize: 0,
relativeIndexReadCostPerDocument: 2
});

await test.applyRemoteEvents(
docAddedRemoteEvent(doc('coll/a', 10, { b: true }), [targetId]),
docAddedRemoteEvent(doc('coll/b', 10, { b: false }), [targetId]),
docAddedRemoteEvent(doc('coll/c', 10, { a: 5, b: false }), [targetId]),
docAddedRemoteEvent(doc('coll/d', 10, { a: true }), [targetId]),
docAddedRemoteEvent(doc('coll/e', 10, { a: 3, b: true }), [targetId])
);

// First time query runs without indexes.
// Based on current heuristic, collection document counts (5) >
// 2 * resultSize (2).
// Full matched index should be created.
await test.executeQuery(query_);
test.assertRemoteDocumentsRead(0, 2);
test.assertQueryReturned('coll/a', 'coll/e');

await test.backfillIndexes();

await test.applyRemoteEvent(
docAddedRemoteEvent(doc('coll/f', 20, { a: 3, b: false }), [targetId])
);

await test.executeQuery(query_);
test.assertRemoteDocumentsRead(2, 1);
test.assertQueryReturned('coll/a', 'coll/e', 'coll/f');
});

it('does not auto-create indexes for small collections', async () => {
const query_ = query('coll', filter('count', '>=', 3));
const query_ = query(
'coll',
filter('foo', '==', 9),
filter('count', '>=', 3)
);
const targetId = await test.allocateQuery(query_);
test.configureIndexAutoCreation({
isEnabled: true,
relativeIndexReadCostPerDocument: 2
});

await test.applyRemoteEvents(
docAddedRemoteEvent(doc('coll/a', 10, { count: 5 }), [targetId]),
docAddedRemoteEvent(doc('coll/b', 10, { count: 1 }), [targetId]),
docAddedRemoteEvent(doc('coll/c', 10, { count: 0 }), [targetId]),
docAddedRemoteEvent(doc('coll/d', 10, { count: 1 }), [targetId]),
docAddedRemoteEvent(doc('coll/e', 10, { count: 3 }), [targetId])
docAddedRemoteEvent(doc('coll/a', 10, { foo: 9, count: 5 }), [targetId]),
docAddedRemoteEvent(doc('coll/b', 10, { foo: 8, count: 6 }), [targetId]),
docAddedRemoteEvent(doc('coll/c', 10, { foo: 9, count: 0 }), [targetId]),
docAddedRemoteEvent(doc('coll/d', 10, { count: 4 }), [targetId]),
docAddedRemoteEvent(doc('coll/e', 10, { foo: 9, count: 3 }), [targetId])
);

// SDK will not create indexes since collection size is too small.
Expand All @@ -558,7 +602,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {
await test.backfillIndexes();

await test.applyRemoteEvent(
docAddedRemoteEvent(doc('coll/f', 20, { count: 4 }), [targetId])
docAddedRemoteEvent(doc('coll/f', 20, { foo: 9, count: 4 }), [targetId])
);

await test.executeQuery(query_);
Expand Down Expand Up @@ -602,7 +646,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {
});

it('index auto creation works when backfiller runs halfway', async () => {
const query_ = query('coll', filter('matches', '==', 'foo'));
const query_ = query(
'coll',
filter('matches', '==', 'foo'),
filter('count', '>', 10)
);
const targetId = await test.allocateQuery(query_);
test.configureIndexAutoCreation({
isEnabled: true,
Expand All @@ -611,11 +659,19 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {
});

await test.applyRemoteEvents(
docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo' }), [targetId]),
docAddedRemoteEvent(doc('coll/b', 10, { matches: '' }), [targetId]),
docAddedRemoteEvent(doc('coll/c', 10, { matches: 'bar' }), [targetId]),
docAddedRemoteEvent(doc('coll/d', 10, { matches: 7 }), [targetId]),
docAddedRemoteEvent(doc('coll/e', 10, { matches: 'foo' }), [targetId])
docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo', count: 11 }), [
targetId
]),
docAddedRemoteEvent(doc('coll/b', 10, { matches: 'foo', count: 9 }), [
targetId
]),
docAddedRemoteEvent(doc('coll/c', 10, { matches: 'foo' }), [targetId]),
docAddedRemoteEvent(doc('coll/d', 10, { matches: 7, count: 11 }), [
targetId
]),
docAddedRemoteEvent(doc('coll/e', 10, { matches: 'foo', count: 21 }), [
targetId
])
);

// First time query runs without indexes.
Expand All @@ -629,7 +685,9 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {
await test.backfillIndexes({ maxDocumentsToProcess: 2 });

await test.applyRemoteEvent(
docAddedRemoteEvent(doc('coll/f', 20, { matches: 'foo' }), [targetId])
docAddedRemoteEvent(doc('coll/f', 20, { matches: 'foo', count: 15 }), [
targetId
])
);

await test.executeQuery(query_);
Expand Down Expand Up @@ -718,9 +776,14 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {

await test.executeQuery(query2);
test.assertRemoteDocumentsRead(0, 2);
test.assertQueryReturned('foo/a', 'foo/e');

await test.backfillIndexes();

// Run the query in second time, test index won't be created
await test.executeQuery(query2);
test.assertRemoteDocumentsRead(0, 2);
test.assertQueryReturned('foo/a', 'foo/e');
});

it('index auto creation works with mutation', async () => {
Expand Down Expand Up @@ -786,7 +849,6 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {
test.assertRemoteDocumentsRead(0, 2);
test.assertQueryReturned('coll/a', 'coll/e');

test.configureIndexAutoCreation({ isEnabled: false });
await test.backfillIndexes();
await test.executeQuery(query_);
test.assertRemoteDocumentsRead(2, 0);
Expand All @@ -796,6 +858,13 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => {
await test.executeQuery(query_);
test.assertRemoteDocumentsRead(0, 2);
test.assertQueryReturned('coll/a', 'coll/e');

// Field index is created again.
await test.backfillIndexes();

await test.executeQuery(query_);
test.assertRemoteDocumentsRead(2, 0);
test.assertQueryReturned('coll/a', 'coll/e');
});

it('delete all indexes works with manual added indexes', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ describe('Target Bounds', () => {
validateBuildTargetIndexCreateFullMatchIndex
));

it('queries with order by', () =>
it('queries with order bys', () =>
queriesWithOrderBy.forEach(validateBuildTargetIndexCreateFullMatchIndex));

it('queries with inequalities uses single field index', () =>
Expand Down