Skip to content

Commit 3826f4b

Browse files
committed
use real MSBuild for all test evaluations
1 parent bb1114f commit 3826f4b

File tree

9 files changed

+208
-132
lines changed

9 files changed

+208
-132
lines changed

Directory.Packages.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
55
<ItemGroup>
6+
<PackageVersion Include="coverlet.collector" Version="3.1.2" />
7+
<PackageVersion Include="GitHubActionsTestLogger" Version="2.0.1" />
8+
<PackageVersion Include="Microsoft.Build.Locator" Version="1.5.5" />
69
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.3.1" />
710
<PackageVersion Include="Microsoft.Build" Version="17.3.1" />
811
<PackageVersion Include="Microsoft.Net.Compilers.Toolset" Version="4.4.0-4.final" />
@@ -11,10 +14,7 @@
1114
<PackageVersion Include="MSTest.TestAdapter" Version="2.3.0-preview-20220810-02" />
1215
<PackageVersion Include="MSTest.TestFramework" Version="2.2.10" />
1316
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.5.109" />
14-
<PackageVersion Include="coverlet.collector" Version="3.1.2" />
15-
<PackageVersion Include="GitHubActionsTestLogger" Version="2.0.1" />
1617
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
17-
<PackageVersion Include="Microsoft.Build.Locator" Version="1.5.5" />
18-
<PackageVersion Include="Valleysoft.DockerCredsProvider" Version="2.1.0" />
18+
<PackageVersion Include="Valleysoft.DockerCredsProvider" Version="2.1.0" />
1919
</ItemGroup>
2020
</Project>

Microsoft.NET.Build.Containers/ParseContainerProperties.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public override bool Execute()
115115
else
116116
{
117117
validTags = Array.Empty<string>();
118-
Log.LogError(null, "CONTAINER003", "Container.InvalidTag", null, 0, 0, 0, 0, $"Invalid {nameof(ContainerImageTag)} provided: {{0}}. Image tags must be alphanumeric, underscore, hyphen, or period.", ContainerImageTag);
118+
Log.LogError(null, "CONTAINER004", "Container.InvalidTag", null, 0, 0, 0, 0, $"Invalid {nameof(ContainerImageTag)} provided: {{0}}. Image tags must be alphanumeric, underscore, hyphen, or period.", ContainerImageTag);
119119
}
120120
}
121121
else if (ContainerImageTags.Length != 0 && TryValidateTags(ContainerImageTags, out var valids, out var invalids))
@@ -128,7 +128,7 @@ public override bool Execute()
128128
{ Length: 1 } => ($"Invalid {nameof(ContainerImageTags)} provided: {{0}}. {nameof(ContainerImageTags)} must be a semicolon-delimited list of valid image tags. Image tags must be alphanumeric, underscore, hyphen, or period.", invalids[0]),
129129
_ => ($"Invalid {nameof(ContainerImageTags)} provided: {{0}}. {nameof(ContainerImageTags)} must be a semicolon-delimited list of valid image tags. Image tags must be alphanumeric, underscore, hyphen, or period.", String.Join(", ", invalids))
130130
};
131-
Log.LogError(null, "CONTAINER003", "Container.InvalidTag", null, 0, 0, 0, 0, message, args);
131+
Log.LogError(null, "CONTAINER004", "Container.InvalidTag", null, 0, 0, 0, 0, message, args);
132132
return !Log.HasLoggedErrors;
133133
}
134134
}

Test.Microsoft.NET.Build.Containers.Filesystem/DockerRegistryManager.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
namespace Test.Microsoft.NET.Build.Containers.Filesystem;
55

