diff --git a/CHANGELOG.md b/CHANGELOG.md index b0bc3700f..22b888a7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ Bugsnag Notifiers on other platforms. * `Bugsnag.addAttribute:value:tab:` is now `Bugsnag.addMetadataToSection::key:value:` [#454](https://github.com/bugsnag/bugsnag-cocoa/pull/454) - * `[Bugsnag clearTab:]` is now `[Bugsnag clearMetadataInSection:]` +* `[Bugsnag clearTab:]` is now `[Bugsnag clearMetadataInSection:]` (Swift: `Bugsnag.clearMetadata(_ section)`) [#457](https://github.com/bugsnag/bugsnag-cocoa/pull/457) @@ -39,12 +39,19 @@ Bugsnag Notifiers on other platforms. had usage aligned with this change. [#459](https://github.com/bugsnag/bugsnag-cocoa/pull/459) +* Added `Bugsnag.getMetadata(_ section: key:)` +[#463](https://github.com/bugsnag/bugsnag-cocoa/pull/463) + * Add a per-Event `apiKey` property. This defaults to the global `BugsnagConfiguration` value but can be overridden in event passed to the `Bugsnag.notify()` callback. [#458](https://github.com/bugsnag/bugsnag-cocoa/pull/458) +* `Bugsnag.stopSession()` is now `Bugsnag.pauseSession()`. This renaming has + also been applied to the `BugsnagNotifier` and `BugsnagSessionTracker` classes. + [#464](https://github.com/bugsnag/bugsnag-cocoa/pull/464) + ## Bug fixes * Fix possible report corruption when using `notify()` from multiple threads diff --git a/Source/Bugsnag.h b/Source/Bugsnag.h index 11a8c2c91..780b12e21 100644 --- a/Source/Bugsnag.h +++ b/Source/Bugsnag.h @@ -223,10 +223,10 @@ static NSString *_Nonnull const BugsnagSeverityInfo = @"info"; * * Any errors which occur in an active session count towards your application's * stability score. You can prevent errors from counting towards your stability - * score by calling stopSession and resumeSession at the appropriate + * score by calling pauseSession and resumeSession at the appropriate * time in your application. * - * @see stopSession: + * @see pauseSession: * @see resumeSession: */ + (void)startSession; @@ -246,7 +246,7 @@ static NSString *_Nonnull const BugsnagSeverityInfo = @"info"; * @see startSession: * @see resumeSession: */ -+ (void)stopSession; ++ (void)pauseSession; /** * Resumes a session which has previously been stopped, or starts a new session if none exists. @@ -264,7 +264,7 @@ static NSString *_Nonnull const BugsnagSeverityInfo = @"info"; * will be reported to Bugsnag and will count towards your application's stability score. * * @see startSession: - * @see stopSession: + * @see pauseSession: * * @return true if a previous session was resumed, false if a new session was started. */ @@ -287,7 +287,7 @@ static NSString *_Nonnull const BugsnagSeverityInfo = @"info"; * @param key The key * @returns The value of the keyed value if it exists or nil. */ -+ (id _Nullable )getMetadata:(NSString *_Nonnull)section key:(NSString *_Nonnull)key ++ (id _Nullable )getMetadata:(NSString *_Nonnull)section key:(NSString *_Nonnull)key NS_SWIFT_NAME(getMetadata(_:key:)); /** diff --git a/Source/Bugsnag.m b/Source/Bugsnag.m index c417adb1c..3baee3c25 100644 --- a/Source/Bugsnag.m +++ b/Source/Bugsnag.m @@ -252,9 +252,9 @@ + (void)startSession { } } -+ (void)stopSession { ++ (void)pauseSession { if ([self bugsnagStarted]) { - [self.notifier stopSession]; + [self.notifier pauseSession]; } } diff --git a/Source/BugsnagMetadata.m b/Source/BugsnagMetadata.m index 724f857b5..79228528c 100644 --- a/Source/BugsnagMetadata.m +++ b/Source/BugsnagMetadata.m @@ -60,11 +60,11 @@ - (NSMutableDictionary *)getMetadata:(NSString *)sectionName { } } -- (NSMutableDictionary *)getMetadata:(NSString *)sectionName - key:(NSString *)key +- (id)getMetadata:(NSString *)sectionName + key:(NSString *)key { @synchronized(self) { - return [self.dictionary valueForKeyPath:[NSString stringWithFormat:@"%@.%@", sectionName, key]]; + return [[self.dictionary objectForKey:sectionName] objectForKey:key]; } } diff --git a/Source/BugsnagNotifier.h b/Source/BugsnagNotifier.h index 90b0150bf..09a0b8f4e 100644 --- a/Source/BugsnagNotifier.h +++ b/Source/BugsnagNotifier.h @@ -48,7 +48,7 @@ - (void)start; - (void)startSession; -- (void)stopSession; +- (void)pauseSession; - (BOOL)resumeSession; - (BOOL)appCrashedLastLaunch; diff --git a/Source/BugsnagNotifier.m b/Source/BugsnagNotifier.m index 8d91b1104..c992a5937 100644 --- a/Source/BugsnagNotifier.m +++ b/Source/BugsnagNotifier.m @@ -507,8 +507,8 @@ - (void)startSession { [self.sessionTracker startNewSession]; } -- (void)stopSession { - [self.sessionTracker stopSession]; +- (void)pauseSession { + [self.sessionTracker pauseSession]; } - (BOOL)resumeSession { diff --git a/Source/BugsnagSessionTracker.h b/Source/BugsnagSessionTracker.h index 630ee6939..2eaa529c8 100644 --- a/Source/BugsnagSessionTracker.h +++ b/Source/BugsnagSessionTracker.h @@ -34,7 +34,7 @@ extern NSString *const BSGSessionUpdateNotification; */ - (void)startNewSession; -- (void)stopSession; +- (void)pauseSession; - (BOOL)resumeSession; /** diff --git a/Source/BugsnagSessionTracker.m b/Source/BugsnagSessionTracker.m index fbc868f9d..977dc61a5 100644 --- a/Source/BugsnagSessionTracker.m +++ b/Source/BugsnagSessionTracker.m @@ -58,7 +58,7 @@ - (void)startNewSession { [self startNewSessionWithAutoCaptureValue:NO]; } -- (void)stopSession { +- (void)pauseSession { [[self currentSession] stop]; if (self.callback) { diff --git a/Tests/BugsnagMetadataTests.m b/Tests/BugsnagMetadataTests.m new file mode 100644 index 000000000..a4a55db8e --- /dev/null +++ b/Tests/BugsnagMetadataTests.m @@ -0,0 +1,33 @@ +// +// BugsnagMetadataTests.m +// Tests +// +// Created by Robin Macharg on 12/02/2020. +// Copyright © 2020 Bugsnag. All rights reserved. +// + +#import +#import "BugsnagMetadata.h" + +@interface BugsnagMetadataTests : XCTestCase + +@end + +@implementation BugsnagMetadataTests + +- (void)testGetMetadataSectionKey { + BugsnagMetadata *metadata = [BugsnagMetadata new]; + [metadata addAttribute:@"myKey1" withValue:@"myValue1" toTabWithName:@"section1"]; + [metadata addAttribute:@"myKey2" withValue:@"myValue2" toTabWithName:@"section1"]; + [metadata addAttribute:@"myKey3" withValue:@"myValue3" toTabWithName:@"section2"]; + + // Test known values + XCTAssertEqual([metadata getMetadata:@"section1" key:@"myKey1"], @"myValue1"); + XCTAssertEqual([metadata getMetadata:@"section1" key:@"myKey2"], @"myValue2"); + + // unknown values + XCTAssertNil([metadata getMetadata:@"sections1" key:@"noKey"]); + XCTAssertNil([metadata getMetadata:@"noSection" key:@"noKey"]); +} + +@end diff --git a/Tests/BugsnagSessionTrackerStopTest.m b/Tests/BugsnagSessionTrackerStopTest.m index 1d06fa5f8..73806bc99 100644 --- a/Tests/BugsnagSessionTrackerStopTest.m +++ b/Tests/BugsnagSessionTrackerStopTest.m @@ -32,7 +32,7 @@ - (void)testResumeFromStoppedSession { BugsnagSession *original = self.tracker.runningSession; XCTAssertNotNil(original); - [self.tracker stopSession]; + [self.tracker pauseSession]; XCTAssertNil(self.tracker.runningSession); XCTAssertTrue([self.tracker resumeSession]); @@ -56,7 +56,7 @@ - (void)testStartNewAfterStoppedSession { [self.tracker startNewSession]; BugsnagSession *originalSession = self.tracker.runningSession; - [self.tracker stopSession]; + [self.tracker pauseSession]; [self.tracker startNewSession]; XCTAssertNotEqual(originalSession, self.tracker.runningSession); } @@ -67,7 +67,7 @@ - (void)testStartNewAfterStoppedSession { - (void)testMultipleResumesHaveNoEffect { [self.tracker startNewSession]; BugsnagSession *original = self.tracker.runningSession; - [self.tracker stopSession]; + [self.tracker pauseSession]; XCTAssertTrue([self.tracker resumeSession]); XCTAssertEqual(original, self.tracker.runningSession); @@ -77,16 +77,16 @@ - (void)testMultipleResumesHaveNoEffect { } /** - * Verifies that calling stopSession multiple times only stops one session + * Verifies that calling pauseSession multiple times only stops one session */ - (void)testMultipleStopsHaveNoEffect { [self.tracker startNewSession]; XCTAssertNotNil(self.tracker.runningSession); - [self.tracker stopSession]; + [self.tracker pauseSession]; XCTAssertNil(self.tracker.runningSession); - [self.tracker stopSession]; + [self.tracker pauseSession]; XCTAssertNil(self.tracker.runningSession); } @@ -102,7 +102,7 @@ - (void)testStoppedSessionDoesNotIncrement { XCTAssertEqual(1, self.tracker.runningSession.handledCount); XCTAssertEqual(1, self.tracker.runningSession.unhandledCount); - [self.tracker stopSession]; + [self.tracker pauseSession]; self.tracker.runningSession.handledCount++; self.tracker.runningSession.unhandledCount++; [self.tracker resumeSession]; diff --git a/Tests/BugsnagTests.m b/Tests/BugsnagTests.m index c1f662179..597e2d6da 100644 --- a/Tests/BugsnagTests.m +++ b/Tests/BugsnagTests.m @@ -11,6 +11,8 @@ #import "BugsnagTestConstants.h" #import +// MARK: - BugsnagTests + @interface BugsnagTests : XCTestCase @end @@ -107,4 +109,24 @@ - (void)testGetMetadata { XCTAssertNil([Bugsnag getMetadata:@"noSection" key:@"notaKey1"]); } +/** + * Test that pausing the session performs as expected. + * NOTE: For now this test is inadequate. Some form of dependency injection + * or mocking is required to isolate and test the session pausing semantics. + */ +-(void)testBugsnagPauseSession { + NSError *error; + BugsnagConfiguration *configuration = [[BugsnagConfiguration alloc] initWithApiKey:DUMMY_APIKEY_32CHAR_1 error:&error]; + [configuration addBeforeSendBlock:^bool(NSDictionary * _Nonnull rawEventData, + BugsnagEvent * _Nonnull reports) + { + return false; + }]; + + [Bugsnag startBugsnagWithConfiguration:configuration]; + + // For now only test that the method exists + [Bugsnag pauseSession]; +} + @end diff --git a/UPGRADING.md b/UPGRADING.md index 93c520b70..692b0ee0d 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -52,6 +52,9 @@ ObjC: + [Bugsnag getSection:] +- [Bugsnag stopSession] ++ [Bugsnag pauseSession] + Swift: - Bugsnag.addAttribute(attributeName:withValue:toTabWithName:) @@ -61,6 +64,9 @@ Swift: + Bugsnag.clearMetadata(_ section) + Bugsnag.getSection(_ section) + +- Bugsnag.stopSession() ++ Bugsnag.pauseSession() ``` ### `BugsnagMetadata` class diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift index cae501764..ae8bc85fe 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift @@ -21,7 +21,7 @@ internal class NewSessionScenario: Scenario { Bugsnag.notifyError(NSError(domain: "First error", code: 101, userInfo: nil)) // stop tracking the existing session - Bugsnag.stopSession() + Bugsnag.pauseSession() // send 2nd exception which should contain new session info Bugsnag.startSession() diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m index e66aa023d..6180c595e 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumeSessionOOMScenario.m @@ -10,7 +10,7 @@ - (void)startBugsnag { - (void)run { [Bugsnag startSession]; [Bugsnag notify:[NSException exceptionWithName:@"foo" reason:nil userInfo:nil]]; - [Bugsnag stopSession]; + [Bugsnag pauseSession]; [Bugsnag resumeSession]; } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift index 6cf9a89c1..c2eaf8acb 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift @@ -21,7 +21,7 @@ internal class ResumedSessionScenario: Scenario { Bugsnag.notifyError(NSError(domain: "First error", code: 101, userInfo: nil)) // send 2nd exception after resuming a session - Bugsnag.stopSession() + Bugsnag.pauseSession() Bugsnag.resumeSession() Bugsnag.notifyError(NSError(domain: "Second error", code: 101, userInfo: nil)) } diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m index a17700541..b3fb8f3e8 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StopSessionOOMScenario.m @@ -10,7 +10,7 @@ - (void)startBugsnag { - (void)run { [Bugsnag startSession]; [Bugsnag notify:[NSException exceptionWithName:@"foo" reason:nil userInfo:nil]]; - [Bugsnag stopSession]; + [Bugsnag pauseSession]; } @end diff --git a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift index 6db3e10c3..775bfa447 100644 --- a/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift +++ b/features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift @@ -21,7 +21,7 @@ internal class StoppedSessionScenario: Scenario { Bugsnag.notifyError(NSError(domain: "First error", code: 101, userInfo: nil)) // send 2nd exception which should not include session info - Bugsnag.stopSession() + Bugsnag.pauseSession() Bugsnag.notifyError(NSError(domain: "Second error", code: 101, userInfo: nil)) } } diff --git a/iOS/Bugsnag.xcodeproj/project.pbxproj b/iOS/Bugsnag.xcodeproj/project.pbxproj index dbf4264a1..cae51051d 100644 --- a/iOS/Bugsnag.xcodeproj/project.pbxproj +++ b/iOS/Bugsnag.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 000E6EA423D8AC8C009D8194 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 000E6EA023D8AC8C009D8194 /* README.md */; }; 000E6EA523D8AC8C009D8194 /* VERSION in Resources */ = {isa = PBXBuildFile; fileRef = 000E6EA123D8AC8C009D8194 /* VERSION */; }; 000E6EA623D8AC8C009D8194 /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = 000E6EA223D8AC8C009D8194 /* CHANGELOG.md */; }; + 009131BC23F46279000810D9 /* BugsnagMetadataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 009131BB23F46279000810D9 /* BugsnagMetadataTests.m */; }; 00D7ACAD23E9C63000FBE4A7 /* BugsnagTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00D7ACAC23E9C63000FBE4A7 /* BugsnagTests.m */; }; 00D7ACAF23EABBC800FBE4A7 /* BugsnagSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D7ACAE23EABBC800FBE4A7 /* BugsnagSwiftTests.swift */; }; 4B47970A22A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B47970922A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m */; }; @@ -414,6 +415,7 @@ 000E6EA023D8AC8C009D8194 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 000E6EA123D8AC8C009D8194 /* VERSION */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = VERSION; path = ../VERSION; sourceTree = ""; }; 000E6EA223D8AC8C009D8194 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = ""; }; + 009131BB23F46279000810D9 /* BugsnagMetadataTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagMetadataTests.m; path = ../../Tests/BugsnagMetadataTests.m; sourceTree = ""; }; 00D7ACAC23E9C63000FBE4A7 /* BugsnagTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagTests.m; path = ../../Tests/BugsnagTests.m; sourceTree = ""; }; 00D7ACAE23EABBC800FBE4A7 /* BugsnagSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BugsnagSwiftTests.swift; sourceTree = ""; }; 4B3B193422CA7B0900475354 /* BugsnagCollectionsBSGDictSetSafeObjectTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BugsnagCollectionsBSGDictSetSafeObjectTest.m; path = ../../Tests/BugsnagCollectionsBSGDictSetSafeObjectTest.m; sourceTree = ""; }; @@ -745,6 +747,7 @@ 4B47970922A9AE1F00FF9C2E /* BugsnagEventFromKSCrashReportTest.m */, E77316E11F73B46600A14F06 /* BugsnagHandledStateTest.m */, F429554A50F3ABE60537F70E /* BugsnagKSCrashSysInfoParserTest.m */, + 009131BB23F46279000810D9 /* BugsnagMetadataTests.m */, E78C1EFB1FCC759B00B976D3 /* BugsnagSessionTest.m */, E78C1EF01FCC2F1700B976D3 /* BugsnagSessionTrackerTest.m */, E78C1EF21FCC615400B976D3 /* BugsnagSessionTrackingPayloadTest.m */, @@ -1261,6 +1264,7 @@ 000DF29423DB4B4900A883CE /* TestConstants.m in Sources */, 8A4E733F1DC13281001F7CC8 /* BugsnagConfigurationTests.m in Sources */, E784D25A1FD70C25004B01E1 /* KSJSONCodec_Tests.m in Sources */, + 009131BC23F46279000810D9 /* BugsnagMetadataTests.m in Sources */, E70EE0881FD7047800FA745C /* KSSystemInfo_Tests.m in Sources */, 4BE6C42622CAD61A0056305D /* BugsnagCollectionsBSGDictMergeTest.m in Sources */, E70EE0871FD7047800FA745C /* KSSysCtl_Tests.m in Sources */,