Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixes

- Cleanup SessionReplay when maximum duration reached (#7421)

## 9.4.0

### Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ import UIKit
SentrySDKLog.debug("[Session Replay] Reached maximum duration, pausing session")
reachedMaximumDuration = true
pause()
// Notify the delegate that the session replay has ended so it can clear the session replay id.
delegate?.sessionReplayEnded()
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Foundation
func sessionReplayShouldCaptureReplayForError() -> Bool
func sessionReplayNewSegment(replayEvent: SentryReplayEvent, replayRecording: SentryReplayRecording, videoUrl: URL)
func sessionReplayStarted(replayId: SentryId)
func sessionReplayEnded()
func breadcrumbsForSessionReplay() -> [Breadcrumb]
func currentScreenNameForSessionReplay() -> String?
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,12 @@ public class SentrySessionReplayIntegration: NSObject, SwiftIntegration, SentryS
SentrySDKInternal.currentHub().configureScope { scope in scope.replayId = replayId.sentryIdString }
}

public func sessionReplayEnded() {
SentrySDKLog.debug("[Session Replay] Session replay ended")
stop()
SentrySDKInternal.currentHub().configureScope { scope in scope.replayId = nil }
}

public func breadcrumbsForSessionReplay() -> [Breadcrumb] {
var result: [Breadcrumb] = []
SentrySDKInternal.currentHub().configureScope { scope in result = scope.breadcrumbs() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class SentrySessionReplayIntegrationTests: XCTestCase {

private var uiApplication: TestSentryUIApplication!
private var globalEventProcessor: SentryGlobalEventProcessor!
private var dateProvider: TestCurrentDateProvider!

private class TestCrashWrapper: SentryCrashWrapper {
let traced: Bool
Expand All @@ -35,10 +36,12 @@ class SentrySessionReplayIntegrationTests: XCTestCase {
uiApplication = TestSentryUIApplication()
globalEventProcessor = SentryGlobalEventProcessor()
uiApplication.windows = [UIWindow()]
dateProvider = TestCurrentDateProvider()

SentryDependencyContainer.sharedInstance().applicationOverride = uiApplication
SentryDependencyContainer.sharedInstance().reachability = TestSentryReachability()
SentryDependencyContainer.sharedInstance().globalEventProcessor = globalEventProcessor
SentryDependencyContainer.sharedInstance().dateProvider = dateProvider
}

override func tearDown() {
Expand Down Expand Up @@ -768,6 +771,57 @@ class SentrySessionReplayIntegrationTests: XCTestCase {
XCTAssertNotNil(instance)
}

func testReplayIdAndSessionReplayCleared_whenMaxDurationReached() throws {
// -- Arrange --
startSDK(sessionSampleRate: 1, errorSampleRate: 0)
let sut = try getSut()
let sessionReplay = try XCTUnwrap(sut.sessionReplay)

var replayId: String?
SentrySDKInternal.currentHub().configureScope { scope in
replayId = scope.replayId
}
XCTAssertNotNil(replayId)

// -- Act --
// Advance time past the maximum duration (60 minutes)
Dynamic(sessionReplay).newFrame(nil)
dateProvider.advance(by: 5)
Dynamic(sessionReplay).newFrame(nil)
dateProvider.advance(by: 3_600)
Dynamic(sessionReplay).newFrame(nil)

// -- Assert --
XCTAssertFalse(sessionReplay.isRunning)
SentrySDKInternal.currentHub().configureScope { scope in
replayId = scope.replayId
}
XCTAssertNil(replayId)
XCTAssertNil(sut.sessionReplay)
}

func testReplayIdAndSessionReplayCleared_whenSessionEnds() throws {
// -- Arrange --
startSDK(sessionSampleRate: 1, errorSampleRate: 0)
let sut = try getSut()

var replayId: String?
SentrySDKInternal.currentHub().configureScope { scope in
replayId = scope.replayId
}
XCTAssertNotNil(replayId)

// -- Act --
sut.sessionReplayEnded()

// -- Assert --
SentrySDKInternal.currentHub().configureScope { scope in
replayId = scope.replayId
}
XCTAssertNil(replayId)
XCTAssertNil(sut.sessionReplay)
}

func testInstallWithOptions_WithoutUnsafe_shouldReturnTrue() {
// -- Arrange --
let options = Options()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class SentrySessionReplayTests: XCTestCase {
var lastVideoUrl: URL?
var lastReplayId: SentryId?
var currentScreen: String?
var sessionReplayEndedCalled = false

func getSut(
options: SentryReplayOptions = .init(sessionSampleRate: 0, onErrorSampleRate: 0),
Expand Down Expand Up @@ -119,6 +120,10 @@ class SentrySessionReplayTests: XCTestCase {
func sessionReplayStarted(replayId: SentryId) {
lastReplayId = replayId
}

func sessionReplayEnded() {
sessionReplayEndedCalled = true
}

func breadcrumbsForSessionReplay() -> [Breadcrumb] {
breadcrumbs ?? []
Expand Down Expand Up @@ -256,18 +261,38 @@ class SentrySessionReplayTests: XCTestCase {
}

func testSessionReplayMaximumDuration() {
// -- Arrange --
let fixture = Fixture()
let sut = fixture.getSut(options: SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1))
sut.start(rootView: fixture.rootView, fullSession: true)


// -- Act --
Dynamic(sut).newFrame(nil)
fixture.dateProvider.advance(by: 5)
Dynamic(sut).newFrame(nil)
XCTAssertTrue(fixture.displayLink.isRunning())
fixture.dateProvider.advance(by: 3_600)
Dynamic(sut).newFrame(nil)


// -- Assert --
XCTAssertFalse(fixture.displayLink.isRunning())
XCTAssertTrue(fixture.sessionReplayEndedCalled)
}

func testSessionReplayMaximumDuration_whenNotReached_shouldNotCallEnded() {
// -- Arrange --
let fixture = Fixture()
let sut = fixture.getSut(options: SentryReplayOptions(sessionSampleRate: 1, onErrorSampleRate: 1))
sut.start(rootView: fixture.rootView, fullSession: true)

// -- Act --
Dynamic(sut).newFrame(nil)
fixture.dateProvider.advance(by: 5)
Dynamic(sut).newFrame(nil)

// -- Assert --
XCTAssertTrue(fixture.displayLink.isRunning())
XCTAssertFalse(fixture.sessionReplayEndedCalled)
}

func testSdkInfoIsSet() throws {
Expand Down
1 change: 1 addition & 0 deletions Tests/SentryTests/SentryHubTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,7 @@ private class MockReplayDelegate: NSObject, SentrySessionReplayDelegate {
func sessionReplayShouldCaptureReplayForError() -> Bool { return true }
func sessionReplayNewSegment(replayEvent: SentryReplayEvent, replayRecording: SentryReplayRecording, videoUrl: URL) {}
func sessionReplayStarted(replayId: SentryId) {}
func sessionReplayEnded() {}
func breadcrumbsForSessionReplay() -> [Breadcrumb] { return [] }
func currentScreenNameForSessionReplay() -> String? { return nil }
}
Expand Down
Loading