UninstallFlow.cpp (9049B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "WorkflowCommon.h" 5 #include <Commands/UninstallCommand.h> 6 #include <Workflows/PortableFlow.h> 7 #include <Workflows/ShellExecuteInstallerHandler.h> 8 #include <Workflows/UninstallFlow.h> 9 10 using namespace TestCommon; 11 using namespace AppInstaller::CLI; 12 using namespace AppInstaller::CLI::Workflow; 13 14 void OverrideForPortableUninstall(TestContext& context) 15 { 16 context.Override({ GetUninstallInfo, [](TestContext&) 17 { 18 } }); 19 20 context.Override({ PortableUninstallImpl, [](TestContext& context) 21 { 22 std::filesystem::path temp = std::filesystem::temp_directory_path(); 23 temp /= "TestPortableUninstalled.txt"; 24 std::ofstream file(temp, std::ofstream::out); 25 file.close(); 26 27 context.Add<Execution::Data::OperationReturnCode>(0); 28 } }); 29 } 30 31 void OverrideForExeUninstall(TestContext& context) 32 { 33 context.Override({ ShellExecuteUninstallImpl, [](TestContext& context) 34 { 35 // Write out the uninstall command 36 std::filesystem::path temp = std::filesystem::temp_directory_path(); 37 temp /= "TestExeUninstalled.txt"; 38 std::ofstream file(temp, std::ofstream::out); 39 file << context.Get<Execution::Data::UninstallString>(); 40 file.close(); 41 42 context.Add<Execution::Data::OperationReturnCode>(0); 43 } }); 44 } 45 46 void OverrideForMSIXUninstall(TestContext& context) 47 { 48 context.Override({ MsixUninstall, [](TestContext& context) 49 { 50 // Write out the package full name 51 std::filesystem::path temp = std::filesystem::temp_directory_path(); 52 temp /= "TestMsixUninstalled.txt"; 53 std::ofstream file(temp, std::ofstream::out); 54 for (const auto& packageFamilyName : context.Get<Execution::Data::PackageFamilyNames>()) 55 { 56 file << packageFamilyName << std::endl; 57 } 58 59 file.close(); 60 } }); 61 } 62 63 TEST_CASE("UninstallFlow_UninstallPortable", "[UninstallFlow][workflow]") 64 { 65 TestCommon::TempFile uninstallResultPath("TestPortableUninstalled.txt"); 66 67 std::ostringstream uninstallOutput; 68 TestContext context{ uninstallOutput, std::cin }; 69 auto previousThreadGlobals = context.SetForCurrentThread(); 70 OverrideForCompositeInstalledSource(context, CreateTestSource({ TSR::TestInstaller_Portable })); 71 OverrideForPortableUninstall(context); 72 context.Args.AddArg(Execution::Args::Type::Query, TSR::TestInstaller_Portable.Query); 73 74 UninstallCommand uninstall({}); 75 uninstall.Execute(context); 76 INFO(uninstallOutput.str()); 77 REQUIRE(std::filesystem::exists(uninstallResultPath.GetPath())); 78 } 79 80 TEST_CASE("UninstallFlow_UninstallExe", "[UninstallFlow][workflow]") 81 { 82 TestCommon::TempFile uninstallResultPath("TestExeUninstalled.txt"); 83 84 std::ostringstream uninstallOutput; 85 TestContext context{ uninstallOutput, std::cin }; 86 auto previousThreadGlobals = context.SetForCurrentThread(); 87 OverrideForCompositeInstalledSource(context, CreateTestSource({ TSR::TestInstaller_Exe })); 88 OverrideForExeUninstall(context); 89 context.Args.AddArg(Execution::Args::Type::Query, TSR::TestInstaller_Exe.Query); 90 context.Args.AddArg(Execution::Args::Type::Silent); 91 92 UninstallCommand uninstall({}); 93 uninstall.Execute(context); 94 INFO(uninstallOutput.str()); 95 96 // Verify Uninstaller is called and parameters are passed in. 97 REQUIRE(std::filesystem::exists(uninstallResultPath.GetPath())); 98 std::ifstream uninstallResultFile(uninstallResultPath.GetPath()); 99 REQUIRE(uninstallResultFile.is_open()); 100 std::string uninstallResultStr; 101 std::getline(uninstallResultFile, uninstallResultStr); 102 REQUIRE(uninstallResultStr.find("uninstall.exe") != std::string::npos); 103 REQUIRE(uninstallResultStr.find("/silence") != std::string::npos); 104 } 105 106 TEST_CASE("UninstallFlow_UninstallMsix", "[UninstallFlow][workflow]") 107 { 108 TestCommon::TempFile uninstallResultPath("TestMsixUninstalled.txt"); 109 110 std::ostringstream uninstallOutput; 111 TestContext context{ uninstallOutput, std::cin }; 112 auto previousThreadGlobals = context.SetForCurrentThread(); 113 OverrideForCompositeInstalledSource(context, CreateTestSource({ TSR::TestInstaller_Msix })); 114 OverrideForMSIXUninstall(context); 115 context.Args.AddArg(Execution::Args::Type::Query, TSR::TestInstaller_Msix.Query); 116 117 UninstallCommand uninstall({}); 118 uninstall.Execute(context); 119 INFO(uninstallOutput.str()); 120 121 // Verify Uninstaller is called with the package full name. 122 REQUIRE(std::filesystem::exists(uninstallResultPath.GetPath())); 123 std::ifstream uninstallResultFile(uninstallResultPath.GetPath()); 124 REQUIRE(uninstallResultFile.is_open()); 125 std::string uninstallResultStr; 126 std::getline(uninstallResultFile, uninstallResultStr); 127 REQUIRE(uninstallResultStr.find("20477fca-282d-49fb-b03e-371dca074f0f_8wekyb3d8bbwe") != std::string::npos); 128 } 129 130 TEST_CASE("UninstallFlow_UninstallMSStore", "[UninstallFlow][workflow]") 131 { 132 TestCommon::TempFile uninstallResultPath("TestMsixUninstalled.txt"); 133 134 std::ostringstream uninstallOutput; 135 TestContext context{ uninstallOutput, std::cin }; 136 auto previousThreadGlobals = context.SetForCurrentThread(); 137 OverrideForCompositeInstalledSource(context, CreateTestSource({ TSR::TestInstaller_MSStore })); 138 OverrideForMSIXUninstall(context); 139 context.Args.AddArg(Execution::Args::Type::Query, TSR::TestInstaller_MSStore.Query); 140 141 UninstallCommand uninstall({}); 142 uninstall.Execute(context); 143 INFO(uninstallOutput.str()); 144 145 // Verify Uninstaller is called with the package full name 146 REQUIRE(std::filesystem::exists(uninstallResultPath.GetPath())); 147 std::ifstream uninstallResultFile(uninstallResultPath.GetPath()); 148 REQUIRE(uninstallResultFile.is_open()); 149 std::string uninstallResultStr; 150 std::getline(uninstallResultFile, uninstallResultStr); 151 REQUIRE(uninstallResultStr.find("microsoft.skypeapp_kzf8qxf38zg5c") != std::string::npos); 152 } 153 154 TEST_CASE("UninstallFlow_UninstallExeNotFound", "[UninstallFlow][workflow]") 155 { 156 TestCommon::TempFile uninstallResultPath("TestExeUninstalled.txt"); 157 158 std::ostringstream uninstallOutput; 159 TestContext context{ uninstallOutput, std::cin }; 160 auto previousThreadGlobals = context.SetForCurrentThread(); 161 OverrideForCompositeInstalledSource(context, CreateTestSource({})); 162 context.Args.AddArg(Execution::Args::Type::Query, "AppInstallerCliTest.MissingApp"sv); 163 context.Args.AddArg(Execution::Args::Type::Silent); 164 165 UninstallCommand uninstall({}); 166 uninstall.Execute(context); 167 INFO(uninstallOutput.str()); 168 169 // Verify Uninstaller is not called. 170 REQUIRE(!std::filesystem::exists(uninstallResultPath.GetPath())); 171 REQUIRE(uninstallOutput.str().find(Resource::LocString(Resource::String::NoInstalledPackageFound).get()) != std::string::npos); 172 REQUIRE(context.GetTerminationHR() == APPINSTALLER_CLI_ERROR_NO_APPLICATIONS_FOUND); 173 } 174 175 TEST_CASE("UninstallFlow_UninstallMultiple", "[UninstallFlow][workflow][MultiQuery]") 176 { 177 TestCommon::TempFile exeUninstallResultPath("TestExeUninstalled.txt"); 178 TestCommon::TempFile msixUninstallResultPath("TestMsixUninstalled.txt"); 179 180 std::ostringstream uninstallOutput; 181 TestContext context{ uninstallOutput, std::cin }; 182 auto previousThreadGlobals = context.SetForCurrentThread(); 183 OverrideForCompositeInstalledSource(context, CreateTestSource({ TSR::TestInstaller_Exe, TSR::TestInstaller_Msix })); 184 OverrideForExeUninstall(context); 185 OverrideForMSIXUninstall(context); 186 context.Args.AddArg(Execution::Args::Type::MultiQuery, TSR::TestInstaller_Exe.Query); 187 context.Args.AddArg(Execution::Args::Type::MultiQuery, TSR::TestInstaller_Msix.Query); 188 189 UninstallCommand uninstall({}); 190 uninstall.Execute(context); 191 INFO(uninstallOutput.str()); 192 193 // Verify Uninstallers are called 194 REQUIRE(std::filesystem::exists(exeUninstallResultPath.GetPath())); 195 REQUIRE(std::filesystem::exists(msixUninstallResultPath.GetPath())); 196 } 197 198 TEST_CASE("UninstallFlow_UninstallMultiple_NotAllInstalled", "[UninstallFlow][workflow][MultiQuery]") 199 { 200 std::ostringstream uninstallOutput; 201 TestContext context{ uninstallOutput, std::cin }; 202 auto previousThreadGlobals = context.SetForCurrentThread(); 203 OverrideForCompositeInstalledSource(context, CreateTestSource({ TSR::TestInstaller_Exe })); 204 context.Args.AddArg(Execution::Args::Type::MultiQuery, TSR::TestInstaller_Exe.Query); 205 context.Args.AddArg(Execution::Args::Type::MultiQuery, TSR::TestInstaller_Msix.Query); 206 207 UninstallCommand uninstall({}); 208 uninstall.Execute(context); 209 INFO(uninstallOutput.str()); 210 211 REQUIRE_TERMINATED_WITH(context, APPINSTALLER_CLI_ERROR_NOT_ALL_QUERIES_FOUND_SINGLE); 212 }