Merge pull request #8839 from element-hq/feature/bca/add_platformcode_to_posthog
Support reporting super properties to posthog (appPlatform)
This commit is contained in:
commit
47bb23a654
|
@ -0,0 +1 @@
|
||||||
|
Posthog | report platform code for EA
|
|
@ -147,5 +147,12 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
|
||||||
fun getSdkVersion(): String {
|
fun getSdkVersion(): String {
|
||||||
return BuildConfig.SDK_VERSION + " (" + BuildConfig.GIT_SDK_REVISION + ")"
|
return BuildConfig.SDK_VERSION + " (" + BuildConfig.GIT_SDK_REVISION + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getCryptoVersion(longFormat: Boolean): String {
|
||||||
|
val version = org.matrix.rustcomponents.sdk.crypto.version()
|
||||||
|
val gitHash = org.matrix.rustcomponents.sdk.crypto.versionInfo().gitSha
|
||||||
|
val vodozemac = org.matrix.rustcomponents.sdk.crypto.vodozemacVersion()
|
||||||
|
return if (longFormat) "Rust SDK $version ($gitHash), Vodozemac $vodozemac" else version
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.api.session.crypto
|
package org.matrix.android.sdk.api.session.crypto
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.annotation.Size
|
import androidx.annotation.Size
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.paging.PagedList
|
import androidx.paging.PagedList
|
||||||
|
@ -61,8 +60,6 @@ interface CryptoService {
|
||||||
|
|
||||||
suspend fun deleteDevices(@Size(min = 1) deviceIds: List<String>, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor)
|
suspend fun deleteDevices(@Size(min = 1) deviceIds: List<String>, userInteractiveAuthInterceptor: UserInteractiveAuthInterceptor)
|
||||||
|
|
||||||
fun getCryptoVersion(context: Context, longFormat: Boolean): String
|
|
||||||
|
|
||||||
fun isCryptoEnabled(): Boolean
|
fun isCryptoEnabled(): Boolean
|
||||||
|
|
||||||
fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean
|
fun isRoomBlacklistUnverifiedDevices(roomId: String?): Boolean
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto
|
package org.matrix.android.sdk.internal.crypto
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.map
|
import androidx.lifecycle.map
|
||||||
import androidx.paging.PagedList
|
import androidx.paging.PagedList
|
||||||
|
@ -184,13 +183,6 @@ internal class RustCryptoService @Inject constructor(
|
||||||
deleteDevices(listOf(deviceId), userInteractiveAuthInterceptor)
|
deleteDevices(listOf(deviceId), userInteractiveAuthInterceptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCryptoVersion(context: Context, longFormat: Boolean): String {
|
|
||||||
val version = org.matrix.rustcomponents.sdk.crypto.version()
|
|
||||||
val gitHash = org.matrix.rustcomponents.sdk.crypto.versionInfo().gitSha
|
|
||||||
val vodozemac = org.matrix.rustcomponents.sdk.crypto.vodozemacVersion()
|
|
||||||
return if (longFormat) "Rust SDK $version ($gitHash), Vodozemac $vodozemac" else version
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getMyCryptoDevice(): CryptoDeviceInfo = withContext(coroutineDispatchers.io) {
|
override suspend fun getMyCryptoDevice(): CryptoDeviceInfo = withContext(coroutineDispatchers.io) {
|
||||||
olmMachine.ownDevice()
|
olmMachine.ownDevice()
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ import im.vector.app.core.pushers.FcmHelper
|
||||||
import im.vector.app.core.resources.BuildMeta
|
import im.vector.app.core.resources.BuildMeta
|
||||||
import im.vector.app.features.analytics.DecryptionFailureTracker
|
import im.vector.app.features.analytics.DecryptionFailureTracker
|
||||||
import im.vector.app.features.analytics.VectorAnalytics
|
import im.vector.app.features.analytics.VectorAnalytics
|
||||||
|
import im.vector.app.features.analytics.plan.SuperProperties
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
import im.vector.app.features.configuration.VectorConfiguration
|
import im.vector.app.features.configuration.VectorConfiguration
|
||||||
import im.vector.app.features.invite.InvitesAcceptor
|
import im.vector.app.features.invite.InvitesAcceptor
|
||||||
|
@ -130,6 +131,13 @@ class VectorApplication :
|
||||||
appContext = this
|
appContext = this
|
||||||
flipperProxy.init(matrix)
|
flipperProxy.init(matrix)
|
||||||
vectorAnalytics.init()
|
vectorAnalytics.init()
|
||||||
|
vectorAnalytics.updateSuperProperties(
|
||||||
|
SuperProperties(
|
||||||
|
appPlatform = SuperProperties.AppPlatform.EA,
|
||||||
|
cryptoSDK = SuperProperties.CryptoSDK.Rust,
|
||||||
|
cryptoSDKVersion = Matrix.getCryptoVersion(longFormat = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
invitesAcceptor.initialize()
|
invitesAcceptor.initialize()
|
||||||
autoRageShaker.initialize()
|
autoRageShaker.initialize()
|
||||||
decryptionFailureTracker.start()
|
decryptionFailureTracker.start()
|
||||||
|
|
|
@ -160,7 +160,7 @@ dependencies {
|
||||||
api 'com.facebook.stetho:stetho:1.6.0'
|
api 'com.facebook.stetho:stetho:1.6.0'
|
||||||
|
|
||||||
// Analytics
|
// Analytics
|
||||||
api 'com.github.matrix-org:matrix-analytics-events:0.15.0'
|
api 'com.github.matrix-org:matrix-analytics-events:0.23.0'
|
||||||
|
|
||||||
api libs.google.phonenumber
|
api libs.google.phonenumber
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ import im.vector.app.core.dispatchers.CoroutineDispatchers
|
||||||
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
|
import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
|
||||||
import im.vector.app.core.services.GuardServiceStarter
|
import im.vector.app.core.services.GuardServiceStarter
|
||||||
import im.vector.app.core.session.ConfigureAndStartSessionUseCase
|
import im.vector.app.core.session.ConfigureAndStartSessionUseCase
|
||||||
import im.vector.app.features.analytics.DecryptionFailureTracker
|
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
||||||
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
||||||
|
@ -57,7 +56,6 @@ class ActiveSessionHolder @Inject constructor(
|
||||||
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
|
private val unregisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
|
||||||
private val applicationCoroutineScope: CoroutineScope,
|
private val applicationCoroutineScope: CoroutineScope,
|
||||||
private val coroutineDispatchers: CoroutineDispatchers,
|
private val coroutineDispatchers: CoroutineDispatchers,
|
||||||
private val decryptionFailureTracker: DecryptionFailureTracker,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private var activeSessionReference: AtomicReference<Session?> = AtomicReference()
|
private var activeSessionReference: AtomicReference<Session?> = AtomicReference()
|
||||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.analytics
|
||||||
|
|
||||||
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
||||||
|
import im.vector.app.features.analytics.plan.SuperProperties
|
||||||
import im.vector.app.features.analytics.plan.UserProperties
|
import im.vector.app.features.analytics.plan.UserProperties
|
||||||
|
|
||||||
interface AnalyticsTracker {
|
interface AnalyticsTracker {
|
||||||
|
@ -35,4 +36,10 @@ interface AnalyticsTracker {
|
||||||
* Update user specific properties.
|
* Update user specific properties.
|
||||||
*/
|
*/
|
||||||
fun updateUserProperties(userProperties: UserProperties)
|
fun updateUserProperties(userProperties: UserProperties)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the super properties.
|
||||||
|
* Super properties are added to any tracked event automatically.
|
||||||
|
*/
|
||||||
|
fun updateSuperProperties(updatedProperties: SuperProperties)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import im.vector.app.features.analytics.VectorAnalytics
|
||||||
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
|
||||||
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
|
||||||
import im.vector.app.features.analytics.log.analyticsTag
|
import im.vector.app.features.analytics.log.analyticsTag
|
||||||
|
import im.vector.app.features.analytics.plan.SuperProperties
|
||||||
import im.vector.app.features.analytics.plan.UserProperties
|
import im.vector.app.features.analytics.plan.UserProperties
|
||||||
import im.vector.app.features.analytics.store.AnalyticsStore
|
import im.vector.app.features.analytics.store.AnalyticsStore
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -63,6 +64,8 @@ class DefaultVectorAnalytics @Inject constructor(
|
||||||
// Cache for the properties to send
|
// Cache for the properties to send
|
||||||
private var pendingUserProperties: UserProperties? = null
|
private var pendingUserProperties: UserProperties? = null
|
||||||
|
|
||||||
|
private var superProperties: SuperProperties? = null
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
observeUserConsent()
|
observeUserConsent()
|
||||||
observeAnalyticsId()
|
observeAnalyticsId()
|
||||||
|
@ -168,20 +171,14 @@ class DefaultVectorAnalytics @Inject constructor(
|
||||||
|
|
||||||
override fun capture(event: VectorAnalyticsEvent) {
|
override fun capture(event: VectorAnalyticsEvent) {
|
||||||
Timber.tag(analyticsTag.value).d("capture($event)")
|
Timber.tag(analyticsTag.value).d("capture($event)")
|
||||||
posthog
|
posthog?.takeIf { userConsent == true }?.capture(
|
||||||
?.takeIf { userConsent == true }
|
event.getName(), analyticsId, event.getProperties()?.toPostHogProperties().orEmpty().withSuperProperties()
|
||||||
?.capture(
|
|
||||||
event.getName(),
|
|
||||||
analyticsId,
|
|
||||||
event.getProperties()?.toPostHogProperties()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun screen(screen: VectorAnalyticsScreen) {
|
override fun screen(screen: VectorAnalyticsScreen) {
|
||||||
Timber.tag(analyticsTag.value).d("screen($screen)")
|
Timber.tag(analyticsTag.value).d("screen($screen)")
|
||||||
posthog
|
posthog?.takeIf { userConsent == true }?.screen(screen.getName(), screen.getProperties()?.toPostHogProperties().orEmpty().withSuperProperties())
|
||||||
?.takeIf { userConsent == true }
|
|
||||||
?.screen(screen.getName(), screen.getProperties()?.toPostHogProperties())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateUserProperties(userProperties: UserProperties) {
|
override fun updateUserProperties(userProperties: UserProperties) {
|
||||||
|
@ -195,9 +192,7 @@ class DefaultVectorAnalytics @Inject constructor(
|
||||||
private fun doUpdateUserProperties(userProperties: UserProperties) {
|
private fun doUpdateUserProperties(userProperties: UserProperties) {
|
||||||
// we need a distinct id to set user properties
|
// we need a distinct id to set user properties
|
||||||
val distinctId = analyticsId ?: return
|
val distinctId = analyticsId ?: return
|
||||||
posthog
|
posthog?.takeIf { userConsent == true }?.identify(distinctId, userProperties.getProperties())
|
||||||
?.takeIf { userConsent == true }
|
|
||||||
?.identify(distinctId, userProperties.getProperties())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Map<String, Any?>?.toPostHogProperties(): Map<String, Any>? {
|
private fun Map<String, Any?>?.toPostHogProperties(): Map<String, Any>? {
|
||||||
|
@ -226,9 +221,32 @@ class DefaultVectorAnalytics @Inject constructor(
|
||||||
return nonNulls
|
return nonNulls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds super properties to the actual property set.
|
||||||
|
* If a property of the same name is already on the reported event it will not be overwritten.
|
||||||
|
*/
|
||||||
|
private fun Map<String, Any>.withSuperProperties(): Map<String, Any>? {
|
||||||
|
val withSuperProperties = this.toMutableMap()
|
||||||
|
val superProperties = this@DefaultVectorAnalytics.superProperties?.getProperties()
|
||||||
|
superProperties?.forEach {
|
||||||
|
if (!withSuperProperties.containsKey(it.key)) {
|
||||||
|
withSuperProperties[it.key] = it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return withSuperProperties.takeIf { it.isEmpty().not() }
|
||||||
|
}
|
||||||
|
|
||||||
override fun trackError(throwable: Throwable) {
|
override fun trackError(throwable: Throwable) {
|
||||||
sentryAnalytics
|
sentryAnalytics
|
||||||
.takeIf { userConsent == true }
|
.takeIf { userConsent == true }
|
||||||
?.trackError(throwable)
|
?.trackError(throwable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateSuperProperties(updatedProperties: SuperProperties) {
|
||||||
|
this.superProperties = SuperProperties(
|
||||||
|
cryptoSDK = updatedProperties.cryptoSDK ?: this.superProperties?.cryptoSDK,
|
||||||
|
appPlatform = updatedProperties.appPlatform ?: this.superProperties?.appPlatform,
|
||||||
|
cryptoSDKVersion = updatedProperties.cryptoSDKVersion ?: superProperties?.cryptoSDKVersion
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,7 +265,7 @@ class BugReporter @Inject constructor(
|
||||||
activeSessionHolder.getSafeActiveSession()?.let { session ->
|
activeSessionHolder.getSafeActiveSession()?.let { session ->
|
||||||
userId = session.myUserId
|
userId = session.myUserId
|
||||||
deviceId = session.sessionParams.deviceId
|
deviceId = session.sessionParams.deviceId
|
||||||
olmVersion = session.cryptoService().getCryptoVersion(context, true)
|
olmVersion = Matrix.getCryptoVersion(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mIsCancelled) {
|
if (!mIsCancelled) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ class VectorSettingsHelpAboutFragment :
|
||||||
|
|
||||||
// olm version
|
// olm version
|
||||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTO_VERSION_PREFERENCE_KEY)!!
|
findPreference<VectorPreference>(VectorPreferences.SETTINGS_CRYPTO_VERSION_PREFERENCE_KEY)!!
|
||||||
.summary = session.cryptoService().getCryptoVersion(requireContext(), true)
|
.summary = Matrix.getCryptoVersion(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.app.features.analytics.impl
|
package im.vector.app.features.analytics.impl
|
||||||
|
|
||||||
|
import im.vector.app.features.analytics.plan.SuperProperties
|
||||||
import im.vector.app.test.fakes.FakeAnalyticsStore
|
import im.vector.app.test.fakes.FakeAnalyticsStore
|
||||||
import im.vector.app.test.fakes.FakeLateInitUserPropertiesFactory
|
import im.vector.app.test.fakes.FakeLateInitUserPropertiesFactory
|
||||||
import im.vector.app.test.fakes.FakePostHog
|
import im.vector.app.test.fakes.FakePostHog
|
||||||
|
@ -51,7 +52,7 @@ class DefaultVectorAnalyticsTest {
|
||||||
analyticsStore = fakeAnalyticsStore.instance,
|
analyticsStore = fakeAnalyticsStore.instance,
|
||||||
globalScope = CoroutineScope(Dispatchers.Unconfined),
|
globalScope = CoroutineScope(Dispatchers.Unconfined),
|
||||||
analyticsConfig = anAnalyticsConfig(isEnabled = true),
|
analyticsConfig = anAnalyticsConfig(isEnabled = true),
|
||||||
lateInitUserPropertiesFactory = fakeLateInitUserPropertiesFactory.instance
|
lateInitUserPropertiesFactory = fakeLateInitUserPropertiesFactory.instance,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -174,6 +175,117 @@ class DefaultVectorAnalyticsTest {
|
||||||
fakeSentryAnalytics.verifyNoErrorTracking()
|
fakeSentryAnalytics.verifyNoErrorTracking()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Super properties should be added to all captured events`() = runTest {
|
||||||
|
fakeAnalyticsStore.givenUserContent(consent = true)
|
||||||
|
|
||||||
|
val updatedProperties = SuperProperties(
|
||||||
|
appPlatform = SuperProperties.AppPlatform.EA,
|
||||||
|
cryptoSDKVersion = "0.0",
|
||||||
|
cryptoSDK = SuperProperties.CryptoSDK.Rust
|
||||||
|
)
|
||||||
|
|
||||||
|
defaultVectorAnalytics.updateSuperProperties(updatedProperties)
|
||||||
|
|
||||||
|
val fakeEvent = aVectorAnalyticsEvent("THE_NAME", mutableMapOf("foo" to "bar"))
|
||||||
|
defaultVectorAnalytics.capture(fakeEvent)
|
||||||
|
|
||||||
|
fakePostHog.verifyEventTracked(
|
||||||
|
"THE_NAME",
|
||||||
|
fakeEvent.getProperties().clearNulls()?.toMutableMap()?.apply {
|
||||||
|
updatedProperties.getProperties()?.let { putAll(it) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check with a screen event
|
||||||
|
val fakeScreen = aVectorAnalyticsScreen("Screen", mutableMapOf("foo" to "bar"))
|
||||||
|
defaultVectorAnalytics.screen(fakeScreen)
|
||||||
|
|
||||||
|
fakePostHog.verifyScreenTracked(
|
||||||
|
"Screen",
|
||||||
|
fakeScreen.getProperties().clearNulls()?.toMutableMap()?.apply {
|
||||||
|
updatedProperties.getProperties()?.let { putAll(it) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Super properties can be updated`() = runTest {
|
||||||
|
fakeAnalyticsStore.givenUserContent(consent = true)
|
||||||
|
|
||||||
|
val superProperties = SuperProperties(
|
||||||
|
appPlatform = SuperProperties.AppPlatform.EA,
|
||||||
|
cryptoSDKVersion = "0.0",
|
||||||
|
cryptoSDK = SuperProperties.CryptoSDK.Rust
|
||||||
|
)
|
||||||
|
|
||||||
|
defaultVectorAnalytics.updateSuperProperties(superProperties)
|
||||||
|
|
||||||
|
val fakeEvent = aVectorAnalyticsEvent("THE_NAME", mutableMapOf("foo" to "bar"))
|
||||||
|
defaultVectorAnalytics.capture(fakeEvent)
|
||||||
|
|
||||||
|
fakePostHog.verifyEventTracked(
|
||||||
|
"THE_NAME",
|
||||||
|
fakeEvent.getProperties().clearNulls()?.toMutableMap()?.apply {
|
||||||
|
superProperties.getProperties()?.let { putAll(it) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val superPropertiesUpdate = superProperties.copy(cryptoSDKVersion = "1.0")
|
||||||
|
defaultVectorAnalytics.updateSuperProperties(superPropertiesUpdate)
|
||||||
|
|
||||||
|
defaultVectorAnalytics.capture(fakeEvent)
|
||||||
|
|
||||||
|
fakePostHog.verifyEventTracked(
|
||||||
|
"THE_NAME",
|
||||||
|
fakeEvent.getProperties().clearNulls()?.toMutableMap()?.apply {
|
||||||
|
superPropertiesUpdate.getProperties()?.let { putAll(it) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Super properties should not override event property`() = runTest {
|
||||||
|
fakeAnalyticsStore.givenUserContent(consent = true)
|
||||||
|
|
||||||
|
val superProperties = SuperProperties(
|
||||||
|
cryptoSDKVersion = "0.0",
|
||||||
|
)
|
||||||
|
|
||||||
|
defaultVectorAnalytics.updateSuperProperties(superProperties)
|
||||||
|
|
||||||
|
val fakeEvent = aVectorAnalyticsEvent("THE_NAME", mutableMapOf("cryptoSDKVersion" to "XXX"))
|
||||||
|
defaultVectorAnalytics.capture(fakeEvent)
|
||||||
|
|
||||||
|
fakePostHog.verifyEventTracked(
|
||||||
|
"THE_NAME",
|
||||||
|
mapOf(
|
||||||
|
"cryptoSDKVersion" to "XXX"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Super properties should be added to event with no properties`() = runTest {
|
||||||
|
fakeAnalyticsStore.givenUserContent(consent = true)
|
||||||
|
|
||||||
|
val superProperties = SuperProperties(
|
||||||
|
cryptoSDKVersion = "0.0",
|
||||||
|
)
|
||||||
|
|
||||||
|
defaultVectorAnalytics.updateSuperProperties(superProperties)
|
||||||
|
|
||||||
|
val fakeEvent = aVectorAnalyticsEvent("THE_NAME", null)
|
||||||
|
defaultVectorAnalytics.capture(fakeEvent)
|
||||||
|
|
||||||
|
fakePostHog.verifyEventTracked(
|
||||||
|
"THE_NAME",
|
||||||
|
mapOf(
|
||||||
|
"cryptoSDKVersion" to "0.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun Map<String, Any?>?.clearNulls(): Map<String, Any>? {
|
private fun Map<String, Any?>?.clearNulls(): Map<String, Any>? {
|
||||||
if (this == null) return null
|
if (this == null) return null
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue