diff --git a/embrace-android-sdk/api/embrace-android-sdk.api b/embrace-android-sdk/api/embrace-android-sdk.api index d051b84fce..12bdf2556a 100644 --- a/embrace-android-sdk/api/embrace-android-sdk.api +++ b/embrace-android-sdk/api/embrace-android-sdk.api @@ -178,6 +178,7 @@ public abstract interface annotation class io/embrace/android/embracesdk/annotat } public abstract interface class io/embrace/android/embracesdk/internal/EmbraceInternalInterface { + public abstract fun getSdkCurrentTime ()J public abstract fun isNetworkSpanForwardingEnabled ()Z public abstract fun logComposeTap (Landroid/util/Pair;Ljava/lang/String;)V public abstract fun logError (Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Z)V diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt index a5b33cac17..a4785c040f 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/EmbraceInternalInterfaceTest.kt @@ -92,6 +92,7 @@ internal class EmbraceInternalInterfaceTest { assertFalse(shouldCaptureNetworkBody("", "")) setProcessStartedByNotification() assertFalse(isNetworkSpanForwardingEnabled()) + getSdkCurrentTime() } } @@ -241,6 +242,16 @@ internal class EmbraceInternalInterfaceTest { } } + @Test + fun `test sdk time`() { + with(testRule) { + embrace.start(harness.fakeCoreModule.context) + assertEquals(harness.fakeClock.now(), embrace.internalInterface.getSdkCurrentTime()) + harness.fakeClock.tick() + assertEquals(harness.fakeClock.now(), embrace.internalInterface.getSdkCurrentTime()) + } + } + companion object { private const val URL = "https://embrace.io" private const val START_TIME = 1692201601L diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java index 5da8762084..d664ba6eae 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceImpl.java @@ -612,6 +612,7 @@ private void startImpl(@NonNull Context context, // initialize internal interfaces InternalInterfaceModuleImpl internalInterfaceModule = new InternalInterfaceModuleImpl( + initModule, coreModule, androidServicesModule, essentialServiceModule, diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImpl.kt index 08b65506bc..df71f0f4df 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImpl.kt @@ -1,6 +1,7 @@ package io.embrace.android.embracesdk import android.util.Pair +import io.embrace.android.embracesdk.injection.InitModule import io.embrace.android.embracesdk.internal.EmbraceInternalInterface import io.embrace.android.embracesdk.network.EmbraceNetworkRequest import io.embrace.android.embracesdk.network.http.HttpMethod @@ -8,7 +9,8 @@ import io.embrace.android.embracesdk.network.http.NetworkCaptureData import io.embrace.android.embracesdk.payload.TapBreadcrumb internal class EmbraceInternalInterfaceImpl( - private val embraceImpl: EmbraceImpl + private val embraceImpl: EmbraceImpl, + private val initModule: InitModule ) : EmbraceInternalInterface { override fun logInfo(message: String, properties: Map?) { @@ -173,4 +175,6 @@ internal class EmbraceInternalInterfaceImpl( override fun isNetworkSpanForwardingEnabled(): Boolean { return embraceImpl.configService?.networkSpanForwardingBehavior?.isNetworkSpanForwardingEnabled() ?: false } + + override fun getSdkCurrentTime(): Long = initModule.clock.now() } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/InternalInterfaceModule.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/InternalInterfaceModule.kt index 1b16a825eb..13527911c2 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/InternalInterfaceModule.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/InternalInterfaceModule.kt @@ -4,6 +4,7 @@ import io.embrace.android.embracesdk.injection.AndroidServicesModule import io.embrace.android.embracesdk.injection.CoreModule import io.embrace.android.embracesdk.injection.CrashModule import io.embrace.android.embracesdk.injection.EssentialServiceModule +import io.embrace.android.embracesdk.injection.InitModule import io.embrace.android.embracesdk.injection.singleton import io.embrace.android.embracesdk.internal.EmbraceInternalInterface @@ -15,6 +16,7 @@ internal interface InternalInterfaceModule { } internal class InternalInterfaceModuleImpl( + initModule: InitModule, coreModule: CoreModule, androidServicesModule: AndroidServicesModule, essentialServiceModule: EssentialServiceModule, @@ -23,7 +25,7 @@ internal class InternalInterfaceModuleImpl( ) : InternalInterfaceModule { override val embraceInternalInterface: EmbraceInternalInterface by singleton { - EmbraceInternalInterfaceImpl(embrace) + EmbraceInternalInterfaceImpl(embrace, initModule) } override val reactNativeInternalInterface: ReactNativeInternalInterface by singleton { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/EmbraceInternalInterface.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/EmbraceInternalInterface.kt index 15a3b4539a..e21964352b 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/EmbraceInternalInterface.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/EmbraceInternalInterface.kt @@ -126,6 +126,12 @@ public interface EmbraceInternalInterface { * Whether the Network Span Forwarding feature is enabled */ public fun isNetworkSpanForwardingEnabled(): Boolean + + /** + * Return internal time the SDK is using in milliseconds. It is equivalent to [System.currentTimeMillis] assuming the system clock did + * not change after the SDK has started. + */ + public fun getSdkCurrentTime(): Long } internal val defaultImpl = object : EmbraceInternalInterface { @@ -185,4 +191,6 @@ internal val defaultImpl = object : EmbraceInternalInterface { override fun setProcessStartedByNotification() { } override fun isNetworkSpanForwardingEnabled(): Boolean = false + + override fun getSdkCurrentTime(): Long = System.currentTimeMillis() } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImplTest.kt index cbe962a288..1a1b42eb98 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceInternalInterfaceImplTest.kt @@ -2,6 +2,10 @@ package io.embrace.android.embracesdk import android.net.Uri import android.webkit.URLUtil +import io.embrace.android.embracesdk.fakes.FakeClock +import io.embrace.android.embracesdk.fakes.injection.FakeInitModule +import io.embrace.android.embracesdk.injection.InitModule +import io.embrace.android.embracesdk.internal.defaultImpl import io.embrace.android.embracesdk.network.EmbraceNetworkRequest import io.embrace.android.embracesdk.network.http.HttpMethod import io.mockk.every @@ -11,6 +15,7 @@ import io.mockk.slot import io.mockk.verify import org.junit.Assert.assertEquals import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test @@ -18,11 +23,15 @@ internal class EmbraceInternalInterfaceImplTest { private lateinit var impl: EmbraceInternalInterfaceImpl private lateinit var embrace: EmbraceImpl + private lateinit var fakeClock: FakeClock + private lateinit var initModule: InitModule @Before fun setUp() { embrace = mockk(relaxed = true) - impl = EmbraceInternalInterfaceImpl(embrace) + fakeClock = FakeClock(currentTime = beforeObjectInitTime) + initModule = FakeInitModule(clock = fakeClock) + impl = EmbraceInternalInterfaceImpl(embrace, initModule) } @Test @@ -176,4 +185,22 @@ internal class EmbraceInternalInterfaceImplTest { assertEquals(url, captor.captured.url) } + + @Test + fun `check usage of SDK time`() { + assertEquals(beforeObjectInitTime, impl.getSdkCurrentTime()) + assertTrue(impl.getSdkCurrentTime() < System.currentTimeMillis()) + fakeClock.tick(10L) + assertEquals(fakeClock.now(), impl.getSdkCurrentTime()) + } + + @Test + fun `check default implementation`() { + assertTrue(beforeObjectInitTime < defaultImpl.getSdkCurrentTime()) + assertTrue(defaultImpl.getSdkCurrentTime() <= System.currentTimeMillis()) + } + + companion object { + val beforeObjectInitTime = System.currentTimeMillis() - 1 + } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/InternalInterfaceModuleImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/InternalInterfaceModuleImplTest.kt index d94f46a9fd..158ef66211 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/InternalInterfaceModuleImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/InternalInterfaceModuleImplTest.kt @@ -4,6 +4,7 @@ import io.embrace.android.embracesdk.fakes.injection.FakeAndroidServicesModule import io.embrace.android.embracesdk.fakes.injection.FakeCoreModule import io.embrace.android.embracesdk.fakes.injection.FakeCrashModule import io.embrace.android.embracesdk.fakes.injection.FakeEssentialServiceModule +import io.embrace.android.embracesdk.fakes.injection.FakeInitModule import org.junit.Assert.assertNotNull import org.junit.Test @@ -12,6 +13,7 @@ internal class InternalInterfaceModuleImplTest { @Test fun testModule() { val module: InternalInterfaceModule = InternalInterfaceModuleImpl( + FakeInitModule(), FakeCoreModule(), FakeAndroidServicesModule(), FakeEssentialServiceModule(),