/* * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed 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://aws.amazon.com/apache2.0 * * This file 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 com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.session.client; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.amazonaws.mobileconnectors.amazonmobileanalytics.MobileAnalyticsTestBase; import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.AnalyticsContext; import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.core.configuration.Configuration; import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.event.DefaultEventClient; import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.event.InternalEventClient; import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.session.Session; import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.session.SessionStore; import com.amazonaws.mobileconnectors.amazonmobileanalytics.internal.session.client.DefaultSessionClient.SessionState; import com.amazonaws.mobileconnectors.amazonmobileanalytics.utils.AnalyticsContextBuilder; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE) public class DefaultSessionClientTest extends MobileAnalyticsTestBase { private static final String UNIQUE_ID = "deadbeef-DEADBEEF-deadbeef-DEADBEEF"; private static final String SDK_NAME = "AppIntelligenceSDK-Analytics"; private static final String SDK_VERSION = "test"; private InternalEventClient mockEventClient; @Mock private AnalyticsContext mockInsightsContext; @Mock private Configuration mockConfiguration; private DefaultSessionClient target; private class TestSessionStore implements SessionStore { private Session session = null; @Override public void storeSession(Session session) { this.session = session; } @Override public Session getSession() { return this.session; } } @Before public void setup() { MockitoAnnotations.initMocks(this); when( mockConfiguration.optLong(eq(DefaultSessionClient.RESTART_DELAY_CONFIG_KEY), eq(DefaultSessionClient.DEFAULT_RESTART_DELAY))).thenReturn(300l); when( mockConfiguration.optLong(eq(DefaultSessionClient.RESUME_DELAY_CONFIG_KEY), eq(DefaultSessionClient.DEFAULT_RESUME_DELAY))).thenReturn(100l); this.mockInsightsContext = new AnalyticsContextBuilder() .withSdkInfo(SDK_NAME, SDK_VERSION) .withUniqueIdValue(UNIQUE_ID) .withConfiguration(mockConfiguration) .build(); mockEventClient = Mockito.mock(DefaultEventClient.class); target = new DefaultSessionClient(mockInsightsContext, mockEventClient, new TestSessionStore()); } @Test(expected = NullPointerException.class) public void constructor_NullEventClient_ThrowsNullPointer() { target = new DefaultSessionClient(mockInsightsContext, null, new TestSessionStore()); } @Test(expected = NullPointerException.class) public void constructor_NullInsightsContext_ThrowsNullPointer() { target = new DefaultSessionClient(null, mockEventClient, new TestSessionStore()); } @Test(expected = NullPointerException.class) public void constructor_NullSessionStore_ThrowsNullPointer() { target = new DefaultSessionClient(mockInsightsContext, mockEventClient, null); } // ~ START SESSION // ========================================================================= // ~\\ // @Test public void startSession_sessionIsActive_doesNotSetNewSession_ifWithinTimeInterval() { target.startSession(); long pTime = target.getSession().getStartTime(); target.startSession(); System.out.print(target.getRestartDelay() + ""); assertTrue(System.currentTimeMillis() - pTime < target.getRestartDelay()); verify(mockEventClient, times(1)) .createEvent(DefaultSessionClient.SESSION_START_EVENT_TYPE); String firstSessionId = target.getSession().getSessionID(); long firstStartTime = target.getSession().getStartTime(); assertTrue(target.state instanceof ActiveSessionState); pTime = target.getSession().getStartTime(); target.startSession(); assertTrue(System.currentTimeMillis() - pTime < target.getRestartDelay()); assertEquals(firstSessionId, target.getSession().getSessionID()); assertEquals(firstStartTime, target.getSession().getStartTime()); verify(mockEventClient, times(1)).setSessionId(firstSessionId); verify(mockEventClient, times(1)).setSessionStartTime(firstStartTime); } @Test public void startSession_sessionIsActive_doesNotStartNewSession_ifWithinTimeInterval() { target.startSession(); long pTime = target.getSession().getStartTime(); target.startSession(); assertTrue(System.currentTimeMillis() - pTime < target.getRestartDelay()); pTime = target.getSession().getStartTime(); target.startSession(); assertTrue(System.currentTimeMillis() - pTime < target.getRestartDelay()); verify(mockEventClient, times(1)).createEvent( eq(DefaultSessionClient.SESSION_START_EVENT_TYPE)); } @Test public void startSession_sessionIsActive_SetsNewSession_ifOutsideTimeInterval() { target.startSession(); String firstSessionId = target.getSession().getSessionID(); long firstStartTime = target.getSession().getStartTime(); verify(mockEventClient, times(1)).setSessionId(firstSessionId); verify(mockEventClient, times(1)).setSessionStartTime(firstStartTime); try { Thread.sleep(target.getRestartDelay() + 50l); long pTime = target.getSession().getStartTime(); target.startSession(); System.out.print(target.getRestartDelay() + ""); assertTrue(System.currentTimeMillis() - pTime > target.getRestartDelay()); String secondSessionId = target.getSession().getSessionID(); long secondStartTime = target.getSession().getStartTime(); assertNotEquals(firstSessionId, secondSessionId); assertNotEquals(firstStartTime, secondStartTime); verify(mockEventClient, times(1)).setSessionId(secondSessionId); verify(mockEventClient, times(1)).setSessionStartTime(secondStartTime); } catch (InterruptedException e) { e.printStackTrace(); } } @Test public void startSession_sessionIsActive_startsNewSession_ifOutsideTimeInterval() { target.startSession(); try { Session session = target.getSession(); assertThat(session.isPaused(), is(false)); Thread.sleep(target.getRestartDelay() + 50l); target.startSession(); // assert the old session was paused and the a new session is now // active assertThat(session.isPaused(), is(true)); assertThat(target.getSession(), is(not(session))); verify(mockEventClient, times(2)).createEvent( eq(DefaultSessionClient.SESSION_START_EVENT_TYPE)); verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_STOP_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); } catch (InterruptedException e) { e.printStackTrace(); } } @Test public void startSession_firesStartEvent() { target.startSession(); verify(mockEventClient, times(1)).createEvent( eq(DefaultSessionClient.SESSION_START_EVENT_TYPE)); } @Test public void startSession_stateChangedToActive() { target.startSession(); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.ACTIVE); } @Test public void startSession_sessionIsPaused_firesStopEvent_firesStartEvent() throws InterruptedException { target.startSession(); Thread.sleep(50); target.pauseSession(); target.startSession(); verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_PAUSE_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_STOP_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); verify(mockEventClient, times(2)).createEvent( eq(DefaultSessionClient.SESSION_START_EVENT_TYPE)); } @Test public void startSession_sessionIsPaused_stateChangedToActive() { target.startSession(); target.pauseSession(); target.startSession(); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.ACTIVE); } @Test public void startSession_previousPausedSessionColdStart_fireStopEvent_firesStartEvent() throws InterruptedException { Session mockSession = Mockito.mock(Session.class); when(mockSession.getSessionDuration()).thenReturn(Long.valueOf(12345l)); when(mockSession.getSessionID()).thenReturn("BEEFY_MKBEEF_CAKES"); when(mockSession.getStartTime()).thenReturn(0l); when(mockSession.getStopTime()).thenReturn(Long.valueOf(12345l)); when(mockSession.isPaused()).thenReturn(true); TestSessionStore mockSessionStore = new TestSessionStore(); mockSessionStore.storeSession(mockSession); // initialize session client with a pending session that needs to be // closed DefaultSessionClient coldStartTarget = new DefaultSessionClient(mockInsightsContext, mockEventClient, mockSessionStore); assertThat(coldStartTarget.getSession(), is(notNullValue())); assertThat(coldStartTarget.getSessionState(), is(SessionState.PAUSED)); // starting a session should close the pending one coldStartTarget.startSession(); verify(mockEventClient, times(1)).createInternalEvent( DefaultSessionClient.SESSION_STOP_EVENT_TYPE, mockSession.getStartTime(), mockSession.getStopTime(), mockSession.getSessionDuration().longValue()); verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_STOP_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); } // // // //~ // ======================================================================================= // ~// // // // // // //~ STOP SESSION // ========================================================================== // ~\\ // // @Test public void stopSession_sessionIsInactive_doesNotFireStopEvent() { target.stopSession(); target.startSession(); target.stopSession(); target.stopSession(); target.stopSession(); verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_STOP_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); } @Test public void stopSession_getStopTime() { target.startSession(); Session originalSession = target.getSession(); target.stopSession(); assertTrue(System.currentTimeMillis() - originalSession.getStopTime() < 100); } @Test public void stopSession_multipleStops_stopTimeNotChanged() throws InterruptedException { target.startSession(); Session originalSession = target.getSession(); target.stopSession(); long originalStopTime = originalSession.getStopTime(); Thread.sleep(500); target.stopSession(); assertTrue(originalStopTime == originalSession.getStopTime()); } @Test public void stopSession_sessionIsActive_firesStopEvent() throws InterruptedException { target.startSession(); Thread.sleep(50); long startTime = target.getSession().getStartTime(); target.stopSession(); // After this call session is null, so we cannot get the stop/duration // time verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_STOP_EVENT_TYPE), eq(startTime), any(Long.class), any(Long.class)); assertTrue(target.state instanceof InactiveSessionState); } @Test public void stopSession_sessionIsActive_pausesOldSession() { target.startSession(); Session session = target.getSession(); assertThat(session.isPaused(), is(false)); target.stopSession(); assertThat(session.isPaused(), is(true)); assertThat(target.getSession(), is(nullValue())); } @Test public void stopSession_sessionIsActive_stateChangedToInactive() { target.startSession(); target.stopSession(); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.INACTIVE); } @Test public void stopSession_sessionIsPaused_firesStopEvent() throws InterruptedException { target.startSession(); Thread.sleep(50); target.pauseSession(); Session originalSession = target.getSession(); target.stopSession(); verify(mockEventClient, times(1)).createInternalEvent( DefaultSessionClient.SESSION_STOP_EVENT_TYPE, originalSession.getStartTime(), originalSession.getStopTime(), originalSession.getSessionDuration().longValue()); } @Test public void stopSession_sessionIsPaused_stateChangedToInactive() { target.startSession(); target.pauseSession(); target.stopSession(); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.INACTIVE); } // // // //~ // ====================================================================================== // ~// // // // // // //~ PAUSE SESSION // ========================================================================= // ~\\ // // @Test public void pauseSession_sessionIsActive_firesPauseEvent() { target.startSession(); target.pauseSession(); verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_PAUSE_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); } @Test public void pauseSession_sessionIsActive_stateChangedToPaused() { target.startSession(); target.pauseSession(); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.PAUSED); } @Test public void pauseSession_sessionIsInactive_firesNoEvent() { target.pauseSession(); target.pauseSession(); target.pauseSession(); verify(mockEventClient, times(0)).createEvent(any(String.class)); verify(mockEventClient, times(0)).createInternalEvent( any(String.class), any(Long.class), any(Long.class), any(Long.class)); } @Test public void pauseSession_sessionIsInactive_stateIsNotChanged() { target.pauseSession(); target.pauseSession(); target.pauseSession(); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.INACTIVE); } @Test public void pauseSession_sessionIsPaused_doesNotFirePauseEvent() { target.startSession(); target.pauseSession(); target.pauseSession(); target.pauseSession(); verify(mockEventClient, times(1)).createInternalEvent( eq(DefaultSessionClient.SESSION_PAUSE_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); } // // // //~ // ======================================================================================= // ~// // // // // // //~ RESUME SESSION // ======================================================================== // ~\\ // // @Test public void resumeSession_sessionIsActive_doesNotFireResumeEvent() { target.startSession(); target.resumeSession(); target.resumeSession(); target.resumeSession(); verify(mockEventClient, times(0)).createInternalEvent( eq(DefaultSessionClient.SESSION_RESUME_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); } @Test public void resumeSession_sessionIsInactive_firesBlankResumeEvent() { target.resumeSession(); target.resumeSession(); target.resumeSession(); verify(mockEventClient, times(3)).createEvent( eq(DefaultSessionClient.SESSION_RESUME_EVENT_TYPE)); } @Test public void resumeSession_sessionIsInactive_stateIsNotChanged() { target.resumeSession(); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.INACTIVE); } @Test public void resumeSession_sessionIsPaused_firesResumeEvent_ifWithinTimeInterval() { target.startSession(); target.pauseSession(); long pTime = target.getSession().getStopTime(); target.resumeSession(); assertTrue(System.currentTimeMillis() - pTime < target.getResumeDelay()); verify(mockEventClient, times(1)).createEvent( DefaultSessionClient.SESSION_RESUME_EVENT_TYPE); } @Test public void resumeSession_sessionIsPaused_stateIsChanged_ifWithinTimeInterval() { target.startSession(); target.pauseSession(); long pTime = target.getSession().getStopTime(); target.resumeSession(); assertTrue(System.currentTimeMillis() - pTime < target.getResumeDelay()); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.ACTIVE); } @Test public void resumeSession_sessionIsPaused_doesNotStartNewSession_ifWithinTimeInterval() { target.startSession(); target.pauseSession(); long pTime = target.getSession().getStopTime(); target.resumeSession(); assertTrue(System.currentTimeMillis() - pTime < target.getResumeDelay()); verify(mockEventClient, times(1)).createEvent( eq(DefaultSessionClient.SESSION_START_EVENT_TYPE)); } @Test public void resumeSession_sessionIsPaused_startsNewSession_ifOutsideTimeInterval() throws InterruptedException { target.startSession(); Thread.sleep(50); Session originalSession = target.getSession(); target.pauseSession(); String pSesId = target.getSession().getSessionID(); try { Thread.sleep(target.getResumeDelay() + 50l); target.resumeSession(); verify(mockEventClient, times(0)).createInternalEvent( eq(DefaultSessionClient.SESSION_RESUME_EVENT_TYPE), any(Long.class), any(Long.class), any(Long.class)); verify(mockEventClient, times(2)).createEvent( eq(DefaultSessionClient.SESSION_START_EVENT_TYPE)); verify(mockEventClient, times(1)).createInternalEvent( DefaultSessionClient.SESSION_STOP_EVENT_TYPE, originalSession.getStartTime(), originalSession.getStopTime(), originalSession.getSessionDuration().longValue()); assertEquals(target.getSessionState(), DefaultSessionClient.SessionState.ACTIVE); assertFalse(target.getSession().getSessionID().equals(pSesId)); } catch (InterruptedException e) { e.printStackTrace(); } } // // ~ // ====================================================================================== // ~// }