188 lines
7.7 KiB
C#
188 lines
7.7 KiB
C#
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
using Microsoft.Build.Framework;
|
|
using NSubstitute;
|
|
using Xunit;
|
|
|
|
namespace OpenTelemetry.AutoInstrumentation.BuildTasks.Tests;
|
|
|
|
public class CheckForInstrumentationPackagesTests
|
|
{
|
|
public static TheoryData<ITaskItem[]?> LogicallyEmptyITaskItemArray()
|
|
{
|
|
var theoryData = new TheoryData<ITaskItem[]?>
|
|
{
|
|
null,
|
|
Array.Empty<ITaskItem>()
|
|
};
|
|
|
|
return theoryData;
|
|
}
|
|
|
|
[Theory]
|
|
[MemberData(nameof(LogicallyEmptyITaskItemArray))]
|
|
public void NoDataInRuntimeLocalCopyItemsTest(ITaskItem[]? runtimeCopyLocalItems)
|
|
{
|
|
var sut = new TaskWithMockBuildEngine();
|
|
|
|
sut.Task.RuntimeCopyLocalItems = runtimeCopyLocalItems;
|
|
Assert.True(sut.Task.Execute());
|
|
|
|
var messageEventArgsList = sut.MessageEventArgsList;
|
|
var buildMessageEventArgs = Assert.Single(messageEventArgsList);
|
|
Assert.Equal("OpenTelemetry.AutoInstrumentation: empty RuntimeCopyLocalItems, skipping check for instrumentation packages.", buildMessageEventArgs.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void EmptyInstrumentationTargetItemsTest()
|
|
{
|
|
var sut = new TaskWithMockBuildEngine();
|
|
|
|
sut.Task.InstrumentationTargetItems = Array.Empty<ITaskItem>();
|
|
|
|
sut.Task.RuntimeCopyLocalItems = BuildMockRuntimeCopyLocalItems(new (string, string)[]
|
|
{
|
|
("Test.Package.A", "1.2.0")
|
|
});
|
|
|
|
Assert.True(sut.Task.Execute());
|
|
|
|
Assert.Empty(sut.MessageEventArgsList);
|
|
}
|
|
|
|
[Fact]
|
|
public void NoPackageToBeInstrumentedTest()
|
|
{
|
|
var sut = new TaskWithMockBuildEngine();
|
|
|
|
sut.Task.RuntimeCopyLocalItems = BuildMockRuntimeCopyLocalItems(new (string, string)[]
|
|
{
|
|
("Test.Package.A", "1.2.0"),
|
|
("Test.Package.A.Instrumentation", "1.1.0"),
|
|
("Test.Package.B", "2.2.0"),
|
|
("Test.Package.D", "3.3.0")
|
|
});
|
|
|
|
sut.Task.InstrumentationTargetItems = BuildMockInstrumentationTargetItems(new (string, string, string, string)[]
|
|
{
|
|
// Matches A package Id but already has instrumentation package.
|
|
("Test.Package.A", "[1.1.0, 2.0.0)", "Test.Package.A.Instrumentation", "1.1.0"),
|
|
// Matches B package Id but not range.
|
|
("Test.Package.B", "[1.0.0, 2.0.0)", "Test.Package.B.Instrumentation", "1.0.0"),
|
|
// Doesn't match any package Id.
|
|
("Test.Package.C", "[1.0.0, 2.0.0)", "Test.Package.C.Instrumentation", "1.0.0")
|
|
});
|
|
|
|
Assert.True(sut.Task.Execute());
|
|
|
|
var expectedMessages = new string[]
|
|
{
|
|
"OpenTelemetry.AutoInstrumentation: project already references 'Test.Package.A.Instrumentation' version 1.1.0 " +
|
|
"required to instrument 'Test.Package.A' version [1.1.0, 2.0.0).",
|
|
"OpenTelemetry.AutoInstrumentation: project references 'Test.Package.B' but not in the range [1.0.0, 2.0.0), " +
|
|
"no need for the instrumentation package 'Test.Package.B.Instrumentation' version 1.0.0.",
|
|
"OpenTelemetry.AutoInstrumentation: project doesn't reference 'Test.Package.C', " +
|
|
"no need for the instrumentation package 'Test.Package.C.Instrumentation' version 1.0.0."
|
|
};
|
|
var messageEventArgsList = sut.MessageEventArgsList;
|
|
Assert.Equal(expectedMessages.Length, messageEventArgsList.Count);
|
|
Assert.All(messageEventArgsList, (eventArgs, i) => Assert.Equal(expectedMessages[i], eventArgs.Message));
|
|
}
|
|
|
|
[Fact]
|
|
public void MissingInstrumentationPackageTest()
|
|
{
|
|
var sut = new TaskWithMockBuildEngine();
|
|
sut.Task.RuntimeCopyLocalItems = BuildMockRuntimeCopyLocalItems(new (string, string)[]
|
|
{
|
|
("Test.Package.A", "1.2.0"),
|
|
("Test.Package.D", "3.3.0")
|
|
});
|
|
|
|
sut.Task.InstrumentationTargetItems = BuildMockInstrumentationTargetItems(new (string, string, string, string)[]
|
|
{
|
|
// Matches A package Id and range, but is not in the project references.
|
|
("Test.Package.A", "[1.1.0, 2.0.0)", "Test.Package.A.Instrumentation", "1.1.0")
|
|
});
|
|
|
|
Assert.False(sut.Task.Execute());
|
|
|
|
Assert.Empty(sut.MessageEventArgsList);
|
|
|
|
var errorEventArgs = Assert.Single(sut.ErrorEventArgsList);
|
|
|
|
var expectedMessage =
|
|
"OpenTelemetry.AutoInstrumentation: add a reference to the instrumentation package 'Test.Package.A.Instrumentation' " +
|
|
"version 1.1.0 or add 'Test.Package.A' to the property 'SkippedInstrumentations' to suppress this error.";
|
|
|
|
Assert.Equal(expectedMessage, errorEventArgs.Message);
|
|
}
|
|
|
|
private static ITaskItem[] BuildMockRuntimeCopyLocalItems((string NuGetPackageId, string NuGetPackageVersion)[] source)
|
|
{
|
|
var taskItems = new ITaskItem[source.Length];
|
|
for (var i = 0; i < source.Length; i++)
|
|
{
|
|
var (nuGetPackageId, nuGetPackageVersion) = source[i];
|
|
var mockTaskItem = Substitute.For<ITaskItem>();
|
|
mockTaskItem.GetMetadata("NuGetPackageId").Returns(nuGetPackageId);
|
|
mockTaskItem.GetMetadata("NuGetPackageVersion").Returns(nuGetPackageVersion);
|
|
taskItems[i] = mockTaskItem;
|
|
}
|
|
|
|
return taskItems;
|
|
}
|
|
|
|
private static ITaskItem[] BuildMockInstrumentationTargetItems(
|
|
(string ItemSpec, string TargetNuGetPackageVersionRange, string InstrumentationNuGetPackageId, string InstrumentationNuGetPackageVersion)[] source)
|
|
{
|
|
var taskItems = new ITaskItem[source.Length];
|
|
for (var i = 0; i < source.Length; i++)
|
|
{
|
|
var (itemSpec, targetNuGetPackageVersionRange, instrumentationNuGetPackageId, instrumentationNuGetPackageVersion) = source[i];
|
|
var mockTaskItem = Substitute.For<ITaskItem>();
|
|
mockTaskItem.ItemSpec.Returns(itemSpec);
|
|
mockTaskItem.GetMetadata("TargetNuGetPackageVersionRange").Returns(targetNuGetPackageVersionRange);
|
|
mockTaskItem.GetMetadata("InstrumentationNuGetPackageId").Returns(instrumentationNuGetPackageId);
|
|
mockTaskItem.GetMetadata("InstrumentationNuGetPackageVersion").Returns(instrumentationNuGetPackageVersion);
|
|
taskItems[i] = mockTaskItem;
|
|
}
|
|
|
|
return taskItems;
|
|
}
|
|
|
|
private class TaskWithMockBuildEngine
|
|
{
|
|
private List<BuildMessageEventArgs> _buildMessageEventArgsList = new List<BuildMessageEventArgs>();
|
|
private List<BuildErrorEventArgs> _buildErrorEventArgsList = new List<BuildErrorEventArgs>();
|
|
|
|
public TaskWithMockBuildEngine()
|
|
{
|
|
var task = new CheckForInstrumentationPackages();
|
|
|
|
var mockBuildEngine = Substitute.For<IBuildEngine>();
|
|
task.BuildEngine = mockBuildEngine;
|
|
|
|
// Capture the BuildMessageEventArgs argument passed to LogMessageEvent.
|
|
mockBuildEngine.When(x => x.LogMessageEvent(Arg.Any<BuildMessageEventArgs>()))
|
|
.Do(x => _buildMessageEventArgsList.Add(x.ArgAt<BuildMessageEventArgs>(0)));
|
|
|
|
// Capture the BuildErrorEventArgs argument passed to LogErrorEvent.
|
|
mockBuildEngine.When(x => x.LogErrorEvent(Arg.Any<BuildErrorEventArgs>()))
|
|
.Do(x => _buildErrorEventArgsList.Add(x.ArgAt<BuildErrorEventArgs>(0)));
|
|
|
|
Task = task;
|
|
MockBuildEngine = mockBuildEngine;
|
|
}
|
|
|
|
public CheckForInstrumentationPackages Task { get; }
|
|
|
|
public IBuildEngine MockBuildEngine { get; }
|
|
|
|
public IReadOnlyList<BuildMessageEventArgs> MessageEventArgsList => _buildMessageEventArgsList;
|
|
|
|
public IReadOnlyList<BuildErrorEventArgs> ErrorEventArgsList => _buildErrorEventArgsList;
|
|
}
|
|
}
|