Skip to content

Commit

Permalink
#444 createUI output datatype (#585)
Browse files Browse the repository at this point in the history
* Fixing #444:  Template Output Data Types

* Adding positive/negative tests

* Expanding list of acceptable data type coercion functions

* Adding Length to -AllowedFunctionInOutput

* Adding boolean case to failure

* Adding Tracing for CI/CD debugging

* More tracing for debugging CI/CD

* Adding -Debug support to test functions

* Adding -Debug to the Outputs-Must-Be-Present-In-Template-Parameters

* Updating failure case (making JSON more correct)

* Fixing casing in createUiDefinition filename

* Cleaning up CI/CD debugging

* Outputs-Must-Be-Present-In-Template-Parameters:  Switching to warning.  Adding notes.

* Outputs-Must-Be-Present-In-Template-Parameters:  Switching to warning.  Adding notes.
  • Loading branch information
StartAutomating committed Mar 1, 2022
1 parent fe46027 commit c899a92
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
Test-AzTemplate .\100-marketplace-sample -Test Outputs-Must-Be-Present-In-Template-Parameters
.Example
.\Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 -CreateUIDefinitionObject @([PSCustomObject]@{badinput=$true}) -TemplateObject ([PSCustomObject]@{})
.Notes
This also attempts to validate the return type of an output, provided that the return type is not a string.
It currently _does not_ attempt to validate the data type of the control,
and thus may give a false positive in the case of Checkboxes and other non-string CreateUiDefinition controls.
The list of acceptable output functions by datatype is accessible in the parameter -AllowedFunctionInOutput.
It currently only checks integer and boolean types. If you believe an additional exception is needed, please file an issue on GitHub.
#>
param(
# The CreateUIDefinition Object (the contents of CreateUIDefinition.json, converted from JSON)
Expand All @@ -21,14 +30,24 @@ $TemplateObject,

# If set, the TemplateObject is an inner template.
[switch]
$IsInnerTemplate
$IsInnerTemplate,

# The allowed functions for a given data type.
# This is not accounting for the type or control.
[Collections.IDictionary]
$AllowedFunctionInOutput = $(@{
int = 'int', 'min', 'max', 'div', 'add', 'mod', 'mul', 'sub', 'copyIndex','length', 'coalesce'
bool = 'equals', 'less', 'lessOrEquals', 'greater', 'greaterOrEquals', 'and', 'or','not', 'true', 'false', 'contains','empty','coalesce','if'
})
)

# If the TemplateObject is inner template of MainTemplate, skip the test
if ($IsInnerTemplate) {
return
}



