From 157e6795ddd19438a25479afd599a4f9733d84ae Mon Sep 17 00:00:00 2001 From: Nikita Ogorodnikov Date: Thu, 1 Sep 2022 17:05:51 +0200 Subject: [PATCH] RUMM-2353: Report frustration count on views --- .../rum/internal/domain/RumDataWriter.kt | 19 ++--- .../internal/domain/event/RumEventMapper.kt | 15 ++-- .../rum/internal/domain/scope/RumRawEvent.kt | 1 + .../rum/internal/domain/scope/RumViewScope.kt | 5 +- .../internal/monitor/AdvancedRumMonitor.kt | 4 +- .../rum/internal/monitor/DatadogRumMonitor.kt | 41 ++++++----- .../monitor/{EventType.kt => StorageEvent.kt} | 14 ++-- .../android/rum/assertj/ViewEventAssert.kt | 10 +++ .../rum/internal/domain/RumDataWriterTest.kt | 18 +++-- .../domain/event/RumEventMapperTest.kt | 21 ++++-- .../internal/domain/scope/RumRawEventExt.kt | 2 +- .../internal/domain/scope/RumViewScopeTest.kt | 71 ++++++++++++++++--- .../internal/monitor/DatadogRumMonitorTest.kt | 27 +++---- .../utils/forge/ActionEventForgeryFactory.kt | 9 ++- .../utils/forge/ViewEventForgeryFactory.kt | 3 +- 15 files changed, 180 insertions(+), 80 deletions(-) rename dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/{EventType.kt => StorageEvent.kt} (51%) diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt index a371c68cf2..c5027d323a 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/RumDataWriter.kt @@ -16,7 +16,7 @@ import com.datadog.android.core.internal.utils.sdkLogger import com.datadog.android.log.Logger import com.datadog.android.rum.GlobalRum import com.datadog.android.rum.internal.monitor.AdvancedRumMonitor -import com.datadog.android.rum.internal.monitor.EventType +import com.datadog.android.rum.internal.monitor.StorageEvent import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent @@ -43,18 +43,21 @@ internal class RumDataWriter( override fun onDataWritten(data: Any, rawData: ByteArray) { when (data) { is ViewEvent -> persistViewEvent(rawData) - is ActionEvent -> notifyEventSent(data.view.id, EventType.ACTION) - is ResourceEvent -> notifyEventSent(data.view.id, EventType.RESOURCE) + is ActionEvent -> notifyEventSent( + data.view.id, + StorageEvent.Action(data.action.frustration?.type?.size ?: 0) + ) + is ResourceEvent -> notifyEventSent(data.view.id, StorageEvent.Resource) is ErrorEvent -> { if (data.error.isCrash != true) { - notifyEventSent(data.view.id, EventType.ERROR) + notifyEventSent(data.view.id, StorageEvent.Error) } } is LongTaskEvent -> { if (data.longTask.isFrozenFrame == true) { - notifyEventSent(data.view.id, EventType.FROZEN_FRAME) + notifyEventSent(data.view.id, StorageEvent.FrozenFrame) } else { - notifyEventSent(data.view.id, EventType.LONG_TASK) + notifyEventSent(data.view.id, StorageEvent.LongTask) } } } @@ -77,10 +80,10 @@ internal class RumDataWriter( } } - private fun notifyEventSent(viewId: String, eventType: EventType) { + private fun notifyEventSent(viewId: String, storageEvent: StorageEvent) { val rumMonitor = GlobalRum.get() if (rumMonitor is AdvancedRumMonitor) { - rumMonitor.eventSent(viewId, eventType) + rumMonitor.eventSent(viewId, storageEvent) } } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt index cc892aec6c..b7988c4898 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt @@ -13,7 +13,7 @@ import com.datadog.android.event.EventMapper import com.datadog.android.log.internal.utils.warningWithTelemetry import com.datadog.android.rum.GlobalRum import com.datadog.android.rum.internal.monitor.AdvancedRumMonitor -import com.datadog.android.rum.internal.monitor.EventType +import com.datadog.android.rum.internal.monitor.StorageEvent import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent @@ -98,14 +98,17 @@ internal data class RumEventMapper( private fun notifyEventDropped(event: Any) { val monitor = (GlobalRum.get() as? AdvancedRumMonitor) ?: return when (event) { - is ActionEvent -> monitor.eventDropped(event.view.id, EventType.ACTION) - is ResourceEvent -> monitor.eventDropped(event.view.id, EventType.RESOURCE) - is ErrorEvent -> monitor.eventDropped(event.view.id, EventType.ERROR) + is ActionEvent -> monitor.eventDropped( + event.view.id, + StorageEvent.Action(frustrationCount = event.action.frustration?.type?.size ?: 0) + ) + is ResourceEvent -> monitor.eventDropped(event.view.id, StorageEvent.Resource) + is ErrorEvent -> monitor.eventDropped(event.view.id, StorageEvent.Error) is LongTaskEvent -> { if (event.longTask.isFrozenFrame == true) { - monitor.eventDropped(event.view.id, EventType.FROZEN_FRAME) + monitor.eventDropped(event.view.id, StorageEvent.FrozenFrame) } else { - monitor.eventDropped(event.view.id, EventType.LONG_TASK) + monitor.eventDropped(event.view.id, StorageEvent.LongTask) } } else -> { diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt index d24648e8d1..cf2a0809a9 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEvent.kt @@ -122,6 +122,7 @@ internal sealed class RumRawEvent { internal data class ActionSent( val viewId: String, + val frustrationCount: Int, override val eventTime: Time = Time() ) : RumRawEvent() diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt index 2fa96499a6..a24d47ead8 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScope.kt @@ -83,6 +83,7 @@ internal open class RumViewScope( private var resourceCount: Long = 0 private var actionCount: Long = 0 + private var frustrationCount: Int = 0 private var errorCount: Long = 0 private var crashCount: Long = 0 private var longTaskCount: Long = 0 @@ -490,6 +491,7 @@ internal open class RumViewScope( if (event.viewId == viewId) { pendingActionCount-- actionCount++ + frustrationCount += event.frustrationCount sendViewUpdate(event, writer) } } @@ -585,7 +587,8 @@ internal open class RumViewScope( memoryMax = memoryInfo?.maxValue, refreshRateAverage = refreshRateInfo?.meanValue?.let { it * refreshRateScale }, refreshRateMin = refreshRateInfo?.minValue?.let { it * refreshRateScale }, - isSlowRendered = isSlowRendered + isSlowRendered = isSlowRendered, + frustration = ViewEvent.Frustration(frustrationCount.toLong()) ), usr = ViewEvent.Usr( id = user.id, diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt index af19d24a78..fafab07b2a 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/AdvancedRumMonitor.kt @@ -35,9 +35,9 @@ internal interface AdvancedRumMonitor : RumMonitor { throwable: Throwable ) - fun eventSent(viewId: String, type: EventType) + fun eventSent(viewId: String, event: StorageEvent) - fun eventDropped(viewId: String, type: EventType) + fun eventDropped(viewId: String, event: StorageEvent) fun setDebugListener(listener: RumDebugListener?) diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt index e9bff2317c..0b8a6dd36a 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitor.kt @@ -298,27 +298,32 @@ internal class DatadogRumMonitor( ) } - override fun eventSent(viewId: String, type: EventType) { - when (type) { - EventType.ACTION -> handleEvent(RumRawEvent.ActionSent(viewId)) - EventType.RESOURCE -> handleEvent(RumRawEvent.ResourceSent(viewId)) - EventType.ERROR -> handleEvent(RumRawEvent.ErrorSent(viewId)) - EventType.LONG_TASK -> handleEvent(RumRawEvent.LongTaskSent(viewId, false)) - EventType.FROZEN_FRAME -> handleEvent(RumRawEvent.LongTaskSent(viewId, true)) - EventType.VIEW -> { + override fun eventSent(viewId: String, event: StorageEvent) { + when (event) { + is StorageEvent.Action -> handleEvent( + RumRawEvent.ActionSent( + viewId, + event.frustrationCount + ) + ) + is StorageEvent.Resource -> handleEvent(RumRawEvent.ResourceSent(viewId)) + is StorageEvent.Error -> handleEvent(RumRawEvent.ErrorSent(viewId)) + is StorageEvent.LongTask -> handleEvent(RumRawEvent.LongTaskSent(viewId, false)) + is StorageEvent.FrozenFrame -> handleEvent(RumRawEvent.LongTaskSent(viewId, true)) + is StorageEvent.View -> { // Nothing to do } } } - override fun eventDropped(viewId: String, type: EventType) { - when (type) { - EventType.ACTION -> handleEvent(RumRawEvent.ActionDropped(viewId)) - EventType.RESOURCE -> handleEvent(RumRawEvent.ResourceDropped(viewId)) - EventType.ERROR -> handleEvent(RumRawEvent.ErrorDropped(viewId)) - EventType.LONG_TASK -> handleEvent(RumRawEvent.LongTaskDropped(viewId, false)) - EventType.FROZEN_FRAME -> handleEvent(RumRawEvent.LongTaskDropped(viewId, true)) - EventType.VIEW -> { + override fun eventDropped(viewId: String, event: StorageEvent) { + when (event) { + is StorageEvent.Action -> handleEvent(RumRawEvent.ActionDropped(viewId)) + is StorageEvent.Resource -> handleEvent(RumRawEvent.ResourceDropped(viewId)) + is StorageEvent.Error -> handleEvent(RumRawEvent.ErrorDropped(viewId)) + is StorageEvent.LongTask -> handleEvent(RumRawEvent.LongTaskDropped(viewId, false)) + is StorageEvent.FrozenFrame -> handleEvent(RumRawEvent.LongTaskDropped(viewId, true)) + is StorageEvent.View -> { // Nothing to do } } @@ -333,8 +338,8 @@ internal class DatadogRumMonitor( } override fun sendErrorTelemetryEvent(message: String, throwable: Throwable?) { - var stack: String? = throwable?.loggableStackTrace() - var kind: String? = throwable?.javaClass?.canonicalName ?: throwable?.javaClass?.simpleName + val stack: String? = throwable?.loggableStackTrace() + val kind: String? = throwable?.javaClass?.canonicalName ?: throwable?.javaClass?.simpleName handleEvent(RumRawEvent.SendTelemetry(TelemetryType.ERROR, message, stack, kind)) } diff --git a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/EventType.kt b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/StorageEvent.kt similarity index 51% rename from dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/EventType.kt rename to dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/StorageEvent.kt index 8075a02b26..b238ca321d 100644 --- a/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/EventType.kt +++ b/dd-sdk-android/src/main/kotlin/com/datadog/android/rum/internal/monitor/StorageEvent.kt @@ -6,11 +6,11 @@ package com.datadog.android.rum.internal.monitor -internal enum class EventType { - VIEW, - ACTION, - RESOURCE, - ERROR, - LONG_TASK, - FROZEN_FRAME +internal sealed class StorageEvent { + object View : StorageEvent() + data class Action(val frustrationCount: Int) : StorageEvent() + object Resource : StorageEvent() + object Error : StorageEvent() + object LongTask : StorageEvent() + object FrozenFrame : StorageEvent() } diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt index d237f5eb33..3a57fc8e39 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/assertj/ViewEventAssert.kt @@ -122,6 +122,16 @@ internal class ViewEventAssert(actual: ViewEvent) : return this } + fun hasFrustrationCount(expected: Long?): ViewEventAssert { + assertThat(actual.view.frustration?.count) + .overridingErrorMessage( + "Expected event data to have view.frustration.count $expected " + + "but was ${actual.view.frustration?.count}" + ) + .isEqualTo(expected) + return this + } + fun hasCrashCount(expected: Long?): ViewEventAssert { assertThat(actual.view.crash?.count) .overridingErrorMessage( diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt index 3538c54656..d8f0370767 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt @@ -13,7 +13,7 @@ import com.datadog.android.core.internal.persistence.file.FileHandler import com.datadog.android.core.internal.persistence.file.FileOrchestrator import com.datadog.android.log.Logger import com.datadog.android.log.internal.logger.LogHandler -import com.datadog.android.rum.internal.monitor.EventType +import com.datadog.android.rum.internal.monitor.StorageEvent import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent @@ -165,7 +165,10 @@ internal class RumDataWriterTest { testedWriter.onDataWritten(actionEvent, fakeSerializedData) // Then - verify(rumMonitor.mockInstance).eventSent(actionEvent.view.id, EventType.ACTION) + verify(rumMonitor.mockInstance).eventSent( + actionEvent.view.id, + StorageEvent.Action(frustrationCount = actionEvent.action.frustration?.type?.size ?: 0) + ) verifyZeroInteractions(mockFileHandler) } @@ -188,7 +191,7 @@ internal class RumDataWriterTest { testedWriter.onDataWritten(resourceEvent, fakeSerializedData) // Then - verify(rumMonitor.mockInstance).eventSent(resourceEvent.view.id, EventType.RESOURCE) + verify(rumMonitor.mockInstance).eventSent(resourceEvent.view.id, StorageEvent.Resource) verifyZeroInteractions(mockFileHandler) } @@ -214,7 +217,7 @@ internal class RumDataWriterTest { testedWriter.onDataWritten(errorEvent, fakeSerializedData) // Then - verify(rumMonitor.mockInstance).eventSent(fakeEvent.view.id, EventType.ERROR) + verify(rumMonitor.mockInstance).eventSent(fakeEvent.view.id, StorageEvent.Error) verifyZeroInteractions(mockFileHandler) } @@ -261,7 +264,7 @@ internal class RumDataWriterTest { testedWriter.onDataWritten(longTaskEvent, fakeSerializedData) // Then - verify(rumMonitor.mockInstance).eventSent(longTaskEvent.view.id, EventType.LONG_TASK) + verify(rumMonitor.mockInstance).eventSent(longTaskEvent.view.id, StorageEvent.LongTask) verifyZeroInteractions(mockFileHandler) } @@ -282,7 +285,10 @@ internal class RumDataWriterTest { testedWriter.onDataWritten(frozenFrameEvent, fakeSerializedData) // Then - verify(rumMonitor.mockInstance).eventSent(frozenFrameEvent.view.id, EventType.FROZEN_FRAME) + verify(rumMonitor.mockInstance).eventSent( + frozenFrameEvent.view.id, + StorageEvent.FrozenFrame + ) verifyZeroInteractions(mockFileHandler) } diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt index 1ecbafdc15..291e65ef01 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt @@ -9,7 +9,7 @@ package com.datadog.android.rum.internal.domain.event import android.util.Log import com.datadog.android.event.EventMapper import com.datadog.android.log.internal.utils.WARN_WITH_TELEMETRY_LEVEL -import com.datadog.android.rum.internal.monitor.EventType +import com.datadog.android.rum.internal.monitor.StorageEvent import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ErrorEvent import com.datadog.android.rum.model.LongTaskEvent @@ -436,7 +436,13 @@ internal class RumEventMapperTest { // THEN assertThat(mappedRumEvent).isNull() - verify(rumMonitor.mockInstance).eventDropped(fakeRumEvent.view.id, EventType.ACTION) + verify(rumMonitor.mockInstance) + .eventDropped( + fakeRumEvent.view.id, + StorageEvent.Action( + frustrationCount = fakeRumEvent.action.frustration?.type?.size ?: 0 + ) + ) } @Test @@ -451,7 +457,7 @@ internal class RumEventMapperTest { // THEN assertThat(mappedRumEvent).isNull() - verify(rumMonitor.mockInstance).eventDropped(fakeRumEvent.view.id, EventType.RESOURCE) + verify(rumMonitor.mockInstance).eventDropped(fakeRumEvent.view.id, StorageEvent.Resource) } @Test @@ -469,7 +475,7 @@ internal class RumEventMapperTest { // THEN assertThat(mappedRumEvent).isNull() - verify(rumMonitor.mockInstance).eventDropped(fakeNoCrashEvent.view.id, EventType.ERROR) + verify(rumMonitor.mockInstance).eventDropped(fakeNoCrashEvent.view.id, StorageEvent.Error) } @Test @@ -490,7 +496,7 @@ internal class RumEventMapperTest { // THEN assertThat(mappedRumEvent).isNull() - verify(rumMonitor.mockInstance).eventDropped(longTaskEvent.view.id, EventType.LONG_TASK) + verify(rumMonitor.mockInstance).eventDropped(longTaskEvent.view.id, StorageEvent.LongTask) } @Test @@ -511,7 +517,10 @@ internal class RumEventMapperTest { // THEN assertThat(mappedRumEvent).isNull() - verify(rumMonitor.mockInstance).eventDropped(longTaskEvent.view.id, EventType.FROZEN_FRAME) + verify(rumMonitor.mockInstance).eventDropped( + longTaskEvent.view.id, + StorageEvent.FrozenFrame + ) } companion object { diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEventExt.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEventExt.kt index d2a0ec649a..87b085fdc2 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEventExt.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumRawEventExt.kt @@ -161,7 +161,7 @@ internal fun Forge.silentOrphanEvent(): RumRawEvent { RumRawEvent.ResetSession(), RumRawEvent.KeepAlive(), RumRawEvent.StopView(anAlphabeticalString(), emptyMap()), - RumRawEvent.ActionSent(fakeId), + RumRawEvent.ActionSent(fakeId, aPositiveInt()), RumRawEvent.ErrorSent(fakeId), RumRawEvent.LongTaskSent(fakeId), RumRawEvent.ResourceSent(fakeId), diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt index bbecbf41cb..0e48d31962 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/domain/scope/RumViewScopeTest.kt @@ -68,6 +68,7 @@ import fr.xgouchet.elmyr.annotation.BoolForgery import fr.xgouchet.elmyr.annotation.DoubleForgery import fr.xgouchet.elmyr.annotation.FloatForgery import fr.xgouchet.elmyr.annotation.Forgery +import fr.xgouchet.elmyr.annotation.IntForgery import fr.xgouchet.elmyr.annotation.LongForgery import fr.xgouchet.elmyr.annotation.StringForgery import fr.xgouchet.elmyr.annotation.StringForgeryType @@ -661,6 +662,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -725,6 +727,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -789,6 +792,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -859,6 +863,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -926,6 +931,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -993,6 +999,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1048,6 +1055,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1132,6 +1140,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1198,6 +1207,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1284,6 +1294,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1372,6 +1383,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1439,6 +1451,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1505,6 +1518,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1564,6 +1578,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1666,6 +1681,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1745,6 +1761,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(1) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1801,10 +1818,11 @@ internal class RumViewScopeTest { @Test fun `𝕄 send event 𝕎 handleEvent(ActionSent) on active view`( - @LongForgery(1) pending: Long + @LongForgery(1) pending: Long, + @IntForgery(0) frustrationCount: Int ) { // Given - fakeEvent = RumRawEvent.ActionSent(testedScope.viewId) + fakeEvent = RumRawEvent.ActionSent(testedScope.viewId, frustrationCount) testedScope.pendingActionCount = pending // When @@ -1824,6 +1842,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(1) + hasFrustrationCount(frustrationCount.toLong()) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1861,12 +1880,13 @@ internal class RumViewScopeTest { @Test fun `𝕄 do nothing 𝕎 handleEvent(ActionSent) on active view {unknown viewId}`( @Forgery viewUuid: UUID, - @LongForgery(1) pending: Long + @LongForgery(1) pending: Long, + @IntForgery(0) frustrationCount: Int ) { // Given val viewId = viewUuid.toString() assumeTrue(viewId != testedScope.viewId) - fakeEvent = RumRawEvent.ActionSent(viewId) + fakeEvent = RumRawEvent.ActionSent(viewId, frustrationCount) testedScope.pendingActionCount = pending // When @@ -1905,6 +1925,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(1) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -1967,6 +1988,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(1) hasFrozenFrameCount(1) hasCpuMetric(null) @@ -2098,6 +2120,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -2177,6 +2200,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(1) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -2233,11 +2257,13 @@ internal class RumViewScopeTest { } @Test - fun `𝕄 send event 𝕎 handleEvent(ActionSent) on stopped view`() { + fun `𝕄 send event 𝕎 handleEvent(ActionSent) on stopped view`( + @IntForgery(0) frustrationCount: Int + ) { // Given testedScope.stopped = true testedScope.pendingActionCount = 1 - fakeEvent = RumRawEvent.ActionSent(testedScope.viewId) + fakeEvent = RumRawEvent.ActionSent(testedScope.viewId, frustrationCount) // When val result = testedScope.handleEvent(fakeEvent, mockWriter) @@ -2256,6 +2282,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(1) + hasFrustrationCount(frustrationCount.toLong()) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -2293,14 +2320,15 @@ internal class RumViewScopeTest { @Test fun `𝕄 do nothing 𝕎 handleEvent(ActionSent) on stopped view {unknown viewId}`( @Forgery viewUuid: UUID, - @LongForgery(1) pending: Long + @LongForgery(1) pending: Long, + @IntForgery(0) frustrationCount: Int ) { // Given testedScope.stopped = true testedScope.pendingActionCount = pending val viewId = viewUuid.toString() assumeTrue(viewId != testedScope.viewId) - fakeEvent = RumRawEvent.ActionSent(viewId) + fakeEvent = RumRawEvent.ActionSent(viewId, frustrationCount) // When val result = testedScope.handleEvent(fakeEvent, mockWriter) @@ -2335,6 +2363,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(1) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -2392,14 +2421,15 @@ internal class RumViewScopeTest { @Test fun `𝕄 close the scope 𝕎 handleEvent(ActionSent) on stopped view { ApplicationStarted }`( - @LongForgery(0) duration: Long + @LongForgery(0) duration: Long, + @IntForgery(0) frustrationCount: Int ) { // Given testedScope.stopped = true val eventTime = Time() val startedNanos = eventTime.nanoTime - duration fakeEvent = RumRawEvent.ApplicationStarted(eventTime, startedNanos) - val fakeActionSent = RumRawEvent.ActionSent(testedScope.viewId) + val fakeActionSent = RumRawEvent.ActionSent(testedScope.viewId, frustrationCount) // When testedScope.handleEvent(fakeEvent, mockWriter) @@ -2532,6 +2562,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -3701,6 +3732,7 @@ internal class RumViewScopeTest { hasCrashCount(1) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -3872,6 +3904,7 @@ internal class RumViewScopeTest { hasCrashCount(1) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -4176,6 +4209,7 @@ internal class RumViewScopeTest { hasCrashCount(1) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -4755,6 +4789,7 @@ internal class RumViewScopeTest { hasErrorCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -4819,6 +4854,7 @@ internal class RumViewScopeTest { hasErrorCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -4902,6 +4938,7 @@ internal class RumViewScopeTest { hasErrorCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -4968,6 +5005,7 @@ internal class RumViewScopeTest { hasErrorCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5008,6 +5046,7 @@ internal class RumViewScopeTest { hasErrorCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5090,6 +5129,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(expectedTotal) @@ -5155,6 +5195,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5230,6 +5271,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5305,6 +5347,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5395,6 +5438,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5485,6 +5529,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5577,6 +5622,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5669,6 +5715,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5762,6 +5809,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5855,6 +5903,7 @@ internal class RumViewScopeTest { hasCrashCount(0) hasResourceCount(0) hasActionCount(0) + hasFrustrationCount(0) hasLongTaskCount(0) hasFrozenFrameCount(0) hasCpuMetric(null) @@ -5907,7 +5956,7 @@ internal class RumViewScopeTest { forge.aBool(), emptyMap() ), - RumRawEvent.ActionSent(forge.anAlphabeticalString()), + RumRawEvent.ActionSent(forge.anAlphabeticalString(), forge.aPositiveInt()), RumRawEvent.StartResource( forge.anAlphabeticalString(), forge.anAlphabeticalString(), diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt index 86c7d2267f..464a2df27a 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/rum/internal/monitor/DatadogRumMonitorTest.kt @@ -934,9 +934,10 @@ internal class DatadogRumMonitorTest { @Test fun `M delegate event to rootScope W eventSent {action}`( - @StringForgery viewId: String + @StringForgery viewId: String, + @IntForgery(0) frustrationCount: Int ) { - testedMonitor.eventSent(viewId, EventType.ACTION) + testedMonitor.eventSent(viewId, StorageEvent.Action(frustrationCount)) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -944,6 +945,7 @@ internal class DatadogRumMonitorTest { val event = firstValue as RumRawEvent.ActionSent assertThat(event.viewId).isEqualTo(viewId) + assertThat(event.frustrationCount).isEqualTo(frustrationCount) } verifyNoMoreInteractions(mockScope, mockWriter) } @@ -952,7 +954,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventSent {resource}`( @StringForgery viewId: String ) { - testedMonitor.eventSent(viewId, EventType.RESOURCE) + testedMonitor.eventSent(viewId, StorageEvent.Resource) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -968,7 +970,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventSent {error}`( @StringForgery viewId: String ) { - testedMonitor.eventSent(viewId, EventType.ERROR) + testedMonitor.eventSent(viewId, StorageEvent.Error) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -984,7 +986,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventSent {longTask}`( @StringForgery viewId: String ) { - testedMonitor.eventSent(viewId, EventType.LONG_TASK) + testedMonitor.eventSent(viewId, StorageEvent.LongTask) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -1001,7 +1003,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventSent {frozenFrame}`( @StringForgery viewId: String ) { - testedMonitor.eventSent(viewId, EventType.FROZEN_FRAME) + testedMonitor.eventSent(viewId, StorageEvent.FrozenFrame) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -1016,9 +1018,10 @@ internal class DatadogRumMonitorTest { @Test fun `M delegate event to rootScope W eventDropped {action}`( - @StringForgery viewId: String + @StringForgery viewId: String, + @IntForgery(0) frustrationCount: Int ) { - testedMonitor.eventDropped(viewId, EventType.ACTION) + testedMonitor.eventDropped(viewId, StorageEvent.Action(frustrationCount)) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -1034,7 +1037,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventDropped {resource}`( @StringForgery viewId: String ) { - testedMonitor.eventDropped(viewId, EventType.RESOURCE) + testedMonitor.eventDropped(viewId, StorageEvent.Resource) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -1050,7 +1053,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventDropped {error}`( @StringForgery viewId: String ) { - testedMonitor.eventDropped(viewId, EventType.ERROR) + testedMonitor.eventDropped(viewId, StorageEvent.Error) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -1066,7 +1069,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventDropped {longTask}`( @StringForgery viewId: String ) { - testedMonitor.eventDropped(viewId, EventType.LONG_TASK) + testedMonitor.eventDropped(viewId, StorageEvent.LongTask) Thread.sleep(PROCESSING_DELAY) argumentCaptor { @@ -1083,7 +1086,7 @@ internal class DatadogRumMonitorTest { fun `M delegate event to rootScope W eventDropped {frozenFrame}`( @StringForgery viewId: String ) { - testedMonitor.eventDropped(viewId, EventType.FROZEN_FRAME) + testedMonitor.eventDropped(viewId, StorageEvent.FrozenFrame) Thread.sleep(PROCESSING_DELAY) argumentCaptor { diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt index 45fdf966ee..784e812c79 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ActionEventForgeryFactory.kt @@ -30,7 +30,14 @@ internal class ActionEventForgeryFactory : crash = forge.aNullable { ActionEvent.Crash(aLong(0, 512)) }, resource = forge.aNullable { ActionEvent.Resource(aLong(0, 512)) }, longTask = forge.aNullable { ActionEvent.LongTask(aLong(0, 512)) }, - loadingTime = forge.aNullable { aPositiveLong(strict = true) } + loadingTime = forge.aNullable { aPositiveLong(strict = true) }, + frustration = forge.aNullable { + ActionEvent.Frustration( + type = forge.aList { + forge.aValueFrom(ActionEvent.Type::class.java) + }.distinct() + ) + } ), view = ActionEvent.View( id = forge.getForgery().toString(), diff --git a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt index 318cd520ad..2876003fc9 100644 --- a/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt +++ b/dd-sdk-android/src/test/kotlin/com/datadog/android/utils/forge/ViewEventForgeryFactory.kt @@ -63,7 +63,8 @@ internal class ViewEventForgeryFactory : ForgeryFactory { cpuTicksCount = forge.aNullable { aPositiveDouble() }, cpuTicksPerSecond = forge.aNullable { aPositiveDouble() }, refreshRateAverage = forge.aNullable { aPositiveDouble() }, - refreshRateMin = forge.aNullable { aPositiveDouble() } + refreshRateMin = forge.aNullable { aPositiveDouble() }, + frustration = forge.aNullable { ViewEvent.Frustration(aPositiveLong()) } ), connectivity = forge.aNullable { ViewEvent.Connectivity(