// Copyright Epic Games, Inc. All Rights Reserved. extern alias HordeAgent; using System; using System.Collections.Generic; using System.Threading.Tasks; using Amazon.EC2.Model; using Build.Bazel.Remote.Execution.V2; using Google.LongRunning; using HordeServer; using HordeServer.Models; using HordeServer.Services; using HordeServer.Tasks.Impl; using HordeServer.Utilities; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Console; using Microsoft.VisualStudio.TestTools.UnitTesting; using PoolId = HordeServer.Utilities.StringId; namespace HordeServerTests.RemoteExec { [TestClass] public class ActionTaskSourceTest : DatabaseIntegrationTest { private readonly TestSetup TestSetup; public ActionTaskSourceTest() { TestSetup = GetTestSetup().Result; } [TestMethod] public async Task BasicExecution() { ActionTaskSource TaskSource = CreateTaskSource(); FakeAgent Agent = new FakeAgent(); await TaskSource.SubscribeAsync(Agent); ExecuteRequest Req1 = new ExecuteRequest(); Req1.SkipCacheLookup = true; Req1.ActionDigest = new Digest { Hash = "bogusTestingHash1", SizeBytes = 17 }; ExecuteRequest Req2 = new ExecuteRequest(); Req2.SkipCacheLookup = true; Req2.ActionDigest = new Digest { Hash = "bogusTestingHash2", SizeBytes = 17 }; IActionExecuteOperation ExecuteOp1 = TaskSource.Execute(Req1); IActionExecuteOperation ExecuteOp2 = TaskSource.Execute(Req2); Task Pump1 = PumpExecuteOperation(TaskSource, ExecuteOp1, 10, Agent); Task Pump2 = PumpExecuteOperation(TaskSource, ExecuteOp2, 20, Agent); await Task.WhenAll(Pump1, Pump2); } [TestMethod] public async Task BasicExecutionWithPoolFilter() { RemoteExecInstanceSettings InstanceSettings = new RemoteExecInstanceSettings(); InstanceSettings.PoolFilter = new List {"pool1"}; TestSetup.ServerSettingsMon.CurrentValue.RemoteExecSettings.Instances["foobar"] = InstanceSettings; ActionTaskSource TaskSource = CreateTaskSource(); FakeAgent Agent = new FakeAgent(); Agent.ExplicitPools = new List {new PoolId("pool1")}; await TaskSource.SubscribeAsync(Agent); ExecuteRequest Req1 = new ExecuteRequest(); Req1.InstanceName = "foobar"; Req1.SkipCacheLookup = true; Req1.ActionDigest = new Digest { Hash = "bogusTestingHash1", SizeBytes = 17 }; IActionExecuteOperation ExecuteOp1 = TaskSource.Execute(Req1); await PumpExecuteOperation(TaskSource, ExecuteOp1, 10, Agent); } [TestMethod] public void CanBeScheduledOnAgent() { FakeAgent AgentWithNoPools = new FakeAgent(); FakeAgent Agent = new FakeAgent(); Agent.ExplicitPools = new List> {new PoolId("pool1"), new PoolId("pool2")}; Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(Agent, new List {"pool1"})); Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(Agent, new List {"pool2"})); Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(Agent, new List {"pool1", "pool2"})); Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(Agent, new List {"bogus", "pool2"})); Assert.IsFalse(ActionTaskSource.CanBeScheduledOnAgent(AgentWithNoPools, new List {"bogus", "pool2"})); Assert.IsFalse(ActionTaskSource.CanBeScheduledOnAgent(Agent, new List {"bogus", "foobar"})); Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(Agent, new List())); Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(AgentWithNoPools, new List())); Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(Agent, null)); Assert.IsTrue(ActionTaskSource.CanBeScheduledOnAgent(AgentWithNoPools, null)); } private async Task PumpExecuteOperation(ActionTaskSource TaskSource, IActionExecuteOperation ExecuteOp, int ExitCode, IAgent? AgentToReschedule) { Operation? LastOperation = null; await foreach (Operation Op in ExecuteOp.ReadStatusUpdatesAsync()) { LastOperation = Op; Assert.IsTrue(Op.Metadata.TryUnpack(out ExecuteOperationMetadata Metadata)); string Msg = $"id={Op.Name} digest={Metadata.ActionDigest.Hash} stage={Metadata.Stage}"; if (Metadata.Stage == ExecutionStage.Types.Value.Executing) { ExecuteOp.TrySetResult(new ActionExecuteResult(new ActionResult {ExitCode = ExitCode})); } if (Op.Done) { Assert.IsTrue(Op.Response.TryUnpack(out ExecuteResponse Response)); Assert.AreEqual(ExitCode, Response.Result.ExitCode); Msg += " result=" + Response; } Console.WriteLine(Msg); } if (AgentToReschedule != null) { // Schedule the agent again so the task source can execute actions on it await TaskSource.SubscribeAsync(AgentToReschedule); } return LastOperation!; } private ActionTaskSource CreateTaskSource() { ILogFileService LogFileService = (TestSetup.ServiceProvider.GetService(typeof(ILogFileService)) as ILogFileService)!; ILoggerFactory LoggerFactory = new LoggerFactory(); ConsoleLoggerOptions LoggerOptions = new ConsoleLoggerOptions(); TestOptionsMonitor LoggerOptionsMon = new TestOptionsMonitor(LoggerOptions); LoggerFactory.AddProvider(new ConsoleLoggerProvider(LoggerOptionsMon)); ILogger Logger = LoggerFactory.CreateLogger(); return new ActionTaskSource(null!, LogFileService, Logger, TestSetup.ServerSettingsMon); } } }