@@ -54,6 +54,7 @@ import org.robolectric.shadow.api.Shadow
5454import org.robolectric.shadows.ShadowActivityManager
5555import java.util.Date
5656import java.util.concurrent.Future
57+ import java.util.concurrent.TimeUnit
5758import kotlin.test.AfterTest
5859import kotlin.test.BeforeTest
5960import kotlin.test.Test
@@ -300,7 +301,7 @@ class ActivityLifecycleIntegrationTest {
300301 val sut = fixture.getSut(initializer = {
301302 it.tracesSampleRate = 1.0
302303 it.isEnableTimeToFullDisplayTracing = true
303- it.idleTimeout = 200
304+ it.idleTimeout = 100
304305 })
305306 sut.register(fixture.scopes, fixture.options)
306307 sut.onActivityCreated(activity, fixture.bundle)
@@ -318,7 +319,7 @@ class ActivityLifecycleIntegrationTest {
318319 )
319320
320321 // but when idle timeout has passed
321- Thread .sleep(400 )
322+ Thread .sleep(200 )
322323
323324 // then the transaction should be finished
324325 verify(fixture.scopes).captureTransaction(
@@ -815,7 +816,6 @@ class ActivityLifecycleIntegrationTest {
815816
816817 // when activity is resumed
817818 sut.onActivityResumed(activity)
818- Thread .sleep(1 )
819819 runFirstDraw(view)
820820 // end-time should be set
821821 assertTrue(AppStartMetrics .getInstance().sdkInitTimeSpan.hasStopped())
@@ -863,17 +863,14 @@ class ActivityLifecycleIntegrationTest {
863863 sut.onActivityCreated(activity, fixture.bundle)
864864 sut.onActivityStarted(activity)
865865 sut.onActivityResumed(activity)
866- Thread .sleep(1 )
867866 runFirstDraw(view)
868867
869868 val firstAppStartEndTime = AppStartMetrics .getInstance().sdkInitTimeSpan.projectedStopTimestamp
870869
871- Thread .sleep(1 )
872870 sut.onActivityPaused(activity)
873871 sut.onActivityStopped(activity)
874872 sut.onActivityStarted(activity)
875873 sut.onActivityResumed(activity)
876- Thread .sleep(1 )
877874 runFirstDraw(view)
878875
879876 // then the end time should not be overwritten
@@ -983,6 +980,36 @@ class ActivityLifecycleIntegrationTest {
983980 )
984981 }
985982
983+ @Test
984+ fun `When isEnableTimeToFullDisplayTracing is true and reportFullyDrawn is called, ttfd is finished on first frame if ttid is running` () {
985+ val sut = fixture.getSut()
986+ val view = fixture.createView()
987+ val activity = mock<Activity >()
988+ whenever(activity.findViewById<View >(any())).thenReturn(view)
989+ fixture.options.tracesSampleRate = 1.0
990+ fixture.options.isEnableTimeToFullDisplayTracing = true
991+ sut.register(fixture.scopes, fixture.options)
992+ sut.onActivityCreated(activity, fixture.bundle)
993+ sut.onActivityResumed(activity)
994+ val ttidSpan = sut.ttidSpanMap[activity]
995+ val ttfdSpan = sut.ttfdSpanMap[activity]
996+
997+ // Assert the ttfd span is running and a timeout autoCancel future has been scheduled
998+ assertNotNull(ttidSpan)
999+ assertNotNull(ttfdSpan)
1000+ assertFalse(ttidSpan.isFinished)
1001+ assertFalse(ttfdSpan.isFinished)
1002+
1003+ // ReportFullyDrawn should not finish the ttfd span, as the ttid is still running
1004+ fixture.options.fullyDisplayedReporter.reportFullyDrawn()
1005+ assertFalse(ttfdSpan.isFinished)
1006+
1007+ // But when ReportFullyDrawn should not finish the ttfd span, as the ttid is still running
1008+ runFirstDraw(view)
1009+ assertTrue(ttidSpan.isFinished)
1010+ assertTrue(ttfdSpan.isFinished)
1011+ }
1012+
9861013 @Test
9871014 fun `When isEnableTimeToFullDisplayTracing is true and reportFullyDrawn is called, ttfd autoClose future is cancelled` () {
9881015 val sut = fixture.getSut()
@@ -991,16 +1018,17 @@ class ActivityLifecycleIntegrationTest {
9911018 sut.register(fixture.scopes, fixture.options)
9921019 val activity = mock<Activity >()
9931020 sut.onActivityCreated(activity, fixture.bundle)
1021+ val ttidSpan = sut.ttidSpanMap[activity]
9941022 val ttfdSpan = sut.ttfdSpanMap[activity]
9951023 var autoCloseFuture = sut.getProperty<Future <* >? > (" ttfdAutoCloseFuture" )
1024+ ttidSpan?.finish()
9961025
9971026 // Assert the ttfd span is running and a timeout autoCancel future has been scheduled
9981027 assertNotNull(ttfdSpan)
9991028 assertFalse(ttfdSpan.isFinished)
10001029 assertNotNull(autoCloseFuture)
10011030
10021031 // ReportFullyDrawn should finish the ttfd span and cancel the future
1003- Thread .sleep(1 )
10041032 fixture.options.fullyDisplayedReporter.reportFullyDrawn()
10051033 assertTrue(ttfdSpan.isFinished)
10061034 assertNotEquals(SpanStatus .DEADLINE_EXCEEDED , ttfdSpan.status)
@@ -1077,7 +1105,6 @@ class ActivityLifecycleIntegrationTest {
10771105 assertFalse(ttidSpan.isFinished)
10781106
10791107 // Mock the draw of the view. The ttid span should finish now
1080- Thread .sleep(1 )
10811108 runFirstDraw(view)
10821109 assertTrue(ttidSpan.isFinished)
10831110
@@ -1097,7 +1124,9 @@ class ActivityLifecycleIntegrationTest {
10971124
10981125 @Test
10991126 fun `When isEnableTimeToFullDisplayTracing is true and reportFullyDrawn is called too early, ttfd is adjusted to equal ttid` () {
1100- val sut = fixture.getSut()
1127+ val sut = fixture.getSut() {
1128+ // it.fullyDisplayedReporter = mock()
1129+ }
11011130 val view = fixture.createView()
11021131 val activity = mock<Activity >()
11031132 fixture.options.tracesSampleRate = 1.0
@@ -1116,18 +1145,28 @@ class ActivityLifecycleIntegrationTest {
11161145 assertFalse(ttfdSpan.isFinished)
11171146
11181147 // Let's finish the ttfd span too early (before the first view is drawn)
1119- ttfdSpan.finish()
1120- assertTrue(ttfdSpan.isFinished)
1121- val oldEndDate = ttfdSpan.finishDate
1148+ fixture.options.fullyDisplayedReporter.reportFullyDrawn()
11221149
1123- // Mock the draw of the view. The ttid span should finish now and the ttfd end date should be adjusted
1150+ // The TTFD shouldn't be finished yet
1151+ assertFalse(ttfdSpan.isFinished)
1152+
1153+ // Mock the draw of the view. The ttid span should finish now and the ttfd, too
11241154 runFirstDraw(view)
11251155 assertTrue(ttidSpan.isFinished)
1126- val newEndDate = ttfdSpan.finishDate
1127- assertNotEquals(newEndDate, oldEndDate)
1128- assertEquals(newEndDate, ttidSpan.finishDate)
1156+ assertTrue(ttfdSpan.isFinished)
1157+ assertEquals(ttfdSpan.finishDate, ttidSpan.finishDate)
11291158
11301159 sut.onActivityDestroyed(activity)
1160+
1161+ // The measurements should be set to the same value for ttid and ttfd
1162+ val ttidDuration = TimeUnit .NANOSECONDS .toMillis(ttidSpan.finishDate!! .diff(ttidSpan.startDate))
1163+ val ttfdDuration = TimeUnit .NANOSECONDS .toMillis(ttfdSpan.finishDate!! .diff(ttfdSpan.startDate))
1164+ assertEquals(ttidDuration, ttfdDuration)
1165+ // TTID also has initial display measurement, but TTFD has not
1166+ assertEquals(ttidDuration, ttidSpan.measurements[MeasurementValue .KEY_TIME_TO_INITIAL_DISPLAY ]!! .value)
1167+ assertEquals(ttidDuration, ttidSpan.measurements[MeasurementValue .KEY_TIME_TO_FULL_DISPLAY ]!! .value)
1168+ assertEquals(ttidDuration, ttfdSpan.measurements[MeasurementValue .KEY_TIME_TO_FULL_DISPLAY ]!! .value)
1169+
11311170 verify(fixture.scopes).captureTransaction(
11321171 check {
11331172 // ttid and ttfd measurements should be the same
@@ -1189,7 +1228,6 @@ class ActivityLifecycleIntegrationTest {
11891228 assertFalse(ttfdSpan.isFinished)
11901229
11911230 // Run the autoClose task 1 ms after finishing the ttid span and assert the ttfd span is finished
1192- Thread .sleep(1 )
11931231 deferredExecutorService.runAll()
11941232 assertTrue(ttfdSpan.isFinished)
11951233
0 commit comments