Skip to content

Commit 0c847e6

Browse files
committed
Update tests
1 parent aa86a9f commit 0c847e6

File tree

1 file changed

+68
-119
lines changed

1 file changed

+68
-119
lines changed

sentry-android-core/src/test/java/io/sentry/android/core/ApplicationStartInfoIntegrationTest.kt

Lines changed: 68 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,18 @@ import android.os.Build
66
import androidx.test.ext.junit.runners.AndroidJUnit4
77
import io.sentry.IScopes
88
import io.sentry.ISentryExecutorService
9-
import io.sentry.ISpan
10-
import io.sentry.ITransaction
11-
import io.sentry.TransactionContext
9+
import io.sentry.protocol.SentryTransaction
1210
import java.util.concurrent.Callable
1311
import java.util.function.Consumer
1412
import kotlin.test.Test
1513
import kotlin.test.assertEquals
1614
import kotlin.test.assertNotNull
15+
import kotlin.test.assertTrue
1716
import org.junit.Before
1817
import org.junit.runner.RunWith
1918
import org.mockito.kotlin.any
2019
import org.mockito.kotlin.anyOrNull
2120
import org.mockito.kotlin.argumentCaptor
22-
import org.mockito.kotlin.eq
2321
import org.mockito.kotlin.mock
2422
import org.mockito.kotlin.never
2523
import org.mockito.kotlin.verify
@@ -50,7 +48,12 @@ class ApplicationStartInfoIntegrationTest {
5048
options.isEnableApplicationStartInfo = true
5149
options.executorService = executor
5250
options.setLogger(mock<io.sentry.ILogger>())
53-
options.dateProvider = mock<io.sentry.SentryDateProvider>()
51+
52+
val mockDateProvider = mock<io.sentry.SentryDateProvider>()
53+
val mockDate = mock<io.sentry.SentryDate>()
54+
whenever(mockDate.nanoTimestamp()).thenReturn(System.currentTimeMillis() * 1_000_000L)
55+
whenever(mockDateProvider.now()).thenReturn(mockDate)
56+
options.dateProvider = mockDateProvider
5457

5558
// Mock BuildInfoProvider to return API 35+
5659
whenever(buildInfoProvider.sdkInfoVersion).thenReturn(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@@ -92,168 +95,117 @@ class ApplicationStartInfoIntegrationTest {
9295
@Test
9396
fun `transaction includes correct tags from ApplicationStartInfo`() {
9497
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
98+
val transactionCaptor = argumentCaptor<SentryTransaction>()
9599
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
96100
integration.register(scopes, options)
97101

98102
verify(activityManager)
99103
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
100104

101-
val mockTransaction = mock<ITransaction>()
102-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>()))
103-
.thenReturn(mockTransaction)
104-
105105
val startInfo = createMockApplicationStartInfo()
106106
listenerCaptor.firstValue.accept(startInfo)
107107

108-
verify(mockTransaction).setTag(eq("start.reason"), any())
108+
verify(scopes).captureTransaction(transactionCaptor.capture(), anyOrNull(), anyOrNull())
109+
val transaction = transactionCaptor.firstValue
110+
assertNotNull(transaction.tags)
111+
assertTrue(transaction.tags!!.containsKey("start.reason"))
112+
assertTrue(transaction.tags!!.containsKey("start.type"))
113+
assertTrue(transaction.tags!!.containsKey("start.launch_mode"))
109114
}
110115

111116
@Test
112117
fun `transaction includes start type from ApplicationStartInfo`() {
113118
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
119+
val transactionCaptor = argumentCaptor<SentryTransaction>()
114120
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
115121
integration.register(scopes, options)
116122

117123
verify(activityManager)
118124
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
119125

120-
val mockTransaction = mock<ITransaction>()
121-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>()))
122-
.thenReturn(mockTransaction)
123-
124-
val startInfo = createMockApplicationStartInfo()
125-
whenever(startInfo.startType)
126-
.thenReturn(
127-
if (Build.VERSION.SDK_INT >= 35) android.app.ApplicationStartInfo.START_TYPE_COLD else 0
128-
)
126+
val startInfo =
127+
createMockApplicationStartInfo(startType = android.app.ApplicationStartInfo.START_TYPE_COLD)
129128
listenerCaptor.firstValue.accept(startInfo)
130129

131-
verify(mockTransaction).setTag("start.type", "cold")
130+
verify(scopes).captureTransaction(transactionCaptor.capture(), anyOrNull(), anyOrNull())
131+
assertEquals("cold", transactionCaptor.firstValue.tags!!["start.type"])
132132
}
133133

