Skip to content

Commit 02ff6bb

Browse files
Closing the write and watch stream after 60s of idleness (#388)
1 parent 1db9fd8 commit 02ff6bb

File tree

14 files changed

+540
-177
lines changed

14 files changed

+540
-177
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
AFE6114F0D4DAECBA7B7C089 /* Pods_Firestore_IntegrationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */; };
6060
C4E749275AD0FBDF9F4716A8 /* Pods_SwiftBuildTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32AD40BF6B0E849B07FFD05E /* Pods_SwiftBuildTest.framework */; };
6161
D5B2532E4676014F57A7EAB9 /* FSTStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */; };
62+
D5B25474286C9800CE42B8C2 /* FSTTestDispatchQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */; };
63+
D5B259FDEE8094E8D710C5BF /* FSTTestDispatchQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */; };
6264
DE03B2C91F2149D600A30B9C /* FSTTransactionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C61F0D48AC0013853F /* FSTTransactionTests.m */; };
6365
DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
6466
DE03B2D51F2149D600A30B9C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
@@ -222,6 +224,8 @@
222224
B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
223225
CE00BABB5A3AAB44A4C209E2 /* Pods-Firestore_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests/Pods-Firestore_Tests.debug.xcconfig"; sourceTree = "<group>"; };
224226
D3CC3DC5338DCAF43A211155 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
227+
D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSTTestDispatchQueue.m; sourceTree = "<group>"; };
228+
D5B259DAA9149B80D6245B57 /* FSTTestDispatchQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSTTestDispatchQueue.h; sourceTree = "<group>"; };
225229
D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSTStreamTests.m; sourceTree = "<group>"; };
226230
DB17FEDFB80770611A935A60 /* Pods-Firestore_IntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_IntegrationTests/Pods-Firestore_IntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
227231
DE03B2E91F2149D600A30B9C /* Firestore_IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -561,6 +565,8 @@
561565
DE51B18A1F0D48AC0013853F /* FSTUtilTests.m */,
562566
54E9282A1F339CAD00C1953E /* XCTestCase+Await.h */,
563567
54E9282B1F339CAD00C1953E /* XCTestCase+Await.m */,
568+
D5B259DAA9149B80D6245B57 /* FSTTestDispatchQueue.h */,
569+
D5B25292CED31B81FDED0411 /* FSTTestDispatchQueue.m */,
564570
);
565571
path = Util;
566572
sourceTree = "<group>";
@@ -1175,6 +1181,7 @@
11751181
DE51B1CD1F0D48CD0013853F /* FSTDatabaseInfoTests.m in Sources */,
11761182
DE51B1F21F0D49140013853F /* FSTPathTests.m in Sources */,
11771183
DE51B1DD1F0D490D0013853F /* FSTLocalStoreTests.m in Sources */,
1184+
D5B25474286C9800CE42B8C2 /* FSTTestDispatchQueue.m in Sources */,
11781185
);
11791186
runOnlyForDeploymentPostprocessing = 0;
11801187
};
@@ -1199,6 +1206,7 @@
11991206
DE03B2C91F2149D600A30B9C /* FSTTransactionTests.m in Sources */,
12001207
54DA12B11F315F3800DD57A1 /* FIRValidationTests.m in Sources */,
12011208
D5B2532E4676014F57A7EAB9 /* FSTStreamTests.m in Sources */,
1209+
D5B259FDEE8094E8D710C5BF /* FSTTestDispatchQueue.m in Sources */,
12021210
);
12031211
runOnlyForDeploymentPostprocessing = 0;
12041212
};

Firestore/Example/Tests/Integration/API/FIRDatabaseTests.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,4 +913,22 @@ - (void)testCantGetDocumentsWhileOffline {
913913
[self awaitExpectations];
914914
}
915915

916+
- (void)testWriteStreamReconnectsAfterIdle {
917+
FIRDocumentReference *doc = [self documentRef];
918+
FIRFirestore *firestore = doc.firestore;
919+
920+
[self writeDocumentRef:doc data:@{@"foo" : @"bar"}];
921+
[self waitForIdleFirestore:firestore];
922+
[self writeDocumentRef:doc data:@{@"foo" : @"bar"}];
923+
}
924+
925+
- (void)testWatchStreamReconnectsAfterIdle {
926+
FIRDocumentReference *doc = [self documentRef];
927+
FIRFirestore *firestore = doc.firestore;
928+
929+
[self readSnapshotForRef:[self documentRef] requireOnline:YES];
930+
[self waitForIdleFirestore:firestore];
931+
[self readSnapshotForRef:[self documentRef] requireOnline:YES];
932+
}
933+
916934
@end

