Skip to content

Commit

Permalink
Merge pull request #504 from DataDog/mconstantin/rumm-1265/support-ru…
Browse files Browse the repository at this point in the history
…m-background-events

RUMM-1265 Correctly handle RUM events when app in background
  • Loading branch information
mariusc83 authored Jun 2, 2021
2 parents 0cbbd47 + 6e9aaf8 commit 66c0dac
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 3 deletions.
20 changes: 19 additions & 1 deletion Sources/Datadog/RUM/RUMMonitor/Scopes/RUMSessionScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider {
switch command {
case let command as RUMStartViewCommand:
startView(on: command)
case is RUMStartResourceCommand, is RUMAddUserActionCommand, is RUMStartUserActionCommand:
handleOrphanStartCommand(command: command)
default:
break
}
Expand Down Expand Up @@ -132,7 +134,23 @@ internal class RUMSessionScope: RUMScope, RUMContextProvider {
)
}

// MARK: - Private
// MARK: - Private
private func handleOrphanStartCommand(command: RUMCommand) {
if viewScopes.isEmpty {
viewScopes.append(
RUMViewScope(
parent: self,
dependencies: dependencies,
identity: RUMViewScope.Constants.backgroundViewURL,
path: RUMViewScope.Constants.backgroundViewURL,
name: RUMViewScope.Constants.backgroundViewName,
attributes: command.attributes,
customTimings: [:],
startTime: command.time
)
)
}
}

private func timedOutOrExpired(currentTime: Date) -> Bool {
let timeElapsedSinceLastInteraction = currentTime.timeIntervalSince(lastInteractionTime)
Expand Down
8 changes: 6 additions & 2 deletions Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
import Foundation

internal class RUMViewScope: RUMScope, RUMContextProvider {
struct Constants {
static let backgroundViewURL = "com/datadog/background/view"
static let backgroundViewName = "Background"
}

// MARK: - Child Scopes

/// Active Resource scopes, keyed by .resourceKey.
Expand All @@ -33,7 +38,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
/// The name of this View, used as the `VIEW NAME` in RUM Explorer.
let viewName: String
/// The start time of this View.
private let viewStartTime: Date
let viewStartTime: Date
/// Date correction to server time.
private let dateCorrection: DateCorrection
/// Tells if this View is the active one.
Expand Down Expand Up @@ -129,7 +134,6 @@ internal class RUMViewScope: RUMScope, RUMContextProvider {
case let command as RUMStopViewCommand where identity.equals(command.identity):
isActiveView = false
needsViewUpdate = true

case let command as RUMAddViewTimingCommand where isActiveView:
customTimings[command.timingName] = command.time.timeIntervalSince(viewStartTime).toInt64Nanoseconds
needsViewUpdate = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import XCTest
@testable import Datadog

class RUMSessionScopeTests: XCTestCase {
// MARK: - Unit Tests

func testDefaultContext() {
let parent: RUMApplicationScope = .mockWith(rumApplicationID: "rum-123")
let scope = RUMSessionScope(parent: parent, dependencies: .mockAny(), samplingRate: 100, startTime: .mockAny())
Expand Down Expand Up @@ -77,6 +79,66 @@ class RUMSessionScopeTests: XCTestCase {
XCTAssertEqual(scope.viewScopes.count, 0)
}

func testWhenNoViewScope_andReceivedStartResourceCommand_itCreatesNewViewScope() {
let parent = RUMContextProviderMock()
let currentTime = Date()

let scope = RUMSessionScope(parent: parent, dependencies: .mockAny(), samplingRate: 100, startTime: Date())

_ = scope.process(command: RUMStartResourceCommand.mockWith(resourceKey: "/resource/1", time: currentTime))

XCTAssertEqual(scope.viewScopes.count,1)
XCTAssertEqual(scope.viewScopes[0].viewStartTime, currentTime)
XCTAssertEqual(scope.viewScopes[0].viewName, RUMViewScope.Constants.backgroundViewName)
XCTAssertEqual(scope.viewScopes[0].viewPath, RUMViewScope.Constants.backgroundViewURL)
}

func testWhenNoViewScope_andReceivedStartActionCommand_itCreatesNewViewScope() {
let parent = RUMContextProviderMock()
let currentTime = Date()

let scope = RUMSessionScope(parent: parent, dependencies: .mockAny(), samplingRate: 100, startTime: Date())

_ = scope.process(command: RUMStartUserActionCommand.mockWith(time: currentTime))

XCTAssertEqual(scope.viewScopes.count,1)
XCTAssertEqual(scope.viewScopes[0].viewStartTime, currentTime)
XCTAssertEqual(scope.viewScopes[0].viewName, RUMViewScope.Constants.backgroundViewName)
XCTAssertEqual(scope.viewScopes[0].viewPath, RUMViewScope.Constants.backgroundViewURL)
}

func testWhenNoViewScope_andReceivedAddUserActionCommand_itCreatesNewViewScope() {
let parent = RUMContextProviderMock()
let currentTime = Date()

let scope = RUMSessionScope(parent: parent, dependencies: .mockAny(), samplingRate: 100, startTime: Date())

_ = scope.process(command: RUMAddUserActionCommand.mockWith(time: currentTime))

XCTAssertEqual(scope.viewScopes.count,1)
XCTAssertEqual(scope.viewScopes[0].viewStartTime, currentTime)
XCTAssertEqual(scope.viewScopes[0].viewName, RUMViewScope.Constants.backgroundViewName)
XCTAssertEqual(scope.viewScopes[0].viewPath, RUMViewScope.Constants.backgroundViewURL)
}

func testWhenActiveViewScope_andReceivingStartCommand_itDoesNotCreateNewViewScope() {
let parent = RUMContextProviderMock()
let currentTime = Date()

let scope = RUMSessionScope(parent: parent, dependencies: .mockAny(), samplingRate: 100, startTime: Date())
_ = scope.process(command: generateRandomNotValidStartCommand())
_ = scope.process(command: RUMAddUserActionCommand.mockWith(time: currentTime))
XCTAssertEqual(scope.viewScopes.count, 1)
}

func testWhenNoActiveViewScope_andReceivingNotValidStartCommand_itDoesNotCreateNewViewScope() {
let parent = RUMContextProviderMock()

let scope = RUMSessionScope(parent: parent, dependencies: .mockAny(), samplingRate: 100, startTime: Date())
_ = scope.process(command: generateRandomNotValidStartCommand())
XCTAssertEqual(scope.viewScopes.count, 0)
}

func testWhenSessionIsSampled_itDoesNotCreateViewScopes() {
let parent = RUMContextProviderMock()

Expand All @@ -88,4 +150,14 @@ class RUMSessionScopeTests: XCTestCase {
)
XCTAssertEqual(scope.viewScopes.count, 0)
}

// MARK: - Private

private func generateRandomValidStartCommand() -> RUMCommand {
return [RUMStartUserActionCommand.mockAny(), RUMStartResourceCommand.mockAny(), RUMAddUserActionCommand.mockAny()].randomElement()!
}

private func generateRandomNotValidStartCommand() -> RUMCommand {
return [RUMStopViewCommand.mockAny(), RUMStopResourceCommand.mockAny(), RUMStopUserActionCommand.mockAny(), RUMAddCurrentViewErrorCommand.mockWithErrorObject()].randomElement()!
}
}

0 comments on commit 66c0dac

Please sign in to comment.