Microsoft.WinGet.Client.Tests.ps1 (37887B)
1 # Copyright (c) Microsoft Corporation. All rights reserved. 2 # Licensed under the MIT License. 3 4 <# 5 .Synopsis 6 Pester tests related to the Microsoft.WinGet.Client PowerShell module. 7 The tests require the localhost web server to be running and serving the test data. 8 'Invoke-Pester' should be called in an admin PowerShell window. 9 #> 10 [CmdletBinding()] 11 param( 12 # Whether to use production or developement targets. 13 [switch]$TargetProduction 14 ) 15 16 BeforeAll { 17 if ($TargetProduction) 18 { 19 $wingetExeName = "winget.exe" 20 } 21 else 22 { 23 $wingetExeName = "wingetdev.exe" 24 } 25 26 $settingsFilePath = (ConvertFrom-Json (& $wingetExeName settings export)).userSettingsFile 27 $originalSettingsContent = Get-Content -Path $settingsFilePath -Raw 28 29 $deviceGroupPolicyRoot = "HKLM:\Software\Policies\Microsoft\Windows" 30 $wingetPolicyKeyName = "AppInstaller" 31 $wingetGroupPolicyRegistryRoot = $deviceGroupPolicyRoot + "\" + $wingetPolicyKeyName 32 33 Import-Module Microsoft.WinGet.Client 34 35 function SetWinGetSettingsHelper($settings) { 36 $content = ConvertTo-Json $settings -Depth 4 37 Set-Content -Path $settingsFilePath -Value $content 38 } 39 40 function RestoreWinGetSettings() { 41 Set-Content -Path $settingsFilePath -Value $originalSettingsContent 42 } 43 44 # Source Add requires admin privileges, this will only execute successfully in an elevated PowerShell. 45 function AddTestSource { 46 try { 47 Get-WinGetSource -Name 'TestSource' 48 } 49 catch { 50 Add-WinGetSource -Name 'TestSource' -Arg 'https://localhost:5001/TestKit/' -TrustLevel 'Trusted' 51 } 52 } 53 54 # This is a workaround to an issue where the server takes longer than expected to terminate when 55 # running from PowerShell. This can cause other E2E tests to fail when attempting to reset the test source. 56 function RemoveTestSource { 57 try { 58 # Source Remove requires admin privileges, this will only execute successfully in an elevated PowerShell. 59 $testSource = Get-WinGetSource | Where-Object -Property 'Name' -eq 'TestSource' 60 if ($null -ne $testSource) 61 { 62 # Source Remove requires admin privileges 63 Remove-WinGetSource -Name 'TestSource' 64 } 65 } 66 catch { 67 # Non-admin 68 Start-Process -FilePath $wingetExeName -ArgumentList "source remove TestSource" 69 } 70 } 71 72 function CreatePolicyKeyIfNotExists() 73 { 74 $registryExists = test-path -Path $wingetGroupPolicyRegistryRoot 75 76 if(-Not($registryExists)) 77 { 78 New-Item -Path $deviceGroupPolicyRoot -Name $wingetPolicyKeyName 79 } 80 } 81 82 function CleanupGroupPolicyKeyIfExists() 83 { 84 $registryExists = test-path -Path $wingetGroupPolicyRegistryRoot 85 86 if($registryExists) 87 { 88 Remove-Item -Path $wingetGroupPolicyRegistryRoot -Recurse 89 } 90 } 91 92 function CleanupGroupPolicies() 93 { 94 $registryExists = test-path -Path $wingetGroupPolicyRegistryRoot 95 96 if($registryExists) 97 { 98 Remove-ItemProperty -Path $wingetGroupPolicyRegistryRoot -Name * 99 } 100 } 101 102 function WaitForWindowsPackageManagerServer([bool]$force = $false) 103 { 104 $processes = Get-Process | Where-Object { $_.Name -eq "WindowsPackageManagerServer" } 105 foreach ($p in $processes) 106 { 107 if ($force) 108 { 109 Stop-Process $p 110 } 111 112 $timeout = 300 113 $secondsToWait = 5 114 $time = 0 115 while ($p.HasExited -eq $false) 116 { 117 $time += $secondsToWait 118 if ($time -ge $timeout ) 119 { 120 throw "Timeout waiting for $($p.Id) to exit" 121 } 122 Start-Sleep -Seconds 5 123 } 124 } 125 } 126 127 function GetRandomTestDirectory() 128 { 129 return Join-Path -Path $env:Temp -ChildPath "WingetPwshTest-$(New-Guid)" 130 } 131 132 function Validate-WinGetResultCommonFields([psobject]$result, [psobject]$expected) { 133 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 134 $result.Id | Should -Be $expected.Id 135 $result.Name | Should -Be $expected.Name 136 $result.Source | Should -Be $expected.Source 137 $result.Status | Should -Be $expected.Status 138 } 139 140 function Validate-WinGetPackageOperationResult([psobject]$result, [psobject]$expected, [string]$operationType) 141 { 142 Validate-WinGetResultCommonFields $result $expected 143 $result.RebootRequired | Should -Be $expected.RebootRequired 144 145 switch ($operationType) { 146 'install' { 147 $result.InstallerErrorCode | Should -Be $expected.InstallerErrorCode 148 } 149 'update' { 150 $result.InstallerErrorCode | Should -Be $expected.InstallerErrorCode 151 } 152 'repair' { 153 $result.RepairErrorCode | Should -Be $expected.RepairErrorCode 154 } 155 'uninstall' { 156 $result.UninstallerErrorCode | Should -Be $expected.UninstallerErrorCode 157 } 158 default { 159 throw "Unknown operation type: $operationType" 160 } 161 } 162 } 163 } 164 165 Describe 'Get-WinGetVersion' { 166 167 It 'Get-WinGetVersion' { 168 $version = Get-WinGetVersion 169 $version | Should -Not -BeNullOrEmpty -ErrorAction Stop 170 } 171 } 172 173 Describe 'Reset-WinGetSource' { 174 BeforeAll { 175 AddTestSource 176 } 177 178 # Requires admin 179 It 'Resets all sources' { 180 Reset-WinGetSource -All 181 } 182 183 It 'Test source should be removed' { 184 { Get-WinGetSource -Name 'TestSource' } | Should -Throw 185 } 186 } 187 188 Describe 'Get|Add|Reset-WinGetSource' { 189 190 BeforeAll { 191 Add-WinGetSource -Name 'TestSource' -Arg 'https://localhost:5001/TestKit/' -TrustLevel 'Trusted' -Explicit 192 } 193 194 It 'Get Test source' { 195 $source = Get-WinGetSource -Name 'TestSource' 196 197 $source | Should -Not -BeNullOrEmpty -ErrorAction Stop 198 $source.Name | Should -Be 'TestSource' 199 $source.Argument | Should -Be 'https://localhost:5001/TestKit/' 200 $source.Type | Should -Be 'Microsoft.PreIndexed.Package' 201 $source.TrustLevel | Should -Be 'Trusted' 202 $source.Explicit | Should -Be $true 203 } 204 205 It 'Get fake source' { 206 { Get-WinGetSource -Name 'Fake' } | Should -Throw 207 } 208 209 # This tests require admin 210 It 'Reset Test source' { 211 Reset-WinGetSource -Name TestSource 212 } 213 } 214 215 Describe 'Find-WinGetPackage' { 216 217 BeforeAll { 218 AddTestSource 219 } 220 221 It 'Given no parameters, lists all available packages' { 222 $allPackages = Find-WinGetPackage -Source TestSource 223 $allPackages.Count | Should -BeGreaterThan 0 224 } 225 226 It 'Find by Id' { 227 $package = Find-WinGetPackage -Source 'TestSource' -Id 'AppInstallerTest.TestExampleInstaller' 228 229 $package | Should -Not -BeNullOrEmpty -ErrorAction Stop 230 $package.Name | Should -Be 'TestExampleInstaller' 231 $package.Id | Should -Be 'AppInstallerTest.TestExampleInstaller' 232 $package.Version | Should -Be '1.2.3.4' 233 $package.Source | Should -Be 'TestSource' 234 } 235 236 It 'Find by Name' { 237 $package = Find-WinGetPackage -Source 'TestSource' -Name 'TestPortableExe' 238 239 $package | Should -Not -BeNullOrEmpty -ErrorAction Stop 240 $package[0].Name | Should -Be 'TestPortableExe' 241 $package[1].Name | Should -Be 'TestPortableExeWithCommand' 242 } 243 244 It 'Find by Name sort by Version' { 245 $package = Find-WinGetPackage -Source 'TestSource' -Name 'TestPortableExe' | Sort-Object 'Version' 246 247 $package | Should -Not -BeNullOrEmpty -ErrorAction Stop 248 $package[0].Name | Should -Be 'TestPortableExeWithCommand' 249 $package[1].Name | Should -Be 'TestPortableExe' 250 } 251 252 It 'Find package and verify PackageVersionInfo' { 253 $package = Find-WinGetPackage -Source 'TestSource' -Id 'AppInstallerTest.TestPortableExe' -MatchOption Equals 254 255 $package | Should -Not -BeNullOrEmpty -ErrorAction Stop 256 $package.AvailableVersions[0] | Should -Be '3.0.0.0' 257 $package.AvailableVersions[1] | Should -Be '2.0.0.0' 258 $package.AvailableVersions.Count | Should -Be 4 259 260 $packageVersionInfo = $package.GetPackageVersionInfo("3.0.0.0") 261 $packageVersionInfo.DisplayName | Should -Be 'TestPortableExe' 262 $packageVersionInfo.Id | Should -Be 'AppInstallerTest.TestPortableExe' 263 $packageVersionInfo.CompareToVersion("2.0.0.0") | Should -Be 'Greater' 264 $packageVersionInfo.CompareToVersion("4.0.0.0") | Should -Be 'Lesser' 265 } 266 } 267 268 Describe 'Install|Update|Uninstall-WinGetPackage' { 269 270 BeforeAll { 271 AddTestSource 272 } 273 274 BeforeEach { 275 $expectedExeInstallerResult = [PSCustomObject]@{ 276 Id = "AppInstallerTest.TestExeInstaller" 277 Name = "TestExeInstaller" 278 Source = "TestSource" 279 Status = 'Ok' 280 RebootRequired = 'False' 281 InstallerErrorCode = 0 282 UninstallerErrorCode = 0 283 } 284 285 $expectedPortableInstallerResult = [PSCustomObject]@{ 286 Id = "AppInstallerTest.TestPortableExe" 287 Name = "TestPortableExe" 288 Source = "TestSource" 289 Status = 'Ok' 290 RebootRequired = 'False' 291 InstallerErrorCode = 0 292 UninstallerErrorCode = 0 293 } 294 } 295 296 It 'Install by Id' { 297 $result = Install-WinGetPackage -Id AppInstallerTest.TestExeInstaller -Version '1.0.0.0' 298 Validate-WinGetPackageOperationResult $result $expectedExeInstallerResult 'install' 299 } 300 301 It 'Install by exact Name and Version' { 302 $result = Install-WinGetPackage -Name TestPortableExe -Version '2.0.0.0' -MatchOption Equals 303 Validate-WinGetPackageOperationResult $result $expectedPortableInstallerResult 'install' 304 } 305 306 It 'Update by Id' { 307 $result = Update-WinGetPackage -Id AppInstallerTest.TestExeInstaller 308 Validate-WinGetPackageOperationResult $result $expectedExeInstallerResult 'update' 309 } 310 311 It 'Update by Name' { 312 $result = Update-WinGetPackage -Name TestPortableExe 313 Validate-WinGetPackageOperationResult $result $expectedPortableInstallerResult 'update' 314 } 315 316 It 'Uninstall by Id' { 317 $result = Uninstall-WinGetPackage -Id AppInstallerTest.TestExeInstaller 318 Validate-WinGetPackageOperationResult $result $expectedExeInstallerResult 'uninstall' 319 } 320 321 It 'Uninstall by Name' { 322 $result = Uninstall-WinGetPackage -Name TestPortableExe 323 Validate-WinGetPackageOperationResult $result $expectedPortableInstallerResult 'uninstall' 324 } 325 326 AfterAll { 327 # Uninstall all test packages after each for proper cleanup. 328 $testExe = Get-WinGetPackage -Id AppInstallerTest.TestExeInstaller -MatchOption Equals 329 if ($testExe.Count -gt 0) 330 { 331 Uninstall-WinGetPackage -Id AppInstallerTest.TestExeInstaller 332 } 333 334 $testPortable = Get-WinGetPackage -Id AppInstallerTest.TestPortableExe -MatchOption Equals 335 if ($testPortable.Count -gt 0) 336 { 337 Uninstall-WinGetPackage -Id AppInstallerTest.TestPortableExe 338 } 339 } 340 } 341 342 Describe 'Install|Repair|Uninstall-WinGetPackage' { 343 344 BeforeAll { 345 AddTestSource 346 } 347 348 Context 'MSIX Repair Scenario' { 349 BeforeEach { 350 $expectedResult = [PSCustomObject]@{ 351 Id = "AppInstallerTest.TestMsixInstaller" 352 Name = "TestMsixInstaller" 353 Source = "TestSource" 354 Status = 'Ok' 355 RebootRequired = 'False' 356 InstallerErrorCode = 0 357 RepairErrorCode = 0 358 UninstallerErrorCode = 0 359 } 360 } 361 362 It 'Install MSIX By Id' { 363 $result = Install-WinGetPackage -Id AppInstallerTest.TestMsixInstaller 364 Validate-WinGetPackageOperationResult $result $expectedResult 'install' 365 } 366 367 It 'Repair MSIX By Id' { 368 $result = Repair-WinGetPackage -Id AppInstallerTest.TestMsixInstaller 369 Validate-WinGetPackageOperationResult $result $expectedResult 'repair' 370 } 371 372 It 'Uninstall MSIX By Id' { 373 $result = Uninstall-WinGetPackage -Id AppInstallerTest.TestMsixInstaller 374 Validate-WinGetPackageOperationResult $result $expectedResult 'uninstall' 375 } 376 } 377 378 Context 'Burn installer "Modify" Repair Scenario' { 379 BeforeEach { 380 $expectedResult = [PSCustomObject]@{ 381 Id = "AppInstallerTest.TestModifyRepair" 382 Name = "TestModifyRepair" 383 Source = "TestSource" 384 Status = 'Ok' 385 RebootRequired = 'False' 386 InstallerErrorCode = 0 387 RepairErrorCode = 0 388 UninstallerErrorCode = 0 389 } 390 } 391 392 It 'Install Burn Installer By Id' { 393 $result = Install-WinGetPackage -Id AppInstallerTest.TestModifyRepair 394 Validate-WinGetPackageOperationResult $result $expectedResult 'install' 395 } 396 397 It 'Repair Burn Installer By Id' { 398 $result = Repair-WinGetPackage -Id AppInstallerTest.TestModifyRepair 399 Validate-WinGetPackageOperationResult $result $expectedResult 'repair' 400 } 401 402 It 'Uninstall Burn Installer By Id' { 403 $result = Uninstall-WinGetPackage -Id AppInstallerTest.TestModifyRepair 404 Validate-WinGetPackageOperationResult $result $expectedResult 'uninstall' 405 } 406 } 407 408 Context 'Exe Installer "Uninstaller" Repair Scenario' { 409 BeforeEach { 410 $expectedResult = [PSCustomObject]@{ 411 Id = "AppInstallerTest.UninstallerRepair" 412 Name = "UninstallerRepair" 413 Source = "TestSource" 414 Status = 'Ok' 415 RebootRequired = 'False' 416 InstallerErrorCode = 0 417 RepairErrorCode = 0 418 UninstallerErrorCode = 0 419 } 420 } 421 422 It 'Install Exe Installer By Id' { 423 $result = Install-WinGetPackage -Id AppInstallerTest.UninstallerRepair 424 Validate-WinGetPackageOperationResult $result $expectedResult 'install' 425 } 426 427 It 'Uninstaller Repair Exe Installer By Id' { 428 $result = Repair-WinGetPackage -Id AppInstallerTest.UninstallerRepair 429 Validate-WinGetPackageOperationResult $result $expectedResult 'repair' 430 } 431 432 It "Uninstall Exe Installer By Id" { 433 $result = Uninstall-WinGetPackage -Id AppInstallerTest.UninstallerRepair 434 Validate-WinGetPackageOperationResult $result $expectedResult 'uninstall' 435 } 436 } 437 438 Context 'Inno "Installer" Repair Scenario' { 439 BeforeEach { 440 $expectedResult = [PSCustomObject]@{ 441 Id = "AppInstallerTest.TestInstallerRepair" 442 Name = "TestInstallerRepair" 443 Source = "TestSource" 444 Status = 'Ok' 445 RebootRequired = 'False' 446 InstallerErrorCode = 0 447 RepairErrorCode = 0 448 UninstallerErrorCode = 0 449 } 450 } 451 452 It 'Install Exe Installer By Id' { 453 $result = Install-WinGetPackage -Id AppInstallerTest.TestInstallerRepair 454 Validate-WinGetPackageOperationResult $result $expectedResult 'install' 455 } 456 457 It 'Installer Repair Exe Installer By Id' { 458 $result = Repair-WinGetPackage -Id AppInstallerTest.TestInstallerRepair 459 Validate-WinGetPackageOperationResult $result $expectedResult 'repair' 460 } 461 462 It "Uninstall Exe Installer By Id" { 463 $result = Uninstall-WinGetPackage -Id AppInstallerTest.TestInstallerRepair 464 Validate-WinGetPackageOperationResult $result $expectedResult 'uninstall' 465 } 466 } 467 468 AfterAll { 469 # Uninstall all test packages after each for proper cleanup. 470 $testMsix = Get-WinGetPackage -Id AppInstallerTest.TestMsixInstaller 471 if ($testMsix.Count -gt 0) 472 { 473 Uninstall-WinGetPackage -Id AppInstallerTest.TestMsixInstaller 474 } 475 476 $testBurn = Get-WinGetPackage -Id AppInstallerTest.TestModifyRepair 477 if ($testBurn.Count -gt 0) 478 { 479 Uninstall-WinGetPackage -Id AppInstallerTest.TestModifyRepair 480 } 481 482 $testExe = Get-WinGetPackage -Id AppInstallerTest.UninstallerRepair 483 if ($testExe.Count -gt 0) 484 { 485 Uninstall-WinGetPackage -Id AppInstallerTest.UninstallerRepair 486 } 487 488 $testInno = Get-WinGetPackage -Id AppInstallerTest.TestInstallerRepair 489 if ($testInno.Count -gt 0) 490 { 491 Uninstall-WinGetPackage -Id AppInstallerTest.TestInstallerRepair 492 } 493 } 494 } 495 496 Describe 'Get-WinGetPackage' { 497 498 BeforeAll { 499 AddTestSource 500 } 501 502 It 'Install by Id' { 503 $result = Install-WinGetPackage -Id AppInstallerTest.TestExeInstaller -Version '1.0.0.0' 504 505 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 506 $result.Id | Should -Be "AppInstallerTest.TestExeInstaller" 507 $result.Name | Should -Be "TestExeInstaller" 508 $result.Source | Should -Be "TestSource" 509 $result.InstallerErrorCode | Should -Be 0 510 $result.Status | Should -Be 'Ok' 511 $result.RebootRequired | Should -Be 'False' 512 } 513 514 It 'Get package by Id' { 515 $result = Get-WinGetPackage -Id AppInstallerTest.TestExeInstaller 516 517 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 518 $result.Name | Should -Be 'TestExeInstaller' 519 $result.Id | Should -Be 'AppInstallerTest.TestExeInstaller' 520 $result.InstalledVersion | Should -Be '1.0.0.0' 521 $result.Source | Should -Be 'TestSource' 522 $result.AvailableVersions[0] | Should -Be '2.0.0.0' 523 } 524 525 It 'Get package by Name' { 526 $result = Get-WinGetPackage -Name TestExeInstaller 527 528 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 529 $result.Name | Should -Be 'TestExeInstaller' 530 $result.Id | Should -Be 'AppInstallerTest.TestExeInstaller' 531 $result.InstalledVersion | Should -Be '1.0.0.0' 532 $result.Source | Should -Be 'TestSource' 533 $result.AvailableVersions[0] | Should -Be '2.0.0.0' 534 } 535 536 AfterAll { 537 # Uninstall all test packages after each for proper cleanup. 538 $testExe = Get-WinGetPackage -Id AppInstallerTest.TestExeInstaller 539 if ($testExe.Count -gt 0) 540 { 541 Uninstall-WinGetPackage -Id AppInstallerTest.TestExeInstaller 542 } 543 } 544 } 545 546 Describe 'Export-WinGetPackage' { 547 548 BeforeAll { 549 AddTestSource 550 } 551 552 It 'Download by Id' { 553 $testDirectory = GetRandomTestDirectory 554 $result = Export-WinGetPackage -Id AppInstallerTest.TestExeInstaller -Version '1.0.0.0' -DownloadDirectory $testDirectory 555 556 $result | Should -Not -BeNullOrEmpty 557 $result.Id | Should -Be "AppInstallerTest.TestExeInstaller" 558 $result.Name | Should -Be "TestExeInstaller" 559 $result.Source | Should -Be "TestSource" 560 $result.Status | Should -Be 'Ok' 561 562 # Download directory should be created and have exactly two files (installer and manifest file). 563 Test-Path -Path $testDirectory | Should -Be $true 564 (Get-ChildItem -Path $testDirectory -Force | Measure-Object).Count | Should -Be 2 565 } 566 567 It 'Download by Locale' { 568 $testDirectory = GetRandomTestDirectory 569 $result = Export-WinGetPackage -Id AppInstallerTest.TestMultipleInstallers -Locale 'zh-CN' -DownloadDirectory $testDirectory 570 571 $result | Should -Not -BeNullOrEmpty 572 $result.Id | Should -Be "AppInstallerTest.TestMultipleInstallers" 573 $result.Name | Should -Be "TestMultipleInstallers" 574 $result.Source | Should -Be "TestSource" 575 $result.Status | Should -Be 'Ok' 576 577 Test-Path -Path $testDirectory | Should -Be $true 578 (Get-ChildItem -Path $testDirectory -Force | Measure-Object).Count | Should -Be 2 579 } 580 581 It 'Download by InstallerType' { 582 $testDirectory = GetRandomTestDirectory 583 $result = Export-WinGetPackage -Id AppInstallerTest.TestMultipleInstallers -InstallerType 'msi' -DownloadDirectory $testDirectory 584 585 $result | Should -Not -BeNullOrEmpty 586 $result.Id | Should -Be "AppInstallerTest.TestMultipleInstallers" 587 $result.Name | Should -Be "TestMultipleInstallers" 588 $result.Source | Should -Be "TestSource" 589 $result.Status | Should -Be 'Ok' 590 591 Test-Path -Path $testDirectory | Should -Be $true 592 (Get-ChildItem -Path $testDirectory -Force | Measure-Object).Count | Should -Be 2 593 } 594 595 It 'Download by InstallerType that does not exist' { 596 $testDirectory = GetRandomTestDirectory 597 $result = Export-WinGetPackage -Id AppInstallerTest.TestExeInstaller -Version '1.0.0.0' -InstallerType 'zip' -DownloadDirectory $testDirectory 598 599 $result | Should -Not -BeNullOrEmpty 600 $result.Id | Should -Be "AppInstallerTest.TestExeInstaller" 601 $result.Name | Should -Be "TestExeInstaller" 602 $result.Source | Should -Be "TestSource" 603 $result.Status | Should -Be 'NoApplicableInstallers' 604 $result.ExtendedErrorCode | Should -Not -BeNullOrEmpty 605 Test-Path -Path $testDirectory | Should -Be $false 606 } 607 608 It 'Download with short Version' { 609 $testDirectory = GetRandomTestDirectory 610 $result = Export-WinGetPackage -Id AppInstallerTest.TestExeInstaller -Version '1' -DownloadDirectory $testDirectory 611 612 $result | Should -Not -BeNullOrEmpty 613 $result.Id | Should -Be "AppInstallerTest.TestExeInstaller" 614 $result.Name | Should -Be "TestExeInstaller" 615 $result.Source | Should -Be "TestSource" 616 $result.Status | Should -Be 'Ok' 617 618 # Download directory should be created and have exactly two files (installer and manifest file). 619 Test-Path -Path $testDirectory | Should -Be $true 620 (Get-ChildItem -Path $testDirectory -Force | Measure-Object).Count | Should -Be 2 621 } 622 623 AfterEach { 624 if (Test-Path $testDirectory) { 625 Remove-Item $testDirectory -Force -Recurse 626 } 627 } 628 } 629 630 Describe 'Get-WinGetUserSetting' { 631 632 It 'Get setting' { 633 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 634 SetWinGetSettingsHelper $ogSettings 635 636 $userSettings = Get-WinGetUserSetting 637 $userSettings | Should -Not -BeNullOrEmpty -ErrorAction Stop 638 $userSettings.Count | Should -Be 2 639 $userSettings.visual.progressBar | Should -Be 'rainbow' 640 $userSettings.experimentalFeatures.experimentalArg | Should -Be $false 641 $userSettings.experimentalFeatures.experimentalCmd | Should -Be $true 642 } 643 644 It 'Get settings. Bad json file' { 645 Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." 646 { Get-WinGetUserSetting } | Should -Throw 647 } 648 649 AfterAll { 650 RestoreWinGetSettings 651 } 652 } 653 654 Describe 'Test-WinGetUserSetting' { 655 656 It 'Bad json file' { 657 Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." 658 659 $inputSettings = @{ visual= @{ progressBar="retro"} } 660 Test-WinGetUserSetting -UserSettings $inputSettings | Should -Be $false 661 } 662 663 It 'Equal' { 664 $ogSettings = @{ visual= @{ progressBar="retro"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 665 SetWinGetSettingsHelper $ogSettings 666 667 Test-WinGetUserSetting -UserSettings $ogSettings | Should -Be $true 668 } 669 670 It 'Equal. Ignore schema' { 671 Set-Content -Path $settingsFilePath -Value '{ "$schema": "https://aka.ms/winget-settings.schema.json", "visual": { "progressBar": "retro" } }' 672 673 $inputSettings = @{ visual= @{ progressBar="retro"} } 674 Test-WinGetUserSetting -UserSettings $inputSettings | Should -Be $true 675 } 676 677 It 'Not Equal string' { 678 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 679 SetWinGetSettingsHelper $ogSettings 680 681 $inputSettings = @{ visual= @{ progressBar="retro"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 682 Test-WinGetUserSetting -UserSettings $inputSettings | Should -Be $false 683 } 684 685 It 'Not Equal bool' { 686 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$true}} 687 SetWinGetSettingsHelper $ogSettings 688 689 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 690 Test-WinGetUserSetting -UserSettings $inputSettings | Should -Be $false 691 } 692 693 It 'Not Equal. More settings' { 694 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true }} 695 SetWinGetSettingsHelper $ogSettings 696 697 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false }} 698 Test-WinGetUserSetting -UserSettings $inputSettings | Should -Be $false 699 } 700 701 It 'Not Equal. More settings input' { 702 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; }} 703 SetWinGetSettingsHelper $ogSettings 704 705 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 706 Test-WinGetUserSetting -UserSettings $inputSettings | Should -Be $false 707 } 708 709 It 'Equal IgnoreNotSet' { 710 $ogSettings = @{ visual= @{ progressBar="retro"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 711 SetWinGetSettingsHelper $ogSettings 712 713 Test-WinGetUserSetting -UserSettings $ogSettings -IgnoreNotSet | Should -Be $true 714 } 715 716 It 'Equal IgnoreNotSet. More settings' { 717 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true }} 718 SetWinGetSettingsHelper $ogSettings 719 720 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false }} 721 Test-WinGetUserSetting -UserSettings $inputSettings -IgnoreNotSet | Should -Be $true 722 } 723 724 It 'Not Equal IgnoreNotSet. More settings input' { 725 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; }} 726 SetWinGetSettingsHelper $ogSettings 727 728 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 729 Test-WinGetUserSetting -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false 730 } 731 732 It 'Not Equal bool IgnoreNotSet' { 733 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$true}} 734 SetWinGetSettingsHelper $ogSettings 735 736 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$false ; experimentalCmd=$true}} 737 Test-WinGetUserSetting -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false 738 } 739 740 It 'Not Equal array IgnoreNotSet' { 741 $ogSettings = @{ installBehavior= @{ preferences= @{ architectures = @("x86", "x64")} }} 742 SetWinGetSettingsHelper $ogSettings 743 744 $inputSettings = @{ installBehavior= @{ preferences= @{ architectures = @("x86", "arm64")} }} 745 Test-WinGetUserSetting -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false 746 } 747 748 It 'Not Equal wrong type IgnoreNotSet' { 749 $ogSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$true}} 750 SetWinGetSettingsHelper $ogSettings 751 752 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=4 ; experimentalCmd=$true}} 753 Test-WinGetUserSetting -UserSettings $inputSettings -IgnoreNotSet | Should -Be $false 754 } 755 756 AfterAll { 757 RestoreWinGetSettings 758 } 759 } 760 761 Describe 'Set-WinGetUserSetting' { 762 763 It 'Overwrites' { 764 $ogSettings = @{ source= @{ autoUpdateIntervalInMinutes=3}} 765 SetWinGetSettingsHelper $ogSettings 766 767 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$false}} 768 $result = Set-WinGetUserSetting -UserSettings $inputSettings 769 770 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 771 $result.'$schema' | Should -Not -BeNullOrEmpty 772 $result.visual | Should -Not -BeNullOrEmpty -ErrorAction Stop 773 $result.visual.progressBar | Should -Be "rainbow" 774 $result.experimentalFeatures | Should -Not -BeNullOrEmpty -ErrorAction Stop 775 $result.experimentalFeatures.experimentalArg | Should -Be $true 776 $result.experimentalFeatures.experimentalCmd | Should -Be $false 777 $result.source | Should -BeNullOrEmpty 778 } 779 780 It 'Merge' { 781 $ogSettings = @{ source= @{ autoUpdateIntervalInMinutes=3}} 782 SetWinGetSettingsHelper $ogSettings 783 784 $inputSettings = @{ visual= @{ progressBar="rainbow"} ; experimentalFeatures= @{experimentalArg=$true ; experimentalCmd=$false}} 785 $result = Set-WinGetUserSetting -UserSettings $inputSettings -Merge 786 787 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 788 $result.'$schema' | Should -Not -BeNullOrEmpty 789 $result.visual | Should -Not -BeNullOrEmpty -ErrorAction Stop 790 $result.visual.progressBar | Should -Be "rainbow" 791 $result.experimentalFeatures | Should -Not -BeNullOrEmpty -ErrorAction Stop 792 $result.experimentalFeatures.experimentalArg | Should -Be $true 793 $result.experimentalFeatures.experimentalCmd | Should -Be $false 794 $result.source | Should -Not -BeNullOrEmpty -ErrorAction Stop 795 $result.source.autoUpdateIntervalInMinutes | Should -Be 3 796 } 797 798 It 'Schema.' { 799 Set-Content -Path $settingsFilePath -Value '{ "$schema": "https://aka.ms/winget-settings.schema.json", "visual": { "progressBar": "retro" } }' 800 801 $inputSettings = @{ visual= @{ progressBar="retro"} } 802 $result = Set-WinGetUserSetting -UserSettings $inputSettings 803 804 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 805 $result.'$schema' | Should -Not -BeNullOrEmpty 806 $result.visual.progressBar | Should -Be "retro" 807 } 808 809 It 'Overwrites Bad json file' { 810 Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." 811 812 $inputSettings = @{ visual= @{ progressBar="retro"} } 813 $result = Set-WinGetUserSetting -UserSettings $inputSettings 814 815 $result | Should -Not -BeNullOrEmpty -ErrorAction Stop 816 $result.'$schema' | Should -Not -BeNullOrEmpty 817 $result.visual.progressBar | Should -Be "retro" 818 } 819 820 It 'Overwrites Bad json file' { 821 Set-Content -Path $settingsFilePath -Value "Hi, im not a json. Thank you, Test." 822 823 $inputSettings = @{ visual= @{ progressBar="retro"} } 824 { Set-WinGetUserSetting -UserSettings $inputSettings -Merge } | Should -Throw 825 } 826 827 AfterAll { 828 RestoreWinGetSettings 829 } 830 } 831 832 Describe 'Get|Enable|Disable-WinGetSetting' { 833 834 It 'Get-WinGetSetting' { 835 $settings = Get-WinGetSetting 836 $settings | Should -Not -BeNullOrEmpty -ErrorAction Stop 837 $settings.'$schema' | Should -Not -BeNullOrEmpty 838 $settings.adminSettings | Should -Not -BeNullOrEmpty 839 $settings.userSettingsFile | Should -Be $settingsFilePath 840 } 841 842 # This tests require admin 843 It 'Enable|Disable' { 844 $settings = Get-WinGetSetting 845 $settings | Should -Not -BeNullOrEmpty -ErrorAction Stop 846 $settings.adminSettings | Should -Not -BeNullOrEmpty 847 $settings.adminSettings.LocalManifestFiles | Should -Be $false 848 849 Enable-WinGetSetting -Name LocalManifestFiles 850 851 $afterEnable = Get-WinGetSetting 852 $afterEnable | Should -Not -BeNullOrEmpty -ErrorAction Stop 853 $afterEnable.adminSettings | Should -Not -BeNullOrEmpty 854 $afterEnable.adminSettings.LocalManifestFiles | Should -Be $true 855 856 Disable-WingetSetting -Name LocalManifestFiles 857 858 $afterDisable = Get-WinGetSetting 859 $afterDisable | Should -Not -BeNullOrEmpty -ErrorAction Stop 860 $afterDisable.adminSettings | Should -Not -BeNullOrEmpty 861 $afterDisable.adminSettings.LocalManifestFiles | Should -Be $false 862 } 863 } 864 865 Describe 'Test-GroupPolicies' { 866 BeforeAll { 867 CleanupGroupPolicies 868 CreatePolicyKeyIfNotExists 869 } 870 871 It "Disable WinGetPolicy and run Get-WinGetVersion" { 872 $policyKeyValueName = "EnableAppInstaller" 873 874 Set-ItemProperty -Path $wingetGroupPolicyRegistryRoot -Name $policyKeyValueName -Value 0 875 $registryKey = Get-ItemProperty -Path $wingetGroupPolicyRegistryRoot -Name $policyKeyValueName 876 $registryKey | Should -Not -BeNullOrEmpty 877 $registryKey.EnableAppInstaller | Should -Be 0 878 879 { Get-WinGetVersion } | Should -Throw "This operation is disabled by Group Policy : Enable Windows Package Manager" 880 881 CleanupGroupPolicies 882 } 883 884 It "Disable EnableWindowsPackageManagerCommandLineInterfaces Policy and run Get-WinGetVersion" { 885 $policyKeyValueName = "EnableWindowsPackageManagerCommandLineInterfaces" 886 887 Set-ItemProperty -Path $wingetGroupPolicyRegistryRoot -Name $policyKeyValueName -Value 0 888 $registryKey = Get-ItemProperty -Path $wingetGroupPolicyRegistryRoot -Name $policyKeyValueName 889 $registryKey | Should -Not -BeNullOrEmpty 890 $registryKey.EnableWindowsPackageManagerCommandLineInterfaces | Should -Be 0 891 892 { Get-WinGetVersion } | Should -Throw "This operation is disabled by Group Policy : Enable Windows Package Manager command line interfaces" 893 894 CleanupGroupPolicies 895 } 896 897 AfterAll { 898 CleanupGroupPolicies 899 CleanupGroupPolicyKeyIfExists 900 } 901 } 902 903 Describe 'WindowsPackageManagerServer' -Skip:($PSEdition -eq "Desktop") { 904 905 BeforeEach { 906 AddTestSource 907 WaitForWindowsPackageManagerServer $true 908 } 909 910 # When WindowsPackageManagerServer dies, we should not fail. 911 It 'Forced termination' { 912 $source = Get-WinGetSource -Name 'TestSource' 913 $source | Should -Not -BeNullOrEmpty 914 $source.Name | Should -Be 'TestSource' 915 916 $process = Get-Process -Name "WindowsPackageManagerServer" 917 $process | Should -Not -BeNullOrEmpty 918 919 # At least one is running. 920 $process | Where-Object { $_.HasExited -eq $false } | Should -Not -BeNullOrEmpty 921 922 WaitForWindowsPackageManagerServer $true 923 924 # From the ones we got, at least one exited 925 $process | Where-Object { $_.HasExited -eq $true } | Should -Not -BeNullOrEmpty 926 927 $source2 = Get-WinGetSource -Name 'TestSource' 928 $source2 | Should -Not -BeNullOrEmpty 929 $source2.Name | Should -Be 'TestSource' 930 931 $process2 = Get-Process -Name "WindowsPackageManagerServer" 932 $process2 | Should -Not -BeNullOrEmpty 933 $process2.Id | Should -Not -Be $process.Id 934 } 935 936 # The Microsoft.WinGet.Client has static proxy objects of WindowsPackageManagerServer 937 # This tests does all the Microsoft.WinGet.Client calls in a different pwsh instance. 938 It 'Graceful termination' { 939 $typeTable = [System.Management.Automation.Runspaces.TypeTable]::LoadDefaultTypeFiles() 940 $oopRunspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateOutOfProcessRunspace($typeTable) 941 $oopRunspace.Open() 942 $oopPwsh = [PowerShell]::Create() 943 $oopPwsh.Runspace = $oopRunspace 944 $oopPwshPid = $oopPwsh.AddScript("`$PID").Invoke() 945 $oopPwshProcess = Get-Process -Id $oopPwshPid 946 $oopPwshProcess.HasExited | Should -Be $false 947 948 $source = $oopPwsh.AddScript("Get-WinGetSource -Name TestSource").Invoke() 949 $source | Should -Not -BeNullOrEmpty 950 $source.Name | Should -Be 'TestSource' 951 952 $wingetProcess = Get-Process -Name "WindowsPackageManagerServer" 953 $wingetProcess | Should -Not -BeNullOrEmpty 954 955 # At least one is running. 956 $wingetProcess | Where-Object { $_.HasExited -eq $false } | Should -Not -BeNullOrEmpty 957 958 $oopRunspace.Close() 959 960 Start-Sleep -Seconds 30 961 $oopPwshProcess.HasExited | Should -Be $true 962 963 # From the ones we got, at least one exited 964 WaitForWindowsPackageManagerServer 965 $wingetProcess | Where-Object { $_.HasExited -eq $true } | Should -Not -BeNullOrEmpty 966 } 967 } 968 969 AfterAll { 970 RestoreWinGetSettings 971 RemoveTestSource 972 }