|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System.CommandLine;
using ManifestReaderTests;
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
using Microsoft.DotNet.Cli.Workload.Install.Tests;
using Microsoft.NET.Sdk.WorkloadManifestReader;
using System.Text.Json;
using Microsoft.DotNet.Cli.Commands.Workload.Clean;
using Microsoft.DotNet.Cli.Commands.Workload.Install;
namespace Microsoft.DotNet.Cli.Workload.Clean.Tests
{
public class GivenDotnetWorkloadClean : SdkTest
{
private readonly BufferedReporter _reporter;
private readonly string _manifestPath;
private MockWorkloadManifestUpdater _manifestUpdater = new();
private readonly string _sdkFeatureVersion = "6.0.100";
private readonly string _installingWorkload = "xamarin-android";
private readonly string dotnet = nameof(dotnet);
private readonly string _profileDirectoryLeafName = "user-profile";
private (string testDirectory, string dotnetRoot, string userProfileDir, WorkloadResolver workloadResolver, MockNuGetPackageDownloader nugetDownloader) Setup(bool userLocal, bool cleanAll)
{
var testDirectory = _testAssetsManager.CreateTestDirectory(identifier: userLocal ? $"userlocal-{cleanAll}" : $"default-{cleanAll}").Path;
var dotnetRoot = Path.Combine(testDirectory, dotnet);
var userProfileDir = Path.Combine(testDirectory, _profileDirectoryLeafName);
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), dotnetRoot, userLocal, userProfileDir);
var nugetDownloader = new MockNuGetPackageDownloader(dotnetRoot);
return (testDirectory, dotnetRoot, userProfileDir, workloadResolver, nugetDownloader);
}
public GivenDotnetWorkloadClean(ITestOutputHelper log) : base(log)
{
_reporter = new BufferedReporter();
_manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "Sample.json");
}
[Theory]
[InlineData(true, true)]
[InlineData(false, true)]
[InlineData(true, false)]
[InlineData(false, false)]
public void GivenWorkloadCleanFileBasedItRemovesPacksAndPackRecords(bool userLocal, bool cleanAll)
{
var (testDirectory, dotnetRoot, userProfileDir, workloadResolver, nugetDownloader) = Setup(userLocal, cleanAll);
string installRoot = userLocal ? userProfileDir : dotnetRoot;
if (userLocal)
{
WorkloadFileBasedInstall.SetUserLocal(dotnetRoot, _sdkFeatureVersion);
}
// Test
InstallWorkload(userProfileDir, dotnetRoot, testDirectory, workloadResolver, nugetDownloader);
var extraPackRecordPath = MakePackRecord(installRoot);
var extraPackPath = MakePack(installRoot);
var cleanCommand = cleanAll ? GenerateWorkloadCleanAllCommand(workloadResolver, userProfileDir, dotnetRoot) : GenerateWorkloadCleanCommand(workloadResolver, userProfileDir, dotnetRoot);
cleanCommand.Execute();
AssertExtraneousPacksAreRemoved(extraPackPath, extraPackRecordPath);
AssertValidPackCountsMatchExpected(installRoot, expectedPackCount: cleanAll ? 0 : 7, expectedPackRecordCount: cleanAll ? 0 : 8);
AssertAdjacentCommandsStillPass(userProfileDir, dotnetRoot, testDirectory, workloadResolver, nugetDownloader);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void GivenWorkloadCleanAllFileBasedItCleansAllFeatureBands(bool userLocal)
{
var (testDirectory, dotnetRoot, userProfileDir, workloadResolver, nugetDownloader) = Setup(userLocal, true);
const string aboveSdkFeatureBand = ToolsetInfo.NextTargetFrameworkVersion + ".100";
const string belowSdkFeatureBand = "5.0.100"; // At the time of writing this test, it would only run on 7-8.0 SDKs or above.
string installRoot = userLocal ? userProfileDir : dotnetRoot;
if (userLocal)
{
WorkloadFileBasedInstall.SetUserLocal(dotnetRoot, _sdkFeatureVersion);
}
// Test
InstallWorkload(userProfileDir, dotnetRoot, testDirectory, workloadResolver, nugetDownloader);
var extraAboveBandPackRecordPath = MakePackRecord(installRoot, aboveSdkFeatureBand);
var extraBelowBandPackRecordPath = MakePackRecord(installRoot, belowSdkFeatureBand);
var extraPackPath = MakePack(installRoot);
var workloadInstallationRecordDirectory = Path.Combine(installRoot, "metadata", "workloads", _sdkFeatureVersion, "InstalledWorkloads");
var oldWorkloadInstallationRecordDirectory = workloadInstallationRecordDirectory.Replace(_sdkFeatureVersion, belowSdkFeatureBand);
MakePseudoWorkloadRecord(oldWorkloadInstallationRecordDirectory);
var cleanCommand = GenerateWorkloadCleanAllCommand(workloadResolver, userProfileDir, dotnetRoot);
cleanCommand.Execute();
AssertExtraneousPacksAreRemoved(extraPackPath, extraBelowBandPackRecordPath, true);
AssertExtraneousPacksAreRemoved(extraPackPath, extraAboveBandPackRecordPath);
AssertWorkloadInstallationRecordIsRemoved(workloadInstallationRecordDirectory);
AssertWorkloadInstallationRecordIsRemoved(oldWorkloadInstallationRecordDirectory);
AssertValidPackCountsMatchExpected(installRoot, expectedPackCount: 0, expectedPackRecordCount: 0);
}
private void InstallWorkload(string userProfileDir, string dotnetRoot, string testDirectory, WorkloadResolver workloadResolver, MockNuGetPackageDownloader nugetDownloader, string sdkBand = null)
{
sdkBand ??= _sdkFeatureVersion;
var installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", _installingWorkload });
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, sdkBand, workloadResolver, userProfileDir);
var installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, workloadResolverFactory: workloadResolverFactory, nugetPackageDownloader: nugetDownloader,
workloadManifestUpdater: _manifestUpdater, tempDirPath: testDirectory);
installCommand.Execute();
}
private WorkloadCleanCommand GenerateWorkloadCleanCommand(WorkloadResolver workloadResolver, string userProfileDir, string dotnetRoot)
{
var cleanParseResult = Parser.Parse(new string[] { "dotnet", "workload", "clean" });
return MakeWorkloadCleanCommand(cleanParseResult, workloadResolver, userProfileDir, dotnetRoot);
}
private WorkloadCleanCommand MakeWorkloadCleanCommand(ParseResult parseResult, WorkloadResolver workloadResolver, string userProfileDir, string dotnetRoot)
{
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, _sdkFeatureVersion, workloadResolver, userProfileDir);
return new WorkloadCleanCommand(parseResult, reporter: _reporter, workloadResolverFactory: workloadResolverFactory);
}
private WorkloadCleanCommand GenerateWorkloadCleanAllCommand(WorkloadResolver workloadResolver, string userProfileDir, string dotnetRoot)
{
var cleanParseResult = Parser.Parse(new string[] { "dotnet", "workload", "clean", "--all" });
return MakeWorkloadCleanCommand(cleanParseResult, workloadResolver, userProfileDir, dotnetRoot);
}
private string MakePackRecord(string installRoot, string sdkBand = null)
{
sdkBand ??= _sdkFeatureVersion;
var packRecordPath = Path.Combine(installRoot, "metadata", "workloads", "InstalledPacks", "v1", "Test.Pack.A", "1.0.0", sdkBand);
var packPath = Path.Combine(installRoot, "packs", "Test.Pack.A", "1.0.0");
Directory.CreateDirectory(Path.GetDirectoryName(packRecordPath));
var packRecordContents = JsonSerializer.Serialize<WorkloadResolver.PackInfo>(new(new WorkloadPackId("Test.Pack.A"), "1.0.0", WorkloadPackKind.Sdk, packPath, "Test.Pack.A"));
File.WriteAllText(packRecordPath, packRecordContents);
return packRecordPath;
}
private string MakePack(string installRoot)
{
var packPath = Path.Combine(installRoot, "packs", "Test.Pack.A", "1.0.0");
Directory.CreateDirectory(packPath);
return packPath;
}
private void MakePseudoWorkloadRecord(string installationPath)
{
Directory.CreateDirectory(installationPath);
File.WriteAllText(Path.Combine(installationPath, "foo"), "");
}
private void AssertExtraneousPacksAreRemoved(string extraPackPath, string extraPackRecordPath, bool entirePackRootPathShouldRemain = false)
{
new FileInfo(extraPackRecordPath).Should().NotExist();
if (!entirePackRootPathShouldRemain)
{
new DirectoryInfo(Path.GetDirectoryName(Path.GetDirectoryName(extraPackRecordPath))).Should().NotExist();
new DirectoryInfo(extraPackPath).Should().NotExist();
}
}
private void AssertWorkloadInstallationRecordIsRemoved(string workloadInstallationRecordDirectory)
{
Assert.Equal(Directory.GetFiles(workloadInstallationRecordDirectory), Array.Empty<string>());
}
private void AssertValidPackCountsMatchExpected(string installRoot, int expectedPackCount, int expectedPackRecordCount)
{
Directory.GetDirectories(Path.Combine(installRoot, "packs")).Length.Should().Be(expectedPackCount);
Directory.GetDirectories(Path.Combine(installRoot, "metadata", "workloads", "InstalledPacks", "v1")).Length.Should().Be(expectedPackRecordCount);
}
/// <summary>
/// Validate that commands that are likely to fail with invalid packs or invalid pack records do not fail, as an "end to end" safety precaution.
/// </summary>
private void AssertAdjacentCommandsStillPass(string userProfileDir, string dotnetRoot, string testDirectory, WorkloadResolver workloadResolver, MockNuGetPackageDownloader nugetDownloader, string sdkBand = null)
{
InstallWorkload(userProfileDir, dotnetRoot, testDirectory, workloadResolver, nugetDownloader, sdkBand);
}
}
}
|