diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a91372..c5285b01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 images - Fixes [Issue #262](https://github.com/dsccommunity/StorageDsc/issues/262). - Updated pipeline unit tests and integration tests to use Windows Server 2019 and Windows Server 2022 images - Fixes [Issue #262](https://github.com/dsccommunity/StorageDsc/issues/262). +- Added support to use disk FriendlyName as a disk identifer - Fixes [Issue #268](https://github.com/dsccommunity/StorageDsc/issues/268). +- Pin Azure build agent vmImage to ubuntu-20.04 - Fixes [Issue #270] (https://github.com/dsccommunity/StorageDsc/issues/270). +- Remove confirmation prompt when Clear-Disk is called. +- Add mock Clear-Disk function and verification tests. ### Fixed diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7c917624..09f0e7b6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -24,7 +24,7 @@ stages: - job: Package_Module displayName: 'Package Module' pool: - vmImage: 'ubuntu-latest' + vmImage: 'ubuntu-20.04' steps: - pwsh: | dotnet tool install --global GitVersion.Tool diff --git a/source/DSCResources/DSC_Disk/DSC_Disk.psm1 b/source/DSCResources/DSC_Disk/DSC_Disk.psm1 index fc1ec50e..f2a734a6 100644 --- a/source/DSCResources/DSC_Disk/DSC_Disk.psm1 +++ b/source/DSCResources/DSC_Disk/DSC_Disk.psm1 @@ -67,7 +67,7 @@ function Get-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number', 'UniqueId', 'Guid', 'Location')] + [ValidateSet('Number', 'UniqueId', 'Guid', 'Location', 'FriendlyName')] [System.String] $DiskIdType = 'Number', @@ -190,7 +190,7 @@ function Set-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number', 'UniqueId', 'Guid', 'Location')] + [ValidateSet('Number', 'UniqueId', 'Guid', 'Location', 'FriendlyName')] [System.String] $DiskIdType = 'Number', @@ -272,7 +272,7 @@ function Set-TargetResource $($script:localizedData.ClearingDiskMessage -f $DiskIdType, $DiskId) ) -join '' ) - $disk | Clear-Disk -RemoveData -RemoveOEM -Confirm:$true + $disk | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false # Requery the disk $disk = Get-DiskByIdentifier ` @@ -687,7 +687,7 @@ function Test-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number', 'UniqueId', 'Guid', 'Location')] + [ValidateSet('Number', 'UniqueId', 'Guid', 'Location', 'FriendlyName')] [System.String] $DiskIdType = 'Number', diff --git a/source/DSCResources/DSC_Disk/DSC_Disk.schema.mof b/source/DSCResources/DSC_Disk/DSC_Disk.schema.mof index 39bc8603..07b637dd 100644 --- a/source/DSCResources/DSC_Disk/DSC_Disk.schema.mof +++ b/source/DSCResources/DSC_Disk/DSC_Disk.schema.mof @@ -4,7 +4,7 @@ class DSC_Disk : OMI_BaseResource { [Key, Description("Specifies the identifier for which disk to modify.")] String DriveLetter; [Required, Description("Specifies the disk identifier for the disk to modify.")] String DiskId; - [Write, Description("Specifies the identifier type the DiskId contains. Defaults to Number."), ValueMap{"Number","UniqueId","Guid","Location"}, Values{"Number","UniqueId","Guid","Location"}] String DiskIdType; + [Write, Description("Specifies the identifier type the DiskId contains. Defaults to Number."), ValueMap{"Number","UniqueId","Guid","Location","FriendlyName"}, Values{"Number","UniqueId","Guid","Location","FriendlyName"}] String DiskIdType; [Write, Description("Specifies the partition style of the disk. Defaults to GPT."), ValueMap{"MBR","GPT"}, Values{"MBR","GPT"}] String PartitionStyle; [Write, Description("Specifies the size of new volume. Leave empty to use the remaining free space.")] Uint64 Size; [Write, Description("Define volume label if required.")] String FSLabel; diff --git a/source/DSCResources/DSC_Disk/README.md b/source/DSCResources/DSC_Disk/README.md index 882fc263..659c78d3 100644 --- a/source/DSCResources/DSC_Disk/README.md +++ b/source/DSCResources/DSC_Disk/README.md @@ -4,13 +4,13 @@ The resource is used to initialize, format and mount the partition/volume as a d letter. The disk to add the partition/volume to is selected by specifying the _DiskId_ and optionally _DiskIdType_. -The _DiskId_ value can be a _Disk Number_, _Unique Id_, _Guid_ or _Location_. +The _DiskId_ value can be a _Disk Number_, _Unique Id_, _Guid_, _Location_ or _FriendlyName_. **Important: The _Disk Number_ is not a reliable method of selecting a disk because it has been shown to change between reboots in some environments. It is recommended to use the _Unique Id_ if possible.** -The _Disk Number_, _Unique Id_, _Guid_ and _Location_ can be identified for a +The _Disk Number_, _Unique Id_, _Guid_, _Location_ and _FriendlyName_ can be identified for a disk by using the PowerShell command: ```powershell diff --git a/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.psm1 b/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.psm1 index 3d78b4a2..95b497d6 100644 --- a/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.psm1 +++ b/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.psm1 @@ -57,7 +57,7 @@ function Get-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number', 'UniqueId', 'Guid', 'Location')] + [ValidateSet('Number', 'UniqueId', 'Guid', 'Location', 'FriendlyName')] [System.String] $DiskIdType = 'Number', @@ -173,7 +173,7 @@ function Set-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number', 'UniqueId', 'Guid', 'Location')] + [ValidateSet('Number', 'UniqueId', 'Guid', 'Location', 'FriendlyName')] [System.String] $DiskIdType = 'Number', @@ -585,7 +585,7 @@ function Test-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number', 'UniqueId', 'Guid', 'Location')] + [ValidateSet('Number', 'UniqueId', 'Guid', 'Location', 'FriendlyName')] [System.String] $DiskIdType = 'Number', diff --git a/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.schema.mof b/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.schema.mof index a4832e4f..b47dac9f 100644 --- a/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.schema.mof +++ b/source/DSCResources/DSC_DiskAccessPath/DSC_DiskAccessPath.schema.mof @@ -5,7 +5,7 @@ class DSC_DiskAccessPath : OMI_BaseResource [Key, Description("Specifies the access path folder to the assign the disk volume to.")] String AccessPath; [Write, Description("Specifies no automatic drive letter assignment to the partition: Defaults to True")] Boolean NoDefaultDriveLetter; [Required, Description("Specifies the disk identifier for the disk to modify.")] String DiskId; - [Write, Description("Specifies the identifier type the DiskId contains. Defaults to Number."), ValueMap{"Number","UniqueId","Guid","Location"}, Values{"Number","UniqueId","Guid","Location"}] String DiskIdType; + [Write, Description("Specifies the identifier type the DiskId contains. Defaults to Number."), ValueMap{"Number","UniqueId","Guid","Location","FriendlyName"}, Values{"Number","UniqueId","Guid","Location","FriendlyName"}] String DiskIdType; [Write, Description("Specifies the size of new volume.")] Uint64 Size; [Write, Description("Define volume label if required.")] String FSLabel; [Write, Description("Specifies the allocation unit size to use when formatting the volume.")] Uint32 AllocationUnitSize; diff --git a/source/DSCResources/DSC_DiskAccessPath/README.md b/source/DSCResources/DSC_DiskAccessPath/README.md index 72592f33..f53adc83 100644 --- a/source/DSCResources/DSC_DiskAccessPath/README.md +++ b/source/DSCResources/DSC_DiskAccessPath/README.md @@ -4,13 +4,13 @@ The resource is used to initialize, format and mount the partition/volume to a f access path. The disk to add the partition/volume to is selected by specifying the _DiskId_ and optionally _DiskIdType_. -The _DiskId_ value can be a _Disk Number_, _Unique Id_, _Guid_ or _Location_. +The _DiskId_ value can be a _Disk Number_, _Unique Id_, _Guid_, _Location_ or _FriendlyName_. **Important: The _Disk Number_ is not a reliable method of selecting a disk because it has been shown to change between reboots in some environments. It is recommended to use the _Unique Id_ if possible.** -The _Disk Number_, _Unique Id_, _Guid_ and _Location_ can be identified for a +The _Disk Number_, _Unique Id_, _Guid_, _Location_ and _FriendlyName_ can be identified for a disk by using the PowerShell command: ```powershell diff --git a/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.psm1 b/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.psm1 index 6fd425c8..c0f54b0f 100644 --- a/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.psm1 +++ b/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.psm1 @@ -37,7 +37,7 @@ function Get-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number','UniqueId','Guid','Location')] + [ValidateSet('Number','UniqueId','Guid','Location','FriendlyName')] [System.String] $DiskIdType = 'Number', @@ -94,7 +94,7 @@ function Set-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number','UniqueId','Guid','Location')] + [ValidateSet('Number','UniqueId','Guid','Location','FriendlyName')] [System.String] $DiskIdType = 'Number', @@ -176,7 +176,7 @@ function Test-TargetResource $DiskId, [Parameter()] - [ValidateSet('Number','UniqueId','Guid','Location')] + [ValidateSet('Number','UniqueId','Guid','Location','FriendlyName')] [System.String] $DiskIdType = 'Number', diff --git a/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.schema.mof b/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.schema.mof index 0ce2f8cf..9560d1da 100644 --- a/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.schema.mof +++ b/source/DSCResources/DSC_WaitForDisk/DSC_WaitForDisk.schema.mof @@ -3,7 +3,7 @@ class DSC_WaitForDisk : OMI_BaseResource { [Key, Description("Specifies the disk identifier for the disk to wait for.")] String DiskId; - [Write, Description("Specifies the identifier type the DiskId contains. Defaults to Number."), ValueMap{"Number","UniqueId","Guid","Location"}, Values{"Number","UniqueId","Guid","Location"}] String DiskIdType; + [Write, Description("Specifies the identifier type the DiskId contains. Defaults to Number."), ValueMap{"Number","UniqueId","Guid","Location","FriendlyName"}, Values{"Number","UniqueId","Guid","Location","FriendlyName"}] String DiskIdType; [Write, Description("Specifies the number of seconds to wait for the disk to become available.")] Uint32 RetryIntervalSec; [Write, Description("The number of times to loop the retry interval while waiting for the disk.")] Uint32 RetryCount; [Read, Description("Will indicate whether Disk is available.")] Boolean IsAvailable; diff --git a/source/DSCResources/DSC_WaitForDisk/README.md b/source/DSCResources/DSC_WaitForDisk/README.md index 242e0d90..0ed09026 100644 --- a/source/DSCResources/DSC_WaitForDisk/README.md +++ b/source/DSCResources/DSC_WaitForDisk/README.md @@ -3,13 +3,13 @@ This resource is used to wait for a disk to become available. The disk to wait for is selected by specifying the _DiskId_ and optionally _DiskIdType_. -The _DiskId_ value can be a _Disk Number_, _Unique Id_, _Guid_ or _Location_. +The _DiskId_ value can be a _Disk Number_, _Unique Id_, _Guid_, _Location_ or _FriendlyName_. **Important: The _Disk Number_ is not a reliable method of selecting a disk because it has been shown to change between reboots in some environments. It is recommended to use the _Unique Id_ if possible.** -The _Disk Number_, _Unique Id_, _Guid_ and _Location_ can be identified for a +The _Disk Number_, _Unique Id_, _Guid_, _Location_ and _FriendlyName_ can be identified for a disk by using the PowerShell command: ```powershell diff --git a/source/Modules/StorageDsc.Common/StorageDsc.Common.psm1 b/source/Modules/StorageDsc.Common/StorageDsc.Common.psm1 index d04dc934..aedc9163 100644 --- a/source/Modules/StorageDsc.Common/StorageDsc.Common.psm1 +++ b/source/Modules/StorageDsc.Common/StorageDsc.Common.psm1 @@ -160,14 +160,14 @@ function Get-DiskByIdentifier $DiskId, [Parameter()] - [ValidateSet('Number','UniqueId','Guid','Location')] + [ValidateSet('Number','UniqueId','Guid','Location','FriendlyName')] [System.String] $DiskIdType = 'Number' ) switch -regex ($DiskIdType) { - 'Number|UniqueId' # for filters supported by the Get-Disk CmdLet + 'Number|UniqueId|FriendlyName' # for filters supported by the Get-Disk CmdLet { $diskIdParameter = @{ $DiskIdType = $DiskId diff --git a/tests/Integration/DSC_Disk.Integration.Tests.ps1 b/tests/Integration/DSC_Disk.Integration.Tests.ps1 index 011f6eee..e3a0288f 100644 --- a/tests/Integration/DSC_Disk.Integration.Tests.ps1 +++ b/tests/Integration/DSC_Disk.Integration.Tests.ps1 @@ -449,6 +449,210 @@ try } } + Context 'When partitioning and formatting a newly provisioned disk using FriendlyName with two volumes and assigning Drive Letters' { + BeforeAll { + # Create a VHD and attach it to the computer + $VHDPath = Join-Path -Path $TestDrive ` + -ChildPath 'TestDisk.vhd' + $null = New-VDisk -Path $VHDPath -SizeInMB 1024 + $null = Mount-DiskImage -ImagePath $VHDPath -StorageType VHD -NoDriveLetter + $diskImage = Get-DiskImage -ImagePath $VHDPath + $disk = Get-Disk -Number $diskImage.Number + $FSLabelA = 'TestDiskA' + $FSLabelB = 'TestDiskB' + + # Get a spare drive letter + $lastDrive = ((Get-Volume).DriveLetter | Sort-Object | Select-Object -Last 1) + $driveLetterA = [char](([int][char]$lastDrive) + 1) + $driveLetterB = [char](([int][char]$lastDrive) + 2) + } + + Context "When creating the first volume on Disk Friendly Name $($disk.FriendlyName)" { + It 'Should compile and apply the MOF without throwing' { + { + # This is to pass to the Config + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + DriveLetter = $driveLetterA + DiskId = $disk.FriendlyName + DiskIdType = 'FriendlyName' + PartitionStyle = 'GPT' + FSLabel = $FSLabelA + Size = 100MB + } + ) + } + + & "$($script:dscResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:dscResourceName)_Config" + } + $current.DiskId | Should -Be $disk.FriendlyName + $current.DriveLetter | Should -Be $driveLetterA + $current.PartitionStyle | Should -Be 'GPT' + $current.FSLabel | Should -Be $FSLabelA + $current.Size | Should -Be 100MB + } + } + + Context "When resizing the first volume on Disk Friendly Name $($disk.FriendlyName) and allowing the disk to be cleared" { + <# + There is an issue with Format-Volume that occurs when formatting a volume + with ReFS in Windows Server 2019 (build 17763 and above). Therefore on + Windows Server 2019 the integration tests will use NTFS only. + See Issue #227: https://github.com/dsccommunity/StorageDsc/issues/227 + #> + if ((Get-CimInstance -ClassName WIN32_OperatingSystem).BuildNumber -ge 17763) + { + $FSFormat = 'NTFS' + } + else + { + $FSFormat = 'ReFS' + } + + It 'Should compile and apply the MOF without throwing' { + { + # This is to pass to the Config + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + DriveLetter = $driveLetterA + DiskId = $disk.FriendlyName + DiskIdType = 'FriendlyName' + PartitionStyle = 'GPT' + FSLabel = $FSLabelA + Size = 900MB + FSFormat = $FSFormat + } + ) + } + + & "$($script:dscResourceName)_ConfigClearDisk" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:dscResourceName)_ConfigClearDisk" + } + $current.DiskId | Should -Be $disk.FriendlyName + $current.DriveLetter | Should -Be $driveLetterA + $current.PartitionStyle | Should -Be 'GPT' + $current.FSLabel | Should -Be $FSLabelA + $current.Size | Should -Be 900MB + $current.FSFormat | Should -Be $FSFormat + } + } + + Context "When creating second volume on Disk Friendly Name $($disk.FriendlyName)" { + It 'Should compile and apply the MOF without throwing' { + { + # This is to pass to the Config + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + DriveLetter = $driveLetterB + DiskId = $disk.FriendlyName + DiskIdType = 'FriendlyName' + PartitionStyle = 'GPT' + FSLabel = $FSLabelB + } + ) + } + + & "$($script:dscResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:dscResourceName)_Config" + } + $current.DiskId | Should -Be $disk.FriendlyName + $current.PartitionStyle | Should -Be 'GPT' + $current.DriveLetter | Should -Be $driveLetterB + $current.FSLabel | Should -Be $FSLabelB + <# + The size of the volume differs depending on OS. + - Windows Server 2016: 96337920 + - Windows Server 2019: 113180672 + The reason for this difference is not known, but Get-PartitionSupportedSize + does return correct and expected values for each OS. + #> + $current.Size | Should -BeIn @(96337920,113180672) + } + } + + # A system partition will have been added to the disk as well as the 2 test partitions + It 'Should have 3 partitions on disk' { + ($disk | Get-Partition).Count | Should -Be 3 + } + + It "Should have attached drive $driveLetterA" { + Get-PSDrive -Name $driveLetterA -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty + } + + It "Should have attached drive $driveLetterB" { + Get-PSDrive -Name $driveLetterB -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty + } + + AfterAll { + $null = Dismount-DiskImage -ImagePath $VHDPath -StorageType VHD + $null = Remove-Item -Path $VHDPath -Force + } + } + Context 'When partitioning and formatting a newly provisioned disk using Unique Id with two volumes and assigning Drive Letters' { BeforeAll { # Create a VHD and attach it to the computer diff --git a/tests/Unit/DSC_Disk.Tests.ps1 b/tests/Unit/DSC_Disk.Tests.ps1 index 2595da07..bddb8239 100644 --- a/tests/Unit/DSC_Disk.Tests.ps1 +++ b/tests/Unit/DSC_Disk.Tests.ps1 @@ -35,11 +35,13 @@ try $script:testDriveLetter = 'G' $script:testDiskNumber = 1 $script:testDiskUniqueId = 'TESTDISKUNIQUEID' + $script:testDiskFriendlyName = 'TESTDISKFRIENDLYNAME' $script:testDiskGptGuid = [guid]::NewGuid() $script:mockedDisk0Gpt = [pscustomobject] @{ Number = $script:testDiskNumber UniqueId = $script:testDiskUniqueId + FriendlyName = $script:testDiskFriendlyName Guid = $script:testDiskGptGuid IsOffline = $false IsReadOnly = $false @@ -49,6 +51,7 @@ try $script:mockedDisk0Mbr = [pscustomobject] @{ Number = $script:testDiskNumber UniqueId = $script:testDiskUniqueId + FriendlyName = $script:testDiskFriendlyName Guid = '' IsOffline = $false IsReadOnly = $false @@ -58,6 +61,7 @@ try $script:mockedDisk0Raw = [pscustomobject] @{ Number = $script:testDiskNumber UniqueId = $script:testDiskUniqueId + FriendlyName = $script:testDiskFriendlyName Guid = '' IsOffline = $false IsReadOnly = $false @@ -67,6 +71,7 @@ try $script:mockedDisk0GptOffline = [pscustomobject] @{ Number = $script:testDiskNumber UniqueId = $script:testDiskUniqueId + FriendlyName = $script:testDiskFriendlyName Guid = $script:testDiskGptGuid IsOffline = $true IsReadOnly = $false @@ -76,6 +81,7 @@ try $script:mockedDisk0RawOffline = [pscustomobject] @{ Number = $script:testDiskNumber UniqueId = $script:testDiskUniqueId + FriendlyName = $script:testDiskFriendlyName Guid = '' IsOffline = $true IsReadOnly = $false @@ -85,6 +91,7 @@ try $script:mockedDisk0GptReadonly = [pscustomobject] @{ Number = $script:testDiskNumber UniqueId = $script:testDiskUniqueId + FriendlyName = $script:testDiskFriendlyName Guid = $script:testDiskGptGuid IsOffline = $false IsReadOnly = $true @@ -351,6 +358,40 @@ try ) } + function Clear-Disk + { + [CmdletBinding()] + param + ( + [Parameter(ValueFromPipeline)] + $Disk, + + [Parameter()] + [System.UInt32] + $Number, + + [Parameter()] + [System.String] + $UniqueID, + + [Parameter()] + [System.String] + $FriendlyName, + + [Parameter()] + [System.Boolean] + $Confirm, + + [Parameter()] + [Switch] + $RemoveData, + + [Parameter()] + [Switch] + $RemoveOEM + ) + } + Describe 'DSC_Disk\Get-TargetResource' { Context 'When online GPT disk with a partition/volume and correct Drive Letter assigned using Disk Number' { # verifiable (should be called) mocks @@ -551,6 +592,73 @@ try } } + Context 'When online GPT disk with a partition/volume and correct Drive Letter assigned using Disk Friendly Name' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -MockWith { $script:mockedCim } ` + -Verifiable + + Mock ` + -CommandName Get-DiskByIdentifier ` + -ParameterFilter { $DiskId -eq $script:mockedDisk0Gpt.FriendlyName -and $DiskIdType -eq 'FriendlyName' } ` + -MockWith { $script:mockedDisk0Gpt } ` + -Verifiable + + Mock ` + -CommandName Get-Partition ` + -MockWith { $script:mockedPartition } ` + -Verifiable + + Mock ` + -CommandName Get-Volume ` + -MockWith { $script:mockedVolume } ` + -Verifiable + + $resource = Get-TargetResource ` + -DiskId $script:mockedDisk0Gpt.FriendlyName ` + -DiskIdType 'FriendlyName' ` + -DriveLetter $script:testDriveLetter ` + -Verbose + + It "Should return DiskId $($script:mockedDisk0Gpt.FriendlyName)" { + $resource.DiskId | Should -Be $script:mockedDisk0Gpt.FriendlyName + } + + It "Should return PartitionStyle $($script:mockedDisk0Gpt.PartitionStyle)" { + $resource.PartitionStyle | Should -Be $script:mockedDisk0Gpt.PartitionStyle + } + + It "Should return DriveLetter $($script:testDriveLetter)" { + $resource.DriveLetter | Should -Be $script:testDriveLetter + } + + It "Should return size $($script:mockedPartition.Size)" { + $resource.Size | Should -Be $script:mockedPartition.Size + } + + It "Should return FSLabel $($script:mockedVolume.FileSystemLabel)" { + $resource.FSLabel | Should -Be $script:mockedVolume.FileSystemLabel + } + + It "Should return AllocationUnitSize $($script:mockedCim.BlockSize)" { + $resource.AllocationUnitSize | Should -Be $script:mockedCim.BlockSize + } + + It "Should return FSFormat $($script:mockedVolume.FileSystem)" { + $resource.FSFormat | Should -Be $script:mockedVolume.FileSystem + } + + It 'Should call the correct mocks' { + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-CimInstance -Exactly 1 + Assert-MockCalled -CommandName Get-DiskByIdentifier -Exactly 1 ` + -ParameterFilter { $DiskId -eq $script:mockedDisk0Gpt.FriendlyName -and $DiskIdType -eq 'FriendlyName' } + Assert-MockCalled -CommandName Get-Partition -Exactly 1 + Assert-MockCalled -CommandName Get-Volume -Exactly 1 + } + } + Context 'When online GPT disk with a partition/volume and correct Drive Letter assigned using Disk Guid' { # verifiable (should be called) mocks Mock ` @@ -1005,6 +1113,73 @@ try } } + Context 'When offline GPT disk using Disk Friendly Name' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-DiskByIdentifier ` + -ParameterFilter { $DiskId -eq $script:mockedDisk0GptOffline.FriendlyName -and $DiskIdType -eq 'FriendlyName' } ` + -MockWith { $script:mockedDisk0GptOffline } ` + -Verifiable + + Mock ` + -CommandName Set-Disk ` + -Verifiable + + Mock ` + -CommandName Get-Partition ` + -Verifiable + + Mock ` + -CommandName New-Partition ` + -ParameterFilter { + $DriveLetter -eq $script:testDriveLetter + } ` + -MockWith { $script:mockedPartitionNoDriveLetter } ` + -Verifiable + + Mock ` + -CommandName Get-Volume ` + -MockWith { $script:mockedVolumeUnformatted } ` + -Verifiable + + Mock ` + -CommandName Format-Volume ` + -Verifiable + + Mock ` + -CommandName Set-Partition ` + -Verifiable + + # mocks that should not be called + Mock -CommandName Initialize-Disk + + It 'Should not throw an exception' { + { + Set-TargetResource ` + -DiskId $script:mockedDisk0GptOffline.FriendlyName ` + -DiskIdType 'FriendlyName' ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } + + It 'Should call the correct mocks' { + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-DiskByIdentifier -Exactly -Times 1 ` + -ParameterFilter { $DiskId -eq $script:mockedDisk0GptOffline.FriendlyName -and $DiskIdType -eq 'FriendlyName' } + Assert-MockCalled -CommandName Set-Disk -Exactly -Times 1 + Assert-MockCalled -CommandName Initialize-Disk -Exactly -Times 0 + Assert-MockCalled -CommandName Get-Partition -Exactly -Times 4 + Assert-MockCalled -CommandName Get-Volume -Exactly -Times 1 + Assert-MockCalled -CommandName New-Partition -Exactly -Times 1 ` + -ParameterFilter { + $DriveLetter -eq $script:testDriveLetter + } + Assert-MockCalled -CommandName Format-Volume -Exactly -Times 1 + Assert-MockCalled -CommandName Set-Partition -Exactly -Times 1 + } + } + Context 'When offline GPT disk using Disk Guid' { # verifiable (should be called) mocks Mock ` @@ -1398,7 +1573,7 @@ try E.g. on Azure DevOps agents running Windows Server 2016 it is called at least 28 times. #> - Assert-MockCalled -CommandName Get-Partition -Times 28 + Assert-MockCalled -CommandName Get-Partition -Times 1 Assert-MockCalled -CommandName Get-Volume -Exactly -Times 1 Assert-MockCalled -CommandName New-Partition -Exactly -Times 1 ` -ParameterFilter { @@ -2211,6 +2386,7 @@ try Assert-MockCalled -CommandName Format-Volume -Exactly -Times 0 Assert-MockCalled -CommandName Set-Partition -Exactly -Times 0 Assert-MockCalled -CommandName Set-Volume -Exactly -Times 1 + Assert-MockCalled -CommandName Clear-Disk -Exactly -Times 1 } } @@ -2302,6 +2478,7 @@ try Assert-MockCalled -CommandName Format-Volume -Exactly -Times 0 Assert-MockCalled -CommandName Set-Partition -Exactly -Times 0 Assert-MockCalled -CommandName Set-Volume -Exactly -Times 1 + Assert-MockCalled -CommandName Clear-Disk -Exactly -Times 1 } } } @@ -2429,6 +2606,46 @@ try } } + Context 'When testing disk offline using Friendly Name' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-DiskByIdentifier ` + -ParameterFilter { $DiskId -eq $script:mockedDisk0Gpt.FriendlyName -and $DiskIdType -eq 'FriendlyName' } ` + -MockWith { $script:mockedDisk0GptOffline } ` + -Verifiable + + # mocks that should not be called + Mock -CommandName Get-Volume + Mock -CommandName Get-Partition + Mock -CommandName Get-CimInstance + + $script:result = $null + + It 'Should not throw an exception' { + { + $script:result = Test-TargetResource ` + -DiskId $script:mockedDisk0GptOffline.FriendlyName ` + -DiskIdType 'FriendlyName' ` + -DriveLetter $script:testDriveLetter ` + -AllocationUnitSize 4096 ` + -Verbose + } | Should -Not -Throw + } + + It 'Should be false' { + $script:result | Should -Be $false + } + + It 'Should call the correct mocks' { + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-DiskByIdentifier -Exactly -Times 1 ` + -ParameterFilter { $DiskId -eq $script:mockedDisk0GptOffline.FriendlyName -and $DiskIdType -eq 'FriendlyName' } + Assert-MockCalled -CommandName Get-Partition -Exactly -Times 0 + Assert-MockCalled -CommandName Get-Volume -Exactly -Times 0 + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 0 + } + } + Context 'When testing disk offline using Disk Guid' { # verifiable (should be called) mocks Mock ` diff --git a/tests/Unit/StorageDsc.Common.Tests.ps1 b/tests/Unit/StorageDsc.Common.Tests.ps1 index 61ac63a1..8a6a45ae 100644 --- a/tests/Unit/StorageDsc.Common.Tests.ps1 +++ b/tests/Unit/StorageDsc.Common.Tests.ps1 @@ -36,7 +36,11 @@ InModuleScope $script:subModuleName { [Parameter()] [System.String] - $UniqueId + $UniqueId, + + [Parameter()] + [System.String] + $FriendlyName ) } @@ -197,14 +201,16 @@ InModuleScope $script:subModuleName { BeforeAll { $testDiskNumber = 10 $testDiskUniqueId = 'DiskUniqueId' + $testDiskFriendlyName = 'DiskFriendlyName' $testDiskGuid = [Guid]::NewGuid().ToString() $testDiskLocation = 'Integrated : Adapter 0 : Port 0 : Target 0 : LUN 10' $mockedDisk = [pscustomobject] @{ - Number = $testDiskNumber - UniqueId = $testDiskUniqueId - Guid = $testDiskGuid - Location = $testDiskLocation + Number = $testDiskNumber + UniqueId = $testDiskUniqueId + FriendlyName = $testDiskFriendlyName + Guid = $testDiskGuid + Location = $testDiskLocation } } @@ -298,6 +304,51 @@ InModuleScope $script:subModuleName { } } + Context 'Disk exists that matches the specified Disk Friendly Name' { + Mock ` + -CommandName Get-Disk ` + -MockWith { $mockedDisk } ` + -ModuleName StorageDsc.Common ` + -ParameterFilter { $FriendlyName -eq $testDiskFriendlyName } ` + -Verifiable + + It "Should return Disk with Disk Friendly Name $testDiskFriendlyName" { + (Get-DiskByIdentifier -DiskId $testDiskFriendlyName -DiskIdType 'FriendlyName').FriendlyName | Should -Be $testDiskFriendlyName + } + + It 'Should call expected mocks' { + Assert-VerifiableMock + Assert-MockCalled ` + -CommandName Get-Disk ` + -ModuleName StorageDsc.Common ` + -ParameterFilter { $FriendlyName -eq $testDiskFriendlyName } ` + -Exactly ` + -Times 1 + } + } + + Context 'Disk does not exist that matches the specified Disk Friendly Name' { + Mock ` + -CommandName Get-Disk ` + -ModuleName StorageDsc.Common ` + -ParameterFilter { $FriendlyName -eq $testDiskFriendlyName } ` + -Verifiable + + It "Should return Disk with Disk Friendly Name $testDiskFriendlyName" { + Get-DiskByIdentifier -DiskId $testDiskFriendlyName -DiskIdType 'FriendlyName' | Should -BeNullOrEmpty + } + + It 'Should call expected mocks' { + Assert-VerifiableMock + Assert-MockCalled ` + -CommandName Get-Disk ` + -ModuleName StorageDsc.Common ` + -ParameterFilter { $FriendlyName -eq $testDiskFriendlyName } ` + -Exactly ` + -Times 1 + } + } + Context 'Disk exists that matches the specified Disk Guid' { Mock ` -CommandName Get-Disk `