Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
848a048
Add more log to improve error handling for optional-logger failures
huulinhnguyen-dev May 9, 2025
f0fe68a
Change the test output
huulinhnguyen-dev May 12, 2025
c9dae4a
change the way output is checked so it can run on multiple os
huulinhnguyen-dev May 12, 2025
6b8bd70
change the way output is checked so it can run on multiple os and fix…
huulinhnguyen-dev May 12, 2025
ab68285
Update logic code for BadImageException
huulinhnguyen-dev May 12, 2025
f0596b7
Merge branch 'main' into dev/huulinhnguyen/issue9560
huulinhnguyen-dev May 12, 2025
a6b41d2
Merge branch 'main' into dev/huulinhnguyen/issue9560
huulinhnguyen-dev May 12, 2025
bfddd35
Merge branch 'main' into dev/huulinhnguyen/issue9560
huulinhnguyen-dev May 13, 2025
1563b84
Added the code have been deleted by mistake
huulinhnguyen-dev May 13, 2025
ee11fba
Merge branch 'dev/huulinhnguyen/issue9560' of https://github.com/huul…
huulinhnguyen-dev May 13, 2025
ebddb09
Update unit test by using TestAssets folder instead of prepare in code
huulinhnguyen-dev May 16, 2025
04e1501
Refactor code and remove unused code
huulinhnguyen-dev May 19, 2025
e0ff90c
Remove space
huulinhnguyen-dev May 19, 2025
690382f
Remove unsued code
huulinhnguyen-dev May 19, 2025
dd85f06
Update PR
huulinhnguyen-dev May 20, 2025
a7bf48b
Update PR
huulinhnguyen-dev May 20, 2025
db54c67
Update PR
huulinhnguyen-dev May 20, 2025
7958e58
Update csproj file
huulinhnguyen-dev May 20, 2025
1a16ab9
Add common method ReportOptionalLoggerCreation
huulinhnguyen-dev May 23, 2025
17546ef
Fix PR base on the comment
huulinhnguyen-dev Jun 5, 2025
204104e
Remove unused code
huulinhnguyen-dev Jun 5, 2025
bf34738
Add more comment
huulinhnguyen-dev Jun 5, 2025
94a68b0
Change the format of the message and change the test logic
huulinhnguyen-dev Jun 5, 2025
0f26809
Update the logic code
huulinhnguyen-dev Jun 5, 2025
b17145f
Change the method name and the param
huulinhnguyen-dev Jun 6, 2025
551bdd4
Fix comment on the PR
huulinhnguyen-dev Jun 6, 2025
b54c1de
Update the comment
huulinhnguyen-dev Jun 6, 2025
32b9100
Merge branch 'main' into dev/huulinhnguyen/issue9560
huulinhnguyen-dev Jun 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,10 @@
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>

<ItemGroup>
<None Include="TestAssets\**" CopyToOutputDirectory="PreserveNewest" />
<Compile Remove="TestAssets\TargetInvocationException\LoggerProject\FaultyLogger.cs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.Framework;

