/******************************************************************************* * Copyright (c) 2014 EclipseSource and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * EclipseSource - initial API and implementation ******************************************************************************/ package com.eclipsesource.tabris.tracking.tracker; import static com.eclipsesource.tabris.tracking.internal.analytics.request.RequestKeyProvider.getRequestKey; import static com.eclipsesource.tabris.tracking.tracker.GoogleAnalyticsTracker.CATEGORY_ACTION; import static com.eclipsesource.tabris.tracking.tracker.GoogleAnalyticsTracker.CATEGORY_EVENT; import static com.eclipsesource.tabris.tracking.tracker.GoogleAnalyticsTracker.CATEGORY_SEARCH; import static com.eclipsesource.tabris.tracking.tracker.GoogleAnalyticsTracker.LABEL_EVENT; import static com.eclipsesource.tabris.tracking.tracker.GoogleAnalyticsTracker.LABEL_EXECUTE; import static com.eclipsesource.tabris.tracking.tracker.GoogleAnalyticsTracker.LABEL_SEARCH; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.math.BigDecimal; import java.util.Locale; import org.eclipse.swt.graphics.Point; import org.junit.Test; import org.mockito.ArgumentCaptor; import com.eclipsesource.tabris.device.ClientDevice.Platform; import com.eclipsesource.tabris.tracking.Order; import com.eclipsesource.tabris.tracking.OrderItem; import com.eclipsesource.tabris.tracking.TrackingEvent; import com.eclipsesource.tabris.tracking.TrackingEvent.EventType; import com.eclipsesource.tabris.tracking.TrackingInfo; import com.eclipsesource.tabris.tracking.internal.analytics.GoogleAnalytics; import com.eclipsesource.tabris.tracking.internal.analytics.model.AdvancedConfiguration; import com.eclipsesource.tabris.tracking.internal.analytics.model.hit.Hit; import com.eclipsesource.tabris.tracking.internal.analytics.request.RequestKeys; public class GoogleAnalyticsTrackerTest { @Test( expected = IllegalArgumentException.class ) public void testFailsWithNullTrackingId() { new GoogleAnalyticsTracker( null, "bar" ); } @Test( expected = IllegalArgumentException.class ) public void testFailsWithEmptyTrackingId() { new GoogleAnalyticsTracker( "", "bar" ); } @Test( expected = IllegalArgumentException.class ) public void testFailsWithNullAppName() { new GoogleAnalyticsTracker( "foo", null ); } @Test( expected = IllegalArgumentException.class ) public void testFailsWithEmptyAppName() { new GoogleAnalyticsTracker( "foo", "" ); } @Test public void testSendsPageView() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); TrackingEvent event = new TrackingEvent( EventType.PAGE_VIEW, createInfo(), "foo", 1 ); tracker.handleEvent( event ); ArgumentCaptor<Hit> hitCaptor = ArgumentCaptor.forClass( Hit.class ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( hitCaptor.capture(), eq( "clientId" ), configCaptor.capture() ); assertAdvancedConfiguration( configCaptor.getValue() ); assertEquals( "foo", hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.SCREEN_NAME ) ) ); } @Test public void testSendsAction() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); TrackingEvent event = new TrackingEvent( EventType.ACTION, createInfo(), "foo", 1 ); tracker.handleEvent( event ); ArgumentCaptor<Hit> hitCaptor = ArgumentCaptor.forClass( Hit.class ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( hitCaptor.capture(), eq( "clientId" ), configCaptor.capture() ); assertAdvancedConfiguration( configCaptor.getValue() ); assertEquals( "foo", hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_LABEL ) ) ); assertEquals( CATEGORY_ACTION, hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_CATEGORY ) ) ); assertEquals( LABEL_EXECUTE, hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_ACTION ) ) ); } @Test public void testSendsSearchAction() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); TrackingEvent event = new TrackingEvent( EventType.SEARCH, createInfo(), "foo", 1 ); tracker.handleEvent( event ); ArgumentCaptor<Hit> hitCaptor = ArgumentCaptor.forClass( Hit.class ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( hitCaptor.capture(), eq( "clientId" ), configCaptor.capture() ); assertAdvancedConfiguration( configCaptor.getValue() ); assertEquals( "foo", hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_LABEL ) ) ); assertEquals( CATEGORY_SEARCH, hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_CATEGORY ) ) ); assertEquals( LABEL_SEARCH, hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_ACTION ) ) ); assertEquals( "query", configCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.CUSTOM_DIMENSION, 1 ) ) ); } @Test public void testSendsSearchActionWithConfiguredCustomDimension() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); TrackingEvent event = new TrackingEvent( EventType.SEARCH, createInfo(), "foo", 1 ); tracker.setSearchCustomDimension( 2 ); tracker.handleEvent( event ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( any( Hit.class ), eq( "clientId" ), configCaptor.capture() ); assertAdvancedConfiguration( configCaptor.getValue() ); assertEquals( "query", configCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.CUSTOM_DIMENSION, 2 ) ) ); } @Test( expected = IllegalArgumentException.class ) public void testFailsToSetZeroSearchIndex() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); tracker.setSearchCustomDimension( 0 ); } @Test( expected = IllegalArgumentException.class ) public void testFailsToSetNegativeSearchIndex() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); tracker.setSearchCustomDimension( -1 ); } @Test public void testSendsEvent() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); TrackingEvent event = new TrackingEvent( EventType.EVENT, createInfo(), "foo", 1 ); tracker.handleEvent( event ); ArgumentCaptor<Hit> hitCaptor = ArgumentCaptor.forClass( Hit.class ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( hitCaptor.capture(), eq( "clientId" ), configCaptor.capture() ); assertAdvancedConfiguration( configCaptor.getValue() ); assertEquals( "foo", hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_LABEL ) ) ); assertEquals( CATEGORY_EVENT, hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_CATEGORY ) ) ); assertEquals( LABEL_EVENT, hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.EVENT_ACTION ) ) ); } @Test public void testSendsOrder() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); Order order = new Order( "foo", BigDecimal.ONE ); TrackingEvent event = new TrackingEvent( EventType.ORDER, createInfo(), order, 1 ); tracker.handleEvent( event ); ArgumentCaptor<Hit> hitCaptor = ArgumentCaptor.forClass( Hit.class ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( hitCaptor.capture(), eq( "clientId" ), configCaptor.capture() ); assertAdvancedConfiguration( configCaptor.getValue() ); assertEquals( order.getOrderId(), hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.TRANSACTION_ID ) ) ); assertEquals( Double.valueOf( 1 ), hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.TRANSACTION_REVENUE ) ) ); assertEquals( Double.valueOf( 0 ), hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.TRANSACTION_SHIPPING ) ) ); assertEquals( Double.valueOf( 0 ), hitCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.TRANSACTION_TAX ) ) ); } @Test public void testSendsOrderWithItems() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); Order order = new Order( "foo", BigDecimal.ONE ); order.addItem( new OrderItem( "bar" ).setCategory( "blub" ).setSKU( "hmpf" ) ); TrackingEvent event = new TrackingEvent( EventType.ORDER, createInfo(), order, 1 ); tracker.handleEvent( event ); ArgumentCaptor<Hit> hitCaptor = ArgumentCaptor.forClass( Hit.class ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics, times( 2 ) ).track( hitCaptor.capture(), eq( "clientId" ), configCaptor.capture() ); assertAdvancedConfiguration( configCaptor.getAllValues().get( 0 ) ); Hit transactionHit = hitCaptor.getAllValues().get( 0 ); Hit itemHit = hitCaptor.getAllValues().get( 1 ); verifyTransactionHit( order, transactionHit ); verifyItemHit( order, itemHit ); } private void verifyTransactionHit( Order order, Hit transactionHit ) { assertEquals( order.getOrderId(), transactionHit.getParameter().get( getRequestKey( RequestKeys.TRANSACTION_ID ) ) ); assertEquals( Double.valueOf( 1 ), transactionHit.getParameter().get( getRequestKey( RequestKeys.TRANSACTION_REVENUE ) ) ); assertEquals( Double.valueOf( 0 ), transactionHit.getParameter().get( getRequestKey( RequestKeys.TRANSACTION_SHIPPING ) ) ); assertEquals( Double.valueOf( 0 ), transactionHit.getParameter().get( getRequestKey( RequestKeys.TRANSACTION_TAX ) ) ); } private void verifyItemHit( Order order, Hit itemHit ) { assertEquals( order.getOrderId(), itemHit.getParameter().get( getRequestKey( RequestKeys.TRANSACTION_ID ) ) ); assertEquals( "bar", itemHit.getParameter().get( getRequestKey( RequestKeys.ITEM_NAME ) ) ); assertEquals( "blub", itemHit.getParameter().get( getRequestKey( RequestKeys.ITEM_CATEGORY ) ) ); assertEquals( "hmpf", itemHit.getParameter().get( getRequestKey( RequestKeys.ITEM_CODE ) ) ); } private void assertAdvancedConfiguration( AdvancedConfiguration configuration ) { assertEquals( "appId", configuration.getParameter().get( getRequestKey( RequestKeys.APP_ID ) ) ); assertEquals( "appVersion", configuration.getParameter().get( getRequestKey( RequestKeys.APP_VERSION ) ) ); assertEquals( "100x200", configuration.getParameter().get( getRequestKey( RequestKeys.SCREEN_RESOLUTION ) ) ); assertEquals( "100x200", configuration.getParameter().get( getRequestKey( RequestKeys.VIEWPORT_SIZE ) ) ); assertEquals( "ip", configuration.getParameter().get( getRequestKey( RequestKeys.IP_OVERRIDE ) ) ); assertEquals( "userAgent", configuration.getParameter().get( getRequestKey( RequestKeys.USER_AGENT_OVERRIDE ) ) ); assertEquals( "en-CA", configuration.getParameter().get( getRequestKey( RequestKeys.USER_LANGUAGE ) ) ); } @Test public void testAndroidUserAgent() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); TrackingInfo info = createInfo(); info.setPlatform( Platform.ANDROID ); info.setDeviceOsVersion( "4.4" ); TrackingEvent event = new TrackingEvent( EventType.SEARCH, info, "foo", 1 ); tracker.handleEvent( event ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( any( Hit.class ), eq( "clientId" ), configCaptor.capture() ); String userAgent = "Mozilla/5.0 (Linux; U; Android 4.4; " + info.getClientLocale() + "; model) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"; assertEquals( userAgent, configCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.USER_AGENT_OVERRIDE ) ) ); } @Test public void testIOSUserAgent() { GoogleAnalytics analytics = mock( GoogleAnalytics.class ); GoogleAnalyticsTracker tracker = new GoogleAnalyticsTracker( analytics ); TrackingInfo info = createInfo(); info.setPlatform( Platform.IOS ); info.setDeviceOsVersion( "7.1" ); TrackingEvent event = new TrackingEvent( EventType.SEARCH, info, "foo", 1 ); tracker.handleEvent( event ); ArgumentCaptor<AdvancedConfiguration> configCaptor = ArgumentCaptor.forClass( AdvancedConfiguration.class ); verify( analytics ).track( any( Hit.class ), eq( "clientId" ), configCaptor.capture() ); String userAgent = "Mozilla/5.0 (model; U; CPU iPhone OS 7_1 like Mac OS X; " + info.getClientLocale() + " ) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7"; assertEquals( userAgent, configCaptor.getValue().getParameter().get( getRequestKey( RequestKeys.USER_AGENT_OVERRIDE ) ) ); } private TrackingInfo createInfo() { TrackingInfo info = new TrackingInfo(); info.setAppId( "appId" ); info.setAppVersion( "appVersion" ); info.setClientId( "clientId" ); info.setClientLocale( Locale.CANADA ); info.setDeviceModel( "model" ); info.setScreenResolution( new Point( 100, 200 ) ); info.setSearchQuery( "query" ); info.setUserAgent( "userAgent" ); info.setClientIp( "ip" ); info.setPlatform( Platform.WEB ); return info; } }