feat(experiments): record rust cli if `cargo` exists (#810)
This commit is contained in:
Родитель
05cf44ae7a
Коммит
c0fe4af38e
|
@ -1,5 +1,6 @@
|
|||
namespace Microsoft.ComponentDetection.Orchestrator.Experiments.Configs;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ComponentDetection.Contracts;
|
||||
|
||||
/// <summary>
|
||||
|
@ -15,6 +16,12 @@ public interface IExperimentConfiguration
|
|||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the experiment configuration.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task InitAsync() => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if the detector is in the control group.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
namespace Microsoft.ComponentDetection.Orchestrator.Experiments.Configs;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ComponentDetection.Contracts;
|
||||
using Microsoft.ComponentDetection.Detectors.Rust;
|
||||
|
||||
|
@ -8,6 +9,15 @@ using Microsoft.ComponentDetection.Detectors.Rust;
|
|||
/// </summary>
|
||||
public class RustCliDetectorExperiment : IExperimentConfiguration
|
||||
{
|
||||
private readonly ICommandLineInvocationService commandLineInvocationService;
|
||||
private bool cargoCliAvailable;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RustCliDetectorExperiment"/> class.
|
||||
/// </summary>
|
||||
/// <param name="commandLineInvocationService">The command line invocation service.</param>
|
||||
public RustCliDetectorExperiment(ICommandLineInvocationService commandLineInvocationService) => this.commandLineInvocationService = commandLineInvocationService;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "RustCliDetector";
|
||||
|
||||
|
@ -18,5 +28,8 @@ public class RustCliDetectorExperiment : IExperimentConfiguration
|
|||
public bool IsInExperimentGroup(IComponentDetector componentDetector) => componentDetector is RustCliDetector;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ShouldRecord(IComponentDetector componentDetector, int numComponents) => true;
|
||||
public bool ShouldRecord(IComponentDetector componentDetector, int numComponents) => this.cargoCliAvailable;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task InitAsync() => this.cargoCliAvailable = await this.commandLineInvocationService.CanCommandBeLocatedAsync("cargo", null);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,23 @@ public class ExperimentService : IExperimentService
|
|||
this.logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
foreach (var config in this.experiments.Keys)
|
||||
{
|
||||
try
|
||||
{
|
||||
await config.InitAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.logger.LogWarning(e, "Failed to initialize experiment {Experiment}, skipping it", config.Name);
|
||||
this.experiments.TryRemove(config, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RecordDetectorRun(
|
||||
IComponentDetector detector,
|
||||
|
|
|
@ -11,6 +11,12 @@ using Microsoft.ComponentDetection.Orchestrator.Commands;
|
|||
/// </summary>
|
||||
public interface IExperimentService
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the experiment services by preparing the experiment configurations.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task InitializeAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Records the results of a detector execution and processes the results for any active experiments.
|
||||
/// </summary>
|
||||
|
|
|
@ -55,6 +55,7 @@ public class DetectorProcessingService : IDetectorProcessingService
|
|||
? this.GenerateDirectoryExclusionPredicate(settings.SourceDirectory.ToString(), settings.DirectoryExclusionList, settings.DirectoryExclusionListObsolete, allowWindowsPaths: false, ignoreCase: false)
|
||||
: this.GenerateDirectoryExclusionPredicate(settings.SourceDirectory.ToString(), settings.DirectoryExclusionList, settings.DirectoryExclusionListObsolete, allowWindowsPaths: true, ignoreCase: true);
|
||||
|
||||
await this.experimentService.InitializeAsync();
|
||||
this.experimentService.RemoveUnwantedExperimentsbyDetectors(detectorRestrictions.DisabledDetectors);
|
||||
|
||||
IEnumerable<Task<(IndividualDetectorScanResult, ComponentRecorder, IComponentDetector)>> scanTasks = detectors
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
@ -279,9 +280,9 @@ public class ExperimentServiceTests
|
|||
var detectorList = new List<IComponentDetector>
|
||||
{
|
||||
new NuGetComponentDetector(
|
||||
new Mock<IComponentStreamEnumerableFactory>().Object,
|
||||
new Mock<IObservableDirectoryWalkerFactory>().Object,
|
||||
new Mock<ILogger<NuGetComponentDetector>>().Object), this.detectorMock.Object,
|
||||
new Mock<IComponentStreamEnumerableFactory>().Object,
|
||||
new Mock<IObservableDirectoryWalkerFactory>().Object,
|
||||
new Mock<ILogger<NuGetComponentDetector>>().Object), this.detectorMock.Object,
|
||||
};
|
||||
|
||||
service.RemoveUnwantedExperimentsbyDetectors(detectorList);
|
||||
|
@ -310,9 +311,9 @@ public class ExperimentServiceTests
|
|||
var detectorList = new List<IComponentDetector>
|
||||
{
|
||||
new NuGetComponentDetector(
|
||||
new Mock<IComponentStreamEnumerableFactory>().Object,
|
||||
new Mock<IObservableDirectoryWalkerFactory>().Object,
|
||||
new Mock<ILogger<NuGetComponentDetector>>().Object),
|
||||
new Mock<IComponentStreamEnumerableFactory>().Object,
|
||||
new Mock<IObservableDirectoryWalkerFactory>().Object,
|
||||
new Mock<ILogger<NuGetComponentDetector>>().Object),
|
||||
};
|
||||
|
||||
service.RemoveUnwantedExperimentsbyDetectors(detectorList);
|
||||
|
@ -325,4 +326,35 @@ public class ExperimentServiceTests
|
|||
x => x.ProcessExperimentAsync(this.experimentConfigMock.Object, It.IsAny<ExperimentDiff>()),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task InitializeAsync_InitsConfigsAsync()
|
||||
{
|
||||
var service = new ExperimentService(
|
||||
new[] { this.experimentConfigMock.Object },
|
||||
new[] { this.experimentProcessorMock.Object },
|
||||
this.graphTranslationServiceMock.Object,
|
||||
this.loggerMock.Object);
|
||||
|
||||
await service.InitializeAsync();
|
||||
|
||||
this.experimentConfigMock.Verify(x => x.InitAsync(), Times.Once());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task InitializeAsync_SwallowsExceptionsAsync()
|
||||
{
|
||||
this.experimentConfigMock.Setup(x => x.InitAsync()).ThrowsAsync(new InvalidOperationException());
|
||||
|
||||
var service = new ExperimentService(
|
||||
new[] { this.experimentConfigMock.Object },
|
||||
new[] { this.experimentProcessorMock.Object },
|
||||
this.graphTranslationServiceMock.Object,
|
||||
this.loggerMock.Object);
|
||||
|
||||
var action = async () => await service.InitializeAsync();
|
||||
|
||||
await action.Should().NotThrowAsync();
|
||||
this.experimentConfigMock.Verify(x => x.InitAsync(), Times.Once());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -321,17 +321,17 @@ public class DetectorProcessingServiceTests
|
|||
public void GenerateDirectoryExclusionPredicate_IgnoreCaseAndAllowWindowsPathsWorksAsExpected()
|
||||
{
|
||||
/*
|
||||
* We can't test a scenario like:
|
||||
*
|
||||
* SourceDirectory = /Some/Source/Directory
|
||||
* DirectoryExclusionList = *Some/*
|
||||
* allowWindowsPath = false
|
||||
*
|
||||
* and expect to exclude the directory, because when
|
||||
* we pass the SourceDirectory path to DirectoryInfo and we are running the test on Windows,
|
||||
* DirectoryInfo transalate it to C:\\Some\Source\Directory
|
||||
* making the test fail
|
||||
*/
|
||||
* We can't test a scenario like:
|
||||
*
|
||||
* SourceDirectory = /Some/Source/Directory
|
||||
* DirectoryExclusionList = *Some/*
|
||||
* allowWindowsPath = false
|
||||
*
|
||||
* and expect to exclude the directory, because when
|
||||
* we pass the SourceDirectory path to DirectoryInfo and we are running the test on Windows,
|
||||
* DirectoryInfo transalate it to C:\\Some\Source\Directory
|
||||
* making the test fail
|
||||
*/
|
||||
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
|
@ -534,6 +534,19 @@ public class DetectorProcessingServiceTests
|
|||
Times.Once());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ProcessDetectorsAsync_InitializesExperimentsAsync()
|
||||
{
|
||||
this.detectorsToUse = new[]
|
||||
{
|
||||
this.firstFileComponentDetectorMock.Object, this.secondFileComponentDetectorMock.Object,
|
||||
};
|
||||
|
||||
await this.serviceUnderTest.ProcessDetectorsAsync(DefaultArgs, this.detectorsToUse, new DetectorRestrictions());
|
||||
|
||||
this.experimentServiceMock.Verify(x => x.InitializeAsync(), Times.Once);
|
||||
}
|
||||
|
||||
private Mock<FileComponentDetector> SetupFileDetectorMock(string id)
|
||||
{
|
||||
var mockFileDetector = new Mock<FileComponentDetector>();
|
||||
|
|
Загрузка…
Ссылка в новой задаче