Skip to content

Add priming logic to integration tests to avoid backend cold start issues. #1890

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
merged 1 commit into from
Oct 2, 2018
Merged
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
54 changes: 54 additions & 0 deletions Firestore/Example/Tests/Util/FSTIntegrationTestCase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
#import <FirebaseFirestore/FIRDocumentChange.h>
#import <FirebaseFirestore/FIRDocumentReference.h>
#import <FirebaseFirestore/FIRDocumentSnapshot.h>
#import <FirebaseFirestore/FIRFirestore.h>
#import <FirebaseFirestore/FIRFirestoreSettings.h>
#import <FirebaseFirestore/FIRQuerySnapshot.h>
#import <FirebaseFirestore/FIRSnapshotMetadata.h>
#import <FirebaseFirestore/FIRTransaction.h>
#import <GRPCClient/GRPCCall+ChannelArg.h>
#import <GRPCClient/GRPCCall+Tests.h>

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<FIRListenerRegistration> 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];
Expand Down