diff --git a/android/build.gradle b/android/build.gradle index fbee74a9..d82b6a5b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -32,9 +32,6 @@ android { } } compileOptions { - // Flag to enable support for the new language APIs - coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } @@ -59,7 +56,6 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-process:2.4.0' implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.0' - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' // TESTING testImplementation 'org.junit.jupiter:junit-jupiter:5.7.2' diff --git a/android/src/test/java/com/segment/analytics/kotlin/android/EventsFileTests.kt b/android/src/test/java/com/segment/analytics/kotlin/android/EventsFileTests.kt index 076dc135..6b39311f 100644 --- a/android/src/test/java/com/segment/analytics/kotlin/android/EventsFileTests.kt +++ b/android/src/test/java/com/segment/analytics/kotlin/android/EventsFileTests.kt @@ -6,6 +6,7 @@ import com.segment.analytics.kotlin.core.TrackEvent import com.segment.analytics.kotlin.core.emptyJsonObject import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson import com.segment.analytics.kotlin.core.utilities.EventsFileManager +import com.segment.analytics.kotlin.core.utilities.dateTimeNowString import io.mockk.every import io.mockk.mockkStatic import kotlinx.coroutines.test.runTest @@ -32,6 +33,8 @@ class EventsFileTests { init { mockkStatic(Instant::class) + mockkStatic(::dateTimeNowString) + every { dateTimeNowString() } returns Date(0).toInstant().toString() every { Instant.now() } returns Date(0).toInstant() } diff --git a/core/src/main/java/com/segment/analytics/kotlin/core/Events.kt b/core/src/main/java/com/segment/analytics/kotlin/core/Events.kt index cc1e0d55..86594a0a 100644 --- a/core/src/main/java/com/segment/analytics/kotlin/core/Events.kt +++ b/core/src/main/java/com/segment/analytics/kotlin/core/Events.kt @@ -1,16 +1,11 @@ package com.segment.analytics.kotlin.core +import com.segment.analytics.kotlin.core.utilities.dateTimeNowString import kotlinx.serialization.DeserializationStrategy -import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.* import sovran.kotlin.Store -import java.time.Instant import java.util.* typealias AnalyticsContext = JsonObject @@ -21,18 +16,6 @@ typealias Traits = JsonObject val emptyJsonObject = JsonObject(emptyMap()) val emptyJsonArray = JsonArray(emptyList()) -class DateSerializer : KSerializer { - override val descriptor = PrimitiveSerialDescriptor("Instant", PrimitiveKind.STRING) - - override fun deserialize(decoder: Decoder): Instant { - return Instant.parse(decoder.decodeString()) - } - - override fun serialize(encoder: Encoder, value: Instant) { - encoder.encodeString(value.toString()) - } -} - @Serializable data class DestinationMetadata( var bundled: List? = emptyList(), @@ -97,7 +80,7 @@ sealed class BaseEvent { } internal fun applyBaseData() { - this.timestamp = Instant.now().toString() + this.timestamp = dateTimeNowString() this.context = emptyJsonObject this.messageId = UUID.randomUUID().toString() } diff --git a/core/src/main/java/com/segment/analytics/kotlin/core/utilities/DateTimeUtils.kt b/core/src/main/java/com/segment/analytics/kotlin/core/utilities/DateTimeUtils.kt new file mode 100644 index 00000000..16d32f59 --- /dev/null +++ b/core/src/main/java/com/segment/analytics/kotlin/core/utilities/DateTimeUtils.kt @@ -0,0 +1,19 @@ +package com.segment.analytics.kotlin.core.utilities + +import java.text.SimpleDateFormat +import java.util.* + +/** + * This function is a replacement for Instant.now().toString(). It produces strings in a + * compatible format. + * + * Ex: + * Instant.now(): 2023-04-19T04:03:46.880969Z + * dateTimeNowString(): 2023-04-19T04:03:46.880Z + */ +fun dateTimeNowString(): String { + val sdf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'Szzz") + val utc = TimeZone.getTimeZone("UTC"); + sdf.timeZone = utc; + return sdf.format(Date()).replace("UTC", "Z") +} \ No newline at end of file diff --git a/core/src/main/java/com/segment/analytics/kotlin/core/utilities/EventsFileManager.kt b/core/src/main/java/com/segment/analytics/kotlin/core/utilities/EventsFileManager.kt index a810b19f..db758e54 100644 --- a/core/src/main/java/com/segment/analytics/kotlin/core/utilities/EventsFileManager.kt +++ b/core/src/main/java/com/segment/analytics/kotlin/core/utilities/EventsFileManager.kt @@ -3,7 +3,6 @@ package com.segment.analytics.kotlin.core.utilities import kotlinx.coroutines.sync.Semaphore import java.io.File import java.io.FileOutputStream -import java.time.Instant /** * Responsible for storing events in a batch payload style @@ -134,7 +133,9 @@ class EventsFileManager( return } // close events array and batch object - val contents = """],"sentAt":"${Instant.now()}","writeKey":"$writeKey"}""" + + + val contents = """],"sentAt":"${dateTimeNowString()}","writeKey":"$writeKey"}""" writeToFile(contents.toByteArray(), file) file.renameTo(File(directory, file.nameWithoutExtension)) os?.close() diff --git a/core/src/test/kotlin/com/segment/analytics/kotlin/core/AnalyticsTests.kt b/core/src/test/kotlin/com/segment/analytics/kotlin/core/AnalyticsTests.kt index 445ce2cf..ced41071 100644 --- a/core/src/test/kotlin/com/segment/analytics/kotlin/core/AnalyticsTests.kt +++ b/core/src/test/kotlin/com/segment/analytics/kotlin/core/AnalyticsTests.kt @@ -3,6 +3,7 @@ package com.segment.analytics.kotlin.core import com.segment.analytics.kotlin.core.platform.DestinationPlugin import com.segment.analytics.kotlin.core.platform.Plugin import com.segment.analytics.kotlin.core.platform.plugins.ContextPlugin +import com.segment.analytics.kotlin.core.utilities.dateTimeNowString import com.segment.analytics.kotlin.core.utils.StubPlugin import com.segment.analytics.kotlin.core.utils.TestRunPlugin import com.segment.analytics.kotlin.core.utils.clearPersistentStorage @@ -56,6 +57,8 @@ class AnalyticsTests { init { mockkStatic(Instant::class) every { Instant.now() } returns Date(0).toInstant() + mockkStatic(::dateTimeNowString) + every { dateTimeNowString() } returns Date(0).toInstant().toString() mockkStatic(UUID::class) every { UUID.randomUUID().toString() } returns "qwerty-qwerty-123" } diff --git a/core/src/test/kotlin/com/segment/analytics/kotlin/core/DateSerializerTests.kt b/core/src/test/kotlin/com/segment/analytics/kotlin/core/DateSerializerTests.kt deleted file mode 100644 index 96858e2c..00000000 --- a/core/src/test/kotlin/com/segment/analytics/kotlin/core/DateSerializerTests.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.segment.analytics.kotlin.core - -import kotlinx.serialization.json.Json -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import java.time.Instant - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -class DateSerializerTests { - @Test - fun `dates are properly serialized`() { - val d1 = Instant.EPOCH - val d2 = Instant.ofEpochSecond(1615918845) - val d3 = Instant.parse("2021-03-16T18:20:45Z") - assertEquals("1970-01-01T00:00:00Z".jsonified(), d1.serialize()) - assertEquals("2021-03-16T18:20:45Z".jsonified(), d2.serialize()) - assertEquals("2021-03-16T18:20:45Z".jsonified(), d3.serialize()) - } - - @Test - fun `dates are properly de-serialized`() { - val d1 = "1970-01-01T00:00:00Z".jsonified() - val d2 = "2021-03-16T18:20:45Z".jsonified() - val d3 = "2021-03-16T18:20:45.000Z".jsonified() - val d4 = "2021-03-16T18:20:45.000000000Z".jsonified() -// val d5 = "2021-03-16T20:20:45+02:00".jsonified() // Need to support offset date time - val d2Expected = Instant.ofEpochSecond(1615918845) - assertEquals(Instant.EPOCH, d1.deserialize()) - assertEquals(d2Expected, d2.deserialize()) - assertEquals(d2Expected, d3.deserialize()) - assertEquals(d2Expected, d4.deserialize()) - } - - private fun Instant.serialize(): String { - return Json.encodeToString(DateSerializer(), this) - } - - private fun String.deserialize(): Instant { - return Json.decodeFromString(DateSerializer(), this) - } - - private fun String.jsonified(): String { - return "\"$this\"" - } - -} diff --git a/core/src/test/kotlin/com/segment/analytics/kotlin/core/compat/JavaAnalyticsTest.kt b/core/src/test/kotlin/com/segment/analytics/kotlin/core/compat/JavaAnalyticsTest.kt index 6559809e..a58fc90e 100644 --- a/core/src/test/kotlin/com/segment/analytics/kotlin/core/compat/JavaAnalyticsTest.kt +++ b/core/src/test/kotlin/com/segment/analytics/kotlin/core/compat/JavaAnalyticsTest.kt @@ -15,6 +15,7 @@ import com.segment.analytics.kotlin.core.emptyJsonObject import com.segment.analytics.kotlin.core.platform.DestinationPlugin import com.segment.analytics.kotlin.core.platform.Plugin import com.segment.analytics.kotlin.core.platform.plugins.ContextPlugin +import com.segment.analytics.kotlin.core.utilities.dateTimeNowString import com.segment.analytics.kotlin.core.utils.StubPlugin import com.segment.analytics.kotlin.core.utils.TestRunPlugin import com.segment.analytics.kotlin.core.utils.mockHTTPClient @@ -62,6 +63,8 @@ internal class JavaAnalyticsTest { init { mockkStatic(Instant::class) every { Instant.now() } returns Date(0).toInstant() + mockkStatic(::dateTimeNowString) + every { dateTimeNowString() } returns Date(0).toInstant().toString() mockkStatic(UUID::class) every { UUID.randomUUID().toString() } returns "qwerty-qwerty-123" mockHTTPClient() diff --git a/core/src/test/kotlin/com/segment/analytics/kotlin/core/utilities/EventsFileManagerTest.kt b/core/src/test/kotlin/com/segment/analytics/kotlin/core/utilities/EventsFileManagerTest.kt index b0df419d..8843f3ca 100644 --- a/core/src/test/kotlin/com/segment/analytics/kotlin/core/utilities/EventsFileManagerTest.kt +++ b/core/src/test/kotlin/com/segment/analytics/kotlin/core/utilities/EventsFileManagerTest.kt @@ -26,6 +26,9 @@ internal class EventsFileManagerTest{ init { mockkStatic(Instant::class) every { Instant.now() } returns Date(0).toInstant() + + mockkStatic(::dateTimeNowString) + every { dateTimeNowString() } returns Date(0).toInstant().toString() } @BeforeEach