Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 19 additions & 27 deletions Sources/Sentry/SentrySessionReplayIntegration.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# import "SentryClient+Private.h"
# import "SentryEvent+Private.h"
# import "SentryHub+Private.h"
# import "SentryInternalDefines.h"
# import "SentryLogC.h"
# import "SentryOptions.h"
# import "SentrySDK+Private.h"
Expand Down Expand Up @@ -45,7 +46,6 @@ - (void)newSceneActivate;
@implementation SentrySessionReplayIntegration {
BOOL _startedAsFullSession;
SentryReplayOptions *_replayOptions;
SentryExperimentalOptions *_experimentalOptions;
id<SentryNSNotificationCenterWrapper> _notificationCenter;
id<SentryRateLimits> _rateLimits;
id<SentryViewScreenshotProvider> _currentScreenshotProvider;
Expand All @@ -57,7 +57,6 @@ @implementation SentrySessionReplayIntegration {
// replay absolutely needs segment 0 to make replay work.
BOOL _rateLimited;
id<SentryCurrentDateProvider> _dateProvider;
id<SentrySessionReplayEnvironmentCheckerProvider> _environmentChecker;
}

- (instancetype)init
Expand All @@ -70,39 +69,38 @@ - (instancetype)initForManualUse:(nonnull SentryOptions *)options
{
if (self = [super init]) {
[self setupWith:options.sessionReplay
experimentalOptions:options.experimental
enableTouchTracker:options.enableSwizzling
enableViewRendererV2:options.sessionReplay.enableViewRendererV2
enableFastViewRendering:options.sessionReplay.enableFastViewRendering];
[self startWithOptions:options.sessionReplay
experimentalOptions:options.experimental
fullSession:YES];
[self startWithOptions:options.sessionReplay fullSession:YES];
}
return self;
}

- (BOOL)installWithOptions:(nonnull SentryOptions *)options
{
if ([super installWithOptions:options] == NO) {
if ([super installWithOptions:options] == NO ||
[SentrySessionReplay
shouldEnableSessionReplayWithEnvironmentChecker:SentryDependencies
.sessionReplayEnvironmentChecker
experimentalOptions:options.experimental]
== NO) {
return NO;
}

[self setupWith:options.sessionReplay
experimentalOptions:options.experimental
enableTouchTracker:options.enableSwizzling
enableViewRendererV2:options.sessionReplay.enableViewRendererV2
enableFastViewRendering:options.sessionReplay.enableFastViewRendering];
return YES;
}

- (void)setupWith:(SentryReplayOptions *)replayOptions
experimentalOptions:(SentryExperimentalOptions *)experimentalOptions
enableTouchTracker:(BOOL)touchTracker
enableViewRendererV2:(BOOL)enableViewRendererV2
enableFastViewRendering:(BOOL)enableFastViewRendering
{
_replayOptions = replayOptions;
_experimentalOptions = experimentalOptions;
_rateLimits = SentryDependencyContainer.sharedInstance.rateLimits;
_dateProvider = SentryDependencyContainer.sharedInstance.dateProvider;

Expand Down Expand Up @@ -133,7 +131,6 @@ - (void)setupWith:(SentryReplayOptions *)replayOptions

_notificationCenter = SentryDependencyContainer.sharedInstance.notificationCenterWrapper;
_dateProvider = SentryDependencyContainer.sharedInstance.dateProvider;
_environmentChecker = SentryDependencies.sessionReplayEnvironmentChecker;

// We use the dispatch queue provider as a factory to create the queues, but store the queues
// directly in this instance, so they get deallocated when the integration is deallocated.
Expand Down Expand Up @@ -331,9 +328,7 @@ - (void)runReplayForAvailableWindow
if ([SentryDependencyContainer.sharedInstance.application getWindows].count > 0) {
SENTRY_LOG_DEBUG(@"[Session Replay] Running replay for available window");
// If a window its already available start replay right away
[self startWithOptions:_replayOptions
experimentalOptions:_experimentalOptions
fullSession:_startedAsFullSession];
[self startWithOptions:_replayOptions fullSession:_startedAsFullSession];
} else {
SENTRY_LOG_DEBUG(
@"[Session Replay] Waiting for a scene to be available to started the replay");
Expand All @@ -352,26 +347,21 @@ - (void)newSceneActivate
removeObserver:self
name:UISceneDidActivateNotification
object:nil];
[self startWithOptions:_replayOptions
experimentalOptions:_experimentalOptions
fullSession:_startedAsFullSession];
[self startWithOptions:_replayOptions fullSession:_startedAsFullSession];
}

- (void)startWithOptions:(SentryReplayOptions *)replayOptions
experimentalOptions:(SentryExperimentalOptions *)experimentalOptions
fullSession:(BOOL)shouldReplayFullSession
{
SENTRY_LOG_DEBUG(@"[Session Replay] Starting session");
[self startWithOptions:replayOptions
experimentalOptions:experimentalOptions
screenshotProvider:_currentScreenshotProvider ?: _viewPhotographer
breadcrumbConverter:_currentBreadcrumbConverter
?: [[SentrySRDefaultBreadcrumbConverter alloc] init]
fullSession:shouldReplayFullSession];
}

- (void)startWithOptions:(SentryReplayOptions *)replayOptions
experimentalOptions:(SentryExperimentalOptions *)experimentalOptions
screenshotProvider:(id<SentryViewScreenshotProvider>)screenshotProvider
breadcrumbConverter:(id<SentryReplayBreadcrumbConverter>)breadcrumbConverter
fullSession:(BOOL)shouldReplayFullSession
Expand Down Expand Up @@ -406,16 +396,14 @@ - (void)startWithOptions:(SentryReplayOptions *)replayOptions

SentryDisplayLinkWrapper *displayLinkWrapper = [[SentryDisplayLinkWrapper alloc] init];
self.sessionReplay = [[SentrySessionReplay alloc] initWithReplayOptions:replayOptions
experimentalOptions:experimentalOptions
replayFolderPath:docs
screenshotProvider:screenshotProvider
replayMaker:replayMaker
breadcrumbConverter:breadcrumbConverter
touchTracker:_touchTracker
dateProvider:_dateProvider
delegate:self
displayLinkWrapper:displayLinkWrapper
environmentChecker:_environmentChecker];
displayLinkWrapper:displayLinkWrapper];

[self.sessionReplay
startWithRootView:[SentryDependencyContainer.sharedInstance.application getWindows]
Expand Down Expand Up @@ -447,15 +435,19 @@ - (nullable NSURL *)replayDirectory
return [dir URLByAppendingPathComponent:SENTRY_REPLAY_FOLDER];
}

- (void)saveCurrentSessionInfo:(SentryId *)sessionId
- (void)saveCurrentSessionInfo:(SentryId *_Nullable)sessionId
path:(NSString *)path
options:(SentryReplayOptions *)options
{
SENTRY_LOG_DEBUG(@"[Session Replay] Saving current session info for session: %@ to path: %@",
sessionId, path);
NSDictionary *info =
[[NSDictionary alloc] initWithObjectsAndKeys:sessionId.sentryIdString, @"replayId",
path.lastPathComponent, @"path", @(options.onErrorSampleRate), @"errorSampleRate", nil];
NSMutableDictionary *info = [NSMutableDictionary new];
if (sessionId != nil) {
[info setObject:SENTRY_UNWRAP_NULLABLE(SentryId, sessionId).sentryIdString
forKey:@"replayId"];
}
[info setObject:path.lastPathComponent forKey:@"path"];
[info setObject:@(options.onErrorSampleRate) forKey:@"errorSampleRate"];

NSData *data = [SentrySerializationSwift dataWithJSONObject:info];

Expand Down
2 changes: 1 addition & 1 deletion Sources/Swift/Helper/Dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@objc public static let threadWrapper = SentryThreadWrapper()
@objc public static let processInfoWrapper: SentryProcessInfoSource = ProcessInfo.processInfo
static let infoPlistWrapper: SentryInfoPlistWrapperProvider = SentryInfoPlistWrapper()
@objc public static let sessionReplayEnvironmentChecker: SentrySessionReplayEnvironmentChecker = {
@objc public static var sessionReplayEnvironmentChecker: SentrySessionReplayEnvironmentCheckerProvider = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a let is thread safe. If you need it to override the value for testing I think it's better to pass the dependencies as a parameter to the class you're testing, rather than having it used from here.

Or if that's too hard to refactor just move it to SentryDependencyContainer and use the lock with a lazy var

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only for testing.

Moving this to SentryDependencyContainer won't work on the v8 branch, which also needs this fix

SentrySessionReplayEnvironmentChecker(infoPlistWrapper: Dependencies.infoPlistWrapper)
}()
@objc public static let dispatchQueueWrapper = SentryDispatchQueueWrapper()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,12 @@ import UIKit
private(set) var isSessionPaused = false

private let replayOptions: SentryReplayOptions
private let experimentalOptions: SentryExperimentalOptions
private let replayMaker: SentryReplayVideoMaker
private let displayLink: SentryReplayDisplayLinkWrapper
private let dateProvider: SentryCurrentDateProvider
private let touchTracker: SentryTouchTracker?
private let lock = NSLock()
public var replayTags: [String: Any]?
private let environmentChecker: SentrySessionReplayEnvironmentCheckerProvider

var isRunning: Bool {
displayLink.isRunning()
Expand All @@ -48,19 +46,16 @@ import UIKit

public init(
replayOptions: SentryReplayOptions,
experimentalOptions: SentryExperimentalOptions,
replayFolderPath: URL,
screenshotProvider: SentryViewScreenshotProvider,
replayMaker: SentryReplayVideoMaker,
breadcrumbConverter: SentryReplayBreadcrumbConverter,
touchTracker: SentryTouchTracker?,
dateProvider: SentryCurrentDateProvider,
delegate: SentrySessionReplayDelegate,
displayLinkWrapper: SentryReplayDisplayLinkWrapper,
environmentChecker: SentrySessionReplayEnvironmentCheckerProvider
displayLinkWrapper: SentryReplayDisplayLinkWrapper
) {
self.replayOptions = replayOptions
self.experimentalOptions = experimentalOptions
self.dateProvider = dateProvider
self.delegate = delegate
self.screenshotProvider = screenshotProvider
Expand All @@ -69,28 +64,30 @@ import UIKit
self.replayMaker = replayMaker
self.breadcrumbConverter = breadcrumbConverter
self.touchTracker = touchTracker
self.environmentChecker = environmentChecker
}

deinit { displayLink.invalidate() }

public func start(rootView: UIView, fullSession: Bool) {
SentrySDKLog.debug("[Session Replay] Starting session replay with full session: \(fullSession)")
guard !isRunning else {
SentrySDKLog.debug("[Session Replay] Session replay is already running, not starting again")
return
}


static public func shouldEnableSessionReplay(environmentChecker: SentrySessionReplayEnvironmentCheckerProvider, experimentalOptions: SentryExperimentalOptions) -> Bool {
// Detect if we are running on iOS 26.0 with Liquid Glass and disable session replay.
// This needs to be done until masking for session replay is properly supported, as it can lead
// to PII leaks otherwise.
if !environmentChecker.isReliable() {
guard experimentalOptions.enableSessionReplayInUnreliableEnvironment else {
SentrySDKLog.fatal("[Session Replay] Detected environment potentially causing PII leaks, disabling Session Replay. To override this mechanism, set `options.experimental.enableSessionReplayInUnreliableEnvironment` to `true`")
return
return false
}
SentrySDKLog.warning("[Session Replay] Detected environment potentially causing PII leaks, but `options.experimental.enableSessionReplayInUnreliableEnvironment` is set to `true`, ignoring and enabling Session Replay.")
}
return true
}

public func start(rootView: UIView, fullSession: Bool) {
SentrySDKLog.debug("[Session Replay] Starting session replay with full session: \(fullSession)")
guard !isRunning else {
SentrySDKLog.debug("[Session Replay] Session replay is already running, not starting again")
return
}

displayLink.link(withTarget: self, selector: #selector(newFrame(_:)))
self.rootView = rootView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
}

private func getSut() throws -> SentrySessionReplayIntegration {
return try XCTUnwrap(SentrySDKInternal.currentHub().installedIntegrations().first as? SentrySessionReplayIntegration)

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testRestartReplayWithNewSessionClosePreviousReplay, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testRestartReplayWithNewSession, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testQueuePriorities_processingQueueShouldHaveLowerPriorityThanWorkerQueue, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testPersistScreenshotProviderAndBreadcrumbConverter, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testPauseSessionReplayWithReacheability, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testPauseAndResumeForApplicationStateChange, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testMoveCurrentReplay_whenLastFileExistsWithoutCurrent_shouldBeRemoved, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testMoveCurrentReplay_whenLastFileExistsWithCurrent_shouldBeReplaced, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testMaskViewFromSDK, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 17 Sentry

testInstallWithSwizzlingHasTouchTracker, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testRestartReplayWithNewSessionClosePreviousReplay, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testRestartReplayWithNewSession, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testQueuePriorities_processingQueueShouldHaveLowerPriorityThanWorkerQueue, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testPersistScreenshotProviderAndBreadcrumbConverter, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testPauseSessionReplayWithReacheability, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testPauseAndResumeForApplicationStateChange, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testMoveCurrentReplay_whenLastFileExistsWithoutCurrent_shouldBeRemoved, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testMoveCurrentReplay_whenLastFileExistsWithCurrent_shouldBeReplaced, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testMaskViewFromSDK, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit tvOS 18 Sentry

testInstallWithSwizzlingHasTouchTracker, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testRestartReplayWithNewSessionClosePreviousReplay, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testRestartReplayWithNewSession, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testQueuePriorities_processingQueueShouldHaveLowerPriorityThanWorkerQueue, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testPersistScreenshotProviderAndBreadcrumbConverter, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testPauseSessionReplayWithReacheability, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testPauseAndResumeForApplicationStateChange, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testMoveCurrentReplay_whenLastFileExistsWithoutCurrent_shouldBeRemoved, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testMoveCurrentReplay_whenLastFileExistsWithCurrent_shouldBeReplaced, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testMaskViewFromSDK, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 14 Sentry

testInstallWithSwizzlingHasTouchTracker, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testRestartReplayWithNewSessionClosePreviousReplay, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testRestartReplayWithNewSession, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testQueuePriorities_processingQueueShouldHaveLowerPriorityThanWorkerQueue, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testPersistScreenshotProviderAndBreadcrumbConverter, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testPauseSessionReplayWithReacheability, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testPauseAndResumeForApplicationStateChange, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testMoveCurrentReplay_whenLastFileExistsWithoutCurrent_shouldBeRemoved, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testMoveCurrentReplay_whenLastFileExistsWithCurrent_shouldBeReplaced, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testMaskViewFromSDK, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 17 Sentry

testInstallWithSwizzlingHasTouchTracker, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testRestartReplayWithNewSessionClosePreviousReplay, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testRestartReplayWithNewSession, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testQueuePriorities_processingQueueShouldHaveLowerPriorityThanWorkerQueue, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testPersistScreenshotProviderAndBreadcrumbConverter, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testPauseSessionReplayWithReacheability, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testPauseAndResumeForApplicationStateChange, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testMoveCurrentReplay_whenLastFileExistsWithoutCurrent_shouldBeRemoved, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testMoveCurrentReplay_whenLastFileExistsWithCurrent_shouldBeReplaced, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testMaskViewFromSDK, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit Catalyst 15 Sentry

testInstallWithSwizzlingHasTouchTracker, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testRestartReplayWithNewSessionClosePreviousReplay, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testRestartReplayWithNewSession, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testQueuePriorities_processingQueueShouldHaveLowerPriorityThanWorkerQueue, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testPersistScreenshotProviderAndBreadcrumbConverter, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testPauseSessionReplayWithReacheability, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testPauseAndResumeForApplicationStateChange, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testMoveCurrentReplay_whenLastFileExistsWithoutCurrent_shouldBeRemoved, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testMoveCurrentReplay_whenLastFileExistsWithCurrent_shouldBeReplaced, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testMaskViewFromSDK, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"

Check failure on line 51 in Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift

View workflow job for this annotation

GitHub Actions / Unit iOS 18 Sentry

testInstallWithSwizzlingHasTouchTracker, XCTUnwrap failed: expected non-nil value of type "SentrySessionReplayIntegration"
}

private func startSDK(sessionSampleRate: Float, errorSampleRate: Float, enableSwizzling: Bool = true, noIntegrations: Bool = false, configure: ((Options) -> Void)? = nil) {
Expand Down Expand Up @@ -736,6 +736,57 @@
// -- Assert --
XCTAssertNil(weakSut, "SentrySessionReplayIntegration should be deallocated")
}

func testInstallWithOptions_WithUnsafe_withoutOverrideOptionEnabled_shouldReturnFalse() {
// -- Arrange --
let instance = SentrySessionReplayIntegration()

let options = Options()
options.sessionReplay = SentryReplayOptions(sessionSampleRate: 1.0, onErrorSampleRate: 1.0)
options.experimental.enableSessionReplayInUnreliableEnvironment = false

Dependencies.sessionReplayEnvironmentChecker = TestSessionReplayEnvironmentChecker(mockedIsReliableReturnValue: false)

// -- Act --
let result = instance.install(with: options)

// -- Assert --
XCTAssertFalse(result)
}

func testInstallWithOptions_WithUnsafe_withOverrideOptionEnabled_shouldReturnTrue() {
// -- Arrange --
let instance = SentrySessionReplayIntegration()

let options = Options()
options.sessionReplay = SentryReplayOptions(sessionSampleRate: 1.0, onErrorSampleRate: 1.0)
options.experimental.enableSessionReplayInUnreliableEnvironment = true

Dependencies.sessionReplayEnvironmentChecker = TestSessionReplayEnvironmentChecker(mockedIsReliableReturnValue: false)

// -- Act --
let result = instance.install(with: options)

// -- Assert --
XCTAssertTrue(result)
}

func testInstallWithOptions_WithoutUnsafe_shouldReturnTrue() {
// -- Arrange --
let instance = SentrySessionReplayIntegration()

let options = Options()
options.sessionReplay = SentryReplayOptions(sessionSampleRate: 1.0, onErrorSampleRate: 1.0)
options.experimental.enableSessionReplayInUnreliableEnvironment = false

Dependencies.sessionReplayEnvironmentChecker = TestSessionReplayEnvironmentChecker(mockedIsReliableReturnValue: true)

// -- Act --
let result = instance.install(with: options)

// -- Assert --
XCTAssertTrue(result)
}

private func createLastSessionReplay(writeSessionInfo: Bool = true, errorSampleRate: Double = 1) throws {
let replayFolder = replayFolder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ class SentrySessionReplayTests: XCTestCase {
let rootView = UIView()
let replayMaker = TestReplayMaker()
let cacheFolder = FileManager.default.temporaryDirectory
let environmentChecker = TestSessionReplayEnvironmentChecker(
mockedIsReliableReturnValue: true
)

var breadcrumbs: [Breadcrumb]?
var isFullSession = true
Expand All @@ -94,28 +91,22 @@ class SentrySessionReplayTests: XCTestCase {

override init() {
super.init()

// By default we are testing a reliable environment so all of the functionality is enabled
environmentChecker.mockIsReliableReturnValue(true)
}

func getSut(
options: SentryReplayOptions = .init(sessionSampleRate: 0, onErrorSampleRate: 0),
experimentalOptions: SentryExperimentalOptions = .init(),
touchTracker: SentryTouchTracker? = nil
) -> SentrySessionReplay {
return SentrySessionReplay(
replayOptions: options,
experimentalOptions: experimentalOptions,
replayFolderPath: cacheFolder,
screenshotProvider: screenshotProvider,
replayMaker: replayMaker,
breadcrumbConverter: SentrySRDefaultBreadcrumbConverter(),
touchTracker: touchTracker ?? SentryTouchTracker(dateProvider: dateProvider, scale: 0),
dateProvider: dateProvider,
delegate: self,
displayLinkWrapper: displayLink,
environmentChecker: environmentChecker
displayLinkWrapper: displayLink
)
}

Expand Down Expand Up @@ -566,48 +557,6 @@ class SentrySessionReplayTests: XCTestCase {
XCTAssertEqual(fixture.displayLink.invalidateInvocations.count, 1)
}

func testStart_withUnreliableEnvironment_withoutOverrideOptionEnabled_shouldNotStart() {
// -- Arrange --
let fixture = Fixture()
fixture.environmentChecker.mockIsReliableReturnValue(false)

let options = SentryReplayOptions(sessionSampleRate: 1.0, onErrorSampleRate: 1.0)
let experimentalOptions = SentryExperimentalOptions()
experimentalOptions.enableSessionReplayInUnreliableEnvironment = false

let sut = fixture.getSut(options: options, experimentalOptions: experimentalOptions)

// -- Act --
// Attempt to start session replay
sut.start(rootView: fixture.rootView, fullSession: true)

// -- Assert --
// Verify that session replay did not actually start
// (it should have been blocked by isInUnreliableEnvironment)
XCTAssertFalse(fixture.displayLink.isRunning())
}

func testStart_withUnreliableEnvironment_withOverrideOptionEnabled_shouldStart() {
// -- Arrange --
let fixture = Fixture()
fixture.environmentChecker.mockIsReliableReturnValue(false)

let options = SentryReplayOptions(sessionSampleRate: 1.0, onErrorSampleRate: 1.0)
let experimentalOptions = SentryExperimentalOptions()
experimentalOptions.enableSessionReplayInUnreliableEnvironment = true

let sut = fixture.getSut(options: options, experimentalOptions: experimentalOptions)

// -- Act --
// Attempt to start session replay
sut.start(rootView: fixture.rootView, fullSession: true)

// -- Assert --
// Verify that session replay started despite unreliable environment
// (override option is enabled)
XCTAssertTrue(fixture.displayLink.isRunning(), "Session replay should start when override option is enabled")
}

// MARK: - Helpers

private func assertFullSession(_ sessionReplay: SentrySessionReplay, expected: Bool) {
Expand Down
Loading