Skip to content

Commit 37666be

Browse files
feat: Add user attributes mapping logic in Rokt execute flow (#574)
1 parent 9376f30 commit 37666be

File tree

3 files changed

+313
-2
lines changed

3 files changed

+313
-2
lines changed

android-kit-base/src/main/java/com/mparticle/kits/KitConfiguration.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public class KitConfiguration {
6161
private final static String KEY_CONSENT_FORWARDING_RULES_VALUE_CONSENTED = "c";
6262
private final static String KEY_CONSENT_FORWARDING_RULES_VALUE_HASH = "h";
6363
private final static String KEY_EXCLUDE_ANONYMOUS_USERS = "eau";
64+
private final static String KEY_PLACEMENT_ATTRIBUTES_MAPPING = "placementAttributesMapping";
6465

6566
//If set to true, our sdk honor user's optout wish. If false, we still collect data on opt-ed out users, but only for reporting.
6667
private final static String HONOR_OPT_OUT = "honorOptOut";
@@ -986,6 +987,14 @@ public boolean shouldHonorOptOut() {
986987
return true;
987988
}
988989

990+
public JSONArray getPlacementAttributesMapping() throws JSONException {
991+
if (!settings.containsKey(KEY_PLACEMENT_ATTRIBUTES_MAPPING)) {
992+
return new JSONArray();
993+
}
994+
String jsonArrayStr = settings.get(KEY_PLACEMENT_ATTRIBUTES_MAPPING);
995+
return new JSONArray(jsonArrayStr);
996+
}
997+
989998
boolean shouldSetIdentity(MParticle.IdentityType identityType) {
990999
SparseBooleanArray userIdentityFilters = getUserIdentityFilters();
9911000
return userIdentityFilters == null ||

android-kit-base/src/main/java/com/mparticle/kits/KitManagerImpl.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,12 +1334,29 @@ public void execute(String viewName,
13341334
try {
13351335
if (provider instanceof KitIntegration.RoktListener && !provider.isDisabled()) {
13361336
MParticleUser user = MParticle.getInstance().Identity().getCurrentUser();
1337+
JSONArray jsonArray = new JSONArray();
1338+
KitConfiguration kitConfig = provider.getConfiguration();
1339+
if (kitConfig != null) {
1340+
try {
1341+
jsonArray = kitConfig.getPlacementAttributesMapping();
1342+
} catch (JSONException e) {
1343+
Logger.warning("Invalid placementAttributes for kit: " + provider.getName() + " JSON: " + e.getMessage());
1344+
}
1345+
}
1346+
for (int i = 0; i < jsonArray.length(); i++) {
1347+
JSONObject obj = jsonArray.optJSONObject(i);
1348+
if (obj == null) continue;
1349+
String mapFrom = obj.optString("map");
1350+
String mapTo = obj.optString("value");
1351+
if (attributes.containsKey(mapFrom)) {
1352+
String value = attributes.remove(mapFrom);
1353+
attributes.put(mapTo, value);
1354+
}
1355+
}
13371356
Map<String, Object> objectAttributes = new HashMap<>();
1338-
13391357
for (Map.Entry<String, String> entry : attributes.entrySet()) {
13401358
objectAttributes.put(entry.getKey(), entry.getValue());
13411359
}
1342-
13431360
user.setUserAttributes(objectAttributes);
13441361
((KitIntegration.RoktListener) provider).execute(viewName,
13451362
attributes,

android-kit-base/src/test/kotlin/com/mparticle/kits/KitManagerImplTest.kt

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.mparticle.kits
22

3+
import android.content.Context
4+
import android.graphics.Typeface
35
import com.mparticle.BaseEvent
46
import com.mparticle.MPEvent
57
import com.mparticle.MParticle
@@ -17,6 +19,7 @@ import com.mparticle.mock.MockContext
1719
import com.mparticle.mock.MockKitConfiguration
1820
import com.mparticle.mock.MockKitManagerImpl
1921
import com.mparticle.mock.MockMParticle
22+
import com.mparticle.rokt.RoktEmbeddedView
2023
import com.mparticle.testutils.TestingUtils
2124
import junit.framework.TestCase
2225
import org.json.JSONArray
@@ -26,8 +29,10 @@ import org.junit.Assert
2629
import org.junit.Before
2730
import org.junit.Test
2831
import org.mockito.Mockito
32+
import java.lang.ref.WeakReference
2933
import java.util.Arrays
3034
import java.util.LinkedList
35+
import java.util.concurrent.ConcurrentHashMap
3136

3237
class KitManagerImplTest {
3338
var mparticle: MParticle? = null
@@ -767,6 +772,286 @@ class KitManagerImplTest {
767772
Assert.assertEquals(2, manager.providers.size)
768773
}
769774

775+
@Test
776+
fun testRokt_non_standard_partner_user_attrs() {
777+
val sideloadedKit = Mockito.mock(MPSideloadedKit::class.java)
778+
val kitId = 6000000
779+
780+
val configJSONObj = JSONObject().apply {
781+
put("id", kitId)
782+
}
783+
val mockedKitConfig = KitConfiguration.createKitConfiguration(configJSONObj)
784+
Mockito.`when`(sideloadedKit.configuration).thenReturn(mockedKitConfig)
785+
786+
val settingsMap = hashMapOf(
787+
"placementAttributesMapping" to """
788+
[
789+
{"map": "number", "value": "no"},
790+
{"map": "customerId", "value": "minorcatid"}
791+
]
792+
""".trimIndent()
793+
)
794+
val field = KitConfiguration::class.java.getDeclaredField("settings")
795+
field.isAccessible = true
796+
field.set(mockedKitConfig, settingsMap)
797+
798+
val mockedProvider = mockProvider(mockedKitConfig)
799+
800+
val options = MParticleOptions.builder(MockContext())
801+
.sideloadedKits(mutableListOf(sideloadedKit) as List<SideloadedKit>).build()
802+
val manager: KitManagerImpl = MockKitManagerImpl(options)
803+
val factory = Mockito.mock(KitIntegrationFactory::class.java)
804+
manager.setKitFactory(factory)
805+
806+
Mockito.`when`(factory.isSupported(Mockito.anyInt())).thenReturn(true)
807+
val supportedKit = mutableSetOf(kitId)
808+
Mockito.`when`(manager.supportedKits).thenReturn(supportedKit)
809+
Mockito.`when`(sideloadedKit.isDisabled).thenReturn(false)
810+
Mockito.`when`(
811+
factory.createInstance(
812+
Mockito.any(
813+
KitManagerImpl::class.java
814+
),
815+
Mockito.any(KitConfiguration::class.java)
816+
)
817+
).thenReturn(sideloadedKit)
818+
manager.providers = ConcurrentHashMap<Int, KitIntegration>().apply {
819+
put(42, mockedProvider)
820+
}
821+
822+
val attributes = hashMapOf(
823+
Pair("test", "Test"),
824+
Pair("lastname", "Test1"),
825+
Pair("number", "(123) 456-9898"),
826+
Pair("customerId", "55555"),
827+
Pair("country", "US")
828+
)
829+
manager.execute("Test", attributes, null, null, null, null, null, null)
830+
Assert.assertEquals(5, attributes.size)
831+
Assert.assertEquals("(123) 456-9898", attributes["no"])
832+
Assert.assertEquals("55555", attributes["minorcatid"])
833+
Assert.assertEquals("Test1", attributes["lastname"])
834+
Assert.assertEquals("Test", attributes["test"])
835+
Assert.assertEquals("US", attributes["country"])
836+
}
837+
838+
@Test
839+
fun testExecute_shouldNotModifyAttributes_ifMappedKeysDoNotExist() {
840+
val sideloadedKit = Mockito.mock(MPSideloadedKit::class.java)
841+
val kitId = 6000000
842+
843+
val configJSONObj = JSONObject().apply {
844+
put("id", kitId)
845+
}
846+
val mockedKitConfig = KitConfiguration.createKitConfiguration(configJSONObj)
847+
Mockito.`when`(sideloadedKit.configuration).thenReturn(mockedKitConfig)
848+
849+
val settingsMap = hashMapOf(
850+
"placementAttributesMapping" to """
851+
[
852+
{"map": "number", "value": "no"},
853+
{"map": "customerId", "value": "minorcatid"}
854+
]
855+
""".trimIndent()
856+
)
857+
val field = KitConfiguration::class.java.getDeclaredField("settings")
858+
field.isAccessible = true
859+
field.set(mockedKitConfig, settingsMap)
860+
861+
val mockedProvider = mockProvider(mockedKitConfig)
862+
863+
val options = MParticleOptions.builder(MockContext())
864+
.sideloadedKits(mutableListOf(sideloadedKit) as List<SideloadedKit>).build()
865+
val manager: KitManagerImpl = MockKitManagerImpl(options)
866+
val factory = Mockito.mock(KitIntegrationFactory::class.java)
867+
manager.setKitFactory(factory)
868+
869+
Mockito.`when`(factory.isSupported(Mockito.anyInt())).thenReturn(true)
870+
val supportedKit = mutableSetOf(kitId)
871+
Mockito.`when`(manager.supportedKits).thenReturn(supportedKit)
872+
Mockito.`when`(sideloadedKit.isDisabled).thenReturn(false)
873+
Mockito.`when`(
874+
factory.createInstance(
875+
Mockito.any(
876+
KitManagerImpl::class.java
877+
),
878+
Mockito.any(KitConfiguration::class.java)
879+
)
880+
).thenReturn(sideloadedKit)
881+
manager.providers = ConcurrentHashMap<Int, KitIntegration>().apply {
882+
put(42, mockedProvider)
883+
}
884+
885+
val attributes = hashMapOf(
886+
Pair("test", "Test"),
887+
Pair("lastname", "Test1"),
888+
Pair("call", "(123) 456-9898"),
889+
Pair("postal", "5-45555"),
890+
Pair("country", "US")
891+
)
892+
manager.execute("Test", attributes, null, null, null, null, null, null)
893+
Assert.assertEquals(5, attributes.size)
894+
Assert.assertEquals("(123) 456-9898", attributes["call"])
895+
Assert.assertEquals("5-45555", attributes["postal"])
896+
Assert.assertEquals("Test1", attributes["lastname"])
897+
Assert.assertEquals("Test", attributes["test"])
898+
Assert.assertEquals("US", attributes["country"])
899+
}
900+
901+
@Test
902+
fun testExecute_shouldNotModifyAttributes_ifMapAndValueKeysAreSame() {
903+
val sideloadedKit = Mockito.mock(MPSideloadedKit::class.java)
904+
val kitId = 6000000
905+
906+
val configJSONObj = JSONObject().apply {
907+
put("id", kitId)
908+
}
909+
val mockedKitConfig = KitConfiguration.createKitConfiguration(configJSONObj)
910+
Mockito.`when`(sideloadedKit.configuration).thenReturn(mockedKitConfig)
911+
912+
val settingsMap = hashMapOf(
913+
"placementAttributesMapping" to """
914+
[
915+
{"map": "number", "value": "no"},
916+
{"map": "customerId", "value": "minorcatid"}
917+
]
918+
""".trimIndent()
919+
)
920+
val field = KitConfiguration::class.java.getDeclaredField("settings")
921+
field.isAccessible = true
922+
field.set(mockedKitConfig, settingsMap)
923+
924+
val mockedProvider = mockProvider(mockedKitConfig)
925+
926+
val options = MParticleOptions.builder(MockContext())
927+
.sideloadedKits(mutableListOf(sideloadedKit) as List<SideloadedKit>).build()
928+
val manager: KitManagerImpl = MockKitManagerImpl(options)
929+
val factory = Mockito.mock(KitIntegrationFactory::class.java)
930+
manager.setKitFactory(factory)
931+
932+
Mockito.`when`(factory.isSupported(Mockito.anyInt())).thenReturn(true)
933+
val supportedKit = mutableSetOf(kitId)
934+
Mockito.`when`(manager.supportedKits).thenReturn(supportedKit)
935+
Mockito.`when`(sideloadedKit.isDisabled).thenReturn(false)
936+
Mockito.`when`(
937+
factory.createInstance(
938+
Mockito.any(
939+
KitManagerImpl::class.java
940+
),
941+
Mockito.any(KitConfiguration::class.java)
942+
)
943+
).thenReturn(sideloadedKit)
944+
manager.providers = ConcurrentHashMap<Int, KitIntegration>().apply {
945+
put(42, mockedProvider)
946+
}
947+
948+
val attributes = hashMapOf(
949+
Pair("test", "Test"),
950+
Pair("lastname", "Test1"),
951+
Pair("no", "(123) 456-9898"),
952+
Pair("minorcatid", "5-45555"),
953+
Pair("country", "US")
954+
)
955+
manager.execute("Test", attributes, null, null, null, null, null, null)
956+
Assert.assertEquals(5, attributes.size)
957+
Assert.assertEquals("(123) 456-9898", attributes["no"])
958+
Assert.assertEquals("5-45555", attributes["minorcatid"])
959+
Assert.assertEquals("Test1", attributes["lastname"])
960+
Assert.assertEquals("Test", attributes["test"])
961+
Assert.assertEquals("US", attributes["country"])
962+
}
963+
964+
@Test
965+
fun testRokt_non_standard_partner_user_attrs_When_placementAttributes_is_empty() {
966+
val sideloadedKit = Mockito.mock(MPSideloadedKit::class.java)
967+
val kitId = 6000000
968+
969+
val configJSONObj = JSONObject().apply {
970+
put("id", kitId)
971+
}
972+
val mockedKitConfig = KitConfiguration.createKitConfiguration(configJSONObj)
973+
Mockito.`when`(sideloadedKit.configuration).thenReturn(mockedKitConfig)
974+
975+
val settingsMap = hashMapOf(
976+
"placementAttributesMapping" to """
977+
[
978+
979+
]
980+
""".trimIndent()
981+
)
982+
val field = KitConfiguration::class.java.getDeclaredField("settings")
983+
field.isAccessible = true
984+
field.set(mockedKitConfig, settingsMap)
985+
986+
val mockedProvider = mockProvider(mockedKitConfig)
987+
988+
val options = MParticleOptions.builder(MockContext())
989+
.sideloadedKits(mutableListOf(sideloadedKit) as List<SideloadedKit>).build()
990+
val manager: KitManagerImpl = MockKitManagerImpl(options)
991+
val factory = Mockito.mock(KitIntegrationFactory::class.java)
992+
manager.setKitFactory(factory)
993+
994+
Mockito.`when`(factory.isSupported(Mockito.anyInt())).thenReturn(true)
995+
val supportedKit = mutableSetOf(kitId)
996+
Mockito.`when`(manager.supportedKits).thenReturn(supportedKit)
997+
Mockito.`when`(sideloadedKit.isDisabled).thenReturn(false)
998+
Mockito.`when`(
999+
factory.createInstance(
1000+
Mockito.any(
1001+
KitManagerImpl::class.java
1002+
),
1003+
Mockito.any(KitConfiguration::class.java)
1004+
)
1005+
).thenReturn(sideloadedKit)
1006+
manager.providers = ConcurrentHashMap<Int, KitIntegration>().apply {
1007+
put(42, mockedProvider)
1008+
}
1009+
1010+
val attributes = hashMapOf(
1011+
Pair("test", "Test"),
1012+
Pair("lastname", "Test1"),
1013+
Pair("number", "(123) 456-9898"),
1014+
Pair("customerId", "55555"),
1015+
Pair("country", "US")
1016+
)
1017+
manager.execute("Test", attributes, null, null, null, null, null, null)
1018+
Assert.assertEquals(5, attributes.size)
1019+
Assert.assertEquals("(123) 456-9898", attributes["number"])
1020+
Assert.assertEquals("55555", attributes["customerId"])
1021+
Assert.assertEquals("Test1", attributes["lastname"])
1022+
Assert.assertEquals("Test", attributes["test"])
1023+
Assert.assertEquals("US", attributes["country"])
1024+
}
1025+
1026+
internal inner class mockProvider(val config: KitConfiguration) : KitIntegration(), KitIntegration.RoktListener {
1027+
override fun isDisabled(): Boolean = false
1028+
override fun getName(): String = "FakeProvider"
1029+
override fun onKitCreate(settings: MutableMap<String, String>?, context: Context?): MutableList<ReportingMessage> {
1030+
TODO("Not yet implemented")
1031+
}
1032+
1033+
override fun setOptOut(optedOut: Boolean): MutableList<ReportingMessage> {
1034+
TODO("Not yet implemented")
1035+
}
1036+
1037+
override fun getConfiguration(): KitConfiguration {
1038+
return config
1039+
}
1040+
1041+
override fun execute(
1042+
viewName: String?,
1043+
attributes: MutableMap<String, String>?,
1044+
onUnload: Runnable?,
1045+
onLoad: Runnable?,
1046+
onShouldHideLoadingIndicator: Runnable?,
1047+
onShouldShowLoadingIndicator: Runnable?,
1048+
placeHolders: MutableMap<String, WeakReference<RoktEmbeddedView>>?,
1049+
fontTypefaces: MutableMap<String, WeakReference<Typeface>>?,
1050+
user: FilteredMParticleUser?
1051+
) {
1052+
println("Executed with $attributes")
1053+
}
1054+
}
7701055
internal inner class KitManagerEventCounter : MockKitManagerImpl() {
7711056
var logBaseEventCalled = 0
7721057
var logCommerceEventCalled = 0

0 commit comments

Comments
 (0)