|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using FakeItEasy;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.NET.Build.Containers.Tasks;
namespace Microsoft.NET.Build.Containers.IntegrationTests.FullFramework;
public class CreateNewImageToolTaskTests
{
private ITestOutputHelper _testOutput;
public CreateNewImageToolTaskTests(ITestOutputHelper testOutput)
{
_testOutput = testOutput;
}
[Fact]
public void GenerateCommandLineCommands_ThrowsWhenRequiredPropertiesNotSet()
{
CreateNewImage task = new();
Exception e = Assert.Throws<InvalidOperationException>(() => task.GenerateCommandLineCommandsInt());
Assert.Equal("CONTAINER4001: Required property 'PublishDirectory' was not set or empty.", e.Message);
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
e = Assert.Throws<InvalidOperationException>(() => task.GenerateCommandLineCommandsInt());
Assert.Equal("CONTAINER4001: Required property 'BaseRegistry' was not set or empty.", e.Message);
task.BaseRegistry = "MyBaseRegistry";
e = Assert.Throws<InvalidOperationException>(() => task.GenerateCommandLineCommandsInt());
Assert.Equal("CONTAINER4001: Required property 'BaseImageName' was not set or empty.", e.Message);
task.BaseImageName = "MyBaseImageName";
e = Assert.Throws<InvalidOperationException>(() => task.GenerateCommandLineCommandsInt());
Assert.Equal("CONTAINER4001: Required property 'Repository' was not set or empty.", e.Message);
task.Repository = "MyImageName";
e = Assert.Throws<InvalidOperationException>(() => task.GenerateCommandLineCommandsInt());
Assert.Equal("CONTAINER4001: Required property 'WorkingDirectory' was not set or empty.", e.Message);
task.WorkingDirectory = "MyWorkingDirectory";
string args = task.GenerateCommandLineCommandsInt();
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:"); //standard help output for parse error
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("ValidTag", true)]
public void GenerateCommandLineCommands_BaseImageTag(string? value, bool optionExpected = false)
{
CreateNewImage task = new();
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
if (value != null)
{
task.BaseImageTag = value;
}
string args = task.GenerateCommandLineCommandsInt();
if (optionExpected)
{
Assert.Contains($"--baseimagetag {value}", args);
}
else
{
Assert.DoesNotContain("--baseimagetag", args);
}
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("Valid", true)]
public void GenerateCommandLineCommands_OutputRegistry(string? value, bool optionExpected = false)
{
CreateNewImage task = new();
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
if (value != null)
{
task.OutputRegistry = value;
}
string args = task.GenerateCommandLineCommandsInt();
if (optionExpected)
{
Assert.Contains($"--outputregistry {value}", args);
}
else
{
Assert.DoesNotContain("--outputregistry", args);
}
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("Valid", true)]
public void GenerateCommandLineCommands_ContainerRuntimeIdentifier(string? value, bool optionExpected = false)
{
CreateNewImage task = new();
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
if (value != null)
{
task.ContainerRuntimeIdentifier = value;
}
string args = task.GenerateCommandLineCommandsInt();
if (optionExpected)
{
Assert.Contains($"--rid {value}", args);
}
else
{
Assert.DoesNotContain("--rid", args);
}
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("Valid", true)]
public void GenerateCommandLineCommands_RuntimeIdentifierGraphPath(string? value, bool optionExpected = false)
{
CreateNewImage task = new();
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
if (value != null)
{
task.RuntimeIdentifierGraphPath = value;
}
string args = task.GenerateCommandLineCommandsInt();
if (optionExpected)
{
Assert.Contains($"--ridgraphpath {value}", args);
}
else
{
Assert.DoesNotContain("--ridgraphpath", args);
}
}
[Fact]
public void GenerateCommandLineCommands_Labels()
{
CreateNewImage task = new();
List<string?> warnings = new();
IBuildEngine buildEngine = A.Fake<IBuildEngine>();
A.CallTo(() => buildEngine.LogWarningEvent(A<BuildWarningEventArgs>.Ignored)).Invokes((BuildWarningEventArgs e) => warnings.Add(e.Message));
task.BuildEngine = buildEngine;
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
task.Labels = new[]
{
new TaskItem("NoValue"),
new TaskItem(" "),
new TaskItem("Valid1", new Dictionary<string, string>() {{ "Value", "Val1" }}),
new TaskItem("Valid12", new Dictionary<string, string>() {{ "Value", "Val2" }}),
new TaskItem("Valid12", new Dictionary<string, string>() {{ "Value", "" }}),
new TaskItem("Valid3", new Dictionary<string, string>() {{ "Value", "has space" }}),
new TaskItem("Valid4", new Dictionary<string, string>() {{ "Value", "has\"quotes\"" }})
};
string args = task.GenerateCommandLineCommandsInt();
Assert.Contains("""
--labels NoValue= Valid1=Val1 Valid12=Val2 Valid12= "Valid3=has space" "Valid4=has\"quotes\""
""", args);
Assert.Equal("Items 'Labels' contain empty item(s) which will be ignored.", Assert.Single(warnings));
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:"); //standard help output for parse error
}
[Fact]
public void GenerateCommandLineCommands_ContainerEnvironmentVariables()
{
CreateNewImage task = new();
List<string?> warnings = new();
IBuildEngine buildEngine = A.Fake<IBuildEngine>();
A.CallTo(() => buildEngine.LogWarningEvent(A<BuildWarningEventArgs>.Ignored)).Invokes((BuildWarningEventArgs e) => warnings.Add(e.Message));
task.BuildEngine = buildEngine;
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
task.ContainerEnvironmentVariables = new[]
{
new TaskItem("NoValue"),
new TaskItem(" "),
new TaskItem("Valid1", new Dictionary<string, string>() {{ "Value", "Val1" }}),
new TaskItem("Valid12", new Dictionary<string, string>() {{ "Value", "Val2" }}),
new TaskItem("Valid12", new Dictionary<string, string>() {{ "Value", "" }}),
new TaskItem("Valid3", new Dictionary<string, string>() {{ "Value", "has space" }}),
new TaskItem("Valid4", new Dictionary<string, string>() {{ "Value", "has\"quotes\"" }})
};
string args = task.GenerateCommandLineCommandsInt();
Assert.Contains("""
--environmentvariables NoValue= Valid1=Val1 Valid12=Val2 Valid12= "Valid3=has space" "Valid4=has\"quotes\""
""", args);
Assert.Equal("Items 'ContainerEnvironmentVariables' contain empty item(s) which will be ignored.", Assert.Single(warnings));
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:"); //standard help output for parse error
}
[InlineData(nameof(CreateNewImage.Entrypoint), "entrypoint")]
[InlineData(nameof(CreateNewImage.EntrypointArgs), "entrypointargs", true)]
[InlineData(nameof(CreateNewImage.DefaultArgs), "defaultargs", true)]
[InlineData(nameof(CreateNewImage.AppCommand), "appcommand", true)]
[InlineData(nameof(CreateNewImage.AppCommandArgs), "appcommandargs", true)]
[Theory]
public void GenerateCommandLineCommands_EntryPointAndCommand(string propertyName, string commandArgName, bool warningExpected = false)
{
CreateNewImage task = new();
List<string?> warnings = new();
IBuildEngine buildEngine = A.Fake<IBuildEngine>();
A.CallTo(() => buildEngine.LogWarningEvent(A<BuildWarningEventArgs>.Ignored)).Invokes((BuildWarningEventArgs e) => warnings.Add(e.Message));
task.BuildEngine = buildEngine;
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
switch (propertyName)
{
case nameof(CreateNewImage.Entrypoint):
task.Entrypoint = new[]
{
new TaskItem("Valid1"),
new TaskItem("Valid2"),
new TaskItem("Quoted item")
};
break;
case nameof(CreateNewImage.EntrypointArgs):
task.EntrypointArgs = new[]
{
new TaskItem(""),
new TaskItem(" "),
new TaskItem("Valid1"),
new TaskItem("Valid2"),
new TaskItem("Quoted item")
};
break;
case nameof(CreateNewImage.DefaultArgs):
task.DefaultArgs = new[]
{
new TaskItem(""),
new TaskItem(" "),
new TaskItem("Valid1"),
new TaskItem("Valid2"),
new TaskItem("Quoted item")
};
break;
case nameof(CreateNewImage.AppCommand):
task.AppCommand = new[]
{
new TaskItem(""),
new TaskItem(" "),
new TaskItem("Valid1"),
new TaskItem("Valid2"),
new TaskItem("Quoted item")
};
break;
case nameof(CreateNewImage.AppCommandArgs):
task.AppCommandArgs = new[]
{
new TaskItem(""),
new TaskItem(" "),
new TaskItem("Valid1"),
new TaskItem("Valid2"),
new TaskItem("Quoted item")
};
break;
}
string args = task.GenerateCommandLineCommandsInt();
Assert.Contains($"""
--{commandArgName} Valid1 Valid2 "Quoted item"
""", args);
if (warningExpected)
{
Assert.Equal($"Items '{propertyName}' contain empty item(s) which will be ignored.", Assert.Single(warnings));
}
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:"); //standard help output for parse error
}
[InlineData("")]
[InlineData(" ")]
[Theory]
public void GenerateCommandLineCommands_EntryPointCanHaveEmptyItems(string itemValue)
{
CreateNewImage task = new();
IBuildEngine buildEngine = A.Fake<IBuildEngine>();
task.BuildEngine = buildEngine;
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem(itemValue) };
task.GenerateCommandLineCommandsInt();
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("Valid", true)]
public void GenerateCommandLineCommands_AppCommandInstruction(string? value, bool optionExpected = false)
{
CreateNewImage task = new();
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
if (value != null)
{
task.AppCommandInstruction = value;
}
string args = task.GenerateCommandLineCommandsInt();
if (optionExpected)
{
Assert.Contains($"--appcommandinstruction {value}", args);
}
else
{
Assert.DoesNotContain("--appcommandinstruction", args);
}
}
[Fact]
public void GenerateCommandLineCommands_ImageTags()
{
CreateNewImage task = new();
List<string?> warnings = new();
IBuildEngine buildEngine = A.Fake<IBuildEngine>();
A.CallTo(() => buildEngine.LogWarningEvent(A<BuildWarningEventArgs>.Ignored)).Invokes((BuildWarningEventArgs e) => warnings.Add(e.Message));
task.BuildEngine = buildEngine;
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
task.ImageTags = new[] { "", " ", "Valid1", "To be quoted" };
string args = task.GenerateCommandLineCommandsInt();
Assert.Contains("""
--imagetags Valid1 "To be quoted"
""", actualString: args);
Assert.Equal("Property 'ImageTags' is empty or contains whitespace and will be ignored.", Assert.Single(warnings));
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:"); //standard help output for parse error
}
[Fact]
public void GenerateCommandLineCommands_ExposedPorts()
{
CreateNewImage task = new();
List<string?> warnings = new();
IBuildEngine buildEngine = A.Fake<IBuildEngine>();
A.CallTo(() => buildEngine.LogWarningEvent(A<BuildWarningEventArgs>.Ignored)).Invokes((BuildWarningEventArgs e) => warnings.Add(e.Message));
task.BuildEngine = buildEngine;
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
task.ExposedPorts = new[]
{
new TaskItem("1500"),
new TaskItem(" "),
new TaskItem("1501", new Dictionary<string, string>() {{ "Type", "udp" }}),
new TaskItem("1501", new Dictionary<string, string>() {{ "Type", "tcp" }}),
new TaskItem("1502", new Dictionary<string, string>() {{ "Type", "tcp" }}),
new TaskItem("1503", new Dictionary<string, string>() {{ "Type", "" }})
};
string args = task.GenerateCommandLineCommandsInt();
Assert.Contains("""
--ports 1500 1501/udp 1501/tcp 1502/tcp 1503
""", args);
Assert.Equal("Items 'ExposedPorts' contain empty item(s) which will be ignored.", Assert.Single(warnings));
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:"); //standard help output for parse error
}
[Fact]
public void Logging_CanEnableTraceLogging()
{
CreateNewImage task = new();
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("") };
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
string args = task.GenerateCommandLineCommandsInt();
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.WithEnvironmentVariable("CONTAINERIZE_TRACE_LOGGING_ENABLED", "1")
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:") //standard help output for parse error
.And.HaveStdOutContaining("Trace logging: enabled.");
}
[Fact]
public void Logging_TraceLoggingIsDisabledByDefault()
{
CreateNewImage task = new();
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("") };
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
string args = task.GenerateCommandLineCommandsInt();
string workDir = GetPathToContainerize();
new DotnetCommand(_testOutput, args)
.WithRawArguments()
.WithWorkingDirectory(workDir)
.Execute().Should().Fail()
.And.NotHaveStdOutContaining("Description:") //standard help output for parse error
.And.NotHaveStdOutContaining("Trace logging: enabled.");
}
[Fact]
public void GenerateCommandLineCommands_LabelGeneration()
{
CreateNewImage task = new();
List<string?> warnings = new();
IBuildEngine buildEngine = A.Fake<IBuildEngine>();
task.BuildEngine = buildEngine;
DirectoryInfo publishDir = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("yyyyMMddHHmmssfff")));
task.PublishDirectory = publishDir.FullName;
task.BaseRegistry = "MyBaseRegistry";
task.BaseImageName = "MyBaseImageName";
task.Repository = "MyImageName";
task.WorkingDirectory = "MyWorkingDirectory";
task.Entrypoint = new[] { new TaskItem("MyEntryPoint") };
task.GenerateLabels = true;
task.GenerateDigestLabel = true;
string args = task.GenerateCommandLineCommandsInt();
Assert.Contains("--generate-labels", args);
Assert.Contains("--generate-digest-label", args);
}
private static string GetPathToContainerize()
{
return Path.Combine(TestContext.Current.TestExecutionDirectory, "Container", "containerize");
}
}
|