# First, make sure CreateUIDefinition has outputs
if (-not $CreateUIDefinitionObject.parameters.outputs) {
Write-Error "CreateUIDefinition is missing the .parameters.outputs property" -ErrorId CreateUIDefinition.Missing.Outputs # ( write an error if it doesn't)
Expand All @@ -52,4 +71,16 @@ foreach ($output in $parameterInfo.outputs.psobject.properties) { # Then walk th
# write an error
Write-Error "output $outputName does not exist in template.parameters" -ErrorId CreateUIDefinition.Output.Missing.From.MainTemplate -TargetObject $parameterInfo.outputs
}

$outputParameterType = $TemplateObject.parameters.$outputName.type
if ($outputParameterType -and $outputParameterType -ne 'string') {
$firstOutputFunction = $output.Value | ?<ARM_Template_Function> -Extract | Select-Object -ExpandProperty FunctionName
if ($AllowedFunctionInOutput) {
foreach ($af in $AllowedFunctionInOutput.GetEnumerator()) {
if ($outputParameterType -eq $af.Key -and $firstOutputFunction -notin $af.Value) {
Write-Warning "output $outputName does not return the expected type '$outputParameterType'" -ErrorId CreateUIDefinition.Output.Incorrect -TargetObject $parameterInfo.outputs
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"swarmRootdiskSize": {
"type": "int",
"minValue": 30,
"maxValue": 2048,
"defaultValue": 30,
"metadata": {
"description": "Please select the size of the data disk you wish to deploy (value is integer GB)."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"basics": [],
"steps": [
{
"bladeTitle": "app Configuration",
"elements": [
{
"name": "deployApp",
"type": "Microsoft.Common.OptionsGroup",
"label": "Deploy App",
"defaultValue": "true",
"toolTip": "Optionally select to deploy App",
"constraints": {
"allowedValues": [
{
"label": "true",
"value": "yes"
},
{
"label": "false",
"value": "no"
}
],
"required": true
}
},
{
"name": "rootDiskSize",
"type": "Microsoft.Common.TextBox",
"label": "Swarm instance root disk size",
"defaultValue": "30",
"toolTip": "Provide the size of the Swarm root disk - The size (GB) of the Managed disk.",
"constraints": {
"required": true,
"regex": "^([3-9]\\d{1}\\d*|\\d{3}\\d*)$",
"validationMessage": "Value must be numeric and greater than or equal to 30"
},
"visible": true
}
],
"visible": "[equals(steps('SwarmConfig').deployApp, 'yes')]"
}
],
"outputs": {
"location": "[location()]",
"swarmRootDiskSize": "[int(coalesce(steps('SwarmConfig').vmSettings.rootDiskSize, 30))]"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"swarmRootdiskSize": {
"type": "int",
"minValue": 30,
"maxValue": 2048,
"defaultValue": 30,
"metadata": {
"description": "Please select the size of the data disk you wish to deploy (value is integer GB)."
}
},
"testBoolean": {
"type": "bool",
"defaultValue": false,
"metadata":{
"description": "A Boolean Parameter"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"basics": [],
"steps": [
{
"name": "swarmConfig",
"label": "swarmConfig",
"bladeTitle": "app Configuration",
"elements": [
{
"name": "deployApp",
"type": "Microsoft.Common.OptionsGroup",
"label": "Deploy App",
"defaultValue": "true",
"toolTip": "Optionally select to deploy App",
"constraints": {
"allowedValues": [
{
"label": "true",
"value": "yes"
},
{
"label": "false",
"value": "no"
}
],
"required": true
}
},
{
"name": "rootDiskSize",
"type": "Microsoft.Common.TextBox",
"label": "Swarm instance root disk size",
"defaultValue": "30",
"toolTip": "Provide the size of the Swarm root disk - The size (GB) of the Managed disk.",
"constraints": {
"required": true,
"regex": "^([3-9]\\d{1}\\d*|\\d{3}\\d*)$",
"validationMessage": "Value must be numeric and greater than or equal to 30"
},
"visible": true
}
]
}
],
"outputs": {
"location": "[location()]",
"swarmRootDiskSize": "[steps('SwarmConfig').vmSettings.rootDiskSize]",
"testBoolean": "[int('1')]"
}
}
}
6 changes: 6 additions & 0 deletions unit-tests/arm-ttk.test.functions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ function Test-TTKPass {

$ttkResults = Get-Item -Path $testFile.Fullname |
Test-AzTemplate @ttkParams
if ($DebugPreference -in 'inquire', 'continue') {
$ttkResults | Out-Host
}
if (-not $ttkResults) { throw "No Test Results" }
if ($ttkResults | Where-Object { -not $_.Passed}) {
throw "$($ttkResults.Errors | Out-String)"
Expand Down Expand Up @@ -121,6 +124,9 @@ function Test-TTKFail {
$ttkResults = Get-Item -Path $testFile.Fullname |
Test-AzTemplate @ttkParams
if (-not $ttkResults) { throw "No Test Results" }
if ($DebugPreference -in 'inquire', 'continue') {
$ttkResults | Out-Host
}
if (-not ($ttkResults | Where-Object {$_.Errors })) {
throw 'Errors were expected'
}
Expand Down

0 comments on commit c899a92

Please sign in to comment.