Firestore/Example/Tests/Integration/FSTStreamTests.m

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222
#import "Core/FSTDatabaseInfo.h"
2323
#import "FSTHelpers.h"
2424
#import "FSTIntegrationTestCase.h"
25+
#import "FSTTestDispatchQueue.h"
2526
#import "Model/FSTDatabaseID.h"
2627
#import "Remote/FSTDatastore.h"
2728
#import "Util/FSTAssert.h"
28-
#import "Util/FSTDispatchQueue.h"
2929

3030
/** Exposes otherwise private methods for testing. */
3131
@interface FSTStream (Testing)
@@ -79,14 +79,14 @@ - (void)writeStreamDidCompleteHandshake {
7979
_expectation = nil;
8080
}
8181

82-
- (void)writeStreamDidClose:(NSError *_Nullable)error {
83-
[_states addObject:@"writeStreamDidClose"];
82+
- (void)writeStreamWasInterruptedWithError:(nullable NSError *)error {
83+
[_states addObject:@"writeStreamWasInterrupted"];
8484
[_expectation fulfill];
8585
_expectation = nil;
8686
}
8787

88-
- (void)watchStreamDidClose:(NSError *_Nullable)error {
89-
[_states addObject:@"watchStreamDidClose"];
88+
- (void)watchStreamWasInterruptedWithError:(nullable NSError *)error {
89+
[_states addObject:@"watchStreamWasInterrupted"];
9090
[_expectation fulfill];
9191
_expectation = nil;
9292
}
@@ -126,10 +126,10 @@ @interface FSTStreamTests : XCTestCase
126126

127127
@implementation FSTStreamTests {
128128
dispatch_queue_t _testQueue;
129+
FSTTestDispatchQueue *_workerDispatchQueue;
129130
FSTDatabaseInfo *_databaseInfo;
130131
FSTEmptyCredentialsProvider *_credentials;
131132
FSTStreamStatusDelegate *_delegate;
132-
FSTDispatchQueue *_workerDispatchQueue;
133133

134134
/** Single mutation to send to the write stream. */
135135
NSArray<FSTMutation *> *_mutations;
@@ -138,38 +138,37 @@ @implementation FSTStreamTests {
138138
- (void)setUp {
139139
[super setUp];
140140

141-
_mutations = @[ FSTTestSetMutation(@"foo/bar", @{}) ];
142-
143141
FIRFirestoreSettings *settings = [FSTIntegrationTestCase settings];
144142
FSTDatabaseID *databaseID =
145143
[FSTDatabaseID databaseIDWithProject:[FSTIntegrationTestCase projectID]
146144
database:kDefaultDatabaseID];
147145

146+
_testQueue = dispatch_queue_create("FSTStreamTestWorkerQueue", DISPATCH_QUEUE_SERIAL);
147+
_workerDispatchQueue = [[FSTTestDispatchQueue alloc] initWithQueue:_testQueue];
148+
148149
_databaseInfo = [FSTDatabaseInfo databaseInfoWithDatabaseID:databaseID
149150
persistenceKey:@"test-key"
150151
host:settings.host
151152
sslEnabled:settings.sslEnabled];
152-
_testQueue = dispatch_queue_create("FSTStreamTestWorkerQueue", DISPATCH_QUEUE_SERIAL);
153-
_workerDispatchQueue = [FSTDispatchQueue queueWith:_testQueue];
154153
_credentials = [[FSTEmptyCredentialsProvider alloc] init];
154+
155+
_delegate = [[FSTStreamStatusDelegate alloc] initWithTestCase:self queue:_workerDispatchQueue];
156+
157+
_mutations = @[ FSTTestSetMutation(@"foo/bar", @{}) ];
155158
}
156159

157160
- (FSTWriteStream *)setUpWriteStream {
158161
FSTDatastore *datastore = [[FSTDatastore alloc] initWithDatabaseInfo:_databaseInfo
159162
workerDispatchQueue:_workerDispatchQueue
160163
credentials:_credentials];
161-
162-
_delegate = [[FSTStreamStatusDelegate alloc] initWithTestCase:self queue:_workerDispatchQueue];
163-
return [datastore createWriteStreamWithDelegate:_delegate];
164+
return [datastore createWriteStream];
164165
}
165166

166167
- (FSTWatchStream *)setUpWatchStream {
167168
FSTDatastore *datastore = [[FSTDatastore alloc] initWithDatabaseInfo:_databaseInfo
168169
workerDispatchQueue:_workerDispatchQueue
169170
credentials:_credentials];
170-
171-
_delegate = [[FSTStreamStatusDelegate alloc] initWithTestCase:self queue:_workerDispatchQueue];
172-
return [datastore createWatchStreamWithDelegate:_delegate];
171+
return [datastore createWatchStream];
173172
}
174173

175174
/**
@@ -190,7 +189,7 @@ - (void)testWatchStreamStopBeforeHandshake {
190189
FSTWatchStream *watchStream = [self setUpWatchStream];
191190

192191
[_delegate awaitNotificationFromBlock:^{
193-
[watchStream start];
192+
[watchStream startWithDelegate:_delegate];
194193
}];
195194

196195
// Stop must not call watchStreamDidClose because the full implementation of the delegate could
@@ -210,7 +209,7 @@ - (void)testWriteStreamStopBeforeHandshake {
210209
FSTWriteStream *writeStream = [self setUpWriteStream];
211210

212211
[_delegate awaitNotificationFromBlock:^{
213-
[writeStream start];
212+
[writeStream startWithDelegate:_delegate];
214213
}];
215214

216215
// Don't start the handshake.
@@ -231,7 +230,7 @@ - (void)testWriteStreamStopAfterHandshake {
231230
FSTWriteStream *writeStream = [self setUpWriteStream];
232231

233232
[_delegate awaitNotificationFromBlock:^{
234-
[writeStream start];
233+
[writeStream startWithDelegate:_delegate];
235234
}];
236235

237236
// Writing before the handshake should throw
@@ -258,4 +257,55 @@ - (void)testWriteStreamStopAfterHandshake {
258257
]];
259258
}
260259

260+
- (void)testStreamClosesWhenIdle {
261+
FSTWriteStream *writeStream = [self setUpWriteStream];
262+
263+
[_delegate awaitNotificationFromBlock:^{
264+
[writeStream startWithDelegate:_delegate];
265+
}];
266+
267+
[_delegate awaitNotificationFromBlock:^{
268+
[writeStream writeHandshake];
269+
}];
270+
271+
[_delegate awaitNotificationFromBlock:^{
272+
[writeStream markIdle];
273+
}];
274+
275+
dispatch_sync(_testQueue, ^{
276+
XCTAssertFalse([writeStream isOpen]);
277+
});
278+
279+
[self verifyDelegateObservedStates:@[
280+
@"writeStreamDidOpen", @"writeStreamDidCompleteHandshake", @"writeStreamWasInterrupted"
281+
]];
282+
}
283+
284+
- (void)testStreamCancelsIdleOnWrite {
285+
FSTWriteStream *writeStream = [self setUpWriteStream];
286+
287+
[_delegate awaitNotificationFromBlock:^{
288+
[writeStream startWithDelegate:_delegate];
289+
}];
290+
291+
[_delegate awaitNotificationFromBlock:^{
292+
[writeStream writeHandshake];
293+
}];
294+
295+
// Mark the stream idle, but immediately cancel the idle timer by issuing another write.
296+
[_delegate awaitNotificationFromBlock:^{
297+
[writeStream markIdle];
298+
[writeStream writeMutations:_mutations];
299+
}];
300+
301+
dispatch_sync(_testQueue, ^{
302+
XCTAssertTrue([writeStream isOpen]);
303+
});
304+
305+
[self verifyDelegateObservedStates:@[
306+
@"writeStreamDidOpen", @"writeStreamDidCompleteHandshake",
307+
@"writeStreamDidReceiveResponseWithVersion"
308+
]];
309+
}
310+
261311
@end

0 commit comments

Comments
 (0)