Skip to content
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

07-workmanager #14

Open
wants to merge 1 commit into
base: 06-navigation
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
@@ -0,0 +1,84 @@
package com.karumi.jetpack.superheroes.worker

import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.testing.WorkManagerTestInitHelper
import com.karumi.jetpack.superheroes.SuperHeroesApplication
import com.karumi.jetpack.superheroes.common.SuperHeroesDatabase
import com.karumi.jetpack.superheroes.data.repository.room.SuperHeroEntity
import com.karumi.jetpack.superheroes.domain.model.SuperHero
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.kodein.di.Kodein
import org.kodein.di.erased.bind
import org.kodein.di.erased.instance
import java.util.concurrent.Executor

class ThanosWorkerTest {

private lateinit var database: SuperHeroesDatabase

@Before
fun setUp() {
val app = ApplicationProvider.getApplicationContext<SuperHeroesApplication>()
WorkManagerTestInitHelper.initializeTestWorkManager(app)
database = Room.inMemoryDatabaseBuilder(app, SuperHeroesDatabase::class.java)
.allowMainThreadQueries()
.build()
app.override(Kodein.Module("Test dependencies", allowSilentOverride = true) {
bind<SuperHeroesDatabase>() with instance(database)
bind<Executor>() with instance(Executor {
getInstrumentation().runOnMainSync { it.run() }
})
})
database.superHeroesDao().deleteAll()
}

@Test
fun thanosWorkerDoNotDeleteAnyoneIfSuperHeroesAreLessThanTwo() {
val superHeroes = insertSuperHeroes(1)

enqueueWorker()

assertEquals(superHeroes, getInsertedSuperHeroes())
}

@Test
fun thanosWorkerDeletesHalfTheSuperHeroesWhenThereAreMoreThanTwo() {
insertSuperHeroes(10)

enqueueWorker()

assertEquals(5, getInsertedSuperHeroes().size)
}

@Test
fun thanosWorkerDeletesHalfTheSuperHeroesRoundingDownWhenThereIsAnOddNumberOfSuperHeroes() {
insertSuperHeroes(11)

enqueueWorker()

assertEquals(6, getInsertedSuperHeroes().size)
}

private fun enqueueWorker() = getInstrumentation().runOnMainSync {
val work = OneTimeWorkRequest.Builder(ThanosWorker::class.java).build()
WorkManager.getInstance().enqueue(work)
}

private fun insertSuperHeroes(numberOfSuperHeroes: Int): List<SuperHero> {
val superHeroes = (1..numberOfSuperHeroes)
.map { SuperHero("#$it", "SH $it", null, false, "") }

database.superHeroesDao().insertAll(superHeroes.map { SuperHeroEntity(it) })

return superHeroes
}

private fun getInsertedSuperHeroes(): List<SuperHero> =
database.superHeroesDao().getAllSuperHeroes().map { it.superHero }
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.karumi.jetpack.superheroes

import android.app.Application
import androidx.work.PeriodicWorkRequest
import androidx.work.PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
import androidx.work.WorkManager
import com.karumi.jetpack.superheroes.common.SuperHeroesDatabase
import com.karumi.jetpack.superheroes.common.module
import com.karumi.jetpack.superheroes.data.repository.LocalSuperHeroDataSource
import com.karumi.jetpack.superheroes.data.repository.RemoteSuperHeroDataSource
import com.karumi.jetpack.superheroes.data.repository.SuperHeroRepository
import com.karumi.jetpack.superheroes.data.repository.SuperHeroesBoundaryCallback
import com.karumi.jetpack.superheroes.data.repository.room.SuperHeroDao
import com.karumi.jetpack.superheroes.worker.ThanosWorker
import org.kodein.di.DKodein
import org.kodein.di.Kodein
import org.kodein.di.KodeinAware
Expand All @@ -16,15 +20,30 @@ import org.kodein.di.erased.bind
import org.kodein.di.erased.instance
import org.kodein.di.erased.provider
import org.kodein.di.erased.singleton
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executor
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

class SuperHeroesApplication : Application(), KodeinAware {
override var kodein = Kodein.lazy {
import(appDependencies())
import(androidModule(this@SuperHeroesApplication))
}

override fun onCreate() {
super.onCreate()
startThanosWork()
}

private fun startThanosWork() {
val work = PeriodicWorkRequest.Builder(
ThanosWorker::class.java,
MIN_PERIODIC_INTERVAL_MILLIS,
TimeUnit.MILLISECONDS
).build()
WorkManager.getInstance().enqueue(work)
}

fun override(overrideModule: Kodein.Module) {
kodein = Kodein.lazy {
import(appDependencies())
Expand Down Expand Up @@ -53,7 +72,7 @@ class SuperHeroesApplication : Application(), KodeinAware {
bind<RemoteSuperHeroDataSource>() with provider {
RemoteSuperHeroDataSource(instance())
}
bind<ExecutorService>() with provider {
davideme marked this conversation as resolved.
Show resolved Hide resolved
bind<Executor>() with provider {
Executors.newCachedThreadPool()
}
bind<DKodein>() with provider { this }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import androidx.paging.PagedList
import com.karumi.jetpack.superheroes.data.repository.room.SuperHeroDao
import com.karumi.jetpack.superheroes.data.repository.room.SuperHeroEntity
import com.karumi.jetpack.superheroes.domain.model.SuperHero
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executor

class LocalSuperHeroDataSource(
private val dao: SuperHeroDao,
private val executor: ExecutorService
private val executor: Executor
) {
fun getAllSuperHeroes(
pageSize: Int,
Expand All @@ -35,6 +35,8 @@ class LocalSuperHeroDataSource(
return superHero
}

fun deleteRandomHalf() = dao.deleteHalf()

private fun SuperHeroEntity.toSuperHero(): SuperHero = superHero
private fun SuperHero.toEntity(): SuperHeroEntity = SuperHeroEntity(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package com.karumi.jetpack.superheroes.data.repository
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.karumi.jetpack.superheroes.domain.model.SuperHero
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executor

class RemoteSuperHeroDataSource(
private val executor: ExecutorService
private val executor: Executor
) {
companion object {
private const val BIT_TIME = 1500L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update

@Dao
interface SuperHeroDao {
@Query("SELECT * FROM superheroes")
fun getAllSuperHeroes(): List<SuperHeroEntity>

@Query("SELECT * FROM superheroes ORDER BY superhero_id ASC")
fun getAll(): DataSource.Factory<Int, SuperHeroEntity>

Expand All @@ -24,4 +28,23 @@ interface SuperHeroDao {

@Query("DELETE FROM superheroes")
fun deleteAll()

@Query("DELETE FROM superheroes WHERE superhero_id IN (:ids)")
fun deleteAll(ids: List<String>)

@Transaction
fun deleteHalf() {
val superHeroes = getAllSuperHeroes()

if (superHeroes.size < 2) {
return
}

val randomSuperHeroIds = superHeroes
.shuffled()
.take(superHeroes.size / 2)
.map { it.superHero.id }

deleteAll(randomSuperHeroIds)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.karumi.jetpack.superheroes.worker

import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import com.karumi.jetpack.superheroes.data.repository.LocalSuperHeroDataSource
import org.kodein.di.KodeinAware
import org.kodein.di.android.closestKodein
import org.kodein.di.erased.instance

class ThanosWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params), KodeinAware {

override val kodein by closestKodein(context)
private val localSuperHeroesDataSource: LocalSuperHeroDataSource by instance()

override fun doWork(): Result {
localSuperHeroesDataSource.deleteRandomHalf()
return Result.success()
}
}