From 2cdd364f08db75705a7a592a1b6cc006fe2729d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Fri, 13 Jun 2014 22:49:16 +0200 Subject: [PATCH 01/15] tests: add environment variable handling facilities 1) Execute-WithEnvironmentBackup - to be able to freely manipulate the environment during tests. Exception-safe. 2) Add-EnvironmentVariable - set the variable at given scope, making sure to update it also at Process scope if necessary 3) Remove-EnvironmentVariable - remove from all scopes 4) Add-DirectoryToPath - add to path at given scope, making sure to update the path also at Process scope 5) Remove-DirectoryFromPath - remove it from path at all scopes 6) Assert-OnPath, Assert-NotOnPath - verify the directory is or is not present on path at given scope --- tests/_Common.ps1 | 2 + tests/_TestHelpers.ps1 | 160 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 tests/_TestHelpers.ps1 diff --git a/tests/_Common.ps1 b/tests/_Common.ps1 index 89f1170..e0e1a98 100644 --- a/tests/_Common.ps1 +++ b/tests/_Common.ps1 @@ -3,6 +3,8 @@ $src = Join-Path (Split-Path $here) 'src' $script = Join-Path $src 'chocolatey.ps1' $setup = Join-Path $here '_Setup.ps1' +. (Join-Path $here '_TestHelpers.ps1') + Get-Module ChocolateyInstaller -All | Remove-Module Get-Module chocolatey | Remove-Module Import-Module $script diff --git a/tests/_TestHelpers.ps1 b/tests/_TestHelpers.ps1 new file mode 100644 index 0000000..03366c2 --- /dev/null +++ b/tests/_TestHelpers.ps1 @@ -0,0 +1,160 @@ +function Backup-Environment() +{ + Write-Debug 'Backing up the environment' + $machineEnv = @{} + $key = Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' + $key.GetValueNames() | ForEach-Object { $machineEnv[$_] = $key.GetValue($_) } + + $userEnv = @{} + $key = Get-Item 'HKCU:\Environment' + $key.GetValueNames() | ForEach-Object { $userEnv[$_] = $key.GetValue($_) } + + $processEnv = @{} + Get-ChildItem Env:\ | ForEach-Object { $processEnv[$_.Key] = $_.Value } + + return New-Object PSCustomObject -Property @{ machine = $machineEnv; user = $userEnv; process = $processEnv } +} + +function Restore-Environment($state) +{ + Write-Debug 'Restoring the environment' + $state.machine.GetEnumerator() | ForEach-Object { + $current = [Environment]::GetEnvironmentVariable($_.Key, 'Machine') + if ($current -ne $_.Value) { + Write-Debug "Restoring value of environment variable $($_.Key) at Machine scope" + [Environment]::SetEnvironmentVariable($_.Key, $_.Value, 'Machine') + } + } + + $key = Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' + $key.GetValueNames() | Where-Object { -not $state.machine.ContainsKey($_) } | ForEach-Object { + Write-Debug "Deleting environment variable $_ at Machine scope" + [Environment]::SetEnvironmentVariable($_, $null, 'Machine') + } + + $state.user.GetEnumerator() | ForEach-Object { + $current = [Environment]::GetEnvironmentVariable($_.Key, 'User') + if ($current -ne $_.Value) { + Write-Debug "Restoring value of environment variable $($_.Key) at User scope" + [Environment]::SetEnvironmentVariable($_.Key, $_.Value, 'User') + } + } + + $key = Get-Item 'HKCU:\Environment' + $key.GetValueNames() | Where-Object { -not $state.user.ContainsKey($_) } | ForEach-Object { + Write-Debug "Deleting environment variable $_ at User scope" + [Environment]::SetEnvironmentVariable($_, $null, 'User') + } + + $state.process.GetEnumerator() | ForEach-Object { + $current = [Environment]::GetEnvironmentVariable($_.Key, 'Process') + if ($current -ne $_.Value) { + Write-Debug "Restoring value of environment variable $($_.Key) at Process scope" + [Environment]::SetEnvironmentVariable($_.Key, $_.Value, 'Process') + } + } + + Get-ChildItem Env:\ | Select-Object -ExpandProperty Name | Where-Object { -not $state.process.ContainsKey($_) } | ForEach-Object { + Write-Debug "Deleting environment variable $_ at Process scope" + [Environment]::SetEnvironmentVariable($_, $null, 'Process') + } +} + +function Execute-WithEnvironmentBackup($scriptBlock) +{ + $savedEnvironment = Backup-Environment + try + { + & $scriptBlock + } + finally + { + Restore-Environment $savedEnvironment + } +} + +function Add-EnvironmentVariable($name, $value, $targetScope) +{ + Write-Debug "Setting $name to $value at $targetScope scope" + [Environment]::SetEnvironmentVariable($name, $value, $targetScope) + if ($targetScope -eq 'Process') { + Write-Debug "Current $name value is '$value' (from Process scope)" + return + } + # find lowest scope with $name set and use that value as current + foreach ($currentScope in @('User', 'Machine')) { + $valueAtCurrentScope = [Environment]::GetEnvironmentVariable($name, $currentScope) + if ($valueAtCurrentScope -ne $null) { + Write-Debug "Current $name value is '$valueAtCurrentScope' (from $currentScope scope)" + [Environment]::SetEnvironmentVariable($name, $valueAtCurrentScope, 'Process') + break + } + } +} + +function Remove-EnvironmentVariable($name) +{ + Write-Debug "Ensuring environment variable $name is not set at any scope" + 'Machine','User','Process' | ForEach-Object { + if (-not ([String]::IsNullOrEmpty([Environment]::GetEnvironmentVariable($name, $_)))) { + Write-Debug "Deleting environment variable $name at $_ scope" + [Environment]::SetEnvironmentVariable($name, $null, $_) + } + } +} + +function Add-DirectoryToPath($directory, $scope) +{ + $curPath = [Environment]::GetEnvironmentVariable('PATH', $scope) + $newPath = ($curPath -split ';' | Where-Object { $_.TrimEnd('\') -ne $directory.TrimEnd('\') }) -join ';' + if ($newPath -ne $curPath) { + Write-Debug "Directory $directory is already on PATH at $scope scope" + } else { + Write-Debug "Adding directory $directory to PATH at $scope scope" + if ([String]::IsNullOrEmpty($newPath)) { + [Environment]::SetEnvironmentVariable('PATH', $directory, $scope) + } else { + [Environment]::SetEnvironmentVariable('PATH', "$($newPath.TrimEnd(';'));$directory", $scope) + } + } + if ($scope -ne 'Process') { + $curPath = [Environment]::GetEnvironmentVariable('PATH', 'Process') + $newPath = ($curPath -split ';' | Where-Object { $_.TrimEnd('\') -ne $directory.TrimEnd('\') }) -join ';' + if ($newPath -eq $curPath) { + Write-Debug "Adding directory $directory to PATH at Process scope" + if ([String]::IsNullOrEmpty($newPath)) { + [Environment]::SetEnvironmentVariable('PATH', $directory, 'Process') + } else { + [Environment]::SetEnvironmentVariable('PATH', "$($newPath.TrimEnd(';'));$directory", 'Process') + } + } + } +} + +function Remove-DirectoryFromPath($directory) +{ + Write-Debug "Ensuring directory $directory is not on PATH at any scope" + 'Machine','User','Process' | ForEach-Object { + $scope = $_ + $curPath = [Environment]::GetEnvironmentVariable('PATH', $scope) + $newPath = ($curPath -split ';' | Where-Object { $_.TrimEnd('\') -ne $directory.TrimEnd('\') }) -join ';' + if ($newPath -ne $curPath) { + Write-Debug "Removing directory $directory from PATH at $scope scope" + [Environment]::SetEnvironmentVariable('PATH', $newPath, $scope) + } + } +} + +function Assert-OnPath($directory, $pathScope) +{ + $path = [Environment]::GetEnvironmentVariable('PATH', $pathScope) + $dirInPath = [Environment]::GetEnvironmentVariable('PATH', $pathScope) -split ';' | Where-Object { $_ -eq $directory } + "$dirInPath" | Should not BeNullOrEmpty +} + +function Assert-NotOnPath($directory, $pathScope) +{ + $path = [Environment]::GetEnvironmentVariable('PATH', $pathScope) + $dirInPath = [Environment]::GetEnvironmentVariable('PATH', $pathScope) -split ';' | Where-Object { $_ -eq $directory } + "$dirInPath" | Should BeNullOrEmpty +} From 78ffeb3aee15d0a78a690a3d7cbfc8a1c2a9f99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Tue, 27 May 2014 03:10:51 +0200 Subject: [PATCH 02/15] add tests for Chocolatey setup (Initialize-Chocolatey) Note: the tests currently assume the test suite is run with administrative rights (i.e. elevated) with UAC enabled. Unfortunately, it is not possible to test the most common scenario, i.e. first installation on a clean machine with no existing environment variables or arguments to the installer, without making specific assumptions about the test machine. (If the tests did that, the primary Chocolatey installation on the developer machine could get overwritten.) The default installation tests will thus only be performed if no existing Chocolatey installation is detected in the default install location. --- tests/unit/Initialize-Chocolatey.Tests.ps1 | 388 +++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 tests/unit/Initialize-Chocolatey.Tests.ps1 diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 new file mode 100644 index 0000000..6f02b89 --- /dev/null +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -0,0 +1,388 @@ +$here = Split-Path -Parent $MyInvocation.MyCommand.Definition +$base = Split-Path -Parent (Split-Path -Parent $here) +. (Join-Path (Split-Path -Parent $here) '_TestHelpers.ps1') + +function Add-ChocolateyInstall($path, $targetScope) +{ + Add-EnvironmentVariable 'ChocolateyInstall' $path $targetScope +} + +function Setup-ChocolateyInstall($path, $targetScope) +{ + Remove-EnvironmentVariable 'ChocolateyInstall' + if ($path -ne $null) { + Add-ChocolateyInstall $path $targetScope + } +} + +function Verify-ExpectedContentInstalled($installDir) +{ + It "should create installation directory" { + $installDir | Should Exist + } + + It "should create expected subdirectories" { + "$installDir\bin" | Should Exist + "$installDir\chocolateyInstall" | Should Exist + "$installDir\lib" | Should Exist + } + + It "should copy files to expected locations" { + "$installDir\bin\choco.exe" | Should Exist + "$installDir\chocolateyInstall\chocolatey.ps1" | Should Exist + "$installDir\chocolateyInstall\helpers\functions\Install-ChocolateyPackage.ps1" | Should Exist + } +} + +function Assert-ChocolateyInstallIs($value, $scope) +{ + "$([Environment]::GetEnvironmentVariable('ChocolateyInstall', $scope))" | Should Be $value +} + +function Assert-ChocolateyInstallIsNull($scope) +{ + "$([Environment]::GetEnvironmentVariable('ChocolateyInstall', $scope))" | Should BeNullOrEmpty +} + +function Setup-ChocolateyInstallationPackage +{ + Setup -Dir 'chocotmp' + Setup -Dir 'chocotmp\chocolateyInstall' + $script:tmpDir = 'TestDrive:\chocotmp' + + Get-ChildItem "$base\nuget\tools" | Copy-Item -Destination $script:tmpDir -Recurse -Force + Get-ChildItem "$base\src" | Copy-Item -Destination "$script:tmpDir\chocolateyInstall" -Recurse -Force + + $script:installDir = Join-Path (Resolve-Path 'TestDrive:\').ProviderPath chocoinstall + + Get-Module chocolateysetup | Remove-Module + Import-Module "$tmpDir\chocolateysetup.psm1" +} + +Describe "Initialize-Chocolatey" { + # note: the specs below are correct when installing with administrative permissions with UAC enabled + # the test suite is always run elevated, so no easy way to test limited user install for now + + Context "When installing with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $null + + Initialize-Chocolatey -chocolateyPath $installDir + + Verify-ExpectedContentInstalled $installDir + + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey -chocolateyPath $installDir + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' + + # Is this really desired behavior - giving precedence to environment over explicit argument? + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at Machine scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Machine' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at Process scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Machine' + Add-ChocolateyInstall $installDir 'User' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' + Add-ChocolateyInstall $installDir 'User' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' + Add-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } + } + } + + Context "When installing with `$Env:ChocolateyInstall set at User scope and different at Process scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'User' + Add-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing with bin directory not on PATH" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should add bin to PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should add bin to PATH at User scope" { + Assert-OnPath $binDir 'User' + } + + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } + } + } + + Context "When installing with bin directory on PATH at Machine scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + Add-DirectoryToPath "$installDir\bin" 'Machine' + + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' + } + + It "should retain bin on PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' + } + } + } + + Context "When installing with bin directory on PATH at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + Add-DirectoryToPath "$installDir\bin" 'User' + + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should retain bin on PATH at User scope" { + Assert-OnPath $binDir 'User' + } + + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } + } + } +} From 0ecec9c50afe1bfe35128f2eafa51cfc9eed22e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Thu, 12 Jun 2014 00:34:23 +0200 Subject: [PATCH 03/15] setup tests: conditionally test default installation Default installation (no arguments or preexisting environment variables) can be tested only when the test machine does not already have Chocolatey installed in the default location (otherwise it would get overwritten). To enable these tests, make sure your Chocolatey is installed in a custom location. --- tests/unit/Initialize-Chocolatey.Tests.ps1 | 52 ++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index 6f02b89..a4bbeab 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -59,10 +59,62 @@ function Setup-ChocolateyInstallationPackage Import-Module "$tmpDir\chocolateysetup.psm1" } +function Get-DefaultChocolateyInstallDir +{ + $programData = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData) + $chocolateyPath = Join-Path $programData chocolatey + return $chocolateyPath +} + +function Execute-ChocolateyInstallationInDefaultDir($scriptBlock) +{ + $defaultDir = Get-DefaultChocolateyInstallDir + if (Test-Path $defaultDir) { + Write-Warning "Skipping default installation test because the default installation directory already exists ($defaultDir)" + return + } + $script:installDir = $defaultDir + try + { + & $scriptBlock + } + finally + { + Write-Debug "Removing default installation directory if exists ($defaultDir)" + Get-Item $defaultDir | Remove-Item -Recurse -Force + } +} + Describe "Initialize-Chocolatey" { # note: the specs below are correct when installing with administrative permissions with UAC enabled # the test suite is always run elevated, so no easy way to test limited user install for now + Context "When installing with `$Env:ChocolateyInstall not set and no arguments" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $null + + Execute-ChocolateyInstallationInDefaultDir { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + } + Context "When installing with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { Setup-ChocolateyInstallationPackage From dfb4372e0c6ff246d99434b81352c269cb468b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Fri, 6 Jun 2014 01:09:11 +0200 Subject: [PATCH 04/15] setup tests: mock UAC status This allows testing setup behavior both with UAC enabled and disabled. The "mocking" mechanism actually changes the UAC registry setting, which is read by UAC checking code in Chocolatey. Since the change requires OS restart to take effect, it is indeed a mockup. However, the test suite should not be interrupted, so that the setting is changed back to the original value. No effort has been made to support running the tests on XP. A modern OS is assumed. --- tests/unit/Initialize-Chocolatey.Tests.ps1 | 749 +++++++++++++++++---- 1 file changed, 605 insertions(+), 144 deletions(-) diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index a4bbeab..0edec32 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -2,6 +2,62 @@ $here = Split-Path -Parent $MyInvocation.MyCommand.Definition $base = Split-Path -Parent (Split-Path -Parent $here) . (Join-Path (Split-Path -Parent $here) '_TestHelpers.ps1') +function Execute-WithMockingUAC([string]$status, $scriptBlock) +{ + switch ($status) { + 'Enabled' { $enabled = $true } + 'Disabled' { $enabled = $false } + default { throw "Invalid `$status value: $status" } + } + $uacRegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" + if (-not (Test-Path $uacRegPath)) { + if ($enabled) { + Write-Warning "UAC mock: registry path $uacRegPath does not exist. This means that tests mocking UAC enabled would not be conclusive, so this test is skipped." + } else { + Write-Verbose "UAC mock: registry path $uacRegPath does not exist, assuming UAC is not present." + & $scriptBlock + } + return + } + $uacRegValue = "EnableLUA" + try + { + $vals = Get-ItemProperty -Path $uacRegPath + $savedValue = $vals.EnableLUA + } + catch + { + $savedValue = $null + } + if ($enabled) { + $mockedValue = 1 + } else { + $mockedValue = 0 + } + if ($savedValue -ne $mockedValue) { + Write-Verbose "UAC mock: setting $uacRegValue value to $mockedValue" + Set-ItemProperty -Path $uacRegPath -Name $uacRegValue -Value $mockedValue -Type DWord + } else { + Write-Verbose "UAC mock: $uacRegValue is already $mockedValue" + } + try + { + & $scriptBlock + } + finally + { + if ($savedValue -ne $mockedValue) { + if ($savedValue -eq $null) { + Write-Verbose "UAC mock: clearing $uacRegValue because it did not exist previously" + Clear-ItemProperty -Path $uacRegPath -Name $uacRegValue + } else { + Write-Verbose "UAC mock: restoring previous $uacRegValue value $savedValue" + Set-ItemProperty -Path $uacRegPath -Name $uacRegValue -Value $savedValue -Type DWord + } + } + } +} + function Add-ChocolateyInstall($path, $targetScope) { Add-EnvironmentVariable 'ChocolateyInstall' $path $targetScope @@ -86,17 +142,45 @@ function Execute-ChocolateyInstallationInDefaultDir($scriptBlock) } Describe "Initialize-Chocolatey" { - # note: the specs below are correct when installing with administrative permissions with UAC enabled + # note: the specs below are correct when installing with administrative permissions # the test suite is always run elevated, so no easy way to test limited user install for now - Context "When installing with `$Env:ChocolateyInstall not set and no arguments" { + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall not set and no arguments" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $null Execute-ChocolateyInstallationInDefaultDir { - Initialize-Chocolatey + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } + } + } + } + } + + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $null + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey -chocolateyPath $installDir Verify-ExpectedContentInstalled $installDir @@ -104,289 +188,662 @@ Describe "Initialize-Chocolatey" { Assert-ChocolateyInstallIs $installDir 'Process' } - It "should create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' } } } } - Context "When installing with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $null + Setup-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey -chocolateyPath $installDir + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey -chocolateyPath $installDir - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should create ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey -chocolateyPath $installDir + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' + + # Is this really desired behavior - giving precedence to environment over explicit argument? + Verify-ExpectedContentInstalled $installDir - Verify-ExpectedContentInstalled $installDir + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } + } + } - # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment - It "should create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Machine' + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } + } + } + + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Process scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir - # Is this really desired behavior - giving precedence to environment over explicit argument? - Verify-ExpectedContentInstalled $installDir + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } + } + } + + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Machine' + Add-ChocolateyInstall $installDir 'User' + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } + } + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' + Add-ChocolateyInstall $installDir 'User' + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at Machine scope" { + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'Machine' + Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' + Add-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } } + } + } + + Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at User scope and different at Process scope" { + Setup-ChocolateyInstallationPackage - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'User' + Add-ChocolateyInstall $installDir 'Process' + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + } + + Context "When installing as admin, without UAC, with bin directory not on PATH" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should add bin to PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' + } + + It "should add bin to PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' + } } + } + } + + Context "When installing as admin, without UAC, with bin directory on PATH at Machine scope" { + Setup-ChocolateyInstallationPackage - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + Add-DirectoryToPath "$installDir\bin" 'Machine' + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' + } + + It "should retain bin on PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at User scope" { + Context "When installing as admin, without UAC, with bin directory on PATH at User scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + Add-DirectoryToPath "$installDir\bin" 'User' + + Execute-WithMockingUAC Disabled { + Initialize-Chocolatey + + $binDir = "$installDir\bin" - Initialize-Chocolatey + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } - Verify-ExpectedContentInstalled $installDir + It "should retain bin on PATH at User scope" { + Assert-OnPath $binDir 'User' + } - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } } + } + } + + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall not set and no arguments" { + Setup-ChocolateyInstallationPackage - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $null + + Execute-ChocolateyInstallationInDefaultDir { + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } } + } + } + + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $null + + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey -chocolateyPath $installDir + + Verify-ExpectedContentInstalled $installDir + + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at Process scope" { + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey -chocolateyPath $installDir - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } + } + } + + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + # Is this really desired behavior - giving precedence to environment over explicit argument? + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Machine' - Add-ChocolateyInstall $installDir 'User' - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } + } + } + } + + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' - Verify-ExpectedContentInstalled $installDir + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } + } + } + + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Process scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } + } + } + + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { + Setup-ChocolateyInstallationPackage + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Machine' + Add-ChocolateyInstall $installDir 'User' + + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'User' - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } } } } - Context "When installing with `$Env:ChocolateyInstall set at User scope and different at Process scope" { + Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at User scope and different at Process scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall 'X:\nonexistent' 'User' Add-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' - } + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } } - Context "When installing with bin directory not on PATH" { + Context "When installing as admin, with UAC, with bin directory not on PATH" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey - $binDir = "$installDir\bin" + $binDir = "$installDir\bin" - It "should add bin to PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } + It "should add bin to PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } - It "should add bin to PATH at User scope" { - Assert-OnPath $binDir 'User' - } + It "should add bin to PATH at User scope" { + Assert-OnPath $binDir 'User' + } - It "should not add bin to PATH at Machine scope" { - Assert-NotOnPath $binDir 'Machine' + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } } } } - Context "When installing with bin directory on PATH at Machine scope" { + Context "When installing as admin, with UAC, with bin directory on PATH at Machine scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { @@ -394,25 +851,27 @@ Describe "Initialize-Chocolatey" { Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'Machine' - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey - $binDir = "$installDir\bin" + $binDir = "$installDir\bin" - It "should retain bin on PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } - It "should not add bin to PATH at User scope" { - Assert-NotOnPath $binDir 'User' - } + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' + } - It "should retain bin on PATH at Machine scope" { - Assert-OnPath $binDir 'Machine' + It "should retain bin on PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' + } } } } - Context "When installing with bin directory on PATH at User scope" { + Context "When installing as admin, with UAC, with bin directory on PATH at User scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { @@ -420,20 +879,22 @@ Describe "Initialize-Chocolatey" { Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'User' - Initialize-Chocolatey + Execute-WithMockingUAC Enabled { + Initialize-Chocolatey - $binDir = "$installDir\bin" + $binDir = "$installDir\bin" - It "should retain bin on PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } - It "should retain bin on PATH at User scope" { - Assert-OnPath $binDir 'User' - } + It "should retain bin on PATH at User scope" { + Assert-OnPath $binDir 'User' + } - It "should not add bin to PATH at Machine scope" { - Assert-NotOnPath $binDir 'Machine' + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } } } } From 5698b2f25507fdcee40d23aa786e2194075fc6f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Tue, 3 Jun 2014 23:21:35 +0200 Subject: [PATCH 05/15] add Test-AdminRights helper This helper tests whether the current user identity is a member of the Administrators group, i.e. if the current process has administrator rights. On systems with UAC enabled, this helper returns true only if the current process is running elevated (so it actually has admin rights). All existing admin checks in Chocolatey code are refactored to take advantage of this helper. --- nuget/tools/chocolateysetup.psm1 | 6 ++--- src/helpers/chocolateyInstaller.psm1 | 1 + .../Install-ChocolateyEnvironmentVariable.ps1 | 3 +-- .../functions/Install-ChocolateyPath.ps1 | 3 +-- src/helpers/functions/Test-AdminRights.ps1 | 23 +++++++++++++++++++ 5 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 src/helpers/functions/Test-AdminRights.ps1 diff --git a/nuget/tools/chocolateysetup.psm1 b/nuget/tools/chocolateysetup.psm1 index 28b176c..1bb30e8 100644 --- a/nuget/tools/chocolateysetup.psm1 +++ b/nuget/tools/chocolateysetup.psm1 @@ -89,9 +89,8 @@ param( [string]$folder ) $environmentTarget = [System.EnvironmentVariableTarget]::User - $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) $UACEnabled = Get-UACEnabled - if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -and !$UACEnabled) { + if ((Test-AdminRights) -and !$UACEnabled) { Write-Debug "Administrator installing with UAC disabled so using Machine environment variable target instead of User." $environmentTarget = [System.EnvironmentVariableTarget]::Machine } @@ -156,9 +155,8 @@ param( ) $environmentTarget = [System.EnvironmentVariableTarget]::User - $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) $UACEnabled = Get-UACEnabled - if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -and !$UACEnabled) { + if ((Test-AdminRights) -and !$UACEnabled) { Write-Debug "Administrator installing with UAC disabled so using Machine environment variable target instead of User." $environmentTarget = [System.EnvironmentVariableTarget]::Machine } diff --git a/src/helpers/chocolateyInstaller.psm1 b/src/helpers/chocolateyInstaller.psm1 index 3c34952..186e3ea 100644 --- a/src/helpers/chocolateyInstaller.psm1 +++ b/src/helpers/chocolateyInstaller.psm1 @@ -31,5 +31,6 @@ Export-ModuleMember -Function ` Write-ChocolateyFailure,` Write-Host,`Write-Debug,`Write-Error,` Start-ChocolateyProcessAsAdmin,` + Test-AdminRights,` Uninstall-ChocolateyPackage,` Update-SessionEnvironment diff --git a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 index 3ea5eb5..aa9db4d 100644 --- a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 +++ b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 @@ -41,9 +41,8 @@ param( Write-Debug "Running 'Install-ChocolateyEnvironmentVariable' with variableName:`'$variableName`' and variableValue:`'$variableValue`'"; if ($variableType -eq [System.EnvironmentVariableTarget]::Machine) { - $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) $UACEnabled = Get-UACEnabled - if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -and !$UACEnabled) { + if ((Test-AdminRights) -and !$UACEnabled) { [Environment]::SetEnvironmentVariable($variableName, $variableValue, $variableType) } else { $psArgs = "[Environment]::SetEnvironmentVariable(`'$variableName`',`'$variableValue`', `'$variableType`')" diff --git a/src/helpers/functions/Install-ChocolateyPath.ps1 b/src/helpers/functions/Install-ChocolateyPath.ps1 index 1bdba26..b49c4b4 100644 --- a/src/helpers/functions/Install-ChocolateyPath.ps1 +++ b/src/helpers/functions/Install-ChocolateyPath.ps1 @@ -22,9 +22,8 @@ param( $actualPath = $actualPath + $pathToInstall if ($pathType -eq [System.EnvironmentVariableTarget]::Machine) { - $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) $UACEnabled = Get-UACEnabled - if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -and !$UACEnabled) { + if ((Test-AdminRights) -and !$UACEnabled) { [Environment]::SetEnvironmentVariable('Path', $actualPath, $pathType) } else { $psArgs = "[Environment]::SetEnvironmentVariable('Path',`'$actualPath`', `'$pathType`')" diff --git a/src/helpers/functions/Test-AdminRights.ps1 b/src/helpers/functions/Test-AdminRights.ps1 new file mode 100644 index 0000000..1614751 --- /dev/null +++ b/src/helpers/functions/Test-AdminRights.ps1 @@ -0,0 +1,23 @@ +function Test-AdminRights { +<# +.SYNOPSIS +Tests whether the current process is running with administrative rights. + +.DESCRIPTION +This function checks whether the current process has administrative rights +by checking if the current user identity is a member of the Administrators group. +It returns $true if the current process is running with administrative rights, +$false otherwise. + +On Windows Vista and later, with UAC enabled, the returned value represents the +actual rights available to the process, i.e. if it returns $true, the process is +running elevated. + +.OUTPUTS +System.Boolean + +#> + + $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) + return $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} From 5785f3f82fa112b6fce2cb4edcd0fc07eddf1e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Wed, 11 Jun 2014 23:06:18 +0200 Subject: [PATCH 06/15] Test-AdminRights: request WindowsIdentity with minimal access necessary To check group membership, only TOKEN_QUERY is needed ([1]). The token, however, needs to be an impersonation token, so in certain circumstances TOKEN_DUPLICATE is also needed ([2]). Requesting the WindowsIdentity with minimum access level is slightly better from a security standpoint. [1] CheckTokenMembership: http://msdn.microsoft.com/en-us/library/windows/desktop/aa376389.aspx [2] WindowsPrincipal source, bool IsInRole (SecurityIdentifier sid): http://referencesource.microsoft.com/#mscorlib/system/security/principal/windowsprincipal.cs --- src/helpers/functions/Test-AdminRights.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/functions/Test-AdminRights.ps1 b/src/helpers/functions/Test-AdminRights.ps1 index 1614751..f5259ae 100644 --- a/src/helpers/functions/Test-AdminRights.ps1 +++ b/src/helpers/functions/Test-AdminRights.ps1 @@ -18,6 +18,6 @@ System.Boolean #> - $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) + $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent([Security.Principal.TokenAccessLevels]'Query,Duplicate')) return $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } From 42fcbbdd5f17c84373ed3d0d480e757bad42f39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Tue, 3 Jun 2014 23:56:06 +0200 Subject: [PATCH 07/15] enable mocking Test-AdminRights for setup tests As Chocolatey setup code explicitly imports the helpers module, Pester mocking mechanisms do not work (the mocks are overridden when the helpers are imported again). Mocking the admin rights check in setup tests is critical to making it possible to test Chocolatey setup at various user right levels. For setup tests, substitute Test-AdminRights implementation in the installation package with a stub returning a canned answer. This slightly reduces the accuracy of setup tests, as not 100% of production code is tested, but keeping production code pure is more important. As an added benefit, this is the first step in enabling the tests to be run as a standard user. --- src/helpers/functions/Test-AdminRights.ps1 | 4 +++- tests/unit/Initialize-Chocolatey.Tests.ps1 | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/helpers/functions/Test-AdminRights.ps1 b/src/helpers/functions/Test-AdminRights.ps1 index f5259ae..a90b97f 100644 --- a/src/helpers/functions/Test-AdminRights.ps1 +++ b/src/helpers/functions/Test-AdminRights.ps1 @@ -19,5 +19,7 @@ System.Boolean #> $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent([Security.Principal.TokenAccessLevels]'Query,Duplicate')) - return $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + $isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + Write-Debug "Test-AdminRights: returning $isAdmin" + return $isAdmin } diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index 0edec32..1f75bd8 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -1,6 +1,7 @@ $here = Split-Path -Parent $MyInvocation.MyCommand.Definition -$base = Split-Path -Parent (Split-Path -Parent $here) -. (Join-Path (Split-Path -Parent $here) '_TestHelpers.ps1') +$testsDir = Split-Path -Parent $here +$baseDir = Split-Path -Parent $testsDir +. (Join-Path $testsDir '_TestHelpers.ps1') function Execute-WithMockingUAC([string]$status, $scriptBlock) { @@ -100,14 +101,20 @@ function Assert-ChocolateyInstallIsNull($scope) "$([Environment]::GetEnvironmentVariable('ChocolateyInstall', $scope))" | Should BeNullOrEmpty } -function Setup-ChocolateyInstallationPackage +function Setup-ChocolateyInstallationPackage([switch] $SimulateStandardUser) { Setup -Dir 'chocotmp' Setup -Dir 'chocotmp\chocolateyInstall' $script:tmpDir = 'TestDrive:\chocotmp' - Get-ChildItem "$base\nuget\tools" | Copy-Item -Destination $script:tmpDir -Recurse -Force - Get-ChildItem "$base\src" | Copy-Item -Destination "$script:tmpDir\chocolateyInstall" -Recurse -Force + Get-ChildItem "$baseDir\nuget\tools" | Copy-Item -Destination $script:tmpDir -Recurse -Force + Get-ChildItem "$baseDir\src" | Copy-Item -Destination "$script:tmpDir\chocolateyInstall" -Recurse -Force + + if ($SimulateStandardUser) { + 'function Test-AdminRights() { return $false }' | Set-Content (Join-Path $script:tmpDir chocolateyInstall\helpers\functions\Test-AdminRights.ps1) + } else { + 'function Test-AdminRights() { return $true }' | Set-Content (Join-Path $script:tmpDir chocolateyInstall\helpers\functions\Test-AdminRights.ps1) + } $script:installDir = Join-Path (Resolve-Path 'TestDrive:\').ProviderPath chocoinstall @@ -142,8 +149,7 @@ function Execute-ChocolateyInstallationInDefaultDir($scriptBlock) } Describe "Initialize-Chocolatey" { - # note: the specs below are correct when installing with administrative permissions - # the test suite is always run elevated, so no easy way to test limited user install for now + # note: the correctness of the specs below is dependent upon all code using Test-AdminRights Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall not set and no arguments" { Setup-ChocolateyInstallationPackage From fd27621d0c2b23d7e0ce47567b1fbd25c4ec9dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Wed, 4 Jun 2014 00:13:10 +0200 Subject: [PATCH 08/15] setup tests: add simulated standard user scenarios With the facility of mocking admin rights tests in place, it is now possible to test setup behavior for limited users (and un-elevated admins). --- tests/unit/Initialize-Chocolatey.Tests.ps1 | 349 +++++++++++++++++++++ 1 file changed, 349 insertions(+) diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index 1f75bd8..f6e110b 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -904,4 +904,353 @@ Describe "Initialize-Chocolatey" { } } } + + Context "When installing as simulated standard user, with `$Env:ChocolateyInstall not set and no arguments" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $null + + Execute-ChocolateyInstallationInDefaultDir { + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + } + + Context "When installing as simulated standard user, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $null + + Initialize-Chocolatey -chocolateyPath $installDir + + Verify-ExpectedContentInstalled $installDir + + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing as simulated standard user, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey -chocolateyPath $installDir + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment + It "should create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing as simulated standard user, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' + + # Is this really desired behavior - giving precedence to environment over explicit argument? + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Machine' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } + } + } + + Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at User scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Process scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'Machine' + Add-ChocolateyInstall $installDir 'User' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } + } + } + + Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' + Add-ChocolateyInstall $installDir 'User' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } + } + } + + Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' + Add-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } + + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } + } + } + + Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at User scope and different at Process scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall 'X:\nonexistent' 'User' + Add-ChocolateyInstall $installDir 'Process' + + Initialize-Chocolatey + + Verify-ExpectedContentInstalled $installDir + + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } + + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' + } + + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } + } + } + + Context "When installing as simulated standard user with bin directory not on PATH" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should add bin to PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should add bin to PATH at User scope" { + Assert-OnPath $binDir 'User' + } + + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } + } + } + + Context "When installing as simulated standard user with bin directory on PATH at Machine scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + Add-DirectoryToPath "$installDir\bin" 'Machine' + + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' + } + + It "should retain bin on PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' + } + } + } + + Context "When installing as simulated standard user with bin directory on PATH at User scope" { + Setup-ChocolateyInstallationPackage -SimulateStandardUser + + Execute-WithEnvironmentBackup { + Setup-ChocolateyInstall $installDir 'User' + Remove-DirectoryFromPath "$installDir\bin" + Add-DirectoryToPath "$installDir\bin" 'User' + + Initialize-Chocolatey + + $binDir = "$installDir\bin" + + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } + + It "should retain bin on PATH at User scope" { + Assert-OnPath $binDir 'User' + } + + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } + } + } } From daae22dcf1b408494bc5d6cb83bb19bb2f045c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Thu, 29 May 2014 02:29:33 +0200 Subject: [PATCH 09/15] setup tests: with admin rights, variables should be set at Machine level regardless of UAC Provided the process is running elevated (i.e. with admin rights), Chocolatey should always be set up at machine (all users) level. There is no need to punish security-conscious users who run their systems with UAC enabled. --- tests/unit/Initialize-Chocolatey.Tests.ps1 | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index f6e110b..1b9f81c 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -544,12 +544,12 @@ Describe "Initialize-Chocolatey" { Assert-ChocolateyInstallIs $installDir 'Process' } - It "should create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' } } } @@ -571,12 +571,12 @@ Describe "Initialize-Chocolatey" { Assert-ChocolateyInstallIs $installDir 'Process' } - It "should create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' + It "should not ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' } } } @@ -597,13 +597,13 @@ Describe "Initialize-Chocolatey" { Assert-ChocolateyInstallIs $installDir 'Process' } - # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment - It "should create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' + # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' } } } @@ -838,12 +838,12 @@ Describe "Initialize-Chocolatey" { Assert-OnPath $binDir 'Process' } - It "should add bin to PATH at User scope" { - Assert-OnPath $binDir 'User' + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' } - It "should not add bin to PATH at Machine scope" { - Assert-NotOnPath $binDir 'Machine' + It "should add bin to PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' } } } From 466633c2490556752df1068d88b7ff8b89ea7c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Tue, 27 May 2014 03:12:56 +0200 Subject: [PATCH 10/15] when running with administrative rights, set environment variables at Machine scope The CurrentPrincipal::IsInRole(Administrators) check is sufficient to ascertain administrative rights, whether UAC is enabled or not. In particular, if UAC is enabled, this check will only return true if running elevated. This change enables per-machine installation on systems with UAC enabled (only if the user installs/invokes Chocolatey from an elevated shell, so UAC prompt is not triggered), while not disrupting the behavior for standard users. --- nuget/tools/chocolateysetup.psm1 | 10 ++++------ .../Install-ChocolateyEnvironmentVariable.ps1 | 3 +-- src/helpers/functions/Install-ChocolateyPath.ps1 | 3 +-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/nuget/tools/chocolateysetup.psm1 b/nuget/tools/chocolateysetup.psm1 index 1bb30e8..52503b5 100644 --- a/nuget/tools/chocolateysetup.psm1 +++ b/nuget/tools/chocolateysetup.psm1 @@ -89,9 +89,8 @@ param( [string]$folder ) $environmentTarget = [System.EnvironmentVariableTarget]::User - $UACEnabled = Get-UACEnabled - if ((Test-AdminRights) -and !$UACEnabled) { - Write-Debug "Administrator installing with UAC disabled so using Machine environment variable target instead of User." + if (Test-AdminRights) { + Write-Debug "Administrator installing so using Machine environment variable target instead of User." $environmentTarget = [System.EnvironmentVariableTarget]::Machine } Write-Host "Creating $chocInstallVariableName as an Environment variable (targeting `'$environmentTarget`') and setting it to `'$folder`'" @@ -155,9 +154,8 @@ param( ) $environmentTarget = [System.EnvironmentVariableTarget]::User - $UACEnabled = Get-UACEnabled - if ((Test-AdminRights) -and !$UACEnabled) { - Write-Debug "Administrator installing with UAC disabled so using Machine environment variable target instead of User." + if (Test-AdminRights) { + Write-Debug "Administrator installing so using Machine environment variable target instead of User." $environmentTarget = [System.EnvironmentVariableTarget]::Machine } diff --git a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 index aa9db4d..616c138 100644 --- a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 +++ b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 @@ -41,8 +41,7 @@ param( Write-Debug "Running 'Install-ChocolateyEnvironmentVariable' with variableName:`'$variableName`' and variableValue:`'$variableValue`'"; if ($variableType -eq [System.EnvironmentVariableTarget]::Machine) { - $UACEnabled = Get-UACEnabled - if ((Test-AdminRights) -and !$UACEnabled) { + if (Test-AdminRights) { [Environment]::SetEnvironmentVariable($variableName, $variableValue, $variableType) } else { $psArgs = "[Environment]::SetEnvironmentVariable(`'$variableName`',`'$variableValue`', `'$variableType`')" diff --git a/src/helpers/functions/Install-ChocolateyPath.ps1 b/src/helpers/functions/Install-ChocolateyPath.ps1 index b49c4b4..d2b3bd4 100644 --- a/src/helpers/functions/Install-ChocolateyPath.ps1 +++ b/src/helpers/functions/Install-ChocolateyPath.ps1 @@ -22,8 +22,7 @@ param( $actualPath = $actualPath + $pathToInstall if ($pathType -eq [System.EnvironmentVariableTarget]::Machine) { - $UACEnabled = Get-UACEnabled - if ((Test-AdminRights) -and !$UACEnabled) { + if (Test-AdminRights) { [Environment]::SetEnvironmentVariable('Path', $actualPath, $pathType) } else { $psArgs = "[Environment]::SetEnvironmentVariable('Path',`'$actualPath`', `'$pathType`')" From ecb5037e3f2e602b8b1e56a4287ca80fbe894319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Fri, 6 Jun 2014 02:14:14 +0200 Subject: [PATCH 11/15] setup tests: do not vary by UAC status Since UAC status is no longer a factor influencing setup behavior, remove effectively duplicated tests. Tampering with UAC settings is also no longer necessary, which eliminates the threat of interrupted tests leaving the OS with changed UAC status. --- tests/unit/Initialize-Chocolatey.Tests.ps1 | 489 +-------------------- 1 file changed, 14 insertions(+), 475 deletions(-) diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index 1b9f81c..ec56dc6 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -3,62 +3,6 @@ $testsDir = Split-Path -Parent $here $baseDir = Split-Path -Parent $testsDir . (Join-Path $testsDir '_TestHelpers.ps1') -function Execute-WithMockingUAC([string]$status, $scriptBlock) -{ - switch ($status) { - 'Enabled' { $enabled = $true } - 'Disabled' { $enabled = $false } - default { throw "Invalid `$status value: $status" } - } - $uacRegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" - if (-not (Test-Path $uacRegPath)) { - if ($enabled) { - Write-Warning "UAC mock: registry path $uacRegPath does not exist. This means that tests mocking UAC enabled would not be conclusive, so this test is skipped." - } else { - Write-Verbose "UAC mock: registry path $uacRegPath does not exist, assuming UAC is not present." - & $scriptBlock - } - return - } - $uacRegValue = "EnableLUA" - try - { - $vals = Get-ItemProperty -Path $uacRegPath - $savedValue = $vals.EnableLUA - } - catch - { - $savedValue = $null - } - if ($enabled) { - $mockedValue = 1 - } else { - $mockedValue = 0 - } - if ($savedValue -ne $mockedValue) { - Write-Verbose "UAC mock: setting $uacRegValue value to $mockedValue" - Set-ItemProperty -Path $uacRegPath -Name $uacRegValue -Value $mockedValue -Type DWord - } else { - Write-Verbose "UAC mock: $uacRegValue is already $mockedValue" - } - try - { - & $scriptBlock - } - finally - { - if ($savedValue -ne $mockedValue) { - if ($savedValue -eq $null) { - Write-Verbose "UAC mock: clearing $uacRegValue because it did not exist previously" - Clear-ItemProperty -Path $uacRegPath -Name $uacRegValue - } else { - Write-Verbose "UAC mock: restoring previous $uacRegValue value $savedValue" - Set-ItemProperty -Path $uacRegPath -Name $uacRegValue -Value $savedValue -Type DWord - } - } - } -} - function Add-ChocolateyInstall($path, $targetScope) { Add-EnvironmentVariable 'ChocolateyInstall' $path $targetScope @@ -151,391 +95,13 @@ function Execute-ChocolateyInstallationInDefaultDir($scriptBlock) Describe "Initialize-Chocolatey" { # note: the correctness of the specs below is dependent upon all code using Test-AdminRights - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall not set and no arguments" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $null - - Execute-ChocolateyInstallationInDefaultDir { - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should create ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } - - It "should create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $null - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey -chocolateyPath $installDir - - Verify-ExpectedContentInstalled $installDir - - It "should create ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } - - It "should create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'Process' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey -chocolateyPath $installDir - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } - - # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment - It "should create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'Process' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' - - # Is this really desired behavior - giving precedence to environment over explicit argument? - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } - - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'Machine' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } - - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at User scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'User' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } - - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Process scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'Process' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } - - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'Machine' - Add-ChocolateyInstall $installDir 'User' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } - - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' - Add-ChocolateyInstall $installDir 'User' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } - - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' - Add-ChocolateyInstall $installDir 'Process' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } - - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with `$Env:ChocolateyInstall set at User scope and different at Process scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall 'X:\nonexistent' 'User' - Add-ChocolateyInstall $installDir 'Process' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - Verify-ExpectedContentInstalled $installDir - - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } - - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' - } - - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with bin directory not on PATH" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'User' - Remove-DirectoryFromPath "$installDir\bin" - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - $binDir = "$installDir\bin" - - It "should add bin to PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } - - It "should not add bin to PATH at User scope" { - Assert-NotOnPath $binDir 'User' - } - - It "should add bin to PATH at Machine scope" { - Assert-OnPath $binDir 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with bin directory on PATH at Machine scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'User' - Remove-DirectoryFromPath "$installDir\bin" - Add-DirectoryToPath "$installDir\bin" 'Machine' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - $binDir = "$installDir\bin" - - It "should retain bin on PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } - - It "should not add bin to PATH at User scope" { - Assert-NotOnPath $binDir 'User' - } - - It "should retain bin on PATH at Machine scope" { - Assert-OnPath $binDir 'Machine' - } - } - } - } - - Context "When installing as admin, without UAC, with bin directory on PATH at User scope" { - Setup-ChocolateyInstallationPackage - - Execute-WithEnvironmentBackup { - Setup-ChocolateyInstall $installDir 'User' - Remove-DirectoryFromPath "$installDir\bin" - Add-DirectoryToPath "$installDir\bin" 'User' - - Execute-WithMockingUAC Disabled { - Initialize-Chocolatey - - $binDir = "$installDir\bin" - - It "should retain bin on PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } - - It "should retain bin on PATH at User scope" { - Assert-OnPath $binDir 'User' - } - - It "should not add bin to PATH at Machine scope" { - Assert-NotOnPath $binDir 'Machine' - } - } - } - } - - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall not set and no arguments" { + Context "When installing as admin, with `$Env:ChocolateyInstall not set and no arguments" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $null Execute-ChocolateyInstallationInDefaultDir { - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -551,18 +117,16 @@ Describe "Initialize-Chocolatey" { It "should create ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIs $installDir 'Machine' } - } } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { + Context "When installing as admin, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $null - Execute-WithMockingUAC Enabled { Initialize-Chocolatey -chocolateyPath $installDir Verify-ExpectedContentInstalled $installDir @@ -578,17 +142,15 @@ Describe "Initialize-Chocolatey" { It "should create ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIs $installDir 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { + Context "When installing as admin, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey -chocolateyPath $installDir Verify-ExpectedContentInstalled $installDir @@ -605,17 +167,15 @@ Describe "Initialize-Chocolatey" { It "should create ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIs $installDir 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { + Context "When installing as admin, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' # Is this really desired behavior - giving precedence to environment over explicit argument? @@ -632,17 +192,15 @@ Describe "Initialize-Chocolatey" { It "should not create ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIsNull 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope" { + Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Machine' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -658,17 +216,15 @@ Describe "Initialize-Chocolatey" { It "should preserve value of ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIs $installDir 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at User scope" { + Context "When installing as admin with `$Env:ChocolateyInstall set at User scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'User' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -684,17 +240,15 @@ Describe "Initialize-Chocolatey" { It "should not create ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIsNull 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Process scope" { + Context "When installing as admin with `$Env:ChocolateyInstall set at Process scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -710,18 +264,16 @@ Describe "Initialize-Chocolatey" { It "should not create ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIsNull 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { + Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Machine' Add-ChocolateyInstall $installDir 'User' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -737,18 +289,16 @@ Describe "Initialize-Chocolatey" { It "should preserve value of ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIs $installDir 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { + Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'User' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -764,18 +314,16 @@ Describe "Initialize-Chocolatey" { It "should preserve value of ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { + Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'Process' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -791,18 +339,16 @@ Describe "Initialize-Chocolatey" { It "should preserve value of ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' } - } } } - Context "When installing as admin, with UAC, with `$Env:ChocolateyInstall set at User scope and different at Process scope" { + Context "When installing as admin with `$Env:ChocolateyInstall set at User scope and different at Process scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall 'X:\nonexistent' 'User' Add-ChocolateyInstall $installDir 'Process' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey Verify-ExpectedContentInstalled $installDir @@ -818,18 +364,16 @@ Describe "Initialize-Chocolatey" { It "should not create ChocolateyInstall at Machine scope" { Assert-ChocolateyInstallIsNull 'Machine' } - } } } - Context "When installing as admin, with UAC, with bin directory not on PATH" { + Context "When installing as admin with bin directory not on PATH" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" - Execute-WithMockingUAC Enabled { Initialize-Chocolatey $binDir = "$installDir\bin" @@ -845,11 +389,10 @@ Describe "Initialize-Chocolatey" { It "should add bin to PATH at Machine scope" { Assert-OnPath $binDir 'Machine' } - } } } - Context "When installing as admin, with UAC, with bin directory on PATH at Machine scope" { + Context "When installing as admin with bin directory on PATH at Machine scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { @@ -857,7 +400,6 @@ Describe "Initialize-Chocolatey" { Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'Machine' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey $binDir = "$installDir\bin" @@ -873,11 +415,10 @@ Describe "Initialize-Chocolatey" { It "should retain bin on PATH at Machine scope" { Assert-OnPath $binDir 'Machine' } - } } } - Context "When installing as admin, with UAC, with bin directory on PATH at User scope" { + Context "When installing as admin with bin directory on PATH at User scope" { Setup-ChocolateyInstallationPackage Execute-WithEnvironmentBackup { @@ -885,7 +426,6 @@ Describe "Initialize-Chocolatey" { Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'User' - Execute-WithMockingUAC Enabled { Initialize-Chocolatey $binDir = "$installDir\bin" @@ -901,7 +441,6 @@ Describe "Initialize-Chocolatey" { It "should not add bin to PATH at Machine scope" { Assert-NotOnPath $binDir 'Machine' } - } } } From 3f8de3ed81397a12dd63a98df66166ff9be2c0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Wed, 11 Jun 2014 22:34:51 +0200 Subject: [PATCH 12/15] setup tests: fix formatting Separated from the previous commit so that the previous diff is easier to review. --- tests/unit/Initialize-Chocolatey.Tests.ps1 | 312 ++++++++++----------- 1 file changed, 156 insertions(+), 156 deletions(-) diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index ec56dc6..491b1c4 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -102,21 +102,21 @@ Describe "Initialize-Chocolatey" { Setup-ChocolateyInstall $null Execute-ChocolateyInstallationInDefaultDir { - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should create ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } } } @@ -127,21 +127,21 @@ Describe "Initialize-Chocolatey" { Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $null - Initialize-Chocolatey -chocolateyPath $installDir + Initialize-Chocolatey -chocolateyPath $installDir - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should create ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should create ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } } @@ -151,22 +151,22 @@ Describe "Initialize-Chocolatey" { Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey -chocolateyPath $installDir + Initialize-Chocolatey -chocolateyPath $installDir - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment - It "should create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } + # this is unexpected - different behavior than both when chocolateyPath is not passed and when passed chocolateyPath is different than environment + It "should create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } } @@ -176,22 +176,22 @@ Describe "Initialize-Chocolatey" { Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' + Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' - # Is this really desired behavior - giving precedence to environment over explicit argument? - Verify-ExpectedContentInstalled $installDir + # Is this really desired behavior - giving precedence to environment over explicit argument? + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } @@ -201,21 +201,21 @@ Describe "Initialize-Chocolatey" { Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Machine' - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } } @@ -225,21 +225,21 @@ Describe "Initialize-Chocolatey" { Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'User' - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } @@ -249,21 +249,21 @@ Describe "Initialize-Chocolatey" { Execute-WithEnvironmentBackup { Setup-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } @@ -274,21 +274,21 @@ Describe "Initialize-Chocolatey" { Setup-ChocolateyInstall $installDir 'Machine' Add-ChocolateyInstall $installDir 'User' - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs $installDir 'Machine' - } + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs $installDir 'Machine' + } } } @@ -299,21 +299,21 @@ Describe "Initialize-Chocolatey" { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'User' - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs $installDir 'User' - } + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs $installDir 'User' + } - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' - } + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } } } @@ -324,21 +324,21 @@ Describe "Initialize-Chocolatey" { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should not create ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIsNull 'User' - } + It "should not create ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIsNull 'User' + } - It "should preserve value of ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' - } + It "should preserve value of ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'Machine' + } } } @@ -349,21 +349,21 @@ Describe "Initialize-Chocolatey" { Setup-ChocolateyInstall 'X:\nonexistent' 'User' Add-ChocolateyInstall $installDir 'Process' - Initialize-Chocolatey + Initialize-Chocolatey - Verify-ExpectedContentInstalled $installDir + Verify-ExpectedContentInstalled $installDir - It "should preserve value of ChocolateyInstall at Process scope" { - Assert-ChocolateyInstallIs $installDir 'Process' - } + It "should preserve value of ChocolateyInstall at Process scope" { + Assert-ChocolateyInstallIs $installDir 'Process' + } - It "should preserve value of ChocolateyInstall at User scope" { - Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' - } + It "should preserve value of ChocolateyInstall at User scope" { + Assert-ChocolateyInstallIs 'X:\nonexistent' 'User' + } - It "should not create ChocolateyInstall at Machine scope" { - Assert-ChocolateyInstallIsNull 'Machine' - } + It "should not create ChocolateyInstall at Machine scope" { + Assert-ChocolateyInstallIsNull 'Machine' + } } } @@ -374,21 +374,21 @@ Describe "Initialize-Chocolatey" { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" - Initialize-Chocolatey + Initialize-Chocolatey - $binDir = "$installDir\bin" + $binDir = "$installDir\bin" - It "should add bin to PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } + It "should add bin to PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } - It "should not add bin to PATH at User scope" { - Assert-NotOnPath $binDir 'User' - } + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' + } - It "should add bin to PATH at Machine scope" { - Assert-OnPath $binDir 'Machine' - } + It "should add bin to PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' + } } } @@ -400,21 +400,21 @@ Describe "Initialize-Chocolatey" { Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'Machine' - Initialize-Chocolatey + Initialize-Chocolatey - $binDir = "$installDir\bin" + $binDir = "$installDir\bin" - It "should retain bin on PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } - It "should not add bin to PATH at User scope" { - Assert-NotOnPath $binDir 'User' - } + It "should not add bin to PATH at User scope" { + Assert-NotOnPath $binDir 'User' + } - It "should retain bin on PATH at Machine scope" { - Assert-OnPath $binDir 'Machine' - } + It "should retain bin on PATH at Machine scope" { + Assert-OnPath $binDir 'Machine' + } } } @@ -426,21 +426,21 @@ Describe "Initialize-Chocolatey" { Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'User' - Initialize-Chocolatey + Initialize-Chocolatey - $binDir = "$installDir\bin" + $binDir = "$installDir\bin" - It "should retain bin on PATH at Process scope" { - Assert-OnPath $binDir 'Process' - } + It "should retain bin on PATH at Process scope" { + Assert-OnPath $binDir 'Process' + } - It "should retain bin on PATH at User scope" { - Assert-OnPath $binDir 'User' - } + It "should retain bin on PATH at User scope" { + Assert-OnPath $binDir 'User' + } - It "should not add bin to PATH at Machine scope" { - Assert-NotOnPath $binDir 'Machine' - } + It "should not add bin to PATH at Machine scope" { + Assert-NotOnPath $binDir 'Machine' + } } } From e8423f2cd92aa7a556f648d499a07f7e0bb01de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Tue, 17 Jun 2014 22:22:20 +0200 Subject: [PATCH 13/15] rename Test-AdminRights to Test-ProcessAdminRights As per @ferventcoder's suggestion. Longer name, but makes it more explicit the current process rights are tested (in contrast to e.g. the user account being member of the Administrators group). --- nuget/tools/chocolateysetup.psm1 | 4 ++-- src/helpers/chocolateyInstaller.psm1 | 2 +- .../functions/Install-ChocolateyEnvironmentVariable.ps1 | 2 +- src/helpers/functions/Install-ChocolateyPath.ps1 | 2 +- .../{Test-AdminRights.ps1 => Test-ProcessAdminRights.ps1} | 4 ++-- tests/unit/Initialize-Chocolatey.Tests.ps1 | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) rename src/helpers/functions/{Test-AdminRights.ps1 => Test-ProcessAdminRights.ps1} (90%) diff --git a/nuget/tools/chocolateysetup.psm1 b/nuget/tools/chocolateysetup.psm1 index 52503b5..d11b2ed 100644 --- a/nuget/tools/chocolateysetup.psm1 +++ b/nuget/tools/chocolateysetup.psm1 @@ -89,7 +89,7 @@ param( [string]$folder ) $environmentTarget = [System.EnvironmentVariableTarget]::User - if (Test-AdminRights) { + if (Test-ProcessAdminRights) { Write-Debug "Administrator installing so using Machine environment variable target instead of User." $environmentTarget = [System.EnvironmentVariableTarget]::Machine } @@ -154,7 +154,7 @@ param( ) $environmentTarget = [System.EnvironmentVariableTarget]::User - if (Test-AdminRights) { + if (Test-ProcessAdminRights) { Write-Debug "Administrator installing so using Machine environment variable target instead of User." $environmentTarget = [System.EnvironmentVariableTarget]::Machine } diff --git a/src/helpers/chocolateyInstaller.psm1 b/src/helpers/chocolateyInstaller.psm1 index 186e3ea..af49da2 100644 --- a/src/helpers/chocolateyInstaller.psm1 +++ b/src/helpers/chocolateyInstaller.psm1 @@ -31,6 +31,6 @@ Export-ModuleMember -Function ` Write-ChocolateyFailure,` Write-Host,`Write-Debug,`Write-Error,` Start-ChocolateyProcessAsAdmin,` - Test-AdminRights,` + Test-ProcessAdminRights,` Uninstall-ChocolateyPackage,` Update-SessionEnvironment diff --git a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 index 616c138..e96b957 100644 --- a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 +++ b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 @@ -41,7 +41,7 @@ param( Write-Debug "Running 'Install-ChocolateyEnvironmentVariable' with variableName:`'$variableName`' and variableValue:`'$variableValue`'"; if ($variableType -eq [System.EnvironmentVariableTarget]::Machine) { - if (Test-AdminRights) { + if (Test-ProcessAdminRights) { [Environment]::SetEnvironmentVariable($variableName, $variableValue, $variableType) } else { $psArgs = "[Environment]::SetEnvironmentVariable(`'$variableName`',`'$variableValue`', `'$variableType`')" diff --git a/src/helpers/functions/Install-ChocolateyPath.ps1 b/src/helpers/functions/Install-ChocolateyPath.ps1 index d2b3bd4..a2786da 100644 --- a/src/helpers/functions/Install-ChocolateyPath.ps1 +++ b/src/helpers/functions/Install-ChocolateyPath.ps1 @@ -22,7 +22,7 @@ param( $actualPath = $actualPath + $pathToInstall if ($pathType -eq [System.EnvironmentVariableTarget]::Machine) { - if (Test-AdminRights) { + if (Test-ProcessAdminRights) { [Environment]::SetEnvironmentVariable('Path', $actualPath, $pathType) } else { $psArgs = "[Environment]::SetEnvironmentVariable('Path',`'$actualPath`', `'$pathType`')" diff --git a/src/helpers/functions/Test-AdminRights.ps1 b/src/helpers/functions/Test-ProcessAdminRights.ps1 similarity index 90% rename from src/helpers/functions/Test-AdminRights.ps1 rename to src/helpers/functions/Test-ProcessAdminRights.ps1 index a90b97f..7ace4af 100644 --- a/src/helpers/functions/Test-AdminRights.ps1 +++ b/src/helpers/functions/Test-ProcessAdminRights.ps1 @@ -1,4 +1,4 @@ -function Test-AdminRights { +function Test-ProcessAdminRights { <# .SYNOPSIS Tests whether the current process is running with administrative rights. @@ -20,6 +20,6 @@ System.Boolean $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent([Security.Principal.TokenAccessLevels]'Query,Duplicate')) $isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) - Write-Debug "Test-AdminRights: returning $isAdmin" + Write-Debug "Test-ProcessAdminRights: returning $isAdmin" return $isAdmin } diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index 491b1c4..514dc9c 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -55,9 +55,9 @@ function Setup-ChocolateyInstallationPackage([switch] $SimulateStandardUser) Get-ChildItem "$baseDir\src" | Copy-Item -Destination "$script:tmpDir\chocolateyInstall" -Recurse -Force if ($SimulateStandardUser) { - 'function Test-AdminRights() { return $false }' | Set-Content (Join-Path $script:tmpDir chocolateyInstall\helpers\functions\Test-AdminRights.ps1) + 'function Test-ProcessAdminRights() { return $false }' | Set-Content (Join-Path $script:tmpDir chocolateyInstall\helpers\functions\Test-ProcessAdminRights.ps1) } else { - 'function Test-AdminRights() { return $true }' | Set-Content (Join-Path $script:tmpDir chocolateyInstall\helpers\functions\Test-AdminRights.ps1) + 'function Test-ProcessAdminRights() { return $true }' | Set-Content (Join-Path $script:tmpDir chocolateyInstall\helpers\functions\Test-ProcessAdminRights.ps1) } $script:installDir = Join-Path (Resolve-Path 'TestDrive:\').ProviderPath chocoinstall @@ -93,7 +93,7 @@ function Execute-ChocolateyInstallationInDefaultDir($scriptBlock) } Describe "Initialize-Chocolatey" { - # note: the correctness of the specs below is dependent upon all code using Test-AdminRights + # note: the correctness of the specs below is dependent upon all code using Test-ProcessAdminRights Context "When installing as admin, with `$Env:ChocolateyInstall not set and no arguments" { Setup-ChocolateyInstallationPackage From f5c47dd38d9121a6d12412404d69ca0e5adef324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Sat, 14 Jun 2014 22:46:45 +0200 Subject: [PATCH 14/15] helpers: add environment variable management abstractions The three added functions wrap [Environment]::Get/SetEnvironmentVariable and obtaining variable names from the registry. The purpose is to enable mocking environment manipulation in tests. The functions are exported from the module, otherwise core Chocolatey (Chocolatey-Python, Chocolatey-RubyGem) would not be able to use them. Nevertheless, packages should in most circumstances use the high-level Install-ChocolateyEnvironmentVariable and Install-ChocolateyPath helpers. All Chocolatey code is changed to use these new functions. --- src/functions/Chocolatey-Python.ps1 | 2 +- src/functions/Chocolatey-RubyGem.ps1 | 2 +- src/helpers/chocolateyInstaller.psm1 | 5 ++++- src/helpers/functions/Get-BinRoot.ps1 | 2 +- .../functions/Get-EnvironmentVariable.ps1 | 3 +++ .../functions/Get-EnvironmentVariableNames.ps1 | 8 ++++++++ .../Install-ChocolateyEnvironmentVariable.ps1 | 6 +++--- .../functions/Install-ChocolateyPath.ps1 | 10 +++++----- .../functions/Set-EnvironmentVariable.ps1 | 3 +++ .../functions/Update-SessionEnvironment.ps1 | 18 +++++------------- 10 files changed, 34 insertions(+), 25 deletions(-) create mode 100644 src/helpers/functions/Get-EnvironmentVariable.ps1 create mode 100644 src/helpers/functions/Get-EnvironmentVariableNames.ps1 create mode 100644 src/helpers/functions/Set-EnvironmentVariable.ps1 diff --git a/src/functions/Chocolatey-Python.ps1 b/src/functions/Chocolatey-Python.ps1 index a9b828c..b166404 100644 --- a/src/functions/Chocolatey-Python.ps1 +++ b/src/functions/Chocolatey-Python.ps1 @@ -10,7 +10,7 @@ param( Chocolatey-InstallIfMissing 'python' if ($($env:Path).ToLower().Contains("python") -eq $false) { - $env:Path = [Environment]::GetEnvironmentVariable('Path',[System.EnvironmentVariableTarget]::Machine); + $env:Path = Get-EnvironmentVariable -Name 'Path' -Scope Machine } Chocolatey-InstallIfMissing 'easy.install' diff --git a/src/functions/Chocolatey-RubyGem.ps1 b/src/functions/Chocolatey-RubyGem.ps1 index aeefa72..0a84a58 100644 --- a/src/functions/Chocolatey-RubyGem.ps1 +++ b/src/functions/Chocolatey-RubyGem.ps1 @@ -9,7 +9,7 @@ param( Chocolatey-InstallIfMissing 'ruby' if ($($env:Path).ToLower().Contains("ruby") -eq $false) { - $env:Path = [Environment]::GetEnvironmentVariable('Path',[System.EnvironmentVariableTarget]::Machine); + $env:Path = Get-EnvironmentVariable -Name 'Path' -Scope Machine } diff --git a/src/helpers/chocolateyInstaller.psm1 b/src/helpers/chocolateyInstaller.psm1 index af49da2..4741fcf 100644 --- a/src/helpers/chocolateyInstaller.psm1 +++ b/src/helpers/chocolateyInstaller.psm1 @@ -33,4 +33,7 @@ Export-ModuleMember -Function ` Start-ChocolateyProcessAsAdmin,` Test-ProcessAdminRights,` Uninstall-ChocolateyPackage,` - Update-SessionEnvironment + Update-SessionEnvironment,` + Get-EnvironmentVariableNames,` + Get-EnvironmentVariable,` + Set-EnvironmentVariable diff --git a/src/helpers/functions/Get-BinRoot.ps1 b/src/helpers/functions/Get-BinRoot.ps1 index 7df0cb3..ac7f091 100644 --- a/src/helpers/functions/Get-BinRoot.ps1 +++ b/src/helpers/functions/Get-BinRoot.ps1 @@ -38,7 +38,7 @@ function Get-BinRoot { # Now that we figured out the binRoot, let's store it as per proposal #3 line #7 if (-not($env:ChocolateyBinRoot -eq $binRoot)) { - [Environment]::SetEnvironmentVariable("ChocolateyBinRoot", "$binRoot", "User") + Set-EnvironmentVariable -Name "ChocolateyBinRoot" -Value $binRoot -Scope User # Note that user variables pose a problem when there are two admins on one computer. But this is what was decided upon. } diff --git a/src/helpers/functions/Get-EnvironmentVariable.ps1 b/src/helpers/functions/Get-EnvironmentVariable.ps1 new file mode 100644 index 0000000..4892360 --- /dev/null +++ b/src/helpers/functions/Get-EnvironmentVariable.ps1 @@ -0,0 +1,3 @@ +function Get-EnvironmentVariable([string] $Name, [System.EnvironmentVariableTarget] $Scope) { + [Environment]::GetEnvironmentVariable($Name, $Scope) +} diff --git a/src/helpers/functions/Get-EnvironmentVariableNames.ps1 b/src/helpers/functions/Get-EnvironmentVariableNames.ps1 new file mode 100644 index 0000000..50b97da --- /dev/null +++ b/src/helpers/functions/Get-EnvironmentVariableNames.ps1 @@ -0,0 +1,8 @@ +function Get-EnvironmentVariableNames([System.EnvironmentVariableTarget] $Scope) { + switch ($Scope) { + 'User' { Get-Item 'HKCU:\Environment' | Select-Object -ExpandProperty Property } + 'Machine' { Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' | Select-Object -ExpandProperty Property } + 'Process' { Get-ChildItem Env:\ | Select-Object -ExpandProperty Key } + default { throw "Unsupported environment scope: $Scope" } + } +} diff --git a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 index e96b957..75d8017 100644 --- a/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 +++ b/src/helpers/functions/Install-ChocolateyEnvironmentVariable.ps1 @@ -42,13 +42,13 @@ param( if ($variableType -eq [System.EnvironmentVariableTarget]::Machine) { if (Test-ProcessAdminRights) { - [Environment]::SetEnvironmentVariable($variableName, $variableValue, $variableType) + Set-EnvironmentVariable -Name $variableName -Value $variableValue -Scope $variableType } else { - $psArgs = "[Environment]::SetEnvironmentVariable(`'$variableName`',`'$variableValue`', `'$variableType`')" + $psArgs = "Install-ChocolateyEnvironmentVariable -variableName `'$variableName`' -variableValue `'$variableValue`' -variableType `'$variableType`'" Start-ChocolateyProcessAsAdmin "$psArgs" } } else { - [Environment]::SetEnvironmentVariable($variableName, $variableValue, $variableType) + Set-EnvironmentVariable -Name $variableName -Value $variableValue -Scope $variableType } Set-Content env:\$variableName $variableValue diff --git a/src/helpers/functions/Install-ChocolateyPath.ps1 b/src/helpers/functions/Install-ChocolateyPath.ps1 index a2786da..8b3fc97 100644 --- a/src/helpers/functions/Install-ChocolateyPath.ps1 +++ b/src/helpers/functions/Install-ChocolateyPath.ps1 @@ -4,14 +4,14 @@ param( [System.EnvironmentVariableTarget] $pathType = [System.EnvironmentVariableTarget]::User ) Write-Debug "Running 'Install-ChocolateyPath' with pathToInstall:`'$pathToInstall`'"; + $originalPathToInstall = $pathToInstall #get the PATH variable $envPath = $env:PATH - #$envPath = [Environment]::GetEnvironmentVariable('Path', $pathType) if (!$envPath.ToLower().Contains($pathToInstall.ToLower())) { Write-Host "PATH environment variable does not have $pathToInstall in it. Adding..." - $actualPath = [Environment]::GetEnvironmentVariable('Path', $pathType) + $actualPath = Get-EnvironmentVariable -Name 'Path' -Scope $pathType $statementTerminator = ";" #does the path end in ';'? @@ -23,13 +23,13 @@ param( if ($pathType -eq [System.EnvironmentVariableTarget]::Machine) { if (Test-ProcessAdminRights) { - [Environment]::SetEnvironmentVariable('Path', $actualPath, $pathType) + Set-EnvironmentVariable -Name 'Path' -Value $actualPath -Scope $pathType } else { - $psArgs = "[Environment]::SetEnvironmentVariable('Path',`'$actualPath`', `'$pathType`')" + $psArgs = "Install-ChocolateyPath -pathToInstall `'$originalPathToInstall`' -pathType `'$pathType`'" Start-ChocolateyProcessAsAdmin "$psArgs" } } else { - [Environment]::SetEnvironmentVariable('Path', $actualPath, $pathType) + Set-EnvironmentVariable -Name 'Path' -Value $actualPath -Scope $pathType } #add it to the local path as well so users will be off and running diff --git a/src/helpers/functions/Set-EnvironmentVariable.ps1 b/src/helpers/functions/Set-EnvironmentVariable.ps1 new file mode 100644 index 0000000..c26409f --- /dev/null +++ b/src/helpers/functions/Set-EnvironmentVariable.ps1 @@ -0,0 +1,3 @@ +function Set-EnvironmentVariable([string] $Name, [string] $Value, [System.EnvironmentVariableTarget] $Scope) { + [Environment]::SetEnvironmentVariable($Name, $Value, $Scope) +} diff --git a/src/helpers/functions/Update-SessionEnvironment.ps1 b/src/helpers/functions/Update-SessionEnvironment.ps1 index 5f9cdaa..114875d 100644 --- a/src/helpers/functions/Update-SessionEnvironment.ps1 +++ b/src/helpers/functions/Update-SessionEnvironment.ps1 @@ -18,29 +18,21 @@ powershell session with all environment settings possibly performed by chocolatey package installs. #> - $user = 'HKCU:\Environment' - $machine ='HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' #ordering is important here, $user comes after so we can override $machine - $machine, $user | - Get-Item | + 'Machine', 'User' | % { - $regPath = $_.PSPath - $_ | - Select -ExpandProperty Property | + $scope = $_ + Get-EnvironmentVariableNames -Scope $scope | % { - Set-Item "Env:$($_)" -Value (Get-ItemProperty $regPath -Name $_).$_ + Set-Item "Env:$($_)" -Value (Get-EnvironmentVariable -Scope $scope -Name $_) } } #Path gets special treatment b/c it munges the two together $paths = 'Machine', 'User' | % { - (Get-EnvironmentVar 'PATH' $_) -split ';' + (Get-EnvironmentVariable -Name 'PATH' -Scope $_) -split ';' } | Select -Unique $Env:PATH = $paths -join ';' } - -function Get-EnvironmentVar($key, $scope) { - [Environment]::GetEnvironmentVariable($key, $scope) -} From 1314e2c9298e5b59591dd30f0e4be2a8e9f02a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bere=C5=BCa=C5=84ski?= Date: Sun, 15 Jun 2014 00:11:19 +0200 Subject: [PATCH 15/15] tests: add environment manipulation mocking facility Add implementations of environment manipulation functions that operate on an object stored in a global variable, instead of on the live system environment. All test code that might manipulate the environment should be wrapped in a call to Execute-WithEnvironmentProtection. This function takes a snapshot of the environment, initializes the mocked environment state based on that snapshot, executes test code and reverts any modifications to the environment to the state from the snapshot. Reverting environment changes is important for two reasons: 1) although the mocking mechanism prevents changes to the actual Machine and User environment (by cooperating code), Process environment still needs to be restored. 2) there is the possibility that some un-cooperating code will execute that will, by bug or omission, bypass the environment management functions and modify the live environment. The environment restoring code will mitigate the damage and will emit a warning in such case, so that the culprit may be caught. If a test case tries to alter the environment without using the mocking/protection facility, an error will occur, instructing to use the appropriate construct in the test case. Together with mocking admin rights tests implemented earlier, this commit makes it possible to run Chocolatey setup and Update-SessionEnvironment tests as standard user, with no fear of corrupting systemwide state. Implementation note: diagnostic messages are emitted at Verbose level, because Debug failed to appear during setup tests (no time to investigate). --- tests/_TestHelpers.ps1 | 74 ++++++++++++------- .../functions/Get-EnvironmentVariable.ps1 | 13 ++++ .../Get-EnvironmentVariableNames.ps1 | 13 ++++ .../functions/Set-EnvironmentVariable.ps1 | 19 +++++ tests/unit/Initialize-Chocolatey.Tests.ps1 | 61 +++++++-------- .../unit/Update-SessionEnvironment.tests.ps1 | 60 +++++---------- 6 files changed, 142 insertions(+), 98 deletions(-) create mode 100644 tests/mocks/helpers/functions/Get-EnvironmentVariable.ps1 create mode 100644 tests/mocks/helpers/functions/Get-EnvironmentVariableNames.ps1 create mode 100644 tests/mocks/helpers/functions/Set-EnvironmentVariable.ps1 diff --git a/tests/_TestHelpers.ps1 b/tests/_TestHelpers.ps1 index 03366c2..e395c85 100644 --- a/tests/_TestHelpers.ps1 +++ b/tests/_TestHelpers.ps1 @@ -1,6 +1,10 @@ -function Backup-Environment() +$here = Split-Path -Parent $MyInvocation.MyCommand.Definition + +Get-ChildItem "$here\mocks" -Filter *.ps1 -Recurse | ForEach-Object { Write-Debug "Importing $($_.FullName)"; . $_.FullName } + +function Get-EnvironmentSnapshot() { - Write-Debug 'Backing up the environment' + Write-Debug 'Obtaining snapshot of the environment' $machineEnv = @{} $key = Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' $key.GetValueNames() | ForEach-Object { $machineEnv[$_] = $key.GetValue($_) } @@ -21,28 +25,28 @@ function Restore-Environment($state) $state.machine.GetEnumerator() | ForEach-Object { $current = [Environment]::GetEnvironmentVariable($_.Key, 'Machine') if ($current -ne $_.Value) { - Write-Debug "Restoring value of environment variable $($_.Key) at Machine scope" + Write-Warning "Restoring value of environment variable $($_.Key) at Machine scope. The need to do that means that some code did not use the environment manipulation functions *-EnvironmentVariable*." [Environment]::SetEnvironmentVariable($_.Key, $_.Value, 'Machine') } } $key = Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' $key.GetValueNames() | Where-Object { -not $state.machine.ContainsKey($_) } | ForEach-Object { - Write-Debug "Deleting environment variable $_ at Machine scope" + Write-Warning "Deleting environment variable $_ at Machine scope. The need to do that means that some code did not use the environment manipulation functions *-EnvironmentVariable*." [Environment]::SetEnvironmentVariable($_, $null, 'Machine') } $state.user.GetEnumerator() | ForEach-Object { $current = [Environment]::GetEnvironmentVariable($_.Key, 'User') if ($current -ne $_.Value) { - Write-Debug "Restoring value of environment variable $($_.Key) at User scope" + Write-Warning "Restoring value of environment variable $($_.Key) at User scope. The need to do that means that some code did not use the environment manipulation functions *-EnvironmentVariable*." [Environment]::SetEnvironmentVariable($_.Key, $_.Value, 'User') } } $key = Get-Item 'HKCU:\Environment' $key.GetValueNames() | Where-Object { -not $state.user.ContainsKey($_) } | ForEach-Object { - Write-Debug "Deleting environment variable $_ at User scope" + Write-Warning "Deleting environment variable $_ at User scope. The need to do that means that some code did not use the environment manipulation functions *-EnvironmentVariable*." [Environment]::SetEnvironmentVariable($_, $null, 'User') } @@ -60,12 +64,30 @@ function Restore-Environment($state) } } -function Execute-WithEnvironmentBackup($scriptBlock) +function Setup-EnvironmentMockup +{ + $global:ChocolateyTestEnvironmentVariables = Get-EnvironmentSnapshot +} + +function Cleanup-EnvironmentMockup { - $savedEnvironment = Backup-Environment + $global:ChocolateyTestEnvironmentVariables = $null +} + +function Execute-WithEnvironmentProtection($scriptBlock) +{ + $savedEnvironment = Get-EnvironmentSnapshot try { - & $scriptBlock + Setup-EnvironmentMockup + try + { + & $scriptBlock + } + finally + { + Cleanup-EnvironmentMockup + } } finally { @@ -76,17 +98,17 @@ function Execute-WithEnvironmentBackup($scriptBlock) function Add-EnvironmentVariable($name, $value, $targetScope) { Write-Debug "Setting $name to $value at $targetScope scope" - [Environment]::SetEnvironmentVariable($name, $value, $targetScope) + Set-EnvironmentVariable -Name $name -Value $Value -Scope $targetScope if ($targetScope -eq 'Process') { Write-Debug "Current $name value is '$value' (from Process scope)" return } # find lowest scope with $name set and use that value as current foreach ($currentScope in @('User', 'Machine')) { - $valueAtCurrentScope = [Environment]::GetEnvironmentVariable($name, $currentScope) + $valueAtCurrentScope = Get-EnvironmentVariable -Name $name -Scope $currentScope if ($valueAtCurrentScope -ne $null) { Write-Debug "Current $name value is '$valueAtCurrentScope' (from $currentScope scope)" - [Environment]::SetEnvironmentVariable($name, $valueAtCurrentScope, 'Process') + Set-EnvironmentVariable -Name $name -Value $valueAtCurrentScope -Scope Process break } } @@ -96,36 +118,36 @@ function Remove-EnvironmentVariable($name) { Write-Debug "Ensuring environment variable $name is not set at any scope" 'Machine','User','Process' | ForEach-Object { - if (-not ([String]::IsNullOrEmpty([Environment]::GetEnvironmentVariable($name, $_)))) { + if (-not ([String]::IsNullOrEmpty((Get-EnvironmentVariable -Name $name -Scope $_)))) { Write-Debug "Deleting environment variable $name at $_ scope" - [Environment]::SetEnvironmentVariable($name, $null, $_) + Set-EnvironmentVariable -Name $name -Value $null -Scope $_ } } } function Add-DirectoryToPath($directory, $scope) { - $curPath = [Environment]::GetEnvironmentVariable('PATH', $scope) + $curPath = Get-EnvironmentVariable -Name 'PATH' -Scope $scope $newPath = ($curPath -split ';' | Where-Object { $_.TrimEnd('\') -ne $directory.TrimEnd('\') }) -join ';' if ($newPath -ne $curPath) { Write-Debug "Directory $directory is already on PATH at $scope scope" } else { Write-Debug "Adding directory $directory to PATH at $scope scope" if ([String]::IsNullOrEmpty($newPath)) { - [Environment]::SetEnvironmentVariable('PATH', $directory, $scope) + Set-EnvironmentVariable -Name 'PATH' -Value $directory -Scope $scope } else { - [Environment]::SetEnvironmentVariable('PATH', "$($newPath.TrimEnd(';'));$directory", $scope) + Set-EnvironmentVariable -Name 'PATH' -Value "$($newPath.TrimEnd(';'));$directory" -Scope $scope } } if ($scope -ne 'Process') { - $curPath = [Environment]::GetEnvironmentVariable('PATH', 'Process') + $curPath = Get-EnvironmentVariable -Name 'PATH' -Scope Process $newPath = ($curPath -split ';' | Where-Object { $_.TrimEnd('\') -ne $directory.TrimEnd('\') }) -join ';' if ($newPath -eq $curPath) { Write-Debug "Adding directory $directory to PATH at Process scope" if ([String]::IsNullOrEmpty($newPath)) { - [Environment]::SetEnvironmentVariable('PATH', $directory, 'Process') + Set-EnvironmentVariable -Name 'PATH' -Value $directory -Scope Process } else { - [Environment]::SetEnvironmentVariable('PATH', "$($newPath.TrimEnd(';'));$directory", 'Process') + Set-EnvironmentVariable -Name 'PATH' -Value "$($newPath.TrimEnd(';'));$directory" -Scope Process } } } @@ -136,25 +158,25 @@ function Remove-DirectoryFromPath($directory) Write-Debug "Ensuring directory $directory is not on PATH at any scope" 'Machine','User','Process' | ForEach-Object { $scope = $_ - $curPath = [Environment]::GetEnvironmentVariable('PATH', $scope) + $curPath = Get-EnvironmentVariable -Name 'PATH' -Scope $scope $newPath = ($curPath -split ';' | Where-Object { $_.TrimEnd('\') -ne $directory.TrimEnd('\') }) -join ';' if ($newPath -ne $curPath) { Write-Debug "Removing directory $directory from PATH at $scope scope" - [Environment]::SetEnvironmentVariable('PATH', $newPath, $scope) + Set-EnvironmentVariable -Name 'PATH' -Value $newPath -Scope $scope } } } function Assert-OnPath($directory, $pathScope) { - $path = [Environment]::GetEnvironmentVariable('PATH', $pathScope) - $dirInPath = [Environment]::GetEnvironmentVariable('PATH', $pathScope) -split ';' | Where-Object { $_ -eq $directory } + $path = Get-EnvironmentVariable -Name 'PATH' -Scope $pathScope + $dirInPath = $path -split ';' | Where-Object { $_ -eq $directory } "$dirInPath" | Should not BeNullOrEmpty } function Assert-NotOnPath($directory, $pathScope) { - $path = [Environment]::GetEnvironmentVariable('PATH', $pathScope) - $dirInPath = [Environment]::GetEnvironmentVariable('PATH', $pathScope) -split ';' | Where-Object { $_ -eq $directory } + $path = Get-EnvironmentVariable -Name 'PATH' -Scope $pathScope + $dirInPath = $path -split ';' | Where-Object { $_ -eq $directory } "$dirInPath" | Should BeNullOrEmpty } diff --git a/tests/mocks/helpers/functions/Get-EnvironmentVariable.ps1 b/tests/mocks/helpers/functions/Get-EnvironmentVariable.ps1 new file mode 100644 index 0000000..71ba854 --- /dev/null +++ b/tests/mocks/helpers/functions/Get-EnvironmentVariable.ps1 @@ -0,0 +1,13 @@ +function Get-EnvironmentVariable([string] $Name, [System.EnvironmentVariableTarget] $Scope) { + Write-Verbose "Mocked Get-EnvironmentVariable scope: $Scope name: $Name" + if ($global:ChocolateyTestEnvironmentVariables -eq $null) { + throw 'Environment mocking has not been set up. Please use Execute-WithEnvironmentProtection.' + } + + switch ($Scope) { + 'User' { return $global:ChocolateyTestEnvironmentVariables.user[$Name] } + 'Machine' { return $global:ChocolateyTestEnvironmentVariables.machine[$Name] } + 'Process' { return Get-Content "Env:\$Name" } + default { throw "Unsupported environment scope: $Scope" } + } +} diff --git a/tests/mocks/helpers/functions/Get-EnvironmentVariableNames.ps1 b/tests/mocks/helpers/functions/Get-EnvironmentVariableNames.ps1 new file mode 100644 index 0000000..5ee1d16 --- /dev/null +++ b/tests/mocks/helpers/functions/Get-EnvironmentVariableNames.ps1 @@ -0,0 +1,13 @@ +function Get-EnvironmentVariableNames([System.EnvironmentVariableTarget] $Scope) { + Write-Verbose "Mocked Get-EnvironmentVariableNames scope: $Scope" + if ($global:ChocolateyTestEnvironmentVariables -eq $null) { + throw 'Environment mocking has not been set up. Please use Execute-WithEnvironmentProtection.' + } + + switch ($Scope) { + 'User' { return @($global:ChocolateyTestEnvironmentVariables.user.Keys) } + 'Machine' { return @($global:ChocolateyTestEnvironmentVariables.machine.Keys) } + 'Process' { Get-ChildItem Env:\ | Select-Object -ExpandProperty Key } + default { throw "Unsupported environment scope: $Scope" } + } +} diff --git a/tests/mocks/helpers/functions/Set-EnvironmentVariable.ps1 b/tests/mocks/helpers/functions/Set-EnvironmentVariable.ps1 new file mode 100644 index 0000000..de9977e --- /dev/null +++ b/tests/mocks/helpers/functions/Set-EnvironmentVariable.ps1 @@ -0,0 +1,19 @@ +function Set-EnvironmentVariable([string] $Name, [string] $Value, [System.EnvironmentVariableTarget] $Scope) { + Write-Verbose "Mocked Set-EnvironmentVariable scope: $Scope name: $Name value: $Value" + if ($global:ChocolateyTestEnvironmentVariables -eq $null) { + throw 'Environment mocking has not been set up. Please use Execute-WithEnvironmentProtection.' + } + + switch ($Scope) { + 'User' { $storage = $global:ChocolateyTestEnvironmentVariables.user } + 'Machine' { $storage = $global:ChocolateyTestEnvironmentVariables.machine } + 'Process' { Set-Content "Env:$Name" $Value; return } + default { throw "Unsupported environment scope: $Scope" } + } + + if ([string]::IsNullOrEmpty($Value)) { + $storage.Remove($Name) + } else { + $storage[$Name] = $Value + } +} diff --git a/tests/unit/Initialize-Chocolatey.Tests.ps1 b/tests/unit/Initialize-Chocolatey.Tests.ps1 index 514dc9c..f256f6b 100644 --- a/tests/unit/Initialize-Chocolatey.Tests.ps1 +++ b/tests/unit/Initialize-Chocolatey.Tests.ps1 @@ -37,12 +37,12 @@ function Verify-ExpectedContentInstalled($installDir) function Assert-ChocolateyInstallIs($value, $scope) { - "$([Environment]::GetEnvironmentVariable('ChocolateyInstall', $scope))" | Should Be $value + "$(Get-EnvironmentVariable -Name 'ChocolateyInstall' -Scope $scope)" | Should Be $value } function Assert-ChocolateyInstallIsNull($scope) { - "$([Environment]::GetEnvironmentVariable('ChocolateyInstall', $scope))" | Should BeNullOrEmpty + "$(Get-EnvironmentVariable -Name 'ChocolateyInstall' -Scope $scope)" | Should BeNullOrEmpty } function Setup-ChocolateyInstallationPackage([switch] $SimulateStandardUser) @@ -53,6 +53,7 @@ function Setup-ChocolateyInstallationPackage([switch] $SimulateStandardUser) Get-ChildItem "$baseDir\nuget\tools" | Copy-Item -Destination $script:tmpDir -Recurse -Force Get-ChildItem "$baseDir\src" | Copy-Item -Destination "$script:tmpDir\chocolateyInstall" -Recurse -Force + Get-ChildItem "$testsDir\mocks" | Copy-Item -Destination "$script:tmpDir\chocolateyInstall" -Recurse -Force if ($SimulateStandardUser) { 'function Test-ProcessAdminRights() { return $false }' | Set-Content (Join-Path $script:tmpDir chocolateyInstall\helpers\functions\Test-ProcessAdminRights.ps1) @@ -98,7 +99,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin, with `$Env:ChocolateyInstall not set and no arguments" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $null Execute-ChocolateyInstallationInDefaultDir { @@ -124,7 +125,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $null Initialize-Chocolatey -chocolateyPath $installDir @@ -148,7 +149,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Process' Initialize-Chocolatey -chocolateyPath $installDir @@ -173,7 +174,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Process' Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' @@ -198,7 +199,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Machine' Initialize-Chocolatey @@ -222,7 +223,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with `$Env:ChocolateyInstall set at User scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Initialize-Chocolatey @@ -246,7 +247,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with `$Env:ChocolateyInstall set at Process scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Process' Initialize-Chocolatey @@ -270,7 +271,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Machine' Add-ChocolateyInstall $installDir 'User' @@ -295,7 +296,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'User' @@ -320,7 +321,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'Process' @@ -345,7 +346,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with `$Env:ChocolateyInstall set at User scope and different at Process scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall 'X:\nonexistent' 'User' Add-ChocolateyInstall $installDir 'Process' @@ -370,7 +371,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with bin directory not on PATH" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" @@ -395,7 +396,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with bin directory on PATH at Machine scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'Machine' @@ -421,7 +422,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as admin with bin directory on PATH at User scope" { Setup-ChocolateyInstallationPackage - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'User' @@ -447,7 +448,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user, with `$Env:ChocolateyInstall not set and no arguments" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $null Execute-ChocolateyInstallationInDefaultDir { @@ -473,7 +474,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user, with `$Env:ChocolateyInstall not set, with explicit chocolateyPath" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $null Initialize-Chocolatey -chocolateyPath $installDir @@ -497,7 +498,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user, with `$Env:ChocolateyInstall set at Process scope, with same explicit chocolateyPath" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Process' Initialize-Chocolatey -chocolateyPath $installDir @@ -522,7 +523,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user, with `$Env:ChocolateyInstall set at Process scope, with different explicit chocolateyPath" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Process' Initialize-Chocolatey -chocolateyPath 'X:\nonexistent' @@ -547,7 +548,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Machine' Initialize-Chocolatey @@ -571,7 +572,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at User scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Initialize-Chocolatey @@ -595,7 +596,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Process scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Process' Initialize-Chocolatey @@ -619,7 +620,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope and same at User scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'Machine' Add-ChocolateyInstall $installDir 'User' @@ -644,7 +645,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope and different at User scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'User' @@ -669,7 +670,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at Machine scope and different at Process scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall 'X:\nonexistent' 'Machine' Add-ChocolateyInstall $installDir 'Process' @@ -694,7 +695,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with `$Env:ChocolateyInstall set at User scope and different at Process scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall 'X:\nonexistent' 'User' Add-ChocolateyInstall $installDir 'Process' @@ -719,7 +720,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with bin directory not on PATH" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" @@ -744,7 +745,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with bin directory on PATH at Machine scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'Machine' @@ -770,7 +771,7 @@ Describe "Initialize-Chocolatey" { Context "When installing as simulated standard user with bin directory on PATH at User scope" { Setup-ChocolateyInstallationPackage -SimulateStandardUser - Execute-WithEnvironmentBackup { + Execute-WithEnvironmentProtection { Setup-ChocolateyInstall $installDir 'User' Remove-DirectoryFromPath "$installDir\bin" Add-DirectoryToPath "$installDir\bin" 'User' diff --git a/tests/unit/Update-SessionEnvironment.tests.ps1 b/tests/unit/Update-SessionEnvironment.tests.ps1 index e10999f..52219ed 100644 --- a/tests/unit/Update-SessionEnvironment.tests.ps1 +++ b/tests/unit/Update-SessionEnvironment.tests.ps1 @@ -5,47 +5,26 @@ $base = Split-Path -parent (Split-Path -Parent $here) . "$base\src\helpers\functions\Update-SessionEnvironment.ps1" Describe "Update-SessionEnvironment" { - Add-Type -language CSharp @' -public class FakeRegKey -{ - public string PSPath; - public string[] Property; - - public FakeRegKey(string PSPath,string[] Property){ - this.PSPath = PSPath; - this.Property = Property; - } -} -'@ Context "under normal circumstances" { - $originalEnv = @{} + $mkey = 'choc' + [Guid]::NewGuid().ToString('n') $mvalue = [Guid]::NewGuid().ToString('n') $ukey = 'choc' + [Guid]::NewGuid().ToString('n') $uvalue = [Guid]::NewGuid().ToString('n') - gci env: | % {$originalEnv.($_.Name)=$_.Value} - try { - #Mock Get-Item {write-host "path: $path"} - Mock Get-Item { - if($_ -eq 'HKCU:\Environment'){ - return New-Object FakeRegKey("user",@($ukey,"Path")) - } - if($_ -eq 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'){ - return New-Object FakeRegKey("machine",@($ukey,$mkey,"Path")) - } - } - #Mock Get-Item {New-Object FakeRegKey("path2",@($ukey,$mkey,"Path"))} -ParameterFilter {$path -eq 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'} - Mock Get-ItemProperty {@{$ukey="someval"}} -ParameterFilter {$path -eq "machine" -and $Name -eq $ukey} - Mock Get-ItemProperty {@{Path="someval1"}} -ParameterFilter {$path -eq "user" -and $Name -eq "Path"} - Mock Get-ItemProperty {@{Path="someval2"}} -ParameterFilter {$path -eq "machine" -and $Name -eq "Path"} - Mock Get-ItemProperty {@{$ukey=$uvalue}} -ParameterFilter {$path -eq "user" -and $Name -eq $ukey} - Mock Get-ItemProperty {@{$mkey=$mvalue}} -ParameterFilter {$path -eq "machine" -and $Name -eq $mkey} - Mock Get-EnvironmentVar {"someval2"} -ParameterFilter {$key -eq "PATH" -and $scope -eq "Machine"} - Mock Get-EnvironmentVar {"someval1"} -ParameterFilter {$key -eq "PATH" -and $scope -eq "User"} - Remove-Item "Env:$($ukey)" -ErrorAction SilentlyContinue - Remove-Item "Env:$($mkey)" -ErrorAction SilentlyContinue - Remove-Item "Env:$('Path')" -ErrorAction SilentlyContinue + + Execute-WithEnvironmentProtection { + + Get-EnvironmentVariableNames Machine | % { Set-EnvironmentVariable $_ $null Machine } + Get-EnvironmentVariableNames User | % { Set-EnvironmentVariable $_ $null User } + Set-EnvironmentVariable $mkey $mvalue Machine + Set-EnvironmentVariable $ukey 'someval' Machine + Set-EnvironmentVariable 'PATH' 'someval2' Machine + Set-EnvironmentVariable $ukey $uvalue User + Set-EnvironmentVariable 'PATH' 'someval1' User + Set-EnvironmentVariable $mkey $null Process + Set-EnvironmentVariable $ukey $null Process + Set-EnvironmentVariable 'PATH' $null Process Update-SessionEnvironment @@ -54,17 +33,14 @@ public class FakeRegKey $plocalSession = Get-ChildItem "Env:$('Path')" It "should properly refresh MACHINE variables set outside this session" { - $mlocalSession.Value | should Be $mvalue + $mlocalSession.Value | should Be $mvalue } It "should properly refresh USER variables set outside this session overriding Machine vars with same key" { - $ulocalSession.Value | should Be $uvalue + $ulocalSession.Value | should Be $uvalue } - It "should properly refresh the PATH variable aconcatenating MACHINE and USER" { - $plocalSession.Value | should Be 'someval2;someval1' + It "should properly refresh the PATH variable concatenating MACHINE and USER" { + $plocalSession.Value | should Be 'someval2;someval1' } } - finally { - $originalEnv.keys | % { Set-Item "Env:$($_)" -Value $originalEnv.$($_) } - } } }