This is an automated email from the ASF dual-hosted git repository.

jkevan pushed a commit to branch fixMergeControlGroup1.x
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 978929f69ef7bd69bcf236f554322ac5db34cba0
Author: Kevan <ke...@jahia.com>
AuthorDate: Thu Nov 17 13:54:44 2022 +0100

    UNOMI-691: fix personalization strategy status stored on profile during 
merge
---
 .../org/apache/unomi/itests/ProfileMergeIT.java    | 84 +++++++++++++++++++++-
 .../services/impl/profiles/ProfileServiceImpl.java | 37 +++++++---
 2 files changed, 109 insertions(+), 12 deletions(-)

diff --git a/itests/src/test/java/org/apache/unomi/itests/ProfileMergeIT.java 
b/itests/src/test/java/org/apache/unomi/itests/ProfileMergeIT.java
index 4512d024e..fb1cc40de 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ProfileMergeIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ProfileMergeIT.java
@@ -24,6 +24,7 @@ import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.rules.Rule;
 import org.apache.unomi.api.services.DefinitionsService;
 import org.apache.unomi.api.services.EventService;
+import org.apache.unomi.api.services.ProfileService;
 import org.apache.unomi.api.services.RulesService;
 import org.junit.After;
 import org.junit.Assert;
@@ -35,9 +36,7 @@ import org.ops4j.pax.exam.spi.reactors.PerSuite;
 import org.ops4j.pax.exam.util.Filter;
 
 import javax.inject.Inject;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
