WorkFlow.cpp (8185B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "WorkflowCommon.h" 5 #include "TestSettings.h" 6 #include <AppInstallerDownloader.h> 7 #include <winget/Settings.h> 8 #include <Workflows/DownloadFlow.h> 9 #include <Commands/InstallCommand.h> 10 #include <Commands/SettingsCommand.h> 11 #include <Commands/ValidateCommand.h> 12 13 using namespace TestCommon; 14 using namespace AppInstaller::CLI; 15 using namespace AppInstaller::CLI::Execution; 16 using namespace AppInstaller::CLI::Workflow; 17 using namespace AppInstaller::Manifest; 18 using namespace AppInstaller::Repository; 19 using namespace AppInstaller::Settings; 20 using namespace AppInstaller::Utility; 21 22 void VerifyMotw(const std::filesystem::path& testFile, DWORD zone) 23 { 24 std::filesystem::path motwFile(testFile); 25 motwFile += ":Zone.Identifier:$data"; 26 std::ifstream motwStream(motwFile); 27 std::stringstream motwContent; 28 motwContent << motwStream.rdbuf(); 29 std::string motwContentStr = motwContent.str(); 30 motwStream.close(); 31 REQUIRE(motwContentStr.find("ZoneId=" + std::to_string(zone)) != std::string::npos); 32 } 33 34 TEST_CASE("VerifyInstallerTrustLevelAndUpdateInstallerFileMotw", "[DownloadInstaller][workflow]") 35 { 36 TestCommon::TempFile testInstallerPath("TestInstaller.txt"); 37 38 std::ofstream ofile(testInstallerPath, std::ofstream::out); 39 ofile << "test"; 40 ofile.close(); 41 42 ApplyMotwIfApplicable(testInstallerPath, URLZONE_INTERNET); 43 VerifyMotw(testInstallerPath, 3); 44 45 std::ostringstream updateMotwOutput; 46 TestContext context{ updateMotwOutput, std::cin }; 47 auto previousThreadGlobals = context.SetForCurrentThread(); 48 context.Add<Data::DownloadHashInfo>({ {}, {} }); 49 context.Add<Data::InstallerPath>(testInstallerPath); 50 auto packageVersion = std::make_shared<TestPackageVersion>(Manifest{}); 51 auto testSource = std::make_shared<TestSource>(); 52 testSource->Details.TrustLevel = SourceTrustLevel::Trusted; 53 packageVersion->Source = testSource; 54 context.Add<Data::PackageVersion>(packageVersion); 55 ManifestInstaller installer; 56 installer.Url = "http://NotTrusted.com"; 57 context.Add<Data::Installer>(std::move(installer)); 58 59 context << VerifyInstallerHash << UpdateInstallerFileMotwIfApplicable; 60 REQUIRE(WI_IsFlagSet(context.GetFlags(), ContextFlag::InstallerTrusted)); 61 VerifyMotw(testInstallerPath, 2); 62 63 testSource->Details.TrustLevel = SourceTrustLevel::None; 64 context.ClearFlags(ContextFlag::InstallerTrusted); 65 context << VerifyInstallerHash << UpdateInstallerFileMotwIfApplicable; 66 REQUIRE_FALSE(WI_IsFlagSet(context.GetFlags(), ContextFlag::InstallerTrusted)); 67 VerifyMotw(testInstallerPath, 3); 68 69 INFO(updateMotwOutput.str()); 70 } 71 72 TEST_CASE("ValidateCommand_Dependencies", "[workflow][dependencies]") 73 { 74 std::ostringstream validateOutput; 75 TestContext context{ validateOutput, std::cin }; 76 auto previousThreadGlobals = context.SetForCurrentThread(); 77 context.Args.AddArg(Args::Type::ValidateManifest, TestDataFile("Manifest-Good-AllDependencyTypes.yaml").GetPath().u8string()); 78 79 ValidateCommand validate({}); 80 validate.Execute(context); 81 INFO(validateOutput.str()); 82 83 // Verify all types of dependencies are printed 84 REQUIRE(validateOutput.str().find(Resource::LocString(Resource::String::ValidateCommandReportDependencies).get()) != std::string::npos); 85 REQUIRE(validateOutput.str().find("WindowsFeaturesDep") != std::string::npos); 86 REQUIRE(validateOutput.str().find("WindowsLibrariesDep") != std::string::npos); 87 // PackageDep1 has minimum version (1.0), PackageDep2 doesn't (shouldn't show [>=...]) 88 REQUIRE(validateOutput.str().find("Package.Dep1-x64 [>= 1.0]") != std::string::npos); 89 REQUIRE(validateOutput.str().find("Package.Dep2-x64") != std::string::npos); 90 REQUIRE(validateOutput.str().find("Package.Dep2-x64 [") == std::string::npos); 91 REQUIRE(validateOutput.str().find("ExternalDep") != std::string::npos); 92 } 93 94 TEST_CASE("AdminSetting_LocalManifestFiles", "[LocalManifests][workflow]") 95 { 96 RemoveSetting(Stream::AdminSettings); 97 98 { 99 // If there's no admin setting, using local manifest should fail. 100 Execution::Args args; 101 args.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_Exe.yaml").GetPath().u8string()); 102 InstallCommand installCommand({}); 103 REQUIRE_THROWS(installCommand.ValidateArguments(args)); 104 } 105 106 { 107 // Using settings command to enable local manifests 108 std::ostringstream settingsOutput; 109 TestContext context{ settingsOutput, std::cin }; 110 auto previousThreadGlobals = context.SetForCurrentThread(); 111 context.Args.AddArg(Execution::Args::Type::AdminSettingEnable, "LocalManifestFiles"sv); 112 context.Override({ EnsureRunningAsAdmin, [](TestContext&) {} }); 113 SettingsCommand settings({}); 114 settings.Execute(context); 115 INFO(settingsOutput.str()); 116 } 117 118 { 119 // Now using local manifests should succeed 120 Execution::Args args2; 121 args2.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_Exe.yaml").GetPath().u8string()); 122 InstallCommand installCommand2({}); 123 REQUIRE_NOTHROW(installCommand2.ValidateArguments(args2)); 124 } 125 126 { 127 // Using settings command to disable local manifests 128 std::ostringstream settingsOutput2; 129 TestContext context2{ settingsOutput2, std::cin }; 130 auto previousThreadGlobals = context2.SetForCurrentThread(); 131 context2.Args.AddArg(Execution::Args::Type::AdminSettingDisable, "LocalManifestFiles"sv); 132 context2.Override({ EnsureRunningAsAdmin, [](TestContext&) {} }); 133 SettingsCommand settings2({}); 134 settings2.Execute(context2); 135 INFO(settingsOutput2.str()); 136 } 137 138 { 139 // Now using local manifests should fail 140 Execution::Args args3; 141 args3.AddArg(Execution::Args::Type::Manifest, TestDataFile("InstallFlowTest_Exe.yaml").GetPath().u8string()); 142 InstallCommand installCommand3({}); 143 REQUIRE_THROWS(installCommand3.ValidateArguments(args3)); 144 } 145 } 146 147 TEST_CASE("Export_Settings", "[Settings][workflow]") 148 { 149 RemoveSetting(Stream::AdminSettings); 150 151 { 152 // No admin settings, local manifest should be false. 153 std::ostringstream exportOutput; 154 TestContext context{ exportOutput, std::cin }; 155 auto previousThreadGlobals = context.SetForCurrentThread(); 156 SettingsExportCommand settingsExportCommand({}); 157 settingsExportCommand.Execute(context); 158 159 auto json = ConvertToJson(exportOutput.str()); 160 REQUIRE(!json.isNull()); 161 REQUIRE_FALSE(json["adminSettings"]["LocalManifestFiles"].asBool()); 162 163 auto userSettingsFileValue = std::string(json["userSettingsFile"].asCString()); 164 REQUIRE(userSettingsFileValue.find("settings.json") != std::string::npos); 165 } 166 167 { 168 // Enable local manifest and verify export works. 169 std::ostringstream settingsOutput; 170 TestContext context{ settingsOutput, std::cin }; 171 auto previousThreadGlobals = context.SetForCurrentThread(); 172 context.Args.AddArg(Execution::Args::Type::AdminSettingEnable, "LocalManifestFiles"sv); 173 context.Override({ EnsureRunningAsAdmin, [](TestContext&) {} }); 174 SettingsCommand settings({}); 175 settings.Execute(context); 176 177 std::ostringstream exportOutput; 178 TestContext context2{ exportOutput, std::cin }; 179 auto previousThreadGlobals2 = context2.SetForCurrentThread(); 180 SettingsExportCommand settingsExportCommand({}); 181 settingsExportCommand.Execute(context2); 182 auto json = ConvertToJson(exportOutput.str()); 183 REQUIRE(!json.isNull()); 184 REQUIRE(json["adminSettings"]["LocalManifestFiles"].asBool()); 185 186 auto userSettingsFileValue = std::string(json["userSettingsFile"].asCString()); 187 REQUIRE(userSettingsFileValue.find("settings.json") != std::string::npos); 188 } 189 }