@@ -3,6 +3,7 @@ package io.sentry.metrics
33import com.google.common.truth.Truth.assertThat
44import io.sentry.DataCategory
55import io.sentry.ISentryClient
6+ import io.sentry.ISentryExecutorService
67import io.sentry.SentryMetricsEvent
78import io.sentry.SentryMetricsEvents
89import io.sentry.SentryNanotimeDate
@@ -12,19 +13,106 @@ import io.sentry.clientreport.DiscardReason
1213import io.sentry.clientreport.DiscardedEvent
1314import io.sentry.protocol.SentryId
1415import io.sentry.test.DeferredExecutorService
16+ import io.sentry.test.getProperty
1517import io.sentry.test.injectForField
18+ import io.sentry.transport.ReusableCountLatch
1619import io.sentry.util.JsonSerializationUtils
1720import kotlin.test.Test
1821import kotlin.test.assertEquals
1922import kotlin.test.assertFalse
2023import kotlin.test.assertTrue
24+ import org.mockito.kotlin.any
2125import org.mockito.kotlin.argumentCaptor
2226import org.mockito.kotlin.atLeast
2327import org.mockito.kotlin.mock
28+ import org.mockito.kotlin.never
2429import org.mockito.kotlin.times
2530import org.mockito.kotlin.verify
31+ import org.mockito.kotlin.verifyNoInteractions
2632
2733class MetricsBatchProcessorTest {
34+ @Test
35+ fun `constructor does not submit processor work` () {
36+ val mockExecutor = mock<ISentryExecutorService >()
37+
38+ MetricsBatchProcessor (SentryOptions (), mock(), mockExecutor)
39+
40+ verifyNoInteractions(mockExecutor)
41+ }
42+
43+ @Test
44+ fun `empty flush does not submit processor work` () {
45+ val mockExecutor = mock<ISentryExecutorService >()
46+ val processor = MetricsBatchProcessor (SentryOptions (), mock(), mockExecutor)
47+
48+ processor.flush(0 )
49+
50+ verifyNoInteractions(mockExecutor)
51+ }
52+
53+ @Test
54+ fun `close before first accepted item does not submit processor work` () {
55+ val mockExecutor = mock<ISentryExecutorService >()
56+ val processor = MetricsBatchProcessor (SentryOptions (), mock(), mockExecutor)
57+
58+ processor.close(false )
59+
60+ verify(mockExecutor).close(any())
61+ verify(mockExecutor, never()).schedule(any(), any())
62+ verify(mockExecutor, never()).submit(any<Runnable >())
63+ }
64+
65+ @Test
66+ fun `restart close before first accepted item does not submit processor work` () {
67+ val mockExecutor = mock<ISentryExecutorService >()
68+ val processor = MetricsBatchProcessor (SentryOptions (), mock(), mockExecutor)
69+
70+ processor.close(true )
71+
72+ verify(mockExecutor).close(any())
73+ verify(mockExecutor, never()).schedule(any(), any())
74+ verify(mockExecutor, never()).submit(any<Runnable >())
75+ }
76+
77+ @Test
78+ fun `item rejected during shutdown does not mark processor as used` () {
79+ val mockExecutor = mock<ISentryExecutorService >()
80+ val processor = MetricsBatchProcessor (SentryOptions (), mock(), mockExecutor)
81+ processor.close(false )
82+
83+ processor.add(metricsEvent(" rejected" ))
84+ processor.flush(0 )
85+
86+ verify(mockExecutor, never()).schedule(any(), any())
87+ verify(mockExecutor, never()).submit(any<Runnable >())
88+ }
89+
90+ @Test
91+ fun `item rejected due to queue capacity does not mark processor as used` () {
92+ val mockExecutor = mock<ISentryExecutorService >()
93+ val processor = MetricsBatchProcessor (SentryOptions (), mock(), mockExecutor)
94+ val pendingCount = processor.getProperty<ReusableCountLatch >(" pendingCount" )
95+ repeat(MetricsBatchProcessor .MAX_QUEUE_SIZE ) { pendingCount.increment() }
96+
97+ processor.add(metricsEvent(" rejected" ))
98+ processor.flush(0 )
99+
100+ verifyNoInteractions(mockExecutor)
101+ }
102+
103+ @Test
104+ fun `flush and restart close submit processor work after first accepted item` () {
105+ val mockExecutor = mock<ISentryExecutorService >()
106+ val processor = MetricsBatchProcessor (SentryOptions (), mock(), mockExecutor)
107+ processor.add(metricsEvent(" accepted" ))
108+
109+ processor.flush(0 )
110+ processor.close(true )
111+
112+ verify(mockExecutor, times(3 )).schedule(any(), any())
113+ verify(mockExecutor).submit(any<Runnable >())
114+ }
115+
28116 @Test
29117 fun `schedules another flush after previous flush has run` () {
30118 val mockClient = mock<ISentryClient >()
@@ -46,6 +134,9 @@ class MetricsBatchProcessorTest {
46134 .inOrder()
47135 }
48136
137+ private fun metricsEvent (name : String ) =
138+ SentryMetricsEvent (SentryId (), SentryNanotimeDate (), name, " gauge" , 1.0 )
139+
49140 @Test
50141 fun `drops metrics events after reaching MAX_QUEUE_SIZE limit` () {
51142 // given
0 commit comments