From 8dca8b719f634d06c86628f154b2ff45d1bd6c79 Mon Sep 17 00:00:00 2001 From: Levi Bostian Date: Wed, 8 Jun 2022 16:28:31 -0500 Subject: [PATCH] feat: delete expired background queue tasks --- .../base/extenstions/DateExtensions.kt | 5 + .../base/extensions/DateExtensionsTest.kt | 13 ++ .../java/io/customer/common_test/BaseTest.kt | 17 +- .../io/customer/common_test/DateUtilStub.kt | 10 +- .../util/DispatchersProviderStub.kt | 29 ++++ .../run Android tests.run.xml | 6 +- .../main/java/io/customer/sdk/CustomerIO.kt | 20 ++- .../java/io/customer/sdk/CustomerIOConfig.kt | 5 + .../io/customer/sdk/di/CustomerIOComponent.kt | 17 +- .../main/java/io/customer/sdk/di/DiGraph.kt | 31 ++++ .../main/java/io/customer/sdk/queue/Queue.kt | 15 +- .../io/customer/sdk/queue/QueueStorage.kt | 147 +++++++++++------- .../sdk/repository/CleanupRepository.kt | 19 +++ .../customer/sdk/util/DispatchersProvider.kt | 18 +++ .../main/java/io/customer/sdk/util/Seconds.kt | 7 +- .../java/io/customer/sdk/util/SimpleTimer.kt | 7 +- .../java/io/customer/sdk/util/Singleton.kt | 28 ---- .../java/io/customer/sdk/CustomerIOTest.kt | 20 +++ .../sdk/queue/QueueIntegrationTests.kt | 1 + .../sdk/queue/QueueStorageIntegrationTest.kt | 53 ++++++- .../java/io/customer/sdk/queue/QueueTest.kt | 2 +- .../java/io/customer/sdk/util/SecondsTest.kt | 10 ++ 22 files changed, 363 insertions(+), 117 deletions(-) create mode 100644 common-test/src/main/java/io/customer/common_test/util/DispatchersProviderStub.kt create mode 100644 sdk/src/main/java/io/customer/sdk/repository/CleanupRepository.kt create mode 100644 sdk/src/main/java/io/customer/sdk/util/DispatchersProvider.kt delete mode 100644 sdk/src/main/java/io/customer/sdk/util/Singleton.kt diff --git a/base/src/main/java/io/customer/base/extenstions/DateExtensions.kt b/base/src/main/java/io/customer/base/extenstions/DateExtensions.kt index 6904e4428..8f1aa1d73 100644 --- a/base/src/main/java/io/customer/base/extenstions/DateExtensions.kt +++ b/base/src/main/java/io/customer/base/extenstions/DateExtensions.kt @@ -18,6 +18,7 @@ fun Date.add(unit: Long, type: TimeUnit): Date { return Date(this.time + type.toMillis(unit)) } +fun Date.subtract(unit: Double, type: TimeUnit): Date = this.subtract(unit.toLong(), type) fun Date.subtract(unit: Int, type: TimeUnit): Date = this.subtract(unit.toLong(), type) fun Date.subtract(unit: Long, type: TimeUnit): Date { return Date(this.time - type.toMillis(unit)) @@ -26,3 +27,7 @@ fun Date.subtract(unit: Long, type: TimeUnit): Date { fun Date.hasPassed(): Boolean { return this.time < Date().time } + +fun Date.isOlderThan(otherDate: Date): Boolean { + return this.time < otherDate.time +} diff --git a/base/src/test/java/io/customer/base/extensions/DateExtensionsTest.kt b/base/src/test/java/io/customer/base/extensions/DateExtensionsTest.kt index 142f957b3..3dc653678 100644 --- a/base/src/test/java/io/customer/base/extensions/DateExtensionsTest.kt +++ b/base/src/test/java/io/customer/base/extensions/DateExtensionsTest.kt @@ -3,9 +3,12 @@ package io.customer.base.extensions import io.customer.base.extenstions.add import io.customer.base.extenstions.getUnixTimestamp import io.customer.base.extenstions.hasPassed +import io.customer.base.extenstions.isOlderThan import io.customer.base.extenstions.subtract import io.customer.base.extenstions.unixTimeToDate import org.amshove.kluent.shouldBeEqualTo +import org.amshove.kluent.shouldBeFalse +import org.amshove.kluent.shouldBeTrue import org.junit.Test import java.text.SimpleDateFormat import java.util.* @@ -61,4 +64,14 @@ class DateExtensionsTest { fun hasPassed_givenDateInFuture_expectFalse() { Date().add(1, TimeUnit.MINUTES).hasPassed() shouldBeEqualTo false } + + @Test + fun isOlderThan_givenDateThatIsOlder_expectTrue() { + Date().subtract(2, TimeUnit.DAYS).isOlderThan(Date().subtract(1, TimeUnit.DAYS)).shouldBeTrue() + } + + @Test + fun isOlderThan_givenDateThatIsNewer_expectFalse() { + Date().subtract(1, TimeUnit.DAYS).isOlderThan(Date().subtract(2, TimeUnit.DAYS)).shouldBeFalse() + } } diff --git a/common-test/src/main/java/io/customer/common_test/BaseTest.kt b/common-test/src/main/java/io/customer/common_test/BaseTest.kt index 6fc85e46a..e372d141e 100644 --- a/common-test/src/main/java/io/customer/common_test/BaseTest.kt +++ b/common-test/src/main/java/io/customer/common_test/BaseTest.kt @@ -4,14 +4,16 @@ import android.app.Application import android.content.Context import androidx.test.core.app.ApplicationProvider import androidx.test.platform.app.InstrumentationRegistry +import io.customer.common_test.util.DispatchersProviderStub import io.customer.sdk.CustomerIOConfig import io.customer.sdk.data.model.Region import io.customer.sdk.data.store.DeviceStore import io.customer.sdk.di.CustomerIOComponent import io.customer.sdk.util.CioLogLevel import io.customer.sdk.util.DateUtil +import io.customer.sdk.util.DispatchersProvider import io.customer.sdk.util.JsonAdapter -import kotlinx.coroutines.test.TestCoroutineDispatcher +import io.customer.sdk.util.Seconds import okhttp3.ResponseBody.Companion.toResponseBody import okhttp3.mockwebserver.MockWebServer import org.junit.After @@ -36,9 +38,7 @@ abstract class BaseTest { protected lateinit var cioConfig: CustomerIOConfig protected val deviceStore: DeviceStore = DeviceStoreStub().deviceStore - - // when you need a CoroutineDispatcher in a test function, use this as it runs your tests synchronous. - protected val testDispatcher = TestCoroutineDispatcher() + protected lateinit var dispatchersProviderStub: DispatchersProviderStub protected lateinit var di: CustomerIOComponent protected val jsonAdapter: JsonAdapter @@ -53,13 +53,16 @@ abstract class BaseTest { @Before open fun setup() { - cioConfig = CustomerIOConfig(siteId, "xyz", Region.EU, 100, null, true, true, 10, 30.0, CioLogLevel.DEBUG, null) + cioConfig = CustomerIOConfig(siteId, "xyz", Region.EU, 100, null, true, true, 10, 30.0, Seconds.fromDays(3).value, CioLogLevel.DEBUG, null) // Initialize the mock web server before constructing DI graph as dependencies may require information such as hostname. mockWebServer = MockWebServer().apply { start() } cioConfig.trackingApiUrl = mockWebServer.url("/").toString() + if (!cioConfig.trackingApiUrl!!.contains("localhost")) { + throw RuntimeException("server didnt' start ${cioConfig.trackingApiUrl}") + } di = CustomerIOComponent( sdkConfig = cioConfig, @@ -71,10 +74,14 @@ abstract class BaseTest { dateUtilStub = DateUtilStub().also { di.overrideDependency(DateUtil::class.java, it) } + dispatchersProviderStub = DispatchersProviderStub().also { + di.overrideDependency(DispatchersProvider::class.java, it) + } } @After open fun teardown() { mockWebServer.shutdown() + di.reset() } } diff --git a/common-test/src/main/java/io/customer/common_test/DateUtilStub.kt b/common-test/src/main/java/io/customer/common_test/DateUtilStub.kt index 63d098339..4fc2d0adc 100644 --- a/common-test/src/main/java/io/customer/common_test/DateUtilStub.kt +++ b/common-test/src/main/java/io/customer/common_test/DateUtilStub.kt @@ -1,6 +1,6 @@ package io.customer.common_test -import io.customer.base.extenstions.unixTimeToDate +import io.customer.base.extenstions.getUnixTimestamp import io.customer.sdk.util.DateUtil import java.util.* @@ -8,15 +8,13 @@ import java.util.* * Convenient alternative to mocking [DateUtil] in your test since the code is boilerplate. */ class DateUtilStub : DateUtil { - // modify this value in your test class if you need to. - var givenDateMillis = 1646238885L - val givenDate: Date - get() = givenDateMillis.unixTimeToDate() + // modify this value in your test class if you need to. + var givenDate: Date = Date(1646238885L) override val now: Date get() = givenDate override val nowUnixTimestamp: Long - get() = givenDateMillis + get() = now.getUnixTimestamp() } diff --git a/common-test/src/main/java/io/customer/common_test/util/DispatchersProviderStub.kt b/common-test/src/main/java/io/customer/common_test/util/DispatchersProviderStub.kt new file mode 100644 index 000000000..e1c36bbd8 --- /dev/null +++ b/common-test/src/main/java/io/customer/common_test/util/DispatchersProviderStub.kt @@ -0,0 +1,29 @@ +package io.customer.common_test.util + +import io.customer.sdk.util.DispatchersProvider +import io.customer.sdk.util.SdkDispatchers +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestCoroutineDispatcher + +class DispatchersProviderStub : DispatchersProvider { + private var overrideBackground: CoroutineDispatcher? = null + private var overrideMain: CoroutineDispatcher? = null + + // If your test function requires real dispatchers to be used, call this function. + // the default behavior is test dispatchers because they are fast and synchronous for more predictable test execution. + fun setRealDispatchers() { + SdkDispatchers().also { + overrideBackground = it.background + overrideMain = it.main + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + override val background: CoroutineDispatcher + get() = overrideBackground ?: TestCoroutineDispatcher() + + @OptIn(ExperimentalCoroutinesApi::class) + override val main: CoroutineDispatcher + get() = overrideMain ?: TestCoroutineDispatcher() +} diff --git a/scripts/androidStudioRunConfigurations/run Android tests.run.xml b/scripts/androidStudioRunConfigurations/run Android tests.run.xml index 7b25fe0c7..0afa837bf 100644 --- a/scripts/androidStudioRunConfigurations/run Android tests.run.xml +++ b/scripts/androidStudioRunConfigurations/run Android tests.run.xml @@ -1,5 +1,5 @@ - +