Skip to content

Commit f3a545e

Browse files
authored
keep dispatcher and scope config internal (#36)
* keep config dispatchers internal * fix blocking issue caused by sovran * remove analytics scope from configuration * fix broken tests * update the default coroutine scope * use single thread instead of fixed thread of 1
1 parent 1e57a32 commit f3a545e

File tree

17 files changed

+64
-162
lines changed

17 files changed

+64
-162
lines changed

android/src/main/java/com/segment/analytics/kotlin/android/AndroidAnalytics.kt

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ import com.segment.analytics.kotlin.core.BaseEvent
99
import com.segment.analytics.kotlin.core.Configuration
1010
import com.segment.analytics.kotlin.core.platform.plugins.LogType
1111
import com.segment.analytics.kotlin.core.platform.plugins.Logger
12-
import kotlinx.coroutines.CoroutineDispatcher
13-
import kotlinx.coroutines.CoroutineScope
14-
import kotlinx.coroutines.Dispatchers
15-
import kotlinx.coroutines.asCoroutineDispatcher
16-
import java.util.concurrent.Executors
1712

1813
// A set of functions tailored to the Android implementation of analytics
1914

@@ -22,18 +17,11 @@ import java.util.concurrent.Executors
2217
// Usage: Analytics("$writeKey", applicationContext, applicationScope)
2318
public fun Analytics(
2419
writeKey: String,
25-
context: Context,
26-
coroutineScope: CoroutineScope,
27-
analyticsDispatcher: CoroutineDispatcher =
28-
Executors.newSingleThreadExecutor().asCoroutineDispatcher(),
29-
ioDispatcher: CoroutineDispatcher = Dispatchers.IO
20+
context: Context
3021
): Analytics {
3122
require(writeKey.isNotBlank()) { "writeKey cannot be blank " }
3223
val conf = Configuration(
3324
writeKey = writeKey,
34-
analyticsScope = coroutineScope,
35-
analyticsDispatcher = analyticsDispatcher,
36-
ioDispatcher = ioDispatcher,
3725
application = context,
3826
storageProvider = AndroidStorageProvider
3927
)

android/src/main/java/com/segment/analytics/kotlin/android/Storage.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,12 @@ class AndroidStorage(
3434
this,
3535
UserInfo::class,
3636
initialState = true,
37-
queue = ioDispatcher,
3837
handler = ::userInfoUpdate
3938
)
4039
store.subscribe(
4140
this,
4241
System::class,
4342
initialState = true,
44-
queue = ioDispatcher,
4543
handler = ::systemUpdate
4644
)
4745
}

android/src/test/java/com/segment/analytics/kotlin/android/AndroidContextCollectorTests.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import android.content.Context
44
import androidx.test.platform.app.InstrumentationRegistry
55
import com.segment.analytics.kotlin.core.*
66
import com.segment.analytics.kotlin.android.plugins.AndroidContextPlugin
7-
import kotlinx.coroutines.CoroutineScope
8-
import kotlinx.coroutines.Dispatchers
97
import kotlinx.serialization.json.*
108
import org.junit.Assert.*
119
import org.junit.Test
@@ -22,7 +20,6 @@ class AndroidContextCollectorTests {
2220
val analytics = Analytics(
2321
Configuration(
2422
writeKey = "123",
25-
analyticsScope = CoroutineScope(Dispatchers.Main),
2623
application = appContext,
2724
storageProvider = AndroidStorageProvider
2825
)

android/src/test/java/com/segment/analytics/kotlin/android/AndroidLifecyclePluginTests.kt

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import com.segment.analytics.kotlin.core.platform.Plugin
1313
import com.segment.analytics.kotlin.android.plugins.AndroidLifecycle
1414
import com.segment.analytics.kotlin.android.plugins.AndroidLifecyclePlugin
1515
import io.mockk.*
16-
import kotlinx.coroutines.test.TestCoroutineDispatcher
17-
import kotlinx.coroutines.test.TestCoroutineScope
1816
import kotlinx.serialization.json.buildJsonObject
1917
import kotlinx.serialization.json.put
2018
import org.junit.Assert.*
@@ -34,9 +32,6 @@ class AndroidLifecyclePluginTests {
3432
private lateinit var analytics: Analytics
3533
private val mockContext = spyk(InstrumentationRegistry.getInstrumentation().targetContext)
3634

37-
private val testDispatcher = TestCoroutineDispatcher()
38-
private val testScope = TestCoroutineScope(testDispatcher)
39-
4035
init {
4136
val packageInfo = PackageInfo()
4237
packageInfo.versionCode = 100
@@ -59,9 +54,6 @@ class AndroidLifecyclePluginTests {
5954
analytics = Analytics(
6055
Configuration(
6156
writeKey = "123",
62-
analyticsScope = testScope,
63-
ioDispatcher = testDispatcher,
64-
analyticsDispatcher = testDispatcher,
6557
application = mockContext,
6658
storageProvider = AndroidStorageProvider
6759
)
@@ -74,64 +66,53 @@ class AndroidLifecyclePluginTests {
7466
analytics.configuration.trackDeepLinks = false
7567
analytics.configuration.useLifecycleObserver = false
7668
analytics.add(lifecyclePlugin)
77-
var invokedCreated = false
78-
var invokedStarted = false
79-
var invokedResumed = false
80-
var invokedPaused = false
81-
var invokedStopped = false
82-
var invokedDestroyed = false
83-
var invokedSaveInstance = false
84-
val test = object : Plugin, AndroidLifecycle {
69+
70+
val test = spyk(object : Plugin, AndroidLifecycle {
8571
override val type: Plugin.Type = Plugin.Type.Utility
8672
override lateinit var analytics: Analytics
8773

8874
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
89-
invokedCreated = true
9075
}
9176

9277
override fun onActivityStarted(activity: Activity?) {
93-
invokedStarted = true
9478
}
9579

9680
override fun onActivityResumed(activity: Activity?) {
97-
invokedResumed = true
9881
}
9982

10083
override fun onActivityPaused(activity: Activity?) {
101-
invokedPaused = true
10284
}
10385

10486
override fun onActivityStopped(activity: Activity?) {
105-
invokedStopped = true
10687
}
10788

10889
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
109-
invokedSaveInstance = true
11090
}
11191

11292
override fun onActivityDestroyed(activity: Activity?) {
113-
invokedDestroyed = true
11493
}
115-
}
94+
})
11695
analytics.add(test)
11796
val mockActivity = mockk<Activity>()
11897
val mockBundle = mockk<Bundle>()
11998

12099
lifecyclePlugin.onActivityCreated(mockActivity, mockBundle)
121-
assertTrue(invokedCreated)
122100
lifecyclePlugin.onActivityStarted(mockActivity)
123-
assertTrue(invokedStarted)
124101
lifecyclePlugin.onActivityResumed(mockActivity)
125-
assertTrue(invokedResumed)
126102
lifecyclePlugin.onActivityPaused(mockActivity)
127-
assertTrue(invokedPaused)
128103
lifecyclePlugin.onActivityStopped(mockActivity)
129-
assertTrue(invokedStopped)
130104
lifecyclePlugin.onActivitySaveInstanceState(mockActivity, mockBundle)
131-
assertTrue(invokedSaveInstance)
132105
lifecyclePlugin.onActivityDestroyed(mockActivity)
133-
assertTrue(invokedDestroyed)
134106

107+
verify {
108+
test.onActivityCreated(mockActivity, mockBundle)
109+
test.onActivityStarted(mockActivity)
110+
test.onActivityResumed(mockActivity)
111+
test.onActivityPaused(mockActivity)
112+
test.onActivityStopped(mockActivity)
113+
test.onActivitySaveInstanceState(mockActivity, mockBundle)
114+
test.onActivityDestroyed(mockActivity)
115+
}
135116
}
136117

137118
@Test
@@ -151,7 +132,7 @@ class AndroidLifecyclePluginTests {
151132
lifecyclePlugin.onActivityStarted(mockActivity)
152133
lifecyclePlugin.onActivityResumed(mockActivity)
153134

154-
assertTrue(mockPlugin.ran)
135+
verify (timeout = 2000){ mockPlugin.updateState(true) }
155136
val tracks = mutableListOf<TrackEvent>()
156137
verify { mockPlugin.track(capture(tracks)) }
157138
assertEquals(2, tracks.size)
@@ -181,7 +162,7 @@ class AndroidLifecyclePluginTests {
181162
lifecyclePlugin.onActivityStopped(mockActivity)
182163
lifecyclePlugin.onActivityDestroyed(mockActivity)
183164

184-
assertTrue(mockPlugin.ran)
165+
verify (timeout = 2000){ mockPlugin.updateState(true) }
185166
val track = slot<TrackEvent>()
186167
verify { mockPlugin.track(capture(track)) }
187168
with(track.captured) {
@@ -205,7 +186,7 @@ class AndroidLifecyclePluginTests {
205186
// Simulate activity startup
206187
lifecyclePlugin.onActivityCreated(mockActivity, mockBundle)
207188

208-
assertTrue(mockPlugin.ran)
189+
verify (timeout = 2000){ mockPlugin.updateState(true) }
209190
val track = slot<TrackEvent>()
210191
verify { mockPlugin.track(capture(track)) }
211192
with(track.captured) {
@@ -236,7 +217,7 @@ class AndroidLifecyclePluginTests {
236217
// Simulate activity startup
237218
lifecyclePlugin.onActivityCreated(mockActivity, mockBundle)
238219

239-
assertTrue(mockPlugin.ran)
220+
verify (timeout = 2000){ mockPlugin.updateState(true) }
240221
val track = slot<TrackEvent>()
241222
verify { mockPlugin.track(capture(track)) }
242223
with(track.captured) {
@@ -292,7 +273,7 @@ class AndroidLifecyclePluginTests {
292273
// Simulate activity startup
293274
lifecyclePlugin.onActivityCreated(mockActivity, mockBundle)
294275

295-
assertTrue(mockPlugin.ran)
276+
verify (timeout = 2000){ mockPlugin.updateState(true) }
296277
val track = slot<TrackEvent>()
297278
verify { mockPlugin.track(capture(track)) }
298279
with(track.captured) {
@@ -327,7 +308,7 @@ class AndroidLifecyclePluginTests {
327308
// Simulate activity startup
328309
lifecyclePlugin.onActivityCreated(mockActivity, mockBundle)
329310

330-
assertTrue(mockPlugin.ran)
311+
verify (timeout = 2000){ mockPlugin.updateState(true) }
331312
val track = slot<TrackEvent>()
332313
verify { mockPlugin.track(capture(track)) }
333314
with(track.captured) {
@@ -364,7 +345,7 @@ class AndroidLifecyclePluginTests {
364345
// Simulate activity startup
365346
lifecyclePlugin.onActivityCreated(mockActivity, mockBundle)
366347
367-
assertTrue(mockPlugin.ran)
348+
verify (timeout = 2000){ mockPlugin.updateState(true) }
368349
val track = slot<TrackEvent>()
369350
verify { mockPlugin.track(capture(track)) }
370351
with(track.captured) {

android/src/test/java/com/segment/analytics/kotlin/android/utils/Plugins.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,42 @@ class TestRunPlugin(var closure: (BaseEvent?) -> Unit): EventPlugin {
1212
ran = false
1313
}
1414

15+
fun updateState(ran: Boolean) {
16+
this.ran = ran
17+
}
18+
1519
override fun execute(event: BaseEvent): BaseEvent {
16-
ran = true
20+
updateState(true)
1721
return event
1822
}
1923

2024
override fun track(payload: TrackEvent): BaseEvent {
2125
closure(payload)
22-
ran = true
26+
updateState(true)
2327
return payload
2428
}
2529

2630
override fun identify(payload: IdentifyEvent): BaseEvent {
2731
closure(payload)
28-
ran = true
32+
updateState(true)
2933
return payload
3034
}
3135

3236
override fun screen(payload: ScreenEvent): BaseEvent {
3337
closure(payload)
34-
ran = true
38+
updateState(true)
3539
return payload
3640
}
3741

3842
override fun group(payload: GroupEvent): BaseEvent {
3943
closure(payload)
40-
ran = true
44+
updateState(true)
4145
return payload
4246
}
4347

4448
override fun alias(payload: AliasEvent): BaseEvent {
4549
closure(payload)
46-
ran = true
50+
updateState(true)
4751
return payload
4852
}
4953
}

core/src/main/java/com/segment/analytics/kotlin/core/Configuration.kt

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@ package com.segment.analytics.kotlin.core
33
import com.segment.analytics.kotlin.core.Constants.DEFAULT_API_HOST
44
import com.segment.analytics.kotlin.core.Constants.DEFAULT_CDN_HOST
55
import com.segment.analytics.kotlin.core.utilities.ConcreteStorageProvider
6-
import kotlinx.coroutines.CoroutineDispatcher
7-
import kotlinx.coroutines.CoroutineScope
8-
import kotlinx.coroutines.Dispatchers
9-
import kotlinx.coroutines.MainScope
10-
import kotlinx.coroutines.asCoroutineDispatcher
6+
import kotlinx.coroutines.*
117
import java.util.concurrent.Executors
128

139
/**
@@ -31,10 +27,6 @@ import java.util.concurrent.Executors
3127
data class Configuration(
3228
val writeKey: String,
3329
var application: Any? = null,
34-
var analyticsScope: CoroutineScope = MainScope(),
35-
var analyticsDispatcher: CoroutineDispatcher = Executors.newSingleThreadExecutor()
36-
.asCoroutineDispatcher(),
37-
var ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
3830
val storageProvider: StorageProvider = ConcreteStorageProvider,
3931
var collectDeviceId: Boolean = false,
4032
var trackApplicationLifecycleEvents: Boolean = false,
@@ -47,6 +39,13 @@ data class Configuration(
4739
var apiHost: String = DEFAULT_API_HOST,
4840
var cdnHost: String = DEFAULT_CDN_HOST
4941
) {
42+
internal var analyticsDispatcher: CoroutineDispatcher = Dispatchers.IO
43+
44+
internal var ioDispatcher: CoroutineDispatcher = Executors.newSingleThreadExecutor()
45+
.asCoroutineDispatcher()
46+
47+
internal var analyticsScope: CoroutineScope = CoroutineScope(SupervisorJob())
48+
5049
fun isValid(): Boolean {
5150
return writeKey.isNotBlank() && application != null
5251
}

core/src/main/java/com/segment/analytics/kotlin/core/compat/ConfigurationBuilder.kt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.segment.analytics.kotlin.core.compat
22

33
import com.segment.analytics.kotlin.core.Configuration
4-
import kotlinx.coroutines.CoroutineDispatcher
5-
import kotlinx.coroutines.CoroutineScope
64

75
/**
86
* This class serves as a helper class for Java compatibility, which makes the
@@ -16,12 +14,6 @@ class ConfigurationBuilder (writeKey: String) {
1614

1715
fun setApplication(application: Any?) = apply { configuration.application = application }
1816

19-
fun setAnalyticsScope(analyticsScope: CoroutineScope) = apply { configuration.analyticsScope = analyticsScope }
20-
21-
fun setAnalyticsDispatcher(analyticsDispatcher: CoroutineDispatcher) = apply { configuration.analyticsDispatcher = analyticsDispatcher }
22-
23-
fun setIODispatcher(ioDispatcher: CoroutineDispatcher) = apply { configuration.ioDispatcher = ioDispatcher }
24-
2517
fun setCollectDeviceId(collectDeviceId: Boolean) = apply { configuration.collectDeviceId = collectDeviceId }
2618

2719
fun setTrackApplicationLifecycleEvents(trackApplicationLifecycleEvents: Boolean) = apply { configuration.trackApplicationLifecycleEvents = trackApplicationLifecycleEvents }

core/src/main/java/com/segment/analytics/kotlin/core/utilities/StorageImpl.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,12 @@ class StorageImpl(
3737
this,
3838
UserInfo::class,
3939
initialState = true,
40-
queue = ioDispatcher,
4140
handler = ::userInfoUpdate
4241
)
4342
store.subscribe(
4443
this,
4544
System::class,
4645
initialState = true,
47-
queue = ioDispatcher,
4846
handler = ::systemUpdate
4947
)
5048
}

core/src/test/kotlin/com/segment/analytics/kotlin/core/AnalyticsTests.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ class AnalyticsTests {
4343
@BeforeEach
4444
fun setup() {
4545
clearPersistentStorage()
46-
analytics = Analytics(
47-
Configuration(
48-
writeKey = "123",
49-
analyticsScope = testScope,
50-
ioDispatcher = testDispatcher,
51-
analyticsDispatcher = testDispatcher,
52-
application = "Test"
53-
)
46+
val config = Configuration(
47+
writeKey = "123",
48+
application = "Test"
5449
)
50+
config.ioDispatcher = testDispatcher
51+
config.analyticsDispatcher = testDispatcher
52+
config.analyticsScope = testScope
53+
54+
analytics = Analytics(config)
5555
analytics.configuration.autoAddSegmentDestination = false
5656
}
5757

0 commit comments

Comments
 (0)