Skip to content

Commit 9bb809c

Browse files
authored
Update the API service to log the returned message from the API (#6458)
* Update the API service to log the raw message from the API * Update CHANGELOG * Run style script * Update log formatting and changelog
1 parent 427cded commit 9bb809c

File tree

3 files changed

+93
-7
lines changed

3 files changed

+93
-7
lines changed

FirebaseAppDistribution/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# v0.9.3
2+
- [changed] Updated error log for non-200 API Service calls.
3+
4+
# v0.9.2
5+
- [fixed] Made bug fixes (#6346) available in Zip build and Carthage.
6+
17
# v0.9.1
28
- [changed] Updated header comments (#6321).
39
- [fixed] Bug for customers with restricted API keys unable to fetch releases (#6346).

FirebaseAppDistribution/Sources/FIRFADApiService.m

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,27 @@ + (NSMutableURLRequest *)createHTTPRequest:(NSString *)method
7878
return request;
7979
}
8080

81+
+ (NSString *)tryParseGoogleAPIErrorFromResponse:(NSData *)data {
82+
NSError *parseError;
83+
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data
84+
options:0
85+
error:&parseError];
86+
if (parseError) {
87+
return @"Could not parse additional details about this API error.";
88+
} else {
89+
NSDictionary *errorDict = [responseDict objectForKey:@"error"];
90+
if (!errorDict) {
91+
return @"Could not parse additional details about this API error.";
92+
}
93+
94+
NSString *message = [errorDict objectForKey:@"message"];
95+
if (!message) {
96+
return @"Could not parse additional details about this API error.";
97+
}
98+
return message;
99+
}
100+
}
101+
81102
+ (NSArray *)handleReleaseResponse:(NSData *)data
82103
response:(NSURLResponse *)response
83104
error:(NSError **_Nullable)error {
@@ -86,7 +107,8 @@ + (NSArray *)handleReleaseResponse:(NSData *)data
86107
httpResponse);
87108

88109
if ([self handleHttpResponseError:httpResponse error:error]) {
89-
FIRFADErrorLog(@"App Tester API service error - %@", [*error localizedDescription]);
110+
FIRFADErrorLog(@"App Tester API service error: %@. %@", [*error localizedDescription],
111+
[self tryParseGoogleAPIErrorFromResponse:data]);
90112
return nil;
91113
}
92114

@@ -142,12 +164,12 @@ + (BOOL)handleHttpResponseError:(NSHTTPURLResponse *)httpResponse error:(NSError
142164

143165
+ (NSError *)createErrorFromStatusCode:(NSInteger)statusCode {
144166
if (statusCode == 401) {
145-
return [self createErrorWithDescription:@"Tester not authenticated."
167+
return [self createErrorWithDescription:@"Tester not authenticated"
146168
code:FIRFADApiErrorUnauthenticated];
147169
}
148170

149171
if (statusCode == 403 || statusCode == 400) {
150-
return [self createErrorWithDescription:@"Tester not authorized."
172+
return [self createErrorWithDescription:@"Tester not authorized"
151173
code:FIRFADApiErrorUnauthorized];
152174
}
153175

@@ -157,7 +179,7 @@ + (NSError *)createErrorFromStatusCode:(NSInteger)statusCode {
157179
}
158180

159181
if (statusCode == 408 || statusCode == 504) {
160-
return [self createErrorWithDescription:@"Request timeout." code:FIRFADApiErrorTimeout];
182+
return [self createErrorWithDescription:@"Request timeout" code:FIRFADApiErrorTimeout];
161183
}
162184

163185
FIRFADErrorLog(@"Encountered unmapped status code: %ld", (long)statusCode);

FirebaseAppDistribution/Tests/Unit/FIRFADApiServiceTests.m

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#import <XCTest/XCTest.h>
1818

1919
#import "FirebaseAppDistribution/Sources/FIRFADApiService.h"
20+
#import "FirebaseAppDistribution/Sources/FIRFADLogger.h"
2021
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
2122
#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h"
2223

@@ -25,14 +26,22 @@
2526
@interface FIRFADApiServiceTests : XCTestCase
2627
@end
2728

29+
@interface FIRFADApiService (PrivateUnitTesting)
30+
31+
+ (NSString *)tryParseGoogleAPIErrorFromResponse:(NSData *)data;
32+
33+
@end
34+
2835
@implementation FIRFADApiServiceTests {
2936
id _mockFIRAppClass;
3037
id _mockURLSession;
3138
id _mockFIRInstallations;
3239
id _mockInstallationToken;
3340
NSString *_mockAuthToken;
3441
NSString *_mockInstallationId;
42+
NSString *_mockAPINotEnabledMessage;
3543
NSDictionary *_mockReleases;
44+
NSDictionary *_mockAPINotEnabledResponse;
3645
}
3746

3847
- (void)setUp {
@@ -65,6 +74,24 @@ - (void)setUp {
6574
}
6675
]
6776
};
77+
78+
_mockAPINotEnabledMessage =
79+
@"This is a long message about what's happening. This is a fake message from the Firebase "
80+
@"App Testers API in project 123456789. This should be logged.";
81+
_mockAPINotEnabledResponse = @{
82+
@"error" : @{
83+
@"code" : @403,
84+
@"message" : _mockAPINotEnabledMessage,
85+
@"status" : @"PERMISSION_DENIED",
86+
@"details" : @[ @{
87+
@"type" : @"type.fakeapis.com/appdistro.api.Help",
88+
@"links" : @[ @{
89+
@"description" : @"this is a short statement about enabling the api",
90+
@"url" : @"this should be a link"
91+
} ],
92+
} ],
93+
}
94+
};
6895
}
6996

7097
- (void)tearDown {
@@ -140,6 +167,37 @@ - (void)rejectUrlSessionResponseWithData {
140167
completionHandler:[OCMArg isNotNil]]);
141168
}
142169

170+
- (void)testTryParseGoogleAPIErrorFromResponseSuccess {
171+
NSData *data = [NSJSONSerialization dataWithJSONObject:_mockAPINotEnabledResponse
172+
options:0
173+
error:nil];
174+
NSString *message = [FIRFADApiService tryParseGoogleAPIErrorFromResponse:data];
175+
XCTAssertTrue([message isEqualToString:_mockAPINotEnabledMessage]);
176+
}
177+
178+
- (void)testTryParseGoogleAPIErrorFromResponseParseFailure {
179+
NSData *data = [@"malformed{json[data" dataUsingEncoding:NSUTF8StringEncoding];
180+
NSString *message = [FIRFADApiService tryParseGoogleAPIErrorFromResponse:data];
181+
XCTAssertTrue(
182+
[message isEqualToString:@"Could not parse additional details about this API error."]);
183+
}
184+
185+
- (void)testTryParseGoogleAPIErrorFromResponseNoErrorFailure {
186+
NSDictionary *errorDictionary = @{@"message" : @"This has no subdict"};
187+
NSData *data = [NSJSONSerialization dataWithJSONObject:errorDictionary options:0 error:nil];
188+
NSString *message = [FIRFADApiService tryParseGoogleAPIErrorFromResponse:data];
189+
XCTAssertTrue(
190+
[message isEqualToString:@"Could not parse additional details about this API error."]);
191+
}
192+
193+
- (void)testTryParseGoogleAPIErrorFromResponseNoMessageFailure {
194+
NSDictionary *errorDictionary = @{@"error" : @{@"status" : @"This has no message"}};
195+
NSData *data = [NSJSONSerialization dataWithJSONObject:errorDictionary options:0 error:nil];
196+
NSString *message = [FIRFADApiService tryParseGoogleAPIErrorFromResponse:data];
197+
XCTAssertTrue(
198+
[message isEqualToString:@"Could not parse additional details about this API error."]);
199+
}
200+
143201
- (void)testGenerateAuthTokenWithCompletionSuccess {
144202
[self mockInstallationAuthCompletion:_mockInstallationToken error:nil];
145203
[self mockInstallationIdCompletion:_mockInstallationId error:nil];
@@ -153,8 +211,8 @@ - (void)testGenerateAuthTokenWithCompletionSuccess {
153211
XCTAssertNotNil(authTokenResult);
154212
XCTAssertNotNil(identifier);
155213
XCTAssertNil(error);
156-
XCTAssertEqual(identifier, self->_mockInstallationId);
157-
XCTAssertEqual([authTokenResult authToken], self -> _mockAuthToken);
214+
XCTAssertTrue([identifier isEqualToString:self->_mockInstallationId]);
215+
XCTAssertTrue([[authTokenResult authToken] isEqualToString:self->_mockAuthToken]);
158216
[expectation fulfill];
159217
}];
160218

@@ -318,7 +376,7 @@ - (void)testFetchReleasesWithCompletionUnauthorized403Failure {
318376
OCMStub([fakeResponse statusCode]).andReturn(403);
319377
[self mockInstallationAuthCompletion:_mockInstallationToken error:nil];
320378
[self mockInstallationIdCompletion:_mockInstallationId error:nil];
321-
[self mockUrlSessionResponse:_mockReleases response:fakeResponse error:nil];
379+
[self mockUrlSessionResponse:_mockAPINotEnabledResponse response:fakeResponse error:nil];
322380
XCTestExpectation *expectation =
323381
[self expectationWithDescription:@"Fetch releases rejects with a 403."];
324382

0 commit comments

Comments
 (0)