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
This commit is contained in:
Julio Barba
2019-12-09 17:54:41 -05:00
committed by GitHub
parent 3ed80b7c10
commit 275ab753a1
16 changed files with 583 additions and 859 deletions

View File

@@ -208,14 +208,6 @@ namespace GitHub.Runner.Common
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG"; 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 public static class System
{ {
// //

View File

@@ -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<IUnixUtil>();
// 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}"); Trace.Info($"Set runner startup type - {startType}");
HostContext.StartupType = startType; HostContext.StartupType = startType;

View File

@@ -75,36 +75,6 @@ namespace GitHub.Runner.Worker
public string System_PhaseDisplayName => Get(Constants.Variables.System.PhaseDisplayName); public string System_PhaseDisplayName => Get(Constants.Variables.System.PhaseDisplayName);
public string System_TFCollectionUrl => Get(WellKnownDistributedTaskVariables.TFCollectionUrl);
public static readonly HashSet<string> PiiVariables = new HashSet<string>(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<string> PiiArtifactVariableSuffixes = new List<string>()
{
"SourceBranch",
"SourceBranchName",
"SourceVersion",
"RequestedFor"
};
public string Get(string name) public string Get(string name)
{ {
Variable variable; Variable variable;

View File

@@ -73,7 +73,7 @@ namespace GitHub.Runner.Worker
SetCulture(jobMessage); SetCulture(jobMessage);
// Start the job. // Start the job.
Trace.Info($"Job message:{Environment.NewLine} {StringUtil.ConvertToJson(WorkerUtilities.ScrubPiiData(jobMessage))}"); Trace.Info($"Job message:{Environment.NewLine} {StringUtil.ConvertToJson(jobMessage)}");
Task<TaskResult> jobRunnerTask = jobRunner.RunAsync(jobMessage, jobRequestCancellationToken.Token); Task<TaskResult> jobRunnerTask = jobRunner.RunAsync(jobMessage, jobRequestCancellationToken.Token);
// Start listening for a cancel message from the channel. // Start listening for a cancel message from the channel.

View File

@@ -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<string, VariableValue>();
// 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<Pipelines.RepositoryResource>();
// Scrub the repository resources
foreach (var repository in message.Resources.Repositories)
{
Pipelines.RepositoryResource scrubbedRepository = repository.Clone();
var versionInfo = repository.Properties.Get<Pipelines.VersionInfo>(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);
}
}
}

View File

@@ -9,7 +9,7 @@ namespace GitHub.Runner.Common.Tests
{ {
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public void BuildConstantGenerateSucceed() public void BuildConstantGenerateSucceed()
{ {
List<string> validPackageNames = new List<string>() List<string> validPackageNames = new List<string>()

View File

@@ -9,7 +9,7 @@ namespace GitHub.Runner.Common.Tests
{ {
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async Task EnsureDotnetsdkBashDownloadScriptUpToDate() public async Task EnsureDotnetsdkBashDownloadScriptUpToDate()
{ {
string shDownloadUrl = "https://dot.net/v1/dotnet-install.sh"; string shDownloadUrl = "https://dot.net/v1/dotnet-install.sh";
@@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async Task EnsureDotnetsdkPowershellDownloadScriptUpToDate() public async Task EnsureDotnetsdkPowershellDownloadScriptUpToDate()
{ {
string ps1DownloadUrl = "https://dot.net/v1/dotnet-install.ps1"; string ps1DownloadUrl = "https://dot.net/v1/dotnet-install.ps1";

View File

@@ -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<IConfigurationManager> _configurationManager;
// private Mock<IJobNotification> _jobNotification;
// private Mock<IMessageListener> _messageListener;
// private Mock<IPromptManager> _promptManager;
// private Mock<IJobDispatcher> _jobDispatcher;
// private Mock<IRunnerServer> _agentServer;
// private Mock<ITerminal> _term;
// private Mock<IConfigurationStore> _configStore;
// private Mock<IRunnerWebProxy> _proxy;
// private Mock<IRunnerCertificateManager> _cert;
// private Mock<ISelfUpdater> _updater;
// public AgentL0()
// {
// _configurationManager = new Mock<IConfigurationManager>();
// _jobNotification = new Mock<IJobNotification>();
// _messageListener = new Mock<IMessageListener>();
// _promptManager = new Mock<IPromptManager>();
// _jobDispatcher = new Mock<IJobDispatcher>();
// _agentServer = new Mock<IRunnerServer>();
// _term = new Mock<ITerminal>();
// _configStore = new Mock<IConfigurationStore>();
// _proxy = new Mock<IRunnerWebProxy>();
// _cert = new Mock<IRunnerCertificateManager>();
// _updater = new Mock<ISelfUpdater>();
// }
// private AgentJobRequestMessage CreateJobRequestMessage(string jobName)
// {
// TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
// TimelineReference timeline = null;
// JobEnvironment environment = new JobEnvironment();
// List<TaskInstance> tasks = new List<TaskInstance>();
// 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<IConfigurationManager>(_configurationManager.Object);
// hc.SetSingleton<IJobNotification>(_jobNotification.Object);
// hc.SetSingleton<IMessageListener>(_messageListener.Object);
// hc.SetSingleton<IPromptManager>(_promptManager.Object);
// hc.SetSingleton<IRunnerServer>(_agentServer.Object);
// hc.SetSingleton<IRunnerWebProxy>(_proxy.Object);
// hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
// hc.SetSingleton<IConfigurationStore>(_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<TaskAgentMessage>();
// 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<CancellationToken>()))
// .Returns(Task.FromResult<bool>(true));
// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
// .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<TaskAgentMessage>()))
// .Returns(Task.CompletedTask);
// _jobDispatcher.Setup(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()))
// .Callback(() =>
// {
// });
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
// .Callback(() =>
// {
// });
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>()))
// .Callback(() =>
// {
// });
// hc.EnqueueInstance<IJobDispatcher>(_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<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()), Times.Once(),
// $"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), Times.AtLeastOnce());
// }
// }
// }
// public static TheoryData<string[], bool, Times> RunAsServiceTestData = new TheoryData<string[], bool, Times>()
// {
// // 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<IConfigurationManager>(_configurationManager.Object);
// hc.SetSingleton<IPromptManager>(_promptManager.Object);
// hc.SetSingleton<IMessageListener>(_messageListener.Object);
// hc.SetSingleton<IRunnerWebProxy>(_proxy.Object);
// hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
// hc.SetSingleton<IConfigurationStore>(_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<CancellationToken>()))
// .Returns(Task.FromResult(false));
// var agent = new Runner.Listener.Runner();
// agent.Initialize(hc);
// await agent.ExecuteCommand(command);
// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), 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<IConfigurationManager>(_configurationManager.Object);
// hc.SetSingleton<IPromptManager>(_promptManager.Object);
// hc.SetSingleton<IMessageListener>(_messageListener.Object);
// hc.SetSingleton<IRunnerWebProxy>(_proxy.Object);
// hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
// hc.SetSingleton<IConfigurationStore>(_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<CancellationToken>()))
// .Returns(Task.FromResult(false));
// var agent = new Runner.Listener.Runner();
// agent.Initialize(hc);
// await agent.ExecuteCommand(command);
// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), 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<IConfigurationManager>(_configurationManager.Object);
// hc.SetSingleton<IPromptManager>(_promptManager.Object);
// hc.SetSingleton<IMessageListener>(_messageListener.Object);
// hc.SetSingleton<IRunnerWebProxy>(_proxy.Object);
// hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
// hc.SetSingleton<IConfigurationStore>(_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<CancellationToken>()))
// .Returns(Task.FromResult(false));
// var agent = new Runner.Listener.Runner();
// agent.Initialize(hc);
// await agent.ExecuteCommand(command);
// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), 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<IConfigurationManager>(_configurationManager.Object);
// hc.SetSingleton<IJobNotification>(_jobNotification.Object);
// hc.SetSingleton<IMessageListener>(_messageListener.Object);
// hc.SetSingleton<IPromptManager>(_promptManager.Object);
// hc.SetSingleton<IRunnerServer>(_agentServer.Object);
// hc.SetSingleton<IRunnerWebProxy>(_proxy.Object);
// hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
// hc.SetSingleton<IConfigurationStore>(_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<TaskAgentMessage>();
// messages.Enqueue(message);
// _configurationManager.Setup(x => x.LoadSettings())
// .Returns(settings);
// _configurationManager.Setup(x => x.IsConfigured())
// .Returns(true);
// _messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
// .Returns(Task.FromResult<bool>(true));
// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
// .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<TaskAgentMessage>()))
// .Returns(Task.CompletedTask);
// var runOnceJobCompleted = new TaskCompletionSource<bool>();
// _jobDispatcher.Setup(x => x.RunOnceJobCompleted)
// .Returns(runOnceJobCompleted);
// _jobDispatcher.Setup(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()))
// .Callback(() =>
// {
// runOnceJobCompleted.TrySetResult(true);
// });
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
// .Callback(() =>
// {
// });
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>()))
// .Callback(() =>
// {
// });
// hc.EnqueueInstance<IJobDispatcher>(_jobDispatcher.Object);
// _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
// //Act
// var command = new CommandSettings(hc, new string[] { "run", "--once" });
// Task<int> 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<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
// $"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), 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<IConfigurationManager>(_configurationManager.Object);
// hc.SetSingleton<IJobNotification>(_jobNotification.Object);
// hc.SetSingleton<IMessageListener>(_messageListener.Object);
// hc.SetSingleton<IPromptManager>(_promptManager.Object);
// hc.SetSingleton<IRunnerServer>(_agentServer.Object);
// hc.SetSingleton<IRunnerWebProxy>(_proxy.Object);
// hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
// hc.SetSingleton<IConfigurationStore>(_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<TaskAgentMessage>();
// 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<CancellationToken>()))
// .Returns(Task.FromResult<bool>(true));
// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
// .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<TaskAgentMessage>()))
// .Returns(Task.CompletedTask);
// var runOnceJobCompleted = new TaskCompletionSource<bool>();
// _jobDispatcher.Setup(x => x.RunOnceJobCompleted)
// .Returns(runOnceJobCompleted);
// _jobDispatcher.Setup(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()))
// .Callback(() =>
// {
// runOnceJobCompleted.TrySetResult(true);
// });
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
// .Callback(() =>
// {
// });
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>()))
// .Callback(() =>
// {
// });
// hc.EnqueueInstance<IJobDispatcher>(_jobDispatcher.Object);
// _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
// //Act
// var command = new CommandSettings(hc, new string[] { "run", "--once" });
// Task<int> 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<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
// $"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), 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<IConfigurationManager>(_configurationManager.Object);
// hc.SetSingleton<IJobNotification>(_jobNotification.Object);
// hc.SetSingleton<IMessageListener>(_messageListener.Object);
// hc.SetSingleton<IPromptManager>(_promptManager.Object);
// hc.SetSingleton<IRunnerServer>(_agentServer.Object);
// hc.SetSingleton<IRunnerWebProxy>(_proxy.Object);
// hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
// hc.SetSingleton<IConfigurationStore>(_configStore.Object);
// hc.SetSingleton<ISelfUpdater>(_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<TaskAgentMessage>();
// messages.Enqueue(message1);
// _updater.Setup(x => x.SelfUpdate(It.IsAny<AgentRefreshMessage>(), It.IsAny<IJobDispatcher>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
// .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<CancellationToken>()))
// .Returns(Task.FromResult<bool>(true));
// _messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
// .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<TaskAgentMessage>()))
// .Returns(Task.CompletedTask);
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>(), It.IsAny<CancellationToken>()))
// .Callback(() =>
// {
// });
// _jobNotification.Setup(x => x.StartClient(It.IsAny<String>(), It.IsAny<String>()))
// .Callback(() =>
// {
// });
// hc.EnqueueInstance<IJobDispatcher>(_jobDispatcher.Object);
// _configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
// //Act
// var command = new CommandSettings(hc, new string[] { "run", "--once" });
// Task<int> 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<AgentRefreshMessage>(), It.IsAny<IJobDispatcher>(), false, It.IsAny<CancellationToken>()), Times.Once);
// _jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Never());
// _messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
// _messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
// _messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
// _messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), Times.Once());
// }
// }
// }
// }

View File

@@ -20,7 +20,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
{ {
public class ConfigurationManagerL0 public class ConfigurationManagerL0
{ {
private Mock<IRunnerServer> _agentServer; private Mock<IRunnerServer> _runnerServer;
private Mock<ILocationServer> _locationServer; private Mock<ILocationServer> _locationServer;
private Mock<ICredentialManager> _credMgr; private Mock<ICredentialManager> _credMgr;
private Mock<IPromptManager> _promptManager; private Mock<IPromptManager> _promptManager;
@@ -50,7 +50,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
public ConfigurationManagerL0() public ConfigurationManagerL0()
{ {
_agentServer = new Mock<IRunnerServer>(); _runnerServer = new Mock<IRunnerServer>();
_locationServer = new Mock<ILocationServer>(); _locationServer = new Mock<ILocationServer>();
_credMgr = new Mock<ICredentialManager>(); _credMgr = new Mock<ICredentialManager>();
_promptManager = new Mock<IPromptManager>(); _promptManager = new Mock<IPromptManager>();
@@ -81,15 +81,9 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
DeploymentType = DeploymentFlags.Hosted, DeploymentType = DeploymentFlags.Hosted,
DeploymentId = Guid.NewGuid() DeploymentId = Guid.NewGuid()
}; };
_agentServer.Setup(x => x.ConnectAsync(It.IsAny<Uri>(), It.IsAny<VssCredentials>())).Returns(Task.FromResult<object>(null)); _runnerServer.Setup(x => x.ConnectAsync(It.IsAny<Uri>(), It.IsAny<VssCredentials>())).Returns(Task.FromResult<object>(null));
_locationServer.Setup(x => x.ConnectAsync(It.IsAny<VssConnection>())).Returns(Task.FromResult<object>(null)); _locationServer.Setup(x => x.ConnectAsync(It.IsAny<VssConnection>())).Returns(Task.FromResult<object>(null));
_locationServer.Setup(x => x.GetConnectionDataAsync()).Returns(Task.FromResult<ConnectionData>(connectionData)); _locationServer.Setup(x => x.GetConnectionDataAsync()).Returns(Task.FromResult<ConnectionData>(connectionData));
// _machineGroupServer.Setup(x => x.ConnectAsync(It.IsAny<VssConnection>())).Returns(Task.FromResult<object>(null));
// _machineGroupServer.Setup(x => x.UpdateDeploymentTargetsAsync(It.IsAny<Guid>(), It.IsAny<int>(), It.IsAny<List<DeploymentMachine>>()));
// _machineGroupServer.Setup(x => x.AddDeploymentTargetAsync(It.IsAny<Guid>(), It.IsAny<int>(), It.IsAny<DeploymentMachine>())).Returns(Task.FromResult(expectedDeploymentMachine));
// _machineGroupServer.Setup(x => x.ReplaceDeploymentTargetAsync(It.IsAny<Guid>(), It.IsAny<int>(), It.IsAny<int>(), It.IsAny<DeploymentMachine>())).Returns(Task.FromResult(expectedDeploymentMachine));
// _machineGroupServer.Setup(x => x.GetDeploymentTargetsAsync(It.IsAny<Guid>(), It.IsAny<int>(), It.IsAny<string>())).Returns(Task.FromResult(new List<DeploymentMachine>() { }));
// _machineGroupServer.Setup(x => x.DeleteDeploymentTargetAsync(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>())).Returns(Task.FromResult<object>(null));
_store.Setup(x => x.IsConfigured()).Returns(false); _store.Setup(x => x.IsConfigured()).Returns(false);
_store.Setup(x => x.HasCredentials()).Returns(false); _store.Setup(x => x.HasCredentials()).Returns(false);
@@ -101,20 +95,20 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
_configMgrAgentSettings = settings; _configMgrAgentSettings = settings;
}); });
_credMgr.Setup(x => x.GetCredentialProvider(It.IsAny<string>())).Returns(new TestAgentCredential()); _credMgr.Setup(x => x.GetCredentialProvider(It.IsAny<string>())).Returns(new TestRunnerCredential());
#if !OS_WINDOWS #if !OS_WINDOWS
_serviceControlManager.Setup(x => x.GenerateScripts(It.IsAny<RunnerSettings>())); _serviceControlManager.Setup(x => x.GenerateScripts(It.IsAny<RunnerSettings>()));
#endif #endif
var expectedPools = new List<TaskAgentPool>() { new TaskAgentPool(_expectedPoolName) { Id = _expectedPoolId } }; var expectedPools = new List<TaskAgentPool>() { new TaskAgentPool(_expectedPoolName) { Id = _expectedPoolId } };
_agentServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.IsAny<TaskAgentPoolType>())).Returns(Task.FromResult(expectedPools)); _runnerServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.IsAny<TaskAgentPoolType>())).Returns(Task.FromResult(expectedPools));
var expectedAgents = new List<TaskAgent>(); var expectedAgents = new List<TaskAgent>();
_agentServer.Setup(x => x.GetAgentsAsync(It.IsAny<int>(), It.IsAny<string>())).Returns(Task.FromResult(expectedAgents)); _runnerServer.Setup(x => x.GetAgentsAsync(It.IsAny<int>(), It.IsAny<string>())).Returns(Task.FromResult(expectedAgents));
_agentServer.Setup(x => x.AddAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent)); _runnerServer.Setup(x => x.AddAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent));
_agentServer.Setup(x => x.ReplaceAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent)); _runnerServer.Setup(x => x.ReplaceAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent));
rsa = new RSACryptoServiceProvider(2048); rsa = new RSACryptoServiceProvider(2048);
@@ -128,7 +122,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
tc.SetSingleton<IPromptManager>(_promptManager.Object); tc.SetSingleton<IPromptManager>(_promptManager.Object);
tc.SetSingleton<IConfigurationStore>(_store.Object); tc.SetSingleton<IConfigurationStore>(_store.Object);
tc.SetSingleton<IExtensionManager>(_extnMgr.Object); tc.SetSingleton<IExtensionManager>(_extnMgr.Object);
tc.SetSingleton<IRunnerServer>(_agentServer.Object); tc.SetSingleton<IRunnerServer>(_runnerServer.Object);
tc.SetSingleton<ILocationServer>(_locationServer.Object); tc.SetSingleton<ILocationServer>(_locationServer.Object);
tc.SetSingleton<IRunnerCertificateManager>(_cert.Object); tc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
@@ -190,9 +184,9 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
Assert.True(s.WorkFolder.Equals(_expectedWorkFolder)); Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
// validate GetAgentPoolsAsync gets called once with automation pool type // validate GetAgentPoolsAsync gets called once with automation pool type
_agentServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Once); _runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Once);
_agentServer.Verify(x => x.AddAgentAsync(It.IsAny<int>(), It.Is<TaskAgent>(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<int>(), It.Is<TaskAgent>(a => a.Labels.Contains("self-hosted") && a.Labels.Contains(VarUtil.OS) && a.Labels.Contains(VarUtil.OSArchitecture))), Times.Once);
} }
} }
} }

