Skip to content

Commit 7f5c478

Browse files
committed
RUM-9908 Add unit tests for intermediate RumScopes
1 parent 953bce8 commit 7f5c478

File tree

3 files changed

+569
-0
lines changed

3 files changed

+569
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.android.rum.internal.domain.scope
8+
9+
import com.datadog.android.api.InternalLogger
10+
import com.datadog.android.api.context.DatadogContext
11+
import com.datadog.android.api.context.NetworkInfo
12+
import com.datadog.android.api.context.TimeInfo
13+
import com.datadog.android.api.feature.FeatureScope
14+
import com.datadog.android.api.storage.DataWriter
15+
import com.datadog.android.api.storage.EventBatchWriter
16+
import com.datadog.android.core.InternalSdkCore
17+
import com.datadog.android.core.internal.net.FirstPartyHostHeaderTypeResolver
18+
import com.datadog.android.rum.RumSessionListener
19+
import com.datadog.android.rum.internal.FeaturesContextResolver
20+
import com.datadog.android.rum.internal.domain.Time
21+
import com.datadog.android.rum.internal.metric.SessionMetricDispatcher
22+
import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener
23+
import com.datadog.android.rum.internal.vitals.VitalMonitor
24+
import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier
25+
import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier
26+
import com.datadog.android.rum.model.ViewEvent
27+
import com.datadog.android.rum.utils.forge.Configurator
28+
import fr.xgouchet.elmyr.Forge
29+
import fr.xgouchet.elmyr.annotation.BoolForgery
30+
import fr.xgouchet.elmyr.annotation.FloatForgery
31+
import fr.xgouchet.elmyr.annotation.Forgery
32+
import fr.xgouchet.elmyr.annotation.StringForgery
33+
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
34+
import fr.xgouchet.elmyr.junit5.ForgeExtension
35+
import org.assertj.core.api.Assertions.assertThat
36+
import org.junit.jupiter.api.BeforeEach
37+
import org.junit.jupiter.api.Test
38+
import org.junit.jupiter.api.extension.ExtendWith
39+
import org.junit.jupiter.api.extension.Extensions
40+
import org.mockito.Mock
41+
import org.mockito.junit.jupiter.MockitoExtension
42+
import org.mockito.junit.jupiter.MockitoSettings
43+
import org.mockito.kotlin.any
44+
import org.mockito.kotlin.doAnswer
45+
import org.mockito.kotlin.doReturn
46+
import org.mockito.kotlin.mock
47+
import org.mockito.kotlin.whenever
48+
import org.mockito.quality.Strictness
49+
import java.util.concurrent.TimeUnit
50+
import kotlin.math.max
51+
import kotlin.math.min
52+
53+
@Extensions(
54+
ExtendWith(MockitoExtension::class),
55+
ExtendWith(ForgeExtension::class)
56+
)
57+
@MockitoSettings(strictness = Strictness.LENIENT)
58+
@ForgeConfiguration(Configurator::class)
59+
internal class RumApplicationScopeAttributePropagationTest {
60+
61+
lateinit var testedScope: RumApplicationScope
62+
63+
@Mock
64+
lateinit var mockSdkCore: InternalSdkCore
65+
66+
@Mock
67+
lateinit var mockParentScope: RumScope
68+
69+
@Mock
70+
lateinit var mockWriter: DataWriter<Any>
71+
72+
@Mock
73+
lateinit var mockResolver: FirstPartyHostHeaderTypeResolver
74+
75+
@Mock
76+
lateinit var mockSessionListener: RumSessionListener
77+
78+
@Mock
79+
lateinit var mockNetworkSettledResourceIdentifier: InitialResourceIdentifier
80+
81+
@Mock
82+
lateinit var mockLastInteractionIdentifier: LastInteractionIdentifier
83+
84+
@Mock
85+
lateinit var mockCpuVitalMonitor: VitalMonitor
86+
87+
@Mock
88+
lateinit var mockMemoryVitalMonitor: VitalMonitor
89+
90+
@Mock
91+
lateinit var mockFrameRateVitalMonitor: VitalMonitor
92+
93+
@Mock
94+
lateinit var mockInternalLogger: InternalLogger
95+
96+
@Mock
97+
lateinit var mockRumFeatureScope: FeatureScope
98+
99+
@Mock
100+
lateinit var mockEventBatchWriter: EventBatchWriter
101+
102+
@Mock
103+
lateinit var mockFeaturesContextResolver: FeaturesContextResolver
104+
105+
@Mock
106+
lateinit var mockViewChangedListener: RumViewChangedListener
107+
108+
@Mock
109+
private lateinit var mockSessionEndedMetricDispatcher: SessionMetricDispatcher
110+
111+
@Mock
112+
lateinit var mockInitialResourceIdentifier: InitialResourceIdentifier
113+
114+
@Mock
115+
lateinit var mockSlowFramesListener: SlowFramesListener
116+
117+
lateinit var fakeEventTime: Time
118+
119+
lateinit var fakeEvent: RumRawEvent
120+
121+
@Forgery
122+
lateinit var fakeTimeInfoAtScopeStart: TimeInfo
123+
124+
@Forgery
125+
lateinit var fakeNetworkInfoAtScopeStart: NetworkInfo
126+
127+
@Forgery
128+
lateinit var fakeDatadogContext: DatadogContext
129+
130+
@BoolForgery
131+
var fakeHasReplay: Boolean = false
132+
133+
@FloatForgery(min = 0f, max = 100f)
134+
var fakeSampleRate: Float = 0f
135+
136+
@BoolForgery
137+
var fakeBackgroundTrackingEnabled: Boolean = false
138+
139+
@BoolForgery
140+
var fakeTrackFrustrations: Boolean = true
141+
142+
@StringForgery
143+
lateinit var fakeApplicationId: String
144+
145+
@BeforeEach
146+
fun `set up`(forge: Forge) {
147+
fakeDatadogContext = fakeDatadogContext.copy(
148+
source = forge.aValueFrom(ViewEvent.ViewEventSource::class.java).toJson().asString
149+
)
150+
151+
val fakeOffset = -forge.aLong(1000, 50000)
152+
val fakeTimestamp = System.currentTimeMillis() + fakeOffset
153+
val fakeNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(fakeOffset)
154+
val maxLimit = max(Long.MAX_VALUE - fakeTimestamp, Long.MAX_VALUE)
155+
val minLimit = min(-fakeTimestamp, maxLimit)
156+
157+
fakeDatadogContext = fakeDatadogContext.copy(
158+
time = fakeTimeInfoAtScopeStart.copy(
159+
serverTimeOffsetMs = forge.aLong(min = minLimit, max = maxLimit)
160+
)
161+
)
162+
fakeEventTime = Time(fakeTimestamp, fakeNanos)
163+
164+
whenever(mockRumFeatureScope.withWriteContext(any(), any())) doAnswer {
165+
val callback = it.getArgument<(DatadogContext, EventBatchWriter) -> Unit>(1)
166+
callback.invoke(fakeDatadogContext, mockEventBatchWriter)
167+
}
168+
169+
whenever(mockSdkCore.internalLogger) doReturn mock()
170+
171+
testedScope = RumApplicationScope(
172+
applicationId = fakeApplicationId,
173+
sdkCore = mockSdkCore,
174+
sampleRate = fakeSampleRate,
175+
backgroundTrackingEnabled = fakeBackgroundTrackingEnabled,
176+
trackFrustrations = fakeTrackFrustrations,
177+
firstPartyHostHeaderTypeResolver = mockResolver,
178+
cpuVitalMonitor = mockCpuVitalMonitor,
179+
memoryVitalMonitor = mockMemoryVitalMonitor,
180+
frameRateVitalMonitor = mockFrameRateVitalMonitor,
181+
sessionEndedMetricDispatcher = mockSessionEndedMetricDispatcher,
182+
sessionListener = mockSessionListener,
183+
initialResourceIdentifier = mockInitialResourceIdentifier,
184+
lastInteractionIdentifier = mockLastInteractionIdentifier,
185+
slowFramesListener = mockSlowFramesListener
186+
)
187+
}
188+
189+
// region Propagate parent attributes
190+
191+
@Test
192+
fun `M return global attributes W getCustomAttributes()`() {
193+
// When
194+
val customAttributes = testedScope.getCustomAttributes()
195+
196+
// Then
197+
assertThat(customAttributes).isEmpty()
198+
}
199+
200+
// endregion
201+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2016-Present Datadog, Inc.
5+
*/
6+
7+
package com.datadog.android.rum.internal.domain.scope
8+
9+
import com.datadog.android.api.InternalLogger
10+
import com.datadog.android.api.context.DatadogContext
11+
import com.datadog.android.api.context.NetworkInfo
12+
import com.datadog.android.api.feature.FeatureScope
13+
import com.datadog.android.api.storage.DataWriter
14+
import com.datadog.android.api.storage.EventBatchWriter
15+
import com.datadog.android.core.InternalSdkCore
16+
import com.datadog.android.core.internal.net.FirstPartyHostHeaderTypeResolver
17+
import com.datadog.android.rum.RumSessionListener
18+
import com.datadog.android.rum.internal.FeaturesContextResolver
19+
import com.datadog.android.rum.internal.domain.RumContext
20+
import com.datadog.android.rum.internal.domain.Time
21+
import com.datadog.android.rum.internal.metric.SessionMetricDispatcher
22+
import com.datadog.android.rum.internal.metric.slowframes.SlowFramesListener
23+
import com.datadog.android.rum.internal.vitals.VitalMonitor
24+
import com.datadog.android.rum.metric.interactiontonextview.LastInteractionIdentifier
25+
import com.datadog.android.rum.metric.networksettled.InitialResourceIdentifier
26+
import com.datadog.android.rum.utils.forge.Configurator
27+
import com.datadog.tools.unit.forge.exhaustiveAttributes
28+
import fr.xgouchet.elmyr.Forge
29+
import fr.xgouchet.elmyr.annotation.BoolForgery
30+
import fr.xgouchet.elmyr.annotation.FloatForgery
31+
import fr.xgouchet.elmyr.annotation.Forgery
32+
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
33+
import fr.xgouchet.elmyr.junit5.ForgeExtension
34+
import org.assertj.core.api.Assertions.assertThat
35+
import org.junit.jupiter.api.BeforeEach
36+
import org.junit.jupiter.api.Test
37+
import org.junit.jupiter.api.extension.ExtendWith
38+
import org.junit.jupiter.api.extension.Extensions
39+
import org.mockito.Mock
40+
import org.mockito.junit.jupiter.MockitoExtension
41+
import org.mockito.junit.jupiter.MockitoSettings
42+
import org.mockito.kotlin.doReturn
43+
import org.mockito.kotlin.mock
44+
import org.mockito.kotlin.whenever
45+
import org.mockito.quality.Strictness
46+
import java.util.concurrent.TimeUnit
47+
import kotlin.math.max
48+
import kotlin.math.min
49+
50+
@Extensions(
51+
ExtendWith(MockitoExtension::class),
52+
ExtendWith(ForgeExtension::class)
53+
)
54+
@MockitoSettings(strictness = Strictness.LENIENT)
55+
@ForgeConfiguration(Configurator::class)
56+
internal class RumSessionScopeAttributePropagationTest {
57+
58+
lateinit var testedScope: RumSessionScope
59+
60+
@Mock
61+
lateinit var mockSdkCore: InternalSdkCore
62+
63+
@Mock
64+
lateinit var mockParentScope: RumScope
65+
66+
@Mock
67+
lateinit var mockWriter: DataWriter<Any>
68+
69+
@Mock
70+
lateinit var mockResolver: FirstPartyHostHeaderTypeResolver
71+
72+
@Mock
73+
lateinit var mockSessionListener: RumSessionListener
74+
75+
@Mock
76+
lateinit var mockNetworkSettledResourceIdentifier: InitialResourceIdentifier
77+
78+
@Mock
79+
lateinit var mockLastInteractionIdentifier: LastInteractionIdentifier
80+
81+
@Mock
82+
lateinit var mockCpuVitalMonitor: VitalMonitor
83+
84+
@Mock
85+
lateinit var mockMemoryVitalMonitor: VitalMonitor
86+
87+
@Mock
88+
lateinit var mockFrameRateVitalMonitor: VitalMonitor
89+
90+
@Mock
91+
lateinit var mockInternalLogger: InternalLogger
92+
93+
@Mock
94+
lateinit var mockRumFeatureScope: FeatureScope
95+
96+
@Mock
97+
lateinit var mockEventBatchWriter: EventBatchWriter
98+
99+
@Mock
100+
lateinit var mockFeaturesContextResolver: FeaturesContextResolver
101+
102+
@Mock
103+
lateinit var mockViewChangedListener: RumViewChangedListener
104+
105+
@Mock
106+
lateinit var mockSessionEndedMetricDispatcher: SessionMetricDispatcher
107+
108+
@Mock
109+
lateinit var mockSlowFramesListener: SlowFramesListener
110+
111+
lateinit var fakeParentAttributes: Map<String, Any?>
112+
113+
@Forgery
114+
lateinit var fakeParentContext: RumContext
115+
116+
lateinit var fakeEventTime: Time
117+
118+
lateinit var fakeEvent: RumRawEvent
119+
120+
@Forgery
121+
lateinit var fakeNetworkInfoAtScopeStart: NetworkInfo
122+
123+
@Forgery
124+
lateinit var fakeDatadogContext: DatadogContext
125+
126+
@BoolForgery
127+
var fakeHasReplay: Boolean = false
128+
129+
@FloatForgery(min = 0f, max = 100f)
130+
var fakeSampleRate: Float = 0f
131+
132+
@BoolForgery
133+
var fakeBackgroundTrackingEnabled: Boolean = false
134+
135+
@BoolForgery
136+
var fakeTrackFrustrations: Boolean = true
137+
138+
@BeforeEach
139+
fun `set up`(forge: Forge) {
140+
fakeParentAttributes = forge.exhaustiveAttributes()
141+
whenever(mockParentScope.getCustomAttributes()) doReturn fakeParentAttributes.toMutableMap()
142+
143+
whenever(mockSdkCore.internalLogger) doReturn mock()
144+
145+
testedScope = RumSessionScope(
146+
parentScope = mockParentScope,
147+
sdkCore = mockSdkCore,
148+
sessionEndedMetricDispatcher = mockSessionEndedMetricDispatcher,
149+
sampleRate = fakeSampleRate,
150+
backgroundTrackingEnabled = fakeBackgroundTrackingEnabled,
151+
trackFrustrations = fakeTrackFrustrations,
152+
viewChangedListener = mockViewChangedListener,
153+
firstPartyHostHeaderTypeResolver = mockResolver,
154+
cpuVitalMonitor = mockCpuVitalMonitor,
155+
memoryVitalMonitor = mockMemoryVitalMonitor,
156+
frameRateVitalMonitor = mockFrameRateVitalMonitor,
157+
sessionListener = mockSessionListener,
158+
applicationDisplayed = false,
159+
networkSettledResourceIdentifier = mockNetworkSettledResourceIdentifier,
160+
lastInteractionIdentifier = mockLastInteractionIdentifier,
161+
slowFramesListener = mockSlowFramesListener,
162+
sessionInactivityNanos = TEST_INACTIVITY_NS,
163+
sessionMaxDurationNanos = TEST_MAX_DURATION_NS
164+
)
165+
}
166+
167+
// region Propagate parent attributes
168+
169+
@Test
170+
fun `M return parent attributes W getCustomAttributes()`() {
171+
// When
172+
val customAttributes = testedScope.getCustomAttributes()
173+
174+
// Then
175+
assertThat(customAttributes)
176+
.containsExactlyInAnyOrderEntriesOf(fakeParentAttributes)
177+
}
178+
179+
// endregion
180+
181+
companion object {
182+
private const val TEST_SLEEP_MS = 50L
183+
private const val TEST_INACTIVITY_MS = TEST_SLEEP_MS * 3
184+
private const val TEST_MAX_DURATION_MS = TEST_SLEEP_MS * 10
185+
186+
private val TEST_INACTIVITY_NS = TimeUnit.MILLISECONDS.toNanos(TEST_INACTIVITY_MS)
187+
private val TEST_MAX_DURATION_NS = TimeUnit.MILLISECONDS.toNanos(TEST_MAX_DURATION_MS)
188+
}
189+
}

0 commit comments

Comments
 (0)