Skip to content

Commit

Permalink
Add ExtendedCriticalBuildMessageEventArgs and related tests (#9363)
Browse files Browse the repository at this point in the history
  • Loading branch information
rokonec authored Oct 27, 2023
1 parent efd0158 commit d3fa669
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 15 deletions.
8 changes: 8 additions & 0 deletions src/Build.UnitTests/BackEnd/NodePackets_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public void VerifyEventType()
ExtendedBuildMessageEventArgs extMessage = new("extMsg", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender", MessageImportance.Normal);
ExtendedCustomBuildEventArgs extCustom = new("extCustom", "message", "help", "sender");
CriticalBuildMessageEventArgs criticalMessage = new("Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "Sender", DateTime.Now, "arg1");
ExtendedCriticalBuildMessageEventArgs extCriticalMessage = new("extCritMsg", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "Sender", DateTime.Now, "arg1");
PropertyInitialValueSetEventArgs propInit = new("prop", "val", "propsource", "message", "help", "sender", MessageImportance.Normal);
MetaprojectGeneratedEventArgs metaProjectGenerated = new("metaName", "path", "message");
PropertyReassignmentEventArgs propReassign = new("prop", "prevValue", "newValue", "loc", "message", "help", "sender", MessageImportance.Normal);
Expand Down Expand Up @@ -98,6 +99,7 @@ public void VerifyEventType()
VerifyLoggingPacket(extMessage, LoggingEventType.ExtendedBuildMessageEvent);
VerifyLoggingPacket(extCustom, LoggingEventType.ExtendedCustomEvent);
VerifyLoggingPacket(criticalMessage, LoggingEventType.CriticalBuildMessage);
VerifyLoggingPacket(extCriticalMessage, LoggingEventType.ExtendedCriticalBuildMessageEvent);
VerifyLoggingPacket(propInit, LoggingEventType.PropertyInitialValueSet);
VerifyLoggingPacket(metaProjectGenerated, LoggingEventType.MetaprojectGenerated);
VerifyLoggingPacket(propReassign, LoggingEventType.PropertyReassignment);
Expand Down Expand Up @@ -299,6 +301,12 @@ public void TestTranslation()
ExtendedMetadata = new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } },
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7)
},
new ExtendedCriticalBuildMessageEventArgs("extCritMsg", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "Sender", DateTime.Now, "arg1")
{
ExtendedData = "{'long-json':'mostly-strings'}",
ExtendedMetadata = new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } },
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7)
},
};
foreach (BuildEventArgs arg in testArgs)
{
Expand Down
42 changes: 42 additions & 0 deletions src/Build.UnitTests/BuildEventArgsSerialization_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,48 @@ public void RoundtripCriticalBuildMessageEventArgs()
e => e.Subcategory);
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public void RoundtripExtendedCriticalBuildMessageEventArgs(bool withOptionalData)
{
var args = new ExtendedCriticalBuildMessageEventArgs(
"extCrit",
"Subcategory",
"Code",
"File",
1,
2,
3,
4,
"Message",
"Help",
"SenderName",
DateTime.Parse("12/12/2015 06:11:56 PM"),
withOptionalData ? new object[] { "argument0" } : null)
{
ExtendedData = withOptionalData ? "{'long-json':'mostly-strings'}" : null,
ExtendedMetadata = withOptionalData ? new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } } : null,
BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null,
};


Roundtrip(args,
e => e.Code,
e => e.ColumnNumber.ToString(),
e => e.EndColumnNumber.ToString(),
e => e.EndLineNumber.ToString(),
e => e.File,
e => e.LineNumber.ToString(),
e => e.Message,
e => e.ProjectFile,
e => e.Subcategory,
e => e.ExtendedType,
e => TranslationHelpers.ToString(e.ExtendedMetadata),
e => e.ExtendedData,
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
}

