This is an automated email from the ASF dual-hosted git repository.
jkevan pushed a commit to branch unomi-1.x
in repository https://gitbox.apache.org/repos/asf/unomi.git
The following commit(s) were added to refs/heads/unomi-1.x by this push:
new 9d0bc24cb UNOMI-691: fix personalization strategy status stored on
profile during merge (#546)
9d0bc24cb is described below
commit 9d0bc24cb5f60bf5091657f67a28ea25d256708b
Author: kevan Jahanshahi <[email protected]>
AuthorDate: Thu Nov 17 14:57:46 2022 +0100
UNOMI-691: fix personalization strategy status stored on profile during
merge (#546)
---
.../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
+ }
}
}
}