Skip to content

Commit 8bdce1d

Browse files
Moving the StreamTest to integration tests (#391)
1 parent 2cdc90e commit 8bdce1d

File tree

7 files changed

+333
-281
lines changed

7 files changed

+333
-281
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; };
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 */; };
61+
D5B2532E4676014F57A7EAB9 /* FSTStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */; };
6162
DE03B2C91F2149D600A30B9C /* FSTTransactionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1C61F0D48AC0013853F /* FSTTransactionTests.m */; };
6263
DE03B2D41F2149D600A30B9C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; };
6364
DE03B2D51F2149D600A30B9C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
@@ -119,7 +120,6 @@
119120
DE51B1F31F0D491B0013853F /* FSTDatastoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B31F0D48AC0013853F /* FSTDatastoreTests.m */; };
120121
DE51B1F41F0D491B0013853F /* FSTRemoteEventTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B41F0D48AC0013853F /* FSTRemoteEventTests.m */; };
121122
DE51B1F61F0D491B0013853F /* FSTSerializerBetaTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B61F0D48AC0013853F /* FSTSerializerBetaTests.m */; };
122-
DE51B1F71F0D491B0013853F /* FSTStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B71F0D48AC0013853F /* FSTStreamTests.m */; };
123123
DE51B1F81F0D491F0013853F /* FSTWatchChange+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1B91F0D48AC0013853F /* FSTWatchChange+Testing.m */; };
124124
DE51B1F91F0D491F0013853F /* FSTWatchChangeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1BA1F0D48AC0013853F /* FSTWatchChangeTests.m */; };
125125
DE51B1FA1F0D492C0013853F /* FSTLevelDBSpecTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DE51B1941F0D48AC0013853F /* FSTLevelDBSpecTests.m */; };
@@ -222,6 +222,7 @@
222222
B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
223223
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>"; };
224224
D3CC3DC5338DCAF43A211155 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = "<group>"; };
225+
D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSTStreamTests.m; sourceTree = "<group>"; };
225226
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>"; };
226227
DE03B2E91F2149D600A30B9C /* Firestore_IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Firestore_IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
227228
DE03B3621F215E1600A30B9C /* CAcert.pem */ = {isa = PBXFileReference; lastKnownFileType = text; path = CAcert.pem; sourceTree = "<group>"; };
@@ -292,7 +293,6 @@
292293
DE51B1B31F0D48AC0013853F /* FSTDatastoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTDatastoreTests.m; sourceTree = "<group>"; };
293294
DE51B1B41F0D48AC0013853F /* FSTRemoteEventTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTRemoteEventTests.m; sourceTree = "<group>"; };
294295
DE51B1B61F0D48AC0013853F /* FSTSerializerBetaTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTSerializerBetaTests.m; sourceTree = "<group>"; };
295-
DE51B1B71F0D48AC0013853F /* FSTStreamTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTStreamTests.m; sourceTree = "<group>"; };
296296
DE51B1B81F0D48AC0013853F /* FSTWatchChange+Testing.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FSTWatchChange+Testing.h"; sourceTree = "<group>"; };
297297
DE51B1B91F0D48AC0013853F /* FSTWatchChange+Testing.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "FSTWatchChange+Testing.m"; sourceTree = "<group>"; };
298298
DE51B1BA1F0D48AC0013853F /* FSTWatchChangeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FSTWatchChangeTests.m; sourceTree = "<group>"; };
@@ -622,7 +622,6 @@
622622
DE51B1B31F0D48AC0013853F /* FSTDatastoreTests.m */,
623623
DE51B1B41F0D48AC0013853F /* FSTRemoteEventTests.m */,
624624
DE51B1B61F0D48AC0013853F /* FSTSerializerBetaTests.m */,
625-
DE51B1B71F0D48AC0013853F /* FSTStreamTests.m */,
626625
DE51B1B81F0D48AC0013853F /* FSTWatchChange+Testing.h */,
627626
DE51B1B91F0D48AC0013853F /* FSTWatchChange+Testing.m */,
628627
DE51B1BA1F0D48AC0013853F /* FSTWatchChangeTests.m */,
@@ -639,6 +638,7 @@
639638
DE51B1C51F0D48AC0013853F /* FSTSmokeTests.m */,
640639
DE51B1C61F0D48AC0013853F /* FSTTransactionTests.m */,
641640
DE51B1C71F0D48AC0013853F /* Util */,
641+
D5B25C0D4AADFCA3ADB883E4 /* FSTStreamTests.m */,
642642
);
643643
path = Integration;
644644
sourceTree = "<group>";
@@ -1162,7 +1162,6 @@
11621162
DE51B1E91F0D490D0013853F /* FSTLevelDBMutationQueueTests.mm in Sources */,
11631163
DE51B1E61F0D490D0013853F /* FSTRemoteDocumentCacheTests.m in Sources */,
11641164
DE51B1D91F0D490D0013853F /* FSTEagerGarbageCollectorTests.m in Sources */,
1165-
DE51B1F71F0D491B0013853F /* FSTStreamTests.m in Sources */,
11661165
DE51B1E21F0D490D0013853F /* FSTMutationQueueTests.m in Sources */,
11671166
DE51B1E81F0D490D0013853F /* FSTLevelDBKeyTests.mm in Sources */,
11681167
DE51B1E31F0D490D0013853F /* FSTPersistenceTestHelpers.m in Sources */,
@@ -1199,6 +1198,7 @@
11991198
DE03B2F21F214BAA00A30B9C /* FIRListenerRegistrationTests.m in Sources */,
12001199
DE03B2C91F2149D600A30B9C /* FSTTransactionTests.m in Sources */,
12011200
54DA12B11F315F3800DD57A1 /* FIRValidationTests.m in Sources */,
1201+
D5B2532E4676014F57A7EAB9 /* FSTStreamTests.m in Sources */,
12021202
);
12031203
runOnlyForDeploymentPostprocessing = 0;
12041204
};
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/*
2+
* Copyright 2017 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <XCTest/XCTest.h>
18+
19+
#import <Firestore/FIRFirestoreSettings.h>
20+
21+
#import "Auth/FSTEmptyCredentialsProvider.h"
22+
#import "Core/FSTDatabaseInfo.h"
23+
#import "FSTHelpers.h"
24+
#import "FSTIntegrationTestCase.h"
25+
#import "Model/FSTDatabaseID.h"
26+
#import "Remote/FSTDatastore.h"
27+
#import "Util/FSTAssert.h"
28+
#import "Util/FSTDispatchQueue.h"
29+
30+
/** Exposes otherwise private methods for testing. */
31+
@interface FSTStream (Testing)
32+
- (void)writesFinishedWithError:(NSError *_Nullable)error;
33+
@end
34+
35+
/**
36+
* Implements FSTWatchStreamDelegate and FSTWriteStreamDelegate and supports waiting on callbacks
37+
* via `fulfillOnCallback`.
38+
*/
39+
@interface FSTStreamStatusDelegate : NSObject <FSTWatchStreamDelegate, FSTWriteStreamDelegate>
40+
41+
- (instancetype)initWithTestCase:(XCTestCase *)testCase
42+
queue:(FSTDispatchQueue *)dispatchQueue NS_DESIGNATED_INITIALIZER;
43+
- (instancetype)init NS_UNAVAILABLE;
44+
45+
@property(nonatomic, weak, readonly) XCTestCase *testCase;
46+
@property(nonatomic, strong, readonly) FSTDispatchQueue *dispatchQueue;
47+
@property(nonatomic, readonly) NSMutableArray<NSString *> *states;
48+
@property(nonatomic, strong) XCTestExpectation *expectation;
49+
50+
@end
51+
52+
@implementation FSTStreamStatusDelegate
53+
54+
- (instancetype)initWithTestCase:(XCTestCase *)testCase queue:(FSTDispatchQueue *)dispatchQueue {
55+
if (self = [super init]) {
56+
_testCase = testCase;
57+
_dispatchQueue = dispatchQueue;
58+
_states = [NSMutableArray new];
59+
}
60+
61+
return self;
62+
}
63+
64+
- (void)watchStreamDidOpen {
65+
[_states addObject:@"watchStreamDidOpen"];
66+
[_expectation fulfill];
67+
_expectation = nil;
68+
}
69+
70+
- (void)writeStreamDidOpen {
71+
[_states addObject:@"writeStreamDidOpen"];
72+
[_expectation fulfill];
73+
_expectation = nil;
74+
}
75+
76+
- (void)writeStreamDidCompleteHandshake {
77+
[_states addObject:@"writeStreamDidCompleteHandshake"];
78+
[_expectation fulfill];
79+
_expectation = nil;
80+
}
81+
82+
- (void)writeStreamDidClose:(NSError *_Nullable)error {
83+
[_states addObject:@"writeStreamDidClose"];
84+
[_expectation fulfill];
85+
_expectation = nil;
86+
}
87+
88+
- (void)watchStreamDidClose:(NSError *_Nullable)error {
89+
[_states addObject:@"watchStreamDidClose"];
90+
[_expectation fulfill];
91+
_expectation = nil;
92+
}
93+
94+
- (void)watchStreamDidChange:(FSTWatchChange *)change
95+
snapshotVersion:(FSTSnapshotVersion *)snapshotVersion {
96+
[_states addObject:@"watchStreamDidChange"];
97+
[_expectation fulfill];
98+
_expectation = nil;
99+
}
100+
101+
- (void)writeStreamDidReceiveResponseWithVersion:(FSTSnapshotVersion *)commitVersion
102+
mutationResults:(NSArray<FSTMutationResult *> *)results {
103+
[_states addObject:@"writeStreamDidReceiveResponseWithVersion"];
104+
[_expectation fulfill];
105+
_expectation = nil;
106+
}
107+
108+
/**
109+
* Executes 'block' using the provided FSTDispatchQueue and waits for any callback on this delegate
110+
* to be called.
111+
*/
112+
- (void)awaitNotificationFromBlock:(void (^)(void))block {
113+
FSTAssert(_expectation == nil, @"Previous expectation still active");
114+
XCTestExpectation *expectation =
115+
[self.testCase expectationWithDescription:@"awaitCallbackInBlock"];
116+
_expectation = expectation;
117+
[self.dispatchQueue dispatchAsync:block];
118+
[self.testCase awaitExpectations];
119+
}
120+
121+
@end
122+
123+
@interface FSTStreamTests : XCTestCase
124+
125+
@end
126+
127+
@implementation FSTStreamTests {
128+
dispatch_queue_t _testQueue;
129+
FSTDatabaseInfo *_databaseInfo;
130+
FSTEmptyCredentialsProvider *_credentials;
131+
FSTStreamStatusDelegate *_delegate;
132+
FSTDispatchQueue *_workerDispatchQueue;
133+
134+
/** Single mutation to send to the write stream. */
135+
NSArray<FSTMutation *> *_mutations;
136+
}
137+
138+
- (void)setUp {
139+
[super setUp];
140+
141+
_mutations = @[ FSTTestSetMutation(@"foo/bar", @{}) ];
142+
143+
FIRFirestoreSettings *settings = [FSTIntegrationTestCase settings];
144+
FSTDatabaseID *databaseID =
145+
[FSTDatabaseID databaseIDWithProject:[FSTIntegrationTestCase projectID]
146+
database:kDefaultDatabaseID];
147+
148+
_databaseInfo = [FSTDatabaseInfo databaseInfoWithDatabaseID:databaseID
149+
persistenceKey:@"test-key"
150+
host:settings.host
151+
sslEnabled:settings.sslEnabled];
152+
_testQueue = dispatch_queue_create("FSTStreamTestWorkerQueue", DISPATCH_QUEUE_SERIAL);
153+
_workerDispatchQueue = [FSTDispatchQueue queueWith:_testQueue];
154+
_credentials = [[FSTEmptyCredentialsProvider alloc] init];
155+
}
156+
157+
- (FSTWriteStream *)setUpWriteStream {
158+
FSTDatastore *datastore = [[FSTDatastore alloc] initWithDatabaseInfo:_databaseInfo
159+
workerDispatchQueue:_workerDispatchQueue
160+
credentials:_credentials];
161+
162+
_delegate = [[FSTStreamStatusDelegate alloc] initWithTestCase:self queue:_workerDispatchQueue];
163+
return [datastore createWriteStreamWithDelegate:_delegate];
164+
}
165+
166+
- (FSTWatchStream *)setUpWatchStream {
167+
FSTDatastore *datastore = [[FSTDatastore alloc] initWithDatabaseInfo:_databaseInfo
168+
workerDispatchQueue:_workerDispatchQueue
169+
credentials:_credentials];
170+
171+
_delegate = [[FSTStreamStatusDelegate alloc] initWithTestCase:self queue:_workerDispatchQueue];
172+
return [datastore createWatchStreamWithDelegate:_delegate];
173+
}
174+
175+
/**
176+
* Drains the test queue and asserts that all the observed callbacks (up to this point) match
177+
* 'expectedStates'. Clears the list of observed callbacks on completion.
178+
*/
179+
- (void)verifyDelegateObservedStates:(NSArray<NSString *> *)expectedStates {
180+
// Drain queue
181+
dispatch_sync(_testQueue, ^{
182+
});
183+
184+
XCTAssertEqualObjects(_delegate.states, expectedStates);
185+
[_delegate.states removeAllObjects];
186+
}
187+
188+
/** Verifies that the watch stream does not issue an onClose callback after a call to stop(). */
189+
- (void)testWatchStreamStopBeforeHandshake {
190+
FSTWatchStream *watchStream = [self setUpWatchStream];
191+
192+
[_delegate awaitNotificationFromBlock:^{
193+
[watchStream start];
194+
}];
195+
196+
// Stop must not call watchStreamDidClose because the full implementation of the delegate could
197+
// attempt to restart the stream in the event it had pending watches.
198+
[_workerDispatchQueue dispatchAsync:^{
199+
[watchStream stop];
200+
}];
201+
202+
// Simulate a final callback from GRPC
203+
[watchStream writesFinishedWithError:nil];
204+
205+
[self verifyDelegateObservedStates:@[ @"watchStreamDidOpen" ]];
206+
}
207+
208+
/** Verifies that the write stream does not issue an onClose callback after a call to stop(). */
209+
- (void)testWriteStreamStopBeforeHandshake {
210+
FSTWriteStream *writeStream = [self setUpWriteStream];
211+
212+
[_delegate awaitNotificationFromBlock:^{
213+
[writeStream start];
214+
}];
215+
216+
// Don't start the handshake.
217+
218+
// Stop must not call watchStreamDidClose because the full implementation of the delegate could
219+
// attempt to restart the stream in the event it had pending watches.
220+
[_workerDispatchQueue dispatchAsync:^{
221+
[writeStream stop];
222+
}];
223+
224+
// Simulate a final callback from GRPC
225+
[writeStream writesFinishedWithError:nil];
226+
227+
[self verifyDelegateObservedStates:@[ @"writeStreamDidOpen" ]];
228+
}
229+
230+
- (void)testWriteStreamStopAfterHandshake {
231+
FSTWriteStream *writeStream = [self setUpWriteStream];
232+
233+
[_delegate awaitNotificationFromBlock:^{
234+
[writeStream start];
235+
}];
236+
237+
// Writing before the handshake should throw
238+
dispatch_sync(_testQueue, ^{
239+
XCTAssertThrows([writeStream writeMutations:_mutations]);
240+
});
241+
242+
[_delegate awaitNotificationFromBlock:^{
243+
[writeStream writeHandshake];
244+
}];
245+
246+
// Now writes should succeed
247+
[_delegate awaitNotificationFromBlock:^{
248+
[writeStream writeMutations:_mutations];
249+
}];
250+
251+
[_workerDispatchQueue dispatchAsync:^{
252+
[writeStream stop];
253+
}];
254+
255+
[self verifyDelegateObservedStates:@[
256+
@"writeStreamDidOpen", @"writeStreamDidCompleteHandshake",
257+
@"writeStreamDidReceiveResponseWithVersion"
258+
]];
259+
}
260+
261+
@end

0 commit comments

Comments
 (0)