[Fact]
public void RoundtripTaskCommandLineEventArgs()
{
Expand Down
56 changes: 42 additions & 14 deletions src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -798,21 +798,49 @@ private BuildEventArgs ReadCriticalBuildMessageEventArgs()
{
var fields = ReadBuildEventArgsFields(readImportance: true);

var e = new CriticalBuildMessageEventArgs(
fields.Subcategory,
fields.Code,
fields.File,
fields.LineNumber,
fields.ColumnNumber,
fields.EndLineNumber,
fields.EndColumnNumber,
fields.Message,
fields.HelpKeyword,
fields.SenderName,
fields.Timestamp,
fields.Arguments);
BuildEventArgs e;
if (fields.Extended == null)
{
e = new CriticalBuildMessageEventArgs(
fields.Subcategory,
fields.Code,
fields.File,
fields.LineNumber,
fields.ColumnNumber,
fields.EndLineNumber,
fields.EndColumnNumber,
fields.Message,
fields.HelpKeyword,
fields.SenderName,
fields.Timestamp,
fields.Arguments)
{
ProjectFile = fields.ProjectFile,
};
}
else
{
e = new ExtendedCriticalBuildMessageEventArgs(
fields.Extended?.ExtendedType ?? string.Empty,
fields.Subcategory,
fields.Code,
fields.File,
fields.LineNumber,
fields.ColumnNumber,
fields.EndLineNumber,
fields.EndColumnNumber,
fields.Message,
fields.HelpKeyword,
fields.SenderName,
fields.Timestamp,
fields.Arguments)
{
ProjectFile = fields.ProjectFile,
ExtendedMetadata = fields.Extended?.ExtendedMetadata,
ExtendedData = fields.Extended?.ExtendedData,
};
}
e.BuildEventContext = fields.BuildEventContext;
e.ProjectFile = fields.ProjectFile;
return e;
}

Expand Down
47 changes: 47 additions & 0 deletions src/Framework.UnitTests/ExtendedBuildEventArgs_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,43 @@ public void ExtendedMessageEventArgs_SerializationDeserialization(bool withOptio
argDeserialized.Should().BeEquivalentTo(arg);
}

[InlineData(true)]
[InlineData(false)]
[Theory]
public void ExtendedCriticalMessageEventArgs_SerializationDeserialization(bool withOptionalData)
{
ExtendedCriticalBuildMessageEventArgs arg = new(
type: "TypeOfExtendedCustom",
subcategory: withOptionalData ? "sub-type" : null,
code: withOptionalData ? "a-code" : null,
file: withOptionalData ? ".\\dev\\my.csproj" : null,
lineNumber: withOptionalData ? 1 : default,
columnNumber: withOptionalData ? 2 : default,
endLineNumber: withOptionalData ? 3 : default,
endColumnNumber: withOptionalData ? 4 : default,
message: withOptionalData ? "a message with args {0} {1}" : null,
helpKeyword: withOptionalData ? "MSBT123" : null,
senderName: withOptionalData ? $"UnitTest {Guid.NewGuid()}" : null,
eventTimestamp: withOptionalData ? DateTime.Parse("3/1/2017 11:11:56 AM") : DateTime.Now,
messageArgs: withOptionalData ? new object[] { "arg0val", "arg1val" } : null)
{
ExtendedData = withOptionalData ? "{'long-json':'mostly-strings'}" : null,
ExtendedMetadata = withOptionalData ? new Dictionary<string, string?> { { "m1", "v1" }, { "m2", "v2" } } : null,
BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null,
};

using MemoryStream stream = new MemoryStream();
using BinaryWriter bw = new BinaryWriter(stream);
arg.WriteToStream(bw);

stream.Position = 0;
using BinaryReader br = new BinaryReader(stream);
ExtendedBuildMessageEventArgs argDeserialized = new();
argDeserialized.CreateFromStream(br, 80);

argDeserialized.Should().BeEquivalentTo(arg);
}

[Fact]
public void ExtendedCustomBuildEventArgs_Ctors()
{
Expand Down Expand Up @@ -215,4 +252,14 @@ public void ExtendedBuildMessageEventArgs_Ctors()
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, default, DateTime.Now);
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, default, DateTime.Now, null);
}

[Fact]
public void ExtendedCriticalBuildMessageEventArgs_Ctors()
{
var ea = new ExtendedCriticalBuildMessageEventArgs();
ea = new ExtendedCriticalBuildMessageEventArgs("type");
ea = new ExtendedCriticalBuildMessageEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender");
ea = new ExtendedCriticalBuildMessageEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender", DateTime.Now);
ea = new ExtendedCriticalBuildMessageEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "sender", DateTime.Now, "arg1", "arg2");
}
}
148 changes: 148 additions & 0 deletions src/Framework/ExtendedCriticalBuildMessageEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// 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.IO;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Framework;