6-
[TestClass]
76
public class DockerRegistryManager
87
{
98
public const string BaseImage = "dotnet/runtime";
@@ -33,8 +32,7 @@ public static void LocateMSBuild()
3332
[AssemblyInitialize]
3433
public static void StartAndPopulateDockerRegistry(TestContext context)
3534
{
36-
Console.WriteLine(nameof(StartAndPopulateDockerRegistry));
37-
35+
context.WriteLine("Spawning local registry");
3836
ProcessStartInfo startRegistry = new("docker", "run --rm --publish 5010:5000 --detach registry:2")
3937
{
4038
RedirectStandardOutput = true,
@@ -50,7 +48,6 @@ public static void StartAndPopulateDockerRegistry(TestContext context)
5048
Assert.IsNotNull(registryContainerId);
5149
registryProcess.WaitForExit();
5250
Assert.AreEqual(0, registryProcess.ExitCode, $"Could not start Docker registry. Are you running one for manual testing?{Environment.NewLine}{errStream}");
53-
5451
s_registryContainerId = registryContainerId;
5552

5653
Exec("docker", $"pull {BaseImageSource}{BaseImage}:{BaseImageTag}");
@@ -59,7 +56,6 @@ public static void StartAndPopulateDockerRegistry(TestContext context)
5956
LocateMSBuild();
6057
}
6158

62-
[AssemblyCleanup]
6359
public static void ShutdownDockerRegistry()
6460
{
6561
Assert.IsNotNull(s_registryContainerId);
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using Microsoft.Build.Evaluation;
3+
using Microsoft.Build.Framework;
4+
using Microsoft.Build.Locator;
5+
6+
namespace Test.Microsoft.NET.Build.Containers;
7+
8+
public static class Evaluator {
9+
private static string CombinedTargetsLocation;
10+
11+
private static string CombineFiles(string propsFile, string targetsFile)
12+
{
13+
var propsContent = File.ReadAllLines(propsFile);
14+
var targetsContent = File.ReadAllLines(targetsFile);
15+
var combinedContent = new List<string>();
16+
combinedContent.AddRange(propsContent[..^1]);
17+
combinedContent.AddRange(targetsContent[1..]);
18+
var tempTargetLocation = Path.Combine(Path.GetTempPath(), "Containers", "Microsoft.NET.Build.Containers.targets");
19+
Directory.CreateDirectory(Path.GetDirectoryName(tempTargetLocation));
20+
File.WriteAllLines(tempTargetLocation, combinedContent);
21+
return tempTargetLocation;
22+
}
23+
24+
public static void LocateMSBuild(TestContext ctx)
25+
{
26+
var instances = MSBuildLocator.RegisterDefaults();
27+
var relativePath = Path.Combine("..", "Microsoft.NET.Build.Containers", "build", "Microsoft.NET.Build.Containers.targets");
28+
var targetsFile = CurrentFile.Relative(relativePath);
29+
var propsFile = Path.ChangeExtension(targetsFile, ".props");
30+
CombinedTargetsLocation = CombineFiles(propsFile, targetsFile);
31+
}
32+
33+
public static void Cleanup()
34+
{
35+
if (CombinedTargetsLocation != null) File.Delete(CombinedTargetsLocation);
36+
}
37+
38+
public static (Project, CapturingLogger?) InitProject(Dictionary<string, string> bonusProps, bool captureLogs = false)
39+
{
40+
var props = new Dictionary<string, string>();
41+
// required parameters
42+
props["TargetFileName"] = "foo.dll";
43+
props["AssemblyName"] = "foo";
44+
props["_TargetFrameworkVersionWithoutV"] = "7.0";
45+
props["_NativeExecutableExtension"] = ".exe"; //TODO: windows/unix split here
46+
props["Version"] = "1.0.0"; // TODO: need to test non-compliant version strings here
47+
48+
// test setup parameters so that we can load the props/targets/tasks
49+
props["CustomTasksAssembly"] = Path.GetFullPath(Path.Combine(".", "Microsoft.NET.Build.Containers.dll"));
50+
props["_IsTest"] = "true";
51+
var loggers = new List<ILogger>
52+
{
53+
// new Microsoft.Build.Logging.BinaryLogger() {CollectProjectImports = Microsoft.Build.Logging.BinaryLogger.ProjectImportsCollectionMode.Embed, Verbosity = LoggerVerbosity.Diagnostic, Parameters = "LogFile=blah.binlog" },
54+
new global::Microsoft.Build.Logging.ConsoleLogger(LoggerVerbosity.Detailed)
55+
};
56+
CapturingLogger? logs;
57+
if (captureLogs) {
58+
logs = new CapturingLogger();
59+
loggers.Add(logs);
60+
} else {
61+
logs = null;
62+
}
63+
64+
var collection = new ProjectCollection(null, loggers, ToolsetDefinitionLocations.Default);
65+
foreach (var kvp in bonusProps)
66+
{
67+
props[kvp.Key] = kvp.Value;
68+
}
69+
return (collection.LoadProject(CombinedTargetsLocation, props, null), logs);
70+
}
71+
}
72+
73+
public class CapturingLogger : ILogger
74+
{
75+
public LoggerVerbosity Verbosity { get => LoggerVerbosity.Diagnostic; set { } }
76+
public string Parameters { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
77+
78+
private List<BuildMessageEventArgs> _messages = new();
79+
public IReadOnlyList<BuildMessageEventArgs> Messages {get { return _messages; } }
80+
81+
private List<BuildWarningEventArgs> _warnings = new();
82+
public IReadOnlyList<BuildWarningEventArgs> Warnings {get { return _warnings; } }
83+
84+
private List<BuildErrorEventArgs> _errors = new();
85+
public IReadOnlyList<BuildErrorEventArgs> Errors {get { return _errors; } }
86+
87+
public void Initialize(IEventSource eventSource)
88+
{
89+
eventSource.MessageRaised += (o, e) => _messages.Add(e);
90+
eventSource.WarningRaised += (o, e) => _warnings.Add(e);
91+
eventSource.ErrorRaised += (o, e) => _errors.Add(e);
92+
}
93+
94+
95+
public void Shutdown()
96+
{
97+
}
98+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
namespace Test.Microsoft.NET.Build.Containers;
2+
3+
public static class KnownStrings {
4+
public static string ContainerBaseImage = nameof(ContainerBaseImage);
5+
public static string ContainerRegistry = nameof(ContainerRegistry);
6+
public static string ContainerImageName = nameof(ContainerImageName);
7+
public static string ContainerImageTag = nameof(ContainerImageTag);
8+
public static string ContainerImageTags = nameof(ContainerImageTags);
9+
public static string ContainerWorkingDirectory = nameof(ContainerWorkingDirectory);
10+
public static string ContainerEntrypoint = nameof(ContainerEntrypoint);
11+
public static string UseAppHost = nameof(UseAppHost);
12+
public static string ContainerLabel = nameof(ContainerLabel);
13+
public static string SelfContained = nameof(SelfContained);
14+
public static string ContainerPort = nameof(ContainerPort);
15+
public static string ContainerEnvironmentVariable = nameof(ContainerEnvironmentVariable);
16+
17+
public static string ComputeContainerConfig = nameof(ComputeContainerConfig);
18+
public static string AssemblyName = nameof(AssemblyName);
19+
public static string ContainerBaseRegistry = nameof(ContainerBaseRegistry);
20+
public static string ContainerBaseName = nameof(ContainerBaseName);
21+
public static string ContainerBaseTag = nameof(ContainerBaseTag);
22+
23+
public static class ErrorCodes {
24+
public static string CONTAINER001 = nameof(CONTAINER001);
25+
public static string CONTAINER004 = nameof(CONTAINER004);
26+
public static string CONTAINER005 = nameof(CONTAINER005);
27+
}
28+
}

Test.Microsoft.NET.Build.Containers.Filesystem/ParseContainerPropertiesTests.cs

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Microsoft.VisualStudio.TestTools.UnitTesting;
22
using Microsoft.NET.Build.Containers.Tasks;
3-
4-
#nullable disable
3+
using static Test.Microsoft.NET.Build.Containers.KnownStrings;
54

65
namespace Test.Microsoft.NET.Build.Containers.Tasks
76
{
@@ -67,68 +66,68 @@ public void UserRegistriesWithNoSchemeGetHttps()
6766
[TestMethod]
6867
public void SpacesGetReplacedWithDashes()
6968
{
70-
ParseContainerProperties task = new ParseContainerProperties();
71-
task.FullyQualifiedBaseImageName = "mcr microsoft com/dotnet runtime:6 0";
72-
task.ContainerRegistry = "localhost:5010";
73-
74-
// Spaces in the "new" container info don't pass the regex.
75-
task.ContainerImageName = "dotnet/testimage";
76-
task.ContainerImageTags = new[] { "5.0" };
69+
var (project, _) = Evaluator.InitProject(new () {
70+
[ContainerBaseImage] = "mcr microsoft com/dotnet runtime:6.0",
71+
[ContainerRegistry] = "localhost:5010"
72+
});
7773

78-
Assert.IsTrue(task.Execute());
79-
Assert.AreEqual("mcr-microsoft-com", task.ParsedContainerRegistry);
80-
Assert.AreEqual("dotnet-runtime", task.ParsedContainerImage);
81-
Assert.AreEqual("6-0", task.ParsedContainerTag);
74+
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
75+
Assert.IsTrue(instance.Build(new[]{ComputeContainerConfig}, null, null, out var outputs));
8276

83-
Assert.AreEqual("dotnet/testimage", task.NewContainerImageName);
84-
CollectionAssert.AreEquivalent(new[] { "5.0" }, task.NewContainerTags);
77+
Assert.AreEqual("mcr-microsoft-com", instance.GetPropertyValue(ContainerBaseRegistry));
78+
Assert.AreEqual("dotnet-runtime", instance.GetPropertyValue(ContainerBaseName));
79+
Assert.AreEqual("6.0", instance.GetPropertyValue(ContainerBaseTag));
8580
}
8681

8782
[TestMethod]
88-
[Ignore("Task logging in tests unsupported.")]
8983
public void RegexCatchesInvalidContainerNames()
9084
{
91-
ParseContainerProperties task = new ParseContainerProperties();
92-
task.FullyQualifiedBaseImageName = "mcr.microsoft.com/dotnet/runtime:6 0";
93-
task.ContainerRegistry = "localhost:5010";
94-
95-
// Spaces in the "new" container info don't pass the regex.
96-
task.ContainerImageName = "dotnet testimage";
97-
task.ContainerImageTags = new[] { "5.0" };
98-
99-
Assert.IsFalse(task.Execute());
100-
// To do: Verify output contains expected error
85+
var (project, logs) = Evaluator.InitProject(new () {
86+
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:6.0",
87+
[ContainerRegistry] = "localhost:5010",
88+
[ContainerImageName] = "dotnet testimage",
89+
[ContainerImageTag] = "5.0"
90+
}, captureLogs: true);
91+
92+
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
93+
Assert.IsTrue(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
94+
Assert.IsTrue(logs.Warnings.Count > 0);
95+
Assert.AreEqual(logs.Warnings[0].Code, ErrorCodes.CONTAINER001);
10196
}
10297

10398
[TestMethod]
104-
[Ignore("Task logging in tests unsupported.")]
10599
public void RegexCatchesInvalidContainerTags()
106100
{
107-
ParseContainerProperties task = new ParseContainerProperties();
108-
task.FullyQualifiedBaseImageName = "mcr.microsoft.com/dotnet/runtime:6 0";
109-
task.ContainerRegistry = "localhost:5010";
110-
// Spaces in the "new" container info don't pass the regex.
111-
task.ContainerImageName = "dotnet/testimage";
112-
task.ContainerImageTags = new[] { "5.0" };
113-
114-
Assert.IsFalse(task.Execute());
115-
// To do: Verify output contains expected error
101+
var (project, logs) = Evaluator.InitProject(new () {
102+
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:6.0",
103+
[ContainerRegistry] = "localhost:5010",
104+
[ContainerImageName] = "dotnet/testimage",
105+
[ContainerImageTag] = "5 0"
106+
}, captureLogs: true);
107+
108+
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
109+
Assert.IsFalse(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
110+
111+
Assert.IsTrue(logs.Errors.Count > 0);
112+
Assert.AreEqual(logs.Errors[0].Code, ErrorCodes.CONTAINER004);
116113
}
117114

118115
[TestMethod]
119-
[Ignore("Task logging in tests unsupported.")]
120116
public void CanOnlySupplyOneOfTagAndTags()
121117
{
122-
ParseContainerProperties task = new ParseContainerProperties();
123-
task.FullyQualifiedBaseImageName = "mcr.microsoft.com/dotnet/runtime:6 0";
124-
task.ContainerRegistry = "localhost:5010";
125-
// Spaces in the "new" container info don't pass the regex.
126-
task.ContainerImageName = "dotnet/testimage";
127-
task.ContainerImageTag = "a.b";
128-
task.ContainerImageTags = new[] { "5.0" };
129-
130-
Assert.IsFalse(task.Execute());
131-
// To do: Verify output contains expected error
118+
var (project, logs) = Evaluator.InitProject(new () {
119+
[ContainerBaseImage] = "mcr.microsoft.com/dotnet/runtime:6.0",
120+
[ContainerRegistry] = "localhost:5010",
121+
[ContainerImageName] = "dotnet/testimage",
122+
[ContainerImageTag] = "5.0",
123+
[ContainerImageTags] = "latest;oldest"
124+
}, captureLogs: true);
125+
126+
var instance = project.CreateProjectInstance(global::Microsoft.Build.Execution.ProjectInstanceSettings.None);
127+
Assert.IsFalse(instance.Build(new[]{ComputeContainerConfig}, new [] { logs }, null, out var outputs));
128+
129+
Assert.IsTrue(logs.Errors.Count > 0);
130+
Assert.AreEqual(logs.Errors[0].Code, ErrorCodes.CONTAINER005);
132131
}
133132
}
134133
}

0 commit comments

Comments
 (0)