diff --git a/arm-ttk/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 b/arm-ttk/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 index 4f14d3d5..37b97f97 100644 --- a/arm-ttk/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 +++ b/arm-ttk/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 @@ -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) @@ -21,7 +30,15 @@ $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 @@ -29,6 +46,8 @@ 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) @@ -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 | ? -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 + } + } + } + } } diff --git a/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Pass/OutputCorrectType/azureDeploy.json b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Pass/OutputCorrectType/azureDeploy.json new file mode 100644 index 00000000..815ff892 --- /dev/null +++ b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Pass/OutputCorrectType/azureDeploy.json @@ -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." + } + } + } +} \ No newline at end of file diff --git a/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Pass/OutputCorrectType/createUiDefinition.json b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Pass/OutputCorrectType/createUiDefinition.json new file mode 100644 index 00000000..4b2acf4f --- /dev/null +++ b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Pass/OutputCorrectType/createUiDefinition.json @@ -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))]" + } + } +} \ No newline at end of file diff --git a/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Warn/OutputIncorrectType/azureDeploy.json b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Warn/OutputIncorrectType/azureDeploy.json new file mode 100644 index 00000000..e527d21a --- /dev/null +++ b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Warn/OutputIncorrectType/azureDeploy.json @@ -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." + } + } + } +} \ No newline at end of file diff --git a/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Warn/OutputIncorrectType/createUiDefinition.json b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Warn/OutputIncorrectType/createUiDefinition.json new file mode 100644 index 00000000..c9b9c2ba --- /dev/null +++ b/unit-tests/Outputs-Must-Be-Present-In-Template-Parameters/Warn/OutputIncorrectType/createUiDefinition.json @@ -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')]" + } + } +} \ No newline at end of file diff --git a/unit-tests/arm-ttk.test.functions.ps1 b/unit-tests/arm-ttk.test.functions.ps1 index 8dfc4eeb..7b7a678b 100644 --- a/unit-tests/arm-ttk.test.functions.ps1 +++ b/unit-tests/arm-ttk.test.functions.ps1 @@ -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)" @@ -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' }