/// <summary>
/// Critical message events arguments including extended data for event enriching.
/// Extended data are implemented by <see cref="IExtendedBuildEventArgs"/>
/// </summary>
public sealed class ExtendedCriticalBuildMessageEventArgs : CriticalBuildMessageEventArgs, IExtendedBuildEventArgs
{
/// <inheritdoc />
public string ExtendedType { get; set; }

/// <inheritdoc />
public IDictionary<string, string?>? ExtendedMetadata { get; set; }

/// <inheritdoc />
public string? ExtendedData { get; set; }

/// <summary>
/// This constructor allows all event data to be initialized
/// </summary>
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
/// <param name="subcategory">event subcategory</param>
/// <param name="code">event code</param>
/// <param name="file">file associated with the event</param>
/// <param name="lineNumber">line number (0 if not applicable)</param>
/// <param name="columnNumber">column number (0 if not applicable)</param>
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
/// <param name="message">text message</param>
/// <param name="helpKeyword">help keyword </param>
/// <param name="senderName">name of event sender</param>
public ExtendedCriticalBuildMessageEventArgs(
string type,
string? subcategory,
string? code,
string? file,
int lineNumber,
int columnNumber,
int endLineNumber,
int endColumnNumber,
string? message,
string? helpKeyword,
string? senderName)
: this(type, subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, DateTime.UtcNow)
{
// do nothing
}

/// <summary>
/// This constructor allows timestamp to be set
/// </summary>
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
/// <param name="subcategory">event subcategory</param>
/// <param name="code">event code</param>
/// <param name="file">file associated with the event</param>
/// <param name="lineNumber">line number (0 if not applicable)</param>
/// <param name="columnNumber">column number (0 if not applicable)</param>
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
/// <param name="message">text message</param>
/// <param name="helpKeyword">help keyword </param>
/// <param name="senderName">name of event sender</param>
/// <param name="eventTimestamp">custom timestamp for the event</param>
public ExtendedCriticalBuildMessageEventArgs(
string type,
string? subcategory,
string? code,
string? file,
int lineNumber,
int columnNumber,
int endLineNumber,
int endColumnNumber,
string? message,
string? helpKeyword,
string? senderName,
DateTime eventTimestamp)
: this(type, subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, eventTimestamp, null!)
{
// do nothing
}

/// <summary>
/// This constructor allows timestamp to be set
/// </summary>
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
/// <param name="subcategory">event subcategory</param>
/// <param name="code">event code</param>
/// <param name="file">file associated with the event</param>
/// <param name="lineNumber">line number (0 if not applicable)</param>
/// <param name="columnNumber">column number (0 if not applicable)</param>
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
/// <param name="message">text message</param>
/// <param name="helpKeyword">help keyword </param>
/// <param name="senderName">name of event sender</param>
/// <param name="eventTimestamp">custom timestamp for the event</param>
/// <param name="messageArgs">message arguments</param>
public ExtendedCriticalBuildMessageEventArgs(
string type,
string? subcategory,
string? code,
string? file,
int lineNumber,
int columnNumber,
int endLineNumber,
int endColumnNumber,
string? message,
string? helpKeyword,
string? senderName,
DateTime eventTimestamp,
params object[]? messageArgs)
//// Force importance to High.
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, eventTimestamp, messageArgs) => ExtendedType = type;

/// <summary>
/// Default constructor. Used for deserialization.
/// </summary>
internal ExtendedCriticalBuildMessageEventArgs() : this("undefined")
{
// do nothing
}

/// <summary>
/// This constructor specifies only type of extended data.
/// </summary>
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
public ExtendedCriticalBuildMessageEventArgs(string type) => ExtendedType = type;

internal override void WriteToStream(BinaryWriter writer)
{
base.WriteToStream(writer);
writer.WriteExtendedBuildEventData(this);
}

internal override void CreateFromStream(BinaryReader reader, int version)
{
base.CreateFromStream(reader, version);
reader.ReadExtendedBuildEventData(this);
}
}
12 changes: 11 additions & 1 deletion src/Shared/LogMessagePacketBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,12 @@ internal enum LoggingEventType : int
/// <summary>
/// Event is <see cref="UninitializedPropertyReadEventArgs"/>
/// </summary>
UninitializedPropertyRead = 32
UninitializedPropertyRead = 32,

/// <summary>
/// Event is <see cref="ExtendedCriticalBuildMessageEventArgs"/>
/// </summary>
ExtendedCriticalBuildMessageEvent = 33,
}
#endregion

Expand Down Expand Up @@ -597,6 +602,7 @@ private BuildEventArgs GetBuildEventArgFromId()
LoggingEventType.ExtendedBuildErrorEvent => new ExtendedBuildErrorEventArgs(),
LoggingEventType.ExtendedBuildWarningEvent => new ExtendedBuildWarningEventArgs(),
LoggingEventType.ExtendedBuildMessageEvent => new ExtendedBuildMessageEventArgs(),
LoggingEventType.ExtendedCriticalBuildMessageEvent => new ExtendedCriticalBuildMessageEventArgs(),
LoggingEventType.ExternalProjectStartedEvent => new ExternalProjectStartedEventArgs(null, null, null, null, null),
LoggingEventType.ExternalProjectFinishedEvent => new ExternalProjectFinishedEventArgs(null, null, null, null, false),
LoggingEventType.CriticalBuildMessage => new CriticalBuildMessageEventArgs(null, null, null, -1, -1, -1, -1, null, null, null),
Expand Down Expand Up @@ -695,6 +701,10 @@ private LoggingEventType GetLoggingEventId(BuildEventArgs eventArg)
{
return LoggingEventType.CriticalBuildMessage;
}
else if (eventType == typeof(ExtendedCriticalBuildMessageEventArgs))
{
return LoggingEventType.ExtendedCriticalBuildMessageEvent;
}
else if (eventType == typeof(MetaprojectGeneratedEventArgs))
{
return LoggingEventType.MetaprojectGenerated;
Expand Down

0 comments on commit d3fa669

Please sign in to comment.