From a52f278f6d73356a56d4bbc4d6c82dfb57356721 Mon Sep 17 00:00:00 2001 From: Ruben Guerrero Date: Fri, 11 Aug 2023 21:39:09 -0700 Subject: [PATCH] Move Microsoft.WinGet.Client E2E test to Pester framework (#3503) This PR finally uses all the refactor to run the Microsoft.WinGet.Client PowerShell module in Pester. The tests are done in the BuildPowerShellModule phase. The E2E Test Source is built in the build phases, then it will be get published as artifacts under E2ETests\TestLocalIndex'. Other artifacts that are required as published in E2ETests` as well. Having the test source as a build artifacts will make it easier to perform repros without building the source all over again. The BuildPowerShellModule phase will download the artifacts, move necessary files to around, install the dev package (and dependencies), start the localhost web server and run the Pester tests. Then it will publish the modules as it used to as well as the test results. It is important to remember the modules published as artifacts target the dev package, so one cannot just download it and use it without it. I port all the E2E tests to Pester tests except the ones dealing with the server shutdown. Eventually we will run tests for Microsoft.WinGet.DSC and Microsoft.WinGet.Configuration. --- .github/actions/spelling/expect.txt | 3 + azure-pipelines.yml | 51 +- .../PowerShell/WinGetClientModule.cs | 986 ------------------ .../Run-LocalhostWebServer.ps1 | 13 +- .../tests/Microsoft.WinGet.Client.Tests.ps1 | 341 +++++- src/PowerShell/tests/RunTests.ps1 | 44 + templates/e2e-setup.yml | 12 +- 7 files changed, 435 insertions(+), 1015 deletions(-) create mode 100644 src/PowerShell/tests/RunTests.ps1 diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 705df91ac8..1762546eb3 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -120,11 +120,13 @@ EFGH EFile endregion ENDSESSION +epth EQU errmsg ERRORONEXIT ESource ESRB +ests etest etl execustom @@ -173,6 +175,7 @@ hmodule Howto hre hresults +hrow hwnd IARP IAttachment diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f7ddc4e59e..5b92e4a54f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -56,6 +56,7 @@ jobs: variables: BuildVer: $[counter(dependencies.GetReleaseTag.outputs['GetTag.tag'], 1)] buildOutDir: $(Build.SourcesDirectory)\src\$(buildPlatform)\$(buildConfiguration) + buildOutDirAnyCpu: $(Build.SourcesDirectory)\src\AnyCPU\$(buildConfiguration) artifactsDir: $(Build.ArtifactStagingDirectory)\$(buildPlatform) packageLayoutDir: $(Build.BinariesDirectory)\WingetPackageLayout @@ -218,8 +219,8 @@ jobs: - template: templates/e2e-setup.yml parameters: - source: $(Build.SourcesDirectory) - buildOutDir: $(buildOutDir) + sourceDir: $(Build.SourcesDirectory) + localhostWebServerArgs: '-BuildRoot $(buildOutDir)\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\localsource.json -SourceCert $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTest.cer' - template: templates/e2e-test.template.yml parameters: @@ -260,6 +261,20 @@ jobs: TargetFolder: '$(artifactsDir)\E2ETests\TestData' condition: succeededOrFailed() + - task: CopyFiles@2 + displayName: 'Copy LocalhostWebServer' + inputs: + SourceFolder: '$(buildOutDir)\LocalhostWebServer' + TargetFolder: '$(artifactsDir)\E2ETests\LocalhostWebServer' + condition: succeededOrFailed() + + - task: CopyFiles@2 + displayName: 'Copy Dev Package Dependencies' + inputs: + SourceFolder: '$(appxPackageDir)\AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\$(buildPlatform)\' + TargetFolder: '$(artifactsDir)\E2ETests\DevPackageDependencies' + condition: succeededOrFailed() + - task: CopyFiles@2 displayName: 'Copy Files: WinGetUtilInterop.UnitTests' inputs: @@ -335,6 +350,13 @@ jobs: TargetFolder: '$(artifactsDir)\PowerShell' condition: succeededOrFailed() + - task: CopyFiles@2 + displayName: 'Copy PowerShell AnyCPU Module Files' + inputs: + SourceFolder: '$(buildOutDirAnyCpu)\PowerShell' + TargetFolder: '$(artifactsDir)\PowerShell' + condition: succeededOrFailed() + - task: CopyFiles@2 displayName: 'Copy Dev Package (Loose Files)' inputs: @@ -407,7 +429,32 @@ jobs: Contents: '**\*' TargetFolder: '$(Build.ArtifactStagingDirectory)' + - task: PowerShell@2 + displayName: Install Tests Dependencies + inputs: + targetType: 'inline' + script: | + Get-ChildItem E2ETests\DevPackageDependencies -Filter *.appx | %{ Add-AppxPackage $_.FullName } + workingDirectory: $(Pipeline.Workspace)\Build.x64release\ + + - template: templates/e2e-setup.yml + parameters: + sourceDir: $(Build.SourcesDirectory) + localhostWebServerArgs: '-BuildRoot $(Pipeline.Workspace)\Build.x64release\E2ETests\LocalhostWebServer -StaticFileRoot $(Pipeline.Workspace)\Build.x64release\E2ETests\TestLocalIndex -SourceCert $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTest.cer' + + - pwsh: .\RunTests.ps1 -testModulesPath $(Build.ArtifactStagingDirectory) -outputPath $(Pipeline.Workspace)\PesterTest -packageLayoutPath $(Pipeline.Workspace)\Build.x64release\DevPackage + workingDirectory: $(Build.SourcesDirectory)\src\PowerShell\tests\ + displayName: Run Tests + + - task: PublishTestResults@2 + displayName: Publish Pester Test Results + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '$(Pipeline.Workspace)\PesterTest\Test*.xml' + failTaskOnFailedTests: true + - task: PublishPipelineArtifact@1 displayName: Publish PowerShell Module Artifacts inputs: targetPath: '$(Build.ArtifactStagingDirectory)' + condition: succeededOrFailed() diff --git a/src/AppInstallerCLIE2ETests/PowerShell/WinGetClientModule.cs b/src/AppInstallerCLIE2ETests/PowerShell/WinGetClientModule.cs index c28705ba13..44810db550 100644 --- a/src/AppInstallerCLIE2ETests/PowerShell/WinGetClientModule.cs +++ b/src/AppInstallerCLIE2ETests/PowerShell/WinGetClientModule.cs @@ -7,10 +7,8 @@ namespace AppInstallerCLIE2ETests.PowerShell { using System; - using System.Collections; using System.Diagnostics; using System.Linq; - using System.Management.Automation; using AppInstallerCLIE2ETests.Helpers; using NUnit.Framework; @@ -22,8 +20,6 @@ namespace AppInstallerCLIE2ETests.PowerShell [Category("PowerShell")] public class WinGetClientModule { - // TODO: Consider using Pester framework for conducting more extensive PowerShell module tests or move to Powershell Host. - /// /// Set setup. /// @@ -74,62 +70,6 @@ public void AssertServerShutdownAfterExecution() Assert.IsTrue(serverProcessExit, $"{Constants.WindowsPackageManagerServer} failed to terminate after creating COM object."); } - /// - /// Test Get-WinGetSource. - /// - [Test] - public void GetWinGetSource() - { - if (!Environment.Is64BitProcess) - { - return; - } - - var getSourceResult = TestCommon.RunPowerShellCoreCommandWithResult(Constants.GetSourceCmdlet, $"-Name {Constants.TestSourceName}"); - Assert.AreEqual(Constants.ErrorCode.S_OK, getSourceResult.ExitCode, $"ExitCode: {getSourceResult.ExitCode} Failed with the following output: {getSourceResult.StdOut}, {getSourceResult.StdErr}"); - Assert.IsTrue(getSourceResult.StdOut.Contains($"{Constants.TestSourceName}")); - } - - /// - /// Tests WinGetPackage cmdlets. - /// Find-WinGetPackage. - /// Install-WinGetPackage. - /// Get-WinGetPackage. - /// Update-WinGetPackage. - /// Uninstall-WinGetPackage. - /// - [Test] - public void WinGetPackageCmdlets() - { - if (!Environment.Is64BitProcess) - { - return; - } - - // TODO: It would be nice to add an installer to be use ONLY by the PowerShell cmdlets for E2E to avoid conflicts and bad - // cleanups in other tests. - var result = TestCommon.RunPowerShellCoreCommandWithResult(Constants.FindCmdlet, $"-Id {Constants.ExeInstallerPackageId}"); - Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode, $"ExitCode: {result.ExitCode} Failed with the following output: {result.StdOut}; {result.StdErr}"); - Assert.IsTrue(result.StdOut.Contains("TestExeInstaller")); - - var installResult = TestCommon.RunPowerShellCoreCommandWithResult(Constants.InstallCmdlet, $"-Id {Constants.ExeInstallerPackageId} -Version 1.0.0.0"); - Assert.AreEqual(Constants.ErrorCode.S_OK, installResult.ExitCode, $"Failed with the following output: {installResult.StdOut}"); - - var updateResult = TestCommon.RunPowerShellCoreCommandWithResult(Constants.UpdateCmdlet, $"-Id {Constants.ExeInstallerPackageId}"); - Assert.AreEqual(Constants.ErrorCode.S_OK, updateResult.ExitCode, $"Failed with the following output: {updateResult.StdOut}"); - - var getResult = TestCommon.RunPowerShellCoreCommandWithResult(Constants.GetCmdlet, $"-Id {Constants.ExeInstallerPackageId}"); - Assert.AreEqual(Constants.ErrorCode.S_OK, getResult.ExitCode, $"Failed with the following output: {getResult.StdOut}"); - - var uninstallResult = TestCommon.RunPowerShellCoreCommandWithResult(Constants.UninstallCmdlet, $"-Id {Constants.ExeInstallerPackageId}"); - Assert.AreEqual(Constants.ErrorCode.S_OK, uninstallResult.ExitCode, $"Failed with the following output: {uninstallResult.StdOut}"); - - Assert.IsTrue(!string.IsNullOrEmpty(installResult.StdOut)); - Assert.IsTrue(!string.IsNullOrEmpty(updateResult.StdOut)); - Assert.IsTrue(getResult.StdOut.Contains("2.0.0.0")); - Assert.IsTrue(!string.IsNullOrEmpty(uninstallResult.StdOut)); - } - /// /// There is a known issue where the server takes an abnormally long time to terminate after the E2E test pwsh processes finish execution. /// This test verifies that the server does indeed terminate within 5 minutes after running all of the cmdlets. @@ -154,932 +94,6 @@ public void VerifyServerTermination() Assert.IsTrue(serverProcessExit, $"{Constants.WindowsPackageManagerServer} failed to terminate after creating COM object."); } - /// - /// Test Get-WinGetUserSettings. - /// - [Test] - public void GetWinGetUserSettings() - { - var ogSettings = @"{ - ""visual"": { - ""progressBar"": ""rainbow"" - }, - ""experimentalFeatures"": { - ""experimentalArg"": false, - ""experimentalCmd"": true - } -}"; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Get-WinGetUserSettings") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - } - - /// - /// Test Get-WinGetUserSettings when the local settings file is not a json. - /// - [Test] - public void GetWinGetUserSettings_BadJsonFile() - { - WinGetSettingsHelper.SetWingetSettings("Hi, im not a json. Thank you, Test."); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - - var cmdletException = Assert.Throws( - () => powerShellHost.PowerShell - .AddCommand("Get-WinGetUserSettings") - .Invoke()); - - // If we reference Microsoft.WinGet.Client to this project PowerShell host fails with - // System.Management.Automation.CmdletInvocationException : Operation is not supported on this platform. (0x80131539) - // System.PlatformNotSupportedException : Operation is not supported on this platform. (0x80131539) - // trying to load the runspace. This is most probably because the same dll is already loaded. - // Check the type the long way. - dynamic exception = cmdletException.InnerException; - Assert.AreEqual(exception.GetType().ToString(), "Newtonsoft.Json.JsonReaderException"); - } - - /// - /// Test Test-WinGetUserSettings. Settings are equal. - /// - [Test] - public void TestWinGetUserSettings_Equal() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", ogSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsTrue((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings. Settings are equal. Ignore schema. - /// - [Test] - public void TestWinGetUserSettings_Equal_Schema() - { - var ogSettings = new Hashtable() - { - { - "$schema", - "https://aka.ms/winget-settings.schema.json" - }, - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsTrue((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings. Settings are not equal. - /// - [Test] - public void TestWinGetUserSettings_NotEqual() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "rainbow" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings. Local settings has more properties. - /// - [Test] - public void TestWinGetUserSettings_MoreSettingsLocal() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings. Input has more properties. - /// - [Test] - public void TestWinGetUserSettings_MoreSettingsInput() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell.AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings. IgnoreNotSet. - /// They are equal. - /// - [Test] - public void TestWinGetUserSettings_Equal_IgnoreNotSet() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", ogSettings) - .AddParameter("IgnoreNotSet") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsTrue((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings IgnoreNotSet. - /// Ignore comparing properties that are not set in the input. - /// - [Test] - public void TestWinGetUserSettings_MoreSettingsLocal_IgnoreNotSet() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .AddParameter("IgnoreNotSet") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsTrue((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings IgnoreNotSet. - /// Local settings doesnt have some properties. - /// - [Test] - public void TestWinGetUserSettings_MoreSettingsInput_IgnoreNotSet() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .AddParameter("IgnoreNotSet") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings IgnoreNotSet. - /// DeepEquals fails, but we should still fail at experimentalArg. - /// - [Test] - public void TestWinGetUserSettings_DifferentValue_IgnoreNotSet() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .AddParameter("IgnoreNotSet") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings IgnoreNotSet. - /// DeepEquals fails, but we should still fail at comparing the array. - /// - [Test] - public void TestWinGetUserSettings_ArrayDifferent_IgnoreNotSet() - { - var ogSettings = new Hashtable() - { - { - "installBehavior", - new Hashtable() - { - { - "preferences", - new Hashtable() - { - { "architectures", new string[] { "x64", "x86" } }, - } - }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "installBehavior", - new Hashtable() - { - { - "preferences", - new Hashtable() - { - { "architectures", new string[] { "x64", "arm64" } }, - } - }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .AddParameter("IgnoreNotSet") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings IgnoreNotSet. - /// DeepEquals fails, but we should still fail at experimentalArg because is an int. - /// - [Test] - public void TestWinGetUserSettings_DifferentValueType_IgnoreNotSet() - { - var ogSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", 4 }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .AddParameter("IgnoreNotSet") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Test-WinGetUserSettings. - /// Settings file is not a json. - /// - [Test] - public void TestWinGetUserSettings_BadJsonFile() - { - WinGetSettingsHelper.SetWingetSettings("Hi, im not a json. Thank you, Test."); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Test-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - Assert.IsFalse((bool)result[0].BaseObject); - } - - /// - /// Test Set-WinGetUserSettings. - /// - [Test] - public void SetWinGetUserSettings_Overwrite() - { - var ogSettings = new Hashtable() - { - { - "$schema", - "https://aka.ms/winget-settings.schema.json" - }, - { - "source", - new Hashtable() - { - { "autoUpdateIntervalInMinutes", 3 }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Set-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - var settingsResult = result[0].BaseObject as Hashtable; - - Assert.True(settingsResult.ContainsKey("$schema")); - Assert.False(settingsResult.ContainsKey("source")); - Assert.True(settingsResult.ContainsKey("experimentalFeatures")); - Assert.True(settingsResult.ContainsKey("visual")); - } - - /// - /// Test Set-WinGetUserSettings. Merge local settings with input. - /// - [Test] - public void SetWinGetUserSettings_Merge() - { - var ogSettings = new Hashtable() - { - { - "source", - new Hashtable() - { - { "autoUpdateIntervalInMinutes", 3 }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Set-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .AddParameter("Merge") - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - var settingsResult = result[0].BaseObject as Hashtable; - - Assert.True(settingsResult.ContainsKey("$schema")); - Assert.True(settingsResult.ContainsKey("source")); - Assert.True(settingsResult.ContainsKey("experimentalFeatures")); - Assert.True(settingsResult.ContainsKey("visual")); - } - - /// - /// Test Set-WinGetUserSettings when the local settings file already have the schema property. It shouldn't - /// be added twice. - /// - [Test] - public void SetWinGetUserSettings_Schema() - { - var ogSettings = new Hashtable() - { - { - "$schema", - "https://aka.ms/winget-settings.schema.json" - }, - { - "source", - new Hashtable() - { - { "autoUpdateIntervalInMinutes", 3 }, - } - }, - }; - - WinGetSettingsHelper.SetWingetSettings(ogSettings); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - { - "experimentalFeatures", - new Hashtable() - { - { "experimentalArg", false }, - { "experimentalCmd", true }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Set-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - var settingsResult = result[0].BaseObject as Hashtable; - - Assert.True(settingsResult.ContainsKey("$schema")); - Assert.False(settingsResult.ContainsKey("source")); - Assert.True(settingsResult.ContainsKey("experimentalFeatures")); - } - - /// - /// Test Set-WinGetUserSettings when the local settings file is not a json. - /// - [Test] - public void SetWinGetUserSettings_BadJsonFile() - { - WinGetSettingsHelper.SetWingetSettings("Hi, im not a json. Thank you, Test."); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - var result = powerShellHost.PowerShell - .AddCommand("Set-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .Invoke(); - - Assert.That(result, Has.Exactly(1).Items); - Assert.IsInstanceOf(result[0].BaseObject); - var settingsResult = result[0].BaseObject as Hashtable; - - Assert.True(settingsResult.ContainsKey("$schema")); - Assert.True(settingsResult.ContainsKey("visual")); - } - - /// - /// Test Set-WinGetUserSettings when the local settings file is not a json. - /// - [Test] - public void SetWinGetUserSettings_BadJsonFile_Merge() - { - WinGetSettingsHelper.SetWingetSettings("Hi, im not a json. Thank you, Test."); - - var inputSettings = new Hashtable() - { - { - "visual", - new Hashtable() - { - { "progressBar", "retro" }, - } - }, - }; - - using var powerShellHost = new PowerShellHost(); - - var cmdletException = Assert.Throws( - () => powerShellHost.PowerShell - .AddCommand("Set-WinGetUserSettings") - .AddParameter("UserSettings", inputSettings) - .AddParameter("Merge") - .Invoke()); - - // If we reference Microsoft.WinGet.Client to this project PowerShell host fails with - // System.Management.Automation.CmdletInvocationException : Operation is not supported on this platform. (0x80131539) - // System.PlatformNotSupportedException : Operation is not supported on this platform. (0x80131539) - // trying to load the runspace. This is most probably because the same dll is already loaded. - // Check the type the long way. - dynamic exception = cmdletException.InnerException; - Assert.AreEqual(exception.GetType().ToString(), "Microsoft.WinGet.Client.Engine.Exceptions.UserSettingsReadException"); - } - private bool IsRunning(string processName) { return Process.GetProcessesByName(processName).Length > 0; diff --git a/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 b/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 index ef243af9ed..d3e6bfb72c 100644 --- a/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 +++ b/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 @@ -13,6 +13,8 @@ Export cert location. .PARAMETER LocalSourceJson Local source json definition +.PARAMETER SourceCert + The certificate of the source package. #> param( @@ -32,9 +34,18 @@ param( [string]$OutCertFile, [Parameter()] - [string]$LocalSourceJson + [string]$LocalSourceJson, + + [Parameter()] + [string]$SourceCert ) +if (-not [System.String]::IsNullOrEmpty($sourceCert)) +{ + # Requires admin + & certutil.exe -addstore -f "TRUSTEDPEOPLE" $sourceCert +} + cd $BuildRoot Start-Process -FilePath "LocalhostWebServer.exe" -ArgumentList "StaticFileRoot=$StaticFileRoot CertPath=$CertPath CertPassword=$CertPassword OutCertFile=$OutCertFile LocalSourceJson=$LocalSourceJson" diff --git a/src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1 b/src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1 index 00faba7012..f52713895d 100644 --- a/src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1 +++ b/src/PowerShell/tests/Microsoft.WinGet.Client.Tests.ps1 @@ -5,37 +5,93 @@ .Synopsis Pester tests related to the Microsoft.WinGet.Client PowerShell module. The tests require the localhost web server to be running and serving the test data. - 'Invoke-Pester' should be called in an admin powershell window with the 'Microsoft.WinGet.Client' PowerShell module already imported. + 'Invoke-Pester' should be called in an admin PowerShell window. #> BeforeAll { + $settingsFilePath = (ConvertFrom-Json (wingetdev.exe settings export)).userSettingsFile + + Import-Module Microsoft.WinGet.Client + + function SetWinGetSettingsHelper($settings) { + $content = ConvertTo-Json $settings -Depth 4 + Set-Content -Path $settingsFilePath -Value $content + } + # Source Add requires admin privileges, this will only execute successfully in an elevated PowerShell. - wingetdev source add 'TestSource' 'https://localhost:5001/TestKit/' + function AddTestSource { + try { + Get-WinGetSource -Name 'TestSource' + } + catch { + Add-WinGetSource -Name 'TestSource' -Arg 'https://localhost:5001/TestKit/' + } + } + + function RemoveTestSource { + try { + Get-WinGetSource -Name 'TestSource' + } + catch { + # Source Remove requires admin privileges, this will only execute successfully in an elevated PowerShell. + # This is a workaround to an issue where the server takes longer than expected to terminate when + # running from PowerShell. This can cause other E2E tests to fail when attempting to reset the test source. + Start-Process -FilePath "wingetdev" -ArgumentList "source remove TestSource" + } + } +} + +Describe 'Get-WinGetVersion' { + + It 'Get-WinGetVersion' { + $version = Get-WinGetVersion + $version | Should -Not -BeNullOrEmpty -ErrorAction Stop + } } -Describe 'Get-WinGetSource' { - - It 'Get Test Source' { +Describe 'Get|Add|Reset-WinGetSource' { + + BeforeAll { + AddTestSource + } + + It 'Get Test source' { $source = Get-WinGetSource -Name 'TestSource' + + $source | Should -Not -BeNullOrEmpty -ErrorAction Stop $source.Name | Should -Be 'TestSource' $source.Argument | Should -Be 'https://localhost:5001/TestKit/' $source.Type | Should -Be 'Microsoft.PreIndexed.Package' } + + It 'Get fake source' { + { Get-WinGetSource -Name 'Fake' } | Should -Throw + } + + # This tests require admin + It 'Reset Test source' { + Reset-WinGetSource -Name TestSource + } } Describe 'Find-WinGetPackage' { + + BeforeAll { + AddTestSource + } + It 'Given no parameters, lists all available packages' { $allPackages = Find-WinGetPackage -Source TestSource $allPackages.Count | Should -BeGreaterThan 0 } It 'Find by Id' { - $package = Find-WinGetPackage -Source 'TestSource' -Id 'AppInstallerTest.TestExeInstaller' + $package = Find-WinGetPackage -Source 'TestSource' -Id 'AppInstallerTest.TestExampleInstaller' $package | Should -Not -BeNullOrEmpty -ErrorAction Stop - $package.Name | Should -Be 'TestExeInstaller' - $package.Id | Should -Be 'AppInstallerTest.TestExeInstaller' - $package.Version | Should -Be '2.0.0.0' + $package.Name | Should -Be 'TestExampleInstaller' + $package.Id | Should -Be 'AppInstallerTest.TestExampleInstaller' + $package.Version | Should -Be '1.2.3.4' $package.Source | Should -Be 'TestSource' } @@ -56,7 +112,7 @@ Describe 'Find-WinGetPackage' { } It 'Find package and verify PackageVersionInfo' { - $package = Find-WinGetPackage -Source 'TestSource' -Id 'AppInstallerTest.TestPortableExe' -Exact + $package = Find-WinGetPackage -Source 'TestSource' -Id 'AppInstallerTest.TestPortableExe' -MatchOption Equals $package | Should -Not -BeNullOrEmpty -ErrorAction Stop $package.AvailableVersions[0] | Should -Be '3.0.0.0' @@ -73,17 +129,23 @@ Describe 'Find-WinGetPackage' { Describe 'Install|Update|Uninstall-WinGetPackage' { + BeforeAll { + AddTestSource + } + It 'Install by Id' { $result = Install-WinGetPackage -Id AppInstallerTest.TestExeInstaller -Version '1.0.0.0' + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.InstallerErrorCode | Should -Be 0 $result.Status | Should -Be 'Ok' $result.RebootRequired | Should -Be 'False' } It 'Install by exact Name and Version' { - $result = Install-WinGetPackage -Name TestPortableExe -Version '2.0.0.0' -Exact + $result = Install-WinGetPackage -Name TestPortableExe -Version '2.0.0.0' -MatchOption Equals + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.InstallerErrorCode | Should -Be 0 $result.Status | Should -Be 'Ok' $result.RebootRequired | Should -Be 'False' @@ -92,14 +154,16 @@ Describe 'Install|Update|Uninstall-WinGetPackage' { It 'Update by Id' { $result = Update-WinGetPackage -Id AppInstallerTest.TestExeInstaller + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.InstallerErrorCode | Should -Be 0 $result.Status | Should -Be 'Ok' $result.RebootRequired | Should -Be 'False' } - It 'Update by Name and Version' { + It 'Update by Name' { $result = Update-WinGetPackage -Name TestPortableExe + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.InstallerErrorCode | Should -Be 0 $result.Status | Should -Be 'Ok' $result.RebootRequired | Should -Be 'False' @@ -108,6 +172,7 @@ Describe 'Install|Update|Uninstall-WinGetPackage' { It 'Uninstall by Id' { $result = Uninstall-WinGetPackage -Id AppInstallerTest.TestExeInstaller + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.UninstallerErrorCode | Should -Be 0 $result.Status | Should -Be 'Ok' $result.RebootRequired | Should -Be 'False' @@ -116,6 +181,7 @@ Describe 'Install|Update|Uninstall-WinGetPackage' { It 'Uninstall by Name' { $result = Uninstall-WinGetPackage -Name TestPortableExe + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.UninstallerErrorCode | Should -Be 0 $result.Status | Should -Be 'Ok' $result.RebootRequired | Should -Be 'False' @@ -123,13 +189,13 @@ Describe 'Install|Update|Uninstall-WinGetPackage' { AfterAll { # Uninstall all test packages after each for proper cleanup. - $testExe = Get-WinGetPackage -Id AppInstallerTest.TestExeInstaller + $testExe = Get-WinGetPackage -Id AppInstallerTest.TestExeInstaller -MatchOption Equals if ($testExe.Count -gt 0) { Uninstall-WinGetPackage -Id AppInstallerTest.TestExeInstaller - } + } - $testPortable = Get-WinGetPackage -Id AppInstallerTest.TestPortableExe + $testPortable = Get-WinGetPackage -Id AppInstallerTest.TestPortableExe -MatchOption Equals if ($testPortable.Count -gt 0) { Uninstall-WinGetPackage -Id AppInstallerTest.TestPortableExe @@ -138,10 +204,15 @@ Describe 'Install|Update|Uninstall-WinGetPackage' { } Describe 'Get-WinGetPackage' { - + + BeforeAll { + AddTestSource + } + It 'Install by Id' { $result = Install-WinGetPackage -Id AppInstallerTest.TestExeInstaller -Version '1.0.0.0' + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.InstallerErrorCode | Should -Be 0 $result.Status | Should -Be 'Ok' $result.RebootRequired | Should -Be 'False' @@ -153,7 +224,7 @@ Describe 'Get-WinGetPackage' { $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.Name | Should -Be 'TestExeInstaller' $result.Id | Should -Be 'AppInstallerTest.TestExeInstaller' - $result.Version | Should -Be '1.0.0.0' + $result.InstalledVersion | Should -Be '1.0.0.0' $result.Source | Should -Be 'TestSource' $result.AvailableVersions[0] | Should -Be '2.0.0.0' } @@ -164,7 +235,7 @@ Describe 'Get-WinGetPackage' { $result | Should -Not -BeNullOrEmpty -ErrorAction Stop $result.Name | Should -Be 'TestExeInstaller' $result.Id | Should -Be 'AppInstallerTest.TestExeInstaller' - $result.Version | Should -Be '1.0.0.0' + $result.InstalledVersion | Should -Be '1.0.0.0' $result.Source | Should -Be 'TestSource' $result.AvailableVersions[0] | Should -Be '2.0.0.0' } @@ -179,7 +250,237 @@ Describe 'Get-WinGetPackage' { } } +Describe 'Get-WinGetUserSettings' { + + It 'Get settings' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + SetWinGetSettingsHelper $ogSettings + + $userSettings = Get-WinGetUserSettings + $userSettings | Should -Not -BeNullOrEmpty -ErrorAction Stop + $userSettings.Count | Should -Be 2 + $userSettings.visual.progressBar | Should -Be 'rainbow' + $userSettings.experimentalFeatures.experimentalArg | Should -Be $false + $userSettings.experimentalFeatures.experimentalCmd | Should -Be $true + } + + It 'Get settings. Bad json file' { + Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." + { Get-WinGetUserSettings } | Should -Throw + } +} + +Describe 'Test-WinGetUserSettings' { + + It 'Bad json file' { + Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." + + $inputSettings = @{ visual= @{ progressBar="retro"} } + Test-WinGetUserSettings -UserSettings $inputSettings | Should -Be $false + } + + It 'Equal' { + $ogSettings = @{ visual= @{ progressBar="retro"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + SetWinGetSettingsHelper $ogSettings + + Test-WinGetUserSettings -UserSettings $ogSettings | Should -Be $true + } + + It 'Equal. Ignore schema' { + Set-Content -Path $settingsFilePath -Value '{ "$schema": "https://aka.ms/winget-settings.schema.json", "visual": { "progressBar": "retro" } }' + + $inputSettings = @{ visual= @{ progressBar="retro"} } + Test-WinGetUserSettings -UserSettings $inputSettings | Should -Be $true + } + + It 'Not Equal string' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="retro"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + Test-WinGetUserSettings -UserSettings $inputSettings | Should -Be $false + } + + It 'Not Equal bool' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$true}} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + Test-WinGetUserSettings -UserSettings $inputSettings | Should -Be $false + } + + It 'Not Equal. More settings' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true }} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false }} + Test-WinGetUserSettings -UserSettings $inputSettings | Should -Be $false + } + + It 'Not Equal. More settings input' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; }} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + Test-WinGetUserSettings -UserSettings $inputSettings | Should -Be $false + } + + It 'Equal IgnoreNotSet' { + $ogSettings = @{ visual= @{ progressBar="retro"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + SetWinGetSettingsHelper $ogSettings + + Test-WinGetUserSettings -UserSettings $ogSettings -IgnoreNotSet | Should -Be $true + } + + It 'Equal IgnoreNotSet. More settings' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true }} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false }} + Test-WinGetUserSettings -UserSettings $inputSettings -IgnoreNotSet | Should -Be $true + } + + It 'Not Equal IgnoreNotSet. More settings input' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; }} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + Test-WinGetUserSettings -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false + } + + It 'Not Equal bool IgnoreNotSet' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$true}} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} + Test-WinGetUserSettings -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false + } + + It 'Not Equal array IgnoreNotSet' { + $ogSettings = @{ installBehavior= @{ preferences= @{ architectures = @("x86", "x64")} }} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ installBehavior= @{ preferences= @{ architectures = @("x86", "arm64")} }} + Test-WinGetUserSettings -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false + } + + It 'Not Equal wrong type IgnoreNotSet' { + $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$true}} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=4 ; experimentalCmd=$true}} + Test-WinGetUserSettings -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false + } + + AfterAll { + SetWinGetSettingsHelper @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true } } + } +} + +Describe 'Set-WinGetUserSettings' { + + It 'Overwrites' { + $ogSettings = @{ source= @{ autoUpdateIntervalInMinutes=3}} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$false}} + $result = Set-WinGetUserSettings -UserSettings $inputSettings + + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.'$schema' | Should -Not -BeNullOrEmpty + $result.visual | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.visual.progressBar | Should -Be "rainbow" + $result.experimentalFeatures | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.experimentalFeatures.experimentalArg | Should -Be $true + $result.experimentalFeatures.experimentalCmd | Should -Be $false + $result.source | Should -BeNullOrEmpty + } + + It 'Merge' { + $ogSettings = @{ source= @{ autoUpdateIntervalInMinutes=3}} + SetWinGetSettingsHelper $ogSettings + + $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$false}} + $result = Set-WinGetUserSettings -UserSettings $inputSettings -Merge + + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.'$schema' | Should -Not -BeNullOrEmpty + $result.visual | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.visual.progressBar | Should -Be "rainbow" + $result.experimentalFeatures | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.experimentalFeatures.experimentalArg | Should -Be $true + $result.experimentalFeatures.experimentalCmd | Should -Be $false + $result.source | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.source.autoUpdateIntervalInMinutes | Should -Be 3 + } + + It 'Schema.' { + Set-Content -Path $settingsFilePath -Value '{ "$schema": "https://aka.ms/winget-settings.schema.json", "visual": { "progressBar": "retro" } }' + + $inputSettings = @{ visual= @{ progressBar="retro"} } + $result = Set-WinGetUserSettings -UserSettings $inputSettings + + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.'$schema' | Should -Not -BeNullOrEmpty + $result.visual.progressBar | Should -Be "retro" + } + + It 'Overwrites Bad json file' { + Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." + + $inputSettings = @{ visual= @{ progressBar="retro"} } + $result = Set-WinGetUserSettings -UserSettings $inputSettings + + $result | Should -Not -BeNullOrEmpty -ErrorAction Stop + $result.'$schema' | Should -Not -BeNullOrEmpty + $result.visual.progressBar | Should -Be "retro" + } + + It 'Overwrites Bad json file' { + Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." + + $inputSettings = @{ visual= @{ progressBar="retro"} } + { Set-WinGetUserSettings -UserSettings $inputSettings -Merge } | Should -Throw + } + + AfterAll { + SetWinGetSettingsHelper @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true } } + } +} + +Describe 'Get|Enable|Disable-WinGetSetting' { + + It 'Get-WinGetSetting' { + $settings = Get-WinGetSettings + $settings | Should -Not -BeNullOrEmpty -ErrorAction Stop + $settings.'$schema' | Should -Not -BeNullOrEmpty + $settings.adminSettings | Should -Not -BeNullOrEmpty + $settings.userSettingsFile | Should -Be $settingsFilePath + } + + # This tests require admin + It 'Enable|Disable' { + $settings = Get-WinGetSettings + $settings | Should -Not -BeNullOrEmpty -ErrorAction Stop + $settings.adminSettings | Should -Not -BeNullOrEmpty + $settings.adminSettings.LocalManifestFiles | Should -Be $false + + Enable-WinGetSetting -Name LocalManifestFiles + + $afterEnable = Get-WinGetSettings + $afterEnable | Should -Not -BeNullOrEmpty -ErrorAction Stop + $afterEnable.adminSettings | Should -Not -BeNullOrEmpty + $afterEnable.adminSettings.LocalManifestFiles | Should -Be $true + + Disable-WingetSetting -Name LocalManifestFiles + + $afterDisable = Get-WinGetSettings + $afterDisable | Should -Not -BeNullOrEmpty -ErrorAction Stop + $afterDisable.adminSettings | Should -Not -BeNullOrEmpty + $afterDisable.adminSettings.LocalManifestFiles | Should -Be $false + } +} + AfterAll { - # Source Remove requires admin privileges, this will only execute successfully in an elevated PowerShell. - wingetdev source remove 'TestSource' + RemoveTestSource } \ No newline at end of file diff --git a/src/PowerShell/tests/RunTests.ps1 b/src/PowerShell/tests/RunTests.ps1 new file mode 100644 index 0000000000..5321558794 --- /dev/null +++ b/src/PowerShell/tests/RunTests.ps1 @@ -0,0 +1,44 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +[CmdletBinding()] +param( + [string]$testModulesPath, + [string]$outputPath, + [string]$packageLayoutPath +) + +# This updates pester not always necessary but worth noting +Install-Module -Name Pester -Force -SkipPublisherCheck +Import-Module Pester + +if (-not [System.String]::IsNullOrEmpty($testModulesPath)) +{ + $env:PSModulePath += ";$testModulesPath" +} + +if (-not (Test-Path $outputPath)) +{ + New-Item -Path $outputPath -ItemType Directory +} +else +{ + Remove-Item $outputPath\* -Recurse -Force +} + +# Register the package +if (-not [System.String]::IsNullOrEmpty($packageLayoutPath)) +{ + $local:packageManifestPath = Join-Path $packageLayoutPath "AppxManifest.xml" + + Import-Module Appx -UseWindowsPowerShell + Add-AppxPackage -Register $local:packageManifestPath + + # Configure crash dump and log file settings + $local:settingsExport = ConvertFrom-Json (wingetdev.exe settings export) + $local:settingsFilePath = $local:settingsExport.userSettingsFile + $local:settingsFileContent = ConvertTo-Json @{ debugging= @{ enableSelfInitiatedMinidump=$true ; keepAllLogFiles=$true } } + + Set-Content -Path $local:settingsFilePath -Value $local:settingsFileContent +} + +Invoke-Pester -Script $PSScriptRoot\Microsoft.WinGet.Client.Tests.ps1 -OutputFile $outputPath\Tests-WinGetClient.XML -OutputFormat NUnitXML diff --git a/templates/e2e-setup.yml b/templates/e2e-setup.yml index efff240da3..adb1f496aa 100644 --- a/templates/e2e-setup.yml +++ b/templates/e2e-setup.yml @@ -1,8 +1,8 @@ # Configures local test source and local PowerShell repository. parameters: -- name: source +- name: sourceDir type: string -- name: buildOutDir +- name: localhostWebServerArgs type: string steps: @@ -21,18 +21,18 @@ steps: - task: PowerShell@2 displayName: Install Root Certificate inputs: - filePath: '${{ parameters.source }}\src\LocalhostWebServer\InstallDevCert.ps1' + filePath: '${{ parameters.sourceDir }}\src\LocalhostWebServer\InstallDevCert.ps1' arguments: '-pfxpath $(HTTPSDevCert.secureFilePath) -password microsoft' - task: PowerShell@2 displayName: Launch LocalhostWebServer inputs: - filePath: '${{ parameters.source }}\src\LocalhostWebServer\Run-LocalhostWebServer.ps1' - arguments: '-BuildRoot ${{ parameters.buildOutDir }}\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -CertPath $(HTTPSDevCert.secureFilePath) -CertPassword microsoft -OutCertFile $(Agent.TempDirectory)\servercert.cer -LocalSourceJson ${{ parameters.source }}\src\AppInstallerCLIE2ETests\TestData\localsource.json' + filePath: '${{ parameters.sourceDir }}\src\LocalhostWebServer\Run-LocalhostWebServer.ps1' + arguments: '-CertPath $(HTTPSDevCert.secureFilePath) -CertPassword microsoft -OutCertFile $(Agent.TempDirectory)\servercert.cer ${{ parameters.localhostWebServerArgs }}' - task: PowerShell@2 displayName: Setup Local PS Repository inputs: - filePath: '${{ parameters.source }}\src\AppInstallerCLIE2ETests\TestData\Configuration\Init-TestRepository.ps1' + filePath: '${{ parameters.sourceDir }}\src\AppInstallerCLIE2ETests\TestData\Configuration\Init-TestRepository.ps1' arguments: '-Force' pwsh: true