File: GivenAAllowEmptyTelemetry.cs
Web Access
Project: ..\..\..\src\Tasks\Microsoft.NET.Build.Tasks.UnitTests\Microsoft.NET.Build.Tasks.UnitTests.csproj (Microsoft.NET.Build.Tasks.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using FluentAssertions;
using Microsoft.Build.Framework;
using Microsoft.Build.Tasks;
using Microsoft.Build.Utilities;
using Xunit;
 
namespace Microsoft.NET.Build.Tasks.UnitTests
{
    public class GivenAAllowEmptyTelemetry
    {
        private static ITaskItem CreateHashItem(string key, string? value = null, bool? hash = null)
        {
            var item = new TaskItem(key);
            item.SetMetadata("Value", value);
            if (hash is not null)
            {
                item.SetMetadata("Hash", hash.Value.ToString());
            }
            return item;
        }
 
        [Fact]
        public void WhenInvokeWithoutValueItSendValueAsNull()
        {
            var engine = new MockBuildEngine5();
 
            AllowEmptyTelemetry telemetryTask = new()
            {
                BuildEngine = engine,
                EventName = "My event name",
                EventData = new ITaskItem[] {
                    CreateHashItem("Property1"),
                    CreateHashItem("Property2", "")
                }
            };
 
            telemetryTask.Execute();
 
            engine.Log.Should().Contain("'Property1' = 'null'");
            engine.Log.Should().Contain("'Property2' = 'null'");
        }
 
        [Fact]
        public void WhenInvokeWithDuplicatedEventDataItKeepsTheLastOne()
        {
            var engine = new MockBuildEngine5();
 
            AllowEmptyTelemetry telemetryTask = new()
            {
                BuildEngine = engine,
                EventName = "My event name",
                EventData = new ITaskItem[] {
                    CreateHashItem("Property1", "EE2493A167D24F00996DE7C8E769EAE6"),
                    CreateHashItem("Property1", "4ADE3D2622CA400B8B95A039DF540037")
                }
            };
 
            bool retVal = telemetryTask.Execute();
 
            retVal.Should().BeTrue();
 
            engine.Log.Should().NotContain("EE2493A167D24F00996DE7C8E769EAE6");
            engine.Log.Should().Contain("4ADE3D2622CA400B8B95A039DF540037");
        }
 
        [Fact]
        public void WhenInvokeWithNoEventDataItSendsEvents()
        {
            var engine = new MockBuildEngine5();
 
            AllowEmptyTelemetry telemetryTask = new()
            {
                BuildEngine = engine,
                EventName = "My event name"
            };
 
            bool retVal = telemetryTask.Execute();
 
            retVal.Should().BeTrue();
            engine.Log.Should().Contain(telemetryTask.EventName);
            engine.Log.Should().NotContain("Property"); // shouldn't have any logged properties since none were supplied
        }
 
        [Fact]
        public void WhenHashIsRequestedValueIsHashed()
        {
            var engine = new MockBuildEngine5();
 
            AllowEmptyTelemetry telemetryTask = new()
            {
                BuildEngine = engine,
                EventName = "My event name",
                EventData = new ITaskItem[] {
                    CreateHashItem("Property1", "hi", true),
                    CreateHashItem("Property2", "hello", false)
                }
            };
 
            telemetryTask.Execute();
            // first property should be hashed
            engine.Log.Should().Contain("'Property1' = 'cd6f6854353f68f47c9c93217c5084bc66ea1af918ae1518a2d715a1885e1fcb'");
            engine.Log.Should().Contain("'Property2' = 'hello'");
        }
 
        /// <summary>
        /// Only implement telemetry related API
        /// </summary>
        private class MockBuildEngine5 : MockBuildEngine, IBuildEngine5
        {
            private readonly object _lockObj = new();
            private readonly StringBuilder _log = new();
 
            internal string Log
            {
                get
                {
                    lock (_lockObj)
                    {
                        return _log.ToString();
                    }
                }
                set
                {
                    if (!string.IsNullOrEmpty(value))
                    {
                        throw new ArgumentException("Expected log setter to be used only to reset the log to empty.");
                    }
 
                    lock (_lockObj)
                    {
                        _log.Clear();
                    }
                }
            }
 
            public void LogTelemetry(string eventName, IDictionary<string, string> properties)
            {
                string message = $"Received telemetry event '{eventName}'{Environment.NewLine}";
                if (properties is not null)
                {
                    foreach (string key in properties.Keys)
                    {
                        message += $"  Property '{key}' = '{properties[key]}'{Environment.NewLine}";
                    }
                }
 
                lock (_lockObj)
                {
                    _log.AppendLine(message);
                }
            }
        }
    }
}