mirror of
https://github.com/actions/runner.git
synced 2025-12-12 15:13:30 +00:00
Compare commits
42 Commits
docker-log
...
avastancu/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f8c069bf3 | ||
|
|
0d782f477f | ||
|
|
f39a18dfd2 | ||
|
|
fec24e8341 | ||
|
|
1778f8f022 | ||
|
|
c5685b7c63 | ||
|
|
82b81f26ed | ||
|
|
b1dd7975bc | ||
|
|
75c40e3cac | ||
|
|
d3f463b4b0 | ||
|
|
3b30e5c0d5 | ||
|
|
805d6fdb39 | ||
|
|
7ba0916092 | ||
|
|
72fe5798c3 | ||
|
|
b15525a8ca | ||
|
|
a9fa7f83e9 | ||
|
|
5b26a1e1ae | ||
|
|
e03ad87776 | ||
|
|
826cec2775 | ||
|
|
b8aafc4ff1 | ||
|
|
47ead99c13 | ||
|
|
3c88e14ca5 | ||
|
|
f5461b78be | ||
|
|
912d7d6932 | ||
|
|
76e4f51a21 | ||
|
|
7a992f844d | ||
|
|
dfcbe9b1e1 | ||
|
|
2dc8f25359 | ||
|
|
f0b315c911 | ||
|
|
354c8bcbed | ||
|
|
ad8f17e956 | ||
|
|
2d4dc37d49 | ||
|
|
cfcf0831f3 | ||
|
|
94e504c40e | ||
|
|
2f9ced96c6 | ||
|
|
29e26c0aa1 | ||
|
|
d533271015 | ||
|
|
892a90cc99 | ||
|
|
ae7bb31431 | ||
|
|
160d07e576 | ||
|
|
2e8d8a74ab | ||
|
|
3b4406161b |
@@ -1,6 +1,9 @@
|
|||||||
## Bugs
|
## Bugs
|
||||||
- Fixed an issue where job and service container envs were corrupted (#2091)
|
- Avoid key based command injection via Docker command arguments (#2062)
|
||||||
## Misc
|
## Misc
|
||||||
|
- Added step context name and start/finish time in step telemetry (#2069)
|
||||||
|
- Improved error logs when there is a missing 'using' token configuration in the metadata file (#2052)
|
||||||
|
- Added full job name and nested workflow details in log (#2049)
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
public bool IsJobContainer { get; set; }
|
public bool IsJobContainer { get; set; }
|
||||||
public bool IsAlpine { get; set; }
|
public bool IsAlpine { get; set; }
|
||||||
|
|
||||||
|
public bool FailedInitialization { get; set; }
|
||||||
|
|
||||||
public IDictionary<string, string> ContainerEnvironmentVariables
|
public IDictionary<string, string> ContainerEnvironmentVariables
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -107,7 +107,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
public async Task<string> DockerCreate(IExecutionContext context, ContainerInfo container)
|
public async Task<string> DockerCreate(IExecutionContext context, ContainerInfo container)
|
||||||
{
|
{
|
||||||
IList<string> dockerOptions = new List<string>();
|
IList<string> dockerOptions = new List<string>();
|
||||||
IDictionary<string, string> environment = new Dictionary<string, string>();
|
|
||||||
// OPTIONS
|
// OPTIONS
|
||||||
dockerOptions.Add($"--name {container.ContainerDisplayName}");
|
dockerOptions.Add($"--name {container.ContainerDisplayName}");
|
||||||
dockerOptions.Add($"--label {DockerInstanceLabel}");
|
dockerOptions.Add($"--label {DockerInstanceLabel}");
|
||||||
@@ -136,8 +135,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
environment.Add(env.Key, env.Value);
|
dockerOptions.Add(DockerUtil.CreateEscapedOption("-e", env.Key, env.Value));
|
||||||
dockerOptions.Add(DockerUtil.CreateEscapedOption("-e", env.Key));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +183,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
dockerOptions.Add($"{container.ContainerEntryPointArgs}");
|
dockerOptions.Add($"{container.ContainerEntryPointArgs}");
|
||||||
|
|
||||||
var optionsString = string.Join(" ", dockerOptions);
|
var optionsString = string.Join(" ", dockerOptions);
|
||||||
List<string> outputStrings = await ExecuteDockerCommandAsync(context, "create", optionsString, environment);
|
List<string> outputStrings = await ExecuteDockerCommandAsync(context, "create", optionsString);
|
||||||
|
|
||||||
return outputStrings.FirstOrDefault();
|
return outputStrings.FirstOrDefault();
|
||||||
}
|
}
|
||||||
@@ -445,11 +443,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<string>> ExecuteDockerCommandAsync(IExecutionContext context, string command, string options)
|
private async Task<List<string>> ExecuteDockerCommandAsync(IExecutionContext context, string command, string options)
|
||||||
{
|
|
||||||
return await ExecuteDockerCommandAsync(context, command, options, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<string>> ExecuteDockerCommandAsync(IExecutionContext context, string command, string options, IDictionary<string, string> environment)
|
|
||||||
{
|
{
|
||||||
string arg = $"{command} {options}".Trim();
|
string arg = $"{command} {options}".Trim();
|
||||||
context.Command($"{DockerPath} {arg}");
|
context.Command($"{DockerPath} {arg}");
|
||||||
@@ -477,7 +470,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
workingDirectory: context.GetGitHubContext("workspace"),
|
workingDirectory: context.GetGitHubContext("workspace"),
|
||||||
fileName: DockerPath,
|
fileName: DockerPath,
|
||||||
arguments: arg,
|
arguments: arg,
|
||||||
environment: environment,
|
environment: null,
|
||||||
requireExitCodeZero: true,
|
requireExitCodeZero: true,
|
||||||
outputEncoding: null,
|
outputEncoding: null,
|
||||||
cancellationToken: CancellationToken.None);
|
cancellationToken: CancellationToken.None);
|
||||||
|
|||||||
@@ -71,6 +71,15 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
return $"{flag} \"{EscapeString(key)}\"";
|
return $"{flag} \"{EscapeString(key)}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CreateEscapedOption(string flag, string key, string value)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return $"{flag} \"{EscapeString(key)}={EscapeString(value)}\"";
|
||||||
|
}
|
||||||
|
|
||||||
private static string EscapeString(string value)
|
private static string EscapeString(string value)
|
||||||
{
|
{
|
||||||
return value.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
return value.Replace("\\", "\\\\").Replace("\"", "\\\"");
|
||||||
|
|||||||
@@ -98,12 +98,41 @@ namespace GitHub.Runner.Worker
|
|||||||
await StartContainerAsync(executionContext, container);
|
await StartContainerAsync(executionContext, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await RunContainersHealthcheck(executionContext, containers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunContainersHealthcheck(IExecutionContext executionContext, List<ContainerInfo> containers)
|
||||||
|
{
|
||||||
executionContext.Output("##[group]Waiting for all services to be ready");
|
executionContext.Output("##[group]Waiting for all services to be ready");
|
||||||
|
|
||||||
|
var unhealthyContainers = new List<ContainerInfo>();
|
||||||
foreach (var container in containers.Where(c => !c.IsJobContainer))
|
foreach (var container in containers.Where(c => !c.IsJobContainer))
|
||||||
{
|
{
|
||||||
await ContainerHealthcheck(executionContext, container);
|
var healthcheck = await ContainerHealthcheck(executionContext, container);
|
||||||
|
|
||||||
|
if (!(string.Equals(healthcheck, "healthy", StringComparison.OrdinalIgnoreCase) || string.IsNullOrEmpty(healthcheck)))
|
||||||
|
{
|
||||||
|
unhealthyContainers.Add(container);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
executionContext.Output($"{container.ContainerNetworkAlias} service is healthy.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
executionContext.Output("##[endgroup]");
|
executionContext.Output("##[endgroup]");
|
||||||
|
|
||||||
|
if (unhealthyContainers.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var container in unhealthyContainers)
|
||||||
|
{
|
||||||
|
executionContext.Output($"##[group]Service container {container.ContainerNetworkAlias} failed.");
|
||||||
|
await _dockerManager.DockerLogs(context: executionContext, containerId: container.ContainerId);
|
||||||
|
executionContext.Error($"Failed to initialize container {container.ContainerImage}");
|
||||||
|
container.FailedInitialization = true;
|
||||||
|
executionContext.Output("##[endgroup]");
|
||||||
|
}
|
||||||
|
throw new InvalidOperationException("One or more containers failed to start.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopContainersAsync(IExecutionContext executionContext, object data)
|
public async Task StopContainersAsync(IExecutionContext executionContext, object data)
|
||||||
@@ -134,6 +163,7 @@ namespace GitHub.Runner.Worker
|
|||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
ArgUtil.NotNull(container, nameof(container));
|
ArgUtil.NotNull(container, nameof(container));
|
||||||
ArgUtil.NotNullOrEmpty(container.ContainerImage, nameof(container.ContainerImage));
|
ArgUtil.NotNullOrEmpty(container.ContainerImage, nameof(container.ContainerImage));
|
||||||
|
|
||||||
Trace.Info($"Container name: {container.ContainerName}");
|
Trace.Info($"Container name: {container.ContainerName}");
|
||||||
Trace.Info($"Container image: {container.ContainerImage}");
|
Trace.Info($"Container image: {container.ContainerImage}");
|
||||||
Trace.Info($"Container options: {container.ContainerCreateOptions}");
|
Trace.Info($"Container options: {container.ContainerCreateOptions}");
|
||||||
@@ -197,8 +227,6 @@ namespace GitHub.Runner.Worker
|
|||||||
container.ContainerId = await _dockerManager.DockerCreate(executionContext, container);
|
container.ContainerId = await _dockerManager.DockerCreate(executionContext, container);
|
||||||
ArgUtil.NotNullOrEmpty(container.ContainerId, nameof(container.ContainerId));
|
ArgUtil.NotNullOrEmpty(container.ContainerId, nameof(container.ContainerId));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Start container
|
// Start container
|
||||||
int startExitCode = await _dockerManager.DockerStart(executionContext, container.ContainerId);
|
int startExitCode = await _dockerManager.DockerStart(executionContext, container.ContainerId);
|
||||||
if (startExitCode != 0)
|
if (startExitCode != 0)
|
||||||
@@ -208,36 +236,19 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
// Make sure container is up and running
|
// Make sure container is up and running
|
||||||
var psOutputs = await _dockerManager.DockerPS(executionContext, $"--all --filter id={container.ContainerId} --filter status=running --no-trunc --format \"{{{{.ID}}}} {{{{.Status}}}}\"");
|
var psOutputs = await _dockerManager.DockerPS(executionContext, $"--all --filter id={container.ContainerId} --filter status=running --no-trunc --format \"{{{{.ID}}}} {{{{.Status}}}}\"");
|
||||||
|
|
||||||
if (psOutputs.FirstOrDefault(x => !string.IsNullOrEmpty(x))?.StartsWith(container.ContainerId) != true)
|
if (psOutputs.FirstOrDefault(x => !string.IsNullOrEmpty(x))?.StartsWith(container.ContainerId) != true)
|
||||||
{
|
{
|
||||||
// container is not up and running, pull docker log for this container.
|
// container is not up and running, pull docker log for this container.
|
||||||
await _dockerManager.DockerPS(executionContext, $"--all --filter id={container.ContainerId} --no-trunc --format \"{{{{.ID}}}} {{{{.Status}}}}\"");
|
await _dockerManager.DockerPS(executionContext, $"--all --filter id={container.ContainerId} --no-trunc --format \"{{{{.ID}}}} {{{{.Status}}}}\"");
|
||||||
|
|
||||||
|
|
||||||
//executionContext.Output("##[group]Getting docker logs..");
|
|
||||||
|
|
||||||
int logsExitCode = await _dockerManager.DockerLogs(executionContext, container.ContainerId);
|
int logsExitCode = await _dockerManager.DockerLogs(executionContext, container.ContainerId);
|
||||||
|
|
||||||
if (logsExitCode != 0)
|
if (logsExitCode != 0)
|
||||||
{
|
{
|
||||||
executionContext.Warning($"Docker logs fail with exit code {logsExitCode}");
|
executionContext.Warning($"Docker logs fail with exit code {logsExitCode}");
|
||||||
}
|
}
|
||||||
//executionContext.Output("##[endgroup]");
|
|
||||||
executionContext.Warning($"Docker container {container.ContainerId} is not in running state.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
executionContext.Output($"##[group]Container {container.ContainerId} is not running!");
|
|
||||||
string opt = "--format=\'{{.State.ExitCode}}\'";
|
|
||||||
await _dockerManager.DockerInspect(executionContext, container.ContainerId, opt);
|
|
||||||
await _dockerManager.DockerLogs(executionContext, container.ContainerId);
|
|
||||||
//if exit code is not 0 we can maybe print a message?
|
|
||||||
//executionContext.Output("Container exit code: ");
|
|
||||||
|
|
||||||
executionContext.Output("##[endgroup]");
|
executionContext.Warning($"Docker container {container.ContainerId} is not in running state.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -317,9 +328,8 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(container.ContainerId))
|
if (!string.IsNullOrEmpty(container.ContainerId))
|
||||||
{
|
{
|
||||||
if (!container.IsJobContainer)
|
if (!container.IsJobContainer && !container.FailedInitialization)
|
||||||
{
|
{
|
||||||
// Print logs for service container jobs (not the "action" job itself b/c that's already logged).
|
|
||||||
executionContext.Output($"Print service container logs: {container.ContainerDisplayName}");
|
executionContext.Output($"Print service container logs: {container.ContainerDisplayName}");
|
||||||
|
|
||||||
int logsExitCode = await _dockerManager.DockerLogs(executionContext, container.ContainerId);
|
int logsExitCode = await _dockerManager.DockerLogs(executionContext, container.ContainerId);
|
||||||
@@ -413,14 +423,14 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ContainerHealthcheck(IExecutionContext executionContext, ContainerInfo container)
|
private async Task<string> ContainerHealthcheck(IExecutionContext executionContext, ContainerInfo container)
|
||||||
{
|
{
|
||||||
string healthCheck = "--format=\"{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}\"";
|
string healthCheck = "--format=\"{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}\"";
|
||||||
string serviceHealth = (await _dockerManager.DockerInspect(context: executionContext, dockerObject: container.ContainerId, options: healthCheck)).FirstOrDefault();
|
string serviceHealth = (await _dockerManager.DockerInspect(context: executionContext, dockerObject: container.ContainerId, options: healthCheck)).FirstOrDefault();
|
||||||
if (string.IsNullOrEmpty(serviceHealth))
|
if (string.IsNullOrEmpty(serviceHealth))
|
||||||
{
|
{
|
||||||
// Container has no HEALTHCHECK
|
// Container has no HEALTHCHECK
|
||||||
return;
|
return String.Empty;
|
||||||
}
|
}
|
||||||
var retryCount = 0;
|
var retryCount = 0;
|
||||||
while (string.Equals(serviceHealth, "starting", StringComparison.OrdinalIgnoreCase))
|
while (string.Equals(serviceHealth, "starting", StringComparison.OrdinalIgnoreCase))
|
||||||
@@ -431,14 +441,7 @@ namespace GitHub.Runner.Worker
|
|||||||
serviceHealth = (await _dockerManager.DockerInspect(context: executionContext, dockerObject: container.ContainerId, options: healthCheck)).FirstOrDefault();
|
serviceHealth = (await _dockerManager.DockerInspect(context: executionContext, dockerObject: container.ContainerId, options: healthCheck)).FirstOrDefault();
|
||||||
retryCount++;
|
retryCount++;
|
||||||
}
|
}
|
||||||
if (string.Equals(serviceHealth, "healthy", StringComparison.OrdinalIgnoreCase))
|
return serviceHealth;
|
||||||
{
|
|
||||||
executionContext.Output($"{container.ContainerNetworkAlias} service is healthy.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Failed to initialize, {container.ContainerNetworkAlias} service is {serviceHealth}.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> ContainerRegistryLogin(IExecutionContext executionContext, ContainerInfo container)
|
private async Task<string> ContainerRegistryLogin(IExecutionContext executionContext, ContainerInfo container)
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
preJobSteps.Add(new JobExtensionRunner(runAsync: containerProvider.StartContainersAsync,
|
preJobSteps.Add(new JobExtensionRunner(runAsync: containerProvider.StartContainersAsync,
|
||||||
condition: $"{PipelineTemplateConstants.Success}()",
|
condition: $"{PipelineTemplateConstants.Success}()",
|
||||||
displayName: "**Initialize containers**",
|
displayName: "Initialize containers",
|
||||||
data: (object)containers));
|
data: (object)containers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,5 +171,32 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
|
|||||||
}
|
}
|
||||||
Assert.Equal(expected, actual);
|
Assert.Equal(expected, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
[InlineData("HOME", "", "HOME", "")]
|
||||||
|
[InlineData("HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #")]
|
||||||
|
[InlineData("HOME \"alpine:3.8 sh -c id #", "HOME \"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #")]
|
||||||
|
[InlineData("HOME \\\"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #")]
|
||||||
|
[InlineData("HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #")]
|
||||||
|
[InlineData("HOME \"\"alpine:3.8 sh -c id #", "HOME \"\"alpine:3.8 sh -c id #", "HOME \\\"\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\"alpine:3.8 sh -c id #")]
|
||||||
|
[InlineData("HOME \\\"\"alpine:3.8 sh -c id #", "HOME \\\"\"alpine:3.8 sh -c id #", "HOME \\\\\\\"\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"\\\"alpine:3.8 sh -c id #")]
|
||||||
|
[InlineData("HOME \"\\\"alpine:3.8 sh -c id #", "HOME \"\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #")]
|
||||||
|
public void CreateEscapedOption_keyValue(string keyInput, string valueInput, string escapedKey, string escapedValue)
|
||||||
|
{
|
||||||
|
var flag = "--example";
|
||||||
|
var actual = DockerUtil.CreateEscapedOption(flag, keyInput, valueInput);
|
||||||
|
string expected;
|
||||||
|
if (String.IsNullOrEmpty(keyInput))
|
||||||
|
{
|
||||||
|
expected = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expected = $"{flag} \"{escapedKey}={escapedValue}\"";
|
||||||
|
}
|
||||||
|
Assert.Equal(expected, actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
126
src/Test/L0/Worker/ContainerOperationProviderL0.cs
Normal file
126
src/Test/L0/Worker/ContainerOperationProviderL0.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using GitHub.Runner.Worker;
|
||||||
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using Xunit;
|
||||||
|
using Moq;
|
||||||
|
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common.Tests.Worker
|
||||||
|
{
|
||||||
|
|
||||||
|
public sealed class ContainerOperationProviderL0
|
||||||
|
{
|
||||||
|
|
||||||
|
private TestHostContext _hc;
|
||||||
|
private Mock<IExecutionContext> _ec;
|
||||||
|
private Mock<IDockerCommandManager> _dockerManager;
|
||||||
|
private Mock<IContainerHookManager> _containerHookManager;
|
||||||
|
private ContainerOperationProvider containerOperationProvider;
|
||||||
|
private Mock<IJobServerQueue> serverQueue;
|
||||||
|
private Mock<IPagingLogger> pagingLogger;
|
||||||
|
private List<string> healthyDockerStatus = new List<string> { "healthy" };
|
||||||
|
private List<string> emptyDockerStatus = new List<string> { string.Empty };
|
||||||
|
private List<string> unhealthyDockerStatus = new List<string> { "unhealthy" };
|
||||||
|
private List<string> dockerLogs = new List<string> { "log1", "log2", "log3" };
|
||||||
|
|
||||||
|
List<ContainerInfo> containers = new List<ContainerInfo>();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void RunServiceContainersHealthcheck_UnhealthyServiceContainer_AssertFailedTask()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
_dockerManager.Setup(x => x.DockerInspect(_ec.Object, It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(unhealthyDockerStatus));
|
||||||
|
|
||||||
|
//Act
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await containerOperationProvider.RunContainersHealthcheck(_ec.Object, containers);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal(TaskResult.Failed, _ec.Object.Result ?? TaskResult.Failed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void RunServiceContainersHealthcheck_UnhealthyServiceContainer_AssertExceptionThrown()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
_dockerManager.Setup(x => x.DockerInspect(_ec.Object, It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(unhealthyDockerStatus));
|
||||||
|
|
||||||
|
//Act and Assert
|
||||||
|
await Assert.ThrowsAsync<InvalidOperationException>(() => containerOperationProvider.RunContainersHealthcheck(_ec.Object, containers));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void RunServiceContainersHealthcheck_healthyServiceContainer_AssertSucceededTask()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
_dockerManager.Setup(x => x.DockerInspect(_ec.Object, It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(healthyDockerStatus));
|
||||||
|
|
||||||
|
//Act
|
||||||
|
await containerOperationProvider.RunContainersHealthcheck(_ec.Object, containers);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal(TaskResult.Succeeded, _ec.Object.Result ?? TaskResult.Succeeded);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void RunServiceContainersHealthcheck_healthyServiceContainerWithoutHealthcheck_AssertSucceededTask()
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
_dockerManager.Setup(x => x.DockerInspect(_ec.Object, It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(emptyDockerStatus));
|
||||||
|
|
||||||
|
//Act
|
||||||
|
await containerOperationProvider.RunContainersHealthcheck(_ec.Object, containers);
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal(TaskResult.Succeeded, _ec.Object.Result ?? TaskResult.Succeeded);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Setup([CallerMemberName] string testName = "")
|
||||||
|
{
|
||||||
|
containers.Add(new ContainerInfo() { ContainerImage = "ubuntu:16.04" });
|
||||||
|
_hc = new TestHostContext(this, testName);
|
||||||
|
_ec = new Mock<IExecutionContext>();
|
||||||
|
serverQueue = new Mock<IJobServerQueue>();
|
||||||
|
pagingLogger = new Mock<IPagingLogger>();
|
||||||
|
|
||||||
|
_dockerManager = new Mock<IDockerCommandManager>();
|
||||||
|
_containerHookManager = new Mock<IContainerHookManager>();
|
||||||
|
containerOperationProvider = new ContainerOperationProvider();
|
||||||
|
|
||||||
|
_hc.SetSingleton<IDockerCommandManager>(_dockerManager.Object);
|
||||||
|
_hc.SetSingleton<IJobServerQueue>(serverQueue.Object);
|
||||||
|
_hc.SetSingleton<IPagingLogger>(pagingLogger.Object);
|
||||||
|
|
||||||
|
_hc.SetSingleton<IDockerCommandManager>(_dockerManager.Object);
|
||||||
|
_hc.SetSingleton<IContainerHookManager>(_containerHookManager.Object);
|
||||||
|
|
||||||
|
_ec.Setup(x => x.Global).Returns(new GlobalContext());
|
||||||
|
|
||||||
|
containerOperationProvider.Initialize(_hc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
2.296.1
|
2.296.0
|
||||||
|
|||||||
Reference in New Issue
Block a user