+import java.util.*;
 
 /**
  * Integration test for MergeProfilesOnPropertyAction
@@ -45,6 +44,10 @@ import java.util.HashMap;
 @RunWith(PaxExam.class)
 @ExamReactorStrategy(PerSuite.class)
 public class ProfileMergeIT extends BaseIT {
+    public static final String PERSONALIZATION_STRATEGY_STATUS = 
"personalizationStrategyStatus";
+    public static final String PERSONALIZATION_STRATEGY_STATUS_ID = 
"personalizationId";
+    public static final String PERSONALIZATION_STRATEGY_STATUS_IN_CTRL_GROUP = 
"inControlGroup";
+    public static final String PERSONALIZATION_STRATEGY_STATUS_DATE = 
"timeStamp";
 
     @Inject @Filter(timeout = 600000)
     protected EventService eventService;
@@ -52,6 +55,8 @@ public class ProfileMergeIT extends BaseIT {
     protected RulesService rulesService;
     @Inject @Filter(timeout = 600000)
     protected DefinitionsService definitionsService;
+    @Inject @Filter(timeout = 600000)
+    protected ProfileService profileService;
 
     private final static String TEST_EVENT_TYPE = "mergeProfileTestEventType";
     private final static String TEST_RULE_ID = "mergeOnPropertyTest";
@@ -79,6 +84,79 @@ public class ProfileMergeIT extends BaseIT {
         Assert.assertEquals(sendEvent().getProfile().getItemId(), 
TEST_PROFILE_ID);
     }
 
+    @Test
+    public void testPersonalizationStrategyStatusMerge() {
+        // create some statuses for the tests:
+        Map<String, Object> perso1true = 
buildPersonalizationStrategyStatus("perso-test-1", true);
+        Map<String, Object> perso1false = 
buildPersonalizationStrategyStatus("perso-test-1", false);
+        Map<String, Object> perso2false = 
buildPersonalizationStrategyStatus("perso-test-2", false);
+        Map<String, Object> perso3true = 
buildPersonalizationStrategyStatus("perso-test-3", true);
+
+        // create a single master profile we will keep along all the tests:
+        Profile profileMaster = new Profile("master-profile");
+
+        // merge test 1: Master do not have statuses, but slave have statuses
+        // master have: NULL
+        // slave have:  perso-test-1 -> true
+        //              perso-test-2 -> false
+        // Expected:    perso-test-1 -> true
+        //              perso-test-2 -> false
+        Profile profileSlave = new Profile("slave-profile");
+        profileSlave.setSystemProperty(PERSONALIZATION_STRATEGY_STATUS, new 
ArrayList<>(Arrays.asList(perso1true, perso2false)));
+        profileMaster = profileService.mergeProfiles(profileMaster, 
Collections.singletonList(profileSlave));
+        assertPersonalizationStrategyStatus(profileMaster,  
Arrays.asList(perso1true, perso2false));
+
+        // merge test 2: Master do not have statuses, but slave have statuses
+        // master have: perso-test-1 -> true
+        //              perso-test-2 -> false
+        // slave have:  NULL
+        // Expected:    perso-test-1 -> true
+        //              perso-test-2 -> false
+        profileSlave = new Profile("slave-profile");
+        profileMaster = profileService.mergeProfiles(profileMaster, 
Collections.singletonList(profileSlave));
+        assertPersonalizationStrategyStatus(profileMaster, 
Arrays.asList(perso1true, perso2false));
+
+        // merge test 3: both master and slave have strategy statuses and some 
are conflicting
+        // master have: perso-test-1 -> true
+        //              perso-test-2 -> false
+        // slave have:  perso-test-1 -> false (conflicting)
+        //              perso-test-3 -> true
+        // Expected:    perso-test-1 -> true
+        //              perso-test-2 -> false
+        //              perso-test-3 -> true
+        profileSlave = new Profile("slave-profile");
+        profileSlave.setSystemProperty(PERSONALIZATION_STRATEGY_STATUS, new 
ArrayList<>(Arrays.asList(perso1false, perso3true)));
+        profileMaster = profileService.mergeProfiles(profileMaster, 
Collections.singletonList(profileSlave));
+        assertPersonalizationStrategyStatus(profileMaster,  
Arrays.asList(perso1true, perso2false, perso3true));
+    }
+
+    private Map<String, Object> buildPersonalizationStrategyStatus(String 
persoId, boolean inControlGroup) {
+        Map<String, Object> personalizationStrategyStatus = new HashMap<>();
+        personalizationStrategyStatus.put(PERSONALIZATION_STRATEGY_STATUS_ID, 
persoId);
+        
personalizationStrategyStatus.put(PERSONALIZATION_STRATEGY_STATUS_DATE, new 
Date());
+        
personalizationStrategyStatus.put(PERSONALIZATION_STRATEGY_STATUS_IN_CTRL_GROUP,
 inControlGroup);
+        return personalizationStrategyStatus;
+    }
+
+    private void assertPersonalizationStrategyStatus(Profile profile, 
List<Map<String, Object>> expectedStatuses) {
+        List<Map<String, Object>> strategyStatuses = (List<Map<String, 
Object>>) profile.getSystemProperties().get(PERSONALIZATION_STRATEGY_STATUS);
+        Assert.assertEquals("We didn't get the good number of expected 
personalization statuses on the given profile: " + profile.getItemId(),
+                expectedStatuses.size(), strategyStatuses.size());
+        for (Map<String, Object> expectedStatus : expectedStatuses) {
+            Optional<Map<String, Object>> foundStatusOp = strategyStatuses
+                    .stream()
+                    .filter(strategyStatus -> 
strategyStatus.get(PERSONALIZATION_STRATEGY_STATUS_ID)
+                            
.equals(expectedStatus.get(PERSONALIZATION_STRATEGY_STATUS_ID)))
+                    .findFirst();
+            if (foundStatusOp.isPresent()) {
+                Map<String, Object> foundStatus = foundStatusOp.get();
+                
Assert.assertEquals(expectedStatus.get(PERSONALIZATION_STRATEGY_STATUS_DATE), 
foundStatus.get(PERSONALIZATION_STRATEGY_STATUS_DATE));
+                
Assert.assertEquals(expectedStatus.get(PERSONALIZATION_STRATEGY_STATUS_IN_CTRL_GROUP),
 foundStatus.get(PERSONALIZATION_STRATEGY_STATUS_IN_CTRL_GROUP));
+            } else {
+                Assert.fail("We didn't found the expected personalization: " + 
expectedStatus.get(PERSONALIZATION_STRATEGY_STATUS_ID) + " status on the given 
profile: " + profile.getItemId());
+            }
+        }
+    }
     private Event sendEvent() {
         Profile profile = new Profile();
         profile.setProperties(new HashMap<>());
diff --git 
a/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
 
b/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
index f9a9a6a41..76c175955 100644
--- 
a/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
+++ 
b/services/src/main/java/org/apache/unomi/services/impl/profiles/ProfileServiceImpl.java
@@ -33,6 +33,7 @@ import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.apache.unomi.persistence.spi.PropertyHelper;
 import org.apache.unomi.services.impl.ParserHelper;
+import org.apache.unomi.services.sorts.ControlGroupPersonalizationStrategy;
 import org.osgi.framework.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -1109,16 +1110,34 @@ public class ProfileServiceImpl implements 
ProfileService, SynchronousBundleList
                         }
                     } else if (targetProperty instanceof Collection && 
sourceProperty.getValue() instanceof Collection) {
                         // merge Collections like "lists"
-                        Collection sourceCollection = (Collection) 
sourceProperty.getValue();
-                        Collection targetCollection = (Collection) 
targetProperty;
-
-                        for (Object sourceItem : sourceCollection) {
-                            if (!targetCollection.contains(sourceItem)) {
-                                try {
-                                    targetCollection.add(sourceItem);
+                        if 
(ControlGroupPersonalizationStrategy.PERSONALIZATION_STRATEGY_STATUS.equals(sourceProperty.getKey()))
 {
+                            // Special handling for personalization strategy 
statuses
+                            // TODO UNOMI-719: move this in a dedicated 
extension point to handle this kind of merge strategy in a more generic way
+                            List<Map<String, Object>> sourceStatuses = 
(List<Map<String, Object>>) sourceProperty.getValue();
+                            List<Map<String, Object>> targetStatuses = 
(List<Map<String, Object>>) targetProperty;
+
+                            for (Map<String, Object> sourceStatus : 
sourceStatuses) {
+                                if (targetStatuses
+                                        .stream()
+                                        .noneMatch(targetStatus -> 
targetStatus.get(ControlGroupPersonalizationStrategy.PERSONALIZATION_STRATEGY_STATUS_ID)
+                                                
.equals(sourceStatus.get(ControlGroupPersonalizationStrategy.PERSONALIZATION_STRATEGY_STATUS_ID))))
 {
+                                    // there is no existing status for the 
status ID, we can safely add it to master
+                                    targetStatuses.add(sourceStatus);
                                     changed = true;
-                                } catch (Exception e) {
-                                    // may be Collection type issue
+                                }
+                            }
+                        } else {
+                            Collection sourceCollection = (Collection) 
sourceProperty.getValue();
+                            Collection targetCollection = (Collection) 
targetProperty;
+
+                            for (Object sourceItem : sourceCollection) {
+                                if (!targetCollection.contains(sourceItem)) {
+                                    try {
+                                        targetCollection.add(sourceItem);
+                                        changed = true;
+                                    } catch (Exception e) {
+                                        // may be Collection type issue
+                                    }
                                 }
                             }
                         }

Reply via email to