diff --git a/DSCResources/MSFT_xCluster/MSFT_xCluster.psm1 b/DSCResources/MSFT_xCluster/MSFT_xCluster.psm1 index e31969b..501e7b6 100644 --- a/DSCResources/MSFT_xCluster/MSFT_xCluster.psm1 +++ b/DSCResources/MSFT_xCluster/MSFT_xCluster.psm1 @@ -36,7 +36,7 @@ function Get-TargetResource throw "Can't find the cluster $Name" } - $address = Get-ClusterGroup -Cluster $Name | Get-ClusterResource -Name 'Cluster IP Address' | Get-ClusterParameter 'Address' + $address = Get-ClusterGroup -Cluster $Name -Name "Cluster IP Address" | Get-ClusterParameter "Address" } finally { @@ -106,6 +106,8 @@ function Set-TargetResource New-Cluster -Name $Name -Node $env:COMPUTERNAME -StaticAddress $StaticIPAddress -NoStorage -Force + While (!(Get-Cluster)){Start-Sleep 5} + Write-Verbose -Message "Created Cluster $Name" } else @@ -119,7 +121,7 @@ function Set-TargetResource { if ($node.Name -eq $env:COMPUTERNAME) { - if ($node.State -eq 'Down') + if ($node.State -eq "Down") { Write-Verbose -Message "node $env:COMPUTERNAME was down, need remove it from the list." @@ -203,7 +205,7 @@ function Test-TargetResource { if ($node.Name -eq $env:COMPUTERNAME) { - if ($node.State -eq 'Up') + if ($node.State -eq "Up") { $bRet = $true } diff --git a/DSCResources/MSFT_xClusterQuorum/MSFT_xClusterQuorum.psm1 b/DSCResources/MSFT_xClusterQuorum/MSFT_xClusterQuorum.psm1 new file mode 100644 index 0000000..783b25c --- /dev/null +++ b/DSCResources/MSFT_xClusterQuorum/MSFT_xClusterQuorum.psm1 @@ -0,0 +1,145 @@ + +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [String] $IsSingleInstance, + + [Parameter(Mandatory = $false)] + [ValidateSet('NodeMajority', 'NodeAndDiskMajority', 'NodeAndFileShareMajority', 'DiskOnly')] + [String] $Type, + + [Parameter(Mandatory = $false)] + [String] $Resource + ) + + $ClusterQuorum = Get-ClusterQuorum + + switch ($ClusterQuorum.QuorumType) + { + # WS2016 only + 'Majority' { + if ($ClusterQuorum.QuorumResource -eq $null) + { + $ClusterQuorumType = 'NodeMajority' + } + elseif ($ClusterQuorum.QuorumResource.ResourceType.DisplayName -eq 'Physical Disk') + { + $ClusterQuorumType = 'NodeAndDiskMajority' + } + elseif ($ClusterQuorum.QuorumResource.ResourceType.DisplayName -eq 'File Share Witness') + { + $ClusterQuorumType = 'NodeAndFileShareMajority' + } + else + { + throw "Unknown quorum resource: $($ClusterQuorum.QuorumResource)" + } + } + + # WS2012R2 only + 'NodeMajority' { + $ClusterQuorumType = 'NodeMajority' + } + 'NodeAndDiskMajority' { + $ClusterQuorumType = 'NodeAndDiskMajority' + } + 'NodeAndFileShareMajority' { + $ClusterQuorumType = 'NodeAndFileShareMajority' + } + + # All + 'DiskOnly' { + $ClusterQuorumType = 'DiskOnly' + } + + # Default + default { + throw "Unknown quorum type: $($ClusterQuorum.QuorumType)" + } + } + + if ($ClusterQuorumType -eq 'NodeAndFileShareMajority') + { + $ClusterQuorumResource = $ClusterQuorum.QuorumResource | Get-ClusterParameter -Name SharePath | Select-Object -ExpandProperty Value + } + else + { + $ClusterQuorumResource = [String] $ClusterQuorum.QuorumResource.Name + } + + @{ + IsSingleInstance = $IsSingleInstance + Type = $ClusterQuorumType + Resource = $ClusterQuorumResource + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [String] $IsSingleInstance, + + [Parameter(Mandatory = $false)] + [ValidateSet('NodeMajority', 'NodeAndDiskMajority', 'NodeAndFileShareMajority', 'DiskOnly')] + [String] $Type, + + [Parameter(Mandatory = $false)] + [String] $Resource + ) + + switch ($Type) + { + 'NodeMajority' { + Set-ClusterQuorum -NoWitness + } + + 'NodeAndDiskMajority' { + Set-ClusterQuorum -DiskWitness $Resource + } + + 'NodeAndFileShareMajority' { + Set-ClusterQuorum -FileShareWitness $Resource + } + + 'DiskOnly' { + Set-ClusterQuorum -DiskOnly $Resource + } + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [String] $IsSingleInstance, + + [Parameter(Mandatory = $false)] + [ValidateSet('NodeMajority', 'NodeAndDiskMajority', 'NodeAndFileShareMajority', 'DiskOnly')] + [String] $Type, + + [Parameter(Mandatory = $false)] + [String] $Resource + ) + + $CurrentQuorum = Get-TargetResource -IsSingleInstance $IsSingleInstance + + return ( + ($CurrentQuorum.Type -eq $Type) -and + ($CurrentQuorum.Resource -eq $Resource) + ) +} + +Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_xClusterQuorum/MSFT_xClusterQuorum.schema.mof b/DSCResources/MSFT_xClusterQuorum/MSFT_xClusterQuorum.schema.mof new file mode 100644 index 0000000..ef0851d --- /dev/null +++ b/DSCResources/MSFT_xClusterQuorum/MSFT_xClusterQuorum.schema.mof @@ -0,0 +1,9 @@ +[ClassVersion("1.0.0.0"), FriendlyName("xClusterQuorum")] +class MSFT_xClusterQuorum : OMI_BaseResource +{ + [Key, ValueMap{"Yes"}, Values{"Yes"}] string IsSingleInstance; + + [Write, ValueMap{"NodeMajority", "NodeAndDiskMajority", "NodeAndFileShareMajority", "DiskOnly"}, Values{"NodeMajority", "NodeAndDiskMajority", "NodeAndFileShareMajority", "DiskOnly"}] string Type; + + [Write] String Resource; +}; diff --git a/README.md b/README.md index 881260e..6e9bec1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,9 @@ -[![Build status](https://ci.appveyor.com/api/projects/status/6a59vfritv4kbc7d/branch/master?svg=true)](https://ci.appveyor.com/project/PowerShell/xfailovercluster/branch/master) +[![Build status](https://ci.appveyor.com/api/projects/status/6a59vfritv4kbc7d/branch/master?svg=true)](https://ci.appveyor.com/project/PowerShell/xfailovercluster/branch/master) # xFailOverCluster The **xFailOverCluster** DSC modules contains **xCluster** and **xWaitForCluster** resources for creating and configuring failover clusters. -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - ## Contributing Please check out common DSC Resources [contributing guidelines](https://github.com/PowerShell/DscResource.Kit/blob/master/CONTRIBUTING.md). @@ -22,13 +19,11 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **StaticIPAddress**: Static IP Address of the cluster * **DomainAdministratorCredential**: Credential used to create the cluster -### xClusterNetwork (Unreleased) +### xClusterQuorum (Unreleased) -* **Address**: The network address (e.g. 192.168.0.0) -* **AddressMask**: The network mask (e.g. 255.255.255.0) -* **Name**: The network label or name -* **Role**: Network role: *0 = None, 1 = Cluster Only, 3 = Clsuter and Client* -* **Metric**: The internal metric for the networks +* **IsSingleInstance** Always set to `Yes` to prevent multiple quorum settings per cluster. +* **Type** Quorum type to use: *NodeMajority*, *NodeAndDiskMajority*, *NodeAndFileShareMajority*, *DiskOnly* +* **Resource** The name of the disk or file share resource to use as witness. Is optional with *NodeMajority* type. ### xClusterDisk (Unreleased) @@ -36,14 +31,6 @@ Please check out common DSC Resources [contributing guidelines](https://github.c * **Ensure**: Define if the cluster disk should be added (Present) or removed (Absent) * **Label**: The disk label inside the Failover Cluster -### xClusterPreferredOwner (Unreleased) -For more information about cluster preferred owners please see: http://support.microsoft.com/kb/299631 -* **ClusterGroup**: Cluster group name -* **ClusterName**: Cluster name -* **Nodes**: Selected cluster nodes. -* **ClusterResources**: Selected cluster resources -* **Ensure**: Whether an owner should be present or removed - ### xWaitForCluster * **Name**: Name of the cluster to wait for @@ -54,21 +41,14 @@ For more information about cluster preferred owners please see: http://support.m ## Versions ### Unreleased -* Converted appveyor.yml to install Pester from PSGallery instead of from Chocolatey. - -### 1.4.0.0 -* xClusterDisk: Fixed Test-TargetResource logic - -### 1.3.0.0 -* Added xClusterNetwork resource +* Added xClusterQuorum resource with options *NodeMajority*, *NodeAndDiskMajority*, *NodeAndFileShareMajority*, *DiskOnly* +* Currently does not implement cloudwitness for Windows 2016. * Added xClusterDisk resource -* Added xClusterPreferredOwner resource -* Resolved issue: Failing Get-TargetResource in xCluster ### 1.2.0.0 -* xCluster: Added -NoStorage switch to add-clusternode. This prevents disks from being automatically added when joining a node to a cluster +* xCluster: Added -NoStorage switch to add-clusterNode. This prevents disks from being automatically added when joining a node to a cluster ### 1.1.0.0 diff --git a/Tests/MSFT_xClusterQuorum.Tests.ps1 b/Tests/MSFT_xClusterQuorum.Tests.ps1 new file mode 100644 index 0000000..00ed8da --- /dev/null +++ b/Tests/MSFT_xClusterQuorum.Tests.ps1 @@ -0,0 +1,595 @@ +[CmdletBinding()] +param +( +) + +if (!$PSScriptRoot) +{ + $PSScriptRoot = [System.IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Path) +} + +$RootPath = (Resolve-Path -Path "$PSScriptRoot\..").Path +$ModuleName = 'MSFT_xClusterQuorum' + +try +{ + if (-not (Get-WindowsFeature -Name RSAT-Clustering-PowerShell -ErrorAction Stop).Installed) + { + Add-WindowsFeature -Name RSAT-Clustering-PowerShell -ErrorAction Stop + } +} +catch +{ + Write-Warning $_ +} + +Import-Module (Join-Path -Path $RootPath -ChildPath "DSCResources\$ModuleName\$ModuleName.psm1") -Force + + +## General test for the xClusterQuorum resource + +Describe 'xClusterQuorum' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'NodeAndDiskMajority' + Resource = 'Witness' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumResource = 'Witness' + QuorumType = 'NodeAndDiskMajority' + } + } + + Mock -CommandName 'Set-ClusterQuorum' -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns a [System.Collection.Hashtable] type' { + + $Result = Get-TargetResource @TestParameter + + $Result -is [System.Collections.Hashtable] | Should Be $true + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Returns nothing' { + + $Result = Set-TargetResource @TestParameter + + $Result -eq $null | Should Be $true + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Returns a [System.Boolean] type' { + + $Result = Test-TargetResource @TestParameter + + $Result -is [System.Boolean] | Should Be $true + } + } + } +} + + +## Test NodeMajority quorum type + +Describe 'xClusterQuorum (NodeMajority / WS2012R2)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'NodeMajority' + Resource = '' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'NodeMajority' + QuorumResource = $null + } + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $NoWitness -eq $true } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $NoWitness -eq $true } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} + +Describe 'xClusterQuorum (NodeMajority / WS2016Prev)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'NodeMajority' + Resource = '' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'Majority' + QuorumResource = $null + } + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $NoWitness -eq $true } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $NoWitness -eq $true } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} + + +## Test NodeAndDiskMajority quorum type + +Describe 'xClusterQuorum (NodeAndDiskMajority / WS2012R2)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'NodeAndDiskMajority' + Resource = 'Witness' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'NodeAndDiskMajority' + QuorumResource = [PSCustomObject] @{ + Name = 'Witness' + OwnerGroup = 'Cluster Group' + ResourceType = [PSCustomObject] @{ + DisplayName = 'Physical Disk' + } + } + } + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskWitness -eq 'Witness' } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskWitness -eq 'Witness' } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} + +Describe 'xClusterQuorum (NodeAndDiskMajority / WS2016Prev)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'NodeAndDiskMajority' + Resource = 'Witness' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'Majority' + QuorumResource = [PSCustomObject] @{ + Name = 'Witness' + OwnerGroup = 'Cluster Group' + ResourceType = [PSCustomObject] @{ + DisplayName = 'Physical Disk' + } + } + } + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskWitness -eq 'Witness' } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskWitness -eq 'Witness' } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} + + +## Test NodeAndFileShareMajority quorum type + +Describe 'xClusterQuorum (NodeAndFileShareMajority / WS2012R2)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'NodeAndFileShareMajority' + Resource = '\\FILE01\CLUSTER01' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'NodeAndFileShareMajority' + QuorumResource = [PSCustomObject] @{ + Name = 'File Share Witness' + OwnerGroup = 'Cluster Group' + ResourceType = [PSCustomObject] @{ + DisplayName = 'File Share Witness' + } + } + } + } + + Mock -CommandName 'Get-ClusterParameter' -ParameterFilter { $Name -eq 'SharePath' } -MockWith { + @( + [PSCustomObject] @{ + ClusterObject = 'File Share Witness' + Name = 'SharePath' + IsReadOnly = 'False' + ParameterType = 'String' + Value = '\\FILE01\CLUSTER01' + } + ) + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $FileShareWitness -eq '\\FILE01\CLUSTER01' } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $FileShareWitness -eq '\\FILE01\CLUSTER01' } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} + +Describe 'xClusterQuorum (NodeAndFileShareMajority / WS2016Prev)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'NodeAndFileShareMajority' + Resource = '\\FILE01\CLUSTER01' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'Majority' + QuorumResource = [PSCustomObject] @{ + Name = 'File Share Witness' + OwnerGroup = 'Cluster Group' + ResourceType = [PSCustomObject] @{ + DisplayName = 'File Share Witness' + } + } + } + } + + Mock -CommandName 'Get-ClusterParameter' -ParameterFilter { $Name -eq 'SharePath' } -MockWith { + @( + [PSCustomObject] @{ + ClusterObject = 'File Share Witness' + Name = 'SharePath' + IsReadOnly = 'False' + ParameterType = 'String' + Value = '\\FILE01\CLUSTER01' + } + ) + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $FileShareWitness -eq '\\FILE01\CLUSTER01' } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $FileShareWitness -eq '\\FILE01\CLUSTER01' } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} + + +## Test DiskOnly quorum type + +Describe 'xClusterQuorum (NodeAndDiskMajority / WS2012R2)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'DiskOnly' + Resource = 'Witness' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'DiskOnly' + QuorumResource = [PSCustomObject] @{ + Name = 'Witness' + OwnerGroup = 'Cluster Group' + ResourceType = [PSCustomObject] @{ + DisplayName = 'Physical Disk' + } + } + } + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskOnly -eq 'Witness' } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskOnly -eq 'Witness' } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} + +Describe 'xClusterQuorum (NodeAndDiskMajority / WS2016Prev)' { + + InModuleScope $ModuleName { + + $TestParameter = @{ + IsSingleInstance = 'Yes' + Type = 'DiskOnly' + Resource = 'Witness' + } + + Mock -CommandName 'Get-ClusterQuorum' -MockWith { + [PSCustomObject] @{ + Cluster = 'CLUSTER01' + QuorumType = 'DiskOnly' + QuorumResource = [PSCustomObject] @{ + Name = 'Witness' + OwnerGroup = 'Cluster Group' + ResourceType = [PSCustomObject] @{ + DisplayName = 'Physical Disk' + } + } + } + } + + Mock -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskOnly -eq 'Witness' } -MockWith { + } + + Context 'Validate Get-TargetResource method' { + + It 'Returns current configuration' { + + $Result = Get-TargetResource @TestParameter + + $Result.IsSingleInstance | Should Be $TestParameter.IsSingleInstance + $Result.Type | Should Be $TestParameter.Type + $Result.Resource | Should Be $TestParameter.Resource + } + } + + Context 'Validate Set-TargetResource method' { + + It 'Set the new configuration' { + + $Result = Set-TargetResource @TestParameter + + Assert-MockCalled -CommandName 'Set-ClusterQuorum' -ParameterFilter { $DiskOnly -eq 'Witness' } -Times 1 + } + } + + Context 'Validate Test-TargetResource method' { + + It 'Check the current configuration' { + + $Result = Test-TargetResource @TestParameter + + $Result | Should Be $true + } + } + } +} +