134134
@Test
135135
fun `transaction includes launch mode from ApplicationStartInfo`() {
136136
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
137+
val transactionCaptor = argumentCaptor<SentryTransaction>()
137138
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
138139
integration.register(scopes, options)
139140

140141
verify(activityManager)
141142
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
142143

143-
val mockTransaction = mock<ITransaction>()
144-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>()))
145-
.thenReturn(mockTransaction)
146-
147-
val startInfo = createMockApplicationStartInfo()
148-
whenever(startInfo.launchMode)
149-
.thenReturn(
150-
if (Build.VERSION.SDK_INT >= 35) android.app.ApplicationStartInfo.LAUNCH_MODE_STANDARD
151-
else 0
144+
val startInfo =
145+
createMockApplicationStartInfo(
146+
launchMode = android.app.ApplicationStartInfo.LAUNCH_MODE_STANDARD
152147
)
153148
listenerCaptor.firstValue.accept(startInfo)
154149

155-
verify(mockTransaction).setTag("start.launch_mode", "standard")
150+
verify(scopes).captureTransaction(transactionCaptor.capture(), anyOrNull(), anyOrNull())
151+
assertEquals("standard", transactionCaptor.firstValue.tags!!["start.launch_mode"])
156152
}
157153

158154
@Test
159155
fun `creates bind_application span when timestamp available`() {
160156
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
157+
val transactionCaptor = argumentCaptor<SentryTransaction>()
161158
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
162159
integration.register(scopes, options)
163160

164161
verify(activityManager)
165162
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
166163

167-
val mockTransaction = mock<ITransaction>()
168-
val mockSpan = mock<ISpan>()
169-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>()))
170-
.thenReturn(mockTransaction)
171-
whenever(
172-
mockTransaction.startChild(eq("app.start.bind_application"), anyOrNull(), any(), any())
173-
)
174-
.thenReturn(mockSpan)
175-
176164
val startInfo =
177165
createMockApplicationStartInfo(forkTime = 1000000000L, bindApplicationTime = 1100000000L)
178166
listenerCaptor.firstValue.accept(startInfo)
179167

180-
verify(mockTransaction).startChild(eq("app.start.bind_application"), anyOrNull(), any(), any())
181-
verify(mockSpan).finish(any(), any())
182-
}
183-
184-
@Test
185-
fun `creates application_oncreate span when timestamp available`() {
186-
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
187-
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
188-
integration.register(scopes, options)
189-
190-
verify(activityManager)
191-
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
192-
193-
val mockTransaction = mock<ITransaction>()
194-
val mockSpan = mock<ISpan>()
195-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>()))
196-
.thenReturn(mockTransaction)
197-
whenever(
198-
mockTransaction.startChild(eq("app.start.application_oncreate"), anyOrNull(), any(), any())
199-
)
200-
.thenReturn(mockSpan)
201-
202-
val startInfo =
203-
createMockApplicationStartInfo(forkTime = 1000000000L, applicationOnCreateTime = 1200000000L)
204-
listenerCaptor.firstValue.accept(startInfo)
205-
206-
verify(mockTransaction)
207-
.startChild(eq("app.start.application_oncreate"), anyOrNull(), any(), any())
208-
verify(mockSpan).finish(any(), any())
168+
verify(scopes).captureTransaction(transactionCaptor.capture(), anyOrNull(), anyOrNull())
169+
val spans = transactionCaptor.firstValue.spans
170+
assertTrue(spans.any { it.op == "bind_application" })
209171
}
210172

211173
@Test
212174
fun `creates ttid span when timestamp available`() {
213175
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
176+
val transactionCaptor = argumentCaptor<SentryTransaction>()
214177
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
215178
integration.register(scopes, options)
216179

217180
verify(activityManager)
218181
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
219182

220-
val mockTransaction = mock<ITransaction>()
221-
val mockSpan = mock<ISpan>()
222-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>()))
223-
.thenReturn(mockTransaction)
224-
whenever(mockTransaction.startChild(eq("app.start.ttid"), anyOrNull(), any(), any()))
225-
.thenReturn(mockSpan)
226-
227183
val startInfo =
228184
createMockApplicationStartInfo(forkTime = 1000000000L, firstFrameTime = 1500000000L)
229185
listenerCaptor.firstValue.accept(startInfo)
230186

231-
verify(mockTransaction).startChild(eq("app.start.ttid"), anyOrNull(), any(), any())
232-
verify(mockSpan).finish(any(), any())
187+
verify(scopes).captureTransaction(transactionCaptor.capture(), anyOrNull(), anyOrNull())
188+
val spans = transactionCaptor.firstValue.spans
189+
assertTrue(spans.any { it.op == "ttid" })
233190
}
234191

235192
@Test
236193
fun `creates ttfd span when timestamp available`() {
237194
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
195+
val transactionCaptor = argumentCaptor<SentryTransaction>()
238196
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
239197
integration.register(scopes, options)
240198

241199
verify(activityManager)
242200
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
243201

244-
val mockTransaction = mock<ITransaction>()
245-
val mockSpan = mock<ISpan>()
246-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>()))
247-
.thenReturn(mockTransaction)
248-
whenever(mockTransaction.startChild(eq("app.start.ttfd"), anyOrNull(), any(), any()))
249-
.thenReturn(mockSpan)
250-
251202
val startInfo =
252203
createMockApplicationStartInfo(forkTime = 1000000000L, fullyDrawnTime = 2000000000L)
253204
listenerCaptor.firstValue.accept(startInfo)
254205

