Skip to content

Commit

Permalink
Create thanos work
Browse files Browse the repository at this point in the history
Add tests
  • Loading branch information
Serchinastico committed Mar 15, 2019
1 parent 9fc98ea commit 38ac427
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,29 @@ import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
import com.karumi.jetpack.superheroes.R
import com.karumi.jetpack.superheroes.SuperHeroesApplication
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.mock
import org.junit.Before
import org.junit.runner.RunWith
import org.kodein.di.Kodein
import org.kodein.di.erased.bind
import org.kodein.di.erased.instance
import org.mockito.MockitoAnnotations
import java.util.concurrent.ExecutorService
import java.util.concurrent.FutureTask
import java.util.concurrent.Executor

@LargeTest
@RunWith(AndroidJUnit4::class)
abstract class FragmentTest<F : Fragment> : ScreenshotTest {

abstract val fragmentBlock: () -> F

private val executorServiceOnUiThread = mock<ExecutorService> {
on(it.execute(any())).thenAnswer { invocation ->
InstrumentationRegistry.getInstrumentation().runOnMainSync {
(invocation.getArgument(0) as Runnable).run()
}
FutureTask { null }
}
}

@Before
fun setup() {
MockitoAnnotations.initMocks(this)
val app = ApplicationProvider.getApplicationContext<SuperHeroesApplication>()
app.override(Kodein.Module("Base test dependencies", allowSilentOverride = true) {
import(testDependencies, allowOverride = true)
bind<ExecutorService>() with instance(executorServiceOnUiThread)
bind<Executor>() with instance(Executor {
InstrumentationRegistry.getInstrumentation().runOnMainSync { it.run() }
})
})
}

Expand Down
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 {
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()
}
}

0 comments on commit 38ac427

Please sign in to comment.