diff --git a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm index 6bbeddd7356..25186c7fb02 100644 --- a/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm +++ b/Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm @@ -22,9 +22,11 @@ #import #import #import +#import #import #import #import +#import #import #import @@ -61,6 +63,12 @@ NS_ASSUME_NONNULL_BEGIN +/** + * Firestore databases can be subject to a ~30s "cold start" delay if they have not been used + * recently, so before any tests run we "prime" the backend. + */ +static const double kPrimingTimeout = 45.0; + @interface FIRFirestore (Testing) @property(nonatomic, strong) FSTDispatchQueue *workerDispatchQueue; @end @@ -195,9 +203,55 @@ - (FIRFirestore *)firestoreWithProjectID:(NSString *)projectID { firestore.settings = [FSTIntegrationTestCase settings]; [_firestores addObject:firestore]; + + [self primeBackend:firestore]; + return firestore; } +- (void)primeBackend:(FIRFirestore *)db { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + XCTestExpectation *watchInitialized = + [self expectationWithDescription:@"Prime backend: Watch initialized"]; + __block XCTestExpectation *watchUpdateReceived; + FIRDocumentReference *docRef = [db documentWithPath:[self documentPath]]; + id listenerRegistration = + [docRef addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) { + if ([snapshot[@"value"] isEqual:@"done"]) { + [watchUpdateReceived fulfill]; + } else { + [watchInitialized fulfill]; + } + }]; + + // Wait for watch to initialize and deliver first event. + [self awaitExpectations]; + + watchUpdateReceived = [self expectationWithDescription:@"Prime backend: Watch update received"]; + + // Use a transaction to perform a write without triggering any local events. + [docRef.firestore + runTransactionWithBlock:^id(FIRTransaction *transaction, NSError **pError) { + [transaction setData:@{@"value" : @"done"} forDocument:docRef]; + return nil; + } + completion:^(id result, NSError *error){ + }]; + + // Wait to see the write on the watch stream. + [self waitForExpectationsWithTimeout:kPrimingTimeout + handler:^(NSError *_Nullable expectationError) { + if (expectationError) { + XCTFail(@"Error waiting for prime backend: %@", + expectationError); + } + }]; + + [listenerRegistration remove]; + }); +} + - (void)shutdownFirestore:(FIRFirestore *)firestore { [firestore shutdownWithCompletion:[self completionForExpectationWithName:@"shutdown"]]; [self awaitExpectations];