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