Manages visitors and sessions to ensure they are correctly saved, restored and time-out as appropriate.
 private static UrchinAnalyticsClient CreateSampleClient(Action<Uri> sender)
 {
     var configuration = new UrchinConfiguration("UA-1234-5", "FindHostName");
     var sessionManager = new SessionManager(TimeSpan.FromDays(1), null);
     var environment = new Environment("en-gb");
     return new UrchinAnalyticsClient(configuration, sessionManager, environment, sender);
 }
        /// <summary>
        /// Create a new AnalyticsClient with a given configuration, session, environment and URI sender.
        /// </summary>
        /// <param name="configuration">Configuration of this Google Analytics Measurement Protocol client.</param>
        /// <param name="sessionManager">Session manager with visitor and session information.</param>
        /// <param name="environment">Provider of environmental information such as screen resolution.</param>
        /// <param name="sender">Action to take prepared URIs for Google Analytics and send them on.</param>
        public MeasurementAnalyticsClient(MeasurementConfiguration configuration, SessionManager sessionManager, IEnvironment environment, Action<Uri> sender)
        {
            this.sessionManager = sessionManager;
            this.sender = sender;

            tracker = new MeasurementTracker(configuration, sessionManager, environment);
        }
        public void SessionManager_Created_From_Null_State_Is_Fresh()
        {
            var sessionManager = new SessionManager(null);

            Assert.IsNull(sessionManager.Referrer);
            Assert.IsNotNull(sessionManager.Visitor);
        }
        public void SessionManager_Creates_New_Session_When_Requested()
        {
            var sessionManager = new SessionManager(null);

            sessionManager.StartNewSession();
            Assert.AreEqual(SessionStatus.Starting, sessionManager.SessionStatus);
        }
        public void SessionManager_SessionStatus_Is_Active_After_First_Hit()
        {
            var sessionManager = new SessionManager(null);
            sessionManager.Hit();

            Assert.AreEqual(SessionStatus.Active, sessionManager.SessionStatus);
        }
        public void SessionManager_Referrer_Property_Can_Be_Set()
        {
            var referrer = new Uri("http://stickertales.com");
            var sessionManager = new SessionManager(null) { Referrer = referrer };

            Assert.AreEqual(referrer, sessionManager.Referrer);
        }
 /// <summary>
 /// Create a new AnalyticsClient with a given configuration, session, environment and URI sender.
 /// </summary>
 /// <param name="configuration">Configuration of this Google Analytics Urchin client.</param>
 /// <param name="sessionManager">Session manager with visitor and session information.</param>
 /// <param name="environment">Provider of environmental information such as screen resolution.</param>
 /// <param name="sender">Action to take prepared URIs for Google Analytics and send them on.</param>
 public UrchinTracker(UrchinConfiguration configuration, SessionManager sessionManager, IEnvironment environment, Action<Uri> sender)
 {
     this.sessionManager = sessionManager;
     this.sender = sender;
     tracker = new UrchinUriBuilder(configuration, sessionManager, environment);
     hostName = configuration.HostName;
 }
 /// <summary>
 /// Configure this MeasurementAnalyticsClient so it can start recording and sending analytics.
 /// </summary>
 /// <param name="configuration">Configuration settings for this client.</param>
 /// <param name="sessionManager">Session manager to store and retreive session state.</param>
 /// <param name="environment">Provider of environmental details such as screen resolution.</param>
 /// <param name="sender">Action delegate responsible for sending URIs to analytics.</param>
 public void Configure(MeasurementConfiguration configuration, SessionManager sessionManager, IEnvironment environment, Action<Uri> sender)
 {
     Debug.Assert(tracker == null);
     var newTracker = new MeasurementTracker(configuration, sessionManager, environment, sender);
     while (queue.Count > 0)
         newTracker.Track(queue.Dequeue());
     tracker = newTracker;
 }
        public void SessionManager_Can_Be_Created_From_State()
        {
            var state = CreateSampleState();

            var sessionManager = new SessionManager(state);

            Assert.AreEqual(state.Referrer, sessionManager.Referrer);
            Assert.AreEqual(state.VisitorId, sessionManager.Visitor.ClientId);
        }
 /// <summary>
 /// Create a cookie-substitute parameter used to track session activity.
 /// </summary>
 /// <param name="sessionManager">Session manager to obtain session and visitor from</param>
 /// <param name="hostNameHash">Hash of this host name.</param>
 /// <returns>String containing a cookie-like set of session information.</returns>
 internal static string CreateCookieSubstituteParameter(SessionManager sessionManager, long hostNameHash)
 {
     return String.Format(CultureInfo.InvariantCulture, "__utma={0}.{1}.{2}.{3}.{4}.{5};",
             hostNameHash,
             ReduceGuidToUint(sessionManager.Visitor.ClientId),
             new EpochTime(sessionManager.Visitor.FirstVisitAt),
             new EpochTime(sessionManager.PreviousSessionStartedAt),
             new EpochTime(sessionManager.Session.StartedAt),
             sessionManager.Session.Number);
 }
        public void SessionManager_Created_From_Null_State_Is_Fresh()
        {
            var sessionManager = new SessionManager(null);

            Assert.IsNull(sessionManager.Referrer);
            Assert.IsNotNull(sessionManager.Visitor);
            Assert.IsNotNull(sessionManager.Session);
            Assert.AreEqual(0, sessionManager.Session.HitCount);
            Assert.IsTrue(sessionManager.PreviousSessionStartedAt <= DateTimeOffset.Now);
        }
        public void SessionManager_Created_From_State_Provides_Same_State()
        {
            var expected = CreateSampleState();

            var sessionManager = new SessionManager(expected);

            var actual = sessionManager.GetState();

            Assert.AreEqual(expected.LastActivityAt, actual.LastActivityAt);
            Assert.AreEqual(expected.Referrer, actual.Referrer);
        }
        public void SessionManager_Creates_New_Session_When_Requested()
        {
            var sessionManager = new SessionManager(null);

            Assert.AreEqual(1, sessionManager.Session.Number);

            var starting = DateTimeOffset.Now;

            sessionManager.StartNewSession();
            Assert.AreEqual(2, sessionManager.Session.Number);
            Assert.IsTrue(sessionManager.Session.StartedAt >= starting, "Session StartedAt too early");
            Assert.IsTrue(sessionManager.Session.StartedAt <= DateTimeOffset.Now, "Session StartedAt too late");
        }
        public void SessionManager_Created_From_State_Provides_Same_State()
        {
            var expected = CreateSampleState();

            var sessionManager = new SessionManager(TimeSpan.FromDays(1), expected);

            var actual = sessionManager.GetState();

            Assert.AreEqual(expected.FirstVisitAt, actual.FirstVisitAt);
            Assert.AreEqual(expected.HitId, actual.HitId);
            Assert.AreEqual(expected.LastActivityAt, actual.LastActivityAt);
            Assert.AreEqual(expected.PreviousSessionStartedAt, actual.PreviousSessionStartedAt);
            Assert.AreEqual(expected.Referrer, actual.Referrer);
            Assert.AreEqual(expected.SessionHitCount, actual.SessionHitCount);
            Assert.AreEqual(expected.SessionNumber, actual.SessionNumber);
            Assert.AreEqual(expected.SessionStartedAt, actual.SessionStartedAt);
        }
        public void UrchinTracker_CreateCookieSubstituteParameter()
        {
            var @event = new EventActivity("action", "catgory", "label", 123, true);
            var sessionState = new SessionState
                {
                    SessionNumber = 5,
                    VisitorId = new Guid("FFFCCBCB-9A87-4987-BD20-CE7C81F96CD2"),
                    FirstVisitAt = new DateTimeOffset(2012, 10, 10, 13, 14, 15, TimeSpan.Zero),
                    PreviousSessionStartedAt = new DateTimeOffset(2012, 12, 10, 13, 14, 15, TimeSpan.Zero),
                    SessionStartedAt = new DateTimeOffset(2012, 12, 14, 13, 14, 15, TimeSpan.Zero),
                };
            var sessionManager = new SessionManager(TimeSpan.FromMinutes(5), sessionState);

            var cookieSubstitute = UrchinTracker.CreateCookieSubstituteParameter(sessionManager, 1);

            Assert.AreEqual("__utma=1.1159017511.1349874855.1355145255.1355490855.5;", cookieSubstitute);
        }
        public void SessionManager_Can_Be_Created_From_State()
        {
            var timeout = TimeSpan.FromMinutes(5);
            var state = CreateSampleState();

            var sessionManager = new SessionManager(state);

            Assert.AreEqual(state.PreviousSessionStartedAt, sessionManager.PreviousSessionStartedAt);
            Assert.AreEqual(state.Referrer, sessionManager.Referrer);

            Assert.AreEqual(state.FirstVisitAt, sessionManager.Visitor.FirstVisitAt);
            Assert.AreEqual(state.VisitorId, sessionManager.Visitor.ClientId);

            Assert.AreEqual(state.HitId, sessionManager.Session.HitId);
            Assert.AreEqual(state.SessionHitCount, sessionManager.Session.HitCount);
            Assert.AreEqual(state.SessionNumber, sessionManager.Session.Number);
            Assert.AreEqual(state.SessionStartedAt, sessionManager.Session.StartedAt);
        }
        /// <summary>
        /// Initialize CSharpAnalytics by restoring the session state and starting the background sender.
        /// </summary>
        /// <param name="configuration">Configuration to use, must at a minimum specify your Google Analytics ID and app name.</param>
        /// <param name="uploadInterval">How often to upload to the server. Lower times = more traffic but realtime. Defaults to 5 seconds.</param>
        /// <example>var analyticsTask = AutoMeasurement.Start(new MeasurementConfiguration("UA-123123123-1", "MyApp", "1.0.0.0"));</example>
        public static async Task Start(MeasurementConfiguration configuration, TimeSpan? uploadInterval = null)
        {
            if (!isStarted)
            {
                isStarted = true;
                lastUploadInterval = uploadInterval ?? TimeSpan.FromSeconds(5);
                systemUserAgent = WinFormsSystemInformation.GetSystemUserAgent();

                var sessionState = await LoadSessionState();
                sessionManager = new SessionManager(sessionState, configuration.SampleRate);
                await StartRequesterAsync();

                if (delayedOptOut != null) SetOptOut(delayedOptOut.Value);

                Client.Configure(configuration, sessionManager, new WinFormsEnvironment(), Add);
            }

            client.TrackEvent("Start", ApplicationLifecycleEvent, "Launch");
        }
        /// <summary>
        /// Initialize CSharpAnalytics by restoring the session state and starting the background sender and tracking
        /// the application lifecycle start event.
        /// </summary>
        /// <param name="configuration">Configuration to use, must at a minimum specify your Google Analytics ID and app name.</param>
        /// <param name="launchArgs">Launch arguments from your Application OnLaunched to determine how the app was launched.</param>
        /// <param name="uploadInterval">How often to upload to the server. Lower times = more traffic but realtime. Defaults to 5 seconds.</param>
        /// <example>var analyticsTask = AutoMeasurement.StartAsync(new MeasurementConfiguration("UA-123123123-1", "MyApp", "1.0.0.0"));</example>
        public static async Task StartAsync(MeasurementConfiguration configuration, IActivatedEventArgs launchArgs, TimeSpan? uploadInterval = null)
        {
            if (!isStarted)
            {
                isStarted = true;
                lastUploadInterval = uploadInterval ?? TimeSpan.FromSeconds(5);
                systemUserAgent = await WindowsStoreSystemInformation.GetSystemUserAgent();
                await StartRequesterAsync();

                var sessionState = await LoadSessionState();
                sessionManager = new SessionManager(sessionState, configuration.SampleRate);
                if (delayedOptOut != null) SetOptOut(delayedOptOut.Value);

                Client.Configure(configuration, sessionManager, new WindowsStoreEnvironment(), Add);
                HookEvents();
            }

            Client.TrackEvent("Start", ApplicationLifecycleEvent, launchArgs.Kind.ToString());
        }
        public void SessionManager_SessionStatus_Is_Starting_For_New_Session()
        {
            var sessionManager = new SessionManager(null);

            Assert.AreEqual(SessionStatus.Starting, sessionManager.SessionStatus);
        }
 /// <summary>
 /// Create new MeasurementUriBuilder to prepare URIs for Google's Measurement Protocol endpoint.
 /// </summary>
 /// <param name="configuration">Configuration of analytics.</param>
 /// <param name="sessionManager">Session manager.</param>
 /// <param name="environment">Environment details.</param>
 public MeasurementUriBuilder(MeasurementConfiguration configuration, SessionManager sessionManager, IEnvironment environment)
 {
     this.configuration = configuration;
     this.sessionManager = sessionManager;
     this.environment = environment;
 }
        /// <summary>
        /// Get parameters for a given session manager and domain hash.
        /// </summary>
        /// <param name="sessionManager">Session manager to obtain parameters from.</param>
        /// <returns>Enumerable of key/value pairs of session information.</returns>
        internal static IEnumerable<KeyValuePair<string, string>> GetParameters(SessionManager sessionManager)
        {
            yield return KeyValuePair.Create("cid", sessionManager.Visitor.ClientId.ToString());

            var sessionControlValue = GetSessionControlValue(sessionManager.SessionStatus);
            if (!String.IsNullOrEmpty(sessionControlValue))
                yield return KeyValuePair.Create("sc", sessionControlValue);
        }
        public void SessionManager_Creates_New_Session_When_Hit_After_Timeout()
        {
            var timeout = TimeSpan.FromSeconds(2);
            var sessionManager = new SessionManager(timeout, null);

            Assert.AreEqual(1, sessionManager.Session.Number);

            var starting = DateTimeOffset.Now;
            Task.Delay(timeout + TimeSpan.FromSeconds(1)).Wait();

            sessionManager.Hit();
            Assert.AreEqual(2, sessionManager.Session.Number);
            Assert.IsTrue(sessionManager.Session.StartedAt >= starting, "Session StartedAt too early");
            Assert.IsTrue(sessionManager.Session.StartedAt <= DateTimeOffset.Now, "Session StartedAt too late");
        }
 /// <summary>
 /// Create new UrchinUriBuilder to prepare URIs for Google's Urchin tracker endpoint.
 /// </summary>
 /// <param name="configuration">Configuration of analytics.</param>
 /// <param name="sessionManager">Session manager.</param>
 /// <param name="environment">Environment details.</param>
 public UrchinUriBuilder(UrchinConfiguration configuration, SessionManager sessionManager, IEnvironment environment)
 {
     this.sessionManager = sessionManager;
     this.configuration = configuration;
     this.environment = environment;
 }
 public void SessionManager_SampleRate_100_Should_Always_Choose_Visitor()
 {
     for (var i = 0; i < 100; i++)
     {
         var sessionManager = new SessionManager(null, 100);
         Assert.AreEqual(VisitorStatus.Active, sessionManager.VisitorStatus);
     }
 }
 public void SessionManager_SampleRate_0_Should_Never_Choose_Visitor()
 {
     for (var i = 0; i < 100; i++)
     {
         var sessionManager = new SessionManager(null, 0);
         Assert.AreEqual(VisitorStatus.SampledOut, sessionManager.VisitorStatus);
     }
 }
        public void SessionManager_Creates_New_Session_In_A_Thread_Safe_Way()
        {
            var timeout = TimeSpan.FromSeconds(2);
            var sessionManager = new SessionManager(timeout, null);

            Task.Delay(timeout + TimeSpan.FromSeconds(1)).Wait();

            Task.WaitAll(
                Task.Run(() => { for (var i = 0; i < 500; i++) sessionManager.Hit(); }),
                Task.Run(() => { for (var i = 0; i < 500; i++) sessionManager.Hit(); }),
                Task.Run(() => { for (var i = 0; i < 500; i++) sessionManager.Hit(); })
            );

            Task.Delay(timeout + TimeSpan.FromSeconds(1)).Wait();

            Task.WaitAll(
                Task.Run(() => { for (var i = 0; i < 500; i++) sessionManager.Hit(); }),
                Task.Run(() => { for (var i = 0; i < 500; i++) sessionManager.Hit(); }),
                Task.Run(() => { for (var i = 0; i < 500; i++) sessionManager.Hit(); })
            );

            Assert.AreEqual(3, sessionManager.Session.Number);
            Assert.AreEqual(1500, sessionManager.Session.HitCount);
        }
        public void SessionManager_SessionStatus_Is_Starting_After_Hit_After_End()
        {
            var sessionManager = new SessionManager(null);
            sessionManager.Hit();
            sessionManager.End();
            sessionManager.Hit();

            Assert.AreEqual(SessionStatus.Starting, sessionManager.SessionStatus);
        }
 /// <summary>
 /// Get parameters for a given session manager and domain hash.
 /// </summary>
 /// <param name="sessionManager">Session manager to obtain parameters from.</param>
 /// <param name="hostNameHash">Hash of this host name.</param>
 /// <returns>Enumerable of key/value pairs of session information.</returns>
 internal static IEnumerable<KeyValuePair<string, string>> GetParameters(SessionManager sessionManager, long hostNameHash)
 {
     yield return KeyValuePair.Create("utmhid", sessionManager.Session.HitId.ToString(CultureInfo.InvariantCulture));
     yield return KeyValuePair.Create("utms", sessionManager.Session.HitCount.ToString(CultureInfo.InvariantCulture));
     yield return KeyValuePair.Create("utmr", sessionManager.Referrer == null ? "-" : sessionManager.Referrer.OriginalString);
     yield return KeyValuePair.Create("utmcc", CreateCookieSubstituteParameter(sessionManager, hostNameHash));
 }
 /// <summary>
 /// Create new UrchinTracker to prepare URIs for Google's Urchin tracker endpoint.
 /// </summary>
 /// <param name="configuration">Configuration of analytics.</param>
 /// <param name="sessionManager">Session manager.</param>
 /// <param name="environment">Environment details.</param>
 public UrchinTracker(Configuration configuration, SessionManager sessionManager, IEnvironment environment)
 {
     this.sessionManager = sessionManager;
     this.configuration = configuration;
     this.environment = environment;
 }
        private static void TestSampleRateDistribution(double sampleRate)
        {
            const int repetitions = 1000;

            var sampledCount = 0;
            var sessionManager = new SessionManager(null);

            // Setup a linear distribution as random numbers are too unpredictable
            var nextSelector = 0.0;
            sessionManager.SampleSelector = () =>
            {
                var selector = nextSelector;
                nextSelector += (100.0 / repetitions);
                return selector;
            };

            for (var i = 0; i < repetitions; i++)
            {
                if (sessionManager.ShouldTrackThisNewVisitor(sampleRate))
                    sampledCount++;
            }

            var expected = repetitions * (sampleRate / 100);
            Assert.AreEqual(expected, sampledCount);
        }