namespace Microsoft.Build.CommandLine.UnitTests.TestAssets.MemberAccessException.LoggerProject
{
public class CustomLogger : ILogger
{
private CustomLogger()
{
Console.WriteLine("Private constructor");
}

public string? Parameters { get; set; }
public LoggerVerbosity Verbosity { get; set; }
public void Initialize(IEventSource eventSource) { }
public void Shutdown() { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Library</OutputType>
<AssemblyName>CustomLogger</AssemblyName>
<OutputPath>artifacts/bin</OutputPath>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="17.0.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.Framework;

namespace Microsoft.Build.CommandLine.UnitTests.TestAssets.TargetInvocationException.LoggerProject
{
public class FaultyLogger : ILogger
{
public FaultyLogger()
{
throw new Exception("Constructor failed intentionally.");
}

public string Parameters { get; set; }
public LoggerVerbosity Verbosity { get; set; }

public void Initialize(IEventSource eventSource) { }

public void Shutdown() { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Library</OutputType>
<AssemblyName>FaultyLogger</AssemblyName>
<OutputPath>artifacts/bin</OutputPath>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Framework" Version="17.0.0" />
</ItemGroup>
</Project>
116 changes: 116 additions & 0 deletions src/MSBuild.UnitTests/XMake_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Microsoft.Build.Shared;
using Microsoft.Build.UnitTests.Shared;
using Microsoft.Build.Utilities;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Shouldly;
using Xunit;
using Xunit.Abstractions;
Expand All @@ -45,6 +46,8 @@ public XMakeAppTests(ITestOutputHelper output)
_env = UnitTests.TestEnvironment.Create(_output);
}

private static string TestAssetsRootPath { get; } = Path.Combine(Path.Combine(Path.GetDirectoryName(typeof(XMakeAppTests).Assembly.Location) ?? AppContext.BaseDirectory), "TestAssets");

private const string AutoResponseFileName = "MSBuild.rsp";

[Fact]
Expand Down Expand Up @@ -2490,6 +2493,99 @@ public void MissingOptionalLoggersAreIgnored(string logger, string expectedLogge
output.ShouldContain($"The specified logger \"{expectedLoggerName}\" could not be created and will not be used.", customMessage: output);
}

[Theory]
[InlineData("-logger:,CustomLogger.dll", "CustomLogger.dll")]
[InlineData("-logger:,Logger.dll", "Logger.dll")]
public void LoggerThrowsIOExceptionWhenDllNotFound(string logger, string expectedLoggerName)
{
string projectString ="<Project><Target Name=\"t\"><Message Text=\"Hello\"/></Target></Project>";
var tempDir = _env.CreateFolder();
var projectFile = tempDir.CreateFile("iologgertest.proj", projectString);

var parametersLogger = $"{logger} -verbosity:diagnostic \"{projectFile.Path}\"";

var output = RunnerUtilities.ExecMSBuild(parametersLogger, out bool successfulExit, _output);
successfulExit.ShouldBe(false);

output.ShouldContain($"Cannot create an instance of the logger {expectedLoggerName}.", customMessage: output);
}

[Theory]
[InlineData("-logger:,BadFile.dll", "BadFile.dll")]
[InlineData("-distributedlogger:,BadFile.dll", "BadFile.dll")]
public void LoggerThrowsBadImageFormatExceptionWhenFileIsInvalid(string logger, string expectedLoggerName)
{
string projectString ="<Project><Target Name=\"t\"><Message Text=\"Hello\"/></Target></Project>";
var tempDir = _env.CreateFolder();
var projectFile = tempDir.CreateFile("badimagetest.proj", projectString);

var dllFilePath = Path.Combine(tempDir.Path, expectedLoggerName);
File.WriteAllText(dllFilePath, "Invalid content, not a valid .NET assembly.");

var loggerParam = $"\"{logger}\"";
var parametersLogger = $"{loggerParam} -verbosity:diagnostic \"{projectFile.Path}\"";

var output = RunnerUtilities.ExecMSBuild(parametersLogger, out bool successfulExit, _output);
successfulExit.ShouldBe(false);

output.ShouldContain($"Cannot create an instance of the logger {expectedLoggerName}.", customMessage: output);
}

[Theory]
[InlineData("MemberAccessException", "-logger:,", "CustomLogger.dll")]
[InlineData("MemberAccessException", "-distributedlogger:,", "CustomLogger.dll")]
public void LoggerThrowsMemberAccessExceptionWhenClassIsInvalid(string memberAccess, string loggerTemplate, string expectedLoggerName)
{
using (var env = TestEnvironment.Create())
{
string projectContent = "<Project><Target Name=\"t\"><Message Text=\"Hello\"/></Target></Project>";
var tempDir = _env.CreateFolder();

(string projectFilePath, string tempLoggerProjDir) = CopyTestAssetsToTestEnv(tempDir, projectContent, memberAccess);

string loggerBuildLog = RunnerUtilities.ExecBootstrapedMSBuild(
$"\"{Path.Combine(tempLoggerProjDir, "CustomLogger.csproj")}\" -restore -verbosity:n", out bool success);

var loggerDllPath = Path.Combine(tempLoggerProjDir, "artifacts", "bin", "netstandard2.0", expectedLoggerName);
var loggerSwitch = $"{loggerTemplate}\"{loggerDllPath}\"";
var mainBuildParameters = $"\"{projectFilePath}\" -restore {loggerSwitch} -verbosity:diagnostic";

string mainBuildLog = RunnerUtilities.ExecBootstrapedMSBuild(
mainBuildParameters,
out bool successfulExit);

mainBuildLog.ShouldContain($"Cannot create an instance of the logger {loggerDllPath}.", customMessage: mainBuildLog);
}
}

[Theory]
[InlineData("TargetInvocationException", "-logger:,", "FaultyLogger.dll")]
[InlineData("TargetInvocationException", "-distributedlogger:,", "FaultyLogger.dll")]
public void LoggerThrowsTargetInvocationException(string targetInvocation, string loggerTemplate, string expectedLoggerName)
{
using (var env = TestEnvironment.Create())
{
string projectContent = "<Project><Target Name=\"t\"><Message Text=\"Hello\"/></Target></Project>";
var tempDir = _env.CreateFolder();

(string projectFilePath, string tempLoggerProjDir) = CopyTestAssetsToTestEnv(tempDir, projectContent, targetInvocation);

string loggerBuildLog = RunnerUtilities.ExecBootstrapedMSBuild(
$"{Path.Combine(tempLoggerProjDir, $"FaultyLogger.csproj")} -restore -verbosity:n", out bool success);

var loggerDllPath = Path.Combine(tempLoggerProjDir, "artifacts", "bin", "netstandard2.0", expectedLoggerName);
var loggerSwitch = $"{loggerTemplate}{loggerDllPath}";
var mainBuildParameters = $"{projectFilePath} -restore {loggerSwitch} -verbosity:diagnostic";

string mainBuildLog = RunnerUtilities.ExecBootstrapedMSBuild(
mainBuildParameters,
out bool successfulExit);

successfulExit.ShouldBeFalse(mainBuildLog);
mainBuildLog.ShouldContain("The logger failed unexpectedly.");
}
}

[Theory]
[InlineData("/interactive")]
[InlineData("/p:NuGetInteractive=true")]
Expand Down Expand Up @@ -2849,6 +2945,26 @@ private string ExecuteMSBuildExeExpectFailure(string projectContents, IDictionar
return (success, output);
}

private (string projectFilePath, string tempLoggerProjDir) CopyTestAssetsToTestEnv(TransientTestFolder tempDir, string projectContent, string folderName)
{
var testAssetsPath = Path.Combine(TestAssetsRootPath, folderName);
var loggerProjDir = Path.Combine(testAssetsPath, "LoggerProject");

var projectFile = tempDir.CreateFile("loggerproject.proj", projectContent);

var tempLoggerProjDir = Path.Combine(tempDir.Path, "LoggerProject");
Directory.CreateDirectory(tempLoggerProjDir);

foreach (var file in Directory.GetFiles(loggerProjDir, "*.*", SearchOption.AllDirectories))
{
var relativePath = file.Substring(loggerProjDir.Length + 1);
var destPath = Path.Combine(tempLoggerProjDir, relativePath);
Directory.CreateDirectory(Path.GetDirectoryName(destPath));
File.Copy(file, destPath, true);
}
return (projectFile.Path, tempLoggerProjDir);
}

public void Dispose()
{
_env.Dispose();
Expand Down
22 changes: 22 additions & 0 deletions src/MSBuild/InitializationException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,28 @@ internal static void Throw(string messageResourceName, string invalidSwitch, Exc
InitializationException.Throw(errorMessage, invalidSwitch);
}

/// <summary>
/// Throws the exception using the given exception context and can include the logger name.
/// </summary>
internal static void Throw(string messageResourceName, string invalidSwitch, Exception e, bool showStackTrace, params object[] formatArgs)
{
string errorMessage = AssemblyResources.GetString(messageResourceName);

ErrorUtilities.VerifyThrow(errorMessage != null, "The resource string must exist.");

// the exception message can contain a format item i.e.
// "{0}" to hold the logger name
// "{1}" to hold the given exception's message
errorMessage = ResourceUtilities.FormatString(errorMessage, formatArgs);

if (showStackTrace && e != null)
{
errorMessage += Environment.NewLine + e.ToString();
}

InitializationException.Throw(errorMessage, invalidSwitch);
}

/// <summary>
/// Throws the exception if the specified condition is not met.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/MSBuild/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1513,7 +1513,7 @@
<comment>{StrBegin="MSBUILD : error MSB1059: "}</comment>
</data>
<data name="XMake.LoggerCreationError" xml:space="preserve">
<value>MSBUILD : error MSB1021: Cannot create an instance of the logger. {0}</value>
<value>MSBUILD : error MSB1021: Cannot create an instance of the logger {0}. {1}</value>
<comment>{StrBegin="MSBUILD : error MSB1021: "}
UE: This error is shown when a logger cannot be loaded and instantiated from its assembly.
LOCALIZATION: The prefix "MSBUILD : error MSBxxxx:" should not be localized. {0} contains a message explaining why the
Expand Down
4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/MSBuild/Resources/xlf/Strings.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading