From 8a17f5c5fc85d42fc2482ce0e8e98acd04d75cd2 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Wed, 29 Dec 2021 16:37:42 +0100 Subject: [PATCH 1/2] RUMM-1779 Keep view active until all resources are consumed --- Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift | 6 ++++-- .../Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift | 7 ++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift index 7e1decf79a..403478b6bc 100644 --- a/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift +++ b/Sources/Datadog/RUM/RUMMonitor/Scopes/RUMViewScope.swift @@ -345,8 +345,10 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { version += 1 attributes.merge(rumCommandAttributes: command.attributes) - let timeSpent = command.time.timeIntervalSince(viewStartTime) + // RUMM-1779 Keep view active as long as we have ongoing resources + let isActive = isActiveView || !resourceScopes.isEmpty + let timeSpent = command.time.timeIntervalSince(viewStartTime) let cpuInfo = vitalInfoSampler.cpu let memoryInfo = vitalInfoSampler.memory let refreshRateInfo = vitalInfoSampler.refreshRate @@ -384,7 +386,7 @@ internal class RUMViewScope: RUMScope, RUMContextProvider { frozenFrame: .init(count: frozenFramesCount), id: viewUUID.toRUMDataFormat, inForegroundPeriods: nil, - isActive: isActiveView, + isActive: isActive, isSlowRendered: isSlowRendered, largestContentfulPaint: nil, loadEvent: nil, diff --git a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift index 964eaf8da0..ef8441aba7 100644 --- a/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift +++ b/Tests/DatadogTests/Datadog/RUM/RUMMonitor/Scopes/RUMViewScopeTests.swift @@ -416,14 +416,19 @@ class RUMViewScopeTests: XCTestCase { scope.process(command: RUMStopResourceCommand.mockWith(resourceKey: "/resource/1")), "The View should be kept alive as all its Resources haven't yet finished loading" ) + + var event = try XCTUnwrap(output.recordedEvents(ofType: RUMEvent.self).last) + XCTAssertTrue(event.model.view.isActive ?? false, "View should stay active") + XCTAssertFalse( scope.process(command: RUMStopResourceWithErrorCommand.mockWithErrorMessage(resourceKey: "/resource/2")), "The View should stop as all its Resources finished loading" ) - let event = try XCTUnwrap(output.recordedEvents(ofType: RUMEvent.self).last) + event = try XCTUnwrap(output.recordedEvents(ofType: RUMEvent.self).last) XCTAssertEqual(event.model.view.resource.count, 1, "View should record 1 successful Resource") XCTAssertEqual(event.model.view.error.count, 1, "View should record 1 error due to second Resource failure") + XCTAssertFalse(event.model.view.isActive ?? true, "View should be inactive") } // MARK: - User Action Tracking From 92a810575b322b2fef25211fb95a45720c976bb1 Mon Sep 17 00:00:00 2001 From: Maxime Epain Date: Thu, 30 Dec 2021 15:46:19 +0100 Subject: [PATCH 2/2] RUMM-1779 Assert no event is sent after view is inactive --- .../Matchers/RUMSessionMatcher.swift | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift index db6e66280e..0870331a1e 100644 --- a/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift +++ b/Tests/DatadogTests/Matchers/RUMSessionMatcher.swift @@ -213,23 +213,26 @@ internal class RUMSessionMatcher { // Validate ViewVisit's view.isActive for each events try visits.forEach { visit in - var viewWasPreviouslyActive = false + var viewIsInactive = false try visit.viewEvents.enumerated().forEach { index, viewEvent in - let viewIsActive = viewEvent.view.isActive! - if index == 0 { - if !viewIsActive { - throw RUMSessionConsistencyException( - description: "A `RUMSessionMatcher.ViewVisit` can't have a first event with an inactive `View`." - ) - } - } else { - if !viewWasPreviouslyActive && viewIsActive { - throw RUMSessionConsistencyException( - description: "A `RUMSessionMatcher.ViewVisit` can't have an event where a `View` is active after the `View` was marked as inactive." - ) - } + guard let viewIsActive = viewEvent.view.isActive else { + throw RUMSessionConsistencyException( + description: "A `RUMSessionMatcher.ViewVisit` can't have an event without the `isActive` parameter set." + ) + } + + if index == 0 && !viewIsActive { + throw RUMSessionConsistencyException( + description: "A `RUMSessionMatcher.ViewVisit` can't have a first event with an inactive `View`." + ) + } + + if viewIsInactive { + throw RUMSessionConsistencyException( + description: "A `RUMSessionMatcher.ViewVisit` can't have an event after the `View` was marked as inactive." + ) } - viewWasPreviouslyActive = viewIsActive + viewIsInactive = !viewIsActive } }