From 275ab753a19165ca6bad71f26095a0873686b6b0 Mon Sep 17 00:00:00 2001 From: Julio Barba Date: Mon, 9 Dec 2019 17:54:41 -0500 Subject: [PATCH] Runner cleanup - continuation (#209) * Agent/AgentCredential -> Runner/RunnerCredential * Test trait rename: Agent -> Runner * Enable remaining RunnerL0 tests * Remove job message PII variable masking code * Remove unused Agent.ToolsDirectory variable * Misc test Agent -> Runner renaming * Some more misc cleaning --- src/Runner.Common/Constants.cs | 8 - src/Runner.Listener/{Agent.cs => Runner.cs} | 19 - src/Runner.Worker/Variables.cs | 30 - src/Runner.Worker/Worker.cs | 2 +- src/Runner.Worker/WorkerUtilties.cs | 92 --- src/Test/L0/ConstantGenerationL0.cs | 2 +- src/Test/L0/DotnetsdkDownloadScriptL0.cs | 4 +- src/Test/L0/Listener/AgentL0.cs | 574 ------------------ .../Configuration/ConfigurationManagerL0.cs | 28 +- ...tCredentialL0.cs => RunnerCredentialL0.cs} | 4 +- src/Test/L0/Listener/JobDispatcherL0.cs | 76 +-- src/Test/L0/Listener/MessageListenerL0.cs | 28 +- src/Test/L0/Listener/RunnerL0.cs | 509 ++++++++++++++++ src/Test/L0/ServiceInterfacesL0.cs | 4 +- src/Test/L0/TestHostContext.cs | 6 +- src/Test/L0/Worker/WorkerL0.cs | 56 -- 16 files changed, 583 insertions(+), 859 deletions(-) rename src/Runner.Listener/{Agent.cs => Runner.cs} (96%) delete mode 100644 src/Runner.Worker/WorkerUtilties.cs delete mode 100644 src/Test/L0/Listener/AgentL0.cs rename src/Test/L0/Listener/Configuration/{AgentCredentialL0.cs => RunnerCredentialL0.cs} (87%) create mode 100644 src/Test/L0/Listener/RunnerL0.cs diff --git a/src/Runner.Common/Constants.cs b/src/Runner.Common/Constants.cs index 72e364e1c..2c5813227 100644 --- a/src/Runner.Common/Constants.cs +++ b/src/Runner.Common/Constants.cs @@ -208,14 +208,6 @@ namespace GitHub.Runner.Common public static readonly string StepDebug = "ACTIONS_STEP_DEBUG"; } - public static class Agent - { - // - // Keep alphabetical - // - public static readonly string ToolsDirectory = "agent.ToolsDirectory"; - } - public static class System { // diff --git a/src/Runner.Listener/Agent.cs b/src/Runner.Listener/Runner.cs similarity index 96% rename from src/Runner.Listener/Agent.cs rename to src/Runner.Listener/Runner.cs index b55b192ff..85cda747f 100644 --- a/src/Runner.Listener/Agent.cs +++ b/src/Runner.Listener/Runner.cs @@ -190,25 +190,6 @@ namespace GitHub.Runner.Listener } } -#if !OS_WINDOWS - // Fix the work folder setting on Linux - if (settings.WorkFolder.Contains("vsts", StringComparison.OrdinalIgnoreCase)) - { - var workFolder = "/runner/work"; - var unix = HostContext.GetService(); - - // create new work folder /runner/work - await unix.ExecAsync(HostContext.GetDirectory(WellKnownDirectory.Root), "sh", $"-c \"sudo mkdir -p {workFolder}\""); - - // fix permission - await unix.ExecAsync(HostContext.GetDirectory(WellKnownDirectory.Root), "sh", $"-c \"sudo chown -R $USER {workFolder}\""); - - // update settings - settings.WorkFolder = workFolder; - store.SaveSettings(settings); - } -#endif - Trace.Info($"Set runner startup type - {startType}"); HostContext.StartupType = startType; diff --git a/src/Runner.Worker/Variables.cs b/src/Runner.Worker/Variables.cs index cee65f5be..84304f989 100644 --- a/src/Runner.Worker/Variables.cs +++ b/src/Runner.Worker/Variables.cs @@ -75,36 +75,6 @@ namespace GitHub.Runner.Worker public string System_PhaseDisplayName => Get(Constants.Variables.System.PhaseDisplayName); - public string System_TFCollectionUrl => Get(WellKnownDistributedTaskVariables.TFCollectionUrl); - - public static readonly HashSet PiiVariables = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "Build.AuthorizeAs", - "Build.QueuedBy", - "Build.RequestedFor", - "Build.RequestedForEmail", - "Build.SourceBranch", - "Build.SourceBranchName", - "Build.SourceTfvcShelveset", - "Build.SourceVersion", - "Build.SourceVersionAuthor", - "Job.AuthorizeAs", - "Release.Deployment.RequestedFor", - "Release.Deployment.RequestedForEmail", - "Release.RequestedFor", - "Release.RequestedForEmail", - }; - - public static readonly string PiiArtifactVariablePrefix = "Release.Artifacts"; - - public static readonly List PiiArtifactVariableSuffixes = new List() - { - "SourceBranch", - "SourceBranchName", - "SourceVersion", - "RequestedFor" - }; - public string Get(string name) { Variable variable; diff --git a/src/Runner.Worker/Worker.cs b/src/Runner.Worker/Worker.cs index bb57b4fdc..de22c444e 100644 --- a/src/Runner.Worker/Worker.cs +++ b/src/Runner.Worker/Worker.cs @@ -73,7 +73,7 @@ namespace GitHub.Runner.Worker SetCulture(jobMessage); // Start the job. - Trace.Info($"Job message:{Environment.NewLine} {StringUtil.ConvertToJson(WorkerUtilities.ScrubPiiData(jobMessage))}"); + Trace.Info($"Job message:{Environment.NewLine} {StringUtil.ConvertToJson(jobMessage)}"); Task jobRunnerTask = jobRunner.RunAsync(jobMessage, jobRequestCancellationToken.Token); // Start listening for a cancel message from the channel. diff --git a/src/Runner.Worker/WorkerUtilties.cs b/src/Runner.Worker/WorkerUtilties.cs deleted file mode 100644 index ac1470469..000000000 --- a/src/Runner.Worker/WorkerUtilties.cs +++ /dev/null @@ -1,92 +0,0 @@ -using GitHub.DistributedTask.Pipelines.ContextData; -using GitHub.DistributedTask.WebApi; -using Pipelines = GitHub.DistributedTask.Pipelines; -using System; -using System.Collections.Generic; -using System.Linq; -using GitHub.Runner.Sdk; - -namespace GitHub.Runner.Worker -{ - public class WorkerUtilities - { - public static Pipelines.AgentJobRequestMessage ScrubPiiData(Pipelines.AgentJobRequestMessage message) - { - ArgUtil.NotNull(message, nameof(message)); - - var scrubbedVariables = new Dictionary(); - - // Scrub the known PII variables - foreach (var variable in message.Variables) - { - if (Variables.PiiVariables.Contains(variable.Key) || - (variable.Key.StartsWith(Variables.PiiArtifactVariablePrefix, StringComparison.OrdinalIgnoreCase) - && Variables.PiiArtifactVariableSuffixes.Any(varSuffix => variable.Key.EndsWith(varSuffix, StringComparison.OrdinalIgnoreCase)))) - { - scrubbedVariables[variable.Key] = "[PII]"; - } - else - { - scrubbedVariables[variable.Key] = variable.Value; - } - } - - var scrubbedRepositories = new List(); - - // Scrub the repository resources - foreach (var repository in message.Resources.Repositories) - { - Pipelines.RepositoryResource scrubbedRepository = repository.Clone(); - - var versionInfo = repository.Properties.Get(Pipelines.RepositoryPropertyNames.VersionInfo); - - if (versionInfo != null) - { - scrubbedRepository.Properties.Set( - Pipelines.RepositoryPropertyNames.VersionInfo, - new Pipelines.VersionInfo() - { - Author = "[PII]", - Message = versionInfo.Message - }); - } - - scrubbedRepositories.Add(scrubbedRepository); - } - - var scrubbedJobResources = new Pipelines.JobResources(); - - scrubbedJobResources.Containers.AddRange(message.Resources.Containers); - scrubbedJobResources.Endpoints.AddRange(message.Resources.Endpoints); - scrubbedJobResources.Repositories.AddRange(scrubbedRepositories); - scrubbedJobResources.SecureFiles.AddRange(message.Resources.SecureFiles); - - var contextData = new DictionaryContextData(); - if (message.ContextData?.Count > 0) - { - foreach (var pair in message.ContextData) - { - contextData[pair.Key] = pair.Value; - } - } - - // Reconstitute a new agent job request message from the scrubbed parts - return new Pipelines.AgentJobRequestMessage( - plan: message.Plan, - timeline: message.Timeline, - jobId: message.JobId, - jobDisplayName: message.JobDisplayName, - jobName: message.JobName, - jobContainer: message.JobContainer, - jobServiceContainers: message.JobServiceContainers, - environmentVariables: message.EnvironmentVariables, - variables: scrubbedVariables, - maskHints: message.MaskHints, - jobResources: scrubbedJobResources, - contextData: contextData, - workspaceOptions: message.Workspace, - steps: message.Steps, - scopes: message.Scopes); - } - } -} diff --git a/src/Test/L0/ConstantGenerationL0.cs b/src/Test/L0/ConstantGenerationL0.cs index 31caa57af..d964ba474 100644 --- a/src/Test/L0/ConstantGenerationL0.cs +++ b/src/Test/L0/ConstantGenerationL0.cs @@ -9,7 +9,7 @@ namespace GitHub.Runner.Common.Tests { [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public void BuildConstantGenerateSucceed() { List validPackageNames = new List() diff --git a/src/Test/L0/DotnetsdkDownloadScriptL0.cs b/src/Test/L0/DotnetsdkDownloadScriptL0.cs index 25646c147..1e66815f6 100644 --- a/src/Test/L0/DotnetsdkDownloadScriptL0.cs +++ b/src/Test/L0/DotnetsdkDownloadScriptL0.cs @@ -9,7 +9,7 @@ namespace GitHub.Runner.Common.Tests { [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async Task EnsureDotnetsdkBashDownloadScriptUpToDate() { string shDownloadUrl = "https://dot.net/v1/dotnet-install.sh"; @@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async Task EnsureDotnetsdkPowershellDownloadScriptUpToDate() { string ps1DownloadUrl = "https://dot.net/v1/dotnet-install.ps1"; diff --git a/src/Test/L0/Listener/AgentL0.cs b/src/Test/L0/Listener/AgentL0.cs deleted file mode 100644 index b5ffa7b6f..000000000 --- a/src/Test/L0/Listener/AgentL0.cs +++ /dev/null @@ -1,574 +0,0 @@ -// using GitHub.DistributedTask.WebApi; -// using GitHub.Runner.Listener; -// using GitHub.Runner.Listener.Configuration; -// using Moq; -// using System; -// using System.Collections.Generic; -// using System.Threading; -// using System.Threading.Tasks; -// using Xunit; -// using GitHub.Services.WebApi; -// using Pipelines = GitHub.DistributedTask.Pipelines; -// using GitHub.Runner.Common.Util; - -// namespace GitHub.Runner.Common.Tests.Listener -// { -// public sealed class AgentL0 -// { -// private Mock _configurationManager; -// private Mock _jobNotification; -// private Mock _messageListener; -// private Mock _promptManager; -// private Mock _jobDispatcher; -// private Mock _agentServer; -// private Mock _term; -// private Mock _configStore; -// private Mock _proxy; -// private Mock _cert; -// private Mock _updater; - -// public AgentL0() -// { -// _configurationManager = new Mock(); -// _jobNotification = new Mock(); -// _messageListener = new Mock(); -// _promptManager = new Mock(); -// _jobDispatcher = new Mock(); -// _agentServer = new Mock(); -// _term = new Mock(); -// _configStore = new Mock(); -// _proxy = new Mock(); -// _cert = new Mock(); -// _updater = new Mock(); -// } - -// private AgentJobRequestMessage CreateJobRequestMessage(string jobName) -// { -// TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference(); -// TimelineReference timeline = null; -// JobEnvironment environment = new JobEnvironment(); -// List tasks = new List(); -// Guid JobId = Guid.NewGuid(); -// var jobRequest = new AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, environment, tasks); -// return jobRequest as AgentJobRequestMessage; -// } - -// private JobCancelMessage CreateJobCancelMessage() -// { -// var message = new JobCancelMessage(Guid.NewGuid(), TimeSpan.FromSeconds(0)); -// return message; -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Agent")] -// //process 2 new job messages, and one cancel message -// public async void TestRunAsync() -// { -// using (var hc = new TestHostContext(this)) -// { -// //Arrange -// var agent = new Runner.Listener.Runner(); -// hc.SetSingleton(_configurationManager.Object); -// hc.SetSingleton(_jobNotification.Object); -// hc.SetSingleton(_messageListener.Object); -// hc.SetSingleton(_promptManager.Object); -// hc.SetSingleton(_agentServer.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_configStore.Object); -// agent.Initialize(hc); -// var settings = new RunnerSettings -// { -// PoolId = 43242 -// }; - -// var message = new TaskAgentMessage() -// { -// Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), -// MessageId = 4234, -// MessageType = JobRequestMessageTypes.AgentJobRequest -// }; - -// var messages = new Queue(); -// messages.Enqueue(message); -// var signalWorkerComplete = new SemaphoreSlim(0, 1); -// _configurationManager.Setup(x => x.LoadSettings()) -// .Returns(settings); -// _configurationManager.Setup(x => x.IsConfigured()) -// .Returns(true); -// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) -// .Returns(Task.FromResult(true)); -// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) -// .Returns(async () => -// { -// if (0 == messages.Count) -// { -// signalWorkerComplete.Release(); -// await Task.Delay(2000, hc.RunnerShutdownToken); -// } - -// return messages.Dequeue(); -// }); -// _messageListener.Setup(x => x.DeleteSessionAsync()) -// .Returns(Task.CompletedTask); -// _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) -// .Returns(Task.CompletedTask); -// _jobDispatcher.Setup(x => x.Run(It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); - -// hc.EnqueueInstance(_jobDispatcher.Object); - -// _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); -// //Act -// var command = new CommandSettings(hc, new string[] { "run" }); -// Task agentTask = agent.ExecuteCommand(command); - -// //Assert -// //wait for the agent to run one job -// if (!await signalWorkerComplete.WaitAsync(2000)) -// { -// Assert.True(false, $"{nameof(_messageListener.Object.GetNextMessageAsync)} was not invoked."); -// } -// else -// { -// //Act -// hc.ShutdownRunner(ShutdownReason.UserCancelled); //stop Agent - -// //Assert -// Task[] taskToWait2 = { agentTask, Task.Delay(2000) }; -// //wait for the Agent to exit -// await Task.WhenAny(taskToWait2); - -// Assert.True(agentTask.IsCompleted, $"{nameof(agent.ExecuteCommand)} timed out."); -// Assert.True(!agentTask.IsFaulted, agentTask.Exception?.ToString()); -// Assert.True(agentTask.IsCanceled); - -// _jobDispatcher.Verify(x => x.Run(It.IsAny(), It.IsAny()), Times.Once(), -// $"{nameof(_jobDispatcher.Object.Run)} was not invoked."); -// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); -// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); -// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); -// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.AtLeastOnce()); -// } -// } -// } - -// public static TheoryData RunAsServiceTestData = new TheoryData() -// { -// // staring with run command, configured as run as service, should start the agent -// { new [] { "run" }, true, Times.Once() }, -// // starting with no argument, configured not to run as service, should start agent interactively -// { new [] { "run" }, false, Times.Once() } -// }; -// [Theory] -// [MemberData("RunAsServiceTestData")] -// [Trait("Level", "L0")] -// [Trait("Category", "Agent")] -// public async void TestExecuteCommandForRunAsService(string[] args, bool configureAsService, Times expectedTimes) -// { -// using (var hc = new TestHostContext(this)) -// { -// hc.SetSingleton(_configurationManager.Object); -// hc.SetSingleton(_promptManager.Object); -// hc.SetSingleton(_messageListener.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_configStore.Object); - -// var command = new CommandSettings(hc, args); - -// _configurationManager.Setup(x => x.IsConfigured()).Returns(true); -// _configurationManager.Setup(x => x.LoadSettings()) -// .Returns(new RunnerSettings { }); - -// _configStore.Setup(x => x.IsServiceConfigured()).Returns(configureAsService); - -// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) -// .Returns(Task.FromResult(false)); - -// var agent = new Runner.Listener.Runner(); -// agent.Initialize(hc); -// await agent.ExecuteCommand(command); - -// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), expectedTimes); -// } -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Agent")] -// //process 2 new job messages, and one cancel message -// public async void TestMachineProvisionerCLI() -// { -// using (var hc = new TestHostContext(this)) -// { -// hc.SetSingleton(_configurationManager.Object); -// hc.SetSingleton(_promptManager.Object); -// hc.SetSingleton(_messageListener.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_configStore.Object); - -// var command = new CommandSettings(hc, new[] { "run" }); - -// _configurationManager.Setup(x => x.IsConfigured()). -// Returns(true); -// _configurationManager.Setup(x => x.LoadSettings()) -// .Returns(new RunnerSettings { }); - -// _configStore.Setup(x => x.IsServiceConfigured()) -// .Returns(false); - -// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) -// .Returns(Task.FromResult(false)); - -// var agent = new Runner.Listener.Runner(); -// agent.Initialize(hc); -// await agent.ExecuteCommand(command); - -// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); -// } -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Agent")] -// //process 2 new job messages, and one cancel message -// public async void TestMachineProvisionerCLICompat() -// { -// using (var hc = new TestHostContext(this)) -// { -// hc.SetSingleton(_configurationManager.Object); -// hc.SetSingleton(_promptManager.Object); -// hc.SetSingleton(_messageListener.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_configStore.Object); - -// var command = new CommandSettings(hc, new string[] { }); - -// _configurationManager.Setup(x => x.IsConfigured()). -// Returns(true); -// _configurationManager.Setup(x => x.LoadSettings()) -// .Returns(new RunnerSettings { }); - -// _configStore.Setup(x => x.IsServiceConfigured()) -// .Returns(false); - -// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) -// .Returns(Task.FromResult(false)); - -// var agent = new Runner.Listener.Runner(); -// agent.Initialize(hc); -// await agent.ExecuteCommand(command); - -// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); -// } -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Agent")] -// public async void TestRunOnce() -// { -// using (var hc = new TestHostContext(this)) -// { -// //Arrange -// var agent = new Runner.Listener.Runner(); -// hc.SetSingleton(_configurationManager.Object); -// hc.SetSingleton(_jobNotification.Object); -// hc.SetSingleton(_messageListener.Object); -// hc.SetSingleton(_promptManager.Object); -// hc.SetSingleton(_agentServer.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_configStore.Object); -// agent.Initialize(hc); -// var settings = new RunnerSettings -// { -// PoolId = 43242 -// }; - -// var message = new TaskAgentMessage() -// { -// Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), -// MessageId = 4234, -// MessageType = JobRequestMessageTypes.AgentJobRequest -// }; - -// var messages = new Queue(); -// messages.Enqueue(message); -// _configurationManager.Setup(x => x.LoadSettings()) -// .Returns(settings); -// _configurationManager.Setup(x => x.IsConfigured()) -// .Returns(true); -// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) -// .Returns(Task.FromResult(true)); -// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) -// .Returns(async () => -// { -// if (0 == messages.Count) -// { -// await Task.Delay(2000); -// } - -// return messages.Dequeue(); -// }); -// _messageListener.Setup(x => x.DeleteSessionAsync()) -// .Returns(Task.CompletedTask); -// _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) -// .Returns(Task.CompletedTask); - -// var runOnceJobCompleted = new TaskCompletionSource(); -// _jobDispatcher.Setup(x => x.RunOnceJobCompleted) -// .Returns(runOnceJobCompleted); -// _jobDispatcher.Setup(x => x.Run(It.IsAny(), It.IsAny())) -// .Callback(() => -// { -// runOnceJobCompleted.TrySetResult(true); -// }); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); - -// hc.EnqueueInstance(_jobDispatcher.Object); - -// _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); -// //Act -// var command = new CommandSettings(hc, new string[] { "run", "--once" }); -// Task agentTask = agent.ExecuteCommand(command); - -// //Assert -// //wait for the agent to run one job and exit -// await Task.WhenAny(agentTask, Task.Delay(30000)); - -// Assert.True(agentTask.IsCompleted, $"{nameof(agent.ExecuteCommand)} timed out."); -// Assert.True(!agentTask.IsFaulted, agentTask.Exception?.ToString()); -// Assert.True(agentTask.Result == Constants.Runner.ReturnCode.Success); - -// _jobDispatcher.Verify(x => x.Run(It.IsAny(), true), Times.Once(), -// $"{nameof(_jobDispatcher.Object.Run)} was not invoked."); -// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); -// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); -// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); -// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.AtLeastOnce()); -// } -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Agent")] -// public async void TestRunOnceOnlyTakeOneJobMessage() -// { -// using (var hc = new TestHostContext(this)) -// { -// //Arrange -// var agent = new Runner.Listener.Runner(); -// hc.SetSingleton(_configurationManager.Object); -// hc.SetSingleton(_jobNotification.Object); -// hc.SetSingleton(_messageListener.Object); -// hc.SetSingleton(_promptManager.Object); -// hc.SetSingleton(_agentServer.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_configStore.Object); -// agent.Initialize(hc); -// var settings = new RunnerSettings -// { -// PoolId = 43242 -// }; - -// var message1 = new TaskAgentMessage() -// { -// Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), -// MessageId = 4234, -// MessageType = JobRequestMessageTypes.AgentJobRequest -// }; -// var message2 = new TaskAgentMessage() -// { -// Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), -// MessageId = 4235, -// MessageType = JobRequestMessageTypes.AgentJobRequest -// }; - -// var messages = new Queue(); -// messages.Enqueue(message1); -// messages.Enqueue(message2); -// _configurationManager.Setup(x => x.LoadSettings()) -// .Returns(settings); -// _configurationManager.Setup(x => x.IsConfigured()) -// .Returns(true); -// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) -// .Returns(Task.FromResult(true)); -// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) -// .Returns(async () => -// { -// if (0 == messages.Count) -// { -// await Task.Delay(2000); -// } - -// return messages.Dequeue(); -// }); -// _messageListener.Setup(x => x.DeleteSessionAsync()) -// .Returns(Task.CompletedTask); -// _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) -// .Returns(Task.CompletedTask); - -// var runOnceJobCompleted = new TaskCompletionSource(); -// _jobDispatcher.Setup(x => x.RunOnceJobCompleted) -// .Returns(runOnceJobCompleted); -// _jobDispatcher.Setup(x => x.Run(It.IsAny(), It.IsAny())) -// .Callback(() => -// { -// runOnceJobCompleted.TrySetResult(true); -// }); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); - -// hc.EnqueueInstance(_jobDispatcher.Object); - -// _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); -// //Act -// var command = new CommandSettings(hc, new string[] { "run", "--once" }); -// Task agentTask = agent.ExecuteCommand(command); - -// //Assert -// //wait for the agent to run one job and exit -// await Task.WhenAny(agentTask, Task.Delay(30000)); - -// Assert.True(agentTask.IsCompleted, $"{nameof(agent.ExecuteCommand)} timed out."); -// Assert.True(!agentTask.IsFaulted, agentTask.Exception?.ToString()); -// Assert.True(agentTask.Result == Constants.Runner.ReturnCode.Success); - -// _jobDispatcher.Verify(x => x.Run(It.IsAny(), true), Times.Once(), -// $"{nameof(_jobDispatcher.Object.Run)} was not invoked."); -// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); -// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); -// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); -// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.Once()); -// } -// } - -// [Fact] -// [Trait("Level", "L0")] -// [Trait("Category", "Agent")] -// public async void TestRunOnceHandleUpdateMessage() -// { -// using (var hc = new TestHostContext(this)) -// { -// //Arrange -// var agent = new Runner.Listener.Runner(); -// hc.SetSingleton(_configurationManager.Object); -// hc.SetSingleton(_jobNotification.Object); -// hc.SetSingleton(_messageListener.Object); -// hc.SetSingleton(_promptManager.Object); -// hc.SetSingleton(_agentServer.Object); -// hc.SetSingleton(_proxy.Object); -// hc.SetSingleton(_cert.Object); -// hc.SetSingleton(_configStore.Object); -// hc.SetSingleton(_updater.Object); - -// agent.Initialize(hc); -// var settings = new RunnerSettings -// { -// PoolId = 43242, -// AgentId = 5678 -// }; - -// var message1 = new TaskAgentMessage() -// { -// Body = JsonUtility.ToString(new AgentRefreshMessage(settings.AgentId, "2.123.0")), -// MessageId = 4234, -// MessageType = AgentRefreshMessage.MessageType -// }; - -// var messages = new Queue(); -// messages.Enqueue(message1); -// _updater.Setup(x => x.SelfUpdate(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) -// .Returns(Task.FromResult(true)); -// _configurationManager.Setup(x => x.LoadSettings()) -// .Returns(settings); -// _configurationManager.Setup(x => x.IsConfigured()) -// .Returns(true); -// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) -// .Returns(Task.FromResult(true)); -// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) -// .Returns(async () => -// { -// if (0 == messages.Count) -// { -// await Task.Delay(2000); -// } - -// return messages.Dequeue(); -// }); -// _messageListener.Setup(x => x.DeleteSessionAsync()) -// .Returns(Task.CompletedTask); -// _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) -// .Returns(Task.CompletedTask); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); -// _jobNotification.Setup(x => x.StartClient(It.IsAny(), It.IsAny())) -// .Callback(() => -// { - -// }); - -// hc.EnqueueInstance(_jobDispatcher.Object); - -// _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); -// //Act -// var command = new CommandSettings(hc, new string[] { "run", "--once" }); -// Task agentTask = agent.ExecuteCommand(command); - -// //Assert -// //wait for the agent to exit with right return code -// await Task.WhenAny(agentTask, Task.Delay(30000)); - -// Assert.True(agentTask.IsCompleted, $"{nameof(agent.ExecuteCommand)} timed out."); -// Assert.True(!agentTask.IsFaulted, agentTask.Exception?.ToString()); -// Assert.True(agentTask.Result == Constants.Runner.ReturnCode.RunOnceRunnerUpdating); - -// _updater.Verify(x => x.SelfUpdate(It.IsAny(), It.IsAny(), false, It.IsAny()), Times.Once); -// _jobDispatcher.Verify(x => x.Run(It.IsAny(), true), Times.Never()); -// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); -// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); -// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); -// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.Once()); -// } -// } -// } -// } diff --git a/src/Test/L0/Listener/Configuration/ConfigurationManagerL0.cs b/src/Test/L0/Listener/Configuration/ConfigurationManagerL0.cs index 0f4c55c72..ebf3de053 100644 --- a/src/Test/L0/Listener/Configuration/ConfigurationManagerL0.cs +++ b/src/Test/L0/Listener/Configuration/ConfigurationManagerL0.cs @@ -20,7 +20,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration { public class ConfigurationManagerL0 { - private Mock _agentServer; + private Mock _runnerServer; private Mock _locationServer; private Mock _credMgr; private Mock _promptManager; @@ -50,7 +50,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration public ConfigurationManagerL0() { - _agentServer = new Mock(); + _runnerServer = new Mock(); _locationServer = new Mock(); _credMgr = new Mock(); _promptManager = new Mock(); @@ -81,15 +81,9 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration DeploymentType = DeploymentFlags.Hosted, DeploymentId = Guid.NewGuid() }; - _agentServer.Setup(x => x.ConnectAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(null)); + _runnerServer.Setup(x => x.ConnectAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(null)); _locationServer.Setup(x => x.ConnectAsync(It.IsAny())).Returns(Task.FromResult(null)); _locationServer.Setup(x => x.GetConnectionDataAsync()).Returns(Task.FromResult(connectionData)); - // _machineGroupServer.Setup(x => x.ConnectAsync(It.IsAny())).Returns(Task.FromResult(null)); - // _machineGroupServer.Setup(x => x.UpdateDeploymentTargetsAsync(It.IsAny(), It.IsAny(), It.IsAny>())); - // _machineGroupServer.Setup(x => x.AddDeploymentTargetAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedDeploymentMachine)); - // _machineGroupServer.Setup(x => x.ReplaceDeploymentTargetAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedDeploymentMachine)); - // _machineGroupServer.Setup(x => x.GetDeploymentTargetsAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(new List() { })); - // _machineGroupServer.Setup(x => x.DeleteDeploymentTargetAsync(It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(null)); _store.Setup(x => x.IsConfigured()).Returns(false); _store.Setup(x => x.HasCredentials()).Returns(false); @@ -101,20 +95,20 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration _configMgrAgentSettings = settings; }); - _credMgr.Setup(x => x.GetCredentialProvider(It.IsAny())).Returns(new TestAgentCredential()); + _credMgr.Setup(x => x.GetCredentialProvider(It.IsAny())).Returns(new TestRunnerCredential()); #if !OS_WINDOWS _serviceControlManager.Setup(x => x.GenerateScripts(It.IsAny())); #endif var expectedPools = new List() { new TaskAgentPool(_expectedPoolName) { Id = _expectedPoolId } }; - _agentServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedPools)); + _runnerServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedPools)); var expectedAgents = new List(); - _agentServer.Setup(x => x.GetAgentsAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedAgents)); + _runnerServer.Setup(x => x.GetAgentsAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedAgents)); - _agentServer.Setup(x => x.AddAgentAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedAgent)); - _agentServer.Setup(x => x.ReplaceAgentAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedAgent)); + _runnerServer.Setup(x => x.AddAgentAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedAgent)); + _runnerServer.Setup(x => x.ReplaceAgentAsync(It.IsAny(), It.IsAny())).Returns(Task.FromResult(expectedAgent)); rsa = new RSACryptoServiceProvider(2048); @@ -128,7 +122,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration tc.SetSingleton(_promptManager.Object); tc.SetSingleton(_store.Object); tc.SetSingleton(_extnMgr.Object); - tc.SetSingleton(_agentServer.Object); + tc.SetSingleton(_runnerServer.Object); tc.SetSingleton(_locationServer.Object); tc.SetSingleton(_cert.Object); @@ -190,9 +184,9 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration Assert.True(s.WorkFolder.Equals(_expectedWorkFolder)); // validate GetAgentPoolsAsync gets called once with automation pool type - _agentServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny(), It.Is(p => p == TaskAgentPoolType.Automation)), Times.Once); + _runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny(), It.Is(p => p == TaskAgentPoolType.Automation)), Times.Once); - _agentServer.Verify(x => x.AddAgentAsync(It.IsAny(), It.Is(a => a.Labels.Contains("self-hosted") && a.Labels.Contains(VarUtil.OS) && a.Labels.Contains(VarUtil.OSArchitecture))), Times.Once); + _runnerServer.Verify(x => x.AddAgentAsync(It.IsAny(), It.Is(a => a.Labels.Contains("self-hosted") && a.Labels.Contains(VarUtil.OS) && a.Labels.Contains(VarUtil.OSArchitecture))), Times.Once); } } } diff --git a/src/Test/L0/Listener/Configuration/AgentCredentialL0.cs b/src/Test/L0/Listener/Configuration/RunnerCredentialL0.cs similarity index 87% rename from src/Test/L0/Listener/Configuration/AgentCredentialL0.cs rename to src/Test/L0/Listener/Configuration/RunnerCredentialL0.cs index 9d743d132..8e2e2f654 100644 --- a/src/Test/L0/Listener/Configuration/AgentCredentialL0.cs +++ b/src/Test/L0/Listener/Configuration/RunnerCredentialL0.cs @@ -5,9 +5,9 @@ using GitHub.Services.Common; namespace GitHub.Runner.Common.Tests.Listener.Configuration { - public class TestAgentCredential : CredentialProvider + public class TestRunnerCredential : CredentialProvider { - public TestAgentCredential(): base("TEST") {} + public TestRunnerCredential(): base("TEST") {} public override VssCredentials GetVssCredentials(IHostContext context) { Tracing trace = context.GetTrace("PersonalAccessToken"); diff --git a/src/Test/L0/Listener/JobDispatcherL0.cs b/src/Test/L0/Listener/JobDispatcherL0.cs index abe27c39b..60955b6fb 100644 --- a/src/Test/L0/Listener/JobDispatcherL0.cs +++ b/src/Test/L0/Listener/JobDispatcherL0.cs @@ -17,14 +17,14 @@ namespace GitHub.Runner.Common.Tests.Listener { private Mock _processChannel; private Mock _processInvoker; - private Mock _agentServer; + private Mock _runnerServer; private Mock _configurationStore; public JobDispatcherL0() { _processChannel = new Mock(); _processInvoker = new Mock(); - _agentServer = new Mock(); + _runnerServer = new Mock(); _configurationStore = new Mock(); } @@ -43,7 +43,7 @@ namespace GitHub.Runner.Common.Tests.Listener [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatchesJobRequest() { //Arrange @@ -51,7 +51,7 @@ namespace GitHub.Runner.Common.Tests.Listener { var jobDispatcher = new JobDispatcher(); hc.SetSingleton(_configurationStore.Object); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.EnqueueInstance(_processChannel.Object); hc.EnqueueInstance(_processInvoker.Object); @@ -76,9 +76,9 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(sessionIdProperty); sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(request)); + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(request)); - _agentServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(new TaskAgentJobRequest())); + _runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(new TaskAgentJobRequest())); //Actt @@ -93,7 +93,7 @@ namespace GitHub.Runner.Common.Tests.Listener [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatcherRenewJobRequest() { //Arrange @@ -112,10 +112,10 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(lockUntilProperty); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.SetSingleton(_configurationStore.Object); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(() => { count++; @@ -145,13 +145,13 @@ namespace GitHub.Runner.Common.Tests.Listener await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token); Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully); - _agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); + _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); } } [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatcherRenewJobRequestStopOnJobNotFoundExceptions() { //Arrange @@ -170,10 +170,10 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(lockUntilProperty); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.SetSingleton(_configurationStore.Object); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(() => { count++; @@ -204,13 +204,13 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.False(cancellationTokenSource.IsCancellationRequested); - _agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); + _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); } } [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatcherRenewJobRequestStopOnJobTokenExpiredExceptions() { //Arrange @@ -229,10 +229,10 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(lockUntilProperty); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.SetSingleton(_configurationStore.Object); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(() => { count++; @@ -263,13 +263,13 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.False(cancellationTokenSource.IsCancellationRequested); - _agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); + _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); } } [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatcherRenewJobRequestRecoverFromExceptions() { //Arrange @@ -288,10 +288,10 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(lockUntilProperty); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.SetSingleton(_configurationStore.Object); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(() => { count++; @@ -322,15 +322,15 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.True(cancellationTokenSource.IsCancellationRequested); - _agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(8)); - _agentServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny()), Times.Exactly(3)); - _agentServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny()), Times.Once); + _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(8)); + _runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny()), Times.Exactly(3)); + _runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny()), Times.Once); } } [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatcherRenewJobRequestFirstRenewRetrySixTimes() { //Arrange @@ -349,10 +349,10 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(lockUntilProperty); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.SetSingleton(_configurationStore.Object); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(() => { count++; @@ -379,13 +379,13 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.False(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should failed."); Assert.False(cancellationTokenSource.IsCancellationRequested); - _agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(6)); + _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(6)); } } [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatcherRenewJobRequestStopOnExpiredRequest() { //Arrange @@ -404,10 +404,10 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(lockUntilProperty); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.SetSingleton(_configurationStore.Object); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(() => { count++; @@ -443,15 +443,15 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.False(cancellationTokenSource.IsCancellationRequested); - _agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); - _agentServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny()), Times.Exactly(3)); - _agentServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny()), Times.Never); + _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(5)); + _runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny()), Times.Exactly(3)); + _runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny()), Times.Never); } } [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DispatchesOneTimeJobRequest() { //Arrange @@ -459,7 +459,7 @@ namespace GitHub.Runner.Common.Tests.Listener { var jobDispatcher = new JobDispatcher(); hc.SetSingleton(_configurationStore.Object); - hc.SetSingleton(_agentServer.Object); + hc.SetSingleton(_runnerServer.Object); hc.EnqueueInstance(_processChannel.Object); hc.EnqueueInstance(_processInvoker.Object); @@ -484,9 +484,9 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(sessionIdProperty); sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); - _agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(request)); + _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(request)); - _agentServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(new TaskAgentJobRequest())); + _runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(Task.FromResult(new TaskAgentJobRequest())); //Act jobDispatcher.Run(message, true); diff --git a/src/Test/L0/Listener/MessageListenerL0.cs b/src/Test/L0/Listener/MessageListenerL0.cs index e85ac6170..626d924a0 100644 --- a/src/Test/L0/Listener/MessageListenerL0.cs +++ b/src/Test/L0/Listener/MessageListenerL0.cs @@ -18,7 +18,7 @@ namespace GitHub.Runner.Common.Tests.Listener { private RunnerSettings _settings; private Mock _config; - private Mock _agentServer; + private Mock _runnerServer; private Mock _credMgr; public MessageListenerL0() @@ -26,7 +26,7 @@ namespace GitHub.Runner.Common.Tests.Listener _settings = new RunnerSettings { AgentId = 1, AgentName = "myagent", PoolId = 123, PoolName = "default", ServerUrl = "http://myserver", WorkFolder = "_work" }; _config = new Mock(); _config.Setup(x => x.LoadSettings()).Returns(_settings); - _agentServer = new Mock(); + _runnerServer = new Mock(); _credMgr = new Mock(); } @@ -34,14 +34,14 @@ namespace GitHub.Runner.Common.Tests.Listener { TestHostContext tc = new TestHostContext(this, testName); tc.SetSingleton(_config.Object); - tc.SetSingleton(_agentServer.Object); + tc.SetSingleton(_runnerServer.Object); tc.SetSingleton(_credMgr.Object); return tc; } [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void CreatesSession() { using (TestHostContext tc = CreateTestContext()) @@ -51,7 +51,7 @@ namespace GitHub.Runner.Common.Tests.Listener // Arrange. var expectedSession = new TaskAgentSession(); - _agentServer + _runnerServer .Setup(x => x.CreateAgentSessionAsync( _settings.PoolId, It.Is(y => y != null), @@ -69,7 +69,7 @@ namespace GitHub.Runner.Common.Tests.Listener // Assert. Assert.True(result); - _agentServer + _runnerServer .Verify(x => x.CreateAgentSessionAsync( _settings.PoolId, It.Is(y => y != null), @@ -79,7 +79,7 @@ namespace GitHub.Runner.Common.Tests.Listener [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void DeleteSession() { using (TestHostContext tc = CreateTestContext()) @@ -93,7 +93,7 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(sessionIdProperty); sessionIdProperty.SetValue(expectedSession, Guid.NewGuid()); - _agentServer + _runnerServer .Setup(x => x.CreateAgentSessionAsync( _settings.PoolId, It.Is(y => y != null), @@ -109,14 +109,14 @@ namespace GitHub.Runner.Common.Tests.Listener bool result = await listener.CreateSessionAsync(tokenSource.Token); Assert.True(result); - _agentServer + _runnerServer .Setup(x => x.DeleteAgentSessionAsync( _settings.PoolId, expectedSession.SessionId, It.IsAny())) .Returns(Task.CompletedTask); await listener.DeleteSessionAsync(); //Assert - _agentServer + _runnerServer .Verify(x => x.DeleteAgentSessionAsync( _settings.PoolId, expectedSession.SessionId, It.IsAny()), Times.Once()); } @@ -124,7 +124,7 @@ namespace GitHub.Runner.Common.Tests.Listener [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] + [Trait("Category", "Runner")] public async void GetNextMessage() { using (TestHostContext tc = CreateTestContext()) @@ -138,7 +138,7 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.NotNull(sessionIdProperty); sessionIdProperty.SetValue(expectedSession, Guid.NewGuid()); - _agentServer + _runnerServer .Setup(x => x.CreateAgentSessionAsync( _settings.PoolId, It.Is(y => y != null), @@ -179,7 +179,7 @@ namespace GitHub.Runner.Common.Tests.Listener }; var messages = new Queue(arMessages); - _agentServer + _runnerServer .Setup(x => x.GetAgentMessageAsync( _settings.PoolId, expectedSession.SessionId, It.IsAny(), tokenSource.Token)) .Returns(async (Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken) => @@ -195,7 +195,7 @@ namespace GitHub.Runner.Common.Tests.Listener Assert.Equal(arMessages[4], message3); //Assert - _agentServer + _runnerServer .Verify(x => x.GetAgentMessageAsync( _settings.PoolId, expectedSession.SessionId, It.IsAny(), tokenSource.Token), Times.Exactly(arMessages.Length)); } diff --git a/src/Test/L0/Listener/RunnerL0.cs b/src/Test/L0/Listener/RunnerL0.cs new file mode 100644 index 000000000..0003ba5cd --- /dev/null +++ b/src/Test/L0/Listener/RunnerL0.cs @@ -0,0 +1,509 @@ +using GitHub.DistributedTask.WebApi; +using GitHub.Runner.Listener; +using GitHub.Runner.Listener.Configuration; +using Moq; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit; +using GitHub.Services.WebApi; +using Pipelines = GitHub.DistributedTask.Pipelines; +using GitHub.Runner.Common.Util; + +namespace GitHub.Runner.Common.Tests.Listener +{ + public sealed class RunnerL0 + { + private Mock _configurationManager; + private Mock _jobNotification; + private Mock _messageListener; + private Mock _promptManager; + private Mock _jobDispatcher; + private Mock _runnerServer; + private Mock _term; + private Mock _configStore; + private Mock _cert; + private Mock _updater; + + public RunnerL0() + { + _configurationManager = new Mock(); + _jobNotification = new Mock(); + _messageListener = new Mock(); + _promptManager = new Mock(); + _jobDispatcher = new Mock(); + _runnerServer = new Mock(); + _term = new Mock(); + _configStore = new Mock(); + _cert = new Mock(); + _updater = new Mock(); + } + + private AgentJobRequestMessage CreateJobRequestMessage(string jobName) + { + TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference(); + TimelineReference timeline = null; + JobEnvironment environment = new JobEnvironment(); + List tasks = new List(); + Guid JobId = Guid.NewGuid(); + var jobRequest = new AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, environment, tasks); + return jobRequest as AgentJobRequestMessage; + } + + private JobCancelMessage CreateJobCancelMessage() + { + var message = new JobCancelMessage(Guid.NewGuid(), TimeSpan.FromSeconds(0)); + return message; + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Runner")] + //process 2 new job messages, and one cancel message + public async void TestRunAsync() + { + using (var hc = new TestHostContext(this)) + { + //Arrange + var runner = new Runner.Listener.Runner(); + hc.SetSingleton(_configurationManager.Object); + hc.SetSingleton(_jobNotification.Object); + hc.SetSingleton(_messageListener.Object); + hc.SetSingleton(_promptManager.Object); + hc.SetSingleton(_runnerServer.Object); + hc.SetSingleton(_cert.Object); + hc.SetSingleton(_configStore.Object); + runner.Initialize(hc); + var settings = new RunnerSettings + { + PoolId = 43242 + }; + + var message = new TaskAgentMessage() + { + Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), + MessageId = 4234, + MessageType = JobRequestMessageTypes.PipelineAgentJobRequest + }; + + var messages = new Queue(); + messages.Enqueue(message); + var signalWorkerComplete = new SemaphoreSlim(0, 1); + _configurationManager.Setup(x => x.LoadSettings()) + .Returns(settings); + _configurationManager.Setup(x => x.IsConfigured()) + .Returns(true); + _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) + .Returns(Task.FromResult(true)); + _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) + .Returns(async () => + { + if (0 == messages.Count) + { + signalWorkerComplete.Release(); + await Task.Delay(2000, hc.RunnerShutdownToken); + } + + return messages.Dequeue(); + }); + _messageListener.Setup(x => x.DeleteSessionAsync()) + .Returns(Task.CompletedTask); + _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) + .Returns(Task.CompletedTask); + _jobDispatcher.Setup(x => x.Run(It.IsAny(), It.IsAny())) + .Callback(() => + { + + }); + _jobNotification.Setup(x => x.StartClient(It.IsAny())) + .Callback(() => + { + + }); + + hc.EnqueueInstance(_jobDispatcher.Object); + + _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); + //Act + var command = new CommandSettings(hc, new string[] { "run" }); + Task runnerTask = runner.ExecuteCommand(command); + + //Assert + //wait for the runner to run one job + if (!await signalWorkerComplete.WaitAsync(2000)) + { + Assert.True(false, $"{nameof(_messageListener.Object.GetNextMessageAsync)} was not invoked."); + } + else + { + //Act + hc.ShutdownRunner(ShutdownReason.UserCancelled); //stop Runner + + //Assert + Task[] taskToWait2 = { runnerTask, Task.Delay(2000) }; + //wait for the runner to exit + await Task.WhenAny(taskToWait2); + + Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out."); + Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString()); + Assert.True(runnerTask.IsCanceled); + + _jobDispatcher.Verify(x => x.Run(It.IsAny(), It.IsAny()), Times.Once(), + $"{nameof(_jobDispatcher.Object.Run)} was not invoked."); + _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); + _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); + _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); + _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.AtLeastOnce()); + } + } + } + + public static TheoryData RunAsServiceTestData = new TheoryData() + { + // staring with run command, configured as run as service, should start the runner + { new [] { "run" }, true, Times.Once() }, + // starting with no argument, configured not to run as service, should start runner interactively + { new [] { "run" }, false, Times.Once() } + }; + [Theory] + [MemberData(nameof(RunAsServiceTestData))] + [Trait("Level", "L0")] + [Trait("Category", "Runner")] + public async void TestExecuteCommandForRunAsService(string[] args, bool configureAsService, Times expectedTimes) + { + using (var hc = new TestHostContext(this)) + { + hc.SetSingleton(_configurationManager.Object); + hc.SetSingleton(_promptManager.Object); + hc.SetSingleton(_messageListener.Object); + hc.SetSingleton(_cert.Object); + hc.SetSingleton(_configStore.Object); + + var command = new CommandSettings(hc, args); + + _configurationManager.Setup(x => x.IsConfigured()).Returns(true); + _configurationManager.Setup(x => x.LoadSettings()) + .Returns(new RunnerSettings { }); + + _configStore.Setup(x => x.IsServiceConfigured()).Returns(configureAsService); + + _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) + .Returns(Task.FromResult(false)); + + var runner = new Runner.Listener.Runner(); + runner.Initialize(hc); + await runner.ExecuteCommand(command); + + _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), expectedTimes); + } + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Runner")] + public async void TestMachineProvisionerCLI() + { + using (var hc = new TestHostContext(this)) + { + hc.SetSingleton(_configurationManager.Object); + hc.SetSingleton(_promptManager.Object); + hc.SetSingleton(_messageListener.Object); + hc.SetSingleton(_cert.Object); + hc.SetSingleton(_configStore.Object); + + var command = new CommandSettings(hc, new[] { "run" }); + + _configurationManager.Setup(x => x.IsConfigured()). + Returns(true); + _configurationManager.Setup(x => x.LoadSettings()) + .Returns(new RunnerSettings { }); + + _configStore.Setup(x => x.IsServiceConfigured()) + .Returns(false); + + _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) + .Returns(Task.FromResult(false)); + + var runner = new Runner.Listener.Runner(); + runner.Initialize(hc); + await runner.ExecuteCommand(command); + + _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); + } + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Runner")] + public async void TestRunOnce() + { + using (var hc = new TestHostContext(this)) + { + //Arrange + var runner = new Runner.Listener.Runner(); + hc.SetSingleton(_configurationManager.Object); + hc.SetSingleton(_jobNotification.Object); + hc.SetSingleton(_messageListener.Object); + hc.SetSingleton(_promptManager.Object); + hc.SetSingleton(_runnerServer.Object); + hc.SetSingleton(_cert.Object); + hc.SetSingleton(_configStore.Object); + runner.Initialize(hc); + var settings = new RunnerSettings + { + PoolId = 43242 + }; + + var message = new TaskAgentMessage() + { + Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), + MessageId = 4234, + MessageType = JobRequestMessageTypes.PipelineAgentJobRequest + }; + + var messages = new Queue(); + messages.Enqueue(message); + _configurationManager.Setup(x => x.LoadSettings()) + .Returns(settings); + _configurationManager.Setup(x => x.IsConfigured()) + .Returns(true); + _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) + .Returns(Task.FromResult(true)); + _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) + .Returns(async () => + { + if (0 == messages.Count) + { + await Task.Delay(2000); + } + + return messages.Dequeue(); + }); + _messageListener.Setup(x => x.DeleteSessionAsync()) + .Returns(Task.CompletedTask); + _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) + .Returns(Task.CompletedTask); + + var runOnceJobCompleted = new TaskCompletionSource(); + _jobDispatcher.Setup(x => x.RunOnceJobCompleted) + .Returns(runOnceJobCompleted); + _jobDispatcher.Setup(x => x.Run(It.IsAny(), It.IsAny())) + .Callback(() => + { + runOnceJobCompleted.TrySetResult(true); + }); + _jobNotification.Setup(x => x.StartClient(It.IsAny())) + .Callback(() => + { + + }); + + hc.EnqueueInstance(_jobDispatcher.Object); + + _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); + //Act + var command = new CommandSettings(hc, new string[] { "run", "--once" }); + Task runnerTask = runner.ExecuteCommand(command); + + //Assert + //wait for the runner to run one job and exit + await Task.WhenAny(runnerTask, Task.Delay(30000)); + + Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out."); + Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString()); + Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.Success); + + _jobDispatcher.Verify(x => x.Run(It.IsAny(), true), Times.Once(), + $"{nameof(_jobDispatcher.Object.Run)} was not invoked."); + _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); + _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); + _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); + _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.AtLeastOnce()); + } + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Runner")] + public async void TestRunOnceOnlyTakeOneJobMessage() + { + using (var hc = new TestHostContext(this)) + { + //Arrange + var runner = new Runner.Listener.Runner(); + hc.SetSingleton(_configurationManager.Object); + hc.SetSingleton(_jobNotification.Object); + hc.SetSingleton(_messageListener.Object); + hc.SetSingleton(_promptManager.Object); + hc.SetSingleton(_runnerServer.Object); + hc.SetSingleton(_cert.Object); + hc.SetSingleton(_configStore.Object); + runner.Initialize(hc); + var settings = new RunnerSettings + { + PoolId = 43242 + }; + + var message1 = new TaskAgentMessage() + { + Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), + MessageId = 4234, + MessageType = JobRequestMessageTypes.PipelineAgentJobRequest + }; + var message2 = new TaskAgentMessage() + { + Body = JsonUtility.ToString(CreateJobRequestMessage("job1")), + MessageId = 4235, + MessageType = JobRequestMessageTypes.PipelineAgentJobRequest + }; + + var messages = new Queue(); + messages.Enqueue(message1); + messages.Enqueue(message2); + _configurationManager.Setup(x => x.LoadSettings()) + .Returns(settings); + _configurationManager.Setup(x => x.IsConfigured()) + .Returns(true); + _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) + .Returns(Task.FromResult(true)); + _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) + .Returns(async () => + { + if (0 == messages.Count) + { + await Task.Delay(2000); + } + + return messages.Dequeue(); + }); + _messageListener.Setup(x => x.DeleteSessionAsync()) + .Returns(Task.CompletedTask); + _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) + .Returns(Task.CompletedTask); + + var runOnceJobCompleted = new TaskCompletionSource(); + _jobDispatcher.Setup(x => x.RunOnceJobCompleted) + .Returns(runOnceJobCompleted); + _jobDispatcher.Setup(x => x.Run(It.IsAny(), It.IsAny())) + .Callback(() => + { + runOnceJobCompleted.TrySetResult(true); + }); + _jobNotification.Setup(x => x.StartClient(It.IsAny())) + .Callback(() => + { + + }); + + hc.EnqueueInstance(_jobDispatcher.Object); + + _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); + //Act + var command = new CommandSettings(hc, new string[] { "run", "--once" }); + Task runnerTask = runner.ExecuteCommand(command); + + //Assert + //wait for the runner to run one job and exit + await Task.WhenAny(runnerTask, Task.Delay(30000)); + + Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out."); + Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString()); + Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.Success); + + _jobDispatcher.Verify(x => x.Run(It.IsAny(), true), Times.Once(), + $"{nameof(_jobDispatcher.Object.Run)} was not invoked."); + _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); + _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); + _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); + _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.Once()); + } + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Runner")] + public async void TestRunOnceHandleUpdateMessage() + { + using (var hc = new TestHostContext(this)) + { + //Arrange + var runner = new Runner.Listener.Runner(); + hc.SetSingleton(_configurationManager.Object); + hc.SetSingleton(_jobNotification.Object); + hc.SetSingleton(_messageListener.Object); + hc.SetSingleton(_promptManager.Object); + hc.SetSingleton(_runnerServer.Object); + hc.SetSingleton(_cert.Object); + hc.SetSingleton(_configStore.Object); + hc.SetSingleton(_updater.Object); + + runner.Initialize(hc); + var settings = new RunnerSettings + { + PoolId = 43242, + AgentId = 5678 + }; + + var message1 = new TaskAgentMessage() + { + Body = JsonUtility.ToString(new AgentRefreshMessage(settings.AgentId, "2.123.0")), + MessageId = 4234, + MessageType = AgentRefreshMessage.MessageType + }; + + var messages = new Queue(); + messages.Enqueue(message1); + _updater.Setup(x => x.SelfUpdate(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(true)); + _configurationManager.Setup(x => x.LoadSettings()) + .Returns(settings); + _configurationManager.Setup(x => x.IsConfigured()) + .Returns(true); + _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny())) + .Returns(Task.FromResult(true)); + _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny())) + .Returns(async () => + { + if (0 == messages.Count) + { + await Task.Delay(2000); + } + + return messages.Dequeue(); + }); + _messageListener.Setup(x => x.DeleteSessionAsync()) + .Returns(Task.CompletedTask); + _messageListener.Setup(x => x.DeleteMessageAsync(It.IsAny())) + .Returns(Task.CompletedTask); + _jobNotification.Setup(x => x.StartClient(It.IsAny())) + .Callback(() => + { + + }); + + hc.EnqueueInstance(_jobDispatcher.Object); + + _configStore.Setup(x => x.IsServiceConfigured()).Returns(false); + //Act + var command = new CommandSettings(hc, new string[] { "run", "--once" }); + Task runnerTask = runner.ExecuteCommand(command); + + //Assert + //wait for the runner to exit with right return code + await Task.WhenAny(runnerTask, Task.Delay(30000)); + + Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out."); + Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString()); + Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.RunOnceRunnerUpdating); + + _updater.Verify(x => x.SelfUpdate(It.IsAny(), It.IsAny(), false, It.IsAny()), Times.Once); + _jobDispatcher.Verify(x => x.Run(It.IsAny(), true), Times.Never()); + _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny()), Times.AtLeastOnce()); + _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny()), Times.Once()); + _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once()); + _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny()), Times.Once()); + } + } + } +} diff --git a/src/Test/L0/ServiceInterfacesL0.cs b/src/Test/L0/ServiceInterfacesL0.cs index 106a9a32b..63c01b17d 100644 --- a/src/Test/L0/ServiceInterfacesL0.cs +++ b/src/Test/L0/ServiceInterfacesL0.cs @@ -14,8 +14,8 @@ namespace GitHub.Runner.Common.Tests { [Fact] [Trait("Level", "L0")] - [Trait("Category", "Agent")] - public void AgentInterfacesSpecifyDefaultImplementation() + [Trait("Category", "Runner")] + public void RunnerInterfacesSpecifyDefaultImplementation() { // Validate all interfaces in the Listener assembly define a valid service locator attribute. // Otherwise, the interface needs to whitelisted. diff --git a/src/Test/L0/TestHostContext.cs b/src/Test/L0/TestHostContext.cs index 0a7657cc6..6f2b6aed1 100644 --- a/src/Test/L0/TestHostContext.cs +++ b/src/Test/L0/TestHostContext.cs @@ -22,7 +22,7 @@ namespace GitHub.Runner.Common.Tests private readonly ITraceManager _traceManager; private readonly Terminal _term; private readonly SecretMasker _secretMasker; - private CancellationTokenSource _agentShutdownTokenSource = new CancellationTokenSource(); + private CancellationTokenSource _runnerShutdownTokenSource = new CancellationTokenSource(); private string _suiteName; private string _testName; private Tracing _trace; @@ -30,7 +30,7 @@ namespace GitHub.Runner.Common.Tests private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D")); private StartupType _startupType; public event EventHandler Unloading; - public CancellationToken RunnerShutdownToken => _agentShutdownTokenSource.Token; + public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token; public ShutdownReason RunnerShutdownReason { get; private set; } public ISecretMasker SecretMasker => _secretMasker; public TestHostContext(object testClass, [CallerMemberName] string testName = "") @@ -306,7 +306,7 @@ namespace GitHub.Runner.Common.Tests { ArgUtil.NotNull(reason, nameof(reason)); RunnerShutdownReason = reason; - _agentShutdownTokenSource.Cancel(); + _runnerShutdownTokenSource.Cancel(); } public void WritePerfCounter(string counter) diff --git a/src/Test/L0/Worker/WorkerL0.cs b/src/Test/L0/Worker/WorkerL0.cs index 0bebcec4c..b84abb870 100644 --- a/src/Test/L0/Worker/WorkerL0.cs +++ b/src/Test/L0/Worker/WorkerL0.cs @@ -183,62 +183,6 @@ namespace GitHub.Runner.Common.Tests.Worker } } - [Fact] - [Trait("Level", "L0")] - [Trait("Category", "Worker")] - public void VerifyJobRequestMessagePiiDataIsScrubbed() - { - // Arrange - Pipelines.AgentJobRequestMessage message = CreateJobRequestMessage("jobwithpiidata"); - - // Populate PII variables - foreach (string piiVariable in Variables.PiiVariables) - { - message.Variables.Add(piiVariable, "MyPiiVariable"); - } - - foreach (string piiVariableSuffix in Variables.PiiArtifactVariableSuffixes) - { - message.Variables.Add($"{Variables.PiiArtifactVariablePrefix}.MyArtifact.{piiVariableSuffix}", "MyPiiVariable"); - } - - // Populate the repository PII data - Pipelines.RepositoryResource repository = new Pipelines.RepositoryResource(); - - repository.Properties.Set( - Pipelines.RepositoryPropertyNames.VersionInfo, - new Pipelines.VersionInfo() - { - Author = "MyAuthor", - Message = "MyMessage" - }); - - message.Resources.Repositories.Add(repository); - - // Act - Pipelines.AgentJobRequestMessage scrubbedMessage = WorkerUtilities.ScrubPiiData(message); - - // Assert - foreach (string piiVariable in Variables.PiiVariables) - { - scrubbedMessage.Variables.TryGetValue(piiVariable, out VariableValue value); - - Assert.Equal("[PII]", value.Value); - } - - foreach (string piiVariableSuffix in Variables.PiiArtifactVariableSuffixes) - { - scrubbedMessage.Variables.TryGetValue($"{Variables.PiiArtifactVariablePrefix}.MyArtifact.{piiVariableSuffix}", out VariableValue value); - - Assert.Equal("[PII]", value.Value); - } - - Pipelines.RepositoryResource scrubbedRepo = scrubbedMessage.Resources.Repositories[0]; - Pipelines.VersionInfo scrubbedInfo = scrubbedRepo.Properties.Get(Pipelines.RepositoryPropertyNames.VersionInfo); - - Assert.Equal("[PII]", scrubbedInfo.Author); - } - private bool IsMessageIdentical(Pipelines.AgentJobRequestMessage source, Pipelines.AgentJobRequestMessage target) { if (source == null && target == null)