|
22 | 22 | #import <FirebaseFirestore/FIRDocumentChange.h>
|
23 | 23 | #import <FirebaseFirestore/FIRDocumentReference.h>
|
24 | 24 | #import <FirebaseFirestore/FIRDocumentSnapshot.h>
|
| 25 | +#import <FirebaseFirestore/FIRFirestore.h> |
25 | 26 | #import <FirebaseFirestore/FIRFirestoreSettings.h>
|
26 | 27 | #import <FirebaseFirestore/FIRQuerySnapshot.h>
|
27 | 28 | #import <FirebaseFirestore/FIRSnapshotMetadata.h>
|
| 29 | +#import <FirebaseFirestore/FIRTransaction.h> |
28 | 30 | #import <GRPCClient/GRPCCall+ChannelArg.h>
|
29 | 31 | #import <GRPCClient/GRPCCall+Tests.h>
|
30 | 32 |
|
|
61 | 63 |
|
62 | 64 | NS_ASSUME_NONNULL_BEGIN
|
63 | 65 |
|
| 66 | +/** |
| 67 | + * Firestore databases can be subject to a ~30s "cold start" delay if they have not been used |
| 68 | + * recently, so before any tests run we "prime" the backend. |
| 69 | + */ |
| 70 | +static const double kPrimingTimeout = 45.0; |
| 71 | + |
64 | 72 | @interface FIRFirestore (Testing)
|
65 | 73 | @property(nonatomic, strong) FSTDispatchQueue *workerDispatchQueue;
|
66 | 74 | @end
|
@@ -195,9 +203,55 @@ - (FIRFirestore *)firestoreWithProjectID:(NSString *)projectID {
|
195 | 203 | firestore.settings = [FSTIntegrationTestCase settings];
|
196 | 204 |
|
197 | 205 | [_firestores addObject:firestore];
|
| 206 | + |
| 207 | + [self primeBackend:firestore]; |
| 208 | + |
198 | 209 | return firestore;
|
199 | 210 | }
|
200 | 211 |
|
| 212 | +- (void)primeBackend:(FIRFirestore *)db { |
| 213 | + static dispatch_once_t onceToken; |
| 214 | + dispatch_once(&onceToken, ^{ |
| 215 | + XCTestExpectation *watchInitialized = |
| 216 | + [self expectationWithDescription:@"Prime backend: Watch initialized"]; |
| 217 | + __block XCTestExpectation *watchUpdateReceived; |
| 218 | + FIRDocumentReference *docRef = [db documentWithPath:[self documentPath]]; |
| 219 | + id<FIRListenerRegistration> listenerRegistration = |
| 220 | + [docRef addSnapshotListener:^(FIRDocumentSnapshot *snapshot, NSError *error) { |
| 221 | + if ([snapshot[@"value"] isEqual:@"done"]) { |
| 222 | + [watchUpdateReceived fulfill]; |
| 223 | + } else { |
| 224 | + [watchInitialized fulfill]; |
| 225 | + } |
| 226 | + }]; |
| 227 | + |
| 228 | + // Wait for watch to initialize and deliver first event. |
| 229 | + [self awaitExpectations]; |
| 230 | + |
| 231 | + watchUpdateReceived = [self expectationWithDescription:@"Prime backend: Watch update received"]; |
| 232 | + |
| 233 | + // Use a transaction to perform a write without triggering any local events. |
| 234 | + [docRef.firestore |
| 235 | + runTransactionWithBlock:^id(FIRTransaction *transaction, NSError **pError) { |
| 236 | + [transaction setData:@{@"value" : @"done"} forDocument:docRef]; |
| 237 | + return nil; |
| 238 | + } |
| 239 | + completion:^(id result, NSError *error){ |
| 240 | + }]; |
| 241 | + |
| 242 | + // Wait to see the write on the watch stream. |
| 243 | + [self waitForExpectationsWithTimeout:kPrimingTimeout |
| 244 | + handler:^(NSError *_Nullable expectationError) { |
| 245 | + if (expectationError) { |
| 246 | + XCTFail(@"Error waiting for prime backend: %@", |
| 247 | + expectationError); |
| 248 | + } |
| 249 | + }]; |
| 250 | + |
| 251 | + [listenerRegistration remove]; |
| 252 | + }); |
| 253 | +} |
| 254 | + |
201 | 255 | - (void)shutdownFirestore:(FIRFirestore *)firestore {
|
202 | 256 | [firestore shutdownWithCompletion:[self completionForExpectationWithName:@"shutdown"]];
|
203 | 257 | [self awaitExpectations];
|
|
0 commit comments