From 303bef0135ee64dde9663313e4ff9321da02f79c Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Mon, 4 Dec 2023 21:47:39 +0530 Subject: [PATCH 01/11] feat(inapp) - add unit tests for recordImpression(), perSession() and perSessionTotal() in EvaluationManagerTest SDK-3459 --- .../sdk/inapp/ImpressionManagerTest.kt | 272 ++++-------------- 1 file changed, 57 insertions(+), 215 deletions(-) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index 3b721b6c3..a964ecc5e 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -1,10 +1,26 @@ package com.clevertap.android.sdk.inapp +import com.clevertap.android.sdk.DeviceInfo +import com.clevertap.android.sdk.StoreProvider +import com.clevertap.android.sdk.inapp.store.preference.ImpressionStore +import com.clevertap.android.sdk.inapp.store.preference.StoreRegistry +import com.clevertap.android.sdk.utils.Clock import com.clevertap.android.shared.test.BaseTestCase +import org.junit.* +import org.mockito.* +import org.mockito.Mockito.* +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import kotlin.test.assertEquals class ImpressionManagerTest : BaseTestCase() { - /* @Mock - private lateinit var clock: Clock + + @Mock + private lateinit var clock: FakeClock + + @Mock + private lateinit var deviceInfo: DeviceInfo private lateinit var impressionManager: ImpressionManager @@ -12,22 +28,48 @@ class ImpressionManagerTest : BaseTestCase() { super.setUp() MockitoAnnotations.openMocks(this) + val storeRegistry = StoreRegistry() + clock = FakeClock() impressionManager = ImpressionManager( - impressionStore = StoreProvider.getInstance().provideImpressionStore(application, DeviceInfo(),"accountId") + storeRegistry = storeRegistry, clock = clock, locale = Locale.US ) + + `when`(deviceInfo.deviceID).thenReturn("device_id") + + val impStore: ImpressionStore = StoreProvider.getInstance().provideImpressionStore( + appCtx, deviceInfo, + "account_id" + ) + + storeRegistry.impressionStore = impStore + } + + class FakeClock : Clock { + + override fun currentTimeMillis(): Long { + val seconds = 1000L + return seconds * 1000 + } + + override fun newDate(): Date { + val dateFormatter = SimpleDateFormat("yyyyMMdd", Locale.getDefault()) + return dateFormatter.parse("20230126")!!// January 26, 2023 + } } @Test - fun testRecordImpression() { + fun `recordImpression should increase sessionImpressionsTotal`() { // Arrange val campaignId = "campaign123" - val currentTime = 123456L // Replace with a desired timestamp +// val currentTime = 123456L // Replace with a desired timestamp +// +// // Mock the clock to return a fixed timestamp +// `when`(clock.currentTimeSeconds()).thenReturn(currentTime) - // Mock the clock to return a fixed timestamp - `when`(clock.currentTimeSeconds()).thenReturn(currentTime) + assertEquals(0, impressionManager.perSessionTotal()) // Act impressionManager.recordImpression(campaignId) @@ -37,17 +79,14 @@ class ImpressionManagerTest : BaseTestCase() { } @Test - fun testPerSessionWithCampaignIdPresent() { + fun `perSession should return correct impression count when campaignId is present`() { // Arrange val campaignId = "campaign123" - // Create a sessionImpressions map with a campaignId and associated list - val sessionImpressions = mutableMapOf( - campaignId to mutableListOf(1L, 2L, 3L) - ) - - // Set the sessionImpressions map in the impressionManager - impressionManager.setSessionImpressions(sessionImpressions) + // Record impressions for the campaign in the session + impressionManager.recordImpression(campaignId) + impressionManager.recordImpression(campaignId) + impressionManager.recordImpression(campaignId) // Act val result = impressionManager.perSession(campaignId) @@ -57,7 +96,7 @@ class ImpressionManagerTest : BaseTestCase() { } @Test - fun testPerSessionWithCampaignIdMissing() { + fun `perSession should return 0 when campaignId is missing`() { // Arrange val campaignId = "campaign123" @@ -69,7 +108,7 @@ class ImpressionManagerTest : BaseTestCase() { } @Test - fun testPerSessionTotalWithInitialValue() { + fun `perSessionTotal should return 0 with initial value`() { // Act val result = impressionManager.perSessionTotal() @@ -78,7 +117,7 @@ class ImpressionManagerTest : BaseTestCase() { } @Test - fun testPerSessionTotalAfterRecordImpressions() { + fun `perSessionTotal should return correct count after recording impressions`() { // Arrange val campaignId = "campaign123" @@ -93,201 +132,4 @@ class ImpressionManagerTest : BaseTestCase() { // Assert assertEquals(3, result) // Expecting the total number of impressions recorded } - - @Test - fun testPerSecondWithImpressions() { - // Arrange - val campaignId = "campaign123" - val currentTimeSeconds = 1000L - val seconds = 10 - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimeSeconds) - - // Record one impression - impressionManager.recordImpression(campaignId) - - // Act - val result = impressionManager.perSecond(campaignId, seconds) - - // Assert - assertEquals(1, result) // Expecting 1 impression within the last 10 seconds - } - - @Test - fun testPerSecondWithoutImpressions() { - // Arrange - val campaignId = "campaign123" - val currentTimeSeconds = 1000L - val seconds = 10 - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimeSeconds) - - // No impressions recorded, so the result should be 0 - - // Act - val result = impressionManager.perSecond(campaignId, seconds) - - // Assert - assertEquals(0, result) // Expecting 0 impressions within the last 10 seconds - } - - @Test - fun testPerMinuteWithImpressions() { - // Arrange - val campaignId = "campaign123" - val currentTimestamp = 1000L // Replace with a desired timestamp - val minutesOffset = 5 // Minutes to subtract - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) - - // Act - impressionManager.recordImpression(campaignId) // Record an impression - val result = impressionManager.perMinute(campaignId, minutesOffset) - - // Assert - assertEquals(1, result) // Expecting 1 impression recorded within the last 5 minutes - } - - @Test - fun testPerMinuteWithoutImpressions() { - // Arrange - val campaignId = "campaign123" - val currentTimestamp = 1000L // Replace with a desired timestamp - val minutesOffset = 5 // Minutes to subtract - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) - - // No impressions recorded, so the result should be 0 - - // Act - val result = impressionManager.perMinute(campaignId, minutesOffset) - - // Assert - assertEquals(0, result) // Expecting 0 impressions within the last 5 minutes - } - - @Test - fun testPerHourWithImpressions() { - // Arrange - val campaignId = "campaign123" - val currentTimestamp = 1000L // Replace with a desired timestamp - val hoursOffset = 2 // Hours to subtract - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) - - // Act - impressionManager.recordImpression(campaignId) // Record an impression - val result = impressionManager.perHour(campaignId, hoursOffset) - - // Assert - assertEquals(1, result) // Expecting 1 impression recorded within the last 2 hours - } - - @Test - fun testPerHourWithoutImpressions() { - // Arrange - val campaignId = "campaign123" - val currentTimestamp = 1000L // Replace with a desired timestamp - val hoursOffset = 2 // Hours to subtract - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) - - // Act - val result = impressionManager.perHour(campaignId, hoursOffset) - - // Assert - assertEquals(0, result) // Expecting 0 impressions within the last 2 hours - } - - @Test - fun testPerDayWithImpressions() { - // Arrange - val campaignId = "campaign123" - val daysOffset = 2 // Days to subtract - - val currentDate = Calendar.getInstance() - //currentDate.set(2023, Calendar.SEPTEMBER, 25) // Set the currentDate to some past date to fail this test - - `when`(clock.currentTimeSeconds()).thenReturn(TimeUnit.MILLISECONDS.toSeconds(currentDate.timeInMillis)) - - // Act - impressionManager.recordImpression(campaignId) // Record an impression - val result = impressionManager.perDay("campaign123", daysOffset) - - // Assert - assertEquals(1, result) // Expecting 1 impression recorded within the last 2 days - } - - @Test - fun testPerDayWithoutImpressions() { - // Arrange - val campaignId = "campaign123" - val daysOffset = 2 // Days to subtract - - val currentDate = Calendar.getInstance() - `when`(clock.currentTimeSeconds()).thenReturn(TimeUnit.MILLISECONDS.toSeconds(currentDate.timeInMillis)) - - // Act - val result = impressionManager.perDay(campaignId, daysOffset) - - // Assert - assertEquals(0, result) // Expecting 0 impressions within the last 2 days - } - - @Test - fun testPerWeekWithImpressions() { - // Arrange - val campaignId = "campaign123" - val weeksOffset = 1 // Weeks to subtract - val currentDate = Calendar.getInstance() - *//*currentDate.set( - 2023, Calendar.SEPTEMBER, 24 - )*//* // Set the currentDate to some past date to fail this test - - `when`(clock.currentTimeSeconds()).thenReturn(TimeUnit.MILLISECONDS.toSeconds(currentDate.timeInMillis)) - - // Act - impressionManager.recordImpression(campaignId) // Record an impression - val result = impressionManager.perWeek(campaignId, weeksOffset) - - // Assert - assertEquals(1, result) // Expecting 1 impression recorded within the last 2 weeks - } - - @Test - fun testPerWeekWithoutImpressions() { - // Arrange - val campaignId = "campaign123" - val weeksOffset = 2 // Weeks to subtract - val currentDate = Calendar.getInstance() - currentDate.set(2023, Calendar.SEPTEMBER, 24) - - `when`(clock.currentTimeSeconds()).thenReturn(TimeUnit.MILLISECONDS.toSeconds(currentDate.timeInMillis)) - - // Act - val result = impressionManager.perWeek(campaignId, weeksOffset) - - // Assert - assertEquals(0, result) // Expecting 0 impressions within the last 2 weeks - } - - @Test - fun testClearSessionData() { - // Arrange - val campaignId = "campaign123" - - // Record an impression to ensure sessionImpressions is not empty - impressionManager.recordImpression(campaignId) - - // Verify that sessionImpressions is not empty initially - val initialSessionImpressionsSize = impressionManager.perSessionTotal() - assert(initialSessionImpressionsSize > 0) - - // Act - impressionManager.clearSessionData() - - // Assert - val clearedSessionImpressionsSize = impressionManager.perSessionTotal() - assertEquals(0, clearedSessionImpressionsSize) // Expecting sessionImpressions to be cleared - }*/ } \ No newline at end of file From 88b4fcd4eb107aa10de0cc74de9dc0311a2e283f Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Tue, 5 Dec 2023 08:23:26 +0530 Subject: [PATCH 02/11] feat(inapp) - add unit tests for perSecond() in EvaluationManagerTest SDK-3459 --- .../sdk/inapp/ImpressionManagerTest.kt | 67 ++++++++++++++++--- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index a964ecc5e..f1ce4aa47 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -17,11 +17,13 @@ import kotlin.test.assertEquals class ImpressionManagerTest : BaseTestCase() { @Mock - private lateinit var clock: FakeClock + private lateinit var clock: Clock @Mock private lateinit var deviceInfo: DeviceInfo + private lateinit var impressionStore: ImpressionStore + private lateinit var impressionManager: ImpressionManager override fun setUp() { @@ -29,7 +31,6 @@ class ImpressionManagerTest : BaseTestCase() { MockitoAnnotations.openMocks(this) val storeRegistry = StoreRegistry() - clock = FakeClock() impressionManager = ImpressionManager( storeRegistry = storeRegistry, @@ -39,12 +40,12 @@ class ImpressionManagerTest : BaseTestCase() { `when`(deviceInfo.deviceID).thenReturn("device_id") - val impStore: ImpressionStore = StoreProvider.getInstance().provideImpressionStore( + impressionStore = StoreProvider.getInstance().provideImpressionStore( appCtx, deviceInfo, "account_id" ) - storeRegistry.impressionStore = impStore + storeRegistry.impressionStore = impressionStore } class FakeClock : Clock { @@ -64,10 +65,6 @@ class ImpressionManagerTest : BaseTestCase() { fun `recordImpression should increase sessionImpressionsTotal`() { // Arrange val campaignId = "campaign123" -// val currentTime = 123456L // Replace with a desired timestamp -// -// // Mock the clock to return a fixed timestamp -// `when`(clock.currentTimeSeconds()).thenReturn(currentTime) assertEquals(0, impressionManager.perSessionTotal()) @@ -75,7 +72,7 @@ class ImpressionManagerTest : BaseTestCase() { impressionManager.recordImpression(campaignId) // Assert - assertEquals(1, impressionManager.perSessionTotal()) // Expecting one impression recorded + assertEquals(1, impressionManager.perSessionTotal()) } @Test @@ -130,6 +127,56 @@ class ImpressionManagerTest : BaseTestCase() { val result = impressionManager.perSessionTotal() // Assert - assertEquals(3, result) // Expecting the total number of impressions recorded + assertEquals(3, result) + } + + @Test + fun `perSecond should return correct impression count for impressions within the last 5 seconds`() { + // Arrange + val campaignId = "campaign123" + val currentTimestamp = System.currentTimeMillis() / 1000 + + // Record impressions within the last 5 seconds + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 1) + impressionManager.recordImpression(campaignId) + + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 2) + impressionManager.recordImpression(campaignId) + + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 3) + impressionManager.recordImpression(campaignId) + + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + + // Act + val result = impressionManager.perSecond(campaignId, 5) + + // Assert + assertEquals(3, result) + } + + @Test + fun `perSecond should return 0 for impressions outside the last 5 seconds`() { + // Arrange + val campaignId = "campaign123" + val currentTimestamp = System.currentTimeMillis() / 1000 + + // Record impressions outside the last 5 seconds + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 10) + impressionManager.recordImpression(campaignId) + + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 20) + impressionManager.recordImpression(campaignId) + + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 30) + impressionManager.recordImpression(campaignId) + + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + + // Act + val result = impressionManager.perSecond(campaignId, 5) + + // Assert + assertEquals(0, result) } } \ No newline at end of file From 8c584999cf9d16cfe893c445a3f2b680cf553cbd Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Tue, 5 Dec 2023 09:50:47 +0530 Subject: [PATCH 03/11] feat(inapp) - add unit tests for perMinute() in EvaluationManagerTest SDK-3459 --- .../sdk/inapp/ImpressionManagerTest.kt | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index f1ce4aa47..c3af058ef 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -12,6 +12,7 @@ import org.mockito.Mockito.* import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +import java.util.concurrent.TimeUnit import kotlin.test.assertEquals class ImpressionManagerTest : BaseTestCase() { @@ -137,18 +138,13 @@ class ImpressionManagerTest : BaseTestCase() { val currentTimestamp = System.currentTimeMillis() / 1000 // Record impressions within the last 5 seconds - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 1) - impressionManager.recordImpression(campaignId) - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 2) - impressionManager.recordImpression(campaignId) - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 3) - impressionManager.recordImpression(campaignId) - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + // IMP: Impression should be recorded in increasing order of timeStamps otherwise unit test will get failed + recordImpression(currentTimestamp - 3, campaignId) + recordImpression(currentTimestamp - 2, campaignId) + recordImpression(currentTimestamp - 1, campaignId) // Act + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) val result = impressionManager.perSecond(campaignId, 5) // Assert @@ -162,21 +158,46 @@ class ImpressionManagerTest : BaseTestCase() { val currentTimestamp = System.currentTimeMillis() / 1000 // Record impressions outside the last 5 seconds - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 10) - impressionManager.recordImpression(campaignId) - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 20) - impressionManager.recordImpression(campaignId) - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp - 30) - impressionManager.recordImpression(campaignId) - - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + // IMP: Impression should be recorded in increasing order of timeStamps otherwise unit test will get failed + recordImpression(currentTimestamp - 30, campaignId) + recordImpression(currentTimestamp - 20, campaignId) + recordImpression(currentTimestamp - 10, campaignId) // Act + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) val result = impressionManager.perSecond(campaignId, 5) // Assert assertEquals(0, result) } + + @Test + fun testPerMinute() { + // Arrange + val campaignId = "campaign123" + val currentTimestamp = System.currentTimeMillis() / 1000 + + val oneMinuteAgo = currentTimestamp - TimeUnit.MINUTES.toSeconds(1) + val oneMinuteOneSecondAgo = oneMinuteAgo - 1 + val thirtySecondsAgo = currentTimestamp - 30 + + // IMP: Impression should be recorded in increasing order of timeStamps otherwise unit test will get failed + recordImpression(oneMinuteOneSecondAgo, campaignId) + recordImpression(oneMinuteAgo, campaignId) + recordImpression(thirtySecondsAgo, campaignId) + + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(2, impressionManager.perMinute(campaignId, 1)) + + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(3, impressionManager.perMinute(campaignId, 2)) + } + + private fun recordImpression(timestamp: Long, campaignId: String) { + `when`(clock.currentTimeSeconds()).thenReturn(timestamp) + impressionManager.recordImpression(campaignId) + } + } \ No newline at end of file From 2988cdc6266e941ef60e48c8f130b152a0d50995 Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Tue, 5 Dec 2023 13:54:54 +0530 Subject: [PATCH 04/11] feat(inapp) - add unit tests for testPerHour() in EvaluationManagerTest SDK-3459 --- .../sdk/inapp/ImpressionManagerTest.kt | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index c3af058ef..f49dfef20 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -186,15 +186,49 @@ class ImpressionManagerTest : BaseTestCase() { recordImpression(oneMinuteAgo, campaignId) recordImpression(thirtySecondsAgo, campaignId) - // Act and Assert + // test per 1 minute `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) assertEquals(2, impressionManager.perMinute(campaignId, 1)) - // Act and Assert + // test per 2 minutes `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) assertEquals(3, impressionManager.perMinute(campaignId, 2)) } + @Test + fun testPerHour() { + // Arrange + val campaignId = "campaign123" + val currentTimestamp = System.currentTimeMillis() / 1000 + + val thirtyMinutesAgo = currentTimestamp - TimeUnit.MINUTES.toSeconds(30) + val oneHourAgo = currentTimestamp - TimeUnit.HOURS.toSeconds(1) + val oneHourOneSecondAgo = oneHourAgo - 1 + val twentyFiveHoursAgo = currentTimestamp - TimeUnit.HOURS.toSeconds(25) + val twentyFiveHoursOneSecondAgo = twentyFiveHoursAgo - 1 + + // IMP: Impression should be recorded in increasing order of timeStamps otherwise unit test will get failed + recordImpression(twentyFiveHoursOneSecondAgo, campaignId) + recordImpression(twentyFiveHoursAgo, campaignId) + recordImpression(oneHourOneSecondAgo, campaignId) + recordImpression(oneHourAgo, campaignId) + recordImpression(thirtyMinutesAgo, campaignId) + + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + + // test per 1 hour + assertEquals(2, impressionManager.perHour(campaignId, 1)) + + // test per 2 hours + assertEquals(3, impressionManager.perHour(campaignId, 2)) + + // test per 25 hours + assertEquals(4, impressionManager.perHour(campaignId, 25)) + + // test per 26 hours + assertEquals(5, impressionManager.perHour(campaignId, 26)) + } + private fun recordImpression(timestamp: Long, campaignId: String) { `when`(clock.currentTimeSeconds()).thenReturn(timestamp) impressionManager.recordImpression(campaignId) From e02b50664dabc556b731523bf67e29eba282adfa Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Tue, 5 Dec 2023 14:10:32 +0530 Subject: [PATCH 05/11] feat(inapp) - refactor unit tests coverage for perSecond() and perMinute() --- .../sdk/inapp/ImpressionManagerTest.kt | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index f49dfef20..a12d0faf1 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -132,43 +132,35 @@ class ImpressionManagerTest : BaseTestCase() { } @Test - fun `perSecond should return correct impression count for impressions within the last 5 seconds`() { + fun testPerSecond() { // Arrange val campaignId = "campaign123" val currentTimestamp = System.currentTimeMillis() / 1000 - // Record impressions within the last 5 seconds + val oneSecondAgo = currentTimestamp - 1 + val twoSecondsAgo = currentTimestamp - 2 + val threeSecondsAgo = currentTimestamp - 3 + val elvenSecondsAgo = currentTimestamp - 11 + // IMP: Impression should be recorded in increasing order of timeStamps otherwise unit test will get failed - recordImpression(currentTimestamp - 3, campaignId) - recordImpression(currentTimestamp - 2, campaignId) - recordImpression(currentTimestamp - 1, campaignId) + recordImpression(elvenSecondsAgo, campaignId) + recordImpression(threeSecondsAgo, campaignId) + recordImpression(twoSecondsAgo, campaignId) + recordImpression(oneSecondAgo, campaignId) - // Act `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) - val result = impressionManager.perSecond(campaignId, 5) - // Assert - assertEquals(3, result) - } + // test per 1 second + assertEquals(1, impressionManager.perSecond(campaignId, 1)) - @Test - fun `perSecond should return 0 for impressions outside the last 5 seconds`() { - // Arrange - val campaignId = "campaign123" - val currentTimestamp = System.currentTimeMillis() / 1000 + // test per 10 second + assertEquals(3, impressionManager.perSecond(campaignId, 10)) - // Record impressions outside the last 5 seconds - // IMP: Impression should be recorded in increasing order of timeStamps otherwise unit test will get failed - recordImpression(currentTimestamp - 30, campaignId) - recordImpression(currentTimestamp - 20, campaignId) - recordImpression(currentTimestamp - 10, campaignId) + // test per 11 second + assertEquals(4, impressionManager.perSecond(campaignId, 11)) - // Act - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) - val result = impressionManager.perSecond(campaignId, 5) - - // Assert - assertEquals(0, result) + // test per 12 second + assertEquals(4, impressionManager.perSecond(campaignId, 12)) } @Test @@ -180,19 +172,27 @@ class ImpressionManagerTest : BaseTestCase() { val oneMinuteAgo = currentTimestamp - TimeUnit.MINUTES.toSeconds(1) val oneMinuteOneSecondAgo = oneMinuteAgo - 1 val thirtySecondsAgo = currentTimestamp - 30 + val sixtyFiveMinutesAgo = currentTimestamp - TimeUnit.MINUTES.toSeconds(65) // IMP: Impression should be recorded in increasing order of timeStamps otherwise unit test will get failed + recordImpression(sixtyFiveMinutesAgo, campaignId) recordImpression(oneMinuteOneSecondAgo, campaignId) recordImpression(oneMinuteAgo, campaignId) recordImpression(thirtySecondsAgo, campaignId) - // test per 1 minute `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + + // test per 1 minute assertEquals(2, impressionManager.perMinute(campaignId, 1)) // test per 2 minutes - `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) assertEquals(3, impressionManager.perMinute(campaignId, 2)) + + // test per 60 minutes + assertEquals(3, impressionManager.perMinute(campaignId, 60)) + + // test per 70 minutes + assertEquals(4, impressionManager.perMinute(campaignId, 70)) } @Test From a960d2d046c8ae166c4cac6e77c0537e9992118f Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Wed, 6 Dec 2023 12:53:36 +0530 Subject: [PATCH 06/11] feat(inapp) - add unit tests for testPerDay() method --- .../sdk/inapp/ImpressionManagerTest.kt | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index a12d0faf1..426a91666 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -10,6 +10,7 @@ import org.junit.* import org.mockito.* import org.mockito.Mockito.* import java.text.SimpleDateFormat +import java.util.Calendar import java.util.Date import java.util.Locale import java.util.concurrent.TimeUnit @@ -229,6 +230,95 @@ class ImpressionManagerTest : BaseTestCase() { assertEquals(5, impressionManager.perHour(campaignId, 26)) } + @Test + fun testPerDay() { + // Arrange + val campaignId = "campaign123" + val currentTimestamp = System.currentTimeMillis() / 1000 + + val referenceTimestamp = getSecondsSinceLastMidnight() + + val twoDayBeforeMidnightMinus1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(2) - 1 + val twoDaysBeforeMidnightOffset1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(2) + 1 + val oneDayBeforeMidnightMinus1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(1) - 1 + val oneDayBeforeMidnightOffset1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(1) + 1 + val tenHoursBeforeMidnight = referenceTimestamp - TimeUnit.HOURS.toSeconds(10) + val oneMinuteBeforeMidnight = referenceTimestamp - TimeUnit.MINUTES.toSeconds(1) + val tenHoursFromMidnight = referenceTimestamp + TimeUnit.HOURS.toSeconds(10) + val oneSecondAgo = currentTimestamp - 1 + + //Arrange + recordImpression(twoDayBeforeMidnightMinus1s, campaignId) + //Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perDay(campaignId, 0)) + assertEquals(0, impressionManager.perDay(campaignId, 1)) + assertEquals(0, impressionManager.perDay(campaignId, 2)) + assertEquals(1, impressionManager.perDay(campaignId, 3)) + + //Arrange + recordImpression(twoDaysBeforeMidnightOffset1s, campaignId) + //Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perDay(campaignId, 0)) + assertEquals(0, impressionManager.perDay(campaignId, 1)) + assertEquals(1, impressionManager.perDay(campaignId, 2)) + assertEquals(2, impressionManager.perDay(campaignId, 3)) + + //Arrange + recordImpression(oneDayBeforeMidnightMinus1s, campaignId) + //Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perDay(campaignId, 0)) + assertEquals(0, impressionManager.perDay(campaignId, 1)) + assertEquals(2, impressionManager.perDay(campaignId, 2)) + assertEquals(3, impressionManager.perDay(campaignId, 3)) + + //Arrange + recordImpression(oneDayBeforeMidnightOffset1s, campaignId) + //Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perDay(campaignId, 0)) + assertEquals(1, impressionManager.perDay(campaignId, 1)) + assertEquals(3, impressionManager.perDay(campaignId, 2)) + assertEquals(4, impressionManager.perDay(campaignId, 3)) + + //Arrange + recordImpression(tenHoursBeforeMidnight, campaignId) + //Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perDay(campaignId, 0)) + assertEquals(2, impressionManager.perDay(campaignId, 1)) + assertEquals(4, impressionManager.perDay(campaignId, 2)) + assertEquals(5, impressionManager.perDay(campaignId, 3)) + + //Arrange + recordImpression(oneMinuteBeforeMidnight, campaignId) + recordImpression(tenHoursFromMidnight, campaignId) + recordImpression(oneSecondAgo, campaignId) + //Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(2, impressionManager.perDay(campaignId, 0)) + assertEquals(5, impressionManager.perDay(campaignId, 1)) + assertEquals(7, impressionManager.perDay(campaignId, 2)) + assertEquals(8, impressionManager.perDay(campaignId, 3)) + } + + private fun getSecondsSinceLastMidnight(): Long { + val timeInMillis = + Calendar.getInstance(Locale.US).apply { + val currentDate = Date() + // Set the calendar's time to the current date and time + time = currentDate + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.time.time + + return TimeUnit.MILLISECONDS.toSeconds(timeInMillis) + } + private fun recordImpression(timestamp: Long, campaignId: String) { `when`(clock.currentTimeSeconds()).thenReturn(timestamp) impressionManager.recordImpression(campaignId) From 023f7cca8e656d52d7a58a3fce85196a45b89694 Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Thu, 7 Dec 2023 07:53:07 +0530 Subject: [PATCH 07/11] feat(inapp) - add unit tests for perWeek() method --- .../sdk/inapp/ImpressionManagerTest.kt | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index 426a91666..e87db8ce8 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -304,6 +304,97 @@ class ImpressionManagerTest : BaseTestCase() { assertEquals(8, impressionManager.perDay(campaignId, 3)) } + @Test + fun testPerWeek() { + // Arrange + val campaignId = "campaign123" + val currentTimestamp = System.currentTimeMillis() / 1000 + + val referenceTimestamp = getSecondsSinceFirstDayOfCurrentWeek() + + val twoWeeksBeforeStartOfWeekMinus1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(14) - 1 + val twoWeeksBeforeStartOfWeekOffset1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(14) + 1 + val oneWeekBeforeStartOfWeekMinus1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(7) - 1 + val oneWeekBeforeStartOfWeekOffset1s = referenceTimestamp - TimeUnit.DAYS.toSeconds(7) + 1 + val tenHoursBeforeStartOfWeek = referenceTimestamp - TimeUnit.HOURS.toSeconds(10) + val oneMinuteBeforeStartOfWeek = referenceTimestamp - TimeUnit.MINUTES.toSeconds(1) + val tenHoursFromStartOfWeek = referenceTimestamp + TimeUnit.HOURS.toSeconds(10) + val oneSecondAgo = currentTimestamp - 1 + + // Arrange + recordImpression(twoWeeksBeforeStartOfWeekMinus1s, campaignId) + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perWeek(campaignId, 0)) + assertEquals(0, impressionManager.perWeek(campaignId, 1)) + assertEquals(0, impressionManager.perWeek(campaignId, 2)) + assertEquals(1, impressionManager.perWeek(campaignId, 3)) + + // Arrange + recordImpression(twoWeeksBeforeStartOfWeekOffset1s, campaignId) + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perWeek(campaignId, 0)) + assertEquals(0, impressionManager.perWeek(campaignId, 1)) + assertEquals(1, impressionManager.perWeek(campaignId, 2)) + assertEquals(2, impressionManager.perWeek(campaignId, 3)) + + // Arrange + recordImpression(oneWeekBeforeStartOfWeekMinus1s, campaignId) + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perWeek(campaignId, 0)) + assertEquals(0, impressionManager.perWeek(campaignId, 1)) + assertEquals(2, impressionManager.perWeek(campaignId, 2)) + assertEquals(3, impressionManager.perWeek(campaignId, 3)) + + // Arrange + recordImpression(oneWeekBeforeStartOfWeekOffset1s, campaignId) + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perWeek(campaignId, 0)) + assertEquals(0, impressionManager.perWeek(campaignId, 1)) + assertEquals(3, impressionManager.perWeek(campaignId, 2)) + assertEquals(4, impressionManager.perWeek(campaignId, 3)) + + // Arrange + recordImpression(tenHoursBeforeStartOfWeek, campaignId) + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(0, impressionManager.perWeek(campaignId, 0)) + assertEquals(0, impressionManager.perWeek(campaignId, 1)) + assertEquals(4, impressionManager.perWeek(campaignId, 2)) + assertEquals(5, impressionManager.perWeek(campaignId, 3)) + + // Arrange + recordImpression(oneMinuteBeforeStartOfWeek, campaignId) + recordImpression(tenHoursFromStartOfWeek, campaignId) + recordImpression(oneSecondAgo, campaignId) + // Act and Assert + `when`(clock.currentTimeSeconds()).thenReturn(currentTimestamp) + assertEquals(2, impressionManager.perWeek(campaignId, 0)) + assertEquals(2, impressionManager.perWeek(campaignId, 1)) + assertEquals(7, impressionManager.perWeek(campaignId, 2)) + assertEquals(8, impressionManager.perWeek(campaignId, 3)) + } + + private fun getSecondsSinceFirstDayOfCurrentWeek(): Long { + // get today and clear time of day + val cal = Calendar.getInstance(Locale.US).apply { + val currentDate = Date() + // Set the calendar's time to the current date and time + time = currentDate + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + } + + // get start of this week in milliseconds + cal[Calendar.DAY_OF_WEEK] = cal.firstDayOfWeek + return TimeUnit.MILLISECONDS.toSeconds(cal.time.time) + } + private fun getSecondsSinceLastMidnight(): Long { val timeInMillis = Calendar.getInstance(Locale.US).apply { From 9d1a6fb062d6883bb2fbc3fced73497b18c034d4 Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Thu, 7 Dec 2023 08:02:58 +0530 Subject: [PATCH 08/11] feat(inapp) - add unit tests for perSessionTotal() method --- .../sdk/inapp/ImpressionManagerTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index e87db8ce8..d5214d0c9 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -415,4 +415,24 @@ class ImpressionManagerTest : BaseTestCase() { impressionManager.recordImpression(campaignId) } + + @Test + fun testClearSessionData() { + // Arrange + val campaignId = "campaign123" + + // Record an impression to ensure sessionImpressions is not empty + impressionManager.recordImpression(campaignId) + + // Verify that sessionImpressions is not empty initially + val initialSessionImpressionsSize = impressionManager.perSessionTotal() + assert(initialSessionImpressionsSize > 0) + + // Act + impressionManager.clearSessionData() + + // Assert + val clearedSessionImpressionsSize = impressionManager.perSessionTotal() + assertEquals(0, clearedSessionImpressionsSize) // Expecting sessionImpressions to be cleared + } } \ No newline at end of file From 3e7d246b47e1f720759cb10465f57cdabe4c9a40 Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Thu, 7 Dec 2023 08:39:45 +0530 Subject: [PATCH 09/11] feat(inapp) - reformat code --- .../sdk/inapp/ImpressionManagerTest.kt | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt index d5214d0c9..c89df94f9 100644 --- a/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt +++ b/clevertap-core/src/test/java/com/clevertap/android/sdk/inapp/ImpressionManagerTest.kt @@ -35,16 +35,13 @@ class ImpressionManagerTest : BaseTestCase() { val storeRegistry = StoreRegistry() impressionManager = ImpressionManager( - storeRegistry = storeRegistry, - clock = clock, - locale = Locale.US + storeRegistry = storeRegistry, clock = clock, locale = Locale.US ) `when`(deviceInfo.deviceID).thenReturn("device_id") impressionStore = StoreProvider.getInstance().provideImpressionStore( - appCtx, deviceInfo, - "account_id" + appCtx, deviceInfo, "account_id" ) storeRegistry.impressionStore = impressionStore @@ -395,27 +392,6 @@ class ImpressionManagerTest : BaseTestCase() { return TimeUnit.MILLISECONDS.toSeconds(cal.time.time) } - private fun getSecondsSinceLastMidnight(): Long { - val timeInMillis = - Calendar.getInstance(Locale.US).apply { - val currentDate = Date() - // Set the calendar's time to the current date and time - time = currentDate - set(Calendar.HOUR_OF_DAY, 0) - set(Calendar.MINUTE, 0) - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - }.time.time - - return TimeUnit.MILLISECONDS.toSeconds(timeInMillis) - } - - private fun recordImpression(timestamp: Long, campaignId: String) { - `when`(clock.currentTimeSeconds()).thenReturn(timestamp) - impressionManager.recordImpression(campaignId) - } - - @Test fun testClearSessionData() { // Arrange @@ -435,4 +411,23 @@ class ImpressionManagerTest : BaseTestCase() { val clearedSessionImpressionsSize = impressionManager.perSessionTotal() assertEquals(0, clearedSessionImpressionsSize) // Expecting sessionImpressions to be cleared } + + private fun getSecondsSinceLastMidnight(): Long { + val timeInMillis = Calendar.getInstance(Locale.US).apply { + val currentDate = Date() + // Set the calendar's time to the current date and time + time = currentDate + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + }.time.time + + return TimeUnit.MILLISECONDS.toSeconds(timeInMillis) + } + + private fun recordImpression(timestamp: Long, campaignId: String) { + `when`(clock.currentTimeSeconds()).thenReturn(timestamp) + impressionManager.recordImpression(campaignId) + } } \ No newline at end of file From cc1ff2a2a2cf0e152bb98b9047877c0fc7553b09 Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Thu, 7 Dec 2023 08:42:26 +0530 Subject: [PATCH 10/11] feat(inapp) - make getImpressionCount methods private --- .../com/clevertap/android/sdk/inapp/ImpressionManager.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt b/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt index 42a5cc1ad..0dd4c582e 100644 --- a/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt +++ b/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt @@ -133,6 +133,7 @@ class ImpressionManager @JvmOverloads constructor( /** * Counts the impressions for a campaign within the last N weeks. + * passing 1 means it will lookup in the current week * * @param campaignId The identifier of the campaign. * @param weeks The time interval in weeks. @@ -177,7 +178,7 @@ class ImpressionManager @JvmOverloads constructor( * @param campaignId The identifier of the campaign. * @return The total number of impressions recorded for the campaign. */ - fun getImpressionCount(campaignId: String): Int { + private fun getImpressionCount(campaignId: String): Int { return storeRegistry.impressionStore?.read(campaignId)?.size ?: 0 } @@ -188,7 +189,7 @@ class ImpressionManager @JvmOverloads constructor( * @param timestampStart The start timestamp of the time interval (in seconds since the Unix epoch). * @return The count of impressions within the specified time interval. */ - fun getImpressionCount(campaignId: String, timestampStart: Long): Int { + private fun getImpressionCount(campaignId: String, timestampStart: Long): Int { val timestamps = getImpressions(campaignId) var count = 0 From eff3560f1da3c82e6365c8a6d3aa6f61690af403 Mon Sep 17 00:00:00 2001 From: Shivam Sharma Date: Thu, 7 Dec 2023 08:45:46 +0530 Subject: [PATCH 11/11] feat(inapp) - add javaDoc details to the perWeek() method --- .../java/com/clevertap/android/sdk/inapp/ImpressionManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt b/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt index 0dd4c582e..0877dcf63 100644 --- a/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt +++ b/clevertap-core/src/main/java/com/clevertap/android/sdk/inapp/ImpressionManager.kt @@ -133,7 +133,7 @@ class ImpressionManager @JvmOverloads constructor( /** * Counts the impressions for a campaign within the last N weeks. - * passing 1 means it will lookup in the current week + * It looks up in the current week if the value one is passed as week offset * * @param campaignId The identifier of the campaign. * @param weeks The time interval in weeks.