File: BackEnd\TaskHostCallbackPacket_Tests.cs
Web Access
Project: ..\..\..\src\Build.UnitTests\Microsoft.Build.Engine.UnitTests.csproj (Microsoft.Build.Engine.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using Microsoft.Build.BackEnd;
using Microsoft.Build.Framework;
using Microsoft.Build.Execution;
using Shouldly;
using Xunit;
 
namespace Microsoft.Build.UnitTests.BackEnd
{
    /// <summary>
    /// Pure unit tests for TaskHost callback packet serialization.
    /// No I/O or BuildManager -- just round-trip translation.
    /// </summary>
    public class TaskHostCallbackPacket_Tests
    {
        [Fact]
        public void TaskHostIsRunningMultipleNodesRequest_RoundTrip_Serialization()
        {
            var request = new TaskHostIsRunningMultipleNodesRequest();
            request.RequestId = 42;
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            request.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostIsRunningMultipleNodesRequest)TaskHostIsRunningMultipleNodesRequest.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(42);
            deserialized.Type.ShouldBe(NodePacketType.TaskHostIsRunningMultipleNodesRequest);
        }
 
        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        public void TaskHostIsRunningMultipleNodesResponse_RoundTrip_Serialization(bool isRunningMultipleNodes)
        {
            var response = new TaskHostIsRunningMultipleNodesResponse(123, isRunningMultipleNodes);
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            response.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostIsRunningMultipleNodesResponse)TaskHostIsRunningMultipleNodesResponse.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(123);
            deserialized.IsRunningMultipleNodes.ShouldBe(isRunningMultipleNodes);
            deserialized.Type.ShouldBe(NodePacketType.TaskHostIsRunningMultipleNodesResponse);
        }
 
        [Theory]
        [InlineData(4, false)]  // RequestCores(4)
        [InlineData(2, true)]   // ReleaseCores(2)
        public void TaskHostCoresRequest_RoundTrip_Serialization(int cores, bool isRelease)
        {
            var request = new TaskHostCoresRequest(cores, isRelease);
            request.RequestId = 77;
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            request.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostCoresRequest)TaskHostCoresRequest.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(77);
            deserialized.RequestedCores.ShouldBe(cores);
            deserialized.IsRelease.ShouldBe(isRelease);
            deserialized.Type.ShouldBe(NodePacketType.TaskHostCoresRequest);
        }
 
        [Theory]
        [InlineData(0)]   // ReleaseCores acknowledgment
        [InlineData(3)]   // RequestCores granted 3
        public void TaskHostCoresResponse_RoundTrip_Serialization(int grantedCores)
        {
            var response = new TaskHostCoresResponse(99, grantedCores);
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            response.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostCoresResponse)TaskHostCoresResponse.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(99);
            deserialized.GrantedCores.ShouldBe(grantedCores);
            deserialized.Type.ShouldBe(NodePacketType.TaskHostCoresResponse);
        }
 
        [Fact]
        public void TaskHostBuildRequest_RoundTrip_Serialization()
        {
            Dictionary<string, string>?[] globalProps = [new(StringComparer.OrdinalIgnoreCase) { ["Configuration"] = "Release" }, null];
            List<string>?[] removeProps = [new() { "Platform" }, null];
            string?[] toolsVersions = ["17.0", null];
            var request = new TaskHostBuildRequest(
                ["proj1.csproj", "proj2.csproj"],
                ["Build", "Test"],
                globalProps,
                removeProps,
                toolsVersions!,
                returnTargetOutputs: true);
            request.RequestId = 55;
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            request.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostBuildRequest)TaskHostBuildRequest.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(55);
            deserialized.Type.ShouldBe(NodePacketType.TaskHostBuildRequest);
            deserialized.ProjectFileNames.ShouldBe(["proj1.csproj", "proj2.csproj"]);
            deserialized.TargetNames.ShouldBe(["Build", "Test"]);
            deserialized.ToolsVersions.ShouldBe(toolsVersions!);
            deserialized.ReturnTargetOutputs.ShouldBeTrue();
            deserialized.GlobalProperties!.Length.ShouldBe(2);
            deserialized.GlobalProperties![0]!["Configuration"].ShouldBe("Release");
            deserialized.GlobalProperties[1].ShouldBeNull();
            deserialized.RemoveGlobalProperties!.Length.ShouldBe(2);
            deserialized.RemoveGlobalProperties![0].ShouldBe(["Platform"]);
            deserialized.RemoveGlobalProperties[1].ShouldBeNull();
        }
 
        [Fact]
        public void TaskHostBuildRequest_NullArrays_RoundTrip_Serialization()
        {
            var request = new TaskHostBuildRequest(
                null, null, null, null, null, returnTargetOutputs: false);
            request.RequestId = 10;
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            request.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostBuildRequest)TaskHostBuildRequest.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(10);
            deserialized.ProjectFileNames.ShouldBeNull();
            deserialized.TargetNames.ShouldBeNull();
            deserialized.GlobalProperties.ShouldBeNull();
            deserialized.RemoveGlobalProperties.ShouldBeNull();
            deserialized.ToolsVersions.ShouldBeNull();
            deserialized.ReturnTargetOutputs.ShouldBeFalse();
        }
 
        [Fact]
        public void TaskHostBuildResponse_Success_WithOutputs_RoundTrip_Serialization()
        {
            var outputs = new List<Dictionary<string, TaskParameter>>
            {
                new(StringComparer.OrdinalIgnoreCase)
                {
                    ["Build"] = new TaskParameter(new ITaskItem[] { new Utilities.TaskItem("item1.dll") }),
                    ["Test"] = new TaskParameter(new ITaskItem[] { new Utilities.TaskItem("result.trx") })
                }
            };
 
            var response = new TaskHostBuildResponse(88, true, outputs);
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            response.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostBuildResponse)TaskHostBuildResponse.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(88);
            deserialized.Success.ShouldBeTrue();
            deserialized.Type.ShouldBe(NodePacketType.TaskHostBuildResponse);
            deserialized.TargetOutputsPerProject.ShouldNotBeNull();
            deserialized.TargetOutputsPerProject.Count.ShouldBe(1);
            deserialized.TargetOutputsPerProject[0].ContainsKey("Build").ShouldBeTrue();
 
            var buildEngineResult = deserialized.ToBuildEngineResult();
            buildEngineResult.Result.ShouldBeTrue();
            buildEngineResult.TargetOutputsPerProject.Count.ShouldBe(1);
            buildEngineResult.TargetOutputsPerProject[0]["Build"].Length.ShouldBe(1);
            buildEngineResult.TargetOutputsPerProject[0]["Build"][0].ItemSpec.ShouldBe("item1.dll");
        }
 
        [Fact]
        public void TaskHostBuildResponse_Failure_NoOutputs_RoundTrip_Serialization()
        {
            var response = new TaskHostBuildResponse(33, false, null);
 
            ITranslator writeTranslator = TranslationHelpers.GetWriteTranslator();
            response.Translate(writeTranslator);
 
            ITranslator readTranslator = TranslationHelpers.GetReadTranslator();
            var deserialized = (TaskHostBuildResponse)TaskHostBuildResponse.FactoryForDeserialization(readTranslator);
 
            deserialized.RequestId.ShouldBe(33);
            deserialized.Success.ShouldBeFalse();
            deserialized.TargetOutputsPerProject.ShouldBeNull();
 
            var buildEngineResult = deserialized.ToBuildEngineResult();
            buildEngineResult.Result.ShouldBeFalse();
        }
    }
}