diff --git a/src/objective-c/tests/InteropTests/InteropTests.m b/src/objective-c/tests/InteropTests/InteropTests.m index 9c86a29373c..e2773984b15 100644 --- a/src/objective-c/tests/InteropTests/InteropTests.m +++ b/src/objective-c/tests/InteropTests/InteropTests.m @@ -39,6 +39,7 @@ #define TEST_TIMEOUT 32 +static const int kTestRetries = 3; extern const char *kCFStreamVarName; // Convenience constructors for the generated proto messages: @@ -382,6 +383,36 @@ static dispatch_once_t initGlobalInterceptorFactory; RMTTestService *_service; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +- (void)retriableTest:(SEL)selector retries:(int)retries timeout:(NSTimeInterval)timeout { + for (int i = 0; i < retries; i++) { + NSDate *waitUntil = [[NSDate date] dateByAddingTimeInterval:timeout]; + NSCondition *cv = [[NSCondition alloc] init]; + __block BOOL done = NO; + [cv lock]; + dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{ + [self performSelector:selector]; + [cv lock]; + done = YES; + [cv signal]; + [cv unlock]; + }); + while (!done && [waitUntil timeIntervalSinceNow] > 0) { + [cv waitUntilDate:waitUntil]; + } + if (done) { + [cv unlock]; + break; + } else { + [cv unlock]; + [self tearDown]; + [self setUp]; + } + } +} +#pragma clang diagnostic pop + + (XCTestSuite *)defaultTestSuite { if (self == [InteropTests class]) { return [XCTestSuite testSuiteWithName:@"InteropTestsEmptySuite"]; @@ -721,14 +752,13 @@ static dispatch_once_t initGlobalInterceptorFactory; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } -- (void)testConcurrentRPCsWithErrors { - NSMutableArray *completeExpectations = [NSMutableArray array]; - int num_rpcs = 10; - for (int i = 0; i < num_rpcs; ++i) { - [completeExpectations - addObject:[self expectationWithDescription: - [NSString stringWithFormat:@"Received trailer for RPC %d", i]]]; - +- (void)concurrentRPCsWithErrors { + const int kNumRpcs = 10; + __block int completedCallCount = 0; + NSCondition *cv = [[NSCondition alloc] init]; + NSDate *waitUntil = [[NSDate date] dateByAddingTimeInterval:TEST_TIMEOUT]; + [cv lock]; + for (int i = 0; i < kNumRpcs; ++i) { RMTSimpleRequest *request = [RMTSimpleRequest message]; request.responseType = RMTPayloadType_Compressable; request.responseSize = 314159; @@ -739,20 +769,33 @@ static dispatch_once_t initGlobalInterceptorFactory; request.responseStatus.code = GRPC_STATUS_CANCELLED; } - [_service unaryCallWithRequest:request - handler:^(RMTSimpleResponse *response, NSError *error) { - if (error == nil) { - RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; - expectedResponse.payload.type = RMTPayloadType_Compressable; - expectedResponse.payload.body = - [NSMutableData dataWithLength:314159]; - XCTAssertEqualObjects(response, expectedResponse); - } - [completeExpectations[i] fulfill]; - }]; + GRPCProtoCall *call = [_service + RPCToUnaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + if (error == nil) { + RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; + expectedResponse.payload.type = RMTPayloadType_Compressable; + expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; + XCTAssertEqualObjects(response, expectedResponse); + } + // DEBUG + [cv lock]; + if (++completedCallCount == kNumRpcs) { + [cv signal]; + } + [cv unlock]; + }]; + [call setResponseDispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)]; + [call start]; + } + while (completedCallCount 0) { + [cv waitUntilDate:waitUntil]; } + [cv unlock]; +} - [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +- (void)testConcurrentRPCsWithErrors { + [self retriableTest:@selector(concurrentRPCsWithErrors) retries:kTestRetries timeout:10]; } - (void)testPacketCoalescing {