Skip to content

Commit

Permalink
feat(experiments): record rust cli if cargo exists (#810)
Browse files Browse the repository at this point in the history
  • Loading branch information
melotic authored Sep 27, 2023
1 parent 05cf44a commit c0fe4af
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Microsoft.ComponentDetection.Orchestrator.Experiments.Configs;

using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;

/// <summary>
Expand All @@ -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>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Microsoft.ComponentDetection.Orchestrator.Experiments.Configs;

using System.Threading.Tasks;
using Microsoft.ComponentDetection.Contracts;
using Microsoft.ComponentDetection.Detectors.Rust;

Expand All @@ -8,6 +9,15 @@ namespace Microsoft.ComponentDetection.Orchestrator.Experiments.Configs;
/// </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";

Expand All @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ public ExperimentService(
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ namespace Microsoft.ComponentDetection.Orchestrator.Experiments;
/// </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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public async Task<DetectorProcessingResult> ProcessDetectorsAsync(
? 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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Microsoft.ComponentDetection.Orchestrator.Tests.Experiments;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -279,9 +280,9 @@ public async Task RecordDetectorRun_CheckUnwantedDetectors_RemoveExperimentAsync
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);
Expand Down Expand Up @@ -310,9 +311,9 @@ public async Task RecordDetectorRun_CheckUnwantedDetectors_KeepExperimentAsync()
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);
Expand All @@ -325,4 +326,35 @@ public async Task RecordDetectorRun_CheckUnwantedDetectors_KeepExperimentAsync()
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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -321,17 +321,17 @@ public async Task ProcessDetectorsAsync_DirectoryExclusionPredicateWorksAsExpect
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))
{
Expand Down Expand Up @@ -534,6 +534,19 @@ public async Task ProcessDetectorsAsync_RecordsDetectorRunsAsync()
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>();
Expand Down

0 comments on commit c0fe4af

Please sign in to comment.