From 24e00d73b2a7e77e825609bbfdc822a5e859f94b Mon Sep 17 00:00:00 2001 From: Noah Martin Date: Wed, 8 Oct 2025 18:32:45 -0700 Subject: [PATCH 1/3] chore: Remove profiling API deprecated in V9 --- .../SentrySampleShared/SentrySDKWrapper.swift | 144 ---- .../iOS-Swift-UITests/ProfilingUITests.swift | 39 - Sentry.xcodeproj/project.pbxproj | 4 - Sources/Sentry/Public/SentryOptions.h | 13 - Sources/Sentry/SentryHub.m | 8 - Sources/Sentry/SentryOptions.m | 23 +- Sources/Sentry/SentrySampling.m | 37 - Sources/Sentry/SentyOptionsInternal.m | 6 - Sources/Sentry/include/SentrySampling.h | 10 - ...yAppStartProfilingConfigurationTests.swift | 1 - .../SentryTraceProfilerTests.swift | 686 ------------------ Tests/SentryTests/SentryOptionsTest.m | 21 - .../Transaction/SentrySpanTests.swift | 15 - 13 files changed, 2 insertions(+), 1005 deletions(-) delete mode 100644 Tests/SentryProfilerTests/SentryTraceProfilerTests.swift diff --git a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift index de938f1fa78..3885eb6c9dc 100644 --- a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift +++ b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift @@ -348,147 +348,3 @@ extension SentrySDKWrapper { config.onSubmitSuccess = { info in let name = info["name"] ?? "$shakespearean_insult_name" let alert = UIAlertController(title: "Thanks?", message: "We have enough jank of our own, we really didn't need yours too, \(name).", preferredStyle: .alert) - alert.addAction(.init(title: "Deal with it 🕶️", style: .default)) - UIApplication.shared.delegate?.window??.rootViewController?.present(alert, animated: true) - - // if there's a screenshot's Data in this dictionary, JSONSerialization crashes _even though_ there's a `try?`, so we'll write the base64 encoding of it - var infoToWriteToFile = info - if let attachments = info["attachments"] as? [Any], let screenshot = attachments.first as? Data { - infoToWriteToFile["attachments"] = [screenshot.base64EncodedString()] - } - - let jsonData = (try? JSONSerialization.data(withJSONObject: infoToWriteToFile, options: .sortedKeys)) ?? Data() - updateHookMarkers(forEvent: "onSubmitSuccess", with: jsonData.base64EncodedString()) - } - config.onSubmitError = { error in - let alert = UIAlertController(title: "D'oh", message: "You tried to report jank, and encountered more jank. The jank has you now: \(error).", preferredStyle: .alert) - alert.addAction(.init(title: "Derp", style: .default)) - UIApplication.shared.delegate?.window??.rootViewController?.present(alert, animated: true) - let nserror = error as NSError - let missingFieldsSorted = (nserror.userInfo["missing_fields"] as? [String])?.sorted().joined(separator: ";") ?? "" - updateHookMarkers(forEvent: "onSubmitError", with: "\(nserror.domain);\(nserror.code);\(nserror.localizedDescription);\(missingFieldsSorted)") - } - } - - func updateHookMarkers(forEvent name: String, with contents: String? = nil) { - guard let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first else { - print("[iOS-Swift] Couldn't retrieve path to application support directory.") - return - } - - let fm = FileManager.default - let dir = "\(appSupportDirectory)/io.sentry/feedback" - let isDirectory = UnsafeMutablePointer.allocate(capacity: 1) - isDirectory.initialize(to: ObjCBool(false)) - let exists = fm.fileExists(atPath: dir, isDirectory: isDirectory) - if exists, !isDirectory.pointee.boolValue { - print("[iOS-Swift] Found a file named \(dir) which is not a directory. Removing it...") - do { - try fm.removeItem(atPath: dir) - } catch { - print("[iOS-Swift] Couldn't remove existing file \(dir): \(error).") - return - } - } else if !exists { - do { - try fm.createDirectory(atPath: dir, withIntermediateDirectories: true) - } catch { - print("[iOS-Swift] Couldn't create directory structure for user feedback form hook marker files: \(error).") - return - } - } - - createHookFile(path: "\(dir)/\(name)", contents: contents) - - switch name { - case "onFormOpen": removeHookFile(path: "\(dir)/onFormClose") - case "onFormClose": removeHookFile(path: "\(dir)/onFormOpen") - case "onSubmitSuccess": removeHookFile(path: "\(dir)/onSubmitError") - case "onSubmitError": removeHookFile(path: "\(dir)/onSubmitSuccess") - default: fatalError("Unexpected marker file name") - } - } - - func createHookFile(path: String, contents: String?) { - if let contents = contents { - do { - try contents.write(to: URL(fileURLWithPath: path), atomically: false, encoding: .utf8) - } catch { - print("[iOS-Swift] Couldn't write contents into user feedback form hook marker file at \(path).") - } - } else if !FileManager.default.createFile(atPath: path, contents: nil) { - print("[iOS-Swift] Couldn't create user feedback form hook marker file at \(path).") - } else { - print("[iOS-Swift] Created user feedback form hook marker file at \(path).") - } - } - - func removeHookFile(path: String) { - let fm = FileManager.default - guard fm.fileExists(atPath: path) else { return } - do { - try fm.removeItem(atPath: path) - } catch { - print("[iOS-Swift] Couldn't remove user feedback form hook marker file \(path): \(error).") - } - } -} -#endif // !os(macOS) && !os(tvOS) && !os(watchOS) && !os(visionOS) - -// MARK: Convenience access to SDK configuration via launch arg / environment variable -extension SentrySDKWrapper { - public static let defaultDSN = "https://6cc9bae94def43cab8444a99e0031c28@o447951.ingest.sentry.io/5428557" - - var args: [String] { - return ProcessInfo.processInfo.arguments - } - - var env: [String: String] { - return ProcessInfo.processInfo.environment - } - - /// For testing purposes, we want to be able to change the DSN and store it to disk. In a real app, you shouldn't need this behavior. - var dsn: String? { - do { - if let dsn = env[SentrySDKOverrides.Special.dsn.rawValue] { - try DSNStorage.shared.saveDSN(dsn: dsn) - } - return try DSNStorage.shared.getDSN() ?? SentrySDKWrapper.defaultDSN - } catch { - print("[iOS-Swift] Error encountered while reading stored DSN: \(error)") - } - return nil - } - - /// Whether or not profiling benchmarks are being run; this requires disabling certain other features for proper functionality. - var isBenchmarking: Bool { args.contains("--io.sentry.test.benchmarking") } - var isUITest: Bool { env[SentrySDKOverrides.Other.environment.rawValue] == "ui-tests" } -} - -// MARK: Profiling configuration -#if !os(tvOS) && !os(watchOS) && !os(visionOS) -extension SentrySDKWrapper { - func configureProfiling(_ options: Options) { - #if !SDK_V9 - if let sampleRate = SentrySDKOverrides.Profiling.sampleRate.floatValue { - options.profilesSampleRate = NSNumber(value: sampleRate) - } - if let samplerValue = SentrySDKOverrides.Profiling.samplerValue.floatValue { - options.profilesSampler = { _ in - return NSNumber(value: samplerValue) - } - } - #endif // !SDK_V9 - - if !SentrySDKOverrides.Profiling.disableUIProfiling.boolValue { - options.configureProfiling = { - $0.lifecycle = SentrySDKOverrides.Profiling.manualLifecycle.boolValue ? .manual : .trace - $0.sessionSampleRate = SentrySDKOverrides.Profiling.sessionSampleRate.floatValue ?? 1 - $0.profileAppStarts = !SentrySDKOverrides.Profiling.disableAppStartProfiling.boolValue - } - } - } -} -#endif // !os(tvOS) && !os(watchOS) && !os(visionOS) - -// swiftlint:enable file_length function_body_length diff --git a/Samples/iOS-Swift/iOS-Swift-UITests/ProfilingUITests.swift b/Samples/iOS-Swift/iOS-Swift-UITests/ProfilingUITests.swift index 1c72308e58e..f59c20cd01c 100644 --- a/Samples/iOS-Swift/iOS-Swift-UITests/ProfilingUITests.swift +++ b/Samples/iOS-Swift/iOS-Swift-UITests/ProfilingUITests.swift @@ -22,45 +22,6 @@ class ProfilingUITests: BaseUITest { try performTest(lifecycle: .manual) } - - /** - * We had a bug where we forgot to install the frames tracker into the profiler, so weren't sending any GPU frame information with profiles. Since it's not possible to enforce such installation via the compiler, we test for the results we expect here, by starting a transaction, triggering an ANR which will cause degraded frame rendering, stop the transaction, and inspect the profile payload. - */ - func testProfilingGPUInfo() throws { - if #available(iOS 16, *) { - app.launchArguments.append(contentsOf: [ - SentrySDKOverrides.Special.wipeDataOnLaunch.rawValue, - - // we're only interested in the manual transaction, the automatic stuff messes up how we try to retrieve the target profile info - SentrySDKOverrides.Other.disableSwizzling.rawValue, - - SentrySDKOverrides.Profiling.disableAppStartProfiling.rawValue - ]) - app.launchEnvironment[SentrySDKOverrides.Profiling.sampleRate.rawValue] = "1.0" - launchApp() - - goToTransactions() - startTransaction() - - app.buttons["appHangFullyBlockingThreadSleeping"].afterWaitingForExistence("Couldn't find button to trigger fully blocking AppHang.").tap() - stopTransaction() - - goToProfiling() - retrieveLastProfileData() - let profileDict = try marshalJSONDictionaryFromApp() - - let metrics = try XCTUnwrap(profileDict["measurements"] as? [String: Any]) - // We can only be sure about frozen frames when triggering an ANR. - // It could be that there is no slow frame for the captured transaction. - let frozenFrames = try XCTUnwrap(metrics["frozen_frame_renders"] as? [String: Any]) - let frozenFrameValues = try XCTUnwrap(frozenFrames["values"] as? [[String: Any]]) - XCTAssertFalse(frozenFrameValues.isEmpty, "The test triggered an ANR while the transaction is running. There must be at least one frozen frame, but there was none.") - - let frameRates = try XCTUnwrap(metrics["screen_frame_rates"] as? [String: Any]) - let frameRateValues = try XCTUnwrap(frameRates["values"] as? [[String: Any]]) - XCTAssertFalse(frameRateValues.isEmpty) - } - } } extension ProfilingUITests { diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index 0166c545b26..faa23f52583 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -582,7 +582,6 @@ 8431EFD329B27B1100D8DC56 /* Resources in Resources */ = {isa = PBXBuildFile; fileRef = 630C01951EC341D600C52CEF /* Resources */; }; 8431EFDC29B27B5300D8DC56 /* SentryProfilerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 03F9D37B2819A65C00602916 /* SentryProfilerTests.mm */; }; 8431EFDD29B27B5300D8DC56 /* SentrySamplingProfilerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 035E73CB27D575B3005EEB11 /* SentrySamplingProfilerTests.mm */; }; - 8431EFDE29B27B5300D8DC56 /* SentryTraceProfilerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8419C0C328C1889D001C8259 /* SentryTraceProfilerTests.swift */; }; 8431EFDF29B27B5300D8DC56 /* SentryThreadHandleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 035E73C927D57398005EEB11 /* SentryThreadHandleTests.mm */; }; 8431EFE029B27B5300D8DC56 /* SentryBacktraceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 035E73C727D56757005EEB11 /* SentryBacktraceTests.mm */; }; 8431EFE129B27B5300D8DC56 /* SentryThreadMetadataCacheTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 035E73CD27D5790A005EEB11 /* SentryThreadMetadataCacheTests.mm */; }; @@ -1898,7 +1897,6 @@ 840B7EF22BBF83DF008B8120 /* SentryProfiler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "SentryProfiler+Private.h"; path = "Sources/Sentry/include/SentryProfiler+Private.h"; sourceTree = SOURCE_ROOT; }; 841325C42BF49EC40029228F /* SentryLaunchProfiling+Tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SentryLaunchProfiling+Tests.h"; sourceTree = ""; }; 841325DE2BFED0510029228F /* TestFramesTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestFramesTracker.swift; sourceTree = ""; }; - 8419C0C328C1889D001C8259 /* SentryTraceProfilerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryTraceProfilerTests.swift; sourceTree = ""; }; 84281C422A578E5600EE88F2 /* SentryProfilerState.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SentryProfilerState.mm; sourceTree = ""; }; 84281C442A57905700EE88F2 /* SentrySample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SentrySample.h; path = ../include/SentrySample.h; sourceTree = ""; }; 84281C452A57905700EE88F2 /* SentrySample.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySample.m; sourceTree = ""; }; @@ -4018,7 +4016,6 @@ 845CEB162D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift */, 84A898CD2E1DBDD1009A551E /* SentryAppStartProfilingConfigurationChangeTests.swift */, 845CEAEE2D83F79500B6B325 /* SentryProfilingPublicAPITests.swift */, - 8419C0C328C1889D001C8259 /* SentryTraceProfilerTests.swift */, 8446F5182BE172290040D57E /* SentryContinuousProfilerTests.swift */, 8431D4522BE1741E009EAEC1 /* SentryProfileTestFixture.swift */, ); @@ -6449,7 +6446,6 @@ 84F2A1CE2E06001300A94524 /* (null) in Sources */, 845CEB172D8A979700B6B325 /* SentryAppStartProfilingConfigurationTests.swift in Sources */, 8431EFE529B27BAD00D8DC56 /* SentryNSProcessInfoWrapperTests.swift in Sources */, - 8431EFDE29B27B5300D8DC56 /* SentryTraceProfilerTests.swift in Sources */, 84A898CE2E1DBDD1009A551E /* SentryAppStartProfilingConfigurationChangeTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index a3ae913d5c0..05836b4b0d7 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -598,19 +598,6 @@ typedef void (^SentryProfilingConfigurationBlock)(SentryProfileOptions *_Nonnull */ @property (nonatomic, assign, readonly) BOOL isProfilingEnabled DEPRECATED_MSG_ATTRIBUTE( "This property is deprecated and will be removed in a future version of the SDK"); - -/** - * @brief Whether to enable the sampling profiler. - * @note Profiling is not supported on watchOS or tvOS. - * @deprecated Use @c profilesSampleRate instead. Setting @c enableProfiling to @c YES is the - * equivalent of setting @c profilesSampleRate to @c 1.0 If @c profilesSampleRate is set, it will - * take precedence over this setting. - * @note Default is @c NO. - * @note Profiling is automatically disabled if a thread sanitizer is attached. - */ -@property (nonatomic, assign) BOOL enableProfiling DEPRECATED_MSG_ATTRIBUTE( - "Use profilesSampleRate or profilesSampler instead. This property will be removed in a future " - "version of the SDK"); # endif // !SDK_V9 #endif // SENTRY_TARGET_PROFILING_SUPPORTED diff --git a/Sources/Sentry/SentryHub.m b/Sources/Sentry/SentryHub.m index e92c237a0b4..50ede302c24 100644 --- a/Sources/Sentry/SentryHub.m +++ b/Sources/Sentry/SentryHub.m @@ -455,14 +455,6 @@ - (SentryTracer *)startTransactionWithContext:(SentryTransactionContext *)transa sampleRate:tracesSamplerDecision.sampleRate sampleRand:tracesSamplerDecision.sampleRand]; -#if SENTRY_TARGET_PROFILING_SUPPORTED && !SDK_V9 - if (![self.client.options isContinuousProfilingEnabled]) { - SentrySamplerDecision *profilesSamplerDecision = sentry_sampleTraceProfile( - samplingContext, tracesSamplerDecision, self.client.options); - configuration.profilesSamplerDecision = profilesSamplerDecision; - } -#endif // SENTRY_TARGET_PROFILING_SUPPORTED && !SDK_V9 - SentryTracer *tracer = [[SentryTracer alloc] initWithTransactionContext:transactionContext hub:self configuration:configuration]; diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 48ebc47c3c6..86b9c4a21cf 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -119,7 +119,6 @@ - (instancetype)init self.tracesSampleRate = nil; #if SENTRY_TARGET_PROFILING_SUPPORTED # if !SDK_V9 - _enableProfiling = NO; # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" self.profilesSampleRate = SENTRY_INITIAL_PROFILES_SAMPLE_RATE; @@ -305,7 +304,7 @@ - (void)setProfilesSampleRate:(NSNumber *)profilesSampleRate - (BOOL)isProfilingEnabled { return (_profilesSampleRate != nil && [_profilesSampleRate doubleValue] > 0) - || _profilesSampler != nil || _enableProfiling; + || _profilesSampler != nil; } - (BOOL)isContinuousProfilingEnabled @@ -315,7 +314,7 @@ - (BOOL)isContinuousProfilingEnabled // this looks a little weird with the `!self.enableProfiling` but that actually is the // deprecated way to say "enable trace-based profiling", which necessarily disables continuous // profiling as they are mutually exclusive modes - return _profilesSampleRate == nil && _profilesSampler == nil && !self.enableProfiling; + return _profilesSampleRate == nil && _profilesSampler == nil; # pragma clang diagnostic pop } @@ -339,24 +338,6 @@ - (BOOL)isProfilingCorrelatedToTraces || (_profiling != nil && _profiling.lifecycle == SentryProfileLifecycleTrace); # endif // SDK_V9 } - -# if !SDK_V9 -- (void)setEnableProfiling_DEPRECATED_TEST_ONLY:(BOOL)enableProfiling_DEPRECATED_TEST_ONLY -{ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - self.enableProfiling = enableProfiling_DEPRECATED_TEST_ONLY; -# pragma clang diagnostic pop -} - -- (BOOL)enableProfiling_DEPRECATED_TEST_ONLY -{ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - return self.enableProfiling; -# pragma clang diagnostic pop -} -# endif // !SDK_V9 #endif // SENTRY_TARGET_PROFILING_SUPPORTED #if SENTRY_UIKIT_AVAILABLE diff --git a/Sources/Sentry/SentrySampling.m b/Sources/Sentry/SentrySampling.m index e5645de02c7..351fc056613 100644 --- a/Sources/Sentry/SentrySampling.m +++ b/Sources/Sentry/SentrySampling.m @@ -86,43 +86,6 @@ #if SENTRY_TARGET_PROFILING_SUPPORTED -# if !SDK_V9 -SentrySamplerDecision * -sentry_sampleTraceProfile(SentrySamplingContext *context, - SentrySamplerDecision *tracesSamplerDecision, SentryOptions *options) -{ - // Profiles are always undersampled with respect to traces. If the trace is not sampled, - // the profile will not be either. If the trace is sampled, we can proceed to checking - // whether the associated profile should be sampled. - if (tracesSamplerDecision.decision != kSentrySampleDecisionYes) { - return [[SentrySamplerDecision alloc] initWithDecision:kSentrySampleDecisionNo - forSampleRate:nil - withSampleRand:nil]; - } - - // Backward compatibility for clients that are still using the enableProfiling option. -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - if (options.enableProfiling) { - return [[SentrySamplerDecision alloc] initWithDecision:kSentrySampleDecisionYes - forSampleRate:@1.0 - withSampleRand:@1.0]; - } - - NSNumber *callbackRate = _sentry_samplerCallbackRate( - options.profilesSampler, context, SENTRY_DEFAULT_PROFILES_SAMPLE_RATE); -# pragma clang diagnostic pop - if (callbackRate != nil) { - return _sentry_calcSample(callbackRate); - } - -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - return _sentry_calcSampleFromNumericalRate(options.profilesSampleRate); -# pragma clang diagnostic pop -} -# endif // !SDK_V9 - SentrySamplerDecision * sentry_sampleProfileSession(float sessionSampleRate) { diff --git a/Sources/Sentry/SentyOptionsInternal.m b/Sources/Sentry/SentyOptionsInternal.m index e0eee4c097c..c19b55ed346 100644 --- a/Sources/Sentry/SentyOptionsInternal.m +++ b/Sources/Sentry/SentyOptionsInternal.m @@ -363,12 +363,6 @@ + (BOOL)validateOptions:(NSDictionary *)options sentryOptions.profilesSampler = options[@"profilesSampler"]; } # pragma clang diagnostic pop - -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - [self setBool:options[@"enableProfiling"] - block:^(BOOL value) { sentryOptions.enableProfiling = value; }]; -# pragma clang diagnostic pop # endif // !SDK_V9 #endif // SENTRY_TARGET_PROFILING_SUPPORTED diff --git a/Sources/Sentry/include/SentrySampling.h b/Sources/Sentry/include/SentrySampling.h index 97742fe8e87..2811752c24c 100644 --- a/Sources/Sentry/include/SentrySampling.h +++ b/Sources/Sentry/include/SentrySampling.h @@ -14,16 +14,6 @@ SENTRY_EXTERN SentrySamplerDecision *sentry_sampleTrace( SentrySamplingContext *context, SentryOptions *options); #if SENTRY_TARGET_PROFILING_SUPPORTED -/** - * Determines whether a profile should be sampled based on the context, options, and - * whether the trace corresponding to the profile was sampled, to decide whether to configure the - * next launch to start a trace profile. - */ -# if !SDK_V9 -SENTRY_EXTERN SentrySamplerDecision *sentry_sampleTraceProfile(SentrySamplingContext *context, - SentrySamplerDecision *tracesSamplerDecision, SentryOptions *options); -# endif // !SDK_V9 - SENTRY_EXTERN SentrySamplerDecision *sentry_sampleProfileSession(float sessionSampleRate); #endif // SENTRY_TARGET_PROFILING_SUPPORTED diff --git a/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift b/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift index 58fa57ac541..f95b0363c1c 100644 --- a/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift +++ b/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift @@ -66,7 +66,6 @@ private extension SentryAppStartProfilingConfigurationTests { @available(*, deprecated, message: "This is only marked as deprecated because enableAppLaunchProfiling is marked as deprecated. Once that is removed this can be removed.") private func performTest(expectedOptions: LaunchProfileOptions, shouldProfileLaunch: Bool) { let actualOptions = Options() - if let tracesSampleRate = expectedOptions.tracesSampleRate { actualOptions.tracesSampleRate = NSNumber(value: tracesSampleRate) } else { diff --git a/Tests/SentryProfilerTests/SentryTraceProfilerTests.swift b/Tests/SentryProfilerTests/SentryTraceProfilerTests.swift deleted file mode 100644 index 66a02b8411c..00000000000 --- a/Tests/SentryProfilerTests/SentryTraceProfilerTests.swift +++ /dev/null @@ -1,686 +0,0 @@ -import _SentryPrivate -@_spi(Private) @testable import Sentry -@_spi(Private) import SentryTestUtils -import XCTest - -#if os(iOS) || os(macOS) || targetEnvironment(macCatalyst) -@available(*, deprecated, message: "This is only marked deprecated because SentryProfileTestFixture is marked as deprecated.") -class SentryTraceProfilerTests: XCTestCase { - - private var fixture: SentryProfileTestFixture! - - override class func setUp() { - super.setUp() - SentrySDKLogSupport.configure(true, diagnosticLevel: .debug) - } - - override func setUp() { - super.setUp() - fixture = SentryProfileTestFixture() - } - - override func tearDown() { - super.tearDown() - clearTestState() - } - - func testSentryProfilerTimoutInterval() { - XCTAssertEqual(30, kSentryProfilerTimeoutInterval) - } - - func testMetricProfiler() throws { - let span = try fixture.newTransaction() - try addMockSamples() - try fixture.gatherMockedTraceProfileMetrics() - self.fixture.currentDateProvider.advanceBy(nanoseconds: 1.toNanoSeconds()) - span.finish() - try self.assertMetricsPayload() - } - - func testCaptureTransactionWithProfile_StopsProfileOnCallingThread() throws { - let span = try fixture.newTransaction() - try addMockSamples() - try fixture.gatherMockedTraceProfileMetrics() - - self.fixture.dispatchQueueWrapper.dispatchAsyncExecutesBlock = false - let currentProfiler = try XCTUnwrap(SentryTraceProfiler.getCurrentProfiler()) - - XCTAssertTrue(currentProfiler.isRunning()) - - span.finish() - - XCTAssertFalse(currentProfiler.isRunning(), "Profiler must be stopped on the calling thread.") - XCTAssertEqual(SentryProfilerTruncationReason.normal, currentProfiler.truncationReason) - - self.fixture.currentDateProvider.advanceBy(nanoseconds: 1.toNanoSeconds()) - self.fixture.dispatchQueueWrapper.dispatchAsyncExecutesBlock = true - self.fixture.dispatchQueueWrapper.invokeLastDispatchAsync() - - try self.assertMetricsPayload() - try self.assertValidTraceProfileData() - } - - func testTransactionWithMutatedTracerID() throws { - let span = try fixture.newTransaction() - try addMockSamples() - self.fixture.currentDateProvider.advanceBy(nanoseconds: 1.toNanoSeconds()) - span.traceId = SentryId() - span.finish() - try self.assertValidTraceProfileData() - } - - func testConcurrentProfilingTransactions() throws { - let numberOfTransactions = 10 - var spans = [Span]() - - func createConcurrentSpansWithMetrics() throws { - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - - for i in 0 ..< numberOfTransactions { - print("creating new concurrent transaction for test") - let span = try fixture.newTransaction() - - // because energy readings are computed as the difference between sequential cumulative readings, we must increment the mock value by the expected result each iteration - fixture.systemWrapper.overrides.cpuEnergyUsage = NSNumber(value: try XCTUnwrap(fixture.systemWrapper.overrides.cpuEnergyUsage).intValue + fixture.mockMetrics.cpuEnergyUsage.intValue) - - XCTAssertTrue(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(i + 1)) - spans.append(span) - fixture.currentDateProvider.advanceBy(nanoseconds: 100) - } - - let threadMetadata = SentryProfileTestFixture.ThreadMetadata(id: 1, priority: 2, name: "test-thread") - try addMockSamples(threadMetadata: threadMetadata) - - for (i, span) in spans.enumerated() { - try fixture.gatherMockedTraceProfileMetrics() - - XCTAssertTrue(SentryTraceProfiler.isCurrentlyProfiling()) - span.finish() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(numberOfTransactions - (i + 1))) - - try self.assertValidTraceProfileData(expectedThreadMetadata: [threadMetadata]) - - // this is a complicated number to come up with, see the explanation for each part... - let expectedUsageReadings = fixture.mockMetrics.readingsPerBatch * (i + 1) // since we fire mock metrics readings for each concurrent span, - // we need to accumulate across the number of spans each iteration - + numberOfTransactions // and then, add the number of spans that were created to account for the start reading for each span - + 1 // and the end reading for this span - try self.assertMetricsPayload(oneLessEnergyReading: i == 0, expectedMetricsReadingsPerBatchOverride: expectedUsageReadings) - } - - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - } - - try createConcurrentSpansWithMetrics() - - // do everything again to make sure that stopping and starting the profiler over again works - spans.removeAll() -#if !os(macOS) - fixture.resetProfileGPUExpectations() -#endif // !os(macOS) - - try createConcurrentSpansWithMetrics() - } - - /// Test a situation where a long-running span starts the profiler, which winds up timing out, and then another span starts that begins a new profile, then finishes, and then the long-running span finishes; both profiles should be separately captured in envelopes. - /// ``` - /// time-> - /// transaction A |---------------------------------------------------| - /// profiler A |---------------------------x <- timeout - /// transaction B |-------| - /// profiler B |-------| <- normal finish - /// ``` - func testConcurrentSpansWithTimeout() throws { - // start span A and mock profile data for it - let spanA = try fixture.newTransaction() - fixture.currentDateProvider.advanceBy(nanoseconds: 1.toNanoSeconds()) - let expectedAddressesA: [NSNumber] = [0x1, 0x2, 0x3] - let expectedThreadMetadataA = SentryProfileTestFixture.ThreadMetadata(id: 1, priority: 2, name: "test-thread1") - try addMockSamples(threadMetadata: expectedThreadMetadataA, addresses: expectedAddressesA) - - // time out profiler for span A - fixture.currentDateProvider.advanceBy(nanoseconds: 30.toNanoSeconds()) - try fixture.timeoutTimerFactory.fire() - - fixture.currentDateProvider.advanceBy(nanoseconds: 0.5.toNanoSeconds()) - - // start span B and mock profile data for it - let spanB = try fixture.newTransaction() - fixture.currentDateProvider.advanceBy(nanoseconds: 0.5.toNanoSeconds()) - let expectedAddressesB: [NSNumber] = [0x7, 0x8, 0x9] - let expectedThreadMetadataB = SentryProfileTestFixture.ThreadMetadata(id: 4, priority: 5, name: "test-thread2") - try addMockSamples(threadMetadata: expectedThreadMetadataB, addresses: expectedAddressesB) - - // finish span B and check profile data - spanB.finish() - try self.assertValidTraceProfileData(expectedAddresses: expectedAddressesB, expectedThreadMetadata: [expectedThreadMetadataB]) - - // finish span A and check profile data - spanA.finish() - try self.assertValidTraceProfileData(expectedAddresses: expectedAddressesA, expectedThreadMetadata: [expectedThreadMetadataA]) - } - - func testProfileTimeoutTimer() throws { - try performTraceProfilingTest(shouldTimeOut: true) - } - - func testStartTransaction_ProfilingDataIsValid() throws { - try performTraceProfilingTest() - } - - func testProfilingDataContainsEnvironmentSetFromOptions() throws { - let expectedEnvironment = "test-environment" - fixture.options.environment = expectedEnvironment - try performTraceProfilingTest(transactionEnvironment: expectedEnvironment) - } - -#if !os(macOS) - func testProfileWithTransactionContainingStartupSpansForColdStart() throws { - try performTraceProfilingTest(uikitParameters: UIKitParameters(launchType: .cold, prewarmed: false)) - } - - func testProfileWithTransactionContainingStartupSpansForWarmStart() throws { - try performTraceProfilingTest(uikitParameters: UIKitParameters(launchType: .warm, prewarmed: false)) - } - - func testProfileWithTransactionContainingStartupSpansForPrewarmedStart() throws { - try performTraceProfilingTest(uikitParameters: UIKitParameters(launchType: .warm, prewarmed: true)) - } -#endif // !os(macOS) - - func testProfilingDataContainsEnvironmentSetFromConfigureScope() throws { - let expectedEnvironment = "test-environment" - fixture.hub.configureScope { scope in - scope.setEnvironment(expectedEnvironment) - } - try performTraceProfilingTest(transactionEnvironment: expectedEnvironment) - } - - func testStartTransaction_NotSamplingProfileUsingEnableProfiling() throws { - try assertProfilesSampler(expectedDecision: .no) { options in - options.enableProfiling_DEPRECATED_TEST_ONLY = false - } - } - - func testStartTransaction_SamplingProfileUsingEnableProfiling() throws { - try assertProfilesSampler(expectedDecision: .yes) { options in - options.enableProfiling_DEPRECATED_TEST_ONLY = true - } - } - - func testStartTransaction_NotSamplingProfileUsingSampleRate() throws { - try assertProfilesSampler(expectedDecision: .no) { options in - options.profilesSampleRate = 0.49 - } - } - - func testStartTransaction_SamplingProfileUsingSampleRate() throws { - try assertProfilesSampler(expectedDecision: .yes) { options in - options.profilesSampleRate = 0.5 - } - } - - func testStartTransaction_SamplingProfileUsingProfilesSampler() throws { - try assertProfilesSampler(expectedDecision: .yes) { options in - options.profilesSampler = { _ in return 0.51 } - } - } - - func testStartTransaction_WhenProfilesSampleRateAndProfilesSamplerNil() throws { - try assertProfilesSampler(expectedDecision: .no) { options in - options.profilesSampleRate = 0 - options.profilesSampler = { _ in return nil } - } - } - - func testStartTransaction_WhenProfilesSamplerOutOfRange_TooBig() throws { - try assertProfilesSampler(expectedDecision: .no) { options in - options.profilesSampler = { _ in return 1.01 } - } - } - - func testStartTransaction_WhenProfilesSamplersOutOfRange_TooSmall() throws { - try assertProfilesSampler(expectedDecision: .no) { options in - options.profilesSampler = { _ in return -0.01 } - } - } - - /// based on ``SentryTracerTests.testFinish_WithoutHub_DoesntCaptureTransaction`` - func testProfilerCleanedUpAfterTransactionDiscarded_NoHub() throws { - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - func performTransaction() { - let sut = SentryTracer(transactionContext: TransactionContext(name: fixture.transactionName, operation: fixture.transactionOperation), hub: nil) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - sut.finish() - } - performTransaction() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - XCTAssertEqual(self.fixture.client?.captureEventWithScopeInvocations.count, 0) - } - - /// based on ``SentryTracerTests.testFinish_WaitForAllChildren_ExceedsMaxDuration_NoTransactionCaptured`` - func testProfilerCleanedUpAfterTransactionDiscarded_ExceedsMaxDuration() throws { - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - func performTransaction() throws { - let sut = try fixture.newTransaction(automaticTransaction: true) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(1)) - fixture.currentDateProvider.advance(by: 500) - sut.finish() - } - try performTransaction() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - XCTAssertEqual(self.fixture.client?.captureEventWithScopeInvocations.count, 0) - } - - func testProfilerCleanedUpAfterInFlightTransactionDeallocated() throws { - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - func performTransaction() throws { - let sut = try fixture.newTransaction(automaticTransaction: true) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(1)) - XCTAssertFalse(sut.isFinished) - } - try performTransaction() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - XCTAssertEqual(self.fixture.client?.captureEventWithScopeInvocations.count, 0) - } - - /// based on ``SentryTracerTests.testFinish_IdleTimeout_ExceedsMaxDuration_NoTransactionCaptured`` - func testProfilerCleanedUpAfterTransactionDiscarded_IdleTimeout_ExceedsMaxDuration() throws { - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - func performTransaction() throws { - let sut = try fixture.newTransaction(automaticTransaction: true, idleTimeout: 1) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(1)) - fixture.currentDateProvider.advance(by: 500) - sut.finish() - } - try performTransaction() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - XCTAssertEqual(self.fixture.client?.captureEventWithScopeInvocations.count, 0) - } - - /// based on ``SentryTracerTests.testIdleTimeout_NoChildren_TransactionNotCaptured`` - func testProfilerCleanedUpAfterTransactionDiscarded_IdleTimeout_NoChildren() throws { - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - func performTransaction() throws { - let span = try fixture.newTransaction(automaticTransaction: true, idleTimeout: 1) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(1)) - fixture.currentDateProvider.advance(by: 500) - fixture.dispatchQueueWrapper.invokeLastDispatchAfter() - XCTAssert(span.isFinished) - } - try performTransaction() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - XCTAssertEqual(self.fixture.client?.captureEventWithScopeInvocations.count, 0) - } - - /// based on ``SentryTracerTests.testIdleTransaction_CreatingDispatchBlockFails_NoTransactionCaptured`` - func testProfilerCleanedUpAfterTransactionDiscarded_IdleTransaction_CreatingDispatchBlockFails() throws { - fixture.dispatchQueueWrapper.createDispatchBlockReturnsNULL = true - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - func performTransaction() throws { - let span = try fixture.newTransaction(automaticTransaction: true, idleTimeout: 1) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(1)) - fixture.currentDateProvider.advance(by: 500) - span.finish() - } - try performTransaction() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - XCTAssertEqual(self.fixture.client?.captureEventWithScopeInvocations.count, 0) - } - -#if !os(macOS) - /// based on ``SentryTracerTests.testFinish_WaitForAllChildren_StartTimeModified_NoTransactionCaptured`` - func testProfilerCleanedUpAfterTransactionDiscarded_WaitForAllChildren_StartTimeModified() throws { - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - let appStartMeasurement = fixture.getAppStartMeasurement(type: .cold) - SentrySDKInternal.setAppStartMeasurement(appStartMeasurement) - fixture.currentDateProvider.advance(by: 1) - func performTransaction() throws { - let sut = try fixture.newTransaction(testingAppLaunchSpans: true, automaticTransaction: true) - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(1)) - fixture.currentDateProvider.advance(by: 499) - sut.finish() - } - try performTransaction() - XCTAssertEqual(SentryTraceProfiler.currentProfiledTracers(), UInt(0)) - XCTAssertEqual(self.fixture.client?.captureEventWithScopeInvocations.count, 0) - } - - // test that receiving a backgrounding notification stops the profiler - func testTraceProfilerStopsOnBackgrounding() throws { - let span = try fixture.newTransaction() - XCTAssert(try XCTUnwrap(SentryTraceProfiler.getCurrentProfiler()).isRunning()) - fixture.currentDateProvider.advance(by: 1) - fixture.notificationCenter.post(Notification(name: UIApplication.willResignActiveNotification, object: nil)) - XCTAssertFalse(try XCTUnwrap(SentryTraceProfiler.getCurrentProfiler()).isRunning()) - span.finish() // this isn't germane to the test, but we need the span to be retained throughout the test, and this satisfies the unused variable check - } -#endif // !os(macOS) -} - -@available(*, deprecated, message: "This is only marked deprecated because SentryProfileTestFixture is marked as deprecated.") -private extension SentryTraceProfilerTests { - func getLatestProfileData() throws -> Data { - let envelope = try XCTUnwrap(self.fixture.client?.captureEventWithScopeInvocations.last) - - XCTAssertEqual(1, envelope.additionalEnvelopeItems.count) - let profileItem = try XCTUnwrap(envelope.additionalEnvelopeItems.first) - - XCTAssertEqual("profile", profileItem.header.type) - return try XCTUnwrap(profileItem.data) - } - - func getLatestTransaction() throws -> Transaction { - let envelope = try XCTUnwrap(self.fixture.client?.captureEventWithScopeInvocations.last) - return try XCTUnwrap(envelope.event as? Transaction) - } - - func addMockSamples(threadMetadata: SentryProfileTestFixture.ThreadMetadata = SentryProfileTestFixture.ThreadMetadata(id: 1, priority: 2, name: "main"), addresses: [NSNumber] = [0x3, 0x4, 0x5]) throws { - let state = try XCTUnwrap(SentryTraceProfiler.getCurrentProfiler()).state - fixture.currentDateProvider.advanceBy(nanoseconds: 1) - SentryProfilerMocksSwiftCompatible.appendMockBacktrace(to: state, threadID: threadMetadata.id, threadPriority: threadMetadata.priority, threadName: threadMetadata.name, addresses: addresses) - fixture.currentDateProvider.advanceBy(nanoseconds: 1) - SentryProfilerMocksSwiftCompatible.appendMockBacktrace(to: state, threadID: threadMetadata.id, threadPriority: threadMetadata.priority, threadName: threadMetadata.name, addresses: addresses) - fixture.currentDateProvider.advanceBy(nanoseconds: 1) - SentryProfilerMocksSwiftCompatible.appendMockBacktrace(to: state, threadID: threadMetadata.id, threadPriority: threadMetadata.priority, threadName: threadMetadata.name, addresses: addresses) - } - - struct UIKitParameters { -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - var launchType: SentryAppStartType - var prewarmed: Bool -#endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - } - - func performTraceProfilingTest(transactionEnvironment: String = kSentryDefaultEnvironment, shouldTimeOut: Bool = false, uikitParameters: UIKitParameters? = nil) throws { - var testingAppLaunchSpans = false - -#if os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - if let uikitParameters = uikitParameters { - testingAppLaunchSpans = true - let appStartMeasurement = fixture.getAppStartMeasurement(type: uikitParameters.launchType, preWarmed: uikitParameters.prewarmed) - SentrySDKInternal.setAppStartMeasurement(appStartMeasurement) - } -#endif // os(iOS) || os(tvOS) || targetEnvironment(macCatalyst) - - let span = try fixture.newTransaction(testingAppLaunchSpans: testingAppLaunchSpans) - - try addMockSamples() - fixture.currentDateProvider.advance(by: 31) - if shouldTimeOut { - try self.fixture.timeoutTimerFactory.fire() - } - - let exp = expectation(description: "finished span") - DispatchQueue.main.async { - span.finish() - exp.fulfill() - } - - waitForExpectations(timeout: 1) - - try self.assertValidTraceProfileData(transactionEnvironment: transactionEnvironment, shouldTimeout: shouldTimeOut, appStartProfile: testingAppLaunchSpans) - } - - func assertMetricsPayload(oneLessEnergyReading: Bool = true, expectedMetricsReadingsPerBatchOverride: Int? = nil) throws { - let profileData = try self.getLatestProfileData() - let transaction = try getLatestTransaction() - let profile = try XCTUnwrap(JSONSerialization.jsonObject(with: profileData) as? [String: Any]) - let measurements = try XCTUnwrap(profile["measurements"] as? [String: Any]) - let expectedUsageReadings = expectedMetricsReadingsPerBatchOverride ?? fixture.mockMetrics.readingsPerBatch + 2 // including one sample at the start and the end - - try assertMetricValue(measurements: measurements, key: kSentryMetricProfilerSerializationKeyCPUUsage, numberOfReadings: expectedUsageReadings, expectedValue: fixture.mockMetrics.cpuUsage, transaction: transaction, expectedUnits: kSentryMetricProfilerSerializationUnitPercentage) - - try assertMetricValue(measurements: measurements, key: kSentryMetricProfilerSerializationKeyMemoryFootprint, numberOfReadings: expectedUsageReadings, expectedValue: fixture.mockMetrics.memoryFootprint, transaction: transaction, expectedUnits: kSentryMetricProfilerSerializationUnitBytes) - - #if arch(arm) || arch(arm64) - // we wind up with one less energy reading for the first concurrent span's metric sample. since we must use the difference between readings to get actual values, the first one is only the baseline reading. - let expectedEnergyReadings = oneLessEnergyReading ? expectedUsageReadings - 1 : expectedUsageReadings - try assertMetricValue(measurements: measurements, key: kSentryMetricProfilerSerializationKeyCPUEnergyUsage, numberOfReadings: expectedEnergyReadings, expectedValue: fixture.mockMetrics.cpuEnergyUsage, transaction: transaction, expectedUnits: kSentryMetricProfilerSerializationUnitNanoJoules) - #endif // arch(arm) || arch(arm64) - -#if !os(macOS) - try assertMetricEntries(measurements: measurements, key: kSentryProfilerSerializationKeySlowFrameRenders, expectedEntries: fixture.expectedTraceProfileSlowFrames, transaction: transaction) - try assertMetricEntries(measurements: measurements, key: kSentryProfilerSerializationKeyFrozenFrameRenders, expectedEntries: fixture.expectedTraceProfileFrozenFrames, transaction: transaction) - try assertMetricEntries(measurements: measurements, key: kSentryProfilerSerializationKeyFrameRates, expectedEntries: fixture.expectedTraceProfileFrameRateChanges, transaction: transaction) -#endif // !os(macOS) - } - - func sortedByTimestamps(_ entries: [[String: Any]]) throws -> [[String: Any]] { - try entries.sorted { a, b in - let aValue = try XCTUnwrap(a["elapsed_since_start_ns"] as? String) - let aIntValue = try XCTUnwrap(UInt64(aValue)) - let bValue = try XCTUnwrap(b["elapsed_since_start_ns"] as? String) - let bIntValue = try XCTUnwrap(UInt64(bValue)) - return aIntValue < bIntValue - } - } - - func printTimestamps(entries: [[String: Any]]) -> [NSString] { - entries.compactMap({ $0["elapsed_since_start_ns"] as? NSString }) - } - - func assertMetricEntries(measurements: [String: Any], key: String, expectedEntries: [[String: Any]], transaction: Transaction) throws { - let metricContainer = try XCTUnwrap(measurements[key] as? [String: Any]) - let actualEntries = try XCTUnwrap(metricContainer["values"] as? [[String: Any]]) - let sortedActualEntries = try sortedByTimestamps(actualEntries) - let sortedExpectedEntries = try sortedByTimestamps(expectedEntries) - - guard actualEntries.count == expectedEntries.count else { - XCTFail("Wrong number of values under \(key). expected: \(printTimestamps(entries: sortedExpectedEntries)); actual: \(printTimestamps(entries: sortedActualEntries)); transaction start time: \(transaction.startSystemTime)") - return - } - - for i in 0..(measurements: [String: Any], key: String, numberOfReadings: Int, expectedValue: T? = nil, transaction: Transaction, expectedUnits: String) throws { - let metricContainer = try XCTUnwrap(measurements[key] as? [String: Any]) - let values = try XCTUnwrap(metricContainer["values"] as? [[String: Any]]) - XCTAssertEqual(values.count, numberOfReadings, "Wrong number of values under \(key)") - - if let expectedValue = expectedValue { - let actualValue = try XCTUnwrap(values.element(at: 1)?["value"] as? T) - XCTAssertEqual(actualValue, expectedValue, "Wrong value for \(key)") - - let timestamp = try XCTUnwrap(values.first?["elapsed_since_start_ns"] as? NSString) - try assertTimestampOccursWithinTransaction(timestamp: timestamp, transaction: transaction) - - let actualUnits = try XCTUnwrap(metricContainer["unit"] as? String) - XCTAssertEqual(actualUnits, expectedUnits) - } - } - - /// Assert that the relative timestamp actually falls within the transaction's duration, so it should be between 0 and the transaction duration. The string that holds an elapsed time actually holds an unsigned long long value (due to us using unsigned 64 bit integers, which are not officially supported by JSON), but there is no Cocoa API to get that back out of a string. So, we'll just convert them to signed 64 bit integers, for which there is an API. This likely won't cause a problem because signed 64 bit ints still support large positive values that are likely to be larger than any amount of nanoseconds of a machine's uptime. We can revisit if this actually fails in practice. - func assertTimestampOccursWithinTransaction(timestamp: NSString, transaction: Transaction) throws { - let transactionDuration = Int64(getDurationNs(transaction.startSystemTime, transaction.endSystemTime)) - let timestampNumericValue = timestamp.longLongValue - XCTAssertGreaterThanOrEqual(timestampNumericValue, 0) - XCTAssertLessThanOrEqual(timestampNumericValue, transactionDuration) - } - - enum SentryProfilerSwiftTestError: Error { - case notEnoughAppStartSpans - } - - func assertValidTraceProfileData(transactionEnvironment: String = kSentryDefaultEnvironment, shouldTimeout: Bool = false, expectedAddresses: [NSNumber]? = nil, expectedThreadMetadata: [SentryProfileTestFixture.ThreadMetadata]? = nil, appStartProfile: Bool = false) throws { - let data = try getLatestProfileData() - let profile = try XCTUnwrap(try JSONSerialization.jsonObject(with: data) as? [String: Any]) - - XCTAssertEqual(try XCTUnwrap(profile["version"] as? String), "1") - - let device = try XCTUnwrap(profile["device"] as? [String: Any?]) - XCTAssertNotNil(device) - XCTAssertEqual("Apple", try XCTUnwrap(device["manufacturer"] as? String)) - XCTAssertEqual(try XCTUnwrap(device["locale"] as? String), (NSLocale.current as NSLocale).localeIdentifier) - XCTAssertFalse(try XCTUnwrap(device["model"] as? String).isEmpty) -#if targetEnvironment(simulator) - XCTAssertTrue(try XCTUnwrap(device["is_emulator"] as? Bool)) -#else - XCTAssertFalse(try XCTUnwrap(device["is_emulator"] as? Bool)) -#endif // targetEnvironment(simulator) - - let os = try XCTUnwrap(profile["os"] as? [String: Any?]) - XCTAssertNotNil(os) - XCTAssertNotNil(try XCTUnwrap(os["name"] as? String)) - XCTAssertFalse(try XCTUnwrap(os["version"] as? String).isEmpty) - XCTAssertFalse(try XCTUnwrap(os["build_number"] as? String).isEmpty) - - let platform = try XCTUnwrap(profile["platform"] as? String) - XCTAssertEqual("cocoa", platform) - - XCTAssertEqual(transactionEnvironment, try XCTUnwrap(profile["environment"] as? String)) - - let bundleID = Bundle.main.object(forInfoDictionaryKey: kCFBundleIdentifierKey as String) ?? "(null)" - let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "(null)" - let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) ?? "(null)" - let expectedReleaseString = "\(bundleID)@\(version)+\(build)" - let actualReleaseString = try XCTUnwrap(profile["release"] as? String) - XCTAssertEqual(actualReleaseString, expectedReleaseString) - - XCTAssertNotEqual(SentryId.empty, SentryId(uuidString: try XCTUnwrap(profile["profile_id"] as? String))) - - let debugMeta = try XCTUnwrap(profile["debug_meta"] as? [String: Any]) - let images = try XCTUnwrap(debugMeta["images"] as? [[String: Any]]) - XCTAssertFalse(images.isEmpty) - let firstImage = try XCTUnwrap(images.first) - XCTAssertFalse(try XCTUnwrap(firstImage["code_file"] as? String).isEmpty) - XCTAssertFalse(try XCTUnwrap(firstImage["debug_id"] as? String).isEmpty) - XCTAssertFalse(try XCTUnwrap(firstImage["image_addr"] as? String).isEmpty) - XCTAssertGreaterThan(try XCTUnwrap(firstImage["image_size"] as? Int), 0) - XCTAssertEqual(try XCTUnwrap(firstImage["type"] as? String), "macho") - - let sampledProfile = try XCTUnwrap(profile["profile"] as? [String: Any]) - let threadMetadata = try XCTUnwrap(sampledProfile["thread_metadata"] as? [String: [String: Any]]) - XCTAssertFalse(threadMetadata.isEmpty) - if let expectedThreadMetadata = expectedThreadMetadata { - try expectedThreadMetadata.forEach { - let actualThreadMetadata = try XCTUnwrap(threadMetadata["\($0.id)"]) - let actualThreadPriority = try XCTUnwrap(actualThreadMetadata["priority"] as? Int32) - XCTAssertEqual(actualThreadPriority, $0.priority) - let actualThreadName = try XCTUnwrap(actualThreadMetadata["name"] as? String) - XCTAssertEqual(actualThreadName, $0.name) - } - } else { - XCTAssertFalse(try threadMetadata.values.compactMap { $0["priority"] }.filter { try XCTUnwrap($0 as? Int) > 0 }.isEmpty) - XCTAssertFalse(try threadMetadata.values.compactMap { $0["name"] }.filter { try XCTUnwrap($0 as? String) == "main" }.isEmpty) - } - - let samples = try XCTUnwrap(sampledProfile["samples"] as? [[String: Any]]) - XCTAssertFalse(samples.isEmpty) - - let frames = try XCTUnwrap(sampledProfile["frames"] as? [[String: Any]]) - XCTAssertFalse(frames.isEmpty) - XCTAssertFalse(try XCTUnwrap(frames.first?["instruction_addr"] as? String).isEmpty) - XCTAssertFalse(try XCTUnwrap(frames.first?["function"] as? String).isEmpty) - - let stacks = try XCTUnwrap(sampledProfile["stacks"] as? [[Int]]) - var foundAtLeastOneNonEmptySample = false - XCTAssertFalse(stacks.isEmpty) - for stack in stacks { - guard !stack.isEmpty else { continue } - foundAtLeastOneNonEmptySample = true - for frameIdx in stack { - XCTAssertNotNil(frames[frameIdx]) - } - } - XCTAssert(foundAtLeastOneNonEmptySample) - - let latestTransaction = try getLatestTransaction() - let linkedTransactionInfo = try XCTUnwrap(profile["transaction"] as? [String: Any]) - - let profileTimestampString = try XCTUnwrap(profile["timestamp"] as? String) - - let latestTransactionTimestamp = try XCTUnwrap(latestTransaction.startTimestamp) - var startTimestampString = sentry_toIso8601String(latestTransactionTimestamp) - #if !os(macOS) - if appStartProfile { - let runtimeInitTimestamp = try XCTUnwrap(SentrySDKInternal.getAppStartMeasurement()?.runtimeInitTimestamp) - startTimestampString = sentry_toIso8601String(runtimeInitTimestamp) - } - #endif // !os(macOS) - - XCTAssertEqual(profileTimestampString, startTimestampString) - - XCTAssertEqual(fixture.transactionName, latestTransaction.transaction) - XCTAssertEqual(fixture.transactionName, try XCTUnwrap(linkedTransactionInfo["name"] as? String)) - - let linkedTransactionId = SentryId(uuidString: try XCTUnwrap(linkedTransactionInfo["id"] as? String)) - XCTAssertEqual(latestTransaction.eventId, linkedTransactionId) - XCTAssertNotEqual(SentryId.empty, linkedTransactionId) - - let linkedTransactionTraceId = SentryId(uuidString: try XCTUnwrap(linkedTransactionInfo["trace_id"] as? String)) - XCTAssertEqual(latestTransaction.trace.traceId, linkedTransactionTraceId) - XCTAssertNotEqual(SentryId.empty, linkedTransactionTraceId) - - let activeThreadId = try XCTUnwrap(linkedTransactionInfo["active_thread_id"] as? NSNumber) - XCTAssertEqual(activeThreadId, latestTransaction.trace.transactionContext.sentry_threadInfo().threadId) - - for sample in samples { - let timestamp = try XCTUnwrap(sample["elapsed_since_start_ns"] as? NSString) - try assertTimestampOccursWithinTransaction(timestamp: timestamp, transaction: latestTransaction) - XCTAssertNotNil(sample["thread_id"]) - let stackIDEntry = try XCTUnwrap(sample["stack_id"]) - let stackID = try XCTUnwrap(stackIDEntry as? Int) - XCTAssertNotNil(stacks[stackID]) - } - - if shouldTimeout { - XCTAssertEqual(try XCTUnwrap(profile["truncation_reason"] as? String), sentry_profilerTruncationReasonName(SentryProfilerTruncationReason.timeout)) - } - } - - func assertProfilesSampler(expectedDecision: SentrySampleDecision, options: (Options) -> Void) throws { - let fixtureOptions = fixture.options - fixtureOptions.tracesSampleRate = 1.0 - fixtureOptions.profilesSampleRate = 0 - fixtureOptions.profilesSampler = { _ in - switch expectedDecision { - case .undecided, .no: - return NSNumber(value: 0) - case .yes: - return NSNumber(value: 1) - @unknown default: - XCTFail("Unexpected value for sample decision") - return NSNumber(value: 0) - } - } - options(fixtureOptions) - - let span = try fixture.newTransaction() - if expectedDecision == .yes { - try addMockSamples() - } - fixture.currentDateProvider.advance(by: 5) - span.finish() - - let client = try XCTUnwrap(self.fixture.client) - - switch expectedDecision { - case .undecided, .no: - let event = try XCTUnwrap(client.captureEventWithScopeInvocations.first) - XCTAssertEqual(0, event.additionalEnvelopeItems.count) - case .yes: - let event = try XCTUnwrap(client.captureEventWithScopeInvocations.first) - XCTAssertEqual(1, event.additionalEnvelopeItems.count) - @unknown default: - XCTFail("Unexpected value for sample decision") - } - } -} -#endif // os(iOS) || os(macOS) || targetEnvironment(macCatalyst) diff --git a/Tests/SentryTests/SentryOptionsTest.m b/Tests/SentryTests/SentryOptionsTest.m index 7ce07be3fa4..a3ea1d517d0 100644 --- a/Tests/SentryTests/SentryOptionsTest.m +++ b/Tests/SentryTests/SentryOptionsTest.m @@ -777,7 +777,6 @@ - (void)assertDefaultValues:(SentryOptions *)options #if SENTRY_TARGET_PROFILING_SUPPORTED # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" - XCTAssertEqual(NO, options.enableProfiling); XCTAssertNil(options.profilesSampleRate); XCTAssertNil(options.profilesSampler); # pragma clang diagnostic pop @@ -1114,10 +1113,6 @@ - (void)testIsTracingEnabled_TracesSamplerSet_IsEnabled } #if SENTRY_TARGET_PROFILING_SUPPORTED -- (void)testEnableProfiling -{ - [self testBooleanField:@"enableProfiling" defaultValue:NO]; -} # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -1247,22 +1242,6 @@ - (void)testIsProfilingEnabled_ProfilesSamplerSet_IsEnabled XCTAssertFalse([options isContinuousProfilingEnabled]); } -- (void)testIsProfilingEnabled_EnableProfilingSet_IsEnabled -{ - SentryOptions *options = [[SentryOptions alloc] init]; -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - options.enableProfiling = YES; -# pragma clang diagnostic pop - - // This property now only refers to trace-based profiling, but renaming it would require a major - // rev - XCTAssertTrue(options.isProfilingEnabled); - - XCTAssertNil(options.profilesSampleRate); - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - - (void)testProfilesSampler { SentryTracesSamplerCallback sampler = ^(SentrySamplingContext *context) { diff --git a/Tests/SentryTests/Transaction/SentrySpanTests.swift b/Tests/SentryTests/Transaction/SentrySpanTests.swift index 6a9fcd5d500..99037a9da87 100644 --- a/Tests/SentryTests/Transaction/SentrySpanTests.swift +++ b/Tests/SentryTests/Transaction/SentrySpanTests.swift @@ -67,21 +67,6 @@ class SentrySpanTests: XCTestCase { } #if os(iOS) || os(macOS) || targetEnvironment(macCatalyst) - func testSpanDoesNotIncludeTraceProfilerID() throws { - fixture.options.profilesSampleRate = 1 - SentrySDKInternal.setStart(with: fixture.options) - let span = fixture.getSut() - let continuousProfileObservations = fixture.notificationCenter.addObserverWithObjectInvocations.invocations.filter { - $0.name?.rawValue == kSentryNotificationContinuousProfileStarted - } - XCTAssertEqual(continuousProfileObservations.count, 0) - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - span.finish() - - let serialized = span.serialize() - XCTAssertNil(serialized["profile_id"]) - } - func testSpanDoesNotSubscribeToNotificationsIfAlreadyCapturedContinuousProfileID() { fixture.options.profilesSampleRate = nil SentryContinuousProfiler.start() From 808a3e896b271f9e22c896ea2e7732e936d7a9de Mon Sep 17 00:00:00 2001 From: Noah Martin Date: Mon, 20 Oct 2025 09:56:42 -0400 Subject: [PATCH 2/3] WIP --- .../SentrySDKOverrides.swift | 12 - .../SentrySampleShared/SentrySDKWrapper.swift | 133 ++ .../iOS-ObjectiveC/AppDelegate.m | 21 - .../Profiling/ProfilingViewController.swift | 21 - .../Sentry/Profiling/SentryLaunchProfiling.m | 77 +- .../Profiling/SentryProfileConfiguration.m | 4 +- .../SentryProfiledTracerConcurrency.mm | 22 +- .../Profiling/SentryProfilingSwiftHelpers.m | 8 - Sources/Sentry/Public/SentryOptions.h | 62 - Sources/Sentry/SentryOptions.m | 47 - Sources/Sentry/SentryProfiler.mm | 15 +- Sources/Sentry/SentrySDKInternal.m | 27 - Sources/Sentry/SentrySpan.m | 4 - Sources/Sentry/SentyOptionsInternal.m | 18 - .../Sentry/include/SentryLaunchProfiling.h | 3 - .../Sentry/include/SentryOptions+Private.h | 8 - .../include/SentryProfileConfiguration.h | 4 +- .../include/SentryProfilingSwiftHelpers.h | 3 - .../SentryAppLaunchProfilingTests.swift | 6 - ...artProfilingConfigurationChangeTests.swift | 1350 +---------------- ...yAppStartProfilingConfigurationTests.swift | 181 +-- .../SentryContinuousProfilerTests.swift | 11 - .../SentryProfileTestFixture.swift | 1 - .../SentryProfilingPublicAPITests.swift | 192 --- .../SentryProfilingSwiftHelpersTests.m | 9 - Tests/SentryTests/SentryOptionsTest.m | 190 --- .../Transaction/SentrySpanTests.swift | 18 - 27 files changed, 230 insertions(+), 2217 deletions(-) diff --git a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift index a17b884035f..1b241a3acbd 100644 --- a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift +++ b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKOverrides.swift @@ -159,10 +159,6 @@ public enum SentrySDKOverrides: String, CaseIterable { case tracing = "Tracing" public enum Profiling: String, SentrySDKOverride { - #if !SDK_V9 - case sampleRate = "--io.sentry.profiling.profilesSampleRate" - case samplerValue = "--io.sentry.profiling.profilesSamplerValue" - #endif // !SDK_V9 case disableAppStartProfiling = "--io.sentry.profiling.disable-app-start-profiling" case manualLifecycle = "--io.sentry.profiling.profile-lifecycle-manual" case sessionSampleRate = "--io.sentry.profiling.profile-session-sample-rate" @@ -266,11 +262,7 @@ private extension SentrySDKOverride { extension SentrySDKOverrides.Profiling { public var overrideType: OverrideType { switch self { - #if SDK_V9 case .sessionSampleRate: return .float - #else - case .sampleRate, .samplerValue, .sessionSampleRate: return .float - #endif // !SDK_V9 case .disableAppStartProfiling, .manualLifecycle, .disableUIProfiling, .slowLoadMethod, .immediateStop: return .boolean } } @@ -363,11 +355,7 @@ extension SentrySDKOverrides.Special { extension SentrySDKOverrides.Profiling { public var ignoresDisableEverything: Bool { switch self { - #if SDK_V9 case .sessionSampleRate, .manualLifecycle, .slowLoadMethod, .immediateStop: return true - #else - case .sampleRate, .samplerValue, .sessionSampleRate, .manualLifecycle, .slowLoadMethod, .immediateStop: return true - #endif // SDK_V9 case .disableAppStartProfiling, .disableUIProfiling: return false } } diff --git a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift index 3885eb6c9dc..86bd929f51a 100644 --- a/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift +++ b/Samples/SentrySampleShared/SentrySampleShared/SentrySDKWrapper.swift @@ -348,3 +348,136 @@ extension SentrySDKWrapper { config.onSubmitSuccess = { info in let name = info["name"] ?? "$shakespearean_insult_name" let alert = UIAlertController(title: "Thanks?", message: "We have enough jank of our own, we really didn't need yours too, \(name).", preferredStyle: .alert) + alert.addAction(.init(title: "Deal with it 🕶️", style: .default)) + UIApplication.shared.delegate?.window??.rootViewController?.present(alert, animated: true) + + // if there's a screenshot's Data in this dictionary, JSONSerialization crashes _even though_ there's a `try?`, so we'll write the base64 encoding of it + var infoToWriteToFile = info + if let attachments = info["attachments"] as? [Any], let screenshot = attachments.first as? Data { + infoToWriteToFile["attachments"] = [screenshot.base64EncodedString()] + } + + let jsonData = (try? JSONSerialization.data(withJSONObject: infoToWriteToFile, options: .sortedKeys)) ?? Data() + updateHookMarkers(forEvent: "onSubmitSuccess", with: jsonData.base64EncodedString()) + } + config.onSubmitError = { error in + let alert = UIAlertController(title: "D'oh", message: "You tried to report jank, and encountered more jank. The jank has you now: \(error).", preferredStyle: .alert) + alert.addAction(.init(title: "Derp", style: .default)) + UIApplication.shared.delegate?.window??.rootViewController?.present(alert, animated: true) + let nserror = error as NSError + let missingFieldsSorted = (nserror.userInfo["missing_fields"] as? [String])?.sorted().joined(separator: ";") ?? "" + updateHookMarkers(forEvent: "onSubmitError", with: "\(nserror.domain);\(nserror.code);\(nserror.localizedDescription);\(missingFieldsSorted)") + } + } + + func updateHookMarkers(forEvent name: String, with contents: String? = nil) { + guard let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).first else { + print("[iOS-Swift] Couldn't retrieve path to application support directory.") + return + } + + let fm = FileManager.default + let dir = "\(appSupportDirectory)/io.sentry/feedback" + let isDirectory = UnsafeMutablePointer.allocate(capacity: 1) + isDirectory.initialize(to: ObjCBool(false)) + let exists = fm.fileExists(atPath: dir, isDirectory: isDirectory) + if exists, !isDirectory.pointee.boolValue { + print("[iOS-Swift] Found a file named \(dir) which is not a directory. Removing it...") + do { + try fm.removeItem(atPath: dir) + } catch { + print("[iOS-Swift] Couldn't remove existing file \(dir): \(error).") + return + } + } else if !exists { + do { + try fm.createDirectory(atPath: dir, withIntermediateDirectories: true) + } catch { + print("[iOS-Swift] Couldn't create directory structure for user feedback form hook marker files: \(error).") + return + } + } + + createHookFile(path: "\(dir)/\(name)", contents: contents) + + switch name { + case "onFormOpen": removeHookFile(path: "\(dir)/onFormClose") + case "onFormClose": removeHookFile(path: "\(dir)/onFormOpen") + case "onSubmitSuccess": removeHookFile(path: "\(dir)/onSubmitError") + case "onSubmitError": removeHookFile(path: "\(dir)/onSubmitSuccess") + default: fatalError("Unexpected marker file name") + } + } + + func createHookFile(path: String, contents: String?) { + if let contents = contents { + do { + try contents.write(to: URL(fileURLWithPath: path), atomically: false, encoding: .utf8) + } catch { + print("[iOS-Swift] Couldn't write contents into user feedback form hook marker file at \(path).") + } + } else if !FileManager.default.createFile(atPath: path, contents: nil) { + print("[iOS-Swift] Couldn't create user feedback form hook marker file at \(path).") + } else { + print("[iOS-Swift] Created user feedback form hook marker file at \(path).") + } + } + + func removeHookFile(path: String) { + let fm = FileManager.default + guard fm.fileExists(atPath: path) else { return } + do { + try fm.removeItem(atPath: path) + } catch { + print("[iOS-Swift] Couldn't remove user feedback form hook marker file \(path): \(error).") + } + } +} +#endif // !os(macOS) && !os(tvOS) && !os(watchOS) && !os(visionOS) + +// MARK: Convenience access to SDK configuration via launch arg / environment variable +extension SentrySDKWrapper { + public static let defaultDSN = "https://6cc9bae94def43cab8444a99e0031c28@o447951.ingest.sentry.io/5428557" + + var args: [String] { + return ProcessInfo.processInfo.arguments + } + + var env: [String: String] { + return ProcessInfo.processInfo.environment + } + + /// For testing purposes, we want to be able to change the DSN and store it to disk. In a real app, you shouldn't need this behavior. + var dsn: String? { + do { + if let dsn = env[SentrySDKOverrides.Special.dsn.rawValue] { + try DSNStorage.shared.saveDSN(dsn: dsn) + } + return try DSNStorage.shared.getDSN() ?? SentrySDKWrapper.defaultDSN + } catch { + print("[iOS-Swift] Error encountered while reading stored DSN: \(error)") + } + return nil + } + + /// Whether or not profiling benchmarks are being run; this requires disabling certain other features for proper functionality. + var isBenchmarking: Bool { args.contains("--io.sentry.test.benchmarking") } + var isUITest: Bool { env[SentrySDKOverrides.Other.environment.rawValue] == "ui-tests" } +} + +// MARK: Profiling configuration +#if !os(tvOS) && !os(watchOS) && !os(visionOS) +extension SentrySDKWrapper { + func configureProfiling(_ options: Options) { + if !SentrySDKOverrides.Profiling.disableUIProfiling.boolValue { + options.configureProfiling = { + $0.lifecycle = SentrySDKOverrides.Profiling.manualLifecycle.boolValue ? .manual : .trace + $0.sessionSampleRate = SentrySDKOverrides.Profiling.sessionSampleRate.floatValue ?? 1 + $0.profileAppStarts = !SentrySDKOverrides.Profiling.disableAppStartProfiling.boolValue + } + } + } +} +#endif // !os(tvOS) && !os(watchOS) && !os(visionOS) + +// swiftlint:enable file_length function_body_length diff --git a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m index 5a0f8057a26..c6d1ea03e5b 100644 --- a/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m +++ b/Samples/iOS-ObjectiveC/iOS-ObjectiveC/AppDelegate.m @@ -51,27 +51,6 @@ - (BOOL)application:(UIApplication *)application }; } -#if !SDK_V9 - if (env[@"--io.sentry.profiling.profilesSampleRate"] != nil) { -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - options.profilesSampleRate = - @([env[@"--io.sentry.profiling.profilesSampleRate"] floatValue]); -# pragma clang diagnostic pop - } - - if (env[@"--io.sentry.profilesSamplerValue"] != nil) { -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - options.profilesSampler - = ^NSNumber *_Nullable(SentrySamplingContext *_Nonnull samplingContext) - { - return @([env[@"--io.sentry.profilesSamplerValue"] floatValue]); - }; -# pragma clang diagnostic pop - } -#endif // !SDK_V9 - SentryHttpStatusCodeRange *httpStatusCodeRange = [[SentryHttpStatusCodeRange alloc] initWithMin:400 max:599]; options.failedRequestStatusCodes = @[ httpStatusCodeRange ]; diff --git a/Samples/iOS-Swift/iOS-Swift/Profiling/ProfilingViewController.swift b/Samples/iOS-Swift/iOS-Swift/Profiling/ProfilingViewController.swift index 443ff30f020..aaa959eb40a 100644 --- a/Samples/iOS-Swift/iOS-Swift/Profiling/ProfilingViewController.swift +++ b/Samples/iOS-Swift/iOS-Swift/Profiling/ProfilingViewController.swift @@ -59,10 +59,6 @@ class ProfilingViewController: UIViewController, UITextFieldDelegate { } @IBAction func sampleRateEdited(_ sender: UITextField) { - #if !SDK_V9 - var sampleRate = SentrySDKOverrides.Profiling.sampleRate - sampleRate.floatValue = getSampleRateOverride(field: sender) - #endif // !SDK_V9 } @IBAction func tracesSampleRateEdited(_ sender: UITextField) { @@ -77,11 +73,6 @@ class ProfilingViewController: UIViewController, UITextFieldDelegate { @IBAction func defineProfilesSampleRateToggled(_ sender: UISwitch) { sampleRateField.isEnabled = sender.isOn - - #if !SDK_V9 - var sampleRate = SentrySDKOverrides.Profiling.sampleRate - sampleRate.floatValue = getSampleRateOverride(field: sampleRateField) - #endif // !SDK_V9 } @IBAction func defineTracesSampleRateToggled(_ sender: UISwitch) { @@ -169,18 +160,6 @@ private extension ProfilingViewController { func optionsConfiguration() { guard let options = SentrySDKInternal.currentHub().getClient()?.options else { return } - #if !SDK_V9 - if let sampleRate = options.profilesSampleRate { - sampleRateField.text = String(format: "%.2f", sampleRate.floatValue) - sampleRateField.isEnabled = true - profilesSampleRateSwitch.isOn = true - } else { - sampleRateField.isEnabled = false - sampleRateField.text = "nil" - profilesSampleRateSwitch.isOn = false - } - #endif // !SDK_V9 - if let sampleRate = options.tracesSampleRate { tracesSampleRateField.text = String(format: "%.2f", sampleRate.floatValue) tracesSampleRateField.isEnabled = true diff --git a/Sources/Sentry/Profiling/SentryLaunchProfiling.m b/Sources/Sentry/Profiling/SentryLaunchProfiling.m index 7732a41ab9e..46075ebed59 100644 --- a/Sources/Sentry/Profiling/SentryLaunchProfiling.m +++ b/Sources/Sentry/Profiling/SentryLaunchProfiling.m @@ -28,9 +28,6 @@ NSString *const kSentryLaunchProfileConfigKeyTracesSampleRand = @"traces.sample_rand"; NSString *const kSentryLaunchProfileConfigKeyProfilesSampleRate = @"profiles"; NSString *const kSentryLaunchProfileConfigKeyProfilesSampleRand = @"profiles.sample_rand"; -# if !SDK_V9 -NSString *const kSentryLaunchProfileConfigKeyContinuousProfiling = @"continuous-profiling"; -# endif // !SDK_V9 NSString *const kSentryLaunchProfileConfigKeyContinuousProfilingV2 = @"continuous-profiling-v2-enabled"; NSString *const kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle @@ -83,15 +80,6 @@ profileOptions:profileOptions]; } -void -_sentry_continuousProfilingV1_startLaunchProfile(BOOL shouldWaitForFullDisplay) -{ - sentry_profileConfiguration = - [[SentryProfileConfiguration alloc] initWaitingForFullDisplay:shouldWaitForFullDisplay - continuousV1:YES]; - [SentryContinuousProfiler start]; -} - /** * Hydrate any relevant launch profiling options persisted from the previous launch and start a * trace that will automatically start a manual lifecycle continuous profile (v2) @@ -269,22 +257,10 @@ BOOL isContinuousV2 = [persistedLaunchConfigOptionsDict[kSentryLaunchProfileConfigKeyContinuousProfilingV2] boolValue]; -# if !SDK_V9 - BOOL isContinuousV1 = - [persistedLaunchConfigOptionsDict[kSentryLaunchProfileConfigKeyContinuousProfiling] - boolValue]; - if (isContinuousV1 && isContinuousV2) { - SENTRY_LOG_WARN(@"Launch profile misconfiguration detected."); - _sentry_cleanUpConfigFile(); - return; - } -# else - BOOL isContinuousV1 = false; -# endif // !SDK_V9 SentrySamplerDecision *decision = _sentry_profileSampleDecision(persistedLaunchConfigOptionsDict); - if (!isContinuousV1 && nil == decision) { + if (nil == decision) { SENTRY_LOG_DEBUG(@"Couldn't hydrate the persisted sample decision."); _sentry_cleanUpConfigFile(); return; @@ -302,13 +278,6 @@ BOOL shouldWaitForFullDisplay = shouldWaitForFullDisplayValue.boolValue; - if (isContinuousV1) { - SENTRY_LOG_DEBUG(@"Starting continuous launch profile v1."); - _sentry_continuousProfilingV1_startLaunchProfile(shouldWaitForFullDisplay); - _sentry_cleanUpConfigFile(); - return; - } - SentryProfileOptions *profileOptions = nil; if (isContinuousV2) { SENTRY_LOG_DEBUG(@"Starting continuous launch profile v2."); @@ -336,8 +305,7 @@ SentryProfileLifecycleTrace, shouldWaitForFullDisplay); } else { sentry_profileConfiguration = - [[SentryProfileConfiguration alloc] initWaitingForFullDisplay:shouldWaitForFullDisplay - continuousV1:NO]; + [[SentryProfileConfiguration alloc] initWaitingForFullDisplay:shouldWaitForFullDisplay]; } // trace lifecycle UI profiling (continuous profiling v2) and trace-based profiling both join @@ -365,43 +333,22 @@ [NSMutableDictionary dictionary]; configDict[kSentryLaunchProfileConfigKeyWaitForFullDisplay] = @(options.enableTimeToFullDisplayTracing); -# if !SDK_V9 - if ([options isContinuousProfilingEnabled]) { -# endif // !SDK_V9 - if ([options isContinuousProfilingV2Enabled]) { - SENTRY_LOG_DEBUG(@"Configuring continuous launch profile v2."); - configDict[kSentryLaunchProfileConfigKeyContinuousProfilingV2] = @YES; - configDict[kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle] = - @(options.profiling.lifecycle); - if (options.profiling.lifecycle == SentryProfileLifecycleTrace) { - configDict[kSentryLaunchProfileConfigKeyTracesSampleRate] - = config.tracesDecision.sampleRate; - configDict[kSentryLaunchProfileConfigKeyTracesSampleRand] - = config.tracesDecision.sampleRand; - } - configDict[kSentryLaunchProfileConfigKeyProfilesSampleRate] - = config.profilesDecision.sampleRate; - configDict[kSentryLaunchProfileConfigKeyProfilesSampleRand] - = config.profilesDecision.sampleRand; - } else { -# if !SDK_V9 - SENTRY_LOG_DEBUG(@"Configuring continuous launch profile."); - configDict[kSentryLaunchProfileConfigKeyContinuousProfiling] = @YES; -# endif // !SDK_V9 + if ([options isContinuousProfilingV2Enabled]) { + SENTRY_LOG_DEBUG(@"Configuring continuous launch profile v2."); + configDict[kSentryLaunchProfileConfigKeyContinuousProfilingV2] = @YES; + configDict[kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle] = + @(options.profiling.lifecycle); + if (options.profiling.lifecycle == SentryProfileLifecycleTrace) { + configDict[kSentryLaunchProfileConfigKeyTracesSampleRate] + = config.tracesDecision.sampleRate; + configDict[kSentryLaunchProfileConfigKeyTracesSampleRand] + = config.tracesDecision.sampleRand; } -# if !SDK_V9 - } else { - SENTRY_LOG_DEBUG(@"Configuring trace launch profile."); - configDict[kSentryLaunchProfileConfigKeyTracesSampleRate] - = config.tracesDecision.sampleRate; - configDict[kSentryLaunchProfileConfigKeyTracesSampleRand] - = config.tracesDecision.sampleRand; configDict[kSentryLaunchProfileConfigKeyProfilesSampleRate] = config.profilesDecision.sampleRate; configDict[kSentryLaunchProfileConfigKeyProfilesSampleRand] = config.profilesDecision.sampleRand; } -# endif // !SDK_V9 writeAppLaunchProfilingConfigFile(configDict); }]; } diff --git a/Sources/Sentry/Profiling/SentryProfileConfiguration.m b/Sources/Sentry/Profiling/SentryProfileConfiguration.m index 096fb26d31b..8f03717df5e 100644 --- a/Sources/Sentry/Profiling/SentryProfileConfiguration.m +++ b/Sources/Sentry/Profiling/SentryProfileConfiguration.m @@ -23,14 +23,12 @@ - (instancetype)initWithProfileOptions:(SentryProfileOptions *)options } - (instancetype)initWaitingForFullDisplay:(BOOL)shouldWaitForFullDisplay - continuousV1:(BOOL)continuousV1 { if (!(self = [super init])) { return nil; } _waitForFullDisplay = shouldWaitForFullDisplay; - _isContinuousV1 = continuousV1; _isProfilingThisLaunch = YES; return self; } @@ -39,7 +37,7 @@ - (instancetype)initContinuousProfilingV2WaitingForFullDisplay:(BOOL)shouldWaitF samplerDecision:(SentrySamplerDecision *)decision profileOptions:(SentryProfileOptions *)options { - if (!(self = [self initWaitingForFullDisplay:shouldWaitForFullDisplay continuousV1:NO])) { + if (!(self = [self initWaitingForFullDisplay:shouldWaitForFullDisplay])) { return nil; } diff --git a/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm b/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm index 0f613bd6dcd..c2aa6f78314 100644 --- a/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm +++ b/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm @@ -176,17 +176,6 @@ sentry_stringFromSentryID(internalTraceId)); _unsafe_cleanUpContinuousProfilerV2(); } else if (internalTraceId != nil) { -# if !SDK_V9 - SentryClient *_Nullable client = hub.getClient; - if (client == nil) { - SENTRY_LOG_ERROR(@"No client found, skipping cleanup."); - return; - } - if (sentry_isContinuousProfilingEnabled(SENTRY_UNWRAP_NULLABLE(SentryClient, client))) { - SENTRY_LOG_ERROR(@"Tracers are not tracked with continuous profiling V1."); - return; - } -# endif // !SDK_V9 if (_gTracersToProfilers == nil) { SENTRY_LOG_ERROR(@"Tracer to profiler should have already been initialized by the " @@ -371,15 +360,8 @@ } BOOL profileShouldBeSampled = configuration.profilesSamplerDecision.decision == kSentrySampleDecisionYes; -# if !SDK_V9 - BOOL isContinuousProfiling = client != nil - && sentry_isContinuousProfilingEnabled(SENTRY_UNWRAP_NULLABLE(SentryClient, client)); - BOOL shouldStartNormalTraceProfile = !isContinuousProfiling && profileShouldBeSampled; -# else - BOOL shouldStartNormalTraceProfile = profileShouldBeSampled; -# endif // !SDK_V9 - - if (sentry_isTracingAppLaunch || shouldStartNormalTraceProfile) { + + if (sentry_isTracingAppLaunch || profileShouldBeSampled) { SentryId *internalID = sentry_getSentryId(); if ([SentryTraceProfiler startWithTracer:internalID]) { SENTRY_LOG_DEBUG(@"Started profiler for trace %@ with internal id %@", diff --git a/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m b/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m index 8d54aa2a911..881238f9231 100644 --- a/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m +++ b/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m @@ -7,14 +7,6 @@ # import "SentrySamplerDecision.h" # import "SentrySwift.h" -# if !SDK_V9 -BOOL -sentry_isContinuousProfilingEnabled(SentryClient *client) -{ - return [client.options isContinuousProfilingEnabled]; -} -# endif // !SDK_V9 - BOOL sentry_isContinuousProfilingV2Enabled(SentryClient *client) { diff --git a/Sources/Sentry/Public/SentryOptions.h b/Sources/Sentry/Public/SentryOptions.h index 05836b4b0d7..1dbfd97ca3d 100644 --- a/Sources/Sentry/Public/SentryOptions.h +++ b/Sources/Sentry/Public/SentryOptions.h @@ -537,68 +537,6 @@ typedef void (^SentryProfilingConfigurationBlock)(SentryProfileOptions *_Nonnull */ @property (nullable, nonatomic, copy) SentryProfilingConfigurationBlock configureProfiling; -# if !SDK_V9 - -/** - * @note Profiling is not supported on watchOS or tvOS. - * Indicates the percentage profiles being sampled out of the sampled transactions. - * @note The value needs to be >= @c 0.0 and \<= @c 1.0. When setting a value out of range - * the SDK sets it to @c 0. When set to a valid nonnull value, this property is dependent on - * @c tracesSampleRate -- if @c tracesSampleRate is @c 0 (default), no profiles will be collected no - * matter what this property is set to. This property is used to undersample profiles *relative to* - * @c tracesSampleRate . - * @note Setting this value to @c nil enables an experimental new profiling mode, called continuous - * profiling. This allows you to start and stop a profiler any time with @c SentrySDK.startProfiler - * and @c SentrySDK.stopProfiler, which can run with no time limit, periodically uploading profiling - * data. You can also set @c SentryOptions.enableAppLaunchProfiling to have the profiler start on - * app launch; there is no automatic stop, you must stop it manually at some later time if you - * choose to do so. Sampling rates do not apply to continuous profiles, including those - * automatically started for app launches. If you wish to sample them, you must do so at the - * callsites where you use the API or configure launch profiling. Continuous profiling is not - * automatically started for performance transactions as was the previous version of profiling. - * @seealso https://docs.sentry.io/platforms/apple/profiling/ for more information about the - * different profiling modes. - * @note The default is @c nil (which implies continuous profiling mode). - * @warning The new continuous profiling mode is experimental and may still contain bugs. - * @note Profiling is automatically disabled if a thread sanitizer is attached. - * @warning This property is deprecated and will be removed in a future version of the SDK. See - * @c SentryProfileOptions.sessionSampleRate. - */ -@property (nullable, nonatomic, strong) NSNumber *profilesSampleRate DEPRECATED_MSG_ATTRIBUTE( - "This property is deprecated and will be removed in a future version of the SDK. See " - "SentryProfileOptions.sessionSampleRate"); - -/** - * @note Profiling is not supported on watchOS or tvOS. - * A callback to a user defined profiles sampler function. This is similar to setting - * @c profilesSampleRate but instead of a static value, the callback function will be called to - * determine the sample rate. - * @note If @c enableAppLaunchProfiling is @c YES , this function will be called during SDK start - * with @c SentrySamplingContext.forNextAppLaunch set to @c YES, and the result will be persisted to - * disk for use on the next app launch. - * @note Profiling is automatically disabled if a thread sanitizer is attached. - * @warning This property is deprecated and will be removed in a future version of the SDK. See - * @c SentryProfileOptions.sessionSampleRate . - */ -@property (nullable, nonatomic) - SentryTracesSamplerCallback profilesSampler NS_SWIFT_SENDABLE DEPRECATED_MSG_ATTRIBUTE( - "This property is deprecated and will be removed in a future version of the SDK. See " - "SentryProfileOptions.sessionSampleRate"); - -/** - * If profiling should be enabled or not. - * @note Profiling is not supported on watchOS or tvOS. - * @note This only returns whether or not trace-based profiling is enabled. If it is not, then - * continuous profiling is effectively enabled, and calling SentrySDK.startProfiler will - * successfully start a continuous profile. - * @returns @c YES if either @c profilesSampleRate > @c 0 and \<= @c 1 , or @c profilesSampler is - * set, otherwise @c NO. - * @note Profiling is automatically disabled if a thread sanitizer is attached. - * @warning This property is deprecated and will be removed in a future version of the SDK. - */ -@property (nonatomic, assign, readonly) BOOL isProfilingEnabled DEPRECATED_MSG_ATTRIBUTE( - "This property is deprecated and will be removed in a future version of the SDK"); -# endif // !SDK_V9 #endif // SENTRY_TARGET_PROFILING_SUPPORTED /** diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 86b9c4a21cf..4cfac2ed8fb 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -117,14 +117,6 @@ - (instancetype)init self.enableNetworkBreadcrumbs = YES; self.enableLogs = NO; self.tracesSampleRate = nil; -#if SENTRY_TARGET_PROFILING_SUPPORTED -# if !SDK_V9 -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - self.profilesSampleRate = SENTRY_INITIAL_PROFILES_SAMPLE_RATE; -# pragma clang diagnostic pop -# endif // !SDK_V9 -#endif // SENTRY_TARGET_PROFILING_SUPPORTED self.enableCoreDataTracing = YES; _enableSwizzling = YES; self.swizzleClassNameExcludes = [NSSet new]; @@ -289,54 +281,15 @@ - (BOOL)isTracingEnabled } #if SENTRY_TARGET_PROFILING_SUPPORTED -# if !SDK_V9 -- (void)setProfilesSampleRate:(NSNumber *)profilesSampleRate -{ - if (profilesSampleRate == nil) { - _profilesSampleRate = nil; - } else if (sentry_isValidSampleRate(profilesSampleRate)) { - _profilesSampleRate = profilesSampleRate; - } else { - _profilesSampleRate = SENTRY_DEFAULT_PROFILES_SAMPLE_RATE; - } -} - -- (BOOL)isProfilingEnabled -{ - return (_profilesSampleRate != nil && [_profilesSampleRate doubleValue] > 0) - || _profilesSampler != nil; -} - -- (BOOL)isContinuousProfilingEnabled -{ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - // this looks a little weird with the `!self.enableProfiling` but that actually is the - // deprecated way to say "enable trace-based profiling", which necessarily disables continuous - // profiling as they are mutually exclusive modes - return _profilesSampleRate == nil && _profilesSampler == nil; -# pragma clang diagnostic pop -} - -# endif // !SDK_V9 - (BOOL)isContinuousProfilingV2Enabled { -# if SDK_V9 return _profiling != nil; -# else - return [self isContinuousProfilingEnabled] && _profiling != nil; -# endif // SDK_V9 } - (BOOL)isProfilingCorrelatedToTraces { -# if SDK_V9 return _profiling != nil && _profiling.lifecycle == SentryProfileLifecycleTrace; -# else - return ![self isContinuousProfilingEnabled] - || (_profiling != nil && _profiling.lifecycle == SentryProfileLifecycleTrace); -# endif // SDK_V9 } #endif // SENTRY_TARGET_PROFILING_SUPPORTED diff --git a/Sources/Sentry/SentryProfiler.mm b/Sources/Sentry/SentryProfiler.mm index 5906fae1e9b..56c2054dee3 100644 --- a/Sources/Sentry/SentryProfiler.mm +++ b/Sources/Sentry/SentryProfiler.mm @@ -55,7 +55,7 @@ SentryProfileOptions *_Nullable nullableOptions = sentry_profileConfiguration.profileOptions; if (nil == nullableOptions) { - return !sentry_profileConfiguration.isContinuousV1; + return YES; } SentryProfileOptions *_Nonnull options = SENTRY_UNWRAP_NULLABLE(SentryProfileOptions, nullableOptions); @@ -66,17 +66,6 @@ void sentry_configureContinuousProfiling(SentryOptions *options) { -# if !SDK_V9 - if (![options isContinuousProfilingEnabled]) { - if (options.configureProfiling != nil) { - SENTRY_LOG_WARN(@"In order to configure SentryProfileOptions you must remove " - @"configuration of the older SentryOptions.profilesSampleRate, " - @"SentryOptions.profilesSampler and/or SentryOptions.enableProfiling"); - } - return; - } -# endif // !SDK_V9 - if (options.configureProfiling == nil) { SENTRY_LOG_DEBUG(@"Continuous profiling V2 configuration not set by SDK consumer, nothing " @"to do here."); @@ -143,7 +132,7 @@ } # endif // SENTRY_HAS_UIKIT - if (configurationFromLaunch.isContinuousV1 || v2LifecycleIsManual) { + if (v2LifecycleIsManual) { SENTRY_LOG_DEBUG(@"Continuous manual launch profiles aren't stopped on calls to " @"SentrySDK.start, " @"not stopping profile."); diff --git a/Sources/Sentry/SentrySDKInternal.m b/Sources/Sentry/SentrySDKInternal.m index 17a0c9095af..2c61fdb5c6c 100644 --- a/Sources/Sentry/SentrySDKInternal.m +++ b/Sources/Sentry/SentrySDKInternal.m @@ -696,18 +696,8 @@ + (void)crash + (void)startProfiler { SentryOptions *options = currentHub.client.options; -# if !SDK_V9 - if (![options isContinuousProfilingEnabled]) { - SENTRY_LOG_WARN( - @"You must disable trace profiling by setting SentryOptions.profilesSampleRate and " - @"SentryOptions.profilesSampler to nil (which is the default initial value for both " - @"properties, so you can also just remove those lines from your configuration " - @"altogether) before attempting to start a continuous profiling session. This behavior " - @"relies on deprecated options and will change in a future version."); -# else if (options == nil) { SENTRY_LOG_WARN(@"Cannot start profiling when options are nil."); -# endif return; } @@ -740,12 +730,6 @@ + (void)stopProfiler // check if we'd be stopping a launch profiler, because then we need to check the hydrated // configuration options, not the current ones if (sentry_profileConfiguration.isProfilingThisLaunch) { - if (sentry_profileConfiguration.isContinuousV1) { - SENTRY_LOG_DEBUG(@"Stopping continuous v1 launch profile."); - [SentryContinuousProfiler stop]; - return; - } - if (sentry_profileConfiguration.profileOptions == nil) { SENTRY_LOG_WARN( @"The current profiler was started on app launch and was configured as a " @@ -767,21 +751,10 @@ + (void)stopProfiler } SentryOptions *options = currentHub.client.options; -# if !SDK_V9 - if (![options isContinuousProfilingEnabled]) { - SENTRY_LOG_WARN( - @"You must disable trace profiling by setting SentryOptions.profilesSampleRate and " - @"SentryOptions.profilesSampler to nil (which is the default initial value for both " - @"properties, so you can also just remove those lines from your configuration " - @"altogether) before attempting to stop a continuous profiling session. This behavior " - @"relies on deprecated options and will change in a future version."); -# else if (options == nil) { SENTRY_LOG_WARN(@"Cannot stop profiling when options are nil."); -# endif return; } - if (options.profiling != nil && options.profiling.lifecycle == SentryProfileLifecycleTrace) { SENTRY_LOG_WARN( @"The profiling lifecycle is set to trace, so you cannot stop profile sessions " diff --git a/Sources/Sentry/SentrySpan.m b/Sources/Sentry/SentrySpan.m index d16e08218c4..3e17450c658 100644 --- a/Sources/Sentry/SentrySpan.m +++ b/Sources/Sentry/SentrySpan.m @@ -91,11 +91,7 @@ - (instancetype)initWithContext:(SentrySpanContext *)context _origin = context.origin; #if SENTRY_TARGET_PROFILING_SUPPORTED -# if !SDK_V9 - _isContinuousProfiling = [SentrySDKInternal.options isContinuousProfilingEnabled]; -# else _isContinuousProfiling = SentrySDKInternal.options != nil; -# endif if (_isContinuousProfiling) { _profileSessionID = SentryContinuousProfiler.currentProfilerID.sentryIdString; if (_profileSessionID == nil) { diff --git a/Sources/Sentry/SentyOptionsInternal.m b/Sources/Sentry/SentyOptionsInternal.m index c19b55ed346..d73d9fac1f6 100644 --- a/Sources/Sentry/SentyOptionsInternal.m +++ b/Sources/Sentry/SentyOptionsInternal.m @@ -348,24 +348,6 @@ + (BOOL)validateOptions:(NSDictionary *)options [self setBool:options[@"enableCoreDataTracing"] block:^(BOOL value) { sentryOptions.enableCoreDataTracing = value; }]; -#if SENTRY_TARGET_PROFILING_SUPPORTED -# if !SDK_V9 - if ([options[@"profilesSampleRate"] isKindOfClass:[NSNumber class]]) { -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - sentryOptions.profilesSampleRate = options[@"profilesSampleRate"]; -# pragma clang diagnostic pop - } - -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - if ([self isBlock:options[@"profilesSampler"]]) { - sentryOptions.profilesSampler = options[@"profilesSampler"]; - } -# pragma clang diagnostic pop -# endif // !SDK_V9 -#endif // SENTRY_TARGET_PROFILING_SUPPORTED - [self setBool:options[@"sendClientReports"] block:^(BOOL value) { sentryOptions.sendClientReports = value; }]; diff --git a/Sources/Sentry/include/SentryLaunchProfiling.h b/Sources/Sentry/include/SentryLaunchProfiling.h index 99b73a173bf..35de6a3d7ff 100644 --- a/Sources/Sentry/include/SentryLaunchProfiling.h +++ b/Sources/Sentry/include/SentryLaunchProfiling.h @@ -18,9 +18,6 @@ SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyTracesSampleRate; SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyTracesSampleRand; SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyProfilesSampleRate; SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyProfilesSampleRand; -# if !SDK_V9 -SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyContinuousProfiling; -# endif // !SDK_V9 SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyContinuousProfilingV2; SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle; SENTRY_EXTERN NSString *const kSentryLaunchProfileConfigKeyWaitForFullDisplay; diff --git a/Sources/Sentry/include/SentryOptions+Private.h b/Sources/Sentry/include/SentryOptions+Private.h index fae56bbbcd1..910690d8339 100644 --- a/Sources/Sentry/include/SentryOptions+Private.h +++ b/Sources/Sentry/include/SentryOptions+Private.h @@ -12,14 +12,6 @@ FOUNDATION_EXPORT NSString *const kSentryDefaultEnvironment; #if SENTRY_TARGET_PROFILING_SUPPORTED @property (nonatomic, assign) BOOL enableProfiling_DEPRECATED_TEST_ONLY; -# if !SDK_V9 -/** - * If continuous profiling mode v1 ("beta") is enabled. - * @note Not for use with launch profiles. See functions in @c SentryLaunchProfiling . - */ -- (BOOL)isContinuousProfilingEnabled; -# endif // !SDK_V9 - /** * If UI profiling mode ("continuous v2") is enabled. * @note Not for use with launch profiles. See functions in @c SentryLaunchProfiling . diff --git a/Sources/Sentry/include/SentryProfileConfiguration.h b/Sources/Sentry/include/SentryProfileConfiguration.h index e2eb75b60ed..102aead6284 100644 --- a/Sources/Sentry/include/SentryProfileConfiguration.h +++ b/Sources/Sentry/include/SentryProfileConfiguration.h @@ -21,7 +21,6 @@ NS_ASSUME_NONNULL_BEGIN SENTRY_NO_INIT -@property (assign, nonatomic, readonly) BOOL isContinuousV1; @property (assign, nonatomic, readonly) BOOL waitForFullDisplay; @property (assign, nonatomic, readonly) BOOL isProfilingThisLaunch; @@ -42,8 +41,7 @@ SENTRY_NO_INIT /** * Initializer for both trace-based and continuous V1 (aka continuous beta) launch profiles. */ -- (instancetype)initWaitingForFullDisplay:(BOOL)shouldWaitForFullDisplay - continuousV1:(BOOL)continuousV1; +- (instancetype)initWaitingForFullDisplay:(BOOL)shouldWaitForFullDisplay; /** Initializer for launch UI profiles (aka continuous V2). */ - (instancetype)initContinuousProfilingV2WaitingForFullDisplay:(BOOL)shouldWaitForFullDisplay diff --git a/Sources/Sentry/include/SentryProfilingSwiftHelpers.h b/Sources/Sentry/include/SentryProfilingSwiftHelpers.h index e5896e492b5..d4a43a52c9b 100644 --- a/Sources/Sentry/include/SentryProfilingSwiftHelpers.h +++ b/Sources/Sentry/include/SentryProfilingSwiftHelpers.h @@ -19,9 +19,6 @@ NS_ASSUME_NONNULL_BEGIN extern "C" { #endif -#if !SDK_V9 -BOOL sentry_isContinuousProfilingEnabled(SentryClient *client); -#endif // !SDK_V9 BOOL sentry_isContinuousProfilingV2Enabled(SentryClient *client); BOOL sentry_isProfilingCorrelatedToTraces(SentryClient *client); SentryProfileOptions *_Nullable sentry_getProfiling(SentryClient *client); diff --git a/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift b/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift index 66cb989df48..3a51d2ebf73 100644 --- a/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift +++ b/Tests/SentryProfilerTests/SentryAppLaunchProfilingTests.swift @@ -23,7 +23,6 @@ extension SentryAppLaunchProfilingTests { func testContinuousLaunchProfileV2TraceLifecycleConfiguration() throws { // Arrange let options = Options() - options.profilesSampleRate = nil options.tracesSampleRate = 1 options.configureProfiling = { $0.lifecycle = .trace @@ -57,7 +56,6 @@ extension SentryAppLaunchProfilingTests { func testContinuousLaunchProfileV2ManualLifecycleConfiguration() throws { // Arrange let options = Options() - options.profilesSampleRate = nil options.configureProfiling = { $0.lifecycle = .manual $0.sessionSampleRate = 1 @@ -95,7 +93,6 @@ extension SentryAppLaunchProfilingTests { func testLaunchContinuousProfileV2TraceLifecycleNotStoppedOnFullyDisplayed() throws { // Arrange fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = nil fixture.options.configureProfiling = { $0.profileAppStarts = true $0.sessionSampleRate = 1 @@ -127,7 +124,6 @@ extension SentryAppLaunchProfilingTests { func testLaunchContinuousProfileV2ManualLifecycleNotStoppedOnFullyDisplayed() throws { // Arrange - fixture.options.profilesSampleRate = nil fixture.options.configureProfiling = { $0.profileAppStarts = true $0.sessionSampleRate = 1 @@ -160,7 +156,6 @@ extension SentryAppLaunchProfilingTests { func testLaunchContinuousProfileV2TraceLifecycleNotStoppedOnInitialDisplayWithoutWaitingForFullDisplay() throws { // Arrange fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = nil fixture.options.configureProfiling = { $0.profileAppStarts = true $0.sessionSampleRate = 1 @@ -191,7 +186,6 @@ extension SentryAppLaunchProfilingTests { func testLaunchContinuousProfileV2ManualLifecycleNotStoppedOnInitialDisplayWithoutWaitingForFullDisplay() throws { // Arrange - fixture.options.profilesSampleRate = nil fixture.options.configureProfiling = { $0.profileAppStarts = true $0.sessionSampleRate = 1 diff --git a/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationChangeTests.swift b/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationChangeTests.swift index cebbfe432e5..7af348c79c7 100644 --- a/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationChangeTests.swift +++ b/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationChangeTests.swift @@ -20,1166 +20,19 @@ final class SentryAppStartProfilingConfigurationChangeTests: XCTestCase { } } -// MARK: configuration changes between launches (no TTFD combinations, see iOS-only tests) -@available(*, deprecated, message: "This is only marked as deprecated because it must still test some deprecated profiling APIs, but the deprecation warnings are converted to errors in our test targets. Once the deprecated API are removed, this can also be removed.") -extension SentryAppStartProfilingConfigurationChangeTests { - func test_lastLaunch_traceBased_currentLaunch_continuousV1() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = nil - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_currentLaunch_continuousV2_traceLifecycle() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .trace - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.tracesSampleRate = 1 - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_currentLaunch_continuousV2_manualLifecycle() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .manual - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV1_currentLaunch_continuousV2_traceLifecycle() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .trace - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.tracesSampleRate = 1 - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV1_currentLaunch_continuousV2_manualLifecycle() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .manual - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV1_currentLaunch_traceBased() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_traceLifecycle_currentLaunch_continuousV1() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate elapsed time to finish UI profile chunk - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_manualLifecycle_currentLaunch_continuousV1() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_traceLifecycle_currentLaunch_traceBased() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate elapsed time to finish UI profile chunk - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_manualLifecycle_currentLaunch_traceBased() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } -} - -#if !os(macOS) -// MARK: configuring launch profiling with TTFD disabled, then launching with it enabled (iOS-only) -@available(*, deprecated, message: "This is only marked as deprecated because it must still test some deprecated profiling APIs, but the deprecation warnings are converted to errors in our test targets. Once the deprecated API are removed, this can also be removed.") -extension SentryAppStartProfilingConfigurationChangeTests { - // MARK: starting with trace-based no TTFD - func test_lastLaunch_traceBased_noTTFD_currentLaunch_continuousV1_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = nil - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_noTTFD_currentLaunch_continuousV2_traceLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .trace - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.tracesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_noTTFD_currentLaunch_continuousV2_manualLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .manual - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_noTTFD_currentLaunch_traceBased_withTTFD() throws { - - } - - // MARK: starting with continuous v1 no TTFD - func test_lastLaunch_continuousV1_noTTFD_currentLaunch_continuousV1_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV1_noTTFD_currentLaunch_continuousV2_traceLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .trace - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.tracesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV1_noTTFD_currentLaunch_continuousV2_manualLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .manual - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV1_noTTFD_currentLaunch_traceBased_withTTFD() throws { - - } - - // MARK: starting with continuous v2 manual lifecycle no TTFD - func test_lastLaunch_continuousV2_manualLifecycle_noTTFD_currentLaunch_continuousV1_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_manualLifecycle_noTTFD_currentLaunch_continuousV2_traceLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .trace - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.tracesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_manualLifecycle_noTTFD_currentLaunch_continuousV2_manualLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .manual - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_manualLifecycle_noTTFD_currentLaunch_traceBased_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - // MARK: starting with continuous v2 trace lifecycle no TTFD - func test_lastLaunch_continuousV2_traceLifecycle_noTTFD_currentLaunch_continuousV1_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate elapsed time to finish UI profile chunk - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_traceLifecycle_noTTFD_currentLaunch_continuousV2_traceLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .trace - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.tracesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate elapsed time to finish UI profile chunk - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_traceLifecycle_noTTFD_currentLaunch_continuousV2_manualLifecycle_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .manual - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate elapsed time to finish UI profile chunk - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV2_traceLifecycle_noTTFD_currentLaunch_traceBased_withTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: false - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate elapsed time to finish UI profile chunk - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } -} - -// MARK: configuring launch profiling with TTFD enabled, then launching with it disabled (iOS-only) -@available(*, deprecated, message: "This is only marked as deprecated because it must still test some deprecated profiling APIs, but the deprecation warnings are converted to errors in our test targets. Once the deprecated API are removed, this can also be removed.") -extension SentryAppStartProfilingConfigurationChangeTests { - // MARK: starting with trace-based with TTFD - func test_lastLaunch_traceBased_withTTFD_currentLaunch_continuousV1_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration (continuous V1) - fixture.options.profilesSampleRate = nil // Enables continuous profiling V1 - fixture.options.enableTimeToFullDisplayTracing = true - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started (trace-based from launch config) - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler not stopped initially (waiting for TTFD due to launch config) - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate TTFD using launch tracer (not a new transaction) - // Since the launch profiler is trace-based, we use the existing launch tracer - let appStartMeasurement = fixture.getAppStartMeasurement(type: .cold) - SentrySDKInternal.setAppStartMeasurement(appStartMeasurement) - - // Use the launch tracer for TTFD simulation - let launchTracer = try XCTUnwrap(sentry_launchTracer) - let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) - ttd.start(for: launchTracer) - ttd.reportInitialDisplay() - ttd.reportFullyDisplayed() - fixture.displayLinkWrapper.call() - - // Assert profile stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_withTTFD_currentLaunch_continuousV2_traceLifecycle_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .trace - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.tracesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = false - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler not stopped (waiting for TTFD) - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate TTFD - let appStartMeasurement = fixture.getAppStartMeasurement(type: .cold) - SentrySDKInternal.setAppStartMeasurement(appStartMeasurement) - - // Use the launch tracer for TTFD simulation - let launchTracer = try XCTUnwrap(sentry_launchTracer) - - let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) - ttd.start(for: launchTracer) - ttd.reportInitialDisplay() - ttd.reportFullyDisplayed() - fixture.displayLinkWrapper.call() - - // Assert profile stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_withTTFD_currentLaunch_continuousV2_manualLifecycle_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.configureProfiling = { - $0.lifecycle = .manual - $0.sessionSampleRate = 1 - $0.profileAppStarts = true - } - fixture.options.enableTimeToFullDisplayTracing = false - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler not stopped (waiting for TTFD) - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate TTFD - let appStartMeasurement = fixture.getAppStartMeasurement(type: .cold) - SentrySDKInternal.setAppStartMeasurement(appStartMeasurement) - let launchTracer = try XCTUnwrap(sentry_launchTracer) - let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) - ttd.start(for: launchTracer) - ttd.reportInitialDisplay() - ttd.reportFullyDisplayed() - fixture.displayLinkWrapper.call() - - // Assert profile stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_traceBased_withTTFD_currentLaunch_traceBased_noTTFD() throws { +#if !os(macOS) +// MARK: configuring launch profiling with TTFD disabled, then launching with it enabled (iOS-only) +@available(*, deprecated, message: "This is only marked as deprecated because it must still test some deprecated profiling APIs, but the deprecation warnings are converted to errors in our test targets. Once the deprecated API are removed, this can also be removed.") +extension SentryAppStartProfilingConfigurationChangeTests { + func test_lastLaunch_continuousV2_manualLifecycle_noTTFD_currentLaunch_continuousV2_traceLifecycle_withTTFD() throws { // Arrange // persisted configuration simulating previous launch let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyTracesSampleRate: 1, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, + kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, + kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = false - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Assert profiler not stopped (waiting for TTFD) - XCTAssert(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate TTFD - let appStartMeasurement = fixture.getAppStartMeasurement(type: .cold) - SentrySDKInternal.setAppStartMeasurement(appStartMeasurement) - let launchTracer = try XCTUnwrap(sentry_launchTracer) - let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) - ttd.start(for: launchTracer) - ttd.reportInitialDisplay() - ttd.reportFullyDisplayed() - fixture.displayLinkWrapper.call() - - // Assert profile stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - // MARK: starting with continuous v1 with TTFD - func test_lastLaunch_continuousV1_withTTFD_currentLaunch_continuousV1_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - fixture.options.enableTimeToFullDisplayTracing = false - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler not stopped initially, continuous profiler doesn't wait for TTFD - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func test_lastLaunch_continuousV1_withTTFD_currentLaunch_continuousV2_traceLifecycle_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true + kSentryLaunchProfileConfigKeyWaitForFullDisplay: false ] let configURL = try XCTUnwrap(launchProfileConfigFileURL()) try (configDict as NSDictionary).write(to: configURL) @@ -1191,7 +44,7 @@ extension SentryAppStartProfilingConfigurationChangeTests { $0.profileAppStarts = true } fixture.options.tracesSampleRate = 1 - fixture.options.enableTimeToFullDisplayTracing = false + fixture.options.enableTimeToFullDisplayTracing = true // Act: simulate app launch _sentry_nondeduplicated_startLaunchProfile() @@ -1213,12 +66,15 @@ extension SentryAppStartProfilingConfigurationChangeTests { XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) } - func test_lastLaunch_continuousV1_withTTFD_currentLaunch_continuousV2_manualLifecycle_noTTFD() throws { + func test_lastLaunch_continuousV2_manualLifecycle_noTTFD_currentLaunch_continuousV2_manualLifecycle_withTTFD() throws { // Arrange // persisted configuration simulating previous launch let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true + kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, + kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, + kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, + kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, + kSentryLaunchProfileConfigKeyWaitForFullDisplay: false ] let configURL = try XCTUnwrap(launchProfileConfigFileURL()) try (configDict as NSDictionary).write(to: configURL) @@ -1229,7 +85,7 @@ extension SentryAppStartProfilingConfigurationChangeTests { $0.sessionSampleRate = 1 $0.profileAppStarts = true } - fixture.options.enableTimeToFullDisplayTracing = false + fixture.options.enableTimeToFullDisplayTracing = true // Act: simulate app launch _sentry_nondeduplicated_startLaunchProfile() @@ -1251,32 +107,42 @@ extension SentryAppStartProfilingConfigurationChangeTests { XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) } - func test_lastLaunch_continuousV1_withTTFD_currentLaunch_traceBased() throws { + // MARK: starting with continuous v2 trace lifecycle no TTFD + func test_lastLaunch_continuousV2_traceLifecycle_noTTFD_currentLaunch_continuousV2_traceLifecycle_withTTFD() throws { // Arrange // persisted configuration simulating previous launch let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfiling: true, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true + kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, + kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, + kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, + kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, + kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, + kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, + kSentryLaunchProfileConfigKeyWaitForFullDisplay: false ] let configURL = try XCTUnwrap(launchProfileConfigFileURL()) try (configDict as NSDictionary).write(to: configURL) // new options simulating current launch configuration + fixture.options.configureProfiling = { + $0.lifecycle = .trace + $0.sessionSampleRate = 1 + $0.profileAppStarts = true + } fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 + fixture.options.enableTimeToFullDisplayTracing = true // Act: simulate app launch _sentry_nondeduplicated_startLaunchProfile() // Assert correct type of profile started - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) + XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) // Act: simulate SDK start sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - // Act: simulate stopping the continuous profiler - SentrySDK.stopProfiler() + // Act: simulate elapsed time to finish UI profile chunk fixture.currentDateProvider.advance(by: 60) try fixture.timeoutTimerFactory.check() @@ -1285,23 +151,28 @@ extension SentryAppStartProfilingConfigurationChangeTests { XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) } - // MARK: starting with continuous v2 manual lifecycle with TTFD - func test_lastLaunch_continuousV2_manualLifecycle_withTTFD_currentLaunch_continuousV1_noTTFD() throws { + func test_lastLaunch_continuousV2_traceLifecycle_noTTFD_currentLaunch_continuousV2_manualLifecycle_withTTFD() throws { // Arrange // persisted configuration simulating previous launch let configDict: [String: Any] = [ kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, + kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true + kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, + kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, + kSentryLaunchProfileConfigKeyWaitForFullDisplay: false ] let configURL = try XCTUnwrap(launchProfileConfigFileURL()) try (configDict as NSDictionary).write(to: configURL) // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - fixture.options.enableTimeToFullDisplayTracing = false + fixture.options.configureProfiling = { + $0.lifecycle = .manual + $0.sessionSampleRate = 1 + $0.profileAppStarts = true + } + fixture.options.enableTimeToFullDisplayTracing = true // Act: simulate app launch _sentry_nondeduplicated_startLaunchProfile() @@ -1311,10 +182,9 @@ extension SentryAppStartProfilingConfigurationChangeTests { XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) + sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) // Act: simulate elapsed time to finish UI profile chunk - SentrySDK.stopProfiler() fixture.currentDateProvider.advance(by: 60) try fixture.timeoutTimerFactory.check() @@ -1322,7 +192,12 @@ extension SentryAppStartProfilingConfigurationChangeTests { XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) } +} +// MARK: configuring launch profiling with TTFD enabled, then launching with it disabled (iOS-only) +@available(*, deprecated, message: "This is only marked as deprecated because it must still test some deprecated profiling APIs, but the deprecation warnings are converted to errors in our test targets. Once the deprecated API are removed, this can also be removed.") +extension SentryAppStartProfilingConfigurationChangeTests { + // MARK: starting with continuous v2 manual lifecycle with TTFD func test_lastLaunch_continuousV2_manualLifecycle_withTTFD_currentLaunch_continuousV2_traceLifecycle_noTTFD() throws { // Arrange // persisted configuration simulating previous launch @@ -1406,88 +281,7 @@ extension SentryAppStartProfilingConfigurationChangeTests { XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) } - func test_lastLaunch_continuousV2_manualLifecycle_withTTFD_currentLaunch_traceBased_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.manual.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate elapsed time to finish UI profile chunk - SentrySDK.stopProfiler() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - // MARK: starting with continuous v2 trace lifecycle with TTFD - func test_lastLaunch_continuousV2_traceLifecycle_withTTFD_currentLaunch_continuousV1_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.profilesSampleRate = nil - fixture.options.enableTimeToFullDisplayTracing = false - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate TTFD stoppage - let launchTracer = try XCTUnwrap(sentry_launchTracer) - let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) - ttd.start(for: launchTracer) - ttd.reportInitialDisplay() - ttd.reportFullyDisplayed() - fixture.displayLinkWrapper.call() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - func test_lastLaunch_continuousV2_traceLifecycle_withTTFD_currentLaunch_continuousV2_traceLifecycle_noTTFD() throws { // Arrange // persisted configuration simulating previous launch @@ -1584,50 +378,6 @@ extension SentryAppStartProfilingConfigurationChangeTests { XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) } - - func test_lastLaunch_continuousV2_traceLifecycle_withTTFD_currentLaunch_traceBased_noTTFD() throws { - // Arrange - // persisted configuration simulating previous launch - let configDict: [String: Any] = [ - kSentryLaunchProfileConfigKeyContinuousProfilingV2: true, - kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle: SentryProfileLifecycle.trace.rawValue, - kSentryLaunchProfileConfigKeyProfilesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyProfilesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRate: 0.5, - kSentryLaunchProfileConfigKeyTracesSampleRand: 0.5, - kSentryLaunchProfileConfigKeyWaitForFullDisplay: true - ] - let configURL = try XCTUnwrap(launchProfileConfigFileURL()) - try (configDict as NSDictionary).write(to: configURL) - - // new options simulating current launch configuration - fixture.options.tracesSampleRate = 1 - fixture.options.profilesSampleRate = 1 - - // Act: simulate app launch - _sentry_nondeduplicated_startLaunchProfile() - - // Assert correct type of profile started - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // Act: simulate SDK start - sentry_sdkInitProfilerTasks(fixture.options, TestHub(client: nil, andScope: nil)) - - // Act: simulate TTFD stoppage - let launchTracer = try XCTUnwrap(sentry_launchTracer) - let ttd = SentryTimeToDisplayTracker(name: "UIViewController", waitForFullDisplay: true, dispatchQueueWrapper: fixture.dispatchQueueWrapper) - ttd.start(for: launchTracer) - ttd.reportInitialDisplay() - ttd.reportFullyDisplayed() - fixture.displayLinkWrapper.call() - fixture.currentDateProvider.advance(by: 60) - try fixture.timeoutTimerFactory.check() - - // Assert profiler stopped - XCTAssertFalse(SentryTraceProfiler.isCurrentlyProfiling()) - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } } #endif // !os(macOS) diff --git a/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift b/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift index f95b0363c1c..48eb3b9981b 100644 --- a/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift +++ b/Tests/SentryProfilerTests/SentryAppStartProfilingConfigurationTests.swift @@ -4,16 +4,10 @@ import XCTest #if os(iOS) || os(macOS) || targetEnvironment(macCatalyst) -/// Test how combinations of the following options interact to ultimately decide whether or not to start the profiler on the next app launch. -/// - `enableLaunchProfiling` (v1 of launch profiling; deprecated) -/// -/// Trace sample rates (tracing v2) affect both transaction-based profiling (deprecated) and continuous profiling v2 +/// Trace sample rates (tracing v2) affects continuous profiling v2 /// - `tracesSampleRate` /// -/// If profile sampling rate (deprecated) is set to nil, we're testing continuous profiling v1 if the v2 options aren't configured, or v2 if they are -/// - `profilesSampleRate` -/// -/// The following three options are for continuous profiling v2; all nil means we're testing continuous profiling v1, if any are defined, we're testing v2 +/// The following three options are for continuous profiling v2; if any are defined, we're testing v2 /// - `SentryProfileOptions.lifecycle` /// - `SentryProfileOptions.sessionSampleRate` /// - `SentryProfileOptions.profileAppStarts` @@ -29,7 +23,6 @@ final class SentryAppStartProfilingConfigurationTests: XCTestCase { } } -@available(*, deprecated, message: "This is only marked as deprecated because enableAppLaunchProfiling is marked as deprecated. Once that is removed this can be removed.") extension SentryAppStartProfilingConfigurationTests { func testValidCombinations() { for config in SentryAppStartProfilingConfigurationTests.validConfigurations { @@ -37,24 +30,6 @@ extension SentryAppStartProfilingConfigurationTests { } } - func testInvalidTransactionProfilingConfigurations() { - for config in SentryAppStartProfilingConfigurationTests.invalidTransactionProfilingConfigurations { - performTest(expectedOptions: config, shouldProfileLaunch: false) - } - } - - func testInvalidContinuousProfilingV1Configurations() { - for config in SentryAppStartProfilingConfigurationTests.invalidContinuousProfilingV1Configurations { - performTest(expectedOptions: config, shouldProfileLaunch: false) - } - } - - func testInvalidTransactionProfilingWithV2OptionsConfigurations() { - for config in SentryAppStartProfilingConfigurationTests.invalidTransactionProfilingWithV2OptionsConfigurations { - performTest(expectedOptions: config, shouldProfileLaunch: false) - } - } - func testInvalidContinuousProfilingV2Configurations() { for config in SentryAppStartProfilingConfigurationTests.invalidContinuousProfilingV2Configurations { performTest(expectedOptions: config, shouldProfileLaunch: false) @@ -63,21 +38,10 @@ extension SentryAppStartProfilingConfigurationTests { } private extension SentryAppStartProfilingConfigurationTests { - @available(*, deprecated, message: "This is only marked as deprecated because enableAppLaunchProfiling is marked as deprecated. Once that is removed this can be removed.") private func performTest(expectedOptions: LaunchProfileOptions, shouldProfileLaunch: Bool) { let actualOptions = Options() - if let tracesSampleRate = expectedOptions.tracesSampleRate { - actualOptions.tracesSampleRate = NSNumber(value: tracesSampleRate) - } else { - actualOptions.tracesSampleRate = nil - } - - if let profilesSampleRate = expectedOptions.profilesSampleRate { - actualOptions.profilesSampleRate = NSNumber(value: profilesSampleRate) - } else { - actualOptions.profilesSampleRate = nil - } + actualOptions.tracesSampleRate = expectedOptions.tracesSampleRate.map { NSNumber(value: $0) } if let continuousProfileV2Options = expectedOptions.continuousProfileV2Options { actualOptions.configureProfiling = { $0.lifecycle = continuousProfileV2Options.lifecycle @@ -102,122 +66,39 @@ private extension SentryAppStartProfilingConfigurationTests { // MARK: Configuration combination lists // MARK: - private extension SentryAppStartProfilingConfigurationTests { - static let invalidTransactionProfilingConfigurations = [ - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1) - ] - - static let invalidContinuousProfilingV1Configurations = [ - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil) - ] - - static let invalidTransactionProfilingWithV2OptionsConfigurations = [ - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), - - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), - - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), - - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), - - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), - - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)) - ] - static let invalidContinuousProfilingV2Configurations = [ - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), - - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), - - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)) + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), + + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), + + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 0, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 0, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: false)), + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)) ] static let validConfigurations = [ - // - // configurations with continuous profiling v2 options set that are not short circuited to either transaction profiling or continuous v1 - // - // continuous profiling v2 trace lifecycle configurations - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .trace, sessionSampleRate: 1, profileAppStarts: true)), // continuous profiling v2 manual lifecycle configurations - LaunchProfileOptions(tracesSampleRate: 0, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: 1, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), - LaunchProfileOptions(tracesSampleRate: nil, profilesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)) + LaunchProfileOptions(tracesSampleRate: 0, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: 1, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)), + LaunchProfileOptions(tracesSampleRate: nil, continuousProfileV2Options: .init(lifecycle: .manual, sessionSampleRate: 1, profileAppStarts: true)) ] } @@ -229,9 +110,6 @@ struct LaunchProfileOptions: Equatable { /// to test transaction based profiling and continuous v2 trace lifecycle let tracesSampleRate: Float? - /// nonnil to test transaction profiling, nil to test continuous v1 and v2 - let profilesSampleRate: Float? - struct ContinuousProfileV2Options: Equatable { let lifecycle: SentryProfileOptions.SentryProfileLifecycle let sessionSampleRate: Float @@ -248,7 +126,6 @@ extension LaunchProfileOptions: CustomStringConvertible { var description: String { return "LaunchProfileOptions(\n" + "\ttracesSampleRate: \(String(describing: tracesSampleRate)),\n" - + "\tprofilesSampleRate: \(String(describing: profilesSampleRate)),\n" + "\tcontinuousProfileV2Options: \(String(describing: continuousProfileV2Options))\n" + ")" } diff --git a/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift b/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift index b1c3e40ccb2..3ccf7762248 100644 --- a/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift +++ b/Tests/SentryProfilerTests/SentryContinuousProfilerTests.swift @@ -17,7 +17,6 @@ final class SentryContinuousProfilerTests: XCTestCase { override func setUp() { super.setUp() fixture = SentryProfileTestFixture() - fixture.options.profilesSampleRate = nil } override func tearDown() { @@ -68,16 +67,6 @@ final class SentryContinuousProfilerTests: XCTestCase { try performContinuousProfilingTest(expectedEnvironment: expectedEnvironment) } - func testStartingContinuousProfilerWithSampleRateOne() throws { - fixture.options.profilesSampleRate = 1 - try performContinuousProfilingTest() - } - - func testStartingContinuousProfilerWithZeroSampleRate() throws { - fixture.options.profilesSampleRate = 0 - try performContinuousProfilingTest() - } - #if !os(macOS) func testDoesNotStopFramesTracker_WhenAppHangsV2Enabled() throws { diff --git a/Tests/SentryProfilerTests/SentryProfileTestFixture.swift b/Tests/SentryProfilerTests/SentryProfileTestFixture.swift index 720099cd189..11dc26d4a23 100644 --- a/Tests/SentryProfilerTests/SentryProfileTestFixture.swift +++ b/Tests/SentryProfilerTests/SentryProfileTestFixture.swift @@ -85,7 +85,6 @@ class SentryProfileTestFixture { hub.bindClient(client) SentrySDKInternal.setCurrentHub(hub) - options.profilesSampleRate = 1.0 options.tracesSampleRate = 1.0 dispatchFactory.vendedSourceHandler = { eventHandler in diff --git a/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift b/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift index e0a0af10e72..cb5fcee5146 100644 --- a/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift +++ b/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift @@ -71,156 +71,12 @@ class SentryProfilingPublicAPITests: XCTestCase { } } -// MARK: transaction profiling -@available(*, deprecated, message: "Transaction profiling is deprecated") -extension SentryProfilingPublicAPITests { - func testSentryOptionsReportsProfilingCorrelatedToTraces_NonnilSampleRate() { - // Arrange - let options = Options() - options.profilesSampleRate = 1 - options.profilesSampler = nil - options.configureProfiling = { - $0.lifecycle = .trace - } - - // Act - sentry_configureContinuousProfiling(options) - - // Assert - XCTAssertTrue(options.isProfilingCorrelatedToTraces()) - } - - func testSentryOptionsReportsProfilingCorrelatedToTraces_NonnilSampler() { - // Arrange - let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = { _ in 1 } - options.configureProfiling = { - $0.lifecycle = .trace - } - - // Act - sentry_configureContinuousProfiling(options) - - // Assert - XCTAssertTrue(options.isProfilingCorrelatedToTraces()) - } -} - -// MARK: continuous profiling v1 -@available(*, deprecated, message: "Continuous profiling v1 is deprecated") -extension SentryProfilingPublicAPITests { - func testSentryOptionsReportsContinuousProfilingEnabled() { - // Arrange - let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = nil - - // Act - sentry_configureContinuousProfiling(options) - - // Assert - XCTAssertTrue(options.isContinuousProfilingEnabled()) - } - - func testSentryOptionsReportsContinuousProfilingDisabledWithNonnilSampleRate() { - // Arrange - let options = Options() - options.profilesSampleRate = 1 - options.profilesSampler = nil - - // Act - sentry_configureContinuousProfiling(options) - - // Assert - XCTAssertFalse(options.isContinuousProfilingEnabled()) - } - - func testSentryOptionsReportsContinuousProfilingDisabledWithNonnilSampler() { - // Arrange - let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = { _ in 1 } - - // Act - sentry_configureContinuousProfiling(options) - - // Assert - XCTAssertFalse(options.isContinuousProfilingEnabled()) - } - - func testStartingContinuousProfilerV1WithSampleRateZero() throws { - givenSdkWithHub() - - fixture.options.profilesSampleRate = 0 - XCTAssertEqual(try XCTUnwrap(fixture.options.profilesSampleRate).doubleValue, 0) - - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - SentrySDK.startProfiler() - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func testStartingContinuousProfilerV1WithSampleRateNil() throws { - givenSdkWithHub() - - // nil is the default initial value for profilesSampleRate, so we don't have to explicitly set it on the fixture - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - SentrySDK.startProfiler() - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - // clean up - try stopProfiler() - } - - func testNotStartingContinuousProfilerV1WithSampleRateBlock() throws { - givenSdkWithHub() - - fixture.options.profilesSampler = { _ in 0 } - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - SentrySDK.startProfiler() - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func testNotStartingContinuousProfilerV1WithSampleRateNonZero() throws { - givenSdkWithHub() - - fixture.options.profilesSampleRate = 1 - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - SentrySDK.startProfiler() - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func testStartingAndStoppingContinuousProfilerV1() throws { - givenSdkWithHub() - SentrySDK.startProfiler() - XCTAssert(SentryContinuousProfiler.isCurrentlyProfiling()) - - try stopProfiler() - - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func testStartingContinuousProfilerV1BeforeStartingSDK() { - SentrySDK.startProfiler() - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - - func testStartingContinuousProfilerV1AfterStoppingSDK() { - givenSdkWithHub() - SentrySDK.close() - SentrySDK.startProfiler() - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } -} - // MARK: continuous profiling v2 @available(*, deprecated, message: "This is only deprecated because profilesSampleRate is deprecated. Once that is removed this attribute can be removed.") extension SentryProfilingPublicAPITests { func testSentryOptionsReportsContinuousProfilingV2Enabled() { // Arrange let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = nil options.configureProfiling = { _ in } // Act @@ -230,39 +86,9 @@ extension SentryProfilingPublicAPITests { XCTAssertTrue(options.isContinuousProfilingV2Enabled()) } - func testSentryOptionsReportsContinuousProfilingV2Disabled_NonnilSampleRate() { - // Arrange - let options = Options() - options.profilesSampleRate = 1 - options.profilesSampler = nil - options.configureProfiling = { _ in } - - // Act - sentry_configureContinuousProfiling(options) - - // Assert - XCTAssertFalse(options.isContinuousProfilingV2Enabled()) - } - - func testSentryOptionsReportsContinuousProfilingV2Disabled_NonnilSampler() { - // Arrange - let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = { _ in 1 } - options.configureProfiling = { _ in } - - // Act - sentry_configureContinuousProfiling(options) - - // Assert - XCTAssertFalse(options.isContinuousProfilingV2Enabled()) - } - func testSentryOptionsReportsContinuousProfilingV2Disabled_NilConfiguration() { // Arrange let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = nil options.configureProfiling = nil // Act @@ -275,8 +101,6 @@ extension SentryProfilingPublicAPITests { func testSentryOptionsReportsProfilingCorrelatedToTraces() { // Arrange let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = nil options.configureProfiling = { $0.lifecycle = .trace } @@ -291,8 +115,6 @@ extension SentryProfilingPublicAPITests { func testSentryOptionsReportsProfilingNotCorrelatedToTraces_ManualLifecycle() { // Arrange let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = nil options.configureProfiling = { $0.lifecycle = .manual // this is the default value, but made explicit here for clarity } @@ -307,8 +129,6 @@ extension SentryProfilingPublicAPITests { func testSentryOptionsReportsProfilingNotCorrelatedToTraces_NilConfiguration() { // Arrange let options = Options() - options.profilesSampleRate = nil - options.profilesSampler = nil options.configureProfiling = nil // Act @@ -374,18 +194,6 @@ extension SentryProfilingPublicAPITests { XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) } - func testStartingContinuousProfilerV2WithoutContinuousProfilingEnabledDoesNotStartProfiler() { - // Arrange - fixture.options.profilesSampleRate = 1 - givenSdkWithHub() - - // Act - SentrySDK.startProfiler() - - // Assert - XCTAssertFalse(SentryContinuousProfiler.isCurrentlyProfiling()) - } - func testStartingContinuousProfilerV2WithTraceLifeCycleDoesNotStartProfiler() { // Arrange fixture.options.configureProfiling = { diff --git a/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m b/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m index 4ebc8180af5..3b91b205b14 100644 --- a/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m +++ b/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m @@ -11,15 +11,6 @@ @implementation SentryProfilingSwiftHelpersTests #if SENTRY_TARGET_PROFILING_SUPPORTED -- (void)testIsContinuousProfilingEnabled -{ - SentryOptions *options = [[SentryOptions alloc] init]; - options.dsn = @"https://username:password@app.getsentry.com/12345"; - SentryClient *client = [[SentryClient alloc] initWithOptions:options]; - XCTAssertEqual( - [client.options isContinuousProfilingEnabled], sentry_isContinuousProfilingEnabled(client)); -} - - (void)testIsContinuousProfilingV2Enabled { SentryOptions *options = [[SentryOptions alloc] init]; diff --git a/Tests/SentryTests/SentryOptionsTest.m b/Tests/SentryTests/SentryOptionsTest.m index a3ea1d517d0..870d70696ca 100644 --- a/Tests/SentryTests/SentryOptionsTest.m +++ b/Tests/SentryTests/SentryOptionsTest.m @@ -774,15 +774,6 @@ - (void)assertDefaultValues:(SentryOptions *)options XCTAssertFalse(options.enableTimeToFullDisplayTracing); -#if SENTRY_TARGET_PROFILING_SUPPORTED -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" - XCTAssertNil(options.profilesSampleRate); - XCTAssertNil(options.profilesSampler); -# pragma clang diagnostic pop - XCTAssertTrue([options isContinuousProfilingEnabled]); -#endif // SENTRY_TARGET_PROFILING_SUPPORTED - XCTAssertTrue([options.spotlightUrl isEqualToString:@"http://localhost:8969/stream"]); } @@ -1112,187 +1103,6 @@ - (void)testIsTracingEnabled_TracesSamplerSet_IsEnabled XCTAssertTrue(options.isTracingEnabled); } -#if SENTRY_TARGET_PROFILING_SUPPORTED - -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -- (void)testProfilesSampleRate -{ - SentryOptions *options = [self getValidOptions:@{ @"profilesSampleRate" : @0.1 }]; - XCTAssertEqual(options.profilesSampleRate.doubleValue, 0.1); - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -- (void)testDefaultProfilesSampleRate -{ - SentryOptions *options = [self getValidOptions:@{}]; - XCTAssertNil(options.profilesSampleRate); - - // This property now only refers to trace-based profiling, but renaming it would require a major - // rev - XCTAssertFalse(options.isProfilingEnabled); - - XCTAssertTrue([options isContinuousProfilingEnabled]); -} - -- (void)testProfilesSampleRate_SetToNil -{ - SentryOptions *options = [[SentryOptions alloc] init]; - options.profilesSampleRate = nil; - XCTAssertNil(options.profilesSampleRate); - - // This property now only refers to trace-based profiling, but renaming it would require a major - // rev - XCTAssertFalse(options.isProfilingEnabled); - - XCTAssert([options isContinuousProfilingEnabled]); -} - -- (void)testProfilesSampleRateLowerBound -{ - SentryOptions *options = [[SentryOptions alloc] init]; - options.profilesSampleRate = @0.5; - - NSNumber *lowerBound = @0; - options.profilesSampleRate = lowerBound; - XCTAssertEqual(lowerBound, options.profilesSampleRate); - - options.profilesSampleRate = @0.5; - - NSNumber *tooLow = @-0.01; - options.profilesSampleRate = tooLow; - XCTAssertEqual(options.profilesSampleRate.doubleValue, 0); - - // setting an invalid sample rate effectively now enables continuous profiling, since it can let - // the backing variable remain nil - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -- (void)testProfilesSampleRateUpperBound -{ - SentryOptions *options = [[SentryOptions alloc] init]; - options.profilesSampleRate = @0.5; - - NSNumber *lowerBound = @1; - options.profilesSampleRate = lowerBound; - XCTAssertEqual(lowerBound, options.profilesSampleRate); - - options.profilesSampleRate = @0.5; - - NSNumber *tooLow = @1.01; - options.profilesSampleRate = tooLow; - XCTAssertEqual(options.profilesSampleRate.doubleValue, 0); - - // setting an invalid sample rate effectively now enables continuous profiling, since it can let - // the backing variable remain nil - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -- (void)testIsProfilingEnabled_NothingSet_IsDisabled -{ - SentryOptions *options = [[SentryOptions alloc] init]; - - // This property now only refers to trace-based profiling, but renaming it would require a major - // rev - XCTAssertFalse(options.isProfilingEnabled); - - XCTAssertNil(options.profilesSampleRate); - XCTAssertTrue([options isContinuousProfilingEnabled]); -} - -- (void)testIsProfilingEnabled_ProfilesSampleRateSetToZero_IsDisabled -{ - SentryOptions *options = [[SentryOptions alloc] init]; - options.profilesSampleRate = @0.00; - - // This property now only refers to trace-based profiling, but renaming it would require a major - // rev - XCTAssertFalse(options.isProfilingEnabled); - - XCTAssertNotNil(options.profilesSampleRate); - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -- (void)testIsProfilingEnabled_ProfilesSampleRateSet_IsEnabled -{ - SentryOptions *options = [[SentryOptions alloc] init]; - options.profilesSampleRate = @0.01; - - // This property now only refers to trace-based profiling, but renaming it would require a major - // rev - XCTAssertTrue(options.isProfilingEnabled); - - XCTAssertNotNil(options.profilesSampleRate); - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -- (void)testIsProfilingEnabled_ProfilesSamplerSet_IsEnabled -{ - SentryOptions *options = [[SentryOptions alloc] init]; - options.profilesSampler = ^(SentrySamplingContext *context) { - XCTAssertNotNil(context); - return @0.0; - }; - - // This property now only refers to trace-based profiling, but renaming it would require a major - // rev - XCTAssertTrue(options.isProfilingEnabled); - - XCTAssertNil(options.profilesSampleRate); - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -- (void)testProfilesSampler -{ - SentryTracesSamplerCallback sampler = ^(SentrySamplingContext *context) { - XCTAssertNotNil(context); - return @1.0; - }; - - SentryOptions *options = [self getValidOptions:@{ @"profilesSampler" : sampler }]; - - SentrySamplingContext *context = [[SentrySamplingContext alloc] init]; - XCTAssertEqual(options.profilesSampler(context), @1.0); - XCTAssertNil(options.profilesSampleRate); - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -// this is a tricky part of the API, because while a profilesSampleRate of nil enables continuous -// profiling, just having the profilesSampler set at all disables it, even if the sampler function -// would return nil -- (void)testProfilesSamplerReturnsNil_ContinuousProfilingNotEnabled -{ - SentryTracesSamplerCallback sampler = ^(SentrySamplingContext *context) { - XCTAssertNotNil(context); - NSNumber *result = nil; - return result; - }; - - SentryOptions *options = [self getValidOptions:@{ @"profilesSampler" : sampler }]; - - SentrySamplingContext *context = [[SentrySamplingContext alloc] init]; - XCTAssertNil(options.profilesSampler(context)); - XCTAssertNil(options.profilesSampleRate); - XCTAssertFalse([options isContinuousProfilingEnabled]); -} - -- (void)testDefaultProfilesSampler -{ - SentryOptions *options = [self getValidOptions:@{}]; - XCTAssertNil(options.profilesSampler); - XCTAssertTrue([options isContinuousProfilingEnabled]); -} - -- (void)testGarbageProfilesSampler_ReturnsNil -{ - SentryOptions *options = [self getValidOptions:@{ @"profilesSampler" : @"fault" }]; - XCTAssertNil(options.profilesSampler); - XCTAssertTrue([options isContinuousProfilingEnabled]); -} -# pragma clang diagnostic pop - -#endif // SENTRY_TARGET_PROFILING_SUPPORTED - - (void)testInAppIncludes { NSArray *expected = @[ @"iOS-Swift", @"BusinessLogic" ]; diff --git a/Tests/SentryTests/Transaction/SentrySpanTests.swift b/Tests/SentryTests/Transaction/SentrySpanTests.swift index 99037a9da87..533eca4f80e 100644 --- a/Tests/SentryTests/Transaction/SentrySpanTests.swift +++ b/Tests/SentryTests/Transaction/SentrySpanTests.swift @@ -68,7 +68,6 @@ class SentrySpanTests: XCTestCase { #if os(iOS) || os(macOS) || targetEnvironment(macCatalyst) func testSpanDoesNotSubscribeToNotificationsIfAlreadyCapturedContinuousProfileID() { - fixture.options.profilesSampleRate = nil SentryContinuousProfiler.start() SentrySDKInternal.setStart(with: fixture.options) let _ = fixture.getSut() @@ -78,18 +77,7 @@ class SentrySpanTests: XCTestCase { XCTAssertEqual(continuousProfileObservations.count, 0) } - func testSpanDoesNotSubscribeToNotificationsIfContinuousProfilingDisabled() { - fixture.options.profilesSampleRate = 1 - SentrySDKInternal.setStart(with: fixture.options) - let _ = fixture.getSut() - let continuousProfileObservations = fixture.notificationCenter.addObserverWithObjectInvocations.invocations.filter { - $0.name?.rawValue == kSentryNotificationContinuousProfileStarted - } - XCTAssertEqual(continuousProfileObservations.count, 0) - } - func testSpanDoesSubscribeToNotificationsIfNotAlreadyCapturedContinuousProfileID() { - fixture.options.profilesSampleRate = nil SentrySDKInternal.setStart(with: fixture.options) let _ = fixture.getSut() let continuousProfileObservations = fixture.notificationCenter.addObserverWithObjectInvocations.invocations.filter { @@ -105,7 +93,6 @@ class SentrySpanTests: XCTestCase { /// +----profile----+ /// ``` func test_spanStart_profileStart_spanEnd_profileEnd_spanIncludesProfileID() throws { - fixture.options.profilesSampleRate = nil SentrySDKInternal.setStart(with: fixture.options) let span = fixture.getSut() XCTAssertEqual(fixture.notificationCenter.addObserverWithObjectInvocations.invocations.filter { @@ -127,7 +114,6 @@ class SentrySpanTests: XCTestCase { /// +----profile----+ /// ``` func test_spanStart_profileStart_profileEnd_spanEnd_spanIncludesProfileID() throws { - fixture.options.profilesSampleRate = nil SentrySDKInternal.setStart(with: fixture.options) let span = fixture.getSut() SentryContinuousProfiler.start() @@ -147,7 +133,6 @@ class SentrySpanTests: XCTestCase { /// +-------span-------+ /// ``` func test_profileStart_spanStart_profileEnd_spanEnd_spanIncludesProfileID() throws { - fixture.options.profilesSampleRate = nil SentrySDKInternal.setStart(with: fixture.options) SentryContinuousProfiler.start() let profileId = try XCTUnwrap(SentryContinuousProfiler.profiler()?.profilerId.sentryIdString) @@ -167,7 +152,6 @@ class SentrySpanTests: XCTestCase { /// +-------span-------+ /// ``` func test_profileStart_spanStart_spanEnd_profileEnd_spanIncludesProfileID() throws { - fixture.options.profilesSampleRate = nil SentrySDKInternal.setStart(with: fixture.options) SentryContinuousProfiler.start() let profileId = try XCTUnwrap(SentryContinuousProfiler.profiler()?.profilerId.sentryIdString) @@ -186,7 +170,6 @@ class SentrySpanTests: XCTestCase { /// +--profile1--+ +--profile2--+ /// ``` func test_spanStart_profileStart_profileEnd_profileStart_profileEnd_spanEnd_spanIncludesSameProfileID() throws { - fixture.options.profilesSampleRate = nil SentrySDKInternal.setStart(with: fixture.options) let span = fixture.getSut() SentryContinuousProfiler.start() @@ -209,7 +192,6 @@ class SentrySpanTests: XCTestCase { /// +----profile----+ /// ``` func test_spanStart_spanEnd_profileStart_profileEnd_spanDoesNotIncludeProfileID() { - fixture.options.profilesSampleRate = nil SentrySDKInternal.setStart(with: fixture.options) SentryContinuousProfiler.start() SentryContinuousProfiler.stop() From 4dc3fdb63d1042f96d9629ec2fbcf2936672e00b Mon Sep 17 00:00:00 2001 From: Noah Martin Date: Fri, 24 Oct 2025 12:13:30 -0400 Subject: [PATCH 3/3] PR feedback --- CHANGELOG.md | 1 + Sources/Sentry/Profiling/SentryLaunchProfiling.m | 8 ++++---- .../Sentry/Profiling/SentryProfiledTracerConcurrency.mm | 4 ++-- Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m | 4 ++-- Sources/Sentry/SentryOptions.m | 2 +- Sources/Sentry/include/SentryOptions+Private.h | 2 +- Sources/Sentry/include/SentryProfilingSwiftHelpers.h | 2 +- .../SentryProfilingPublicAPITests.swift | 4 ++-- .../SentryProfilingSwiftHelpersTests.m | 6 +++--- 9 files changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c18f438d70..06e0205f1b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Removes unused SentryLogLevel (#5591) - Removes deprecated `setExtraValue` from SentrySpan (#5864) - Removes deprecated getStoreEndpoint (#5591) +- Remove legacy profiling, the only supported profiling is now what was known as continuous V2 (#6386) - Removes deprecated useSpan function (#5591) - Removes deprecated user feedback API, this is replaced with the new feedback API (#5591) - Removes `enablePerformanceV2` option and makes this the default. The app start duration will now finish when the first frame is drawn instead of when the OS posts the UIWindowDidBecomeVisibleNotification. (#6008) diff --git a/Sources/Sentry/Profiling/SentryLaunchProfiling.m b/Sources/Sentry/Profiling/SentryLaunchProfiling.m index 46075ebed59..ae92688f25e 100644 --- a/Sources/Sentry/Profiling/SentryLaunchProfiling.m +++ b/Sources/Sentry/Profiling/SentryLaunchProfiling.m @@ -150,7 +150,7 @@ } SentryLaunchProfileDecision -sentry_launchShouldHaveContinuousProfilingV2(SentryOptions *options) +sentry_launchShouldHaveContinuousProfiling(SentryOptions *options) { if (!options.profiling.profileAppStarts) { SENTRY_LOG_DEBUG(@"Continuous profiling v2 enabled but disabled app start profiling, " @@ -207,8 +207,8 @@ SentryLaunchProfileDecision sentry_shouldProfileNextLaunch(SentryOptions *options) { - if ([options isContinuousProfilingV2Enabled]) { - return sentry_launchShouldHaveContinuousProfilingV2(options); + if ([options isContinuousProfilingEnabled]) { + return sentry_launchShouldHaveContinuousProfiling(options); } return (SentryLaunchProfileDecision) { NO, nil, nil }; } @@ -333,7 +333,7 @@ [NSMutableDictionary dictionary]; configDict[kSentryLaunchProfileConfigKeyWaitForFullDisplay] = @(options.enableTimeToFullDisplayTracing); - if ([options isContinuousProfilingV2Enabled]) { + if ([options isContinuousProfilingEnabled]) { SENTRY_LOG_DEBUG(@"Configuring continuous launch profile v2."); configDict[kSentryLaunchProfileConfigKeyContinuousProfilingV2] = @YES; configDict[kSentryLaunchProfileConfigKeyContinuousProfilingV2Lifecycle] = diff --git a/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm b/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm index c2aa6f78314..e831ff9cfc6 100644 --- a/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm +++ b/Sources/Sentry/Profiling/SentryProfiledTracerConcurrency.mm @@ -258,7 +258,7 @@ SentryClient *_Nullable client = hub.getClient; if (isProfiling && client != nil - && sentry_isContinuousProfilingV2Enabled(SENTRY_UNWRAP_NULLABLE(SentryClient, client)) + && sentry_isContinuousProfilingEnabled(SENTRY_UNWRAP_NULLABLE(SentryClient, client)) && sentry_isProfilingCorrelatedToTraces(SENTRY_UNWRAP_NULLABLE(SentryClient, client))) { SENTRY_LOG_DEBUG(@"Stopping tracking root span tracer with profilerReferenceId %@", sentry_stringFromSentryID(transaction.trace.profilerReferenceID)); @@ -344,7 +344,7 @@ } SentryClient *_Nullable client = hub.getClient; if (client != nil - && sentry_isContinuousProfilingV2Enabled(SENTRY_UNWRAP_NULLABLE(SentryClient, client))) { + && sentry_isContinuousProfilingEnabled(SENTRY_UNWRAP_NULLABLE(SentryClient, client))) { // non launch profile if (sentry_getParentSpanID(transactionContext) != nil) { SENTRY_LOG_DEBUG(@"Not a root span, will not start automatically for trace lifecycle."); diff --git a/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m b/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m index 881238f9231..1eb7fdfc2ee 100644 --- a/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m +++ b/Sources/Sentry/Profiling/SentryProfilingSwiftHelpers.m @@ -8,9 +8,9 @@ # import "SentrySwift.h" BOOL -sentry_isContinuousProfilingV2Enabled(SentryClient *client) +sentry_isContinuousProfilingEnabled(SentryClient *client) { - return [client.options isContinuousProfilingV2Enabled]; + return [client.options isContinuousProfilingEnabled]; } BOOL diff --git a/Sources/Sentry/SentryOptions.m b/Sources/Sentry/SentryOptions.m index 4cfac2ed8fb..c9519f7d280 100644 --- a/Sources/Sentry/SentryOptions.m +++ b/Sources/Sentry/SentryOptions.m @@ -282,7 +282,7 @@ - (BOOL)isTracingEnabled #if SENTRY_TARGET_PROFILING_SUPPORTED -- (BOOL)isContinuousProfilingV2Enabled +- (BOOL)isContinuousProfilingEnabled { return _profiling != nil; } diff --git a/Sources/Sentry/include/SentryOptions+Private.h b/Sources/Sentry/include/SentryOptions+Private.h index 910690d8339..d9dd3bbd4fa 100644 --- a/Sources/Sentry/include/SentryOptions+Private.h +++ b/Sources/Sentry/include/SentryOptions+Private.h @@ -16,7 +16,7 @@ FOUNDATION_EXPORT NSString *const kSentryDefaultEnvironment; * If UI profiling mode ("continuous v2") is enabled. * @note Not for use with launch profiles. See functions in @c SentryLaunchProfiling . */ -- (BOOL)isContinuousProfilingV2Enabled; +- (BOOL)isContinuousProfilingEnabled; /** * Whether or not the SDK was configured with a profile mode that automatically starts and tracks diff --git a/Sources/Sentry/include/SentryProfilingSwiftHelpers.h b/Sources/Sentry/include/SentryProfilingSwiftHelpers.h index d4a43a52c9b..50e5d5555b0 100644 --- a/Sources/Sentry/include/SentryProfilingSwiftHelpers.h +++ b/Sources/Sentry/include/SentryProfilingSwiftHelpers.h @@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN extern "C" { #endif -BOOL sentry_isContinuousProfilingV2Enabled(SentryClient *client); +BOOL sentry_isContinuousProfilingEnabled(SentryClient *client); BOOL sentry_isProfilingCorrelatedToTraces(SentryClient *client); SentryProfileOptions *_Nullable sentry_getProfiling(SentryClient *client); NSString *sentry_stringFromSentryID(SentryId *sentryID); diff --git a/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift b/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift index cb5fcee5146..39cec65ed36 100644 --- a/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift +++ b/Tests/SentryProfilerTests/SentryProfilingPublicAPITests.swift @@ -83,7 +83,7 @@ extension SentryProfilingPublicAPITests { sentry_configureContinuousProfiling(options) // Assert - XCTAssertTrue(options.isContinuousProfilingV2Enabled()) + XCTAssertTrue(options.isContinuousProfilingEnabled()) } func testSentryOptionsReportsContinuousProfilingV2Disabled_NilConfiguration() { @@ -95,7 +95,7 @@ extension SentryProfilingPublicAPITests { sentry_configureContinuousProfiling(options) // Assert - XCTAssertFalse(options.isContinuousProfilingV2Enabled()) + XCTAssertFalse(options.isContinuousProfilingEnabled()) } func testSentryOptionsReportsProfilingCorrelatedToTraces() { diff --git a/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m b/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m index 3b91b205b14..1a93ecd7704 100644 --- a/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m +++ b/Tests/SentryProfilerTests/SentryProfilingSwiftHelpersTests.m @@ -11,14 +11,14 @@ @implementation SentryProfilingSwiftHelpersTests #if SENTRY_TARGET_PROFILING_SUPPORTED -- (void)testIsContinuousProfilingV2Enabled +- (void)testIsContinuousProfilingEnabled { SentryOptions *options = [[SentryOptions alloc] init]; options.dsn = @"https://username:password@app.getsentry.com/12345"; options.profiling = [[SentryProfileOptions alloc] init]; SentryClient *client = [[SentryClient alloc] initWithOptions:options]; - XCTAssertEqual([client.options isContinuousProfilingV2Enabled], - sentry_isContinuousProfilingV2Enabled(client)); + XCTAssertEqual( + [client.options isContinuousProfilingEnabled], sentry_isContinuousProfilingEnabled(client)); } - (void)testIsProfilingCorrelatedToTraces