Skip to content

Remove FeatureExceptions.Store and all its implementations #5877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ annotation class ContributesRemoteFeature(
val settingsStore: KClass<*> = Unit::class,

/** The class that implements the [FeatureExceptions.Store] interface */
@Deprecated("Not needed anymore. Exceptions is now supported in top-level and sub-features and Toggle#getExceptions returns it")
val exceptionsStore: KClass<*> = Unit::class,

/** The class that implements the [Toggle.Store] interface */
Expand Down
20 changes: 0 additions & 20 deletions app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import android.content.pm.PackageManager
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
import androidx.room.Room
import androidx.work.WorkManager
import com.duckduckgo.adclick.api.AdClickManager
import com.duckduckgo.app.browser.*
Expand All @@ -45,9 +44,6 @@ import com.duckduckgo.app.browser.httperrors.HttpCodeSiteErrorHandlerImpl
import com.duckduckgo.app.browser.httperrors.StringSiteErrorHandler
import com.duckduckgo.app.browser.httperrors.StringSiteErrorHandlerImpl
import com.duckduckgo.app.browser.logindetection.*
import com.duckduckgo.app.browser.mediaplayback.store.ALL_MIGRATIONS
import com.duckduckgo.app.browser.mediaplayback.store.MediaPlaybackDao
import com.duckduckgo.app.browser.mediaplayback.store.MediaPlaybackDatabase
import com.duckduckgo.app.browser.pageloadpixel.PageLoadedPixelDao
import com.duckduckgo.app.browser.pageloadpixel.firstpaint.PagePaintedPixelDao
import com.duckduckgo.app.browser.refreshpixels.RefreshDao
Expand Down Expand Up @@ -339,22 +335,6 @@ class BrowserModule {
return appDatabase.pagePaintedPixelDao()
}

@Provides
@SingleInstanceIn(AppScope::class)
fun provideMediaPlaybackDatabase(context: Context): MediaPlaybackDatabase {
return Room.databaseBuilder(context, MediaPlaybackDatabase::class.java, "media_playback.db")
.enableMultiInstanceInvalidation()
.fallbackToDestructiveMigration()
.addMigrations(*ALL_MIGRATIONS)
.build()
}

@Provides
@SingleInstanceIn(AppScope::class)
fun providesMediaPlaybackDao(mediaPlaybackDatabase: MediaPlaybackDatabase): MediaPlaybackDao {
return mediaPlaybackDatabase.mediaPlaybackDao()
}

