@@ -38,17 +38,25 @@ - (void)writesFinishedWithError:(NSError *_Nullable)error;
38
38
*/
39
39
@interface FSTStreamStatusDelegate : NSObject <FSTWatchStreamDelegate, FSTWriteStreamDelegate>
40
40
41
+ - (instancetype )initFrom : (XCTestCase *)testCase
42
+ usingQueue : (FSTDispatchQueue *)dispatchQueue NS_DESIGNATED_INITIALIZER;
43
+ - (instancetype )init NS_UNAVAILABLE;
44
+
41
45
@property (nonatomic , readonly ) NSMutableArray <NSString *> *states;
42
46
@property (atomic , readwrite ) BOOL invokeCallbacks;
43
47
@property (nonatomic , weak ) XCTestExpectation *expectation;
44
48
@property (nonatomic , weak , readonly ) FSTStream *stream;
49
+ @property (nonatomic , weak , readonly ) XCTestCase *testCase;
50
+ @property (nonatomic , weak , readonly ) FSTDispatchQueue *dispatchQueue;
45
51
46
52
@end
47
53
48
54
@implementation FSTStreamStatusDelegate
49
55
50
- - (instancetype )init {
56
+ - (instancetype )initFrom : (XCTestCase *) testCase usingQueue : (FSTDispatchQueue *) dispatchQueue {
51
57
if (self = [super init ]) {
58
+ _testCase = testCase;
59
+ _dispatchQueue = dispatchQueue;
52
60
_states = [NSMutableArray new ];
53
61
}
54
62
@@ -99,9 +107,15 @@ - (void)writeStreamDidReceiveResponseWithVersion:(FSTSnapshotVersion *)commitVer
99
107
_expectation = nil ;
100
108
}
101
109
102
- - (void )fulfillOnCallback : (XCTestExpectation *)expectation {
110
+ /* * Executes 'block' using the provided FSTDispatchQueue and waits for any callback on this delegate
111
+ * to be called. */
112
+ - (void )awaitNotificationFromBlock : (void (^)(void ))block {
103
113
FSTAssert (_expectation == nil , @" Previous expectation still active" );
114
+ XCTestExpectation *expectation =
115
+ [self .testCase expectationWithDescription: @" awaitCallbackInBlock" ];
104
116
_expectation = expectation;
117
+ [self .dispatchQueue dispatchAsync: block];
118
+ [self .testCase awaitExpectations ];
105
119
}
106
120
107
121
@end
@@ -140,16 +154,12 @@ - (void)setUp {
140
154
_credentials = [[FSTEmptyCredentialsProvider alloc ] init ];
141
155
}
142
156
143
- - (void )tearDown {
144
- [super tearDown ];
145
- }
146
-
147
157
- (FSTWriteStream *)setUpWriteStream {
148
158
FSTDatastore *datastore = [[FSTDatastore alloc ] initWithDatabaseInfo: _databaseInfo
149
159
workerDispatchQueue: _workerDispatchQueue
150
160
credentials: _credentials];
151
161
152
- _delegate = [FSTStreamStatusDelegate new ];
162
+ _delegate = [[ FSTStreamStatusDelegate alloc ] initFrom: self usingQueue: _workerDispatchQueue ];
153
163
return [datastore createWriteStreamWithDelegate: _delegate];
154
164
}
155
165
@@ -158,28 +168,30 @@ - (FSTWatchStream *)setUpWatchStream {
158
168
workerDispatchQueue: _workerDispatchQueue
159
169
credentials: _credentials];
160
170
161
- _delegate = [FSTStreamStatusDelegate new ];
171
+ _delegate = [[ FSTStreamStatusDelegate alloc ] initFrom: self usingQueue: _workerDispatchQueue ];
162
172
return [datastore createWatchStreamWithDelegate: _delegate];
163
173
}
164
174
165
- - (void )verifyDelegate : (NSArray <NSString *> *)expectedStates {
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 {
166
180
// Drain queue
167
181
dispatch_sync (_testQueue, ^{
168
182
});
169
183
170
184
XCTAssertEqualObjects (_delegate.states , expectedStates);
185
+ [_delegate.states removeAllObjects ];
171
186
}
172
187
173
188
/* * Verifies that the watch stream does not issue an onClose callback after a call to stop(). */
174
189
- (void )testWatchStreamStopBeforeHandshake {
175
190
FSTWatchStream *watchStream = [self setUpWatchStream ];
176
191
177
- XCTestExpectation *openExpectation = [self expectationWithDescription: @" open" ];
178
- [_delegate fulfillOnCallback: openExpectation];
179
- [_workerDispatchQueue dispatchAsync: ^{
192
+ [_delegate awaitNotificationFromBlock: ^() {
180
193
[watchStream start ];
181
194
}];
182
- [self awaitExpectations ];
183
195
184
196
// Stop must not call watchStreamDidClose because the full implementation of the delegate could
185
197
// attempt to restart the stream in the event it had pending watches.
@@ -190,19 +202,16 @@ - (void)testWatchStreamStopBeforeHandshake {
190
202
// Simulate a final callback from GRPC
191
203
[watchStream writesFinishedWithError: nil ];
192
204
193
- [self verifyDelegate : @[ @" watchStreamDidOpen" ]];
205
+ [self verifyDelegateObservedStates : @[ @" watchStreamDidOpen" ]];
194
206
}
195
207
196
208
/* * Verifies that the write stream does not issue an onClose callback after a call to stop(). */
197
209
- (void )testWriteStreamStopBeforeHandshake {
198
210
FSTWriteStream *writeStream = [self setUpWriteStream ];
199
211
200
- XCTestExpectation *openExpectation = [self expectationWithDescription: @" open" ];
201
- [_delegate fulfillOnCallback: openExpectation];
202
- [_workerDispatchQueue dispatchAsync: ^{
212
+ [_delegate awaitNotificationFromBlock: ^() {
203
213
[writeStream start ];
204
214
}];
205
- [self awaitExpectations ];
206
215
207
216
// Don't start the handshake.
208
217
@@ -215,44 +224,35 @@ - (void)testWriteStreamStopBeforeHandshake {
215
224
// Simulate a final callback from GRPC
216
225
[writeStream writesFinishedWithError: nil ];
217
226
218
- [self verifyDelegate : @[ @" writeStreamDidOpen" ]];
227
+ [self verifyDelegateObservedStates : @[ @" writeStreamDidOpen" ]];
219
228
}
220
229
221
230
- (void )testWriteStreamStopAfterHandshake {
222
231
FSTWriteStream *writeStream = [self setUpWriteStream ];
223
232
224
- XCTestExpectation *openExpectation = [self expectationWithDescription: @" open" ];
225
- [_delegate fulfillOnCallback: openExpectation];
226
- [_workerDispatchQueue dispatchAsync: ^{
233
+ [_delegate awaitNotificationFromBlock: ^() {
227
234
[writeStream start ];
228
235
}];
229
- [self awaitExpectations ];
230
236
231
237
// Writing before the handshake should throw
232
238
dispatch_sync (_testQueue, ^{
233
239
XCTAssertThrows ([writeStream writeMutations: _mutations]);
234
240
});
235
241
236
- XCTestExpectation *handshakeExpectation = [self expectationWithDescription: @" handshake" ];
237
- [_delegate fulfillOnCallback: handshakeExpectation];
238
- [_workerDispatchQueue dispatchAsync: ^{
242
+ [_delegate awaitNotificationFromBlock: ^() {
239
243
[writeStream writeHandshake ];
240
244
}];
241
- [self awaitExpectations ];
242
245
243
246
// Now writes should succeed
244
- XCTestExpectation *writeExpectation = [self expectationWithDescription: @" write" ];
245
- [_delegate fulfillOnCallback: writeExpectation];
246
- [_workerDispatchQueue dispatchAsync: ^{
247
+ [_delegate awaitNotificationFromBlock: ^() {
247
248
[writeStream writeMutations: _mutations];
248
249
}];
249
- [self awaitExpectations ];
250
250
251
251
[_workerDispatchQueue dispatchAsync: ^{
252
252
[writeStream stop ];
253
253
}];
254
254
255
- [self verifyDelegate : @[
255
+ [self verifyDelegateObservedStates : @[
256
256
@" writeStreamDidOpen" , @" writeStreamDidCompleteHandshake" ,
257
257
@" writeStreamDidReceiveResponseWithVersion"
258
258
]];
0 commit comments