From 8c38b239eb1d0d502d9bce58415d37cd2b15cdf5 Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Fri, 20 Feb 2026 11:27:52 -0500 Subject: [PATCH 1/2] Align e2e-cli types with sdk-e2e-tests definitions Add missing field extraction: timestamp, category, context, integrations. Wire timestamp, messageId, context, and integrations through to the Java SDK MessageBuilder for full fidelity. Co-Authored-By: Claude Opus 4.6 --- e2e-cli/src/main/kotlin/cli/Main.kt | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/e2e-cli/src/main/kotlin/cli/Main.kt b/e2e-cli/src/main/kotlin/cli/Main.kt index 6db10cbd..6642d38d 100644 --- a/e2e-cli/src/main/kotlin/cli/Main.kt +++ b/e2e-cli/src/main/kotlin/cli/Main.kt @@ -5,6 +5,10 @@ import com.google.gson.reflect.TypeToken import com.segment.analytics.Analytics import com.segment.analytics.Callback import com.segment.analytics.messages.* +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.TimeZone import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean @@ -107,14 +111,20 @@ fun sendEvent(analytics: Analytics, event: Map) { val userId = event["userId"] as? String ?: "" val anonymousId = event["anonymousId"] as? String val messageId = event["messageId"] as? String + val timestamp = event["timestamp"] as? String @Suppress("UNCHECKED_CAST") val traits = event["traits"] as? Map ?: emptyMap() @Suppress("UNCHECKED_CAST") val properties = event["properties"] as? Map ?: emptyMap() val eventName = event["event"] as? String val name = event["name"] as? String + val category = event["category"] as? String val groupId = event["groupId"] as? String val previousId = event["previousId"] as? String + @Suppress("UNCHECKED_CAST") + val context = event["context"] as? Map + @Suppress("UNCHECKED_CAST") + val integrations = event["integrations"] as? Map val messageBuilder: MessageBuilder<*, *> = when (type) { "identify" -> { @@ -154,6 +164,37 @@ fun sendEvent(analytics: Analytics, event: Map) { if (anonymousId != null) { messageBuilder.anonymousId(anonymousId) } + if (messageId != null) { + messageBuilder.messageId(messageId) + } + if (timestamp != null) { + messageBuilder.timestamp(parseTimestamp(timestamp)) + } + if (context != null) { + messageBuilder.context(context) + } + if (integrations != null) { + for ((key, value) in integrations) { + when (value) { + is Boolean -> messageBuilder.enableIntegration(key, value) + is Map<*, *> -> @Suppress("UNCHECKED_CAST") + messageBuilder.integrationOptions(key, value as Map) + } + } + } analytics.enqueue(messageBuilder) } + +private fun parseTimestamp(iso: String): Date { + val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US) + format.timeZone = TimeZone.getTimeZone("UTC") + return try { + format.parse(iso)!! + } catch (_: Exception) { + // Fallback: try without millis + val fallback = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US) + fallback.timeZone = TimeZone.getTimeZone("UTC") + fallback.parse(iso)!! + } +} From ceefb2aad37ecbc636a34b9fd80a194b82625b5f Mon Sep 17 00:00:00 2001 From: Michael Grosse Huelsewiesche Date: Thu, 26 Feb 2026 12:12:39 -0500 Subject: [PATCH 2/2] Replace SimpleDateFormat with java.time.Instant for timestamp parsing Instant.parse() handles all ISO 8601 formats natively, avoids deprecated SimpleDateFormat, and throws DateTimeParseException with clear context on invalid input instead of returning null. Co-Authored-By: Claude Opus 4.6 --- e2e-cli/src/main/kotlin/cli/Main.kt | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/e2e-cli/src/main/kotlin/cli/Main.kt b/e2e-cli/src/main/kotlin/cli/Main.kt index 6642d38d..b4577615 100644 --- a/e2e-cli/src/main/kotlin/cli/Main.kt +++ b/e2e-cli/src/main/kotlin/cli/Main.kt @@ -5,10 +5,8 @@ import com.google.gson.reflect.TypeToken import com.segment.analytics.Analytics import com.segment.analytics.Callback import com.segment.analytics.messages.* -import java.text.SimpleDateFormat +import java.time.Instant import java.util.Date -import java.util.Locale -import java.util.TimeZone import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean @@ -187,14 +185,5 @@ fun sendEvent(analytics: Analytics, event: Map) { } private fun parseTimestamp(iso: String): Date { - val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US) - format.timeZone = TimeZone.getTimeZone("UTC") - return try { - format.parse(iso)!! - } catch (_: Exception) { - // Fallback: try without millis - val fallback = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US) - fallback.timeZone = TimeZone.getTimeZone("UTC") - fallback.parse(iso)!! - } + return Date.from(Instant.parse(iso)) }