private val Context.indonesiaNewTabSectionDataStore: DataStore<Preferences> by preferencesDataStore(
name = "indonesia_new_tab_section_store",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@
package com.duckduckgo.app.browser.mediaplayback

import com.duckduckgo.anvil.annotations.ContributesRemoteFeature
import com.duckduckgo.app.browser.mediaplayback.store.MediaPlaybackStore
import com.duckduckgo.di.scopes.AppScope

@ContributesRemoteFeature(
scope = AppScope::class,
featureName = "mediaPlaybackRequiresUserGesture",
exceptionsStore = MediaPlaybackStore::class,
boundType = MediaPlaybackFeature::class,
)
@Suppress("unused")
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,57 @@

package com.duckduckgo.app.browser.mediaplayback.store

import com.duckduckgo.app.browser.mediaplayback.MediaPlaybackFeature
import com.duckduckgo.app.di.AppCoroutineScope
import com.duckduckgo.app.di.IsMainProcess
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.feature.toggles.api.FeatureExceptions
import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin
import com.squareup.anvil.annotations.ContributesBinding
import com.squareup.anvil.annotations.ContributesMultibinding
import dagger.SingleInstanceIn
import java.util.concurrent.CopyOnWriteArrayList
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

interface MediaPlaybackRepository {
fun updateAll(exceptions: List<MediaPlaybackExceptionEntity>)
val exceptions: CopyOnWriteArrayList<FeatureExceptions.FeatureException>
}

@ContributesBinding(AppScope::class)
@ContributesBinding(
scope = AppScope::class,
boundType = MediaPlaybackRepository::class,
)
@ContributesMultibinding(
scope = AppScope::class,
boundType = PrivacyConfigCallbackPlugin::class,
)
@SingleInstanceIn(AppScope::class)
class RealMediaPlaybackRepository @Inject constructor(
private val mediaPlaybackDao: MediaPlaybackDao,
@AppCoroutineScope appCoroutineScope: CoroutineScope,
dispatcherProvider: DispatcherProvider,
@IsMainProcess isMainProcess: Boolean,
) : MediaPlaybackRepository {
private val mediaPlaybackFeature: MediaPlaybackFeature,
@AppCoroutineScope private val appCoroutineScope: CoroutineScope,
private val dispatcherProvider: DispatcherProvider,
@IsMainProcess private val isMainProcess: Boolean,
) : MediaPlaybackRepository, PrivacyConfigCallbackPlugin {

override val exceptions = CopyOnWriteArrayList<FeatureExceptions.FeatureException>()

init {
appCoroutineScope.launch(dispatcherProvider.io()) {
if (isMainProcess) {
loadToMemory()
}
}
loadToMemory()
}

override fun updateAll(exceptions: List<MediaPlaybackExceptionEntity>) {
mediaPlaybackDao.updateAll(exceptions)
override fun onPrivacyConfigDownloaded() {
loadToMemory()
}

private fun loadToMemory() {
exceptions.clear()
mediaPlaybackDao.getAll().map {
exceptions.add(it.toFeatureException())
appCoroutineScope.launch(dispatcherProvider.io()) {
if (isMainProcess) {
exceptions.clear()
exceptions.addAll(mediaPlaybackFeature.self().getExceptions())
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,81 +1,56 @@
package com.duckduckgo.app.browser.mediaplayback.store

import com.duckduckgo.app.browser.mediaplayback.MediaPlaybackFeature
import com.duckduckgo.common.test.CoroutineTestRule
import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory
import com.duckduckgo.feature.toggles.api.FeatureExceptions.FeatureException
import com.duckduckgo.feature.toggles.api.Toggle
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentMatchers.anyList
import org.mockito.kotlin.mock
import org.mockito.kotlin.reset
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

class RealMediaPlaybackRepositoryTest {
@get:Rule
var coroutineRule = CoroutineTestRule()

lateinit var testee: RealMediaPlaybackRepository

private val mockMediaPlaybackDatabase: MediaPlaybackDatabase = mock()
private val mockMediaPlaybackDao: MediaPlaybackDao = mock()
private val mediaPlaybackFeature = FakeFeatureToggleFactory.create(MediaPlaybackFeature::class.java)

@Before
fun before() {
whenever(mockMediaPlaybackDatabase.mediaPlaybackDao()).thenReturn(mockMediaPlaybackDao)
initRepository()
mediaPlaybackFeature.self().setRawStoredState(Toggle.State(exceptions = exceptions))
}

@Test
fun whenRepositoryIsCreatedThenValuesLoadedIntoMemory() {
givenMediaPlaybackDaoContainsEntities()

initRepository()

assertEquals(mediaPlaybackExceptionEntity.toFeatureException(), testee.exceptions.first())
}

@Test
fun whenUpdateAllThenUpdateAllCalled() = runTest {
initRepository()

testee.updateAll(listOf())
val repository = RealMediaPlaybackRepository(
mediaPlaybackFeature,
TestScope(),
coroutineRule.testDispatcherProvider,
isMainProcess = true,
)

verify(mockMediaPlaybackDao).updateAll(anyList())
assertEquals(exceptions, repository.exceptions)
}

@Test
fun whenUpdateAllThenPreviousValuesAreClearedAndNewValuesUpdated() = runTest {
givenMediaPlaybackDaoContainsEntities()

initRepository()
assertEquals(1, testee.exceptions.size)

reset(mockMediaPlaybackDao)

testee.updateAll(listOf())

assertEquals(0, testee.exceptions.size)
}

private fun initRepository() {
testee = RealMediaPlaybackRepository(
mockMediaPlaybackDao,
fun whenRemoteConfigUpdateThenExceptionsUpdated() = runTest {
val repository = RealMediaPlaybackRepository(
mediaPlaybackFeature,
TestScope(),
coroutineRule.testDispatcherProvider,
isMainProcess = true,
)
}

private fun givenMediaPlaybackDaoContainsEntities() {
whenever(mockMediaPlaybackDao.getAll()).thenReturn(listOf(mediaPlaybackExceptionEntity))
assertEquals(exceptions, repository.exceptions)
mediaPlaybackFeature.self().setRawStoredState(Toggle.State(exceptions = emptyList()))
repository.onPrivacyConfigDownloaded()
assertEquals(emptyList<FeatureException>(), repository.exceptions)
}

companion object {
val mediaPlaybackExceptionEntity = MediaPlaybackExceptionEntity(
domain = "example.com",
)
val exceptions = listOf(FeatureException("example.com", "reason"))
}
}
Loading
Loading