Skip to content

Commit 571996e

Browse files
authored
Json Utility improvements & Re-add Alias Event (#29)
* improve usage of JSON * improve test quality * add jvm filenames to util files * made getters safe to use improved test code quality for JSON * add new safe conversion functions * update usages of jsonCast to safe conversion
1 parent 96c3dff commit 571996e

File tree

20 files changed

+748
-469
lines changed

20 files changed

+748
-469
lines changed

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.segment.analytics.kotlin.android
33
import com.segment.analytics.kotlin.android.utilities.AndroidKVS
44
import com.segment.analytics.kotlin.android.utils.MemorySharedPreferences
55
import com.segment.analytics.kotlin.core.*
6+
import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson
67
import com.segment.analytics.kotlin.core.utilities.EventsFileManager
78
import io.mockk.every
89
import io.mockk.mockkStatic
@@ -50,7 +51,7 @@ class EventsFileTests {
5051
context = emptyJsonObject
5152
timestamp = epochTimestamp
5253
}
53-
val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
54+
val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
5455
file.storeEvent(eventString)
5556

5657
val expectedContents = """{"batch":[${eventString}"""
@@ -73,7 +74,7 @@ class EventsFileTests {
7374
context = emptyJsonObject
7475
timestamp = epochTimestamp
7576
}
76-
val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
77+
val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
7778
file.storeEvent(eventString)
7879
file.storeEvent(eventString)
7980

@@ -97,7 +98,7 @@ class EventsFileTests {
9798
context = emptyJsonObject
9899
timestamp = epochTimestamp
99100
}
100-
val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
101+
val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
101102
file.storeEvent(eventString)
102103
// artificially add 500kb of data to file
103104
FileOutputStream(File(directory, "123-0.tmp"), true).write(
@@ -134,7 +135,7 @@ class EventsFileTests {
134135
context = emptyJsonObject
135136
timestamp = epochTimestamp
136137
}
137-
val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
138+
val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
138139
file.storeEvent(eventString)
139140

140141
val fileUrls = file.read()
@@ -159,7 +160,7 @@ class EventsFileTests {
159160
context = emptyJsonObject
160161
timestamp = epochTimestamp
161162
}
162-
val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
163+
val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
163164
file.storeEvent(eventString)
164165

165166
file.read().let {
@@ -190,7 +191,7 @@ class EventsFileTests {
190191
context = emptyJsonObject
191192
timestamp = epochTimestamp
192193
}
193-
val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
194+
val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
194195

195196
val file1 = EventsFileManager(directory, "123", kvStore)
196197
val file2 = EventsFileManager(directory, "qwerty", kvStore)
@@ -215,7 +216,7 @@ class EventsFileTests {
215216
// context = emptyJsonObject
216217
// timestamp = epochTimestamp
217218
// }
218-
// val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
219+
// val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
219220
// file.storeEvent(eventString)
220221
//
221222
// val expectedContents = """{"batch":[${eventString}"""
@@ -244,7 +245,7 @@ class EventsFileTests {
244245
context = emptyJsonObject
245246
timestamp = epochTimestamp
246247
}
247-
val eventString = Json { encodeDefaults = true }.encodeToString(trackEvent)
248+
val eventString = EncodeDefaultsJson.encodeToString(trackEvent)
248249
file.storeEvent(eventString)
249250

250251
val list = file.read()

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import android.content.SharedPreferences
55
import com.segment.analytics.kotlin.core.*
66
import com.segment.analytics.kotlin.android.utils.MemorySharedPreferences
7+
import com.segment.analytics.kotlin.android.utils.clearPersistentStorage
78
import com.segment.analytics.kotlin.android.utils.mockAnalytics
89
import com.segment.analytics.kotlin.android.utils.mockContext
910
import kotlinx.coroutines.test.TestCoroutineDispatcher
@@ -33,8 +34,7 @@ class StorageTests {
3334

3435
@BeforeEach
3536
fun setup() {
36-
File("/tmp/analytics-android").deleteRecursively()
37-
File("/tmp/analytics-android").mkdir()
37+
clearPersistentStorage()
3838
store.provide(
3939
UserInfo(
4040
anonymousId = "oldAnonId",

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ fun mockContext(): Context {
2727
every { mockPkgMgr.getPackageInfo("com.foo", 0) } returns packageInfo
2828
val mock = mockk<Context> {
2929
every { getSharedPreferences(any(), any()) } returns mockPrefs
30-
every { getDir(any(), any()) } returns File("/tmp/analytics-android/")
30+
every { getDir(any(), any()) } returns File("/tmp/analytics-android-test/")
3131
every { packageName } returns "com.foo"
3232
every { packageManager } returns mockPkgMgr
3333
}
3434
return mock
3535
}
36+
37+
fun clearPersistentStorage() {
38+
File("/tmp/analytics-android-test/").deleteRecursively()
39+
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ class Analytics(val configuration: Configuration) : Subscriber {
312312
) {
313313
group(groupId, traits, Json.serializersModule.serializer())
314314
}
315-
/*
315+
316316
/**
317317
* The alias method is used to merge two user identities, effectively connecting two sets of
318318
* user data as one. This is an advanced method, but it is required to manage user identities
@@ -337,7 +337,6 @@ class Analytics(val configuration: Configuration) : Subscriber {
337337
log("failed to fetch current UserInfo state")
338338
}
339339
}
340-
*/
341340

342341
fun process(event: BaseEvent) {
343342
log("applying base attributes on ${Thread.currentThread().name}")

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.segment.analytics.kotlin.core.platform.DestinationPlugin
44
import com.segment.analytics.kotlin.core.platform.Plugin
55
import com.segment.analytics.kotlin.core.platform.plugins.LogType
66
import com.segment.analytics.kotlin.core.platform.plugins.log
7+
import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson
78
import kotlinx.coroutines.launch
89
import kotlinx.serialization.encodeToString
910
import kotlinx.serialization.json.Json
@@ -64,9 +65,7 @@ class SegmentDestination(
6465

6566
private inline fun <reified T : BaseEvent> enqueue(payload: T) {
6667
// needs to be inline reified for encoding using Json
67-
val jsonVal = Json {
68-
encodeDefaults = true
69-
}.encodeToJsonElement(payload).jsonObject.filterNot { (k, v) ->
68+
val jsonVal = EncodeDefaultsJson.encodeToJsonElement(payload).jsonObject.filterNot { (k, v) ->
7069
// filter out empty userId and traits values
7170
(k == "userId" && v.jsonPrimitive.content.isBlank()) || (k == "traits" && v == emptyJsonObject)
7271
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import com.segment.analytics.kotlin.core.platform.DestinationPlugin
44
import com.segment.analytics.kotlin.core.platform.Plugin
55
import com.segment.analytics.kotlin.core.platform.plugins.LogType
66
import com.segment.analytics.kotlin.core.platform.plugins.log
7+
import com.segment.analytics.kotlin.core.utilities.LenientJson
8+
import com.segment.analytics.kotlin.core.utilities.safeJsonObject
79
import kotlinx.coroutines.launch
810
import kotlinx.serialization.DeserializationStrategy
911
import kotlinx.serialization.Serializable
1012
import kotlinx.serialization.decodeFromString
1113
import kotlinx.serialization.json.Json
1214
import kotlinx.serialization.json.JsonObject
13-
import kotlinx.serialization.json.jsonObject
1415
import kotlinx.serialization.serializer
1516
import java.io.BufferedReader
1617

@@ -24,8 +25,8 @@ data class Settings(
2425
name: String,
2526
strategy: DeserializationStrategy<T> = Json.serializersModule.serializer()
2627
): T? {
27-
val integrationData = integrations[name]?.jsonObject ?: return null
28-
val typedSettings = Json.decodeFromJsonElement(strategy, integrationData)
28+
val integrationData = integrations[name]?.safeJsonObject ?: return null
29+
val typedSettings = LenientJson.decodeFromJsonElement(strategy, integrationData)
2930
return typedSettings
3031
}
3132

@@ -61,7 +62,7 @@ fun Analytics.checkSettings() {
6162
val settingsString =
6263
connection.inputStream?.bufferedReader()?.use(BufferedReader::readText) ?: ""
6364
log("Fetched Settings: $settingsString")
64-
Json { ignoreUnknownKeys = true }.decodeFromString(settingsString)
65+
LenientJson.decodeFromString(settingsString)
6566
} catch (ex: Exception) {
6667
log(message = "${ex.message}: failed to fetch settings", type = LogType.ERROR)
6768
null

core/src/main/java/com/segment/analytics/kotlin/core/platform/plugins/Metrics.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package com.segment.analytics.kotlin.core.platform.plugins
22

33
import com.segment.analytics.kotlin.core.BaseEvent
44
import com.segment.analytics.kotlin.core.DateSerializer
5+
import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson
56
import com.segment.analytics.kotlin.core.utilities.putInContext
7+
import com.segment.analytics.kotlin.core.utilities.safeJsonArray
68
import kotlinx.serialization.Serializable
7-
import kotlinx.serialization.json.Json
89
import kotlinx.serialization.json.buildJsonArray
9-
import kotlinx.serialization.json.jsonArray
1010
import java.time.Instant
1111

1212
enum class MetricType(val type: Int) {
@@ -41,10 +41,10 @@ fun BaseEvent.addMetric(
4141
)
4242

4343
val metrics = buildJsonArray {
44-
context["metrics"]?.jsonArray?.forEach {
44+
context["metrics"]?.safeJsonArray?.forEach {
4545
add(it)
4646
}
47-
add(Json { encodeDefaults = true }.encodeToJsonElement(Metric.serializer(), metric))
47+
add(EncodeDefaultsJson.encodeToJsonElement(Metric.serializer(), metric))
4848
}
4949

5050
putInContext("metrics", metrics)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
@file:JvmName("Base64Utils")
12
package com.segment.analytics.kotlin.core.utilities
23

34
// Encode string to base64

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import kotlinx.serialization.SerializationStrategy
66
import kotlinx.serialization.json.Json
77
import kotlinx.serialization.json.JsonObject
88
import kotlinx.serialization.json.buildJsonObject
9-
import kotlinx.serialization.json.jsonObject
109
import kotlinx.serialization.serializer
1110

1211
// Mark integration as enabled, for this event
@@ -60,7 +59,7 @@ fun <T : Any> BaseEvent.putInContextUnderKey(
6059
value: T,
6160
serializationStrategy: SerializationStrategy<T>
6261
): BaseEvent {
63-
val parent = context[parentKey]?.jsonObject ?: emptyJsonObject
62+
val parent: JsonObject = context[parentKey]?.safeJsonObject ?: emptyJsonObject
6463
context = buildJsonObject {
6564
putAll(context)
6665
val newParent = buildJsonObject {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
@file:JvmName("FileUtils")
12
package com.segment.analytics.kotlin.core.utilities
23

34
import java.io.File

0 commit comments

Comments
 (0)