Skip to content

Commit 2ac7c2f

Browse files
authored
Verify large write batches support (#2321)
* Reorder tests to match Android * Add missing NS_ASSUME_NONNULL_BEGIN * Add missing [self awaitExpectations] * Port can write very large batches from Android
1 parent 7c51215 commit 2ac7c2f

File tree

1 file changed

+84
-35
lines changed

1 file changed

+84
-35
lines changed

Firestore/Example/Tests/Integration/API/FIRWriteBatchTests.mm

Lines changed: 84 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
#import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
2525
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
2626

27+
#include "Firestore/core/src/firebase/firestore/util/autoid.h"
28+
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
29+
30+
using firebase::firestore::util::CreateAutoId;
31+
using firebase::firestore::util::WrapNSString;
32+
33+
NS_ASSUME_NONNULL_BEGIN
34+
2735
@interface FIRWriteBatchTests : FSTIntegrationTestCase
2836
@end
2937

@@ -124,6 +132,52 @@ - (void)testCannotUpdateNonexistentDocuments {
124132
XCTAssertFalse(result.exists);
125133
}
126134

135+
- (void)testUpdateFieldsWithDots {
136+
FIRDocumentReference *doc = [self documentRef];
137+
138+
XCTestExpectation *expectation = [self expectationWithDescription:@"testUpdateFieldsWithDots"];
139+
FIRWriteBatch *batch = [doc.firestore batch];
140+
[batch setData:@{@"a.b" : @"old", @"c.d" : @"old"} forDocument:doc];
141+
[batch updateData:@{[[FIRFieldPath alloc] initWithFields:@[ @"a.b" ]] : @"new"} forDocument:doc];
142+
143+
[batch commitWithCompletion:^(NSError *_Nullable error) {
144+
XCTAssertNil(error);
145+
[doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
146+
XCTAssertNil(error);
147+
XCTAssertEqualObjects(snapshot.data, (@{@"a.b" : @"new", @"c.d" : @"old"}));
148+
}];
149+
[expectation fulfill];
150+
}];
151+
152+
[self awaitExpectations];
153+
}
154+
155+
- (void)testUpdateNestedFields {
156+
FIRDocumentReference *doc = [self documentRef];
157+
158+
XCTestExpectation *expectation = [self expectationWithDescription:@"testUpdateNestedFields"];
159+
FIRWriteBatch *batch = [doc.firestore batch];
160+
[batch setData:@{@"a" : @{@"b" : @"old"}, @"c" : @{@"d" : @"old"}, @"e" : @{@"f" : @"old"}}
161+
forDocument:doc];
162+
[batch
163+
updateData:@{@"a.b" : @"new", [[FIRFieldPath alloc] initWithFields:@[ @"c", @"d" ]] : @"new"}
164+
forDocument:doc];
165+
[batch commitWithCompletion:^(NSError *_Nullable error) {
166+
XCTAssertNil(error);
167+
[doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
168+
XCTAssertNil(error);
169+
XCTAssertEqualObjects(snapshot.data, (@{
170+
@"a" : @{@"b" : @"new"},
171+
@"c" : @{@"d" : @"new"},
172+
@"e" : @{@"f" : @"old"}
173+
}));
174+
}];
175+
[expectation fulfill];
176+
}];
177+
178+
[self awaitExpectations];
179+
}
180+
127181
- (void)testDeleteDocuments {
128182
FIRDocumentReference *doc = [self documentRef];
129183
[self writeDocumentRef:doc data:@{@"foo" : @"bar"}];
@@ -161,6 +215,7 @@ - (void)testBatchesCommitAtomicallyRaisingCorrectEvents {
161215
XCTAssertNil(error);
162216
[expectation fulfill];
163217
}];
218+
[self awaitExpectations];
164219

165220
FIRQuerySnapshot *localSnap = [accumulator awaitEventWithName:@"local event"];
166221
XCTAssertTrue(localSnap.metadata.hasPendingWrites);
@@ -192,6 +247,7 @@ - (void)testBatchesFailAtomicallyRaisingCorrectEvents {
192247
XCTAssertEqual(error.code, FIRFirestoreErrorCodeNotFound);
193248
[expectation fulfill];
194249
}];
250+
[self awaitExpectations];
195251

196252
// Local event with the set document.
197253
FIRQuerySnapshot *localSnap = [accumulator awaitEventWithName:@"local event"];
@@ -223,6 +279,7 @@ - (void)testWriteTheSameServerTimestampAcrossWrites {
223279
XCTAssertNil(error);
224280
[expectation fulfill];
225281
}];
282+
[self awaitExpectations];
226283

