UNOMI-414 Fix the ScorePersonalizationStrategy (#235)
* UNOMI-414 Fix the ScorePersonalizationStrategy
Avoid nullpointer when the profile doesnt have any interests
* UNOMI-414 Add integration tests
Co-authored-by: Serge Huber <shuber@jahia.com>
diff --git a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
index ba9392b..9d5d06e 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
@@ -557,4 +557,17 @@
assertFalse("Vulnerability successfully executed ! File created at " + vulnFileCanonicalPath, vulnFile.exists());
}
+
+ @Test
+ public void testPersonalization() throws IOException, InterruptedException {
+
+ Map<String,String> parameters = new HashMap<>();
+ HttpPost request = new HttpPost(URL + CONTEXT_URL);
+ request.setEntity(new StringEntity(getValidatedBundleJSON("personalization.json", parameters), ContentType.create("application/json")));
+ TestUtils.RequestResponse response = TestUtils.executeContextJSONRequest(request);
+ assertEquals("Invalid response code", 200, response.getStatusCode());
+ refreshPersistence();
+ Thread.sleep(2000); //Making sure event is updated in DB
+
+ }
}
diff --git a/itests/src/test/java/org/apache/unomi/itests/TestUtils.java b/itests/src/test/java/org/apache/unomi/itests/TestUtils.java
index 5e385f5..97feed0 100644
--- a/itests/src/test/java/org/apache/unomi/itests/TestUtils.java
+++ b/itests/src/test/java/org/apache/unomi/itests/TestUtils.java
@@ -86,7 +86,7 @@
if (response.containsHeader("Set-Cookie")) {
cookieHeader = response.getHeaders("Set-Cookie")[0].toString().substring(12);
}
- return new RequestResponse(context, cookieHeader);
+ return new RequestResponse(response.getStatusLine().getStatusCode(), context, cookieHeader);
}
}
@@ -124,10 +124,12 @@
public static class RequestResponse {
private ContextResponse contextResponse;
private String cookieHeaderValue;
+ int statusCode;
- public RequestResponse(ContextResponse contextResponse, String cookieHeaderValue) {
+ public RequestResponse(int statusCode, ContextResponse contextResponse, String cookieHeaderValue) {
this.contextResponse = contextResponse;
this.cookieHeaderValue = cookieHeaderValue;
+ this.statusCode = statusCode;
}
public ContextResponse getContextResponse() {
@@ -137,5 +139,9 @@
public String getCookieHeaderValue() {
return cookieHeaderValue;
}
+
+ public int getStatusCode() {
+ return statusCode;
+ }
}
}
diff --git a/itests/src/test/resources/personalization.json b/itests/src/test/resources/personalization.json
new file mode 100644
index 0000000..7c5723a
--- /dev/null
+++ b/itests/src/test/resources/personalization.json
@@ -0,0 +1,284 @@
+{
+ "source": {
+ "itemId": "CMSServer",
+ "itemType": "custom",
+ "scope": "acme",
+ "version": null,
+ "properties": {}
+ },
+ "requireSegments": true,
+ "requiredProfileProperties": [
+ "interests"
+ ],
+ "requiredSessionProperties": [
+ "*"
+ ],
+ "events": null,
+ "filters": null,
+ "personalizations": [
+ {
+ "id": "recommendations-by-interest",
+ "strategy": "score-sorted",
+ "strategyOptions": {
+ "threshold": -1
+ },
+ "contents": [
+ {
+ "id": "ac02dbe3-2445-4727-acea-50cfed001996",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "ac02dbe3-2445-4727-acea-50cfed001996"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": {
+ "interests": "health food"
+ }
+ },
+ {
+ "id": "62194fdd-2a1c-46ce-8f9b-19dc168f3454",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "62194fdd-2a1c-46ce-8f9b-19dc168f3454"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "dbb3a797-d24e-4701-97ad-dc0a708fa06f",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "dbb3a797-d24e-4701-97ad-dc0a708fa06f"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "90664d1d-6558-4239-a024-8212f2652673",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "90664d1d-6558-4239-a024-8212f2652673"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "f13af275-2002-4200-bd58-96847c74dafb",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "f13af275-2002-4200-bd58-96847c74dafb"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "2305ab1a-f6b1-47c1-bc46-a8c69c553d87",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "2305ab1a-f6b1-47c1-bc46-a8c69c553d87"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "50c4064c-ef6e-4afe-adcf-f876111f50bc",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "50c4064c-ef6e-4afe-adcf-f876111f50bc"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "55371bb0-c516-4038-ab6d-0acab57b4790",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "55371bb0-c516-4038-ab6d-0acab57b4790"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "eaaa15eb-e2c2-49cf-bb99-20ea90bd3fdb",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "eaaa15eb-e2c2-49cf-bb99-20ea90bd3fdb"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ },
+ {
+ "id": "15cdd5dd-909d-4d91-8f79-62226b96843a",
+ "filters": [
+ {
+ "appliesOn": null,
+ "condition": {
+ "parameterValues": {
+ "minimumEventCount": 1,
+ "eventCondition": {
+ "type": "pageViewEventCondition",
+ "parameterValues": {
+ "pageID": "15cdd5dd-909d-4d91-8f79-62226b96843a"
+ }
+ },
+ "numberOfDays": 30
+ },
+ "type": "pastEventCondition"
+ },
+ "properties": {
+ "score": -1000
+ }
+ }
+ ],
+ "properties": null
+ }
+ ]
+ }
+ ],
+ "profileOverrides": null,
+ "sessionPropertiesOverrides": null,
+ "sessionId": "21bf6d3d-ba5d-4b8c-98bb-af4dcf506c03"
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java b/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java
index f3b6cf5..7e636d3 100644
--- a/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java
+++ b/services/src/main/java/org/apache/unomi/services/sorts/ScorePersonalizationStrategy.java
@@ -51,7 +51,7 @@
if (interestList != null) {
Map<String,Integer> interestValues = (Map<String, Integer>) profile.getProperties().get("interests");
for (String interest : interestList.split(" ")) {
- if (interestValues.get(interest) != null) {
+ if (interestValues != null && interestValues.get(interest) != null) {
score += interestValues.get(interest);
}
}