-
Notifications
You must be signed in to change notification settings - Fork 1
Bind privacy settings and userInfo with the TracksTracker #118
Changes from all commits
da425d4
b246c15
8c30994
b09ff9e
4e4291b
389ef2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,6 @@ | ||
| package com.gravatar.analytics | ||
|
|
||
| abstract class Tracker { | ||
| abstract var userId: String? | ||
| abstract fun trackEvent(event: Event) | ||
| abstract fun flush() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.gravatar.analytics | ||
|
|
||
| data class TrackerSetupData( | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about the name. Any ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm not sure - do you have a strong preference for any of those? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like |
||
| val trackingState: TrackingState = TrackingState.ENABLED, | ||
| val userId: String? = null, | ||
| ) | ||
|
|
||
| enum class TrackingState { | ||
| ENABLED, | ||
| DISABLED, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.gravatar.analytics | ||
|
|
||
| import kotlinx.coroutines.flow.Flow | ||
|
|
||
| interface TrackerSetupDataProvider { | ||
| fun getTrackerSetupData(): Flow<TrackerSetupData> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.gravatar.app | ||
|
|
||
| import com.gravatar.analytics.TrackerSetupData | ||
| import com.gravatar.analytics.TrackerSetupDataProvider | ||
| import com.gravatar.analytics.TrackingState | ||
| import com.gravatar.app.usercomponent.domain.repository.UserRepository | ||
| import com.gravatar.app.usercomponent.domain.usecase.GetPrivacySettings | ||
| import kotlinx.coroutines.flow.Flow | ||
| import kotlinx.coroutines.flow.combine | ||
| import kotlinx.coroutines.flow.distinctUntilChanged | ||
| import kotlinx.coroutines.flow.map | ||
|
|
||
| class AppTrackerSetupDataProvider( | ||
| private val getPrivacySettings: GetPrivacySettings, | ||
| private val userRepository: UserRepository, | ||
| ) : TrackerSetupDataProvider { | ||
| override fun getTrackerSetupData(): Flow<TrackerSetupData> { | ||
| val userIdFlow: Flow<String?> = userRepository.getProfile().map { it?.userLogin }.distinctUntilChanged() | ||
| return getPrivacySettings() | ||
| .combine(userIdFlow) { privacySettings, userId -> | ||
| TrackerSetupData( | ||
| trackingState = if (privacySettings.analyticsEnabled) { | ||
| TrackingState.ENABLED | ||
| } else { | ||
| TrackingState.DISABLED | ||
| }, | ||
| userId = userId | ||
| ) | ||
| } | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,151 @@ | ||||
| package com.gravatar.app | ||||
|
|
||||
| import app.cash.turbine.test | ||||
| import com.gravatar.analytics.TrackerSetupData | ||||
| import com.gravatar.analytics.TrackingState | ||||
| import com.gravatar.app.testUtils.CoroutineTestRule | ||||
| import com.gravatar.app.usercomponent.domain.model.PrivacySettings | ||||
| import com.gravatar.app.usercomponent.domain.repository.UserRepository | ||||
| import com.gravatar.app.usercomponent.domain.usecase.GetPrivacySettings | ||||
| import com.gravatar.restapi.models.Profile | ||||
| import kotlinx.coroutines.ExperimentalCoroutinesApi | ||||
| import kotlinx.coroutines.flow.Flow | ||||
| import kotlinx.coroutines.flow.MutableSharedFlow | ||||
| import kotlinx.coroutines.test.StandardTestDispatcher | ||||
| import kotlinx.coroutines.test.runTest | ||||
| import org.junit.Assert.assertEquals | ||||
| import org.junit.Before | ||||
| import org.junit.Rule | ||||
| import org.junit.Test | ||||
| import java.net.URI | ||||
|
|
||||
| @OptIn(ExperimentalCoroutinesApi::class) | ||||
| class AppTrackerSetupDataProviderTest { | ||||
| private val testDispatcher = StandardTestDispatcher() | ||||
|
|
||||
| @get:Rule | ||||
| var coroutineTestRule = CoroutineTestRule(testDispatcher) | ||||
|
|
||||
| private lateinit var provider: AppTrackerSetupDataProvider | ||||
|
|
||||
| private lateinit var privacySettingsFlow: MutableSharedFlow<PrivacySettings> | ||||
| private lateinit var profileFlow: MutableSharedFlow<Profile?> | ||||
|
|
||||
| private val getPrivacySettings: GetPrivacySettings = object : GetPrivacySettings { | ||||
| override fun invoke() = privacySettingsFlow | ||||
| } | ||||
|
|
||||
| private val userRepository: UserRepository = object : UserRepository { | ||||
| override suspend fun refreshProfile(): Result<Unit> = throw NotImplementedError() | ||||
| override suspend fun selectAvatar(avatarId: String): Result<Unit> = throw NotImplementedError() | ||||
| override suspend fun getAvatars() = throw NotImplementedError() | ||||
| override fun getProfile(): Flow<Profile?> = profileFlow | ||||
| override suspend fun updateProfile( | ||||
| updateRequest: com.gravatar.restapi.models.UpdateProfileRequest | ||||
| ): Result<Unit> = | ||||
| throw NotImplementedError() | ||||
|
|
||||
| override suspend fun uploadAvatar(avatarFile: java.io.File) = throw NotImplementedError() | ||||
| override suspend fun deleteAvatar(avatarId: String): Result<Unit> = throw NotImplementedError() | ||||
| } | ||||
|
|
||||
| @Before | ||||
| fun setup() { | ||||
| privacySettingsFlow = MutableSharedFlow() | ||||
| profileFlow = MutableSharedFlow() | ||||
| provider = AppTrackerSetupDataProvider( | ||||
| getPrivacySettings = getPrivacySettings, | ||||
| userRepository = userRepository, | ||||
| ) | ||||
| } | ||||
|
|
||||
| @Test | ||||
| fun `emits ENABLED when analytics enabled and non-null user id`() = runTest { | ||||
| // Given | ||||
| val profile = createProfile("user") | ||||
|
|
||||
| provider.getTrackerSetupData().test { | ||||
| // When: emit both flows (combine requires both) | ||||
| privacySettingsFlow.emit(PrivacySettings(analyticsEnabled = true, crashReportingEnabled = true)) | ||||
| profileFlow.emit(profile) | ||||
|
|
||||
| // Then | ||||
| assertEquals(TrackerSetupData(TrackingState.ENABLED, "user"), awaitItem()) | ||||
| cancelAndIgnoreRemainingEvents() | ||||
| } | ||||
| } | ||||
|
|
||||
| @Test | ||||
| fun `emits DISABLED when analytics disabled and null user Id when profile is null`() = runTest { | ||||
| provider.getTrackerSetupData().test { | ||||
| // When | ||||
| privacySettingsFlow.emit(PrivacySettings(analyticsEnabled = false, crashReportingEnabled = true)) | ||||
| profileFlow.emit(null) | ||||
|
|
||||
| // Then | ||||
| assertEquals(TrackerSetupData(TrackingState.DISABLED, null), awaitItem()) | ||||
| cancelAndIgnoreRemainingEvents() | ||||
| } | ||||
| } | ||||
|
|
||||
| @Test | ||||
| fun `updates when privacy settings or user id changes and skips duplicate user id`() = runTest { | ||||
| // Given initial emissions | ||||
| val user1 = "user1" | ||||
| val user2 = "user2" | ||||
| val profile = createProfile(user1) | ||||
|
|
||||
| provider.getTrackerSetupData().test { | ||||
| privacySettingsFlow.emit(PrivacySettings(analyticsEnabled = true, crashReportingEnabled = true)) | ||||
| profileFlow.emit(profile) | ||||
|
|
||||
| // First combined emission | ||||
| assertEquals( | ||||
| TrackerSetupData(trackingState = TrackingState.ENABLED, userId = user1), | ||||
| awaitItem() | ||||
| ) | ||||
|
|
||||
| // When: change privacy to disabled => new emission expected | ||||
| privacySettingsFlow.emit(PrivacySettings(analyticsEnabled = false, crashReportingEnabled = true)) | ||||
| assertEquals( | ||||
| TrackerSetupData(trackingState = TrackingState.DISABLED, userId = user1), | ||||
| awaitItem() | ||||
| ) | ||||
|
|
||||
| // When: emit profile with same userId (1) => due to distinctUntilChanged on userIdFlow, no new emission from combine | ||||
| profileFlow.emit(profile) | ||||
| expectNoEvents() | ||||
|
|
||||
| // When: emit profile with new userId (2) => new emission expected | ||||
| val profile2 = createProfile(user2) | ||||
| profileFlow.emit(profile2) | ||||
| assertEquals( | ||||
| TrackerSetupData(trackingState = TrackingState.DISABLED, userId = user2), | ||||
| awaitItem() | ||||
| ) | ||||
|
|
||||
| cancelAndIgnoreRemainingEvents() | ||||
| } | ||||
| } | ||||
|
|
||||
| private fun createProfile(user: String): Profile { | ||||
| return Profile { | ||||
| firstName = "John" | ||||
| lastName = "Doe" | ||||
| displayName = "Johny" | ||||
| hash = "1234567890abcdef1234567890abcdef" | ||||
| location = "New York, USA" | ||||
| jobTitle = "Software Engineer" | ||||
| company = "Acme Inc." | ||||
| description = "A passionate software engineer with a love for coding and technology." | ||||
| verifiedAccounts = emptyList() | ||||
| profileUrl = URI.create("https://johndoe.com") | ||||
| avatarUrl = URI.create("https://www.gravatar.com/avatar/123") | ||||
| avatarAltText = "John Doe's Gravatar" | ||||
| pronouns = "he/him" | ||||
| pronunciation = "John Doe" | ||||
| verifiedAccounts = emptyList() | ||||
|
||||
| verifiedAccounts = emptyList() |
Uh oh!
There was an error while loading. Please reload this page.