blob: 0ae2feb52679d821a6c9d09e04a2b81f87fb6ad7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package org.apache.unomi.itests;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.unomi.api.*;
import org.apache.unomi.api.conditions.ConditionType;
import org.apache.unomi.api.rules.Rule;
import org.apache.unomi.api.services.DefinitionsService;
import org.apache.unomi.api.services.ProfileService;
import org.apache.unomi.api.services.RulesService;
import org.apache.unomi.lifecycle.BundleWatcher;
import org.apache.unomi.persistence.spi.CustomObjectMapper;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerSuite;
import org.ops4j.pax.exam.util.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.util.*;
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerSuite.class)
public class BasicIT extends BaseIT {
private final static Logger LOGGER = LoggerFactory.getLogger(BasicIT.class);
private ObjectMapper objectMapper = new ObjectMapper();
private static final String SESSION_ID_0 = "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d0";
private static final String SESSION_ID_1 = "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d1";
private static final String SESSION_ID_2 = "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d2";
private static final String SESSION_ID_3 = "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d3";
private static final String SESSION_ID_4 = "aa3b04bd-8f4d-4a07-8e96-d33ffa04d3d4";
private static final String EVENT_TYPE_LOGIN = "login";
private static final String EVENT_TYPE_VIEW = "view";
private static final String TEST_SCOPE = "testScope";
private static final String ITEM_TYPE_SITE = "site";
private static final String ITEM_ID_SITE = "/test/site";
private static final String ITEM_TYPE_VISITOR = "VISITOR";
private static final String ITEM_ID_PAGE_1 = "/test/site/page1";
private static final String ITEM_TYPE_PAGE = "page";
private static final String FIRST_NAME = "firstName";
private static final String LAST_NAME = "lastName";
private static final String EMAIL = "email";
private static final String FIRST_NAME_VISITOR_1 = "firstNameVisitor1";
private static final String FIRST_NAME_VISITOR_2 = "firstNameVisitor2";
private static final String LAST_NAME_VISITOR_1 = "lastNameVisitor1";
private static final String LAST_NAME_VISITOR_2 = "lastNameVisitor2";
private static final String EMAIL_VISITOR_1 = "visitor1@apache.unomi.org";
private static final String EMAIL_VISITOR_2 = "visitor2@apache.unomi.org";
@Inject @Filter(timeout = 600000)
protected RulesService rulesService;
@Inject @Filter(timeout = 600000)
protected ProfileService profileService;
@Inject @Filter(timeout = 600000)
protected DefinitionsService definitionsService;
@Inject @Filter(timeout = 600000)
protected BundleWatcher bundleWatcher;
@Before
public void setUp() throws InterruptedException {
while (!bundleWatcher.isStartupComplete()) {
LOGGER.info("Waiting for startup to complete...");
Thread.sleep(1000);
}
}
@Test
public void testContextJS() throws IOException {
LOGGER.info("Start test testContextJS");
HttpUriRequest request = new HttpGet(URL + "/context.js?sessionId=" + SESSION_ID_0);
// The underlying HTTP connection is still held by the response object
// to allow the response content to be streamed directly from the network socket.
// In order to ensure correct deallocation of system resources
// the profile MUST call CloseableHttpResponse#close() from a finally clause.
// Please note that if response content is not fully consumed the underlying
// connection cannot be safely re-used and will be shut down and discarded
// by the connection manager.
String responseContent;
try (CloseableHttpResponse response = HttpClientBuilder.create().build().execute(request)) {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
// do something useful with the response body
// and ensure it is fully consumed
responseContent = EntityUtils.toString(entity);
}
Assert.assertTrue("Response should contain context object", responseContent.contains("window.digitalData = window.digitalData || {};\n"));
// @todo we should check the validity of the context object, but this is rather complex since it would potentially require parsing the Javascript !
LOGGER.info("End test testContextJS");
}
@Test
public void testContextJSONWithUrlParameter() throws IOException, InterruptedException {
LOGGER.info("Start test testContextJSONWithUrlParameter");
ContextRequest contextRequest = new ContextRequest();
HttpPost request = new HttpPost(URL + "/context.json?sessionId=" + SESSION_ID_1);
request.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequest), ContentType.create("application/json")));
executeContextJSONRequest(request, SESSION_ID_1);
LOGGER.info("End test testContextJSONWithUrlParameter");
}
@Test
public void testContextJSON() throws IOException, InterruptedException {
LOGGER.info("Start test testContextJSON");
ContextRequest contextRequest = new ContextRequest();
contextRequest.setSessionId(SESSION_ID_2);
HttpPost request = new HttpPost(URL + "/context.json");
request.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequest), ContentType.create("application/json")));
executeContextJSONRequest(request, SESSION_ID_2);
LOGGER.info("End test testContextJSON");
}
@Test
public void testMultipleLoginOnSameBrowser() throws IOException, InterruptedException {
LOGGER.info("Start test testMultipleLoginOnSameBrowser");
// Add login event condition
ConditionType conditionType = CustomObjectMapper.getObjectMapper().readValue(
new File("data/tmp/testLoginEventCondition.json").toURI().toURL(), ConditionType.class);
definitionsService.setConditionType(conditionType);
Thread.sleep(2000);
// Add login rule
Rule rule = CustomObjectMapper.getObjectMapper().readValue(new File("data/tmp/testLogin.json").toURI().toURL(),
Rule.class);
rulesService.setRule(rule);
Thread.sleep(2000);
CustomItem sourceSite = new CustomItem(ITEM_ID_SITE, ITEM_TYPE_SITE);
sourceSite.setScope(TEST_SCOPE);
// First page view with the first visitor aka VISITOR_1 and SESSION_ID_3
ContextRequest contextRequestPageViewSession1 = getContextRequestWithPageViewEvent(sourceSite, SESSION_ID_3);
HttpPost requestPageView1 = new HttpPost(URL + "/context.json");
requestPageView1.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequestPageViewSession1),
ContentType.create("application/json")));
TestUtils.RequestResponse requestResponsePageView1 = executeContextJSONRequest(requestPageView1, SESSION_ID_3);
String profileIdVisitor1 = requestResponsePageView1.getContextResponse().getProfileId();
Thread.sleep(1000);
// Initialize VISITOR_1 properties
Map<String, Object> loginEventPropertiesVisitor1 = new HashMap<>();
loginEventPropertiesVisitor1.put(FIRST_NAME, FIRST_NAME_VISITOR_1);
loginEventPropertiesVisitor1.put(LAST_NAME, LAST_NAME_VISITOR_1);
loginEventPropertiesVisitor1.put(EMAIL, EMAIL_VISITOR_1);
// Create login event with VISITOR_1
ContextRequest contextRequestLoginVisitor1 = getContextRequestWithLoginEvent(sourceSite, loginEventPropertiesVisitor1,
EMAIL_VISITOR_1, SESSION_ID_3);
HttpPost requestLoginVisitor1 = new HttpPost(URL + "/context.json");
requestLoginVisitor1.addHeader("Cookie", requestResponsePageView1.getCookieHeaderValue());
requestLoginVisitor1.addHeader("X-Unomi-Peer", UNOMI_KEY);
requestLoginVisitor1.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequestLoginVisitor1),
ContentType.create("application/json")));
TestUtils.RequestResponse requestResponseLoginVisitor1 = executeContextJSONRequest(requestLoginVisitor1, SESSION_ID_3);
Assert.assertEquals("Context profile id should be the same", profileIdVisitor1,
requestResponseLoginVisitor1.getContextResponse().getProfileId());
checkVisitor1ResponseProperties(requestResponseLoginVisitor1.getContextResponse().getProfileProperties());
Thread.sleep(1000);
// Lets add a page view with VISITOR_1 to simulate reloading the page after login and be able to check the profile properties
HttpPost requestPageView2 = new HttpPost(URL + "/context.json");
requestPageView2.addHeader("Cookie", requestResponsePageView1.getCookieHeaderValue());
requestPageView2.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequestPageViewSession1),
ContentType.create("application/json")));
TestUtils.RequestResponse requestResponsePageView2 = executeContextJSONRequest(requestPageView2, SESSION_ID_3);
Assert.assertEquals("Context profile id should be the same", profileIdVisitor1,
requestResponsePageView2.getContextResponse().getProfileId());
checkVisitor1ResponseProperties(requestResponsePageView2.getContextResponse().getProfileProperties());
Thread.sleep(1000);
// Lets simulate a logout by requesting the context with a new page view event and a new session id
// but we will send the cookie of the profile id from VISITOR_1
ContextRequest contextRequestPageViewSession2 = getContextRequestWithPageViewEvent(sourceSite, SESSION_ID_4);
HttpPost requestPageView3 = new HttpPost(URL + "/context.json");
requestPageView3.addHeader("Cookie", requestResponsePageView1.getCookieHeaderValue());
requestPageView3.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequestPageViewSession2),
ContentType.create("application/json")));
TestUtils.RequestResponse requestResponsePageView3 = executeContextJSONRequest(requestPageView3, SESSION_ID_4);
Assert.assertEquals("Context profile id should be the same", profileIdVisitor1,
requestResponsePageView3.getContextResponse().getProfileId());
checkVisitor1ResponseProperties(requestResponsePageView3.getContextResponse().getProfileProperties());
Thread.sleep(1000);
// Initialize VISITOR_2 properties
Map<String, Object> loginEventPropertiesVisitor2 = new HashMap<>();
loginEventPropertiesVisitor2.put(FIRST_NAME, FIRST_NAME_VISITOR_2);
loginEventPropertiesVisitor2.put(LAST_NAME, LAST_NAME_VISITOR_2);
loginEventPropertiesVisitor2.put(EMAIL, EMAIL_VISITOR_2);
// Create login event with VISITOR_2
ContextRequest contextRequestLoginVisitor2 = getContextRequestWithLoginEvent(sourceSite, loginEventPropertiesVisitor2,
EMAIL_VISITOR_2, SESSION_ID_4);
HttpPost requestLoginVisitor2 = new HttpPost(URL + "/context.json");
requestLoginVisitor2.addHeader("Cookie", requestResponsePageView1.getCookieHeaderValue());
requestLoginVisitor2.addHeader("X-Unomi-Peer", UNOMI_KEY);
requestLoginVisitor2.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequestLoginVisitor2),
ContentType.create("application/json")));
TestUtils.RequestResponse requestResponseLoginVisitor2 = executeContextJSONRequest(requestLoginVisitor2, SESSION_ID_4);
// We should have a new profile id so the session should have been moved from VISITOR_1 to VISITOR_2
String profileIdVisitor2 = requestResponseLoginVisitor2.getContextResponse().getProfileId();
Assert.assertNotEquals("Context profile id should not be the same", profileIdVisitor1,
profileIdVisitor2);
checkVisitor2ResponseProperties(requestResponseLoginVisitor2.getContextResponse().getProfileProperties());
Thread.sleep(1000);
// Lets add a page view with VISITOR_2 to simulate reloading the page after login
HttpPost requestPageView4 = new HttpPost(URL + "/context.json");
requestPageView4.addHeader("Cookie", requestResponseLoginVisitor2.getCookieHeaderValue());
requestPageView4.setEntity(new StringEntity(objectMapper.writeValueAsString(contextRequestPageViewSession2),
ContentType.create("application/json")));
TestUtils.RequestResponse requestResponsePageView4 = executeContextJSONRequest(requestPageView4, SESSION_ID_4);
Assert.assertEquals("Context profile id should be the same", profileIdVisitor2,
requestResponsePageView4.getContextResponse().getProfileId());
checkVisitor2ResponseProperties(requestResponsePageView4.getContextResponse().getProfileProperties());
Thread.sleep(1000);
// Check both visitor profile at the end by loading them directly
Profile profileVisitor1 = profileService.load(profileIdVisitor1);
checkVisitor1ResponseProperties(profileVisitor1.getProperties());
Profile profileVisitor2 = profileService.load(profileIdVisitor2);
checkVisitor2ResponseProperties(profileVisitor2.getProperties());
LOGGER.info("End test testMultipleLoginOnSameBrowser");
}
private ContextRequest getContextRequestWithLoginEvent(CustomItem sourceSite, Map<String, Object> loginEventProperties,
String visitorId, String sessionId) {
CustomItem loginEventTarget = new CustomItem(visitorId, ITEM_TYPE_VISITOR);
loginEventTarget.setProperties(loginEventProperties);
Event loginEvent = new Event(EVENT_TYPE_LOGIN, null, new Profile(""), TEST_SCOPE,
null, loginEventTarget, new Date());
ContextRequest contextRequest = new ContextRequest();
contextRequest.setSource(sourceSite);
contextRequest.setRequireSegments(false);
contextRequest.setEvents(Collections.singletonList(loginEvent));
contextRequest.setRequiredProfileProperties(Arrays.asList(FIRST_NAME, LAST_NAME, EMAIL));
contextRequest.setSessionId(sessionId);
return contextRequest;
}
private ContextRequest getContextRequestWithPageViewEvent(CustomItem sourceSite, String sessionId) {
CustomItem customPageItem = new CustomItem(ITEM_ID_PAGE_1, ITEM_TYPE_PAGE);
customPageItem.setScope(TEST_SCOPE);
Map<String, Object> pageInfo = new HashMap<>();
pageInfo.put("referringURL", "http://localhost:8080");
Map<String, Object> properties = new HashMap<>();
properties.put("pageInfo", pageInfo);
customPageItem.setProperties(properties);
// Create page view event to mock a connection to a site
Event pageViewEvent = new Event(EVENT_TYPE_VIEW, null, new Profile(""), TEST_SCOPE, sourceSite, customPageItem, new Date());
// Initialize context like if you display the first page on the website
ContextRequest contextRequest = new ContextRequest();
contextRequest.setSessionId(sessionId);
contextRequest.setSource(customPageItem);
contextRequest.setRequireSegments(false);
contextRequest.setEvents(Collections.singletonList(pageViewEvent));
contextRequest.setRequiredProfileProperties(Arrays.asList(FIRST_NAME, LAST_NAME, EMAIL));
return contextRequest;
}
private TestUtils.RequestResponse executeContextJSONRequest(HttpPost request, String sessionId) throws IOException {
return TestUtils.executeContextJSONRequest(request, sessionId);
}
private void checkVisitor1ResponseProperties(Map<String, Object> profileProperties) {
checkVisitorResponseProperties(profileProperties, FIRST_NAME_VISITOR_1, LAST_NAME_VISITOR_1, EMAIL_VISITOR_1);
}
private void checkVisitor2ResponseProperties(Map<String, Object> profileProperties) {
checkVisitorResponseProperties(profileProperties, FIRST_NAME_VISITOR_2, LAST_NAME_VISITOR_2, EMAIL_VISITOR_2);
}
private void checkVisitorResponseProperties(Map<String, Object> profileProperties, String firstNameVisitor,
String lastNameVisitor, String emailVisitor) {
Assert.assertNotNull("Context profile properties should not be null", profileProperties);
Assert.assertTrue("Context profile properties should contains the entry " + FIRST_NAME,
profileProperties.containsKey(FIRST_NAME));
Assert.assertTrue("Context profile properties should contains the entry " + LAST_NAME,
profileProperties.containsKey(LAST_NAME));
Assert.assertTrue("Context profile properties should contains the entry " + EMAIL,
profileProperties.containsKey(EMAIL));
Assert.assertEquals("Context profile properties " + FIRST_NAME + " should be equal to " + firstNameVisitor,
profileProperties.get(FIRST_NAME), firstNameVisitor);
Assert.assertEquals("Context profile properties " + LAST_NAME + " should be equal to " + lastNameVisitor,
profileProperties.get(LAST_NAME), lastNameVisitor);
Assert.assertEquals("Context profile properties " + EMAIL + " should be equal to " + emailVisitor,
profileProperties.get(EMAIL), emailVisitor);
}
}