View File

@@ -5,9 +5,9 @@ using GitHub.Services.Common;
namespace GitHub.Runner.Common.Tests.Listener.Configuration 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) public override VssCredentials GetVssCredentials(IHostContext context)
{ {
Tracing trace = context.GetTrace("PersonalAccessToken"); Tracing trace = context.GetTrace("PersonalAccessToken");

View File

@@ -17,14 +17,14 @@ namespace GitHub.Runner.Common.Tests.Listener
{ {
private Mock<IProcessChannel> _processChannel; private Mock<IProcessChannel> _processChannel;
private Mock<IProcessInvoker> _processInvoker; private Mock<IProcessInvoker> _processInvoker;
private Mock<IRunnerServer> _agentServer; private Mock<IRunnerServer> _runnerServer;
private Mock<IConfigurationStore> _configurationStore; private Mock<IConfigurationStore> _configurationStore;
public JobDispatcherL0() public JobDispatcherL0()
{ {
_processChannel = new Mock<IProcessChannel>(); _processChannel = new Mock<IProcessChannel>();
_processInvoker = new Mock<IProcessInvoker>(); _processInvoker = new Mock<IProcessInvoker>();
_agentServer = new Mock<IRunnerServer>(); _runnerServer = new Mock<IRunnerServer>();
_configurationStore = new Mock<IConfigurationStore>(); _configurationStore = new Mock<IConfigurationStore>();
} }
@@ -43,7 +43,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatchesJobRequest() public async void DispatchesJobRequest()
{ {
//Arrange //Arrange
@@ -51,7 +51,7 @@ namespace GitHub.Runner.Common.Tests.Listener
{ {
var jobDispatcher = new JobDispatcher(); var jobDispatcher = new JobDispatcher();
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.EnqueueInstance<IProcessChannel>(_processChannel.Object); hc.EnqueueInstance<IProcessChannel>(_processChannel.Object);
hc.EnqueueInstance<IProcessInvoker>(_processInvoker.Object); hc.EnqueueInstance<IProcessInvoker>(_processInvoker.Object);
@@ -76,9 +76,9 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(sessionIdProperty); Assert.NotNull(sessionIdProperty);
sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request)); _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request));
_agentServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest())); _runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest()));
//Actt //Actt
@@ -93,7 +93,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatcherRenewJobRequest() public async void DispatcherRenewJobRequest()
{ {
//Arrange //Arrange
@@ -112,10 +112,10 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(lockUntilProperty); Assert.NotNull(lockUntilProperty);
lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())) _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.Returns(() => .Returns(() =>
{ {
count++; count++;
@@ -145,13 +145,13 @@ namespace GitHub.Runner.Common.Tests.Listener
await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token); await jobDispatcher.RenewJobRequestAsync(poolId, requestId, Guid.Empty, firstJobRequestRenewed, cancellationTokenSource.Token);
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully); Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully);
_agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5)); _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
} }
} }
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatcherRenewJobRequestStopOnJobNotFoundExceptions() public async void DispatcherRenewJobRequestStopOnJobNotFoundExceptions()
{ {
//Arrange //Arrange
@@ -170,10 +170,10 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(lockUntilProperty); Assert.NotNull(lockUntilProperty);
lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())) _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.Returns(() => .Returns(() =>
{ {
count++; count++;
@@ -204,13 +204,13 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
Assert.False(cancellationTokenSource.IsCancellationRequested); Assert.False(cancellationTokenSource.IsCancellationRequested);
_agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5)); _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
} }
} }
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatcherRenewJobRequestStopOnJobTokenExpiredExceptions() public async void DispatcherRenewJobRequestStopOnJobTokenExpiredExceptions()
{ {
//Arrange //Arrange
@@ -229,10 +229,10 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(lockUntilProperty); Assert.NotNull(lockUntilProperty);
lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())) _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.Returns(() => .Returns(() =>
{ {
count++; count++;
@@ -263,13 +263,13 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
Assert.False(cancellationTokenSource.IsCancellationRequested); Assert.False(cancellationTokenSource.IsCancellationRequested);
_agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5)); _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
} }
} }
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatcherRenewJobRequestRecoverFromExceptions() public async void DispatcherRenewJobRequestRecoverFromExceptions()
{ {
//Arrange //Arrange
@@ -288,10 +288,10 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(lockUntilProperty); Assert.NotNull(lockUntilProperty);
lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())) _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.Returns(() => .Returns(() =>
{ {
count++; count++;
@@ -322,15 +322,15 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
Assert.True(cancellationTokenSource.IsCancellationRequested); Assert.True(cancellationTokenSource.IsCancellationRequested);
_agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(8)); _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(8));
_agentServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3)); _runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3));
_agentServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Once); _runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Once);
} }
} }
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatcherRenewJobRequestFirstRenewRetrySixTimes() public async void DispatcherRenewJobRequestFirstRenewRetrySixTimes()
{ {
//Arrange //Arrange
@@ -349,10 +349,10 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(lockUntilProperty); Assert.NotNull(lockUntilProperty);
lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())) _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.Returns(() => .Returns(() =>
{ {
count++; count++;
@@ -379,13 +379,13 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.False(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should failed."); Assert.False(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should failed.");
Assert.False(cancellationTokenSource.IsCancellationRequested); Assert.False(cancellationTokenSource.IsCancellationRequested);
_agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(6)); _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(6));
} }
} }
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatcherRenewJobRequestStopOnExpiredRequest() public async void DispatcherRenewJobRequestStopOnExpiredRequest()
{ {
//Arrange //Arrange
@@ -404,10 +404,10 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(lockUntilProperty); Assert.NotNull(lockUntilProperty);
lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); lockUntilProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
_configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 }); _configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings() { PoolId = 1 });
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())) _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
.Returns(() => .Returns(() =>
{ {
count++; count++;
@@ -443,15 +443,15 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed."); Assert.True(firstJobRequestRenewed.Task.IsCompletedSuccessfully, "First renew should succeed.");
Assert.False(cancellationTokenSource.IsCancellationRequested); Assert.False(cancellationTokenSource.IsCancellationRequested);
_agentServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5)); _runnerServer.Verify(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()), Times.Exactly(5));
_agentServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3)); _runnerServer.Verify(x => x.RefreshConnectionAsync(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Exactly(3));
_agentServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Never); _runnerServer.Verify(x => x.SetConnectionTimeout(RunnerConnectionType.JobRequest, It.IsAny<TimeSpan>()), Times.Never);
} }
} }
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DispatchesOneTimeJobRequest() public async void DispatchesOneTimeJobRequest()
{ {
//Arrange //Arrange
@@ -459,7 +459,7 @@ namespace GitHub.Runner.Common.Tests.Listener
{ {
var jobDispatcher = new JobDispatcher(); var jobDispatcher = new JobDispatcher();
hc.SetSingleton<IConfigurationStore>(_configurationStore.Object); hc.SetSingleton<IConfigurationStore>(_configurationStore.Object);
hc.SetSingleton<IRunnerServer>(_agentServer.Object); hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.EnqueueInstance<IProcessChannel>(_processChannel.Object); hc.EnqueueInstance<IProcessChannel>(_processChannel.Object);
hc.EnqueueInstance<IProcessInvoker>(_processInvoker.Object); hc.EnqueueInstance<IProcessInvoker>(_processInvoker.Object);
@@ -484,9 +484,9 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(sessionIdProperty); Assert.NotNull(sessionIdProperty);
sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5)); sessionIdProperty.SetValue(request, DateTime.UtcNow.AddMinutes(5));
_agentServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request)); _runnerServer.Setup(x => x.RenewAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(request));
_agentServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest())); _runnerServer.Setup(x => x.FinishAgentRequestAsync(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<Guid>(), It.IsAny<DateTime>(), It.IsAny<TaskResult>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult<TaskAgentJobRequest>(new TaskAgentJobRequest()));
//Act //Act
jobDispatcher.Run(message, true); jobDispatcher.Run(message, true);

View File

@@ -18,7 +18,7 @@ namespace GitHub.Runner.Common.Tests.Listener
{ {
private RunnerSettings _settings; private RunnerSettings _settings;
private Mock<IConfigurationManager> _config; private Mock<IConfigurationManager> _config;
private Mock<IRunnerServer> _agentServer; private Mock<IRunnerServer> _runnerServer;
private Mock<ICredentialManager> _credMgr; private Mock<ICredentialManager> _credMgr;
public MessageListenerL0() 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" }; _settings = new RunnerSettings { AgentId = 1, AgentName = "myagent", PoolId = 123, PoolName = "default", ServerUrl = "http://myserver", WorkFolder = "_work" };
_config = new Mock<IConfigurationManager>(); _config = new Mock<IConfigurationManager>();
_config.Setup(x => x.LoadSettings()).Returns(_settings); _config.Setup(x => x.LoadSettings()).Returns(_settings);
_agentServer = new Mock<IRunnerServer>(); _runnerServer = new Mock<IRunnerServer>();
_credMgr = new Mock<ICredentialManager>(); _credMgr = new Mock<ICredentialManager>();
} }
@@ -34,14 +34,14 @@ namespace GitHub.Runner.Common.Tests.Listener
{ {
TestHostContext tc = new TestHostContext(this, testName); TestHostContext tc = new TestHostContext(this, testName);
tc.SetSingleton<IConfigurationManager>(_config.Object); tc.SetSingleton<IConfigurationManager>(_config.Object);
tc.SetSingleton<IRunnerServer>(_agentServer.Object); tc.SetSingleton<IRunnerServer>(_runnerServer.Object);
tc.SetSingleton<ICredentialManager>(_credMgr.Object); tc.SetSingleton<ICredentialManager>(_credMgr.Object);
return tc; return tc;
} }
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void CreatesSession() public async void CreatesSession()
{ {
using (TestHostContext tc = CreateTestContext()) using (TestHostContext tc = CreateTestContext())
@@ -51,7 +51,7 @@ namespace GitHub.Runner.Common.Tests.Listener
// Arrange. // Arrange.
var expectedSession = new TaskAgentSession(); var expectedSession = new TaskAgentSession();
_agentServer _runnerServer
.Setup(x => x.CreateAgentSessionAsync( .Setup(x => x.CreateAgentSessionAsync(
_settings.PoolId, _settings.PoolId,
It.Is<TaskAgentSession>(y => y != null), It.Is<TaskAgentSession>(y => y != null),
@@ -69,7 +69,7 @@ namespace GitHub.Runner.Common.Tests.Listener
// Assert. // Assert.
Assert.True(result); Assert.True(result);
_agentServer _runnerServer
.Verify(x => x.CreateAgentSessionAsync( .Verify(x => x.CreateAgentSessionAsync(
_settings.PoolId, _settings.PoolId,
It.Is<TaskAgentSession>(y => y != null), It.Is<TaskAgentSession>(y => y != null),
@@ -79,7 +79,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void DeleteSession() public async void DeleteSession()
{ {
using (TestHostContext tc = CreateTestContext()) using (TestHostContext tc = CreateTestContext())
@@ -93,7 +93,7 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(sessionIdProperty); Assert.NotNull(sessionIdProperty);
sessionIdProperty.SetValue(expectedSession, Guid.NewGuid()); sessionIdProperty.SetValue(expectedSession, Guid.NewGuid());
_agentServer _runnerServer
.Setup(x => x.CreateAgentSessionAsync( .Setup(x => x.CreateAgentSessionAsync(
_settings.PoolId, _settings.PoolId,
It.Is<TaskAgentSession>(y => y != null), It.Is<TaskAgentSession>(y => y != null),
@@ -109,14 +109,14 @@ namespace GitHub.Runner.Common.Tests.Listener
bool result = await listener.CreateSessionAsync(tokenSource.Token); bool result = await listener.CreateSessionAsync(tokenSource.Token);
Assert.True(result); Assert.True(result);
_agentServer _runnerServer
.Setup(x => x.DeleteAgentSessionAsync( .Setup(x => x.DeleteAgentSessionAsync(
_settings.PoolId, expectedSession.SessionId, It.IsAny<CancellationToken>())) _settings.PoolId, expectedSession.SessionId, It.IsAny<CancellationToken>()))
.Returns(Task.CompletedTask); .Returns(Task.CompletedTask);
await listener.DeleteSessionAsync(); await listener.DeleteSessionAsync();
//Assert //Assert
_agentServer _runnerServer
.Verify(x => x.DeleteAgentSessionAsync( .Verify(x => x.DeleteAgentSessionAsync(
_settings.PoolId, expectedSession.SessionId, It.IsAny<CancellationToken>()), Times.Once()); _settings.PoolId, expectedSession.SessionId, It.IsAny<CancellationToken>()), Times.Once());
} }
@@ -124,7 +124,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public async void GetNextMessage() public async void GetNextMessage()
{ {
using (TestHostContext tc = CreateTestContext()) using (TestHostContext tc = CreateTestContext())
@@ -138,7 +138,7 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.NotNull(sessionIdProperty); Assert.NotNull(sessionIdProperty);
sessionIdProperty.SetValue(expectedSession, Guid.NewGuid()); sessionIdProperty.SetValue(expectedSession, Guid.NewGuid());
_agentServer _runnerServer
.Setup(x => x.CreateAgentSessionAsync( .Setup(x => x.CreateAgentSessionAsync(
_settings.PoolId, _settings.PoolId,
It.Is<TaskAgentSession>(y => y != null), It.Is<TaskAgentSession>(y => y != null),
@@ -179,7 +179,7 @@ namespace GitHub.Runner.Common.Tests.Listener
}; };
var messages = new Queue<TaskAgentMessage>(arMessages); var messages = new Queue<TaskAgentMessage>(arMessages);
_agentServer _runnerServer
.Setup(x => x.GetAgentMessageAsync( .Setup(x => x.GetAgentMessageAsync(
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), tokenSource.Token)) _settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), tokenSource.Token))
.Returns(async (Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken) => .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.Equal(arMessages[4], message3);
//Assert //Assert
_agentServer _runnerServer
.Verify(x => x.GetAgentMessageAsync( .Verify(x => x.GetAgentMessageAsync(
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), tokenSource.Token), Times.Exactly(arMessages.Length)); _settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), tokenSource.Token), Times.Exactly(arMessages.Length));
} }

View File

@@ -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<IConfigurationManager> _configurationManager;
private Mock<IJobNotification> _jobNotification;
private Mock<IMessageListener> _messageListener;
private Mock<IPromptManager> _promptManager;
private Mock<IJobDispatcher> _jobDispatcher;
private Mock<IRunnerServer> _runnerServer;
private Mock<ITerminal> _term;
private Mock<IConfigurationStore> _configStore;
private Mock<IRunnerCertificateManager> _cert;
private Mock<ISelfUpdater> _updater;
public RunnerL0()
{
_configurationManager = new Mock<IConfigurationManager>();
_jobNotification = new Mock<IJobNotification>();
_messageListener = new Mock<IMessageListener>();
_promptManager = new Mock<IPromptManager>();
_jobDispatcher = new Mock<IJobDispatcher>();
_runnerServer = new Mock<IRunnerServer>();
_term = new Mock<ITerminal>();
_configStore = new Mock<IConfigurationStore>();
_cert = new Mock<IRunnerCertificateManager>();
_updater = new Mock<ISelfUpdater>();
}
private AgentJobRequestMessage CreateJobRequestMessage(string jobName)
{
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
TimelineReference timeline = null;
JobEnvironment environment = new JobEnvironment();
List<TaskInstance> tasks = new List<TaskInstance>();
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<IConfigurationManager>(_configurationManager.Object);
hc.SetSingleton<IJobNotification>(_jobNotification.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
hc.SetSingleton<IConfigurationStore>(_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<TaskAgentMessage>();
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<CancellationToken>()))
.Returns(Task.FromResult<bool>(true));
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
.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<TaskAgentMessage>()))
.Returns(Task.CompletedTask);
_jobDispatcher.Setup(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()))
.Callback(() =>
{
});
_jobNotification.Setup(x => x.StartClient(It.IsAny<String>()))
.Callback(() =>
{
});
hc.EnqueueInstance<IJobDispatcher>(_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<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()), Times.Once(),
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
_messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
_messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
_messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
_messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), Times.AtLeastOnce());
}
}
}
public static TheoryData<string[], bool, Times> RunAsServiceTestData = new TheoryData<string[], bool, Times>()
{
// 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<IConfigurationManager>(_configurationManager.Object);
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
hc.SetSingleton<IConfigurationStore>(_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<CancellationToken>()))
.Returns(Task.FromResult(false));
var runner = new Runner.Listener.Runner();
runner.Initialize(hc);
await runner.ExecuteCommand(command);
_messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), expectedTimes);
}
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async void TestMachineProvisionerCLI()
{
using (var hc = new TestHostContext(this))
{
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
hc.SetSingleton<IConfigurationStore>(_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<CancellationToken>()))
.Returns(Task.FromResult(false));
var runner = new Runner.Listener.Runner();
runner.Initialize(hc);
await runner.ExecuteCommand(command);
_messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), 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<IConfigurationManager>(_configurationManager.Object);
hc.SetSingleton<IJobNotification>(_jobNotification.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
hc.SetSingleton<IConfigurationStore>(_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<TaskAgentMessage>();
messages.Enqueue(message);
_configurationManager.Setup(x => x.LoadSettings())
.Returns(settings);
_configurationManager.Setup(x => x.IsConfigured())
.Returns(true);
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
.Returns(Task.FromResult<bool>(true));
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
.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<TaskAgentMessage>()))
.Returns(Task.CompletedTask);
var runOnceJobCompleted = new TaskCompletionSource<bool>();
_jobDispatcher.Setup(x => x.RunOnceJobCompleted)
.Returns(runOnceJobCompleted);
_jobDispatcher.Setup(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()))
.Callback(() =>
{
runOnceJobCompleted.TrySetResult(true);
});
_jobNotification.Setup(x => x.StartClient(It.IsAny<String>()))
.Callback(() =>
{
});
hc.EnqueueInstance<IJobDispatcher>(_jobDispatcher.Object);
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
//Act
var command = new CommandSettings(hc, new string[] { "run", "--once" });
Task<int> 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<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
_messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
_messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
_messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
_messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), 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<IConfigurationManager>(_configurationManager.Object);
hc.SetSingleton<IJobNotification>(_jobNotification.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
hc.SetSingleton<IConfigurationStore>(_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<TaskAgentMessage>();
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<CancellationToken>()))
.Returns(Task.FromResult<bool>(true));
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
.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<TaskAgentMessage>()))
.Returns(Task.CompletedTask);
var runOnceJobCompleted = new TaskCompletionSource<bool>();
_jobDispatcher.Setup(x => x.RunOnceJobCompleted)
.Returns(runOnceJobCompleted);
_jobDispatcher.Setup(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), It.IsAny<bool>()))
.Callback(() =>
{
runOnceJobCompleted.TrySetResult(true);
});
_jobNotification.Setup(x => x.StartClient(It.IsAny<String>()))
.Callback(() =>
{
});
hc.EnqueueInstance<IJobDispatcher>(_jobDispatcher.Object);
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
//Act
var command = new CommandSettings(hc, new string[] { "run", "--once" });
Task<int> 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<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
_messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
_messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
_messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
_messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), 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<IConfigurationManager>(_configurationManager.Object);
hc.SetSingleton<IJobNotification>(_jobNotification.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IRunnerCertificateManager>(_cert.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.SetSingleton<ISelfUpdater>(_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<TaskAgentMessage>();
messages.Enqueue(message1);
_updater.Setup(x => x.SelfUpdate(It.IsAny<AgentRefreshMessage>(), It.IsAny<IJobDispatcher>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()))
.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<CancellationToken>()))
.Returns(Task.FromResult<bool>(true));
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
.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<TaskAgentMessage>()))
.Returns(Task.CompletedTask);
_jobNotification.Setup(x => x.StartClient(It.IsAny<String>()))
.Callback(() =>
{
});
hc.EnqueueInstance<IJobDispatcher>(_jobDispatcher.Object);
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
//Act
var command = new CommandSettings(hc, new string[] { "run", "--once" });
Task<int> 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<AgentRefreshMessage>(), It.IsAny<IJobDispatcher>(), false, It.IsAny<CancellationToken>()), Times.Once);
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Never());
_messageListener.Verify(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()), Times.AtLeastOnce());
_messageListener.Verify(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
_messageListener.Verify(x => x.DeleteSessionAsync(), Times.Once());
_messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), Times.Once());
}
}
}
}

