1+ package com.segment.analytics.kotlin.core
2+
3+ import com.segment.analytics.kotlin.core.platform.EventPlugin
4+ import com.segment.analytics.kotlin.core.platform.Plugin
5+ import com.segment.analytics.kotlin.core.utils.StubDestinationPlugin
6+ import com.segment.analytics.kotlin.core.utils.clearPersistentStorage
7+ import com.segment.analytics.kotlin.core.utils.mockHTTPClient
8+ import com.segment.analytics.kotlin.core.utils.testAnalytics
9+ import io.mockk.coEvery
10+ import io.mockk.coVerify
11+ import io.mockk.mockkStatic
12+ import kotlinx.coroutines.Job
13+ import kotlinx.coroutines.delay
14+ import kotlinx.coroutines.launch
15+ import kotlinx.coroutines.test.TestScope
16+ import kotlinx.coroutines.test.UnconfinedTestDispatcher
17+ import kotlinx.coroutines.test.advanceTimeBy
18+ import kotlinx.coroutines.test.advanceUntilIdle
19+ import kotlinx.coroutines.test.runTest
20+ import org.junit.jupiter.api.BeforeEach
21+ import org.junit.jupiter.api.Test
22+ import org.junit.jupiter.api.Assertions.*
23+
24+
25+ class WaitingTests {
26+
27+ private lateinit var analytics: Analytics
28+
29+ private val testDispatcher = UnconfinedTestDispatcher ()
30+
31+ private val testScope = TestScope (testDispatcher)
32+
33+ @BeforeEach
34+ fun setup () {
35+ clearPersistentStorage()
36+ mockHTTPClient()
37+ val config = Configuration (
38+ writeKey = " 123" ,
39+ application = " Test" ,
40+ autoAddSegmentDestination = false
41+ )
42+ analytics = testAnalytics(config, testScope, testDispatcher)
43+ }
44+
45+ @Test
46+ fun `test resume after timeout` () = testScope.runTest {
47+ assertTrue(analytics.running())
48+ analytics.pauseEventProcessing(1000 )
49+ assertFalse(analytics.running())
50+ advanceTimeBy(2000 )
51+ assertTrue(analytics.running())
52+ }
53+
54+ @Test
55+ fun `test manual resume` () = testScope.runTest {
56+ assertTrue(analytics.running())
57+ analytics.pauseEventProcessing()
58+ assertFalse(analytics.running())
59+ analytics.resumeEventProcessing()
60+ assertTrue(analytics.running())
61+ }
62+
63+
64+ @Test
65+ fun `test pause does not dispatch state if already pause` () {
66+ mockkStatic(" com.segment.analytics.kotlin.core.WaitingKt" )
67+ coEvery { analytics.startProcessingAfterTimeout(any()) } returns Job ()
68+
69+ testScope.runTest {
70+ analytics.pauseEventProcessing()
71+ analytics.pauseEventProcessing()
72+ analytics.pauseEventProcessing()
73+ coVerify(exactly = 1 ) {
74+ analytics.startProcessingAfterTimeout(any())
75+ }
76+ }
77+ }
78+
79+ @Test
80+ fun `test WaitingPlugin makes analytics to wait` () = testScope.runTest {
81+ assertTrue(analytics.running())
82+ val waitingPlugin = ExampleWaitingPlugin ()
83+ analytics.add(waitingPlugin)
84+ analytics.track(" foo" )
85+
86+ assertFalse(analytics.running())
87+ assertFalse(waitingPlugin.tracked)
88+
89+ advanceUntilIdle()
90+
91+ assertTrue(analytics.running())
92+ assertTrue(waitingPlugin.tracked)
93+ }
94+
95+ @Test
96+ fun `test timeout force resume` () = testScope.runTest {
97+ assertTrue(analytics.running())
98+ val waitingPlugin = ManualResumeWaitingPlugin ()
99+ analytics.add(waitingPlugin)
100+ analytics.track(" foo" )
101+
102+ assertFalse(analytics.running())
103+ assertFalse(waitingPlugin.tracked)
104+
105+ advanceUntilIdle()
106+
107+ assertTrue(analytics.running())
108+ assertTrue(waitingPlugin.tracked)
109+ }
110+
111+ @Test
112+ fun `test multiple WaitingPlugin` () = testScope.runTest {
113+ assertTrue(analytics.running())
114+ val plugin1 = ExampleWaitingPlugin ()
115+ val plugin2 = ManualResumeWaitingPlugin ()
116+ analytics.add(plugin1)
117+ analytics.add(plugin2)
118+ analytics.track(" foo" )
119+
120+ assertFalse(analytics.running())
121+ assertFalse(plugin1.tracked)
122+ assertFalse(plugin2.tracked)
123+
124+ plugin1.resume()
125+ advanceTimeBy(6000 )
126+
127+ assertFalse(analytics.running())
128+ assertFalse(plugin1.tracked)
129+ assertFalse(plugin2.tracked)
130+
131+ plugin2.resume()
132+ advanceUntilIdle()
133+ assertTrue(analytics.running())
134+ assertTrue(plugin1.tracked)
135+ assertTrue(plugin2.tracked)
136+ }
137+
138+ @Test
139+ fun `test WaitingPlugin makes analytics to wait on DestinationPlugin` () = testScope.runTest {
140+ assertTrue(analytics.running())
141+ val waitingPlugin = ExampleWaitingPlugin ()
142+ val destinationPlugin = StubDestinationPlugin ()
143+ analytics.add(destinationPlugin)
144+ destinationPlugin.add(waitingPlugin)
145+ analytics.track(" foo" )
146+
147+ assertFalse(analytics.running())
148+ assertFalse(waitingPlugin.tracked)
149+
150+ advanceUntilIdle()
151+
152+ assertTrue(analytics.running())
153+ assertTrue(waitingPlugin.tracked)
154+ }
155+
156+ @Test
157+ fun `test timeout force resume on DestinationPlugin` () = testScope.runTest {
158+ assertTrue(analytics.running())
159+ val waitingPlugin = ManualResumeWaitingPlugin ()
160+ val destinationPlugin = StubDestinationPlugin ()
161+ analytics.add(destinationPlugin)
162+ destinationPlugin.add(waitingPlugin)
163+ analytics.track(" foo" )
164+
165+ assertFalse(analytics.running())
166+ assertFalse(waitingPlugin.tracked)
167+
168+ advanceUntilIdle()
169+
170+ assertTrue(analytics.running())
171+ assertTrue(waitingPlugin.tracked)
172+ }
173+
174+ @Test
175+ fun `test multiple WaitingPlugin on DestinationPlugin` () = testScope.runTest {
176+ assertTrue(analytics.running())
177+ val destinationPlugin = StubDestinationPlugin ()
178+ analytics.add(destinationPlugin)
179+ val plugin1 = ExampleWaitingPlugin ()
180+ val plugin2 = ManualResumeWaitingPlugin ()
181+ destinationPlugin.add(plugin1)
182+ destinationPlugin.add(plugin2)
183+ analytics.track(" foo" )
184+
185+ assertFalse(analytics.running())
186+ assertFalse(plugin1.tracked)
187+ assertFalse(plugin2.tracked)
188+
189+ plugin1.resume()
190+ advanceTimeBy(6000 )
191+
192+ assertFalse(analytics.running())
193+ assertFalse(plugin1.tracked)
194+ assertFalse(plugin2.tracked)
195+
196+ plugin2.resume()
197+ advanceUntilIdle()
198+ assertTrue(analytics.running())
199+ assertTrue(plugin1.tracked)
200+ assertTrue(plugin2.tracked)
201+ }
202+
203+ class ExampleWaitingPlugin : EventPlugin , WaitingPlugin {
204+ override val type: Plugin .Type = Plugin .Type .Enrichment
205+ override lateinit var analytics: Analytics
206+ var tracked = false
207+
208+ override fun update (settings : Settings , type : Plugin .UpdateType ) {
209+ if (type == Plugin .UpdateType .Initial ) {
210+ analytics.analyticsScope.launch(analytics.analyticsDispatcher) {
211+ delay(3000 )
212+ resume()
213+ }
214+ }
215+ }
216+
217+ override fun track (payload : TrackEvent ): BaseEvent ? {
218+ tracked = true
219+ return super .track(payload)
220+ }
221+ }
222+
223+ class ManualResumeWaitingPlugin : EventPlugin , WaitingPlugin {
224+ override val type: Plugin .Type = Plugin .Type .Enrichment
225+ override lateinit var analytics: Analytics
226+ var tracked = false
227+
228+ override fun track (payload : TrackEvent ): BaseEvent ? {
229+ tracked = true
230+ return super .track(payload)
231+ }
232+ }
233+ }
0 commit comments