Testing a rule#
Each rule in PSRule for Azure must include unit tests to ensure the rule works as expected. The unit test ensures the rule logic passes when the rule is expected to pass, and fails when the rule is expected to fail.
Tests are organized by the service that the rule applies to, and the file name include the rule prefix.
In many cases the test file will already exist, and you can add your tests to the existing file.
For example, if the rule is named Azure.Storage.SecureTransfer
the test file should be named Azure.Storage.Tests.ps1
.
To support testing rules, PSRule for Azure includes a set of sample resources that can be used to test the rules. Similar to tests, many samples already exist and you can add your samples to the existing file.
Both tests and samples are located in the tests/PSRule.Rules.Azure.Tests/
directory.
Adding or updating a sample#
Start by adding or updating a sample resource that can be used to test the rule. Samples are:
- Written as a JSON array of resources and are placed in the
tests/PSRule.Rules.Azure.Tests/
directory, - Each sample file is named after the rule service in the format
Resources.<servicename>.json
. For example, if the rule is calledAzure.Storage.SecureTransfer
, the sample file should be namedResources.Storage.json
.
In many cases, the existing resource samples will already fail a new rules. Add/ update samples as required to test the passing and failing scenarios for the rule.
For example, the rule Azure.Storage.SecureTransfer
requires that secure transfer is enabled for storage accounts by
the properties.supportsHttpsTrafficOnly
property.
This sample demonstrates minimum resources that will pass and fail the rule:
[
{
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Storage/storageAccounts/storage-A",
"Kind": "Storage",
"Location": "region",
"Name": "storage-A",
"Properties": {
"supportsHttpsTrafficOnly": true
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.Storage/storageAccounts",
"ResourceType": "Microsoft.Storage/storageAccounts",
"Sku": {
"Name": "Standard_GRS",
"Tier": "Standard"
}
},
{
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Storage/storageAccounts/storage-B",
"Kind": "Storage",
"Location": "region",
"Name": "storage-B",
"Properties": {
"supportsHttpsTrafficOnly": false
},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.Storage/storageAccounts",
"ResourceType": "Microsoft.Storage/storageAccounts",
"Sku": {
"Name": "Standard_GRS",
"Tier": "Standard"
}
},
{
"Id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Storage/storageAccounts/storage-C",
"Kind": "Storage",
"Location": "region",
"Name": "storage-C",
"Properties": {},
"ResourceGroupName": "test-rg",
"Type": "Microsoft.Storage/storageAccounts",
"ResourceType": "Microsoft.Storage/storageAccounts",
"Sku": {
"Name": "Standard_GRS",
"Tier": "Standard"
}
}
]
- The
storage-A
resource is expected to pass the rule becausesupportsHttpsTrafficOnly
is set totrue
. - The
storage-B
resource is expected to fail the rule becausesupportsHttpsTrafficOnly
is set tofalse
. - The
storage-C
resource is expected to fail the rule becausesupportsHttpsTrafficOnly
is not set.
Creating a unit test#
Unit tests for rules are written in PowerShell using Pester and placed in the tests/PSRule.Rules.Azure.Tests/
directory.
To create add a test to an existing file, you can use the following boilerplate code:
It '<rule_name>' {
$filteredResult = $result | Where-Object { $_.RuleName -eq '<rule_name>' };
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.TargetName | Should -BeIn '<name>', '<name>';
$ruleResult.Length | Should -Be 2;
# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.TargetName | Should -BeIn '<name>';
$ruleResult.Length | Should -Be 1;
}
- Replace
<rule_name>
with the name of the rule you are testing. - Replace
<name>
with the name of the resources you expect to pass or fail.
For example:
It 'Azure.Storage.SecureTransfer' { # (1)
$filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.Storage.SecureTransfer' };
# Fail
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.TargetName | Should -BeIn 'storage-B', 'storage-C', 'storage-D'; # (2)
$ruleResult.Length | Should -Be 3;
# Pass
$ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' });
$ruleResult | Should -Not -BeNullOrEmpty;
$ruleResult.TargetName | Should -BeIn 'storage-A', 'storage-E', 'storage-F', 'storage-G', 'storage-H'; # (3)
$ruleResult.Length | Should -Be 5;
}
- The name of the rule is
Azure.Storage.SecureTransfer
. - The rule is expected to fail for resources
storage-B
,storage-C
, andstorage-D
. - The rule is expected to pass for resources
storage-A
,storage-E
,storage-F
,storage-G
, andstorage-H
.
Here is an example of a unit test for validating rules: Azure.ACR.Tests.ps1 Example
Testing a rule locally#
Before opening a pull request, it's important to build and test your changes locally. This is the fastest way to ensure that your changes work as expected and that the rules are functioning correctly.
CI tests must pass before the pull request can be merged, however they are manually triggered by a maintainer after the pull request is reviewed.
- Build and test locally — Ensure that you can build your changes locally. Follow the instructions in the Building from Source guide to set up your local environment for testing.
- Run all tests — Before creating your PR, run the tests to make sure your changes are working as expected.