From 500c1358386449aca4ca64c5ced240aaac39fd3d Mon Sep 17 00:00:00 2001 From: diftodi Date: Mon, 18 Aug 2025 17:55:22 +0300 Subject: [PATCH 1/3] Native SDK removing debug methods for cache clearing --- .../java/com/extole/android/sdk/Extole.kt | 7 - .../extole/android/sdk/impl/CampaignImpl.kt | 4 - .../com/extole/android/sdk/impl/ExtoleImpl.kt | 11 -- .../extole/android/sdk/impl/ExtoleInternal.kt | 12 -- .../android/sdk/impl/ExtoleImplCacheTest.kt | 125 ++++++++++++++++++ 5 files changed, 125 insertions(+), 34 deletions(-) create mode 100644 mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt index fa196cc..d250c83 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt @@ -47,15 +47,8 @@ interface Extole { */ fun getContext(): ApplicationContext - /** - * Clear cache for a specific zone. Useful for debugging caching issues. - * @param zoneName - the name of the zone to clear from cache - */ - fun clearZoneCache(zoneName: String) - /** * Used to send an event, the accessToken, headers and data associated with this instance - * of Extole will be included with the request * @param eventName - the name of the event that will be sent * @param data - additional data can be sent with the event * @return [Id]<[Event]> the ID of the event that was created diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt index 9ab46d4..2d862f3 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt @@ -116,10 +116,6 @@ class CampaignImpl( extole.logout() } - override fun clearZoneCache(zoneName: String) { - extole.clearZoneCache(zoneName) - } - override suspend fun clone( programDomain: String?, appName: String?, diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt index 3b11275..84c9b2a 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt @@ -293,17 +293,6 @@ class ExtoleImpl( this.zonesResponse = Zones(mutableMapOf()) } - /** - * Clear cache for a specific zone. Useful for debugging React Native caching issues. - */ - override fun clearZoneCache(zoneName: String) { - val currentCache = zonesResponse.getAll().toMutableMap() - val keysToRemove = currentCache.keys.filter { it.zoneName == zoneName } - keysToRemove.forEach { currentCache.remove(it) } - this.zonesResponse = Zones(currentCache) - logger.debug("Cleared cache for zone: $zoneName") - } - private fun subscribe() { configurationLoader?.let { operations.addAll(it(App, mapOf())) } if (configurationLoader == null) { diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleInternal.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleInternal.kt index a0a3a74..b29fa0c 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleInternal.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleInternal.kt @@ -80,16 +80,4 @@ interface ExtoleInternal : Extole { fun getOperations(): MutableList fun getJsonConfiguration(): MutableList fun getDisabledActions(): Set - - /** - * ApplicationContext represents the context where the Mobile SDK is used - * @return [ApplicationContext] - */ - override fun getContext(): ApplicationContext - - /** - * Clear cache for a specific zone. Useful for debugging caching issues. - * @param zoneName - the name of the zone to clear from cache - */ - override fun clearZoneCache(zoneName: String) } diff --git a/mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt b/mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt new file mode 100644 index 0000000..f78fce8 --- /dev/null +++ b/mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt @@ -0,0 +1,125 @@ +package com.extole.android.sdk.impl + +import org.junit.Test +import org.junit.Assert.* +import com.extole.android.sdk.impl.ZoneResponseKey + +class ExtoleImplCacheTest { + + @Test + fun `testCacheKeyGenerationWithDifferentDataTypes`() { + // This test demonstrates a potential issue with React Native data types + + // Simulate React Native passing data + val reactNativeData1 = mapOf("clientKey" to "Go") + val reactNativeData2 = mapOf("clientKey" to "Uc") + + // Create cache keys + val key1 = ZoneResponseKey("go_configuration", reactNativeData1) + val key2 = ZoneResponseKey("go_configuration", reactNativeData2) + + // These keys should be different + assertNotEquals("Cache keys should be different for different clientKey values", key1, key2) + + // Test hash code consistency + assertNotEquals("Hash codes should be different for different clientKey values", key1.hashCode(), key2.hashCode()) + + // Test that the same data produces the same key + val key1Again = ZoneResponseKey("go_configuration", reactNativeData1) + assertEquals("Same data should produce equal keys", key1, key1Again) + assertEquals("Same data should produce same hash codes", key1.hashCode(), key1Again.hashCode()) + } + + @Test + fun `testCacheKeyWithMixedDataTypes`() { + // Test with different data types that might come from React Native + val data1 = mapOf("clientKey" to "Go", "number" to 42, "boolean" to true) + val data2 = mapOf("clientKey" to "Go", "number" to 42, "boolean" to true) + val data3 = mapOf("clientKey" to "Go", "number" to 42, "boolean" to false) + + val key1 = ZoneResponseKey("test_zone", data1) + val key2 = ZoneResponseKey("test_zone", data2) + val key3 = ZoneResponseKey("test_zone", data3) + + assertEquals("Identical data should produce equal keys", key1, key2) + assertNotEquals("Different data should produce different keys", key1, key3) + } + + @Test + fun `testCacheKeyWithNullValues`() { + // Test with null values that might come from React Native + val data1 = mapOf("clientKey" to "Go", "optional" to null) + val data2 = mapOf("clientKey" to "Go", "optional" to null) + val data3 = mapOf("clientKey" to "Go") + + val key1 = ZoneResponseKey("test_zone", data1) + val key2 = ZoneResponseKey("test_zone", data2) + val key3 = ZoneResponseKey("test_zone", data3) + + assertEquals("Data with null values should be equal", key1, key2) + assertNotEquals("Data with and without null values should be different", key1, key3) + } + + @Test + fun `testCacheKeyWithEmptyMaps`() { + // Test edge cases + val emptyData = emptyMap() + val dataWithClientKey = mapOf("clientKey" to "Go") + + val emptyKey = ZoneResponseKey("test_zone", emptyData) + val dataKey = ZoneResponseKey("test_zone", dataWithClientKey) + + assertNotEquals("Empty data and data with clientKey should be different", emptyKey, dataKey) + } + + @Test + fun `testFetchZoneCacheKeyConsistency`() { + // This test verifies that the fetchZone fix works correctly + + // Simulate the FIXED fetchZone logic: + val userData = mapOf("clientKey" to "Go") + val instanceData = mapOf("version" to "1.0") + val labels = setOf("business") + + // Both cache lookup and cache storage now use the same data (requestData) + val requestData = mutableMapOf() + requestData.putAll(userData) + requestData.putAll(instanceData) + requestData["labels"] = labels.joinToString(",") + + val cacheLookupKey = ZoneResponseKey("go_configuration", requestData) + val cacheStorageKey = ZoneResponseKey("go_configuration", requestData) + + // These keys should now be equal after the fix! + assertEquals("Cache lookup and storage keys should now be equal after the fix", cacheLookupKey, cacheStorageKey) + assertEquals("Hash codes should also be equal", cacheLookupKey.hashCode(), cacheStorageKey.hashCode()) + + println("✅ CACHING FIX VERIFIED!") + println(" Both cache lookup and storage now use the same data (requestData)") + println(" This means caching will work correctly!") + } + + @Test + fun `testDifferentClientKeysGenerateDifferentCacheKeys`() { + // This test verifies that different clientKey values generate different cache keys + + // Create two different clientKey values + val dataGo = mapOf("clientKey" to "Go") + val dataUc = mapOf("clientKey" to "Uc") + + // Create cache keys + val keyGo = ZoneResponseKey("go_configuration", dataGo) + val keyUc = ZoneResponseKey("go_configuration", dataUc) + + // These keys should be different + assertNotEquals("Cache keys with different clientKey values should not be equal", keyGo, keyUc) + assertNotEquals("Cache keys with different clientKey values should have different hash codes", + keyGo.hashCode(), keyUc.hashCode()) + + println("✅ Different clientKey values generate different cache keys:") + println(" Key Go: $keyGo") + println(" Key Uc: $keyUc") + println(" Keys are different: ${keyGo != keyUc}") + println(" Hash codes are different: ${keyGo.hashCode() != keyUc.hashCode()}") + } +} From 56d719a46abe5528a139521253873eea39b3f2d1 Mon Sep 17 00:00:00 2001 From: diftodi Date: Mon, 18 Aug 2025 17:55:58 +0300 Subject: [PATCH 2/3] Self review --- .../android/sdk/impl/ExtoleImplCacheTest.kt | 125 ------------------ 1 file changed, 125 deletions(-) delete mode 100644 mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt diff --git a/mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt b/mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt deleted file mode 100644 index f78fce8..0000000 --- a/mobile-sdk/src/test/java/com/extole/android/sdk/impl/ExtoleImplCacheTest.kt +++ /dev/null @@ -1,125 +0,0 @@ -package com.extole.android.sdk.impl - -import org.junit.Test -import org.junit.Assert.* -import com.extole.android.sdk.impl.ZoneResponseKey - -class ExtoleImplCacheTest { - - @Test - fun `testCacheKeyGenerationWithDifferentDataTypes`() { - // This test demonstrates a potential issue with React Native data types - - // Simulate React Native passing data - val reactNativeData1 = mapOf("clientKey" to "Go") - val reactNativeData2 = mapOf("clientKey" to "Uc") - - // Create cache keys - val key1 = ZoneResponseKey("go_configuration", reactNativeData1) - val key2 = ZoneResponseKey("go_configuration", reactNativeData2) - - // These keys should be different - assertNotEquals("Cache keys should be different for different clientKey values", key1, key2) - - // Test hash code consistency - assertNotEquals("Hash codes should be different for different clientKey values", key1.hashCode(), key2.hashCode()) - - // Test that the same data produces the same key - val key1Again = ZoneResponseKey("go_configuration", reactNativeData1) - assertEquals("Same data should produce equal keys", key1, key1Again) - assertEquals("Same data should produce same hash codes", key1.hashCode(), key1Again.hashCode()) - } - - @Test - fun `testCacheKeyWithMixedDataTypes`() { - // Test with different data types that might come from React Native - val data1 = mapOf("clientKey" to "Go", "number" to 42, "boolean" to true) - val data2 = mapOf("clientKey" to "Go", "number" to 42, "boolean" to true) - val data3 = mapOf("clientKey" to "Go", "number" to 42, "boolean" to false) - - val key1 = ZoneResponseKey("test_zone", data1) - val key2 = ZoneResponseKey("test_zone", data2) - val key3 = ZoneResponseKey("test_zone", data3) - - assertEquals("Identical data should produce equal keys", key1, key2) - assertNotEquals("Different data should produce different keys", key1, key3) - } - - @Test - fun `testCacheKeyWithNullValues`() { - // Test with null values that might come from React Native - val data1 = mapOf("clientKey" to "Go", "optional" to null) - val data2 = mapOf("clientKey" to "Go", "optional" to null) - val data3 = mapOf("clientKey" to "Go") - - val key1 = ZoneResponseKey("test_zone", data1) - val key2 = ZoneResponseKey("test_zone", data2) - val key3 = ZoneResponseKey("test_zone", data3) - - assertEquals("Data with null values should be equal", key1, key2) - assertNotEquals("Data with and without null values should be different", key1, key3) - } - - @Test - fun `testCacheKeyWithEmptyMaps`() { - // Test edge cases - val emptyData = emptyMap() - val dataWithClientKey = mapOf("clientKey" to "Go") - - val emptyKey = ZoneResponseKey("test_zone", emptyData) - val dataKey = ZoneResponseKey("test_zone", dataWithClientKey) - - assertNotEquals("Empty data and data with clientKey should be different", emptyKey, dataKey) - } - - @Test - fun `testFetchZoneCacheKeyConsistency`() { - // This test verifies that the fetchZone fix works correctly - - // Simulate the FIXED fetchZone logic: - val userData = mapOf("clientKey" to "Go") - val instanceData = mapOf("version" to "1.0") - val labels = setOf("business") - - // Both cache lookup and cache storage now use the same data (requestData) - val requestData = mutableMapOf() - requestData.putAll(userData) - requestData.putAll(instanceData) - requestData["labels"] = labels.joinToString(",") - - val cacheLookupKey = ZoneResponseKey("go_configuration", requestData) - val cacheStorageKey = ZoneResponseKey("go_configuration", requestData) - - // These keys should now be equal after the fix! - assertEquals("Cache lookup and storage keys should now be equal after the fix", cacheLookupKey, cacheStorageKey) - assertEquals("Hash codes should also be equal", cacheLookupKey.hashCode(), cacheStorageKey.hashCode()) - - println("✅ CACHING FIX VERIFIED!") - println(" Both cache lookup and storage now use the same data (requestData)") - println(" This means caching will work correctly!") - } - - @Test - fun `testDifferentClientKeysGenerateDifferentCacheKeys`() { - // This test verifies that different clientKey values generate different cache keys - - // Create two different clientKey values - val dataGo = mapOf("clientKey" to "Go") - val dataUc = mapOf("clientKey" to "Uc") - - // Create cache keys - val keyGo = ZoneResponseKey("go_configuration", dataGo) - val keyUc = ZoneResponseKey("go_configuration", dataUc) - - // These keys should be different - assertNotEquals("Cache keys with different clientKey values should not be equal", keyGo, keyUc) - assertNotEquals("Cache keys with different clientKey values should have different hash codes", - keyGo.hashCode(), keyUc.hashCode()) - - println("✅ Different clientKey values generate different cache keys:") - println(" Key Go: $keyGo") - println(" Key Uc: $keyUc") - println(" Keys are different: ${keyGo != keyUc}") - println(" Hash codes are different: ${keyGo.hashCode() != keyUc.hashCode()}") - } -} From 6fe7107229421cbf6ebbf0a2a2760a3895f60a5a Mon Sep 17 00:00:00 2001 From: diftodi Date: Mon, 18 Aug 2025 17:58:28 +0300 Subject: [PATCH 3/3] Fix --- mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt index d250c83..85be254 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt @@ -49,6 +49,7 @@ interface Extole { /** * Used to send an event, the accessToken, headers and data associated with this instance + * of Extole will be included with the request * @param eventName - the name of the event that will be sent * @param data - additional data can be sent with the event * @return [Id]<[Event]> the ID of the event that was created