Skip to content

Instantly share code, notes, and snippets.

@Satak
Created December 31, 2021 07:07
Show Gist options
  • Save Satak/c747932d64d21c6be0547d5b1b2ff8bf to your computer and use it in GitHub Desktop.
Save Satak/c747932d64d21c6be0547d5b1b2ff8bf to your computer and use it in GitHub Desktop.
Terraform unit test with Pester/Powershell
BeforeDiscovery {
$testCases = Get-ChildItem -Path (Join-Path $PSScriptRoot examples) -Directory
}
describe 'terraform-module-storage - <_.Name>' -ForEach $testCases {
BeforeAll -ErrorAction Stop {
$exampleName = $_
Push-Location $exampleName
Write-Host "Test case: $($ExampleName.Name)" -Foreground Magenta
Write-Host 'Initializing...'
terraform init
Write-Host 'Validating...'
terraform validate
Write-Host 'Planning...'
(terraform plan -out terraform.plan) | Write-Host
# Parse plan file and pull out provided variables
$plan = terraform show -json terraform.plan | ConvertFrom-Json
$vars = $plan.variables
Write-Host 'Plan variables: '
Write-Host ($plan.variables | ConvertTo-Json)
}
AfterAll {
Pop-Location
}
context 'Unit' -Tag Unit {
BeforeAll {
$stgAddress = 'module.storage.azurerm_storage_account.storage'
$containerAddress = 'module.storage.azurerm_storage_container.my_stuff'
$atpAddress = 'module.storage.azurerm_advanced_threat_protection.atp'
$stgAccountPlan = ($plan.resource_changes | Where-Object {$_.address -eq $stgAddress})[0]
$container = ($plan.resource_changes | Where-Object {$_.address -eq $containerAddress})[0]
$atp = ($plan.resource_changes | Where-Object {$_.address -eq $atpAddress})[0]
}
it 'Will create storage account' {
$stgAccountPlan.change.actions[0] | Should -Be 'create'
}
it 'Will be in correct location' {
$stgAccountPlan.change.after.location | Should -Be $vars.location.value
}
it 'Will have correct account_tier' {
$stgAccountPlan.change.after.account_tier | Should -Be $vars.account_tier.value
}
it 'Will have correct replication_type' {
$stgAccountPlan.change.after.account_replication_type | Should -Be $vars.replication_type.value
}
it 'Will only allow HTTPS' {
$stgAccountPlan.change.after.enable_https_traffic_only | Should -Be $true
}
it 'Will prevent public blob containers' {
$stgAccountPlan.change.after.allow_blob_public_access | Should -Be $false
}
it 'Will have correct delete_retention_days' {
$retentionDays = $stgAccountPlan.change.after.blob_properties.delete_retention_policy.days
$retentionDays | Should -Be $vars.delete_retention_days.value
}
it 'Will create private storage container' {
$container.change.actions[0] | Should -Be 'create'
}
it 'Will enable ATP' {
$atp.change.actions[0] | Should -Be 'create'
}
}
context 'Integration' -Tag Integration {
BeforeAll {
Write-Host 'Applying infrastructure...'
(terraform apply --auto-approve terraform.plan) | Write-Host
# Get the provisioned resources from the state file
$state = terraform show -json terraform.tfstate | ConvertFrom-Json
# The prefix was generated by the random_id resource
# so we need to retrieve the value for that
$prefix = ($state.values.root_module.resources |
Where-Object {$_.address -eq 'random_id.prefix'}
)[0].values.hex
# Get the storage account from state
$childModuleResources = $state.values.root_module.child_modules.resources
$stgAccountState = ($childModuleResources |
Where-Object {$_.address -eq 'module.storage.azurerm_storage_account.storage'})[0]
$stgName = $stgAccountState.values.name
$stgRsg = $stgAccountState.values.resource_group_name
# Get the provisioned storage account from Azure
$stgAccount = Get-AzStorageAccount -Name $stgName -ResourceGroupName $stgRsg
$container = Get-AzStorageContainer -Context $stgAccount.Context -Name mystuff
}
AfterAll {
Write-Host 'Destroying infrastructure...'
Write-Host (terraform destroy --auto-approve *>&1)
}
it 'Created storage account' {
$stgAccount.StorageAccountName | Should -Be "$($prefix)storage"
}
it 'Public blob container is disallowed' {
{$stgAccount | New-AzStorageContainer -Name public1 -Permission Blob -ErrorAction Stop} | Should -Throw
{$stgAccount | New-AzStorageContainer -Name public2 -Permission Container -ErrorAction Stop} | Should -Throw
}
it 'Created private storage container' {
$container | Should -Not -BeNullOrEmpty
}
it 'Can upload to private container' {
# Premium storage SKUs must be page blobs aligned to 512 bytes boundarys
$blobType = $stgAccount.Sku.Tier -eq 'Premium' ? 'Page' : 'Block'
$tmpName = [IO.Path]::GetRandomFileName()
$tmpFilePath = Join-Path $TestDrive $tmpName
$tmpFile = [IO.FileStream]::new($tmpFilePath, 'Create', 'ReadWrite')
$tmpFile.SetLength(1MB)
$tmpFile.Close()
$uploadParam = @{
Container = $container.Name
File = $tmpFile.Name
Blob = $random.Name
Context = $stgAccount.Context
BlobType = $blobType
Force = $true
}
{Set-AzStorageBlobContent @uploadParam } | Should -Not -Throw
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment