diff --git a/functional-tests/CloudbaseInit.Tests.ps1 b/functional-tests/CloudbaseInit.Tests.ps1 new file mode 100644 index 0000000..43aba57 --- /dev/null +++ b/functional-tests/CloudbaseInit.Tests.ps1 @@ -0,0 +1,161 @@ +$global:here = Split-Path -Parent $MyInvocation.MyCommand.Path +$ErrorActionPreference = "Stop" + +Import-Module "${here}/ini.psm1" + +$global:metadataService = "empty" +$cloudbaseInitRegistryPath = "HKLM:\SOFTWARE\Cloudbase Solutions\Cloudbase-Init" + + +function before.cloudbaseinit.plugins.common.mtu.MTUPlugin { + # NOOP +} +function after.cloudbaseinit.plugins.common.mtu.MTUPlugin { + # NOOP +} + + +function before.cloudbaseinit.plugins.windows.ntpclient.NTPClientPlugin { + It "w32time service should exist" { + { Get-Service "w32time" -ErrorAction Stop } | Should -Not -Throw + } +} +function after.cloudbaseinit.plugins.windows.ntpclient.NTPClientPlugin { + It "w32time service should be running" { + $status = (Get-Service "w32time" -ErrorAction Stop).Status + $status | Should -Be "Running" + } +} + +function before.cloudbaseinit.plugins.windows.sanpolicy.SANPolicyPlugin { + It "Get-StorageSetting should return" { + { (Get-StorageSetting).NewDiskPolicy } | Should -Not -Throw + } +} + +function after.cloudbaseinit.plugins.windows.sanpolicy.SANPolicyPlugin { + It "Get-StorageSetting should be OnlineAll" { + $sanPolicy = (Get-StorageSetting).NewDiskPolicy + $sanPolicy | Should -Be "OnlineAll" + } +} + +function before.cloudbaseinit.plugins.windows.displayidletimeout.DisplayIdleTimeoutConfigPlugin { + It "powercfg returns SUB_VIDEO VIDEOIDLE" { + $powerCfgOut = $(cmd /c 'powercfg /query SCHEME_CURRENT SUB_VIDEO VIDEOIDLE') ` + | Select-String -Pattern "Current AC Power Setting Index:" + $powerCfgOut.Matches.Count | Should -Be 1 + } +} +function after.cloudbaseinit.plugins.windows.displayidletimeout.DisplayIdleTimeoutConfigPlugin { + It "powercfg returns SUB_VIDEO VIDEOIDLE 0" { + $powerCfgOut = $(cmd /c 'powercfg /query SCHEME_CURRENT SUB_VIDEO VIDEOIDLE') ` + | Select-String -Pattern "Current AC Power Setting Index: 0x00000000" + $powerCfgOut.Matches.Count | Should -Be 1 + } +} + +function before.cloudbaseinit.plugins.windows.bootconfig.BootStatusPolicyPlugin { + It "bcdedit returns base identifier" { + $bcdOut = $(cmd /c 'bcdedit /enum {current}') ` + | Select-String -Pattern "identifier" + $bcdOut.Matches.Count | Should -Be 1 + } + +} +function after.cloudbaseinit.plugins.windows.bootconfig.BootStatusPolicyPlugin { + It "bcdedit returns ignoreallfailures" { + $bcdOut = $(cmd /c 'bcdedit /enum {current}') ` + | Select-String -Pattern "ignoreallfailures" + $bcdOut.Matches.Count | Should -Be 1 + } +} + +function before.cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin { + +} +function after.cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin { + +} +function before.cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin { + +} +function after.cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin { + +} +function before.cloudbaseinit.plugins.common.userdata.UserDataPlugin { + +} +function after.cloudbaseinit.plugins.common.userdata.UserDataPlugin { + +} +function before.cloudbaseinit.plugins.windows.winrmlistener.ConfigWinRMListenerPlugin { + +} +function after.cloudbaseinit.plugins.windows.winrmlistener.ConfigWinRMListenerPlugin { + +} +function before.cloudbaseinit.plugins.common.localscripts.LocalScriptsPlugin { + +} +function after.cloudbaseinit.plugins.common.localscripts.LocalScriptsPlugin { + +} +function before.cloudbaseinit.plugins.common.trim.TrimConfigPlugin { + +} +function after.cloudbaseinit.plugins.common.trim.TrimConfigPlugin { + +} + +BeforeDiscovery { + $global:metadataService | Should -Be "empty" + $metadataServiceConfigFile = Resolve-Path "$here/../$metadataService/cloudbase-init.conf" + $pluginList = Get-IniFileValue -Path $metadataServiceConfigFile -Section "DEFAULT" ` + -Key "plugins" ` + -Default "" + $pluginList = $pluginList.Split(",") +} + +Describe "TestVerifyBeforeAllPlugins" { + foreach ($plugin in $pluginList) { + if (!$plugin) { + return + } + Context "Verify state for plugin ${plugin}"{ + & "before.${plugin}" + + It "Checks for Registry Key state ${plugin}" { + $propertyName = "TEST" + $propertyValue = "NOT_INITIALIZED" + try { + $propertyValue = Get-ItemProperty -Path $cloudbaseInitRegistryPath -Name $propertyNameopertyName -ErrorAction "Stop" + } catch { + $propertyValue = "NOT_EXISTENT" + } + $propertyValue | Should -BeExactly "NOT_EXISTENT" + } + } + } +} + +Describe "TestVerifyAfterAllPlugins" { + $pluginList | ForEach-Object { + $plugin = $_ + if (!$plugin) { + return + } + & "after.${plugin}" + + It "Checks for Registry Key state ${plugin}" { + $propertyName = "TEST" + $propertyValue = "NOT_INITIALIZED" + try { + $propertyValue = Get-ItemProperty -Path $cloudbaseInitRegistryPath -Name $propertyNameopertyName -ErrorAction "Stop" + } catch { + $propertyValue = "NOT_EXISTENT" + } + $propertyValue | Should -BeExactly "NOT_EXISTENT" + } + } +} diff --git a/functional-tests/ini.psm1 b/functional-tests/ini.psm1 new file mode 100644 index 0000000..46de2b1 --- /dev/null +++ b/functional-tests/ini.psm1 @@ -0,0 +1,163 @@ +<# +Copyright 2014 Cloudbase Solutions Srl + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +#> + +$Source = @" +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace PSCloudbase +{ + public sealed class Win32IniApi + { + [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] + public static extern uint GetPrivateProfileString( + string lpAppName, + string lpKeyName, + string lpDefault, + StringBuilder lpReturnedString, + uint nSize, + string lpFileName); + + [DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WritePrivateProfileString( + string lpAppName, + string lpKeyName, + StringBuilder lpString, // Don't use string, as Powershell replaces $null with an empty string + string lpFileName); + + [DllImport("Kernel32.dll")] + public static extern uint GetLastError(); + } +} +"@ + +Add-Type -TypeDefinition $Source -Language CSharp + +function Get-IniFileValue +{ <# + .SYNOPSIS + This function returns the value of the key specified as a parameter. + #> + [CmdletBinding()] + param + ( + [parameter(Mandatory=$true, ValueFromPipeline=$true)] + [string]$Key, + + [parameter()] + [string]$Section = "DEFAULT", + + [parameter()] + [string]$Default = $null, + + [parameter(Mandatory=$true)] + [string]$Path, + + [parameter()] + [switch]$AsBoolean + ) + process + { + $Path = Resolve-Path $Path + $sb = New-Object -TypeName "System.Text.StringBuilder" -ArgumentList 1000 + $retVal = [PSCloudbase.Win32IniApi]::GetPrivateProfileString($Section, $Key, $Default, $sb, $sb.Capacity, $Path) + if (!$retVal) + { + $lastErr = [PSCloudbase.Win32IniApi]::GetLastError() + if ($lastErr -ne 2) + { + throw "Cannot get value from ini file: " + [PSCloudbase.Win32IniApi]::GetLastError() + } + elseif (!(Test-Path $Path)) + { + throw "Ini file '$Path' does not exist" + } + } + + $value = $sb.ToString() + if($AsBoolean) + { + return [System.Convert]::ToBoolean($value) + } + else + { + return $value + } + } +} + +function Set-IniFileValue +{ <# + .SYNOPSIS + This function sets a value to the key within the file specified as a parameter. + #> + [CmdletBinding()] + param + ( + [parameter(Mandatory=$true, ValueFromPipeline=$true)] + [string]$Key, + + [parameter()] + [string]$Section = "DEFAULT", + + [parameter(Mandatory=$true)] + [string]$Value, + + [parameter(Mandatory=$true)] + [string]$Path + ) + process + { + $Path = Resolve-Path $Path + $retVal = [PSCloudbase.Win32IniApi]::WritePrivateProfileString($Section, $Key, $Value, $Path) + if (!$retVal -and [PSCloudbase.Win32IniApi]::GetLastError()) + { + throw "Cannot set value in ini file: " + [PSCloudbase.Win32IniApi]::GetLastError() + } + } +} + +function Remove-IniFileValue +{ <# + .SYNOPSIS + This function removes a value from the ini file specified as a parameter. + #> + [CmdletBinding()] + param + ( + [parameter(Mandatory=$true, ValueFromPipeline=$true)] + [string]$Key, + + [parameter()] + [string]$Section = "DEFAULT", + + [parameter(Mandatory=$true)] + [string]$Path + ) + process + { + $Path = Resolve-Path $Path + $retVal = [PSCloudbase.Win32IniApi]::WritePrivateProfileString($Section, $Key, $null, $Path) + if (!$retVal -and [PSCloudbase.Win32IniApi]::GetLastError()) + { + throw "Cannot remove value from ini file: " + [PSCloudbase.Win32IniApi]::GetLastError() + } + } +} + +Export-ModuleMember Get-IniFileValue, Set-IniFileValue, Remove-IniFileValue