Skip to content

Commit 12ce39e

Browse files
Adding Spec Test Benchmark suite
1 parent fc2e967 commit 12ce39e

File tree

2 files changed

+231
-2
lines changed

2 files changed

+231
-2
lines changed

packages/firestore/test/unit/specs/describe_spec.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ const NO_WEB_TAG = 'no-web';
3131
const NO_ANDROID_TAG = 'no-android';
3232
const NO_IOS_TAG = 'no-ios';
3333
const NO_LRU = 'no-lru';
34+
const BENCHMARK_TAG = 'benchmark';
3435
const KNOWN_TAGS = [
36+
BENCHMARK_TAG,
3537
EXCLUSIVE_TAG,
3638
PERSISTENCE_TAG,
3739
NO_WEB_TAG,
@@ -40,6 +42,9 @@ const KNOWN_TAGS = [
4042
NO_LRU
4143
];
4244

45+
// TOOD: Make this configurable with mocha options.
46+
const RUN_BENCHMARK_TESTS = false;
47+
4348
const WEB_SPEC_TEST_FILTER = (tags: string[]) =>
4449
tags.indexOf(NO_WEB_TAG) === -1;
4550

@@ -127,6 +132,8 @@ export function specTest(
127132
runner = it.only;
128133
} else if (!WEB_SPEC_TEST_FILTER(tags)) {
129134
runner = it.skip;
135+
} else if (tags.indexOf(BENCHMARK_TAG) >= 0 && !RUN_BENCHMARK_TESTS) {
136+
runner = it.skip;
130137
} else if (usePersistence && tags.indexOf('no-lru') !== -1) {
131138
// spec should have a comment explaining why it is being skipped.
132139
runner = it.skip;
@@ -135,8 +142,14 @@ export function specTest(
135142
}
136143
const mode = usePersistence ? '(Persistence)' : '(Memory)';
137144
const fullName = `${mode} ${name}`;
138-
runner(fullName, () => {
139-
return spec.runAsTest(fullName, usePersistence);
145+
runner(fullName, async () => {
146+
const start = Date.now();
147+
await spec.runAsTest(fullName, usePersistence);
148+
const end = Date.now();
149+
if (tags.indexOf(BENCHMARK_TAG) >= 0) {
150+
// tslint:disable-next-line:no-console
151+
console.log(`Runtime: ${end - start} ms.`);
152+
}
140153
});
141154
}
142155
} else {
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Query } from '../../../src/core/query';
18+
import { doc, orderBy, path } from '../../util/helpers';
19+
20+
import { describeSpec, specTest } from './describe_spec';
21+
import { spec } from './spec_builder';
22+
23+
const STEP_COUNT = 10;
24+
25+
describeSpec('Performance Tests:', ['benchmark'], () => {
26+
specTest('Insert a new document', [], () => {
27+
let steps = spec().withGCEnabled(false);
28+
for (let i = 0; i < STEP_COUNT; ++i) {
29+
steps = steps.userSets(`collection/{i}`, { doc: i }).writeAcks(i);
30+
}
31+
return steps;
32+
});
33+
34+
specTest('Insert a new document and wait for snapshot', [], () => {
35+
let currentVersion = 1;
36+
let steps = spec().withGCEnabled(false);
37+
38+
for (let i = 0; i < STEP_COUNT; ++i) {
39+
const query = Query.atPath(path(`collection/${i}`));
40+
const docLocal = doc(
41+
`collection/${i}`,
42+
0,
43+
{ doc: i },
44+
{ hasLocalMutations: true }
45+
);
46+
const docRemote = doc(`collection/${i}`, ++currentVersion, { doc: i });
47+
48+
steps = steps
49+
.userListens(query)
50+
.userSets(`collection/${i}`, { doc: i })
51+
.expectEvents(query, {
52+
added: [docLocal],
53+
fromCache: true,
54+
hasPendingWrites: true
55+
})
56+
.writeAcks(++currentVersion)
57+
.watchAcksFull(query, ++currentVersion, docRemote)
58+
.expectEvents(query, { metadata: [docRemote] })
59+
.userUnlistens(query)
60+
.watchRemoves(query);
61+
}
62+
return steps;
63+
});
64+
65+
specTest('Watch has cached mutations', [], () => {
66+
const cachedDocumentCount = 100;
67+
68+
const query = Query.atPath(path(`collection`)).addOrderBy(orderBy('v'));
69+
70+
let steps = spec().withGCEnabled(false);
71+
72+
const docs = [];
73+
74+
for (let i = 0; i < cachedDocumentCount; ++i) {
75+
steps.userSets(`collection/${i}`, { v: i });
76+
docs.push(
77+
doc(`collection/${i}`, 0, { v: i }, { hasLocalMutations: true })
78+
);
79+
}
80+
81+
for (let i = 1; i <= STEP_COUNT; ++i) {
82+
steps = steps
83+
.userListens(query)
84+
.expectEvents(query, {
85+
added: docs,
86+
fromCache: true,
87+
hasPendingWrites: true
88+
})
89+
.userUnlistens(query);
90+
}
91+
92+
return steps;
93+
});
94+
95+
specTest('Update a single document', [], () => {
96+
let steps = spec().withGCEnabled(false);
97+
steps = steps.userSets(`collection/doc`, { v: 0 });
98+
for (let i = 1; i <= STEP_COUNT; ++i) {
99+
steps = steps.userPatches(`collection/doc`, { v: i }).writeAcks(i);
100+
}
101+
return steps;
102+
});
103+
104+
specTest('Update a single document and wait for snapshot', [], () => {
105+
const query = Query.atPath(path(`collection/doc`));
106+
107+
let currentVersion = 1;
108+
let steps = spec().withGCEnabled(false);
109+
110+
let docLocal = doc(
111+
`collection/doc`,
112+
0,
113+
{ v: 0 },
114+
{ hasLocalMutations: true }
115+
);
116+
let docRemote = doc(`collection/doc`, ++currentVersion, { v: 0 });
117+
let lastRemoteVersion = currentVersion;
118+
119+
steps = steps
120+
.userListens(query)
121+
.userSets(`collection/doc`, { v: 0 })
122+
.expectEvents(query, {
123+
added: [docLocal],
124+
fromCache: true,
125+
hasPendingWrites: true
126+
})
127+
.writeAcks(++currentVersion)
128+
.watchAcksFull(query, ++currentVersion, docRemote)
129+
.expectEvents(query, { metadata: [docRemote] });
130+
131+
for (let i = 1; i <= STEP_COUNT; ++i) {
132+
docLocal = doc(
133+
`collection/doc`,
134+
lastRemoteVersion,
135+
{ v: i },
136+
{ hasLocalMutations: true }
137+
);
138+
docRemote = doc(`collection/doc`, ++currentVersion, { v: i });
139+
lastRemoteVersion = currentVersion;
140+
141+
steps = steps
142+
.userPatches(`collection/doc`, { v: i })
143+
.expectEvents(query, { modified: [docLocal], hasPendingWrites: true })
144+
.writeAcks(++currentVersion)
145+
.watchSends({ affects: [query] }, docRemote)
146+
.watchSnapshots(++currentVersion)
147+
.expectEvents(query, { metadata: [docRemote] });
148+
}
149+
return steps;
150+
});
151+
152+
specTest('Watch sends 100 documents', [], () => {
153+
const documentsPerStep = 100;
154+
155+
const query = Query.atPath(path(`collection`)).addOrderBy(orderBy('v'));
156+
157+
let currentVersion = 1;
158+
let steps = spec().withGCEnabled(false);
159+
160+
steps = steps
161+
.userListens(query)
162+
.watchAcksFull(query, currentVersion)
163+
.expectEvents(query, {});
164+
165+
for (let i = 1; i <= STEP_COUNT; ++i) {
166+
const docs = [];
167+
168+
for (let j = 0; j < documentsPerStep; ++j) {
169+
docs.push(
170+
doc(`collection/${j}`, ++currentVersion, { v: currentVersion })
171+
);
172+
}
173+
174+
const changeType = i === 1 ? 'added' : 'modified';
175+
176+
steps = steps
177+
.watchSends({ affects: [query] }, ...docs)
178+
.watchSnapshots(++currentVersion)
179+
.expectEvents(query, { [changeType]: docs });
180+
}
181+
182+
return steps;
183+
});
184+
185+
specTest('Watch has cached results', [], () => {
186+
const documentsPerStep = 100;
187+
188+
let currentVersion = 1;
189+
let steps = spec().withGCEnabled(false);
190+
191+
for (let i = 1; i <= STEP_COUNT; ++i) {
192+
const collPath = `collection/${i}/coll`;
193+
const query = Query.atPath(path(collPath)).addOrderBy(orderBy('v'));
194+
195+
const docs = [];
196+
for (let j = 0; j < documentsPerStep; ++j) {
197+
docs.push(doc(`${collPath}/${j}`, ++currentVersion, { v: j }));
198+
}
199+
200+
steps = steps
201+
.userListens(query)
202+
.watchAcksFull(query, ++currentVersion, ...docs)
203+
.expectEvents(query, { added: docs })
204+
.userUnlistens(query)
205+
.watchRemoves(query)
206+
.userListens(query, 'resume-token-' + currentVersion)
207+
.expectEvents(query, { added: docs, fromCache: true })
208+
.watchAcksFull(query, ++currentVersion)
209+
.expectEvents(query, {})
210+
.userUnlistens(query)
211+
.watchRemoves(query);
212+
}
213+
214+
return steps;
215+
});
216+
});

0 commit comments

Comments
 (0)