winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit b025a3f7e6f259e297d835ada4861f9f83c0791b
parent 32ee81b430f5bce2546dcd741ff1bc7792db8ec0
Author: Ryan Fu <69221034+ryfu-msft@users.noreply.github.com>
Date:   Tue,  6 Dec 2022 08:02:50 -0800

Allow upgrade for unknown version packages (#2747)


Diffstat:
Msrc/AppInstallerCLICore/Commands/UpgradeCommand.cpp | 3+--
Msrc/AppInstallerCLITests/AppInstallerCLITests.vcxproj | 3+++
Msrc/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters | 3+++
Asrc/AppInstallerCLITests/TestData/InstallFlowTest_UnknownVersion.yaml | 20++++++++++++++++++++
Msrc/AppInstallerCLITests/WorkFlow.cpp | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 169 insertions(+), 4 deletions(-)

diff --git a/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp b/src/AppInstallerCLICore/Commands/UpgradeCommand.cpp @@ -45,8 +45,7 @@ namespace AppInstaller::CLI // either for upgrading or for listing available upgrades. bool HasArgumentsForMultiplePackages(Execution::Args& execArgs) { - return execArgs.Contains(Args::Type::All) || - execArgs.Contains(Args::Type::IncludeUnknown); + return execArgs.Contains(Args::Type::All); } // Determines whether there are any arguments only used as options during an upgrade, diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -303,6 +303,9 @@ <CopyFileToFolders Include="TestData\InstallFlowTest_Portable_WithCommand.yaml"> <DeploymentContent>true</DeploymentContent> </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InstallFlowTest_UnknownVersion.yaml"> + <DeploymentContent>true</DeploymentContent> + </CopyFileToFolders> <CopyFileToFolders Include="TestData\InstallFlowTest_UnsupportedArguments.yaml"> <DeploymentContent>true</DeploymentContent> </CopyFileToFolders> diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -552,6 +552,9 @@ <CopyFileToFolders Include="TestData\InstallFlowTest_Portable_WithCommand.yaml"> <Filter>TestData</Filter> </CopyFileToFolders> + <CopyFileToFolders Include="TestData\InstallFlowTest_UnknownVersion.yaml"> + <Filter>TestData</Filter> + </CopyFileToFolders> <CopyFileToFolders Include="TestData\InstallFlowTest_UnsupportedArguments.yaml"> <Filter>TestData</Filter> </CopyFileToFolders> diff --git a/src/AppInstallerCLITests/TestData/InstallFlowTest_UnknownVersion.yaml b/src/AppInstallerCLITests/TestData/InstallFlowTest_UnknownVersion.yaml @@ -0,0 +1,19 @@ +# Test manifest for upgrading a package with an unknown version. +PackageIdentifier: AppInstallerCliTest.TestExeUnknownVersion +PackageVersion: 1.0.0.0 +PackageLocale: en-US +PackageName: AppInstaller Test Exe Unknown Version +Publisher: Microsoft Corporation +AppMoniker: AICLITestExe +License: Test +Switches: + SilentWithProgress: /silentwithprogress + Silent: /silence + Update: /update +Installers: + - Architecture: x64 + InstallerUrl: https://ThisIsNotUsed + InstallerType: exe + InstallerSha256: 65DB2F2AC2686C7F2FD69D4A4C6683B888DC55BFA20A0E32CA9F838B51689A3B +ManifestType: singleton +ManifestVersion: 1.3.0+ \ No newline at end of file diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp @@ -258,6 +258,23 @@ namespace PackageMatchFilter(PackageMatchField::Id, MatchType::Exact, "AppInstallerCliTest.TestMSStoreInstaller"))); } + if (input.empty() || input == "TestExeInstallerWithUnknownVersion") + { + auto installed = YamlParser::CreateFromPath(TestDataFile("InstallFlowTest_UnknownVersion.yaml")); + auto available = installed; + // Override the installed version to be unknown. + installed.Version = "unknown"; + result.Matches.emplace_back( + ResultMatch( + TestPackage::Make( + installed, + TestPackage::MetadataMap{ { PackageVersionMetadata::InstalledType, "Exe" } }, + std::vector<Manifest>{ available }, + shared_from_this() + ), + PackageMatchFilter(PackageMatchField::Id, MatchType::Exact, "AppInstallerCliTest.TestExeUnknownVersion"))); + } + if (input == "TestExeInstallerWithLatestInstalled") { auto manifest = YamlParser::CreateFromPath(TestDataFile("InstallFlowTest_Exe.yaml")); @@ -2191,6 +2208,84 @@ TEST_CASE("UpdateFlow_UpdateExeWithUnsupportedArgs", "[UpdateFlow][workflow]") REQUIRE(updateOutput.str().find("-l,--location") != std::string::npos); } +TEST_CASE("UpdateFlow_UnknownVersion", "[UpdateFlow][workflow]") +{ + TestCommon::TempFile updateResultPath("TestExeInstalled.txt"); + TestCommon::TempDirectory tempDirectory("TempDirectory", false); + + std::ostringstream updateOutput; + TestContext context{ updateOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + OverrideForCompositeInstalledSource(context); + context.Args.AddArg(Execution::Args::Type::Query, "TestExeInstallerWithUnknownVersion"sv); + context.Args.AddArg(Execution::Args::Type::InstallLocation, tempDirectory); + + UpgradeCommand update({}); + context.SetExecutingCommand(&update); + update.Execute(context); + INFO(updateOutput.str()); + + // Verify help message is shown the user to use --include-unknown + REQUIRE(context.GetTerminationHR() == APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE); + REQUIRE(!std::filesystem::exists(updateResultPath.GetPath())); + REQUIRE(updateOutput.str().find(Resource::LocString(Resource::String::UpgradeUnknownVersionExplanation).get()) != std::string::npos); +} + +TEST_CASE("UpdateFlow_UnknownVersion_IncludeUnknownArg", "[UpdateFlow][workflow]") +{ + TestCommon::TempFile updateResultPath("TestExeInstalled.txt"); + TestCommon::TempDirectory tempDirectory("TempDirectory", false); + + std::ostringstream updateOutput; + TestContext context{ updateOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + OverrideForCompositeInstalledSource(context); + OverrideForShellExecute(context); + context.Args.AddArg(Execution::Args::Type::Query, "TestExeInstallerWithUnknownVersion"sv); + context.Args.AddArg(Execution::Args::Type::InstallLocation, tempDirectory); + context.Args.AddArg(Execution::Args::Type::IncludeUnknown); + + UpgradeCommand update({}); + context.SetExecutingCommand(&update); + update.Execute(context); + INFO(updateOutput.str()); + REQUIRE(std::filesystem::exists(updateResultPath.GetPath())); +} + +TEST_CASE("UpdateFlow_NoArgs_UnknownVersion", "[UpdateFlow][workflow]") +{ + std::ostringstream updateOutput; + TestContext context{ updateOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + OverrideForCompositeInstalledSource(context); + + UpgradeCommand update({}); + context.SetExecutingCommand(&update); + update.Execute(context); + INFO(updateOutput.str()); + + // Verify --include-unknown help text is displayed if update is executed with no args and an unknown version package is available for upgrade. + REQUIRE(updateOutput.str().find(Resource::LocString(Resource::String::UpgradeUnknownVersionCount).get()) != std::string::npos); +} + +TEST_CASE("UpdateFlow_IncludeUnknown", "[UpdateFlow][workflow]") +{ + std::ostringstream updateOutput; + TestContext context{ updateOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + OverrideForCompositeInstalledSource(context); + context.Args.AddArg(Execution::Args::Type::IncludeUnknown); + + UpgradeCommand update({}); + context.SetExecutingCommand(&update); + update.Execute(context); + INFO(updateOutput.str()); + + // Verify unknown version package is displayed available for upgrade. + REQUIRE(updateOutput.str().find(Resource::LocString(Resource::String::UpgradeUnknownVersionCount).get()) == std::string::npos); + REQUIRE(updateOutput.str().find("unknown") != std::string::npos); +} + TEST_CASE("UpdateFlow_UpdatePortableWithManifest", "[UpdateFlow][workflow]") { TestCommon::TempFile updateResultPath("TestPortableInstalled.txt"); @@ -2396,6 +2491,43 @@ TEST_CASE("UpdateFlow_UpdateAllApplicable", "[UpdateFlow][workflow]") update.Execute(context); INFO(updateOutput.str()); + // Verify that --include-unknown help message is displayed. + REQUIRE(updateOutput.str().find(Resource::LocString(Resource::String::UpgradeUnknownVersionCount).get()) != std::string::npos); + REQUIRE(updateOutput.str().find("AppInstallerCliTest.TestExeUnknownVersion") == std::string::npos); + + // Verify installers are called. + REQUIRE(std::filesystem::exists(updateExeResultPath.GetPath())); + REQUIRE(std::filesystem::exists(updateMsixResultPath.GetPath())); + REQUIRE(std::filesystem::exists(updateMSStoreResultPath.GetPath())); + REQUIRE(std::filesystem::exists(updatePortableResultPath.GetPath())); +} + +TEST_CASE("UpdateFlow_UpdateAll_IncludeUnknown", "[UpdateFlow][workflow]") +{ + TestCommon::TempFile updateExeResultPath("TestExeInstalled.txt"); + TestCommon::TempFile updateMsixResultPath("TestMsixInstalled.txt"); + TestCommon::TempFile updateMSStoreResultPath("TestMSStoreUpdated.txt"); + TestCommon::TempFile updatePortableResultPath("TestPortableInstalled.txt"); + + std::ostringstream updateOutput; + TestContext context{ updateOutput, std::cin }; + auto previousThreadGlobals = context.SetForCurrentThread(); + OverrideForCompositeInstalledSource(context); + OverrideForShellExecute(context); + OverrideForMSIX(context); + OverrideForMSStore(context, true); + OverrideForPortableInstall(context); + context.Args.AddArg(Execution::Args::Type::All); + context.Args.AddArg(Execution::Args::Type::IncludeUnknown); + + UpgradeCommand update({}); + update.Execute(context); + INFO(updateOutput.str()); + + // Verify that --include-unknown help message is NOT displayed and unknown version package is upgraded. + REQUIRE(updateOutput.str().find(Resource::LocString(Resource::String::UpgradeUnknownVersionCount).get()) == std::string::npos); + REQUIRE(updateOutput.str().find("AppInstallerCliTest.TestExeUnknownVersion") != std::string::npos); + // Verify installers are called. REQUIRE(std::filesystem::exists(updateExeResultPath.GetPath())); REQUIRE(std::filesystem::exists(updateMsixResultPath.GetPath())); @@ -2767,7 +2899,7 @@ TEST_CASE("ExportFlow_ExportAll", "[ExportFlow][workflow]") REQUIRE(exportedCollection.Sources[0].Details.Identifier == "*TestSource"); const auto& exportedPackages = exportedCollection.Sources[0].Packages; - REQUIRE(exportedPackages.size() == 5); + REQUIRE(exportedPackages.size() == 6); REQUIRE(exportedPackages.end() != std::find_if(exportedPackages.begin(), exportedPackages.end(), [](const auto& p) { return p.Id == "AppInstallerCliTest.TestExeInstaller" && p.VersionAndChannel.GetVersion().ToString().empty(); @@ -2788,6 +2920,10 @@ TEST_CASE("ExportFlow_ExportAll", "[ExportFlow][workflow]") { return p.Id == "AppInstallerCliTest.TestZipInstaller" && p.VersionAndChannel.GetVersion().ToString().empty(); })); + REQUIRE(exportedPackages.end() != std::find_if(exportedPackages.begin(), exportedPackages.end(), [](const auto& p) + { + return p.Id == "AppInstallerCliTest.TestExeUnknownVersion" && p.VersionAndChannel.GetVersion().ToString().empty(); + })); } TEST_CASE("ExportFlow_ExportAll_WithVersions", "[ExportFlow][workflow]") @@ -2811,7 +2947,7 @@ TEST_CASE("ExportFlow_ExportAll_WithVersions", "[ExportFlow][workflow]") REQUIRE(exportedCollection.Sources[0].Details.Identifier == "*TestSource"); const auto& exportedPackages = exportedCollection.Sources[0].Packages; - REQUIRE(exportedPackages.size() == 5); + REQUIRE(exportedPackages.size() == 6); REQUIRE(exportedPackages.end() != std::find_if(exportedPackages.begin(), exportedPackages.end(), [](const auto& p) { return p.Id == "AppInstallerCliTest.TestExeInstaller" && p.VersionAndChannel.GetVersion().ToString() == "1.0.0.0"; @@ -2832,6 +2968,10 @@ TEST_CASE("ExportFlow_ExportAll_WithVersions", "[ExportFlow][workflow]") { return p.Id == "AppInstallerCliTest.TestZipInstaller" && p.VersionAndChannel.GetVersion().ToString() == "1.0.0.0"; })); + REQUIRE(exportedPackages.end() != std::find_if(exportedPackages.begin(), exportedPackages.end(), [](const auto& p) + { + return p.Id == "AppInstallerCliTest.TestExeUnknownVersion" && p.VersionAndChannel.GetVersion().ToString() == "unknown"; + })); } TEST_CASE("ImportFlow_Successful", "[ImportFlow][workflow]")