Skip to content

Commit

Permalink
tests: add tests for SendEvents usecase
Browse files Browse the repository at this point in the history
  • Loading branch information
wzieba committed Nov 11, 2023
1 parent debd023 commit 940b241
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import kotlinx.coroutines.launch
* Handles stopping and starting the flush timer. The flush timer
* controls how often we send events to Parse.ly servers.
*/
internal class FlushManager(
internal open class FlushManager(
private val parselyTracker: ParselyTracker,
val intervalMillis: Long,
private val coroutineScope: CoroutineScope
) {
private var job: Job? = null

fun start() {
open fun start() {
if (job?.isActive == true) return

job = coroutineScope.launch {
Expand All @@ -31,8 +31,8 @@ internal class FlushManager(
}
}

fun stop() = job?.cancel()
open fun stop() = job?.cancel()

val isRunning: Boolean
open val isRunning: Boolean
get() = job?.isActive ?: false
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal open class LocalStorageRepository(private val context: Context) {
}
}

suspend fun remove(toRemove: List<Map<String, Any?>?>) = mutex.withLock {
open suspend fun remove(toRemove: List<Map<String, Any?>?>) = mutex.withLock {
persistObject(getStoredQueue() - toRemove.toSet())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

internal class ParselyAPIConnection @JvmOverloads constructor(
internal open class ParselyAPIConnection @JvmOverloads constructor(
private val url: String,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) {
suspend fun send(payload: String): Result<Unit> {
open suspend fun send(payload: String): Result<Unit> {
return withContext(dispatcher) {
var connection: HttpURLConnection? = null
try {
Expand Down
206 changes: 206 additions & 0 deletions parsely/src/test/java/com/parsely/parselyandroid/SendEventsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package com.parsely.parselyandroid

import androidx.test.core.app.ApplicationProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(RobolectricTestRunner::class)
class SendEventsTest {

private lateinit var sut: SendEvents

@Test
fun `given empty local storage, when sending events, then do nothing`() =
runTest {
// given
sut = SendEvents(
FakeFlushManager(this),
FakeLocalStorageRepository(),
FakeParselyAPIConnection(),
this
)

// when
sut.invoke(false)
runCurrent()

// then
assertThat(FakeLocalStorageRepository().getStoredQueue()).isEmpty()
}

@Test
fun `given non-empty local storage and debug mode off, when sending events, then events are sent and removed from local storage`() =
runTest {
// given
val repository = FakeLocalStorageRepository().apply {
insertEvents(listOf(mapOf("test" to 123)))
}
val parselyAPIConnection = FakeParselyAPIConnection().apply {
nextResult = Result.success(Unit)
}
sut = SendEvents(
FakeFlushManager(this),
repository,
parselyAPIConnection,
this
)

// when
sut.invoke(false)
runCurrent()

// then
assertThat(repository.getStoredQueue()).isEmpty()
}

@Test
fun `given non-empty local storage and debug mode on, when sending events, then events are not sent and removed from local storage`() =
runTest {
// given
val repository = FakeLocalStorageRepository().apply {
insertEvents(listOf(mapOf("test" to 123)))
}
sut = SendEvents(
FakeFlushManager(this),
repository,
FakeParselyAPIConnection(),
this
)

// when
sut.invoke(true)
runCurrent()

// then
assertThat(repository.getStoredQueue()).isEmpty()
}

@Test
fun `given non-empty local storage and debug mode off, when sending events fails, then events are not removed from local storage`() =
runTest {
// given
val repository = FakeLocalStorageRepository().apply {
insertEvents(listOf(mapOf("test" to 123)))
}
val parselyAPIConnection = FakeParselyAPIConnection().apply {
nextResult = Result.failure(Exception())
}
sut = SendEvents(
FakeFlushManager(this),
repository,
parselyAPIConnection,
this
)

// when
sut.invoke(false)
runCurrent()

// then
assertThat(repository.getStoredQueue()).isNotEmpty
}

@Test
fun `given non-empty local storage and debug mode off, when sending events, then flush manager is stopped`() =
runTest {
// given
val flushManager = FakeFlushManager(this)
val repository = FakeLocalStorageRepository().apply {
insertEvents(listOf(mapOf("test" to 123)))
}
val parselyAPIConnection = FakeParselyAPIConnection().apply {
nextResult = Result.success(Unit)
}
sut = SendEvents(
flushManager,
repository,
parselyAPIConnection,
this
)

// when
sut.invoke(false)
runCurrent()

// then
assertThat(flushManager.stopped).isTrue
}

@Test
fun `given non-empty local storage and debug mode off, when sending events fails, then flush manager is not stopped`() =
runTest {
// given
val flushManager = FakeFlushManager(this)
val repository = FakeLocalStorageRepository().apply {
insertEvents(listOf(mapOf("test" to 123)))
}
val parselyAPIConnection = FakeParselyAPIConnection().apply {
nextResult = Result.failure(Exception())
}
sut = SendEvents(
flushManager,
repository,
parselyAPIConnection,
this
)

// when
sut.invoke(false)
runCurrent()

// then
assertThat(flushManager.stopped).isFalse
}

private class FakeFlushManager(scope: CoroutineScope) : FlushManager(FakeTracker(), 10, scope) {
var stopped = false

override fun stop() {
stopped = true
}
}

private class FakeTracker : ParselyTracker(
"siteId", 10, ApplicationProvider.getApplicationContext()
) {

var flushTimerStopped = false

override fun stopFlushTimer() {
flushTimerStopped = true
}
}

private class FakeLocalStorageRepository :
LocalStorageRepository(ApplicationProvider.getApplicationContext()) {
private var storage = emptyList<Map<String, Any?>?>()

override suspend fun insertEvents(toInsert: List<Map<String, Any?>?>) {
storage = storage + toInsert
}

override suspend fun remove(toRemove: List<Map<String, Any?>?>) {
storage = storage - toRemove.toSet()
}

override fun getStoredQueue(): ArrayList<Map<String, Any?>?> {
return ArrayList(storage)
}
}

private class FakeParselyAPIConnection : ParselyAPIConnection("") {

var nextResult: Result<Unit>? = null

override suspend fun send(payload: String): Result<Unit> {
return nextResult!!
}
}
}

0 comments on commit 940b241

Please sign in to comment.