View File

@@ -14,8 +14,8 @@ namespace GitHub.Runner.Common.Tests
{ {
[Fact] [Fact]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Agent")] [Trait("Category", "Runner")]
public void AgentInterfacesSpecifyDefaultImplementation() public void RunnerInterfacesSpecifyDefaultImplementation()
{ {
// Validate all interfaces in the Listener assembly define a valid service locator attribute. // Validate all interfaces in the Listener assembly define a valid service locator attribute.
// Otherwise, the interface needs to whitelisted. // Otherwise, the interface needs to whitelisted.

View File

@@ -22,7 +22,7 @@ namespace GitHub.Runner.Common.Tests
private readonly ITraceManager _traceManager; private readonly ITraceManager _traceManager;
private readonly Terminal _term; private readonly Terminal _term;
private readonly SecretMasker _secretMasker; private readonly SecretMasker _secretMasker;
private CancellationTokenSource _agentShutdownTokenSource = new CancellationTokenSource(); private CancellationTokenSource _runnerShutdownTokenSource = new CancellationTokenSource();
private string _suiteName; private string _suiteName;
private string _testName; private string _testName;
private Tracing _trace; private Tracing _trace;
@@ -30,7 +30,7 @@ namespace GitHub.Runner.Common.Tests
private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D")); private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D"));
private StartupType _startupType; private StartupType _startupType;
public event EventHandler Unloading; public event EventHandler Unloading;
public CancellationToken RunnerShutdownToken => _agentShutdownTokenSource.Token; public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
public ShutdownReason RunnerShutdownReason { get; private set; } public ShutdownReason RunnerShutdownReason { get; private set; }
public ISecretMasker SecretMasker => _secretMasker; public ISecretMasker SecretMasker => _secretMasker;
public TestHostContext(object testClass, [CallerMemberName] string testName = "") public TestHostContext(object testClass, [CallerMemberName] string testName = "")
@@ -306,7 +306,7 @@ namespace GitHub.Runner.Common.Tests
{ {
ArgUtil.NotNull(reason, nameof(reason)); ArgUtil.NotNull(reason, nameof(reason));
RunnerShutdownReason = reason; RunnerShutdownReason = reason;
_agentShutdownTokenSource.Cancel(); _runnerShutdownTokenSource.Cancel();
} }
public void WritePerfCounter(string counter) public void WritePerfCounter(string counter)

View File

@@ -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.VersionInfo>(Pipelines.RepositoryPropertyNames.VersionInfo);
Assert.Equal("[PII]", scrubbedInfo.Author);
}
private bool IsMessageIdentical(Pipelines.AgentJobRequestMessage source, Pipelines.AgentJobRequestMessage target) private bool IsMessageIdentical(Pipelines.AgentJobRequestMessage source, Pipelines.AgentJobRequestMessage target)
{ {
if (source == null && target == null) if (source == null && target == null)