package org.piwik.sdk;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.piwik.sdk.dispatcher.DispatchMode;
import org.piwik.sdk.dispatcher.Dispatcher;
import org.piwik.sdk.dispatcher.DispatcherFactory;
import org.piwik.sdk.extra.TrackHelper;
import org.piwik.sdk.testhelper.TestPreferences;
import org.piwik.sdk.tools.DeviceHelper;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.piwik.sdk.QueryParams.FIRST_VISIT_TIMESTAMP;
import static org.piwik.sdk.QueryParams.SESSION_START;
@SuppressWarnings("PointlessArithmeticExpression")
public class TrackerTest {
ArgumentCaptor<TrackMe> mCaptor = ArgumentCaptor.forClass(TrackMe.class);
Tracker mTracker;
@Mock Piwik mPiwik;
@Mock Context mContext;
@Mock Dispatcher mDispatcher;
@Mock DispatcherFactory mDispatcherFactory;
@Mock DeviceHelper mDeviceHelper;
SharedPreferences mTrackerPreferences = new TestPreferences();
SharedPreferences mPiwikPreferences = new TestPreferences();
private final String mApiUrl = "http://example.com";
private final int mSiteId = 11;
private final String mName = "Default Tracker";
private final TrackerConfig mTrackerConfig = new TrackerConfig(mApiUrl, mSiteId, mName);
@Before
public void setup() throws PackageManager.NameNotFoundException, MalformedURLException {
MockitoAnnotations.initMocks(this);
when(mPiwik.getContext()).thenReturn(mContext);
when(mContext.getPackageName()).thenReturn("package");
when(mPiwik.getTrackerPreferences(any(Tracker.class))).thenReturn(mTrackerPreferences);
when(mPiwik.getPiwikPreferences()).thenReturn(mPiwikPreferences);
when(mPiwik.getDispatcherFactory()).thenReturn(mDispatcherFactory);
when(mPiwik.getApplicationDomain()).thenReturn("org.piwik.sdk.test");
when(mDispatcherFactory.build(any(Tracker.class))).thenReturn(mDispatcher);
when(mPiwik.getDeviceHelper()).thenReturn(mDeviceHelper);
when(mDeviceHelper.getResolution()).thenReturn(new int[]{480, 800});
when(mDeviceHelper.getUserAgent()).thenReturn("aUserAgent");
when(mDeviceHelper.getUserLanguage()).thenReturn("en");
mTracker = new Tracker(mPiwik, mTrackerConfig);
}
@Test
public void testGetPreferences() {
Tracker tracker1 = new Tracker(mPiwik, new TrackerConfig(mApiUrl, mSiteId, "Tracker1"));
verify(mPiwik).getTrackerPreferences(tracker1);
Tracker tracker2 = new Tracker(mPiwik, new TrackerConfig(mApiUrl, mSiteId, "Tracker2"));
verify(mPiwik).getTrackerPreferences(tracker2);
}
@Test
public void testLastScreenUrl() throws Exception {
mTracker.track(new TrackMe());
verify(mDispatcher).submit(mCaptor.capture());
assertEquals(mTracker.getApplicationBaseURL() + "/", mCaptor.getValue().get(QueryParams.URL_PATH));
mTracker.track(new TrackMe().set(QueryParams.URL_PATH, "http://some.thing.com/foo/bar"));
verify(mDispatcher, times(2)).submit(mCaptor.capture());
assertEquals("http://some.thing.com/foo/bar", mCaptor.getValue().get(QueryParams.URL_PATH));
mTracker.track(new TrackMe().set(QueryParams.URL_PATH, "http://some.other/thing"));
verify(mDispatcher, times(3)).submit(mCaptor.capture());
assertEquals("http://some.other/thing", mCaptor.getValue().get(QueryParams.URL_PATH));
mTracker.track(new TrackMe());
verify(mDispatcher, times(4)).submit(mCaptor.capture());
assertEquals("http://some.other/thing", mCaptor.getValue().get(QueryParams.URL_PATH));
}
@Test
public void testSetDispatchInterval() throws Exception {
mTracker.setDispatchInterval(1);
verify(mDispatcher).setDispatchInterval(1);
mTracker.getDispatchInterval();
verify(mDispatcher).getDispatchInterval();
}
@Test
public void testSetDispatchTimeout() throws Exception {
int timeout = 1337;
mTracker.setDispatchTimeout(timeout);
verify(mDispatcher).setConnectionTimeOut(timeout);
mTracker.getDispatchTimeout();
verify(mDispatcher).getConnectionTimeOut();
}
@Test
public void testGetOfflineCacheAge_defaultValue() throws Exception {
assertEquals(24 * 60 * 60 * 1000, mTracker.getOfflineCacheAge());
}
@Test
public void testSetOfflineCacheAge() throws Exception {
mTracker.setOfflineCacheAge(80085);
assertEquals(80085, mTracker.getOfflineCacheAge());
}
@Test
public void testGetOfflineCacheSize_defaultValue() throws Exception {
assertEquals(4 * 1024 * 1024, mTracker.getOfflineCacheSize());
}
@Test
public void testSetOfflineCacheSize() throws Exception {
mTracker.setOfflineCacheSize(16 * 1000 * 1000);
assertEquals(16 * 1000 * 1000, mTracker.getOfflineCacheSize());
}
@Test
public void testSetDispatchMode() throws MalformedURLException {
assertEquals(DispatchMode.ALWAYS, mTracker.getDispatchMode());
verify(mDispatcher, times(1)).setDispatchMode(DispatchMode.ALWAYS);
mTracker.setDispatchMode(DispatchMode.WIFI_ONLY);
assertEquals(DispatchMode.WIFI_ONLY, mTracker.getDispatchMode());
verify(mDispatcher, times(1)).setDispatchMode(DispatchMode.WIFI_ONLY);
mTracker.getPreferences().edit().putString(Tracker.PREF_KEY_DISPATCHER_MODE, "lol").apply();
assertEquals(DispatchMode.ALWAYS, mTracker.getDispatchMode());
verify(mDispatcher, times(2)).setDispatchMode(DispatchMode.ALWAYS);
mTracker.setDispatchMode(DispatchMode.WIFI_ONLY);
assertEquals(DispatchMode.WIFI_ONLY, mTracker.getDispatchMode());
verify(mDispatcher, times(2)).setDispatchMode(DispatchMode.WIFI_ONLY);
}
@Test
public void testsetDispatchGzip() {
mTracker.setDispatchGzipped(true);
verify(mDispatcher).setDispatchGzipped(true);
}
@Test
public void testOptOut_set() throws Exception {
mTracker.setOptOut(true);
verify(mDispatcher).clear();
assertTrue(mTracker.isOptOut());
mTracker.setOptOut(false);
assertFalse(mTracker.isOptOut());
}
@Test
public void testOptOut_init() throws Exception {
mTrackerPreferences.edit().putBoolean(Tracker.PREF_KEY_TRACKER_OPTOUT, false).apply();
Tracker tracker = new Tracker(mPiwik, mTrackerConfig);
assertFalse(tracker.isOptOut());
mTrackerPreferences.edit().putBoolean(Tracker.PREF_KEY_TRACKER_OPTOUT, true).apply();
tracker = new Tracker(mPiwik, mTrackerConfig);
assertTrue(tracker.isOptOut());
}
@Test
public void testDispatch() {
mTracker.dispatch();
verify(mDispatcher).forceDispatch();
mTracker.dispatch();
verify(mDispatcher, times(2)).forceDispatch();
}
@Test
public void testDispatch_optOut() {
mTracker.setOptOut(true);
mTracker.dispatch();
verify(mDispatcher, never()).forceDispatch();
mTracker.setOptOut(false);
mTracker.dispatch();
verify(mDispatcher).forceDispatch();
}
@Test
public void testGetSiteId() throws Exception {
assertEquals(mTracker.getSiteId(), 11);
}
@Test
public void testGetPiwik() throws Exception {
assertEquals(mPiwik, mTracker.getPiwik());
}
@Test
public void testSetURL() throws Exception {
mTracker.setApplicationDomain("test.com");
assertEquals(mTracker.getApplicationDomain(), "test.com");
assertEquals(mTracker.getApplicationBaseURL(), "http://test.com");
TrackMe trackMe = new TrackMe();
mTracker.track(trackMe);
assertEquals("http://test.com/", trackMe.get(QueryParams.URL_PATH));
trackMe.set(QueryParams.URL_PATH, "me");
mTracker.track(trackMe);
assertEquals("http://test.com/me", trackMe.get(QueryParams.URL_PATH));
// override protocol
trackMe.set(QueryParams.URL_PATH, "https://my.com/secure");
mTracker.track(trackMe);
assertEquals("https://my.com/secure", trackMe.get(QueryParams.URL_PATH));
}
@Test
public void testSetApplicationDomain() throws Exception {
mTracker.setApplicationDomain("my-domain.com");
TrackHelper.track().screen("test/test").title("Test title").with(mTracker);
verify(mDispatcher).submit(mCaptor.capture());
validateDefaultQuery(mCaptor.getValue());
assertTrue(mCaptor.getValue().get(QueryParams.URL_PATH).equals("http://my-domain.com/test/test"));
}
@Test(expected = IllegalArgumentException.class)
public void testSetTooShortVistorId() throws MalformedURLException {
String tooShortVisitorId = "0123456789ab";
mTracker.setVisitorId(tooShortVisitorId);
assertNotEquals(tooShortVisitorId, mTracker.getVisitorId());
}
@Test(expected = IllegalArgumentException.class)
public void testSetTooLongVistorId() throws MalformedURLException {
String tooLongVisitorId = "0123456789abcdefghi";
mTracker.setVisitorId(tooLongVisitorId);
assertNotEquals(tooLongVisitorId, mTracker.getVisitorId());
}
@Test(expected = IllegalArgumentException.class)
public void testSetVistorIdWithInvalidCharacters() throws MalformedURLException {
String invalidCharacterVisitorId = "01234-6789-ghief";
mTracker.setVisitorId(invalidCharacterVisitorId);
assertNotEquals(invalidCharacterVisitorId, mTracker.getVisitorId());
}
@Test
public void testSetVistorId() throws Exception {
String visitorId = "0123456789abcdef";
mTracker.setVisitorId(visitorId);
assertEquals(visitorId, mTracker.getVisitorId());
TrackMe trackMe = new TrackMe();
mTracker.track(trackMe);
verify(mDispatcher).submit(mCaptor.capture());
assertEquals(visitorId, mCaptor.getValue().get(QueryParams.VISITOR_ID));
}
@Test
public void testSetUserId() throws Exception {
assertNotNull(mTracker.getDefaultTrackMe().get(QueryParams.USER_ID));
mTracker.setUserId("test");
assertEquals(mTracker.getUserId(), "test");
mTracker.setUserId("");
assertEquals(mTracker.getUserId(), "test");
mTracker.setUserId(null);
assertNull(mTracker.getUserId());
String uuid = UUID.randomUUID().toString();
mTracker.setUserId(uuid);
assertEquals(uuid, mTracker.getUserId());
assertEquals(uuid, mTracker.getUserId());
}
@Test
public void testGetResolution() throws Exception {
TrackMe trackMe = new TrackMe();
mTracker.track(trackMe);
verify(mDispatcher).submit(mCaptor.capture());
assertEquals("480x800", mCaptor.getValue().get(QueryParams.SCREEN_RESOLUTION));
}
@Test
public void testSetNewSession() throws Exception {
TrackMe trackMe = new TrackMe();
mTracker.track(trackMe);
verify(mDispatcher).submit(mCaptor.capture());
assertEquals("1", mCaptor.getValue().get(QueryParams.SESSION_START));
TrackHelper.track().screen("").with(mTracker);
verify(mDispatcher, times(2)).submit(mCaptor.capture());
assertEquals(null, mCaptor.getValue().get(QueryParams.SESSION_START));
TrackHelper.track().screen("").with(mTracker);
verify(mDispatcher, times(3)).submit(mCaptor.capture());
assertEquals(null, mCaptor.getValue().get(QueryParams.SESSION_START));
mTracker.startNewSession();
TrackHelper.track().screen("").with(mTracker);
verify(mDispatcher, times(4)).submit(mCaptor.capture());
assertEquals("1", mCaptor.getValue().get(QueryParams.SESSION_START));
}
@Test
public void testSetNewSessionRaceCondition() throws Exception {
for (int retry = 0; retry < 5; retry++) {
final List<TrackMe> trackMes = Collections.synchronizedList(new ArrayList<TrackMe>());
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
trackMes.add((TrackMe) invocation.getArgument(0));
return null;
}
}).when(mDispatcher).submit(any(TrackMe.class));
final Tracker tracker = new Tracker(mPiwik, mTrackerConfig);
tracker.setDispatchInterval(0);
int count = 20;
for (int i = 0; i < count; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
TrackHelper.track().screen("Test").with(tracker);
}
}).start();
}
Thread.sleep(500);
assertEquals(count, trackMes.size());
int found = 0;
for (TrackMe trackMe : trackMes) {
if (trackMe.get(QueryParams.SESSION_START) != null) found++;
}
assertEquals(1, found);
}
}
@Test
public void testSetSessionTimeout() throws Exception {
mTracker.setSessionTimeout(10000);
TrackHelper.track().screen("test").with(mTracker);
assertFalse(mTracker.tryNewSession());
mTracker.setSessionTimeout(0);
Thread.sleep(1, 0);
assertTrue(mTracker.tryNewSession());
mTracker.setSessionTimeout(10000);
assertFalse(mTracker.tryNewSession());
assertEquals(mTracker.getSessionTimeout(), 10000);
}
@Test
public void testCheckSessionTimeout() throws Exception {
mTracker.setSessionTimeout(0);
TrackHelper.track().screen("test").with(mTracker);
verify(mDispatcher).submit(mCaptor.capture());
assertEquals("1", mCaptor.getValue().get(QueryParams.SESSION_START));
Thread.sleep(1, 0);
TrackHelper.track().screen("test").with(mTracker);
verify(mDispatcher, times(2)).submit(mCaptor.capture());
assertEquals("1", mCaptor.getValue().get(QueryParams.SESSION_START));
mTracker.setSessionTimeout(60000);
TrackHelper.track().screen("test").with(mTracker);
verify(mDispatcher, times(3)).submit(mCaptor.capture());
assertEquals(null, mCaptor.getValue().get(QueryParams.SESSION_START));
}
@Test
public void testTrackerEquals() throws Exception {
Tracker tracker2 = new Tracker(mPiwik, new TrackerConfig("http://localhost", 100, "Default Tracker"));
Tracker tracker3 = new Tracker(mPiwik, new TrackerConfig("http://example.com", 11, "Default Tracker"));
assertNotNull(mTracker);
assertFalse(mTracker.equals(tracker2));
assertTrue(mTracker.equals(tracker3));
}
@Test
public void testTrackerHashCode() throws Exception {
assertEquals(mTrackerConfig.hashCode(), mTracker.hashCode());
}
@Test
public void testUrlPathCorrection() throws Exception {
String[] paths = new String[]{null, "", "/",};
for (String path : paths) {
TrackMe trackMe = new TrackMe();
trackMe.set(QueryParams.URL_PATH, path);
mTracker.track(trackMe);
assertEquals("http://org.piwik.sdk.test/", trackMe.get(QueryParams.URL_PATH));
}
}
@Test
public void testSetUserAgent() throws MalformedURLException {
TrackMe trackMe = new TrackMe();
mTracker.track(trackMe);
assertEquals("aUserAgent", trackMe.get(QueryParams.USER_AGENT));
// Custom developer specified useragent
trackMe = new TrackMe();
String customUserAgent = "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0";
trackMe.set(QueryParams.USER_AGENT, customUserAgent);
mTracker.track(trackMe);
assertEquals(customUserAgent, trackMe.get(QueryParams.USER_AGENT));
// Modifying default TrackMe, no USER_AGENT
trackMe = new TrackMe();
mTracker.getDefaultTrackMe().set(QueryParams.USER_AGENT, null);
mTracker.track(trackMe);
assertEquals(null, trackMe.get(QueryParams.USER_AGENT));
}
@Test
public void testFirstVisitTimeStamp() throws Exception {
assertEquals(-1, mTracker.getPreferences().getLong(Tracker.PREF_KEY_TRACKER_FIRSTVISIT, -1));
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher).submit(mCaptor.capture());
TrackMe trackMe1 = mCaptor.getValue();
Thread.sleep(10);
// make sure we are tracking in seconds
assertTrue(Math.abs((System.currentTimeMillis() / 1000) - Long.parseLong(trackMe1.get(FIRST_VISIT_TIMESTAMP))) < 2);
mTracker = new Tracker(mPiwik, mTrackerConfig);
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher, times(2)).submit(mCaptor.capture());
TrackMe trackMe2 = mCaptor.getValue();
assertEquals(Long.parseLong(trackMe1.get(FIRST_VISIT_TIMESTAMP)), Long.parseLong(trackMe2.get(FIRST_VISIT_TIMESTAMP)));
assertEquals(mTracker.getPreferences().getLong(Tracker.PREF_KEY_TRACKER_FIRSTVISIT, -1), Long.parseLong(trackMe1.get(FIRST_VISIT_TIMESTAMP)));
}
@Test
public void testTotalVisitCount() throws Exception {
assertEquals(-1, mTracker.getPreferences().getInt(Tracker.PREF_KEY_TRACKER_VISITCOUNT, -1));
assertNull(mTracker.getDefaultTrackMe().get(QueryParams.TOTAL_NUMBER_OF_VISITS));
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher).submit(mCaptor.capture());
assertEquals(1, Integer.parseInt(mCaptor.getValue().get(QueryParams.TOTAL_NUMBER_OF_VISITS)));
mTracker = new Tracker(mPiwik, mTrackerConfig);
assertEquals(1, mTracker.getPreferences().getLong(Tracker.PREF_KEY_TRACKER_VISITCOUNT, -1));
assertNull(mTracker.getDefaultTrackMe().get(QueryParams.TOTAL_NUMBER_OF_VISITS));
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher, times(2)).submit(mCaptor.capture());
assertEquals(2, Integer.parseInt(mCaptor.getValue().get(QueryParams.TOTAL_NUMBER_OF_VISITS)));
assertEquals(2, mTracker.getPreferences().getLong(Tracker.PREF_KEY_TRACKER_VISITCOUNT, -1));
}
@Test
public void testVisitCountMultipleThreads() throws Exception {
int threadCount = 1000;
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(20 - 0) + 0);
} catch (InterruptedException e) { e.printStackTrace(); }
TrackHelper.track().event("TestCategory", "TestAction").with(new Tracker(mPiwik, mTrackerConfig));
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();
assertEquals(threadCount, mTrackerPreferences.getLong(Tracker.PREF_KEY_TRACKER_VISITCOUNT, 0));
}
@Test
public void testSessionStartRaceCondition() throws Exception {
final List<TrackMe> trackMes = Collections.synchronizedList(new ArrayList<TrackMe>());
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
trackMes.add((TrackMe) invocation.getArgument(0));
return null;
}
}).when(mDispatcher).submit(any(TrackMe.class));
when(mDispatcher.getConnectionTimeOut()).thenReturn(1000);
for (int i = 0; i < 1000; i++) {
trackMes.clear();
final Tracker tracker = new Tracker(mPiwik, mTrackerConfig);
final CountDownLatch countDownLatch = new CountDownLatch(10);
for (int j = 0; j < 10; j++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(4 - 0) + 0);
TrackMe trackMe = new TrackMe()
.set(QueryParams.EVENT_ACTION, UUID.randomUUID().toString())
.set(QueryParams.EVENT_CATEGORY, UUID.randomUUID().toString())
.set(QueryParams.EVENT_NAME, UUID.randomUUID().toString())
.set(QueryParams.EVENT_VALUE, 1);
tracker.track(trackMe);
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
assertFalse(true);
}
}
}).start();
}
countDownLatch.await();
for (TrackMe out : trackMes) {
if (trackMes.indexOf(out) == 0) {
assertTrue(i + "#" + out.toMap().size(), out.get(QueryParams.LANGUAGE) != null);
assertTrue(out.get(QueryParams.FIRST_VISIT_TIMESTAMP) != null);
assertTrue(out.get(SESSION_START) != null);
} else {
assertTrue(out.get(QueryParams.LANGUAGE) == null);
assertTrue(out.get(QueryParams.FIRST_VISIT_TIMESTAMP) == null);
assertTrue(out.get(SESSION_START) == null);
}
}
}
}
@Test
public void testFirstVisitMultipleThreads() throws Exception {
int threadCount = 100;
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
final List<Long> firstVisitTimes = Collections.synchronizedList(new ArrayList<Long>());
for (int i = 0; i < threadCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(20 - 0) + 0);
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
long firstVisit = Long.valueOf(mTracker.getDefaultTrackMe().get(FIRST_VISIT_TIMESTAMP));
firstVisitTimes.add(firstVisit);
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
countDownLatch.await();
for (Long firstVisit : firstVisitTimes) assertEquals(firstVisitTimes.get(0), firstVisit);
}
@Test
public void testPreviousVisits() throws Exception {
final List<Long> previousVisitTimes = new ArrayList<>();
for (int i = 0; i < 5; i++) {
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
String previousVisit = mTracker.getDefaultTrackMe().get(QueryParams.PREVIOUS_VISIT_TIMESTAMP);
if (previousVisit != null)
previousVisitTimes.add(Long.parseLong(previousVisit));
Thread.sleep(1010);
}
assertFalse(previousVisitTimes.contains(0L));
Long lastTime = 0L;
for (Long time : previousVisitTimes) {
assertTrue(lastTime < time);
lastTime = time;
}
}
@Test
public void testPreviousVisit() throws Exception {
// No timestamp yet
assertEquals(-1, mTracker.getPreferences().getLong(Tracker.PREF_KEY_TRACKER_PREVIOUSVISIT, -1));
mTracker = new Tracker(mPiwik, mTrackerConfig);
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher).submit(mCaptor.capture());
long _startTime = System.currentTimeMillis() / 1000;
// There was no previous visit
assertNull(mCaptor.getValue().get(QueryParams.PREVIOUS_VISIT_TIMESTAMP));
Thread.sleep(1000);
// After the first visit we now have a timestamp for the previous visit
long previousVisit = mTracker.getPreferences().getLong(Tracker.PREF_KEY_TRACKER_PREVIOUSVISIT, -1);
assertTrue(previousVisit - _startTime < 2000);
assertNotEquals(-1, previousVisit);
mTracker = new Tracker(mPiwik, mTrackerConfig);
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher, times(2)).submit(mCaptor.capture());
// Transmitted timestamp is the one from the first visit visit
assertEquals(previousVisit, Long.parseLong(mCaptor.getValue().get(QueryParams.PREVIOUS_VISIT_TIMESTAMP)));
Thread.sleep(1000);
mTracker = new Tracker(mPiwik, mTrackerConfig);
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher, times(3)).submit(mCaptor.capture());
// Now the timestamp changed as this is the 3rd visit.
assertNotEquals(previousVisit, Long.parseLong(mCaptor.getValue().get(QueryParams.PREVIOUS_VISIT_TIMESTAMP)));
Thread.sleep(1000);
previousVisit = mTracker.getPreferences().getLong(Tracker.PREF_KEY_TRACKER_PREVIOUSVISIT, -1);
mTracker = new Tracker(mPiwik, mTrackerConfig);
TrackHelper.track().event("TestCategory", "TestAction").with(mTracker);
verify(mDispatcher, times(4)).submit(mCaptor.capture());
// Just make sure the timestamp in the 4th visit is from the 3rd visit
assertEquals(previousVisit, Long.parseLong(mCaptor.getValue().get(QueryParams.PREVIOUS_VISIT_TIMESTAMP)));
// Test setting a custom timestamp
TrackMe custom = new TrackMe();
custom.set(QueryParams.PREVIOUS_VISIT_TIMESTAMP, 1000L);
mTracker.track(custom);
verify(mDispatcher, times(5)).submit(mCaptor.capture());
assertEquals(1000L, Long.parseLong(mCaptor.getValue().get(QueryParams.PREVIOUS_VISIT_TIMESTAMP)));
}
private static void validateDefaultQuery(TrackMe params) {
assertEquals(params.get(QueryParams.SITE_ID), "11");
assertEquals(params.get(QueryParams.RECORD), "1");
assertEquals(params.get(QueryParams.SEND_IMAGE), "0");
assertEquals(params.get(QueryParams.VISITOR_ID).length(), 16);
assertTrue(params.get(QueryParams.URL_PATH).startsWith("http://"));
assertTrue(Integer.parseInt(params.get(QueryParams.RANDOM_NUMBER)) > 0);
}
}