255-
verify(mockTransaction).startChild(eq("app.start.ttfd"), anyOrNull(), any(), any())
256-
verify(mockSpan).finish(any(), any())
206+
verify(scopes).captureTransaction(transactionCaptor.capture(), anyOrNull(), anyOrNull())
207+
val spans = transactionCaptor.firstValue.spans
208+
assertTrue(spans.any { it.op == "ttfd" })
257209
}
258210

259211
@Test
@@ -266,63 +218,60 @@ class ApplicationStartInfoIntegrationTest {
266218
}
267219

268220
@Test
269-
fun `transaction name includes reason label`() {
221+
fun `transaction name is app_start`() {
270222
val listenerCaptor = argumentCaptor<Consumer<android.app.ApplicationStartInfo>>()
223+
val transactionCaptor = argumentCaptor<SentryTransaction>()
271224
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
272225
integration.register(scopes, options)
273226

274227
verify(activityManager)
275228
.addApplicationStartInfoCompletionListener(any(), listenerCaptor.capture())
276229

277-
var capturedContext: TransactionContext? = null
278-
whenever(scopes.startTransaction(any(), any<io.sentry.TransactionOptions>())).thenAnswer {
279-
capturedContext = it.arguments[0] as TransactionContext
280-
mock()
281-
}
282-
283230
val startInfo = createMockApplicationStartInfo()
284-
whenever(startInfo.reason)
285-
.thenReturn(
286-
if (Build.VERSION.SDK_INT >= 35) android.app.ApplicationStartInfo.START_REASON_LAUNCHER
287-
else 0
288-
)
289231
listenerCaptor.firstValue.accept(startInfo)
290232

291-
assertNotNull(capturedContext)
292-
assertEquals("app.start.launcher", capturedContext!!.name)
233+
verify(scopes).captureTransaction(transactionCaptor.capture(), anyOrNull(), anyOrNull())
234+
assertEquals("app.start", transactionCaptor.firstValue.transaction)
235+
}
236+
237+
@Test
238+
fun `does not register on API lower than 35`() {
239+
whenever(buildInfoProvider.sdkInfoVersion).thenReturn(34)
240+
val integration = ApplicationStartInfoIntegration(context, buildInfoProvider)
241+
242+
integration.register(scopes, options)
243+
244+
verify(activityManager, never()).addApplicationStartInfoCompletionListener(any(), any())
293245
}
294246

295247
// Helper methods
296248
private fun createMockApplicationStartInfo(
297249
forkTime: Long = 1000000000L, // nanoseconds
298250
bindApplicationTime: Long = 0L,
299-
applicationOnCreateTime: Long = 0L,
300251
firstFrameTime: Long = 0L,
301252
fullyDrawnTime: Long = 0L,
253+
reason: Int = android.app.ApplicationStartInfo.START_REASON_LAUNCHER,
254+
startType: Int = android.app.ApplicationStartInfo.START_TYPE_COLD,
255+
launchMode: Int = android.app.ApplicationStartInfo.LAUNCH_MODE_STANDARD,
302256
): android.app.ApplicationStartInfo {
303257
val startInfo = mock<android.app.ApplicationStartInfo>()
304258

305259
val timestamps = mutableMapOf<Int, Long>()
306-
if (Build.VERSION.SDK_INT >= 35) {
307-
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_FORK] = forkTime
308-
if (bindApplicationTime > 0) {
309-
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION] =
310-
bindApplicationTime
311-
}
312-
if (applicationOnCreateTime > 0) {
313-
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_APPLICATION_ONCREATE] =
314-
applicationOnCreateTime
315-
}
316-
if (firstFrameTime > 0) {
317-
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME] = firstFrameTime
318-
}
319-
if (fullyDrawnTime > 0) {
320-
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN] = fullyDrawnTime
321-
}
322-
323-
whenever(startInfo.reason).thenReturn(android.app.ApplicationStartInfo.START_REASON_LAUNCHER)
260+
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_FORK] = forkTime
261+
if (bindApplicationTime > 0) {
262+
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_BIND_APPLICATION] =
263+
bindApplicationTime
264+
}
265+
if (firstFrameTime > 0) {
266+
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME] = firstFrameTime
267+
}
268+
if (fullyDrawnTime > 0) {
269+
timestamps[android.app.ApplicationStartInfo.START_TIMESTAMP_FULLY_DRAWN] = fullyDrawnTime
324270
}
325271

272+
whenever(startInfo.reason).thenReturn(reason)
273+
whenever(startInfo.startType).thenReturn(startType)
274+
whenever(startInfo.launchMode).thenReturn(launchMode)
326275
whenever(startInfo.startupTimestamps).thenReturn(timestamps)
327276

328277
return startInfo

0 commit comments

Comments
 (0)