227284
FIRQuerySnapshot *localSnap = [accumulator awaitEventWithName:@"local event"];
228285
XCTAssertTrue(localSnap.metadata.hasPendingWrites);
@@ -254,6 +311,7 @@ - (void)testCanWriteTheSameDocumentMultipleTimes {
254311
XCTAssertNil(error);
255312
[expectation fulfill];
256313
}];
314+
[self awaitExpectations];
257315

258316
FIRDocumentSnapshot *localSnap = [accumulator awaitEventWithName:@"local event"];
259317
XCTAssertTrue(localSnap.metadata.hasPendingWrites);
@@ -265,50 +323,39 @@ - (void)testCanWriteTheSameDocumentMultipleTimes {
265323
XCTAssertEqualObjects(serverSnap.data, (@{@"a" : @1, @"b" : @2, @"when" : when}));
266324
}
267325

268-
- (void)testUpdateFieldsWithDots {
269-
FIRDocumentReference *doc = [self documentRef];
326+
- (void)testCanWriteVeryLargeBatches {
327+
// On Android, SQLite Cursors are limited reading no more than 2 MB per row (despite being able
328+
// to write very large values). This test verifies that the local MutationQueue is not subject
329+
// to this limitation.
330+
331+
// Create a map containing nearly 1 MB of data. Note that if you use 1024 below this will create
332+
// a document larger than 1 MB, which will be rejected by the backend as too large.
333+
NSString *kb = [@"" stringByPaddingToLength:1000 withString:@"a" startingAtIndex:0];
334+
NSMutableDictionary<NSString *, id> *values = [NSMutableDictionary dictionary];
335+
for (int i = 0; i < 1000; i++) {
336+
values[WrapNSString(CreateAutoId())] = kb;
337+
}
270338

271-
XCTestExpectation *expectation = [self expectationWithDescription:@"testUpdateFieldsWithDots"];
339+
FIRDocumentReference *doc = [self documentRef];
272340
FIRWriteBatch *batch = [doc.firestore batch];
273-
[batch setData:@{@"a.b" : @"old", @"c.d" : @"old"} forDocument:doc];
274-
[batch updateData:@{[[FIRFieldPath alloc] initWithFields:@[ @"a.b" ]] : @"new"} forDocument:doc];
275-
276-
[batch commitWithCompletion:^(NSError *_Nullable error) {
277-
XCTAssertNil(error);
278-
[doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
279-
XCTAssertNil(error);
280-
XCTAssertEqualObjects(snapshot.data, (@{@"a.b" : @"new", @"c.d" : @"old"}));
281-
}];
282-
[expectation fulfill];
283-
}];
284341

285-
[self awaitExpectations];
286-
}
287-
288-
- (void)testUpdateNestedFields {
289-
FIRDocumentReference *doc = [self documentRef];
342+
// Write a batch containing 3 copies of the data, creating a ~3 MB batch. Writing to the same
343+
// document in a batch is allowed and so long as the net size of the document is under 1 MB the
344+
// batch is allowed.
345+
[batch setData:values forDocument:doc];
346+
for (int i = 0; i < 2; i++) {
347+
[batch updateData:values forDocument:doc];
348+
}
290349

291-
XCTestExpectation *expectation = [self expectationWithDescription:@"testUpdateNestedFields"];
292-
FIRWriteBatch *batch = [doc.firestore batch];
293-
[batch setData:@{@"a" : @{@"b" : @"old"}, @"c" : @{@"d" : @"old"}, @"e" : @{@"f" : @"old"}}
294-
forDocument:doc];
295-
[batch
296-
updateData:@{@"a.b" : @"new", [[FIRFieldPath alloc] initWithFields:@[ @"c", @"d" ]] : @"new"}
297-
forDocument:doc];
350+
XCTestExpectation *expectation = [self expectationWithDescription:@"batch written"];
298351
[batch commitWithCompletion:^(NSError *_Nullable error) {
299352
XCTAssertNil(error);
300-
[doc getDocumentWithCompletion:^(FIRDocumentSnapshot *snapshot, NSError *error) {
301-
XCTAssertNil(error);
302-
XCTAssertEqualObjects(snapshot.data, (@{
303-
@"a" : @{@"b" : @"new"},
304-
@"c" : @{@"d" : @"new"},
305-
@"e" : @{@"f" : @"old"}
306-
}));
307-
}];
308353
[expectation fulfill];
309354
}];
310-
311355
[self awaitExpectations];
356+
357+
FIRDocumentSnapshot *snap = [self readDocumentForRef:doc];
358+
XCTAssertEqualObjects(values, snap.data);
312359
}
313360

314361
// Returns how much memory the test application is currently using, in megabytes (fractional part is
@@ -363,3 +410,5 @@ - (void)testReasonableMemoryUsageForLotsOfMutations {
363410
}
364411

365412
@end
413+
414+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)