|
// 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 System.Runtime.CompilerServices;
using ManifestReaderTests;
using Microsoft.DotNet.Cli.NuGetPackageDownloader;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.Extensions.EnvironmentAbstractions;
using Microsoft.NET.Sdk.WorkloadManifestReader;
using Microsoft.DotNet.Cli.Commands.Workload.Install;
using Microsoft.DotNet.Cli.Commands.Workload;
using Microsoft.DotNet.Cli.Commands.Workload.Config;
using Microsoft.DotNet.Cli.Commands;
namespace Microsoft.DotNet.Cli.Workload.Install.Tests
{
public class GivenDotnetWorkloadInstall : SdkTest
{
private readonly BufferedReporter _reporter;
private readonly string _manifestPath;
public GivenDotnetWorkloadInstall(ITestOutputHelper log) : base(log)
{
_reporter = new BufferedReporter();
_manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "Sample.json");
}
// These two tests hit an IOException when run in helix on non-windows
[WindowsOnlyFact]
public void GivenWorkloadInstallItErrorsOnFakeWorkloadName()
{
var command = new DotnetCommand(Log);
command
.WithEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR", string.Empty)
.WithEnvironmentVariable("PATH", "fake")
.Execute("workload", "install", "fake", "--skip-manifest-update")
.Should()
.Fail()
.And
.HaveStdErrContaining(string.Format(CliCommandStrings.WorkloadNotRecognized, "fake"));
}
[Fact(Skip = "https://github.com/dotnet/sdk/issues/26624")]
public void ItErrorUsingSkipManifestAndRollback()
{
var command = new DotnetCommand(Log);
command
.WithEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR", string.Empty)
.WithEnvironmentVariable("PATH", "fake")
.Execute("workload", "install", "wasm-tools", "--skip-manifest-update", "--from-rollback-file", "foo.txt")
.Should()
.Fail()
.And
.HaveStdErrContaining(string.Format(CliCommandStrings.CannotCombineSkipManifestAndRollback, "skip-manifest-update", "from-rollback-file"));
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallItCanInstallPacks(bool userLocal, string sdkVersion)
{
var mockWorkloadIds = new WorkloadId[] { new WorkloadId("xamarin-android") };
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "--skip-manifest-update" });
(_, var installManager, var installer, _, _, _, _) = GetTestInstallers(parseResult, userLocal, sdkVersion, installedFeatureBand: sdkVersion);
installManager.Execute()
.Should().Be(0);
installer.GarbageCollectionCalled.Should().BeTrue();
installer.CachePath.Should().BeNull();
installer.InstallationRecordRepository.WorkloadInstallRecord.Should().BeEquivalentTo(mockWorkloadIds);
installer.InstalledPacks.Count.Should().Be(8);
installer.InstalledPacks.Where(pack => pack.Id.ToString().Contains("Android")).Count().Should().Be(8);
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallItCanRollBackPackInstallation(bool userLocal, string sdkVersion)
{
var mockWorkloadIds = new WorkloadId[] { new WorkloadId("xamarin-android"), new WorkloadId("xamarin-android-build") };
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "xamarin-android-build", "--skip-manifest-update" });
(_, var installManager, var installer, var workloadResolver, _, _, _) = GetTestInstallers(parseResult, userLocal, sdkVersion, failingWorkload: "xamarin-android-build", installedFeatureBand: sdkVersion);
var exceptionThrown = Assert.Throws<GracefulException>(() => installManager.Execute());
exceptionThrown.Message.Should().Contain("Failing workload: xamarin-android-build");
var expectedPacks = mockWorkloadIds
.SelectMany(workloadId => workloadResolver.GetPacksInWorkload(workloadId))
.Distinct()
.Select(packId => workloadResolver.TryGetPackInfo(packId))
.Where(pack => pack != null);
installer.RolledBackPacks.Should().BeEquivalentTo(expectedPacks);
installer.InstallationRecordRepository.WorkloadInstallRecord.Should().BeEmpty();
}
[Fact]
public void GivenWorkloadInstallOnFailingRollbackItDisplaysTopLevelError()
{
var mockWorkloadIds = new WorkloadId[] { new WorkloadId("xamarin-android"), new WorkloadId("xamarin-android-build") };
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var installer = new MockPackWorkloadInstaller(failingWorkload: "xamarin-android-build", failingRollback: true);
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), dotnetRoot);
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "xamarin-android-build", "--skip-manifest-update" });
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, "6.0.100", workloadResolver);
var installManager = new WorkloadInstallCommand(parseResult, reporter: _reporter, workloadResolverFactory, workloadInstaller: installer);
var exceptionThrown = Assert.Throws<GracefulException>(() => installManager.Execute());
exceptionThrown.Message.Should().Contain("Failing workload: xamarin-android-build");
string.Join(" ", _reporter.Lines).Should().Contain("Rollback failure");
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallItCanUpdateAdvertisingManifests(bool userLocal, string sdkVersion)
{
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android" });
(_, var installManager, var installer, _, var manifestUpdater, _, var resolverFactory) = GetTestInstallers(parseResult, userLocal, sdkVersion, installedFeatureBand: sdkVersion);
new WorkloadConfigCommand(Parser.Parse(["dotnet", "workload", "config", "--update-mode", "manifests"]), workloadResolverFactory: resolverFactory).Execute().Should().Be(0);
installManager.Execute()
.Should().Be(0);
installer.InstalledManifests.Should().BeEmpty(); // Didn't try to alter any installed manifests
manifestUpdater.CalculateManifestUpdatesCallCount.Should().Be(1);
manifestUpdater.UpdateAdvertisingManifestsCallCount.Should().Be(1);
}
[Fact]
public void GivenWorkloadInstallItWarnsOnGarbageCollectionFailure()
{
_reporter.Clear();
var mockWorkloadIds = new WorkloadId[] { new WorkloadId("xamarin-android"), new WorkloadId("xamarin-android-build") };
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var installer = new MockPackWorkloadInstaller(failingGarbageCollection: true);
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), dotnetRoot);
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "xamarin-android-build", "--skip-manifest-update" });
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, "6.0.100", workloadResolver);
var installManager = new WorkloadInstallCommand(parseResult, reporter: _reporter, workloadResolverFactory, workloadInstaller: installer);
installManager.Execute()
.Should()
.Be(0);
string.Join(" ", _reporter.Lines).Should().Contain("Failing garbage collection");
}
[Fact]
public void GivenInfoOptionWorkloadBaseCommandAcceptsThatOption()
{
var command = new DotnetCommand(Log);
var commandResult = command
.WithEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR", string.Empty)
.WithEnvironmentVariable("PATH", "fake")
.Execute("workload", "--info");
commandResult.Should().Pass();
}
[Fact]
public void GivenNoWorkloadsInstalledInfoOptionRemarksOnThat()
{
// We can't easily mock the end to end process of installing a workload and testing --info on it so we are adding that to the manual testing document.
// However, we can test a setup where no workloads are installed and --info is provided.
_reporter.Clear();
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), dotnetRoot);
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android" });
WorkloadInfoHelper workloadInfoHelper = new WorkloadInfoHelper(isInteractive: false, workloadResolver: workloadResolver);
WorkloadCommandParser.ShowWorkloadsInfo(parseResult, workloadInfoHelper: workloadInfoHelper, reporter: _reporter);
_reporter.Lines.Should().Contain("There are no installed workloads to display.");
}
[Fact]
public void GivenBadOptionWorkloadBaseInformsRequiredCommandWasNotProvided()
{
_reporter.Clear();
var command = new DotnetCommand(Log);
command
.WithEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR", string.Empty)
.WithEnvironmentVariable("PATH", "fake")
.Execute("workload", "--infoz")
.Should()
.Fail()
.And
.HaveStdErrContaining("'--infoz'"); // we should complain about the bad option not being recognized
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallItCanUpdateInstalledManifests(bool userLocal, string sdkVersion)
{
var parseResult =
Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android" });
var featureBand = new SdkFeatureBand(sdkVersion);
var manifestsToUpdate =
new ManifestUpdateWithWorkloads[]
{
new(new ManifestVersionUpdate(new ManifestId("mock-manifest"), new ManifestVersion("2.0.0"), featureBand.ToString()), null),
};
(_, var installManager, var installer, _, _, _, var resolverFactory) =
GetTestInstallers(parseResult, userLocal, sdkVersion, manifestUpdates: manifestsToUpdate, installedFeatureBand: sdkVersion);
new WorkloadConfigCommand(Parser.Parse(["dotnet", "workload", "config", "--update-mode", "manifests"]), workloadResolverFactory: resolverFactory).Execute().Should().Be(0);
installManager.Execute()
.Should().Be(0);
installer.InstalledManifests[0].manifestUpdate.ManifestId.Should().Be(manifestsToUpdate[0].ManifestUpdate.ManifestId);
installer.InstalledManifests[0].manifestUpdate.NewVersion.Should().Be(manifestsToUpdate[0].ManifestUpdate.NewVersion);
installer.InstalledManifests[0].manifestUpdate.NewFeatureBand.Should().Be(new SdkFeatureBand(sdkVersion).ToString());
installer.InstalledManifests[0].offlineCache.Should().Be(null);
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallFromCacheItInstallsCachedManifest(bool userLocal, string sdkVersion)
{
var featureBand = new SdkFeatureBand(sdkVersion);
var manifestsToUpdate =
new ManifestUpdateWithWorkloads[]
{
new(new ManifestVersionUpdate(new ManifestId("mock-manifest"), new ManifestVersion("2.0.0"), featureBand.ToString()), null)
};
var cachePath = Path.Combine(_testAssetsManager.CreateTestDirectory(identifier: AppendForUserLocal("mockCache_", userLocal) + sdkVersion).Path,
"mockCachePath");
var parseResult = Parser.Parse(new string[]
{
"dotnet", "workload", "install", "xamarin-android", "--from-cache", cachePath
});
(_, var installManager, var installer, _, _, _, var resolverFactory) = GetTestInstallers(parseResult, userLocal, sdkVersion,
tempDirManifestPath: _manifestPath, manifestUpdates: manifestsToUpdate, installedFeatureBand: sdkVersion);
new WorkloadConfigCommand(Parser.Parse(["dotnet", "workload", "config", "--update-mode", "manifests"]), workloadResolverFactory: resolverFactory).Execute().Should().Be(0);
installManager.Execute();
installer.InstalledManifests[0].manifestUpdate.ManifestId.Should().Be(manifestsToUpdate[0].ManifestUpdate.ManifestId);
installer.InstalledManifests[0].manifestUpdate.NewVersion.Should().Be(manifestsToUpdate[0].ManifestUpdate.NewVersion);
installer.InstalledManifests[0].manifestUpdate.NewFeatureBand.Should().Be(new SdkFeatureBand(sdkVersion).ToString());
installer.InstalledManifests[0].offlineCache.Should().Be(new DirectoryPath(cachePath));
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallItCanDownloadToOfflineCache(bool userLocal, string sdkVersion)
{
var cachePath = Path.Combine(_testAssetsManager.CreateTestDirectory(identifier: AppendForUserLocal("mockCache_", userLocal) + sdkVersion).Path, "mockCachePath");
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "--download-to-cache", cachePath });
(_, var installManager, _, _, var manifestUpdater, var packageDownloader, _) = GetTestInstallers(parseResult, userLocal, sdkVersion, tempDirManifestPath: _manifestPath, installedFeatureBand: sdkVersion);
installManager.Execute();
// Manifest packages should have been 'downloaded' and used for pack resolution
manifestUpdater.GetManifestPackageDownloadsCallCount.Should().Be(1);
// 8 android pack packages, plus 1 manifest
packageDownloader.DownloadCallParams.Count.Should().Be(9);
foreach (var downloadParams in packageDownloader.DownloadCallParams)
{
downloadParams.downloadFolder.Value.Value.Should().Be(cachePath);
}
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallItCanInstallFromOfflineCache(bool userLocal, string sdkVersion)
{
var mockWorkloadIds = new WorkloadId[] { new WorkloadId("xamarin-android") };
var cachePath = "mockCachePath";
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "--from-cache", cachePath });
(_, var installManager, var installer, _, _, var nugetDownloader, _) = GetTestInstallers(parseResult, userLocal, sdkVersion, installedFeatureBand: sdkVersion);
installManager.Execute();
installer.GarbageCollectionCalled.Should().BeTrue();
installer.CachePath.Should().Contain(cachePath);
installer.InstallationRecordRepository.WorkloadInstallRecord.Should().BeEquivalentTo(mockWorkloadIds);
installer.InstalledPacks.Count.Should().Be(8);
installer.InstalledPacks.Where(pack => pack.Id.ToString().Contains("Android")).Count().Should().Be(8);
nugetDownloader.DownloadCallParams.Count().Should().Be(0);
}
[Theory]
[InlineData(true, "6.0.100")]
[InlineData(true, "6.0.101")]
[InlineData(true, "6.0.102-preview1")]
[InlineData(false, "6.0.100")]
public void GivenWorkloadInstallItPrintsDownloadUrls(bool userLocal, string sdkVersion)
{
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", "xamarin-android", "--print-download-link-only" });
(_, var installManager, _, _, _, _, _) = GetTestInstallers(parseResult, userLocal, sdkVersion, tempDirManifestPath: _manifestPath, installedFeatureBand: sdkVersion);
installManager.Execute();
string.Join(" ", _reporter.Lines).Should().Contain("http://mock-url/xamarin.android.sdk.8.4.7.nupkg");
string.Join(" ", _reporter.Lines).Should().Contain("http://mock-url/mock-manifest-package.1.0.5.nupkg");
}
[Fact]
public void GivenWorkloadInstallItErrorsOnUnsupportedPlatform()
{
var mockWorkloadId = "unsupported";
var manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "UnsupportedPlatform.json");
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var installer = new MockPackWorkloadInstaller();
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { manifestPath }), dotnetRoot);
var nugetDownloader = new MockNuGetPackageDownloader(dotnetRoot);
var manifestUpdater = new MockWorkloadManifestUpdater();
var parseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", mockWorkloadId });
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, "6.0.100", workloadResolver, userProfileDir: testDirectory);
var command = new WorkloadInstallCommand(parseResult, reporter: _reporter, workloadResolverFactory, workloadInstaller: installer,
nugetPackageDownloader: nugetDownloader, workloadManifestUpdater: manifestUpdater);
var exceptionThrown = Assert.Throws<GracefulException>(() => command.Execute());
exceptionThrown.Message.Should().Be(String.Format(CliCommandStrings.WorkloadInstallationFailed, String.Format(CliCommandStrings.WorkloadNotSupportedOnPlatform, mockWorkloadId)));
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void GivenWorkloadInstallItDoesNotRemoveOldInstallsOnRollback(bool userLocal)
{
var testDirectory = _testAssetsManager.CreateTestDirectory(identifier: userLocal ? "userlocal" : "default").Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var userProfileDir = Path.Combine(testDirectory, "user-profile");
var tmpDir = Path.Combine(testDirectory, "tmp");
var manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "MockWorkloadsSample.json");
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { manifestPath }), dotnetRoot, userLocal, userProfileDir);
var nugetDownloader = new FailingNuGetPackageDownloader(tmpDir);
var manifestUpdater = new MockWorkloadManifestUpdater();
var sdkFeatureVersion = "6.0.100";
var existingWorkload = "mock-1";
var installingWorkload = "mock-2";
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, sdkFeatureVersion, workloadResolver, userProfileDir);
if (userLocal)
{
WorkloadFileBasedInstall.SetUserLocal(dotnetRoot, sdkFeatureVersion);
}
// Successfully install a workload
var installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", existingWorkload });
var installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, workloadResolverFactory, nugetPackageDownloader: new MockNuGetPackageDownloader(tmpDir),
workloadManifestUpdater: manifestUpdater, tempDirPath: testDirectory);
installCommand.Execute();
// Install a workload with a mocked nuget failure
installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", installingWorkload });
installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, workloadResolverFactory, nugetPackageDownloader: nugetDownloader,
workloadManifestUpdater: manifestUpdater, tempDirPath: testDirectory);
var exceptionThrown = Assert.Throws<GracefulException>(() => installCommand.Execute());
exceptionThrown.Message.Should().Contain("Test Failure");
// Existing installation is still present
string installRoot = userLocal ? userProfileDir : dotnetRoot;
var installRecordPath = Path.Combine(installRoot, "metadata", "workloads", sdkFeatureVersion, "InstalledWorkloads");
Directory.GetFiles(installRecordPath).Count().Should().Be(1);
File.Exists(Path.Combine(installRecordPath, existingWorkload))
.Should().BeTrue();
var packRecordDirs = Directory.GetDirectories(Path.Combine(installRoot, "metadata", "workloads", "InstalledPacks", "v1"));
packRecordDirs.Count().Should().Be(3);
var installPacks = Directory.GetDirectories(Path.Combine(installRoot, "packs"));
installPacks.Count().Should().Be(3);
}
[Fact]
public void GivenWorkloadInstallItTreatsPreviewsAsSeparateFeatureBands()
{
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var userProfileDir = Path.Combine(testDirectory, "user-profile");
var tmpDir = Path.Combine(testDirectory, "tmp");
var manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "MockWorkloadsSample.json");
var manifestUpdater = new MockWorkloadManifestUpdater();
var prev7SdkFeatureVersion = "6.0.100-preview.7.21379.14";
var prev7FormattedFeatureVersion = "6.0.100-preview.7";
var rc1SdkFeatureVersion = "6.0.100-rc.1.21463.6";
var rc1FormattedFeatureVersion = "6.0.100-rc.1";
static void CreateFile(string path)
{
string directory = Path.GetDirectoryName(path);
Directory.CreateDirectory(directory);
using var _ = File.Create(path);
}
// Create fake SDK directories (so garbage collector will see them as installed versions)
CreateFile(Path.Combine(dotnetRoot, "sdk", prev7SdkFeatureVersion, "dotnet.dll"));
CreateFile(Path.Combine(dotnetRoot, "sdk", rc1SdkFeatureVersion, "dotnet.dll"));
var existingWorkload = "mock-1";
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { manifestPath }), dotnetRoot, userProfileDir: userProfileDir);
var prev7workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, prev7SdkFeatureVersion, workloadResolver, userProfileDir);
var rc1WorkloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, rc1SdkFeatureVersion, workloadResolver, userProfileDir);
// Install a workload for preview 7
var installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", existingWorkload });
var installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, prev7workloadResolverFactory, nugetPackageDownloader: new MockNuGetPackageDownloader(tmpDir),
workloadManifestUpdater: manifestUpdater, tempDirPath: testDirectory);
installCommand.Execute();
// Install workload for RC1
installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, rc1WorkloadResolverFactory, nugetPackageDownloader: new MockNuGetPackageDownloader(tmpDir),
workloadManifestUpdater: manifestUpdater, tempDirPath: testDirectory);
installCommand.Execute();
// Existing installation is present
var prev7InstallRecordPath = Path.Combine(dotnetRoot, "metadata", "workloads", prev7FormattedFeatureVersion, "InstalledWorkloads");
Directory.GetFiles(prev7InstallRecordPath).Count().Should().Be(1);
File.Exists(Path.Combine(prev7InstallRecordPath, existingWorkload))
.Should().BeTrue();
var rc1InstallRecordPath = Path.Combine(dotnetRoot, "metadata", "workloads", rc1FormattedFeatureVersion, "InstalledWorkloads");
Directory.GetFiles(rc1InstallRecordPath).Count().Should().Be(1);
File.Exists(Path.Combine(rc1InstallRecordPath, existingWorkload))
.Should().BeTrue();
// Assert that packs have been installed
var packRecordDirs = Directory.GetDirectories(Path.Combine(dotnetRoot, "metadata", "workloads", "InstalledPacks", "v1"));
packRecordDirs.Count().Should().Be(3);
var installPacks = Directory.GetDirectories(Path.Combine(dotnetRoot, "packs"));
installPacks.Count().Should().Be(2);
// Assert feature band records are correct
var featureBandRecords = Directory.GetFiles(Directory.GetDirectories(packRecordDirs[0])[0]);
featureBandRecords.Count().Should().Be(2);
featureBandRecords.Select(recordPath => Path.GetFileName(recordPath))
.Should().BeEquivalentTo(new string[] { prev7FormattedFeatureVersion, rc1FormattedFeatureVersion });
}
private (string, WorkloadInstallCommand, MockPackWorkloadInstaller, IWorkloadResolver, MockWorkloadManifestUpdater, MockNuGetPackageDownloader, IWorkloadResolverFactory) GetTestInstallers(
ParseResult parseResult,
bool userLocal,
string sdkVersion,
[CallerMemberName] string testName = "",
string failingWorkload = null,
IEnumerable<ManifestUpdateWithWorkloads> manifestUpdates = null,
string tempDirManifestPath = null,
string installedFeatureBand = null)
{
_reporter.Clear();
var testDirectory = _testAssetsManager.CreateTestDirectory(testName: testName, identifier: (userLocal ? "userlocal" : "default") + sdkVersion).Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var userProfileDir = Path.Combine(testDirectory, "user-profile");
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), dotnetRoot);
var installer = new MockPackWorkloadInstaller(failingWorkload: failingWorkload)
{
WorkloadResolver = workloadResolver
};
var nugetDownloader = new MockNuGetPackageDownloader(dotnetRoot);
var manifestUpdater = new MockWorkloadManifestUpdater(manifestUpdates);
if (userLocal)
{
WorkloadFileBasedInstall.SetUserLocal(dotnetRoot, sdkVersion);
}
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, sdkVersion, workloadResolver, userProfileDir);
var installManager = new WorkloadInstallCommand(
parseResult,
reporter: _reporter,
workloadResolverFactory: workloadResolverFactory,
workloadInstaller: installer,
nugetPackageDownloader: nugetDownloader,
workloadManifestUpdater: manifestUpdater);
return (testDirectory, installManager, installer, workloadResolver, manifestUpdater, nugetDownloader, workloadResolverFactory);
}
[Fact]
public void GivenWorkloadInstallItErrorsOnInvalidWorkloadRollbackFile()
{
_reporter.Clear();
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var userProfileDir = Path.Combine(testDirectory, "user-profile");
var tmpDir = Path.Combine(testDirectory, "tmp");
var manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "MockWorkloadsSample.json");
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { manifestPath }), dotnetRoot);
var sdkFeatureVersion = "6.0.100";
var workload = "mock-1";
var mockRollbackFileContent = @"[{""fake.manifest.name"":""1.0.0""}]";
var rollbackFilePath = Path.Combine(testDirectory, "rollback.json");
File.WriteAllText(rollbackFilePath, mockRollbackFileContent);
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, sdkFeatureVersion, workloadResolver, userProfileDir);
var installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", workload, "--from-rollback-file", rollbackFilePath });
var installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, workloadResolverFactory, nugetPackageDownloader: new MockNuGetPackageDownloader(tmpDir),
tempDirPath: testDirectory);
var ex = Assert.Throws<GracefulException>(() => installCommand.Execute());
ex.Message.Should().StartWith("Workload installation failed:");
string.Join(" ", _reporter.Lines).Should().Contain("Workload installation failed.");
}
[Fact]
public void GivenWorkloadInstallItWarnsWhenManifestFromRollbackFileIsntInstalled()
{
_reporter.Clear();
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var userProfileDir = Path.Combine(testDirectory, "user-profile");
var tmpDir = Path.Combine(testDirectory, "tmp");
var manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "MockWorkloadsSample.json");
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { manifestPath }), dotnetRoot);
var sdkFeatureVersion = "6.0.100";
var workload = "mock-1";
var mockRollbackFileContent = @"{""fake.manifest.name"":""1.0.0""}";
var rollbackFilePath = Path.Combine(testDirectory, "rollback.json");
File.WriteAllText(rollbackFilePath, mockRollbackFileContent);
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, sdkFeatureVersion, workloadResolver, userProfileDir);
var installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", workload, "--from-rollback-file", rollbackFilePath });
var installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, workloadResolverFactory, nugetPackageDownloader: new MockNuGetPackageDownloader(tmpDir),
tempDirPath: testDirectory);
installCommand.Execute().Should().Be(0);
string.Join(" ", _reporter.Lines).Should().Contain("Invalid rollback definition. The manifest IDs in rollback definition");
}
[Fact]
public void GivenWorkloadInstallItWarnsWhenTheWorkloadIsAlreadyInstalled()
{
var testDirectory = _testAssetsManager.CreateTestDirectory().Path;
var dotnetRoot = Path.Combine(testDirectory, "dotnet");
var userProfileDir = Path.Combine(testDirectory, "user-profile");
var tmpDir = Path.Combine(testDirectory, "tmp");
var manifestPath = Path.Combine(_testAssetsManager.GetAndValidateTestProjectDirectory("SampleManifest"), "MockWorkloadsSample.json");
var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { manifestPath }), dotnetRoot, false, userProfileDir);
var manifestUpdater = new MockWorkloadManifestUpdater();
var sdkFeatureVersion = "6.0.100";
var workloadId = "mock-1";
var workloadResolverFactory = new MockWorkloadResolverFactory(dotnetRoot, sdkFeatureVersion, workloadResolver, userProfileDir);
// Successfully install a workload
var installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", workloadId });
var installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, workloadResolverFactory, nugetPackageDownloader: new MockNuGetPackageDownloader(tmpDir),
workloadManifestUpdater: manifestUpdater, tempDirPath: testDirectory);
installCommand.Execute()
.Should().Be(0);
_reporter.Clear();
// Install again, this time it should tell you that you already have the workload installed
installParseResult = Parser.Parse(new string[] { "dotnet", "workload", "install", workloadId, "mock-2" });
installCommand = new WorkloadInstallCommand(installParseResult, reporter: _reporter, workloadResolverFactory, nugetPackageDownloader: new MockNuGetPackageDownloader(tmpDir),
workloadManifestUpdater: manifestUpdater, tempDirPath: testDirectory);
installCommand.Execute()
.Should().Be(0);
// Install command warns
string.Join(" ", _reporter.Lines).Should().Contain(string.Format(CliCommandStrings.WorkloadAlreadyInstalled, workloadId));
// Both workloads are installed
var installRecordPath = Path.Combine(dotnetRoot, "metadata", "workloads", sdkFeatureVersion, "InstalledWorkloads");
Directory.GetFiles(installRecordPath).Count().Should().Be(2);
}
[Fact(Skip = "https://github.com/dotnet/sdk/issues/25175")]
public void HideManifestUpdateCheckWhenVerbosityIsQuiet()
{
var command = new DotnetCommand(Log);
command
.WithEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR", string.Empty)
.WithEnvironmentVariable("PATH", "fake")
.Execute("workload", "install", "--verbosity:quiet", "wasm-tools")
.Should()
.NotHaveStdOutContaining(CliCommandStrings.CheckForUpdatedWorkloadManifests)
.And
.NotHaveStdOutContaining(CliCommandStrings.AdManifestUpdated);
}
[Theory(Skip = "https://github.com/dotnet/sdk/issues/25175")]
[InlineData("--verbosity:minimal")]
[InlineData("--verbosity:normal")]
public void HideManifestUpdatesWhenVerbosityIsMinimalOrNormal(string verbosityFlag)
{
var command = new DotnetCommand(Log);
command
.WithEnvironmentVariable("DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR", string.Empty)
.WithEnvironmentVariable("PATH", "fake")
.Execute("workload", "install", verbosityFlag, "wasm-tools")
.Should()
.HaveStdOutContaining(CliCommandStrings.CheckForUpdatedWorkloadManifests)
.And
.NotHaveStdOutContaining(CliCommandStrings.AdManifestUpdated);
}
[Theory(Skip = "https://github.com/dotnet/sdk/issues/25175")]
[InlineData("--verbosity:detailed")]
[InlineData("--verbosity:diagnostic")]
public void ShowManifestUpdatesWhenVerbosityIsDetailedOrDiagnostic(string verbosityFlag)
{
string sdkFeatureBand = "6.0.300";
var parseResult =
Parser.Parse(new string[] { "dotnet", "workload", "install", verbosityFlag, "xamarin-android" });
var manifestsToUpdate =
new ManifestUpdateWithWorkloads[]
{
new(new ManifestVersionUpdate(new ManifestId("mock-manifest"), new ManifestVersion("2.0.0"), sdkFeatureBand), null),
};
(_, var installManager, _, _, _, _, _) =
GetTestInstallers(parseResult, true, sdkFeatureBand, manifestUpdates: manifestsToUpdate);
installManager.Execute().Should().Be(0);
string.Join(" ", _reporter.Lines).Should().Contain(CliCommandStrings.CheckForUpdatedWorkloadManifests);
string.Join(" ", _reporter.Lines).Should().Contain(string.Format(CliCommandStrings.CheckForUpdatedWorkloadManifests, "mock-manifest"));
}
private string AppendForUserLocal(string identifier, bool userLocal)
{
if (!userLocal)
{
return identifier;
}
return $"{identifier}_userlocal";
}
}
}
|