File: TelemetryCommonPropertiesTests.cs
Web Access
Project: ..\..\..\test\dotnet.Tests\dotnet.Tests.csproj (dotnet.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable disable
 
using Microsoft.DotNet.Cli.Telemetry;
using Microsoft.DotNet.Configurer;
 
namespace Microsoft.DotNet.Tests
{
    public class TelemetryCommonPropertiesTests : SdkTest
    {
        public TelemetryCommonPropertiesTests(ITestOutputHelper log) : base(log)
        {
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldContainIfItIsInDockerOrNot()
        {
            var unitUnderTest = new TelemetryCommonProperties(userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId").Should().ContainKey("Docker Container");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnHashedPath()
        {
            var unitUnderTest = new TelemetryCommonProperties(() => "ADirectory", userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Current Path Hash"].Should().NotBe("ADirectory");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnHashedMachineId()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => "plaintext", userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Machine ID"].Should().NotBe("plaintext");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnDevDeviceId()
        {
            var unitUnderTest = new TelemetryCommonProperties(getDeviceId: () => "plaintext", userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["devdeviceid"].Should().Be("plaintext");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnNewGuidWhenCannotGetMacAddress()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            var assignedMachineId = unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Machine ID"];
 
            Guid.TryParse(assignedMachineId, out var _).Should().BeTrue("it should be a guid");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldEnsureDevDeviceIDIsCached()
        {
            var unitUnderTest = new TelemetryCommonProperties(userLevelCacheWriter: new NothingCache());
            var assignedMachineId = unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["devdeviceid"];
 
            Guid.TryParse(assignedMachineId, out var _).Should().BeTrue("it should be a guid");
            var secondAssignedMachineId = unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["devdeviceid"];
 
            Guid.TryParse(secondAssignedMachineId, out var _).Should().BeTrue("it should be a guid");
            secondAssignedMachineId.Should().Be(assignedMachineId, "it should match the previously assigned guid");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnHashedMachineIdOld()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => "plaintext", userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Machine ID Old"].Should().NotBe("plaintext");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnNewGuidWhenCannotGetMacAddressOld()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            var assignedMachineId = unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Machine ID Old"];
 
            Guid.TryParse(assignedMachineId, out var _).Should().BeTrue("it should be a guid");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnIsOutputRedirected()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Output Redirected"].Should().BeOneOf("True", "False");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnIsCIDetection()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Continuous Integration"].Should().BeOneOf("True", "False");
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldContainKernelVersion()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Kernel Version"].Should().Be(RuntimeInformation.OSDescription);
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldContainArchitectureInformation()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["OS Architecture"].Should().Be(RuntimeInformation.OSArchitecture.ToString());
        }
 
        [WindowsOnlyFact]
        public void TelemetryCommonPropertiesShouldContainWindowsInstallType()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Installation Type"].Should().NotBeEmpty();
        }
 
        [UnixOnlyFact]
        public void TelemetryCommonPropertiesShouldContainEmptyWindowsInstallType()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Installation Type"].Should().BeEmpty();
        }
 
        [WindowsOnlyFact]
        public void TelemetryCommonPropertiesShouldContainWindowsProductType()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Product Type"].Should().NotBeEmpty();
        }
 
        [UnixOnlyFact]
        public void TelemetryCommonPropertiesShouldContainEmptyWindowsProductType()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Product Type"].Should().BeEmpty();
        }
 
        [WindowsOnlyFact]
        public void TelemetryCommonPropertiesShouldContainEmptyLibcReleaseAndVersion()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Libc Release"].Should().BeEmpty();
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Libc Version"].Should().BeEmpty();
        }
 
        [MacOsOnlyFact]
        public void TelemetryCommonPropertiesShouldContainEmptyLibcReleaseAndVersion2()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Libc Release"].Should().BeEmpty();
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Libc Version"].Should().BeEmpty();
        }
 
        [LinuxOnlyFact]
        public void TelemetryCommonPropertiesShouldContainLibcReleaseAndVersion()
        {
            if (!RuntimeInformation.RuntimeIdentifier.Contains("alpine", StringComparison.OrdinalIgnoreCase))
            {
                var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
                unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Libc Release"].Should().NotBeEmpty();
                unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["Libc Version"].Should().NotBeEmpty();
            }
        }
 
        [Fact]
        public void TelemetryCommonPropertiesShouldReturnIsLLMDetection()
        {
            var unitUnderTest = new TelemetryCommonProperties(getMACAddress: () => null, userLevelCacheWriter: new NothingCache());
            unitUnderTest.GetTelemetryCommonProperties("dummySessionId")["llm"].Should().BeOneOf("claude", null);
        }
 
        [Theory]
        [MemberData(nameof(CITelemetryTestCases))]
        public void CanDetectCIStatusForEnvVars(Dictionary<string, string> envVars, bool expected)
        {
            try
            {
                foreach (var (key, value) in envVars)
                {
                    Environment.SetEnvironmentVariable(key, value);
                }
                new CIEnvironmentDetectorForTelemetry().IsCIEnvironment().Should().Be(expected);
            }
            finally
            {
                foreach (var (key, value) in envVars)
                {
                    Environment.SetEnvironmentVariable(key, null);
                }
            }
        }
 
        [Theory]
        [MemberData(nameof(LLMTelemetryTestCases))]
        public void CanDetectLLMStatusForEnvVars(Dictionary<string, string> envVars, string expected)
        {
            try
            {
                foreach (var (key, value) in envVars)
                {
                    Environment.SetEnvironmentVariable(key, value);
                }
                new LLMEnvironmentDetectorForTelemetry().GetLLMEnvironment().Should().Be(expected);
            }
            finally
            {
                foreach (var (key, value) in envVars)
                {
                    Environment.SetEnvironmentVariable(key, null);
                }
            }
        }
        
        [Theory]
        [InlineData("dummySessionId")]
        [InlineData(null)]
        public void TelemetryCommonPropertiesShouldContainSessionId(string sessionId)
        {
            var unitUnderTest = new TelemetryCommonProperties(userLevelCacheWriter: new NothingCache());
            var commonProperties = unitUnderTest.GetTelemetryCommonProperties(sessionId);
 
            commonProperties.Should().ContainKey("SessionId");
            commonProperties["SessionId"].Should().Be(sessionId);
        }
 
 
        public static IEnumerable<object[]> LLMTelemetryTestCases => new List<object[]>{
            new object[] { new Dictionary<string, string> { { "CLAUDECODE", "1" } }, "claude" },
            new object[] { new Dictionary<string, string> { { "CURSOR_EDITOR", "1" } }, "cursor" },
            new object[] { new Dictionary<string, string> { { "CLAUDECODE", "1" }, { "CURSOR_EDITOR", "1" } }, "claude, cursor" },
            new object[] { new Dictionary<string, string>(), null },
        };
 
        public static IEnumerable<object[]> CITelemetryTestCases => new List<object[]>{
            new object[] { new Dictionary<string, string> { { "TF_BUILD", "true" } }, true },
            new object[] { new Dictionary<string, string> { { "GITHUB_ACTIONS", "true" } }, true },
            new object[] { new Dictionary<string, string> { { "APPVEYOR", "true"} }, true },
            new object[] { new Dictionary<string, string> { { "CI", "true"} }, true },
            new object[] { new Dictionary<string, string> { { "TRAVIS", "true"} }, true },
            new object[] { new Dictionary<string, string> { { "CIRCLECI", "true"} }, true },
 
            new object[] { new Dictionary<string, string> { { "CODEBUILD_BUILD_ID", "hi" }, { "AWS_REGION", "hi" } }, true },
            new object[] { new Dictionary<string, string> { { "CODEBUILD_BUILD_ID", "hi" } }, false },
            new object[] { new Dictionary<string, string> { { "BUILD_ID", "hi" }, { "BUILD_URL", "hi" } }, true },
            new object[] { new Dictionary<string, string> { { "BUILD_ID", "hi" } }, false },
            new object[] { new Dictionary<string, string> { { "BUILD_ID", "hi" }, { "PROJECT_ID", "hi" } }, true },
            new object[] { new Dictionary<string, string> { { "BUILD_ID", "hi" } }, false },
 
            new object[] { new Dictionary<string, string> { { "TEAMCITY_VERSION", "hi" } }, true },
            new object[] { new Dictionary<string, string> { { "TEAMCITY_VERSION", "" } }, false },
            new object[] { new Dictionary<string, string> { { "JB_SPACE_API_URL", "hi" } }, true },
            new object[] { new Dictionary<string, string> { { "JB_SPACE_API_URL", "" } }, false },
 
            new object[] { new Dictionary<string, string> { { "SomethingElse", "hi" } }, false },
        };
 
        private class NothingCache : IUserLevelCacheWriter
        {
            public string RunWithCache(string cacheKey, Func<string> getValueToCache)
            {
                return getValueToCache();
            }
 
            public string RunWithCacheInFilePath(string cacheFilepath, Func<string> getValueToCache)
            {
                return getValueToCache();
            }
        }
    }
}