/*
* ApplicationInsights-Java
* Copyright (c) Microsoft Corporation
* All rights reserved.
*
* MIT License
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the ""Software""), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package com.microsoft.applicationinsights.web.extensibility.modules;
import java.util.List;
import com.microsoft.applicationinsights.extensibility.TelemetryInitializer;
import com.microsoft.applicationinsights.extensibility.context.SessionContext;
import com.microsoft.applicationinsights.internal.util.DateTimeUtils;
import com.microsoft.applicationinsights.internal.util.Sanitizer;
import com.microsoft.applicationinsights.telemetry.RequestTelemetry;
import com.microsoft.applicationinsights.telemetry.Telemetry;
import com.microsoft.applicationinsights.web.internal.RequestTelemetryContext;
import com.microsoft.applicationinsights.web.internal.ThreadContext;
import org.junit.*;
import com.microsoft.applicationinsights.TelemetryConfiguration;
import com.microsoft.applicationinsights.telemetry.SessionState;
import com.microsoft.applicationinsights.telemetry.SessionStateTelemetry;
import com.microsoft.applicationinsights.web.utils.MockTelemetryChannel;
import com.microsoft.applicationinsights.web.utils.CookiesContainer;
import com.microsoft.applicationinsights.web.utils.HttpHelper;
import com.microsoft.applicationinsights.web.utils.JettyTestServer;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
/**
* Created by yonisha on 2/5/2015.
*/
public class WebSessionTrackingTelemetryModuleTests {
private static class TestModuleInitializer implements TelemetryInitializer {
private final String expectedSessionId;
private final boolean expectedIsFirst;
private TestModuleInitializer(String expectedSessionId, boolean expectedIsFirst) {
this.expectedSessionId = expectedSessionId;
this.expectedIsFirst = expectedIsFirst;
}
@Override
public void initialize(Telemetry telemetry) {
RequestTelemetry requestTelemetry = ThreadContext.getRequestTelemetryContext().getHttpRequestTelemetry();
SessionContext requestSessionContext = requestTelemetry.getContext().getSession();
if (expectedSessionId == null) {
Assert.assertTrue(Sanitizer.isUUID(requestSessionContext.getId()));
Assert.assertNotEquals(requestSessionContext.getId(), HttpHelper.getCookie());
} else {
Assert.assertEquals(expectedSessionId, requestSessionContext.getId());
}
Assert.assertEquals(expectedIsFirst, requestSessionContext.getIsFirst());
}
}
// region Members
private static String sessionCookieFormatted;
private static JettyTestServer server = new JettyTestServer();
private static MockTelemetryChannel channel;
// endregion Members
// region Initialization
@BeforeClass
public static void classInitialize() throws Exception {
server.start();
// Set mock channel
channel = MockTelemetryChannel.INSTANCE;
TelemetryConfiguration.getActive().setChannel(channel);
TelemetryConfiguration.getActive().setInstrumentationKey("SOME_INT_KEY");
}
@Before
public void testInitialize() {
sessionCookieFormatted = HttpHelper.getFormattedSessionCookieHeader(false);
channel.reset();
}
@AfterClass
public static void classCleanup() throws Exception {
server.shutdown();
}
// endregion Initialization
// region Tests
@Test
public void testNewSessionCookieIsNotCreatedWhenCookieNotExist() throws Exception {
TelemetryConfiguration.getActive().getTelemetryInitializers().add(new TestModuleInitializer(null, false));
CookiesContainer cookiesContainer = HttpHelper.sendRequestAndGetResponseCookie();
Assert.assertNull("Session cookie should be null.", cookiesContainer.getSessionCookie());
}
@Test
public void testWhenCookieExistCorrectSessionIdAttachedToSentTelemetry() throws Exception {
HttpHelper.sendRequestAndGetResponseCookie(sessionCookieFormatted);
RequestTelemetry requestTelemetry = channel.getTelemetryItems(RequestTelemetry.class).get(0);
Assert.assertTrue(sessionCookieFormatted.contains(requestTelemetry.getContext().getSession().getId()));
Assert.assertEquals(requestTelemetry.getContext().getSession().getId(), HttpHelper.getCookie());
}
@Ignore
@Test
public void testWhenSessionExpiredSessionStateEndTracked() throws Exception {
sessionCookieFormatted = HttpHelper.getFormattedSessionCookieHeader(true);
HttpHelper.sendRequestAndGetResponseCookie(sessionCookieFormatted);
verifySessionState(SessionState.End);
}
@Test
public void testOnFirstSessionStartedNoSessionStateEndTracked() throws Exception {
HttpHelper.sendRequestAndGetResponseCookie();
SessionStateTelemetry telemetry = getSessionStateTelemetryWithState(SessionState.End);
Assert.assertNull("No telemetry with SessionEnd expected.", telemetry);
}
@Test
@Ignore
public void testSessionStateTelemetryContainsSessionIdOnEndState() throws Exception {
sessionCookieFormatted = HttpHelper.getFormattedSessionCookieHeader(true);
HttpHelper.sendRequestAndGetResponseCookie(sessionCookieFormatted);
SessionStateTelemetry telemetry = getSessionStateTelemetryWithState(SessionState.End);
Assert.assertNotNull("Session ID shouldn't be null", telemetry.getContext().getSession().getId());
}
@Test
@Ignore
public void testSessionStateTelemetryEndStateContainsExpiredSessionId() throws Exception {
sessionCookieFormatted = HttpHelper.getFormattedSessionCookieHeader(true);
HttpHelper.sendRequestAndGetResponseCookie(sessionCookieFormatted);
SessionStateTelemetry telemetry = getSessionStateTelemetryWithState(SessionState.End);
String expectedSessionId = HttpHelper.getSessionIdFromCookie(sessionCookieFormatted);
Assert.assertEquals(
"Expected session ID of the expired session cookie",
expectedSessionId,
telemetry.getContext().getSession().getId());
}
// endregion Tests
// region Private
private Cookie callOnBeginRequestAndGetCookieResult(WebSessionTrackingTelemetryModule module) {
ThreadContext.setRequestTelemetryContext(new RequestTelemetryContext(DateTimeUtils.getDateTimeNow().getTime()));
module.initialize(TelemetryConfiguration.getActive());
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
final Cookie[] cookies = new Cookie[1];
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
cookies[0] = ((Cookie) invocation.getArguments()[0]);
return null;
}
}).when(response).addCookie(any(Cookie.class));
module.onBeginRequest(request, response);
return cookies[0];
}
private void verifySessionState(SessionState expectedSessionState) {
SessionStateTelemetry telemetry = getSessionStateTelemetryWithState(expectedSessionState);
Assert.assertNotNull("Session state telemetry expected.", telemetry);
Assert.assertEquals(expectedSessionState + " state expected.", expectedSessionState, telemetry.getSessionState());
}
private SessionStateTelemetry getSessionStateTelemetryWithState(SessionState state) {
List<SessionStateTelemetry> items = channel.getTelemetryItems(SessionStateTelemetry.class);
for (SessionStateTelemetry telemetry : items) {
if (telemetry.getSessionState().compareTo(state) == 0) {
return telemetry;
}
}
return null;
}
// endregion Private
}