Skip to content

Commit 275300d

Browse files
Add LocalStoreTest
1 parent b1b07eb commit 275300d

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

packages/firestore/test/unit/local/local_store.test.ts

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import {
9393
doc,
9494
docAddedRemoteEvent,
9595
docUpdateRemoteEvent,
96+
existenceFilterEvent,
9697
expectEqual,
9798
filter,
9899
key,
@@ -130,6 +131,7 @@ class LocalStoreTester {
130131

131132
constructor(
132133
public localStore: LocalStore,
134+
private readonly persistence: Persistence,
133135
private readonly queryEngine: CountingQueryEngine,
134136
readonly gcIsEager: boolean
135137
) {
@@ -379,6 +381,30 @@ class LocalStoreTester {
379381
return this;
380382
}
381383

384+
toContainTargetData(
385+
target: Target,
386+
snapshotVersion: number,
387+
lastLimboFreeSnapshotVersion: number,
388+
resumeToken: ByteString
389+
): LocalStoreTester {
390+
this.promiseChain = this.promiseChain.then(async () => {
391+
const targetData = await this.persistence.runTransaction(
392+
'getTargetData',
393+
'readonly',
394+
txn => localStoreGetTargetData(this.localStore, txn, target)
395+
);
396+
expect(targetData!.snapshotVersion.isEqual(version(snapshotVersion))).to
397+
.be.true;
398+
expect(
399+
targetData!.lastLimboFreeSnapshotVersion.isEqual(
400+
version(lastLimboFreeSnapshotVersion)
401+
)
402+
).to.be.true;
403+
expect(targetData!.resumeToken.isEqual(resumeToken)).to.be.true;
404+
});
405+
return this;
406+
}
407+
382408
toReturnChanged(...docs: Document[]): LocalStoreTester {
383409
this.promiseChain = this.promiseChain.then(() => {
384410
debugAssert(
@@ -583,7 +609,12 @@ function genericLocalStoreTests(
583609
});
584610

585611
function expectLocalStore(): LocalStoreTester {
586-
return new LocalStoreTester(localStore, queryEngine, gcIsEager);
612+
return new LocalStoreTester(
613+
localStore,
614+
persistence,
615+
queryEngine,
616+
gcIsEager
617+
);
587618
}
588619

589620
it('handles SetMutation', () => {
@@ -1876,6 +1907,47 @@ function genericLocalStoreTests(
18761907
}
18771908
});
18781909

1910+
// eslint-disable-next-line no-restricted-properties
1911+
(gcIsEager ? it.skip : it)(
1912+
'ignores target mapping after existence filter mismatch',
1913+
async () => {
1914+
const query1 = query('foo', filter('matches', '==', true));
1915+
const target = queryToTarget(query1);
1916+
const targetId = 2;
1917+
1918+
return (
1919+
expectLocalStore()
1920+
.afterAllocatingQuery(query1)
1921+
.toReturnTargetId(targetId)
1922+
// Persist a mapping with a single document
1923+
.after(
1924+
docAddedRemoteEvent(
1925+
doc('foo/a', 10, { matches: true }),
1926+
[targetId],
1927+
[],
1928+
[targetId]
1929+
)
1930+
)
1931+
.after(noChangeEvent(targetId, 10, byteStringFromString('foo')))
1932+
.after(localViewChanges(targetId, /* fromCache= */ false, {}))
1933+
.afterExecutingQuery(query1)
1934+
.toReturnChanged(doc('foo/a', 10, { matches: true }))
1935+
.toHaveRead({ documentsByKey: 1 })
1936+
.toContainTargetData(target, 10, 10, byteStringFromString('foo'))
1937+
// Create an existence filter mismatch and verify that the last limbo
1938+
// free snapshot version is deleted
1939+
.after(existenceFilterEvent(targetId, 2, 20))
1940+
.after(noChangeEvent(targetId, 20))
1941+
.toContainTargetData(target, 0, 0, ByteString.EMPTY_BYTE_STRING)
1942+
// Re-run the query as a collection scan
1943+
.afterExecutingQuery(query1)
1944+
.toReturnChanged(doc('foo/a', 10, { matches: true }))
1945+
.toHaveRead({ documentsByQuery: 1 })
1946+
.finish()
1947+
);
1948+
}
1949+
);
1950+
18791951
// eslint-disable-next-line no-restricted-properties
18801952
(gcIsEager ? it.skip : it)(
18811953
'queries include locally modified documents',

packages/firestore/test/util/helpers.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import {
8787
LimitType as ProtoLimitType
8888
} from '../../src/protos/firestore_bundle_proto';
8989
import * as api from '../../src/protos/firestore_proto_api';
90+
import { ExistenceFilter } from '../../src/remote/existence_filter';
9091
import { RemoteEvent, TargetChange } from '../../src/remote/remote_event';
9192
import {
9293
JsonProtoSerializer,
@@ -98,6 +99,7 @@ import {
9899
} from '../../src/remote/serializer';
99100
import {
100101
DocumentWatchChange,
102+
ExistenceFilterChange,
101103
WatchChangeAggregator,
102104
WatchTargetChange,
103105
WatchTargetChangeState
@@ -352,6 +354,22 @@ export function noChangeEvent(
352354
return aggregator.createRemoteEvent(version(snapshotVersion));
353355
}
354356

357+
export function existenceFilterEvent(
358+
targetId: number,
359+
count: number,
360+
snapshotVersion: number
361+
): RemoteEvent {
362+
const aggregator = new WatchChangeAggregator({
363+
getRemoteKeysForTarget: () => documentKeySet(),
364+
getTargetDataForTarget: targetId =>
365+
targetData(targetId, TargetPurpose.Listen, 'foo')
366+
});
367+
aggregator.handleExistenceFilter(
368+
new ExistenceFilterChange(targetId, new ExistenceFilter(count))
369+
);
370+
return aggregator.createRemoteEvent(version(snapshotVersion));
371+
}
372+
355373
export function docAddedRemoteEvent(
356374
docOrDocs: MutableDocument | MutableDocument[],
357375
updatedInTargets?: TargetId[],

0 commit comments

Comments
 (0)