-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from mvarnagiris/memory_cache
Memory cache
- Loading branch information
Showing
4 changed files
with
102 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.mvcoding.mvp | ||
|
||
interface DataSource<DATA> { | ||
fun data(): O<DATA> | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/kotlin/com/mvcoding/mvp/data/FunctionDataSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.mvcoding.mvp.data | ||
|
||
import com.mvcoding.mvp.DataSource | ||
import com.mvcoding.mvp.O | ||
|
||
class FunctionDataSource<DATA>(private val dataSource: () -> O<DATA>) : DataSource<DATA> { | ||
override fun data(): O<DATA> = dataSource() | ||
} | ||
|
||
fun <DATA> (() -> O<DATA>).dataSource() = FunctionDataSource(this) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.mvcoding.mvp.data | ||
|
||
import com.mvcoding.mvp.DataSource | ||
import com.mvcoding.mvp.O | ||
|
||
class MemoryDataSource<DATA>(dataSource: DataSource<DATA>) : DataSource<DATA> { | ||
constructor(dataSource: () -> O<DATA>) : this(dataSource.dataSource()) | ||
|
||
private val observable by lazy { dataSource.data().replay(1).autoConnect() } | ||
|
||
override fun data(): O<DATA> = observable | ||
} | ||
|
||
fun <DATA> DataSource<DATA>.memoryDataSource() = MemoryDataSource(this) | ||
fun <DATA> (() -> O<DATA>).memoryDataSource() = MemoryDataSource(this) |
72 changes: 72 additions & 0 deletions
72
src/test/kotlin/com/mvcoding/mvp/data/MemoryDataSourceTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package com.mvcoding.mvp.data | ||
|
||
import com.jakewharton.rxrelay2.PublishRelay | ||
import com.mvcoding.mvp.DataSource | ||
import com.nhaarman.mockitokotlin2.mock | ||
import com.nhaarman.mockitokotlin2.times | ||
import com.nhaarman.mockitokotlin2.verify | ||
import com.nhaarman.mockitokotlin2.whenever | ||
import io.reactivex.observers.TestObserver | ||
import org.junit.Test | ||
|
||
class MemoryDataSourceTest { | ||
|
||
@Test | ||
fun `upstream DataSource is called only once and cached data is returned to other observers`() { | ||
testUpstreamDataSourceIsCalledOnlyOnceAndCachedDataIsReturnedToOtherObservers(1) { it.memoryDataSource() } | ||
} | ||
|
||
@Test | ||
fun `returns data to late observers when initial observers are disposed before data is delivered`() { | ||
testReturnsDataToLateObserversWhenInitialObserversAreDisposedBeforeDataIsDelivered(1) { it.memoryDataSource() } | ||
} | ||
} | ||
|
||
fun <DATA> testMemoryDataSource(data: DATA, createDataSource: (DataSource<DATA>) -> DataSource<DATA>) { | ||
testUpstreamDataSourceIsCalledOnlyOnceAndCachedDataIsReturnedToOtherObservers(data, createDataSource) | ||
testReturnsDataToLateObserversWhenInitialObserversAreDisposedBeforeDataIsDelivered(data, createDataSource) | ||
} | ||
|
||
private fun <DATA> testUpstreamDataSourceIsCalledOnlyOnceAndCachedDataIsReturnedToOtherObservers( | ||
data: DATA, | ||
createDataSource: (DataSource<DATA>) -> DataSource<DATA>) { | ||
|
||
val initialObserver1 = TestObserver.create<DATA>() | ||
val initialObserver2 = TestObserver.create<DATA>() | ||
val otherObserver = TestObserver.create<DATA>() | ||
val relay = PublishRelay.create<DATA>() | ||
val upstreamDataSource = mock<DataSource<DATA>>() | ||
val dataSource = createDataSource(upstreamDataSource) | ||
whenever(upstreamDataSource.data()).thenReturn(relay) | ||
|
||
dataSource.data().subscribe(initialObserver1) | ||
dataSource.data().subscribe(initialObserver2) | ||
relay.accept(data) | ||
dataSource.data().subscribe(otherObserver) | ||
|
||
initialObserver1.assertValue(data) | ||
initialObserver2.assertValue(data) | ||
otherObserver.assertValue(data) | ||
verify(upstreamDataSource, times(1)).data() | ||
} | ||
|
||
private fun <DATA> testReturnsDataToLateObserversWhenInitialObserversAreDisposedBeforeDataIsDelivered( | ||
data: DATA, | ||
createDataSource: (DataSource<DATA>) -> DataSource<DATA>) { | ||
|
||
val initialObserver = TestObserver.create<DATA>() | ||
val otherObserver = TestObserver.create<DATA>() | ||
val relay = PublishRelay.create<DATA>() | ||
val upstreamDataSource = mock<DataSource<DATA>>() | ||
val dataSource = createDataSource(upstreamDataSource) | ||
whenever(upstreamDataSource.data()).thenReturn(relay) | ||
|
||
dataSource.data().subscribe(initialObserver) | ||
initialObserver.dispose() | ||
relay.accept(data) | ||
dataSource.data().subscribe(otherObserver) | ||
|
||
initialObserver.assertNoValues() | ||
otherObserver.assertValue(data) | ||
verify(upstreamDataSource, times(1)).data() | ||
} |