diff --git a/utilities/pipelines/staticValidation/compliance/module.tests.ps1 b/utilities/pipelines/staticValidation/compliance/module.tests.ps1 index d6a0882b72..6bfd55aaa2 100644 --- a/utilities/pipelines/staticValidation/compliance/module.tests.ps1 +++ b/utilities/pipelines/staticValidation/compliance/module.tests.ps1 @@ -631,7 +631,6 @@ Describe 'Module tests' -Tag 'Module' { $incorrectParameters | Should -BeNullOrEmpty -Because ('parameters in the template file should be camel-cased. Found incorrect items: [{0}].' -f ($incorrectParameters -join ', ')) } - It "[] Each parameters' & UDT's description should start with a one word category starting with a capital letter, followed by a dot, a space and the actual description text ending with a dot." -TestCases $moduleFolderTestCases { param( @@ -1174,6 +1173,98 @@ Describe 'Module tests' -Tag 'Module' { $outputs | Should -Contain 'systemAssignedMIPrincipalId' } } + + Context 'UDT-spcific' { + + It '[] A UDT should not be of type array, but instead the parameter that uses it. AVM-Spec-Ref: BCPNFR18.' -TestCases $moduleFolderTestCases -Tag 'UDT' { + + param( + [hashtable] $templateFileContent + ) + + if (-not $templateFileContent.definitions) { + Set-ItResult -Skipped -Because 'the module template has no user-defined types.' + return + } + + $incorrectTypes = [System.Collections.ArrayList]@() + foreach ($type in $templateFileContent.definitions.Keys) { + if ($templateFileContent.definitions.$type.type -eq 'array') { + $incorrectTypes += $type + } + } + # To be re-enabled once more modules are prepared. The code right below can then be removed. + # $incorrectTypes | Should -BeNullOrEmpty -Because ('no user-defined type should be declared as an array, but instead the parameter that uses the type. This makes the template and its parameters easier to understand. Found incorrect items: [{0}].' -f ($incorrectTypes -join ', ')) + if ($incorrectTypes.Count -gt 0) { + $warningMessage = ('No user-defined type should be declared as an array, but instead the parameter that uses the type. This makes the template and its parameters easier to understand. Found incorrect items: [{0}].' -f ($incorrectTypes -join ', ')) + Write-Warning $warningMessage + + Write-Output @{ + Warning = $warningMessage + } + } + } + + It '[] A UDT should not be nullable, but instead the parameter that uses it. AVM-Spec-Ref: BCPNFR18.' -TestCases $moduleFolderTestCases -Tag 'UDT' { + + param( + [hashtable] $templateFileContent + ) + + if (-not $templateFileContent.definitions) { + Set-ItResult -Skipped -Because 'the module template has no user-defined types.' + return + } + + $incorrectTypes = [System.Collections.ArrayList]@() + foreach ($type in $templateFileContent.definitions.Keys) { + if ($templateFileContent.definitions.$type.nullable -eq $true) { + $incorrectTypes += $type + } + } + + # To be re-enabled once more modules are prepared. The code right below can then be removed. + # $incorrectTypes | Should -BeNullOrEmpty -Because ('no user-defined type should be declared as nullable, but instead the parameter that uses the type. This makes the template and its parameters easier to understand. Found incorrect items: [{0}].' -f ($incorrectTypes -join ', ')) + if ($incorrectTypes.Count -gt 0) { + $warningMessage = ('No user-defined type should be declared as nullable, but instead the parameter that uses the type. This makes the template and its parameters easier to understand. Found incorrect items: [{0}].' -f ($incorrectTypes -join ', ')) + Write-Warning $warningMessage + + Write-Output @{ + Warning = $warningMessage + } + } + } + + It '[] A UDT should always be camel-cased and end with the suffix "Type". AVM-Spec-Ref: BCPNFR19.' -TestCases $moduleFolderTestCases -Tag 'UDT' { + + param( + [hashtable] $templateFileContent + ) + + if (-not $templateFileContent.definitions) { + Set-ItResult -Skipped -Because 'the module template has no user-defined types.' + return + } + + $incorrectTypes = [System.Collections.ArrayList]@() + foreach ($typeName in $templateFileContent.definitions.Keys) { + if ($typeName -cnotmatch '^[a-z].*Type$') { + $incorrectTypes += $typeName + } + } + + # To be re-enabled once more modules are prepared. The code right below can then be removed. + # $incorrectTypes | Should -BeNullOrEmpty -Because ('every used-defined type should be camel-cased and end with the suffix "Type". Found incorrect items: [{0}].' -f ($incorrectTypes -join ', ')) + if ($incorrectTypes.Count -gt 0) { + $warningMessage = ('Every used-defined type should be camel-cased and end with the suffix "Type". Found incorrect items: [{0}].' -f ($incorrectTypes -join ', ')) + Write-Warning $warningMessage + + Write-Output @{ + Warning = $warningMessage + } + } + } + } } } @@ -1546,8 +1637,12 @@ Describe 'API version tests' -Tag 'ApiCheck' { if ($approvedApiVersions -notcontains $TargetApi) { # Using a warning now instead of an error, as we don't want to block PRs for this. - Write-Warning ("The used API version [$TargetApi] is not one of the most recent 5 versions. Please consider upgrading to one of the following: {0}" -f $approvedApiVersions -join ', ') + $warningMessage = "The used API version [$TargetApi] is not one of the most recent 5 versions. Please consider upgrading to one of the following: {0}" -f ($approvedApiVersions -join ', ') + Write-Warning $warningMessage + Write-Output @{ + Warning = $warningMessage + } # The original failed test was # $approvedApiVersions | Should -Contain $TargetApi } else { @@ -1564,7 +1659,13 @@ Describe 'API version tests' -Tag 'ApiCheck' { if ($indexOfVersion -gt ($approvedApiVersions.Count - 2)) { $newerAPIVersions = $approvedApiVersions[0..($indexOfVersion - 1)] - Write-Warning ("The used API version [$TargetApi] for Resource Type [$ProviderNamespace/$ResourceType] will soon expire. Please consider updating it. Consider using one of the newer API versions [{0}]" -f ($newerAPIVersions -join ', ')) + + $warningMessage = "The used API version [$TargetApi] for Resource Type [$ProviderNamespace/$ResourceType] will soon expire. Please consider updating it. Consider using one of the newer API versions [{0}]" -f ($newerAPIVersions -join ', ') + Write-Warning $warningMessage + + Write-Output @{ + Warning = $warningMessage + } } } } diff --git a/utilities/tools/Test-ModuleLocally.ps1 b/utilities/tools/Test-ModuleLocally.ps1 index 10791bc671..662d56dd8b 100644 --- a/utilities/tools/Test-ModuleLocally.ps1 +++ b/utilities/tools/Test-ModuleLocally.ps1 @@ -12,6 +12,9 @@ Mandatory. Path to the Bicep/ARM module that is being tested .PARAMETER ModuleTestFilePath Optional. Path to the template file/folder that is to be tested with the template file. Defaults to the module's default '.test' folder. Will be used if the DeploymentTest/ValidationTest switches are set. +.PARAMETER PesterTag +Optional. A string array that can be specified to run only Pester tests with the specified tag + .PARAMETER PesterTest Optional. A switch parameter that triggers a Pester test for the module @@ -34,7 +37,6 @@ Optional. Additional parameters you can provide with the deployment. E.g. @{ res Optional. A hashtable parameter that contains custom tokens to be replaced in the paramter files for deployment .EXAMPLE - $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' ModuleTestFilePath = 'C:\network\route-table\.test\common\main.test.bicep' @@ -59,7 +61,16 @@ Test-ModuleLocally @TestModuleLocallyInput -Verbose Run a Test-Az*Deployment using a test file with the provided tokens .EXAMPLE +$TestModuleLocallyInput = @{ + TemplateFilePath = 'C:\network\route-table\main.bicep' + PesterTest = $true + PesterTag = 'UDT' +} +Test-ModuleLocally @TestModuleLocallyInput -Verbose + +Run the Pester tests with Tag 'UDT' for the given template file +.EXAMPLE $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' PesterTest = $true @@ -69,7 +80,6 @@ Test-ModuleLocally @TestModuleLocallyInput -Verbose Run all Pester tests for the given template file .EXAMPLE - $TestModuleLocallyInput = @{ TemplateFilePath = 'C:\network\route-table\main.bicep' PesterTest = $true @@ -135,6 +145,10 @@ function Test-ModuleLocally { [Parameter(Mandatory = $false)] [hashtable] $AdditionalTokens = @{}, + [Parameter(Mandatory = $false)] + [Alias('PesterTags')] + [string[]] $PesterTag, + [Parameter(Mandatory = $false)] [switch] $PesterTest, @@ -186,7 +200,7 @@ function Test-ModuleLocally { } } - Invoke-Pester -Configuration @{ + $configuration = @{ Run = @{ Container = New-PesterContainer -Path $testFiles -Data @{ repoRootPath = $repoRootPath @@ -197,6 +211,14 @@ function Test-ModuleLocally { Verbosity = 'Detailed' } } + + if (-not [String]::IsNullOrEmpty($PesterTag)) { + $configuration['Filter'] = @{ + Tag = $PesterTag + } + } + + Invoke-Pester -Configuration $configuration } catch { $PSItem.Exception.Message }