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