diff --git a/Bugsnag/Configuration/BugsnagConfiguration+Private.h b/Bugsnag/Configuration/BugsnagConfiguration+Private.h index e17c863c6..4a0e7b83d 100644 --- a/Bugsnag/Configuration/BugsnagConfiguration+Private.h +++ b/Bugsnag/Configuration/BugsnagConfiguration+Private.h @@ -46,8 +46,6 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly, nonatomic) BOOL shouldSendReports; -@property (readonly, nonatomic) NSDictionary *sessionApiHeaders; - @property (readonly, nullable, nonatomic) NSURL *sessionURL; @property (readwrite, retain, nonnull, nonatomic) BugsnagUser *user; diff --git a/Bugsnag/Configuration/BugsnagConfiguration.m b/Bugsnag/Configuration/BugsnagConfiguration.m index a69d3e8a2..f74d47f4e 100644 --- a/Bugsnag/Configuration/BugsnagConfiguration.m +++ b/Bugsnag/Configuration/BugsnagConfiguration.m @@ -28,7 +28,6 @@ #import "BSGConfigurationBuilder.h" #import "BSGKeys.h" -#import "BSG_RFC3339DateTool.h" #import "BugsnagApiClient.h" #import "BugsnagEndpointConfiguration.h" #import "BugsnagErrorTypes.h" @@ -361,13 +360,6 @@ - (void)removeOnBreadcrumbBlock:(BugsnagOnBreadcrumbBlock)block { // MARK: - // ============================================================================= -- (NSDictionary *)sessionApiHeaders { - return @{BugsnagHTTPHeaderNameApiKey: self.apiKey ?: @"", - BugsnagHTTPHeaderNamePayloadVersion: @"1.0", - BugsnagHTTPHeaderNameSentAt: [BSG_RFC3339DateTool stringFromDate:[NSDate date]] - }; -} - - (void)setEndpoints:(BugsnagEndpointConfiguration *)endpoints { if ([self isValidURLString:endpoints.notify]) { _endpoints.notify = [endpoints.notify copy]; diff --git a/Bugsnag/Delivery/BSGEventUploadOperation.h b/Bugsnag/Delivery/BSGEventUploadOperation.h index 6bc439eb9..45e0b15e0 100644 --- a/Bugsnag/Delivery/BSGEventUploadOperation.h +++ b/Bugsnag/Delivery/BSGEventUploadOperation.h @@ -54,8 +54,6 @@ static const NSUInteger MaxPersistedSize = 1000000; @protocol BSGEventUploadOperationDelegate -@property (readonly, nonatomic) BugsnagApiClient *apiClient; - @property (readonly, nonatomic) BugsnagConfiguration *configuration; @property (readonly, nonatomic) BugsnagNotifier *notifier; diff --git a/Bugsnag/Delivery/BSGEventUploadOperation.m b/Bugsnag/Delivery/BSGEventUploadOperation.m index 3c9e4b002..7ff7bee91 100644 --- a/Bugsnag/Delivery/BSGEventUploadOperation.m +++ b/Bugsnag/Delivery/BSGEventUploadOperation.m @@ -10,8 +10,8 @@ #import "BSGFileLocations.h" #import "BSGInternalErrorReporter.h" +#import "BSGJSONSerialization.h" #import "BSGKeys.h" -#import "BSG_RFC3339DateTool.h" #import "BugsnagAppWithState+Private.h" #import "BugsnagConfiguration+Private.h" #import "BugsnagError+Private.h" @@ -123,7 +123,6 @@ - (void)runWithDelegate:(id)delegate completion NSMutableDictionary *requestHeaders = [NSMutableDictionary dictionary]; requestHeaders[BugsnagHTTPHeaderNameApiKey] = apiKey; requestHeaders[BugsnagHTTPHeaderNamePayloadVersion] = EventPayloadVersion; - requestHeaders[BugsnagHTTPHeaderNameSentAt] = [BSG_RFC3339DateTool stringFromDate:[NSDate date]]; requestHeaders[BugsnagHTTPHeaderNameStacktraceTypes] = [event.stacktraceTypes componentsJoinedByString:@","]; NSURL *notifyURL = configuration.notifyURL; @@ -133,29 +132,34 @@ - (void)runWithDelegate:(id)delegate completion return; } - __block NSData *HTTPBody = - [delegate.apiClient sendJSONPayload:requestPayload headers:requestHeaders toURL:notifyURL - completionHandler:^(BugsnagApiClientDeliveryStatus status, __unused NSError *deliveryError) { - + NSData *data = BSGJSONDataFromDictionary(requestPayload, NULL); + if (!data) { + bsg_log_debug(@"Encoding failed; will discard event %@", self.name); + [self deleteEvent]; + completionHandler(); + return; + } + + BSGPostJSONData(configuration.session, data, requestHeaders, notifyURL, ^(BSGDeliveryStatus status, __unused NSError *deliveryError) { switch (status) { - case BugsnagApiClientDeliveryStatusDelivered: + case BSGDeliveryStatusDelivered: bsg_log_debug(@"Uploaded event %@", self.name); [self deleteEvent]; break; - case BugsnagApiClientDeliveryStatusFailed: + case BSGDeliveryStatusFailed: bsg_log_debug(@"Upload failed retryably for event %@", self.name); - [self prepareForRetry:originalPayload ?: eventPayload HTTPBodySize:HTTPBody.length]; + [self prepareForRetry:originalPayload ?: eventPayload HTTPBodySize:data.length]; break; - case BugsnagApiClientDeliveryStatusUndeliverable: + case BSGDeliveryStatusUndeliverable: bsg_log_debug(@"Upload failed; will discard event %@", self.name); [self deleteEvent]; break; } completionHandler(); - }]; + }); } // MARK: Subclassing diff --git a/Bugsnag/Delivery/BSGEventUploader.m b/Bugsnag/Delivery/BSGEventUploader.m index bc78d20e4..1976b1ad7 100644 --- a/Bugsnag/Delivery/BSGEventUploader.m +++ b/Bugsnag/Delivery/BSGEventUploader.m @@ -40,13 +40,11 @@ @interface BSGEventUploader () @implementation BSGEventUploader -@synthesize apiClient = _apiClient; @synthesize configuration = _configuration; @synthesize notifier = _notifier; - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration notifier:(BugsnagNotifier *)notifier { if ((self = [super init])) { - _apiClient = [[BugsnagApiClient alloc] initWithSession:configuration.session]; _configuration = configuration; _eventsDirectory = [BSGFileLocations current].events; _kscrashReportsDirectory = [BSGFileLocations current].kscrashReports; diff --git a/Bugsnag/Delivery/BSGSessionUploader.m b/Bugsnag/Delivery/BSGSessionUploader.m index 14893bfc1..6af243593 100644 --- a/Bugsnag/Delivery/BSGSessionUploader.m +++ b/Bugsnag/Delivery/BSGSessionUploader.m @@ -30,7 +30,6 @@ @interface BSGSessionUploader () @property (nonatomic) NSMutableSet *activeIds; -@property (nonatomic) BugsnagApiClient *apiClient; @property(nonatomic) BugsnagConfiguration *config; @end @@ -40,7 +39,6 @@ @implementation BSGSessionUploader - (instancetype)initWithConfig:(BugsnagConfiguration *)config notifier:(BugsnagNotifier *)notifier { if ((self = [super init])) { _activeIds = [NSMutableSet new]; - _apiClient = [[BugsnagApiClient alloc] initWithSession:config.session]; _config = config; _notifier = notifier; } @@ -48,17 +46,17 @@ - (instancetype)initWithConfig:(BugsnagConfiguration *)config notifier:(BugsnagN } - (void)uploadSession:(BugsnagSession *)session { - [self sendSession:session completionHandler:^(BugsnagApiClientDeliveryStatus status) { + [self sendSession:session completionHandler:^(BSGDeliveryStatus status) { switch (status) { - case BugsnagApiClientDeliveryStatusDelivered: + case BSGDeliveryStatusDelivered: [self processStoredSessions]; break; - case BugsnagApiClientDeliveryStatusFailed: + case BSGDeliveryStatusFailed: [self storeSession:session]; // Retry later break; - case BugsnagApiClientDeliveryStatusUndeliverable: + case BSGDeliveryStatusUndeliverable: break; } }]; @@ -108,8 +106,8 @@ - (void)processStoredSessions { [self.activeIds addObject:file]; } - [self sendSession:session completionHandler:^(BugsnagApiClientDeliveryStatus status) { - if (status != BugsnagApiClientDeliveryStatusFailed) { + [self sendSession:session completionHandler:^(BSGDeliveryStatus status) { + if (status != BSGDeliveryStatusFailed) { [fileManager removeItemAtPath:file error:nil]; } @synchronized (self.activeIds) { @@ -135,25 +133,24 @@ - (void)pruneFiles { // // https://bugsnagsessiontrackingapi.docs.apiary.io/#reference/0/session/report-a-session-starting // -- (void)sendSession:(BugsnagSession *)session completionHandler:(nonnull void (^)(BugsnagApiClientDeliveryStatus status))completionHandler { +- (void)sendSession:(BugsnagSession *)session completionHandler:(nonnull void (^)(BSGDeliveryStatus status))completionHandler { NSString *apiKey = [self.config.apiKey copy]; if (!apiKey) { bsg_log_err(@"Cannot send session because no apiKey is configured."); - completionHandler(BugsnagApiClientDeliveryStatusUndeliverable); + completionHandler(BSGDeliveryStatusUndeliverable); return; } NSURL *url = self.config.sessionURL; if (!url) { bsg_log_err(@"Cannot send session because no endpoint is configured."); - completionHandler(BugsnagApiClientDeliveryStatusUndeliverable); + completionHandler(BSGDeliveryStatusUndeliverable); return; } NSDictionary *headers = @{ BugsnagHTTPHeaderNameApiKey: apiKey, - BugsnagHTTPHeaderNamePayloadVersion: @"1.0", - BugsnagHTTPHeaderNameSentAt: [BSG_RFC3339DateTool stringFromDate:[NSDate date]] ?: [NSNull null] + BugsnagHTTPHeaderNamePayloadVersion: @"1.0" }; NSDictionary *payload = @{ @@ -167,20 +164,27 @@ - (void)sendSession:(BugsnagSession *)session completionHandler:(nonnull void (^ }] }; - [self.apiClient sendJSONPayload:payload headers:headers toURL:url completionHandler:^(BugsnagApiClientDeliveryStatus status, NSError *error) { + NSData *data = BSGJSONDataFromDictionary(payload, NULL); + if (!data) { + bsg_log_err(@"Failed to encode session %@", session.id); + completionHandler(BSGDeliveryStatusUndeliverable); + return; + } + + BSGPostJSONData(self.config.session, data, headers, url, ^(BSGDeliveryStatus status, NSError *error) { switch (status) { - case BugsnagApiClientDeliveryStatusDelivered: + case BSGDeliveryStatusDelivered: bsg_log_info(@"Sent session %@", session.id); break; - case BugsnagApiClientDeliveryStatusFailed: + case BSGDeliveryStatusFailed: bsg_log_warn(@"Failed to send sessions: %@", error); break; - case BugsnagApiClientDeliveryStatusUndeliverable: + case BSGDeliveryStatusUndeliverable: bsg_log_warn(@"Failed to send sessions: %@", error); break; } completionHandler(status); - }]; + }); } @end diff --git a/Bugsnag/Delivery/BugsnagApiClient.h b/Bugsnag/Delivery/BugsnagApiClient.h index a285c7662..4083ee761 100644 --- a/Bugsnag/Delivery/BugsnagApiClient.h +++ b/Bugsnag/Delivery/BugsnagApiClient.h @@ -15,26 +15,21 @@ static BugsnagHTTPHeaderName const BugsnagHTTPHeaderNamePayloadVersion = @"B static BugsnagHTTPHeaderName const BugsnagHTTPHeaderNameSentAt = @"Bugsnag-Sent-At"; static BugsnagHTTPHeaderName const BugsnagHTTPHeaderNameStacktraceTypes = @"Bugsnag-Stacktrace-Types"; -typedef NS_ENUM(NSInteger, BugsnagApiClientDeliveryStatus) { +typedef NS_ENUM(NSInteger, BSGDeliveryStatus) { /// The payload was delivered successfully and can be deleted. - BugsnagApiClientDeliveryStatusDelivered, + BSGDeliveryStatusDelivered, /// The payload was not delivered but can be retried, e.g. when there was a loss of connectivity. - BugsnagApiClientDeliveryStatusFailed, + BSGDeliveryStatusFailed, /// The payload cannot be delivered and should be deleted without attempting to retry. - BugsnagApiClientDeliveryStatusUndeliverable, + BSGDeliveryStatusUndeliverable, }; -@interface BugsnagApiClient : NSObject +void BSGPostJSONData(NSURLSession *URLSession, + NSData *data, + NSDictionary *headers, + NSURL *url, + void (^ completionHandler)(BSGDeliveryStatus status, NSError *_Nullable error)); -- (instancetype)initWithSession:(nullable NSURLSession *)session; - -- (nullable NSData *)sendJSONPayload:(NSDictionary *)payload - headers:(NSDictionary *)headers - toURL:(NSURL *)url - completionHandler:(void (^)(BugsnagApiClientDeliveryStatus status, NSError *_Nullable error))completionHandler; - -+ (NSString *)SHA1HashStringWithData:(NSData *)data; - -@end +NSString *_Nullable BSGIntegrityHeaderValue(NSData *_Nullable data); NS_ASSUME_NONNULL_END diff --git a/Bugsnag/Delivery/BugsnagApiClient.m b/Bugsnag/Delivery/BugsnagApiClient.m index 1673dcdd0..2c98c1657 100644 --- a/Bugsnag/Delivery/BugsnagApiClient.m +++ b/Bugsnag/Delivery/BugsnagApiClient.m @@ -7,6 +7,7 @@ #import "BSGJSONSerialization.h" #import "BSGKeys.h" +#import "BSG_RFC3339DateTool.h" #import "Bugsnag.h" #import "BugsnagConfiguration.h" #import "BugsnagLogger.h" @@ -30,45 +31,28 @@ typedef NS_ENUM(NSInteger, HTTPStatusCode) { HTTPStatusCodeTooManyRequests = 429, }; -@interface BugsnagApiClient() -@property (nonatomic, strong) NSURLSession *session; -@end - -@implementation BugsnagApiClient - -- (instancetype)initWithSession:(nullable NSURLSession *)session { - if ((self = [super init])) { - _session = session ?: [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; - } - return self; -} - -#pragma mark - Delivery - -- (NSData *)sendJSONPayload:(NSDictionary *)payload - headers:(NSDictionary *)headers - toURL:(NSURL *)url - completionHandler:(void (^)(BugsnagApiClientDeliveryStatus status, NSError *_Nullable error))completionHandler { +void BSGPostJSONData(NSURLSession *URLSession, + NSData *data, + NSDictionary *headers, + NSURL *url, + void (^ completionHandler)(BSGDeliveryStatus status, NSError *_Nullable error)) { - NSError *error = nil; - NSData *data = BSGJSONDataFromDictionary(payload, &error); - if (!data) { - bsg_log_err(@"Error: Could not encode JSON payload passed to %s", __PRETTY_FUNCTION__); - completionHandler(BugsnagApiClientDeliveryStatusUndeliverable, error); - return nil; - } + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15]; + request.HTTPMethod = @"POST"; + [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + [request setValue:BSGIntegrityHeaderValue(data) forHTTPHeaderField:BugsnagHTTPHeaderNameIntegrity]; + [request setValue:[BSG_RFC3339DateTool stringFromDate:[NSDate date]] forHTTPHeaderField:BugsnagHTTPHeaderNameSentAt]; - NSMutableDictionary *mutableHeaders = [headers mutableCopy]; - mutableHeaders[BugsnagHTTPHeaderNameIntegrity] = [NSString stringWithFormat:@"sha1 %@", [BugsnagApiClient SHA1HashStringWithData:data]]; + for (BugsnagHTTPHeaderName name in headers) { + [request setValue:headers[name] forHTTPHeaderField:name]; + } - NSMutableURLRequest *request = [self prepareRequest:url headers:mutableHeaders]; bsg_log_debug(@"Sending %lu byte payload to %@", (unsigned long)data.length, url); - [[self.session uploadTaskWithRequest:request fromData:data completionHandler:^(__unused NSData *responseData, - NSURLResponse *response, NSError *connectionError) { + [[URLSession uploadTaskWithRequest:request fromData:data completionHandler:^(__unused NSData *responseData, NSURLResponse *response, NSError *error) { if (![response isKindOfClass:[NSHTTPURLResponse class]]) { bsg_log_debug(@"Request to %@ completed with error %@", url, error); - completionHandler(BugsnagApiClientDeliveryStatusFailed, connectionError ?: + completionHandler(BSGDeliveryStatusFailed, error ?: [NSError errorWithDomain:@"BugsnagApiClientErrorDomain" code:0 userInfo:@{ NSLocalizedDescriptionKey: @"Request failed: no response was received", NSURLErrorFailingURLErrorKey: url }]); @@ -79,11 +63,11 @@ - (NSData *)sendJSONPayload:(NSDictionary *)payload bsg_log_debug(@"Request to %@ completed with status code %ld", url, (long)statusCode); if (statusCode / 100 == 2) { - completionHandler(BugsnagApiClientDeliveryStatusDelivered, nil); + completionHandler(BSGDeliveryStatusDelivered, nil); return; } - connectionError = [NSError errorWithDomain:@"BugsnagApiClientErrorDomain" code:1 userInfo:@{ + error = [NSError errorWithDomain:@"BugsnagApiClientErrorDomain" code:1 userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Request failed: unacceptable status code %ld (%@)", (long)statusCode, [NSHTTPURLResponse localizedStringForStatusCode:statusCode]], NSURLErrorFailingURLErrorKey: url }]; @@ -96,41 +80,23 @@ - (NSData *)sendJSONPayload:(NSDictionary *)payload statusCode != HTTPStatusCodeProxyAuthenticationRequired && statusCode != HTTPStatusCodeClientTimeout && statusCode != HTTPStatusCodeTooManyRequests) { - completionHandler(BugsnagApiClientDeliveryStatusUndeliverable, connectionError); + completionHandler(BSGDeliveryStatusUndeliverable, error); return; } - completionHandler(BugsnagApiClientDeliveryStatusFailed, connectionError); + completionHandler(BSGDeliveryStatusFailed, error); }] resume]; - return data; } -- (NSMutableURLRequest *)prepareRequest:(NSURL *)url - headers:(NSDictionary *)headers { - NSMutableURLRequest *request = [NSMutableURLRequest - requestWithURL:url - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval:15]; - request.HTTPMethod = @"POST"; - [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - - for (NSString *key in [headers allKeys]) { - [request setValue:headers[key] forHTTPHeaderField:key]; - } - return request; -} - -+ (NSString *)SHA1HashStringWithData:(NSData *)data { +NSString * BSGIntegrityHeaderValue(NSData *data) { if (!data) { return nil; } unsigned char md[CC_SHA1_DIGEST_LENGTH]; CC_SHA1(data.bytes, (CC_LONG)data.length, md); - return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + return [NSString stringWithFormat:@"sha1 %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", md[0], md[1], md[2], md[3], md[4], md[5], md[6], md[7], md[8], md[9], md[10], md[11], md[12], md[13], md[14], md[15], md[16], md[17], md[18], md[19]]; } - -@end diff --git a/Bugsnag/Helpers/BSGInternalErrorReporter.m b/Bugsnag/Helpers/BSGInternalErrorReporter.m index 342ba419d..f0bf2df89 100644 --- a/Bugsnag/Helpers/BSGInternalErrorReporter.m +++ b/Bugsnag/Helpers/BSGInternalErrorReporter.m @@ -258,7 +258,7 @@ - (NSURLRequest *)requestForEvent:(nonnull BugsnagEvent *)event error:(NSError * NSMutableDictionary *headers = [NSMutableDictionary dictionary]; headers[@"Content-Type"] = @"application/json"; - headers[BugsnagHTTPHeaderNameIntegrity] = [NSString stringWithFormat:@"sha1 %@", [BugsnagApiClient SHA1HashStringWithData:data]]; + headers[BugsnagHTTPHeaderNameIntegrity] = BSGIntegrityHeaderValue(data); headers[BugsnagHTTPHeaderNameInternalError] = @"bugsnag-cocoa"; headers[BugsnagHTTPHeaderNamePayloadVersion] = EventPayloadVersion; headers[BugsnagHTTPHeaderNameSentAt] = [BSG_RFC3339DateTool stringFromDate:[NSDate date]]; diff --git a/Tests/BugsnagTests/BugsnagApiClientTest.m b/Tests/BugsnagTests/BugsnagApiClientTest.m index d18dbb268..4abfb2992 100644 --- a/Tests/BugsnagTests/BugsnagApiClientTest.m +++ b/Tests/BugsnagTests/BugsnagApiClientTest.m @@ -18,64 +18,56 @@ @interface BugsnagApiClientTest : XCTestCase @implementation BugsnagApiClientTest -- (void)testBadJSON { - BugsnagApiClient *client = [[BugsnagApiClient alloc] initWithSession:nil]; - XCTAssertNoThrow([client sendJSONPayload:(id)@{@1: @"a"} headers:(id)@{@1: @"a"} toURL:[NSURL URLWithString:@"file:///dev/null"] - completionHandler:^(BugsnagApiClientDeliveryStatus status, NSError * _Nullable error) {}]); -} - - (void)testHTTPStatusCodes { NSURL *url = [NSURL URLWithString:@"https://example.com"]; - URLSessionMock *session = [[URLSessionMock alloc] init]; - BugsnagApiClient *client = [[BugsnagApiClient alloc] initWithSession:(id)session]; + id URLSession = [[URLSessionMock alloc] init]; - void (^ test)(NSInteger, BugsnagApiClientDeliveryStatus, BOOL) = - ^(NSInteger statusCode, BugsnagApiClientDeliveryStatus expectedDeliveryStatus, BOOL expectError) { + void (^ test)(NSInteger, BSGDeliveryStatus, BOOL) = + ^(NSInteger statusCode, BSGDeliveryStatus expectedDeliveryStatus, BOOL expectError) { XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler should be called"]; id response = [[NSHTTPURLResponse alloc] initWithURL:url statusCode:statusCode HTTPVersion:@"1.1" headerFields:nil]; - [session mockData:[NSData data] response:response error:nil]; - [client sendJSONPayload:@{} headers:@{} toURL:url completionHandler:^(BugsnagApiClientDeliveryStatus status, NSError * _Nullable error) { + [URLSession mockData:[NSData data] response:response error:nil]; + BSGPostJSONData(URLSession, [NSData data], @{}, url, ^(BSGDeliveryStatus status, NSError * _Nullable error) { XCTAssertEqual(status, expectedDeliveryStatus); expectError ? XCTAssertNotNil(error) : XCTAssertNil(error); [expectation fulfill]; - }]; + }); }; - test(200, BugsnagApiClientDeliveryStatusDelivered, NO); + test(200, BSGDeliveryStatusDelivered, NO); // Permanent failures - test(400, BugsnagApiClientDeliveryStatusUndeliverable, YES); - test(401, BugsnagApiClientDeliveryStatusUndeliverable, YES); - test(403, BugsnagApiClientDeliveryStatusUndeliverable, YES); - test(404, BugsnagApiClientDeliveryStatusUndeliverable, YES); - test(405, BugsnagApiClientDeliveryStatusUndeliverable, YES); - test(406, BugsnagApiClientDeliveryStatusUndeliverable, YES); + test(400, BSGDeliveryStatusUndeliverable, YES); + test(401, BSGDeliveryStatusUndeliverable, YES); + test(403, BSGDeliveryStatusUndeliverable, YES); + test(404, BSGDeliveryStatusUndeliverable, YES); + test(405, BSGDeliveryStatusUndeliverable, YES); + test(406, BSGDeliveryStatusUndeliverable, YES); // Transient failures - test(402, BugsnagApiClientDeliveryStatusFailed, YES); - test(407, BugsnagApiClientDeliveryStatusFailed, YES); - test(408, BugsnagApiClientDeliveryStatusFailed, YES); - test(429, BugsnagApiClientDeliveryStatusFailed, YES); - test(500, BugsnagApiClientDeliveryStatusFailed, YES); + test(402, BSGDeliveryStatusFailed, YES); + test(407, BSGDeliveryStatusFailed, YES); + test(408, BSGDeliveryStatusFailed, YES); + test(429, BSGDeliveryStatusFailed, YES); + test(500, BSGDeliveryStatusFailed, YES); [self waitForExpectationsWithTimeout:1 handler:nil]; } - (void)testNotConnectedToInternetError { NSURL *url = [NSURL URLWithString:@"https://example.com"]; - URLSessionMock *session = [[URLSessionMock alloc] init]; - BugsnagApiClient *client = [[BugsnagApiClient alloc] initWithSession:(id)session]; + id URLSession = [[URLSessionMock alloc] init]; XCTestExpectation *expectation = [self expectationWithDescription:@"completionHandler should be called"]; - [session mockData:nil response:nil error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorNotConnectedToInternet userInfo:@{ + [URLSession mockData:nil response:nil error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorNotConnectedToInternet userInfo:@{ NSURLErrorFailingURLErrorKey: url, }]]; - [client sendJSONPayload:@{} headers:@{} toURL:url completionHandler:^(BugsnagApiClientDeliveryStatus status, NSError * _Nullable error) { - XCTAssertEqual(status, BugsnagApiClientDeliveryStatusFailed); + BSGPostJSONData(URLSession, [NSData data], @{}, url, ^(BSGDeliveryStatus status, NSError * _Nullable error) { + XCTAssertEqual(status, BSGDeliveryStatusFailed); XCTAssertNotNil(error); XCTAssertEqualObjects(error.domain, NSURLErrorDomain); [expectation fulfill]; - }]; + }); [self waitForExpectationsWithTimeout:1 handler:nil]; } @@ -83,9 +75,9 @@ - (void)testNotConnectedToInternetError { - (void)testSHA1HashStringWithData { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wnonnull" - XCTAssertNil([BugsnagApiClient SHA1HashStringWithData:nil]); + XCTAssertNil(BSGIntegrityHeaderValue(nil)); #pragma clang diagnostic pop - XCTAssertEqualObjects([BugsnagApiClient SHA1HashStringWithData:[@"{\"foo\":\"bar\"}" dataUsingEncoding:NSUTF8StringEncoding]], @"a5e744d0164540d33b1d7ea616c28f2fa97e754a"); + XCTAssertEqualObjects(BSGIntegrityHeaderValue([@"{\"foo\":\"bar\"}" dataUsingEncoding:NSUTF8StringEncoding]), @"sha1 a5e744d0164540d33b1d7ea616c28f2fa97e754a"); } @end diff --git a/Tests/BugsnagTests/BugsnagConfigurationTests.m b/Tests/BugsnagTests/BugsnagConfigurationTests.m index 2f7108f02..81ac1f8a6 100644 --- a/Tests/BugsnagTests/BugsnagConfigurationTests.m +++ b/Tests/BugsnagTests/BugsnagConfigurationTests.m @@ -38,14 +38,6 @@ - (void)testDefaultSessionConfig { XCTAssertTrue([config autoTrackSessions]); } -- (void)testSessionApiHeaders { - BugsnagConfiguration *config = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1]; - NSDictionary *headers = [config sessionApiHeaders]; - XCTAssertEqualObjects(config.apiKey, headers[@"Bugsnag-Api-Key"]); - XCTAssertNotNil(headers[@"Bugsnag-Sent-At"]); - XCTAssertNotNil(headers[@"Bugsnag-Payload-Version"]); -} - - (void)testSessionEndpoints { BugsnagConfiguration *config = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1];