From ae013976b24ce95140d3a9b129f15d4714532e28 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 7 Aug 2018 09:34:51 -0700 Subject: [PATCH 1/3] Surface error_string to ObjC users --- src/objective-c/GRPCClient/private/GRPCWrappedCall.m | 8 ++++++-- src/objective-c/GRPCClient/private/NSError+GRPC.h | 4 +++- src/objective-c/GRPCClient/private/NSError+GRPC.m | 10 ++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m index f28e494868e..7781d27ca4f 100644 --- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m +++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m @@ -187,6 +187,7 @@ grpc_slice _details; size_t _detailsCapacity; grpc_metadata_array _trailers; + const char *_errorString; } - (instancetype)init { @@ -200,6 +201,7 @@ _op.data.recv_status_on_client.status_details = &_details; grpc_metadata_array_init(&_trailers); _op.data.recv_status_on_client.trailing_metadata = &_trailers; + _op.data.recv_status_on_client.error_string = &_errorString; if (handler) { // Prevent reference cycle with _handler __weak typeof(self) weakSelf = self; @@ -207,8 +209,9 @@ __strong typeof(self) strongSelf = weakSelf; if (strongSelf) { char *details = grpc_slice_to_c_string(strongSelf->_details); - NSError *error = - [NSError grpc_errorFromStatusCode:strongSelf->_statusCode details:details]; + NSError *error = [NSError grpc_errorFromStatusCode:strongSelf->_statusCode + details:details + errorString:strongSelf->_errorString]; NSDictionary *trailers = [NSDictionary grpc_dictionaryFromMetadataArray:strongSelf->_trailers]; handler(error, trailers); @@ -223,6 +226,7 @@ - (void)dealloc { grpc_metadata_array_destroy(&_trailers); grpc_slice_unref(_details); + gpr_free((void *)_errorString); } @end diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.h b/src/objective-c/GRPCClient/private/NSError+GRPC.h index e96b7297c28..a63e76ee4d0 100644 --- a/src/objective-c/GRPCClient/private/NSError+GRPC.h +++ b/src/objective-c/GRPCClient/private/NSError+GRPC.h @@ -24,5 +24,7 @@ * Returns nil if the status code is OK. Otherwise, a NSError whose code is one of |GRPCErrorCode| * and whose domain is |kGRPCErrorDomain|. */ -+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details; ++ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode + details:(char *)details + errorString:(const char *)errorString; @end diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.m b/src/objective-c/GRPCClient/private/NSError+GRPC.m index c2e65e4d8a2..199b2ebb6c3 100644 --- a/src/objective-c/GRPCClient/private/NSError+GRPC.m +++ b/src/objective-c/GRPCClient/private/NSError+GRPC.m @@ -23,13 +23,19 @@ NSString *const kGRPCErrorDomain = @"io.grpc"; @implementation NSError (GRPC) -+ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode details:(char *)details { ++ (instancetype)grpc_errorFromStatusCode:(grpc_status_code)statusCode + details:(char *)details + errorString:(const char *)errorString { if (statusCode == GRPC_STATUS_OK) { return nil; } NSString *message = [NSString stringWithCString:details encoding:NSUTF8StringEncoding]; + NSString *debugMessage = [NSString stringWithCString:errorString encoding:NSUTF8StringEncoding]; return [NSError errorWithDomain:kGRPCErrorDomain code:statusCode - userInfo:@{NSLocalizedDescriptionKey : message}]; + userInfo:@{ + NSLocalizedDescriptionKey : message, + NSDebugDescriptionErrorKey : debugMessage + }]; } @end From 8617879613133c06782c955b03c0bd3d1f8517e2 Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 7 Aug 2018 12:04:35 -0700 Subject: [PATCH 2/3] Add test for returned debug information --- src/objective-c/tests/GRPCClientTests.m | 35 +++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 2a169800a09..6dda346514e 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -591,4 +591,39 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self testTimeoutBackoffWithTimeout:0.3 Backoff:0.7]; } +- (void)testErrorDebugInformation { + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"RPC unauthorized."]; + + RMTSimpleRequest *request = [RMTSimpleRequest message]; + request.fillUsername = YES; + request.fillOauthScope = YES; + GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]]; + + GRPCCall *call = [[GRPCCall alloc] initWithHost:kRemoteSSLHost + path:kUnaryCallMethod.HTTPPath + requestsWriter:requestsWriter]; + + call.oauth2AccessToken = @"bogusToken"; + + id responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTFail(@"Received unexpected response: %@", value); + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNotNil(errorOrNil, @"Finished without error!"); + NSDictionary *userInfo = errorOrNil.userInfo; + NSString *debugInformation = userInfo[NSDebugDescriptionErrorKey]; + XCTAssertNotNil(debugInformation); + XCTAssertNotEqual([debugInformation length], 0); + NSString *challengeHeader = call.oauth2ChallengeHeader; + XCTAssertGreaterThan(challengeHeader.length, 0, @"No challenge in response headers %@", + call.responseHeaders); + [expectation fulfill]; + }]; + + [call startWithWriteable:responsesWriteable]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + @end From d562ad11accb84c06c15e8e1b9177ac353f1c01c Mon Sep 17 00:00:00 2001 From: Muxi Yan Date: Tue, 7 Aug 2018 17:19:55 -0700 Subject: [PATCH 3/3] clang-format --- src/objective-c/tests/GRPCClientTests.m | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 6dda346514e..a0de8ba8990 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -606,20 +606,20 @@ static GRPCProtoMethod *kFullDuplexCallMethod; call.oauth2AccessToken = @"bogusToken"; id responsesWriteable = - [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTFail(@"Received unexpected response: %@", value); - } - completionHandler:^(NSError *errorOrNil) { - XCTAssertNotNil(errorOrNil, @"Finished without error!"); - NSDictionary *userInfo = errorOrNil.userInfo; - NSString *debugInformation = userInfo[NSDebugDescriptionErrorKey]; - XCTAssertNotNil(debugInformation); - XCTAssertNotEqual([debugInformation length], 0); - NSString *challengeHeader = call.oauth2ChallengeHeader; - XCTAssertGreaterThan(challengeHeader.length, 0, @"No challenge in response headers %@", - call.responseHeaders); - [expectation fulfill]; - }]; + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTFail(@"Received unexpected response: %@", value); + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNotNil(errorOrNil, @"Finished without error!"); + NSDictionary *userInfo = errorOrNil.userInfo; + NSString *debugInformation = userInfo[NSDebugDescriptionErrorKey]; + XCTAssertNotNil(debugInformation); + XCTAssertNotEqual([debugInformation length], 0); + NSString *challengeHeader = call.oauth2ChallengeHeader; + XCTAssertGreaterThan(challengeHeader.length, 0, @"No challenge in response headers %@", + call.responseHeaders); + [expectation fulfill]; + }]; [call startWithWriteable:responsesWriteable];