Skip to content

Commit c899a92

Browse files
#444 createUI output datatype (#585)
* 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.
1 parent fe46027 commit c899a92

File tree

6 files changed

+197
-1
lines changed

6 files changed

+197
-1
lines changed

arm-ttk/testcases/CreateUIDefinition/Outputs-Must-Be-Present-In-Template-Parameters.test.ps1

+32-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
Test-AzTemplate .\100-marketplace-sample -Test Outputs-Must-Be-Present-In-Template-Parameters
88
.Example
99
.\Outputs-Must-Be-Present-In-Template-Parameters.test.ps1 -CreateUIDefinitionObject @([PSCustomObject]@{badinput=$true}) -TemplateObject ([PSCustomObject]@{})
10+
.Notes
11+
This also attempts to validate the return type of an output, provided that the return type is not a string.
12+
13+
It currently _does not_ attempt to validate the data type of the control,
14+
and thus may give a false positive in the case of Checkboxes and other non-string CreateUiDefinition controls.
15+
16+
The list of acceptable output functions by datatype is accessible in the parameter -AllowedFunctionInOutput.
17+
18+
It currently only checks integer and boolean types. If you believe an additional exception is needed, please file an issue on GitHub.
1019
#>
1120
param(
1221
# The CreateUIDefinition Object (the contents of CreateUIDefinition.json, converted from JSON)
@@ -21,14 +30,24 @@ $TemplateObject,
2130

2231
# If set, the TemplateObject is an inner template.
2332
[switch]
24-
$IsInnerTemplate
33+
$IsInnerTemplate,
34+
35+
# The allowed functions for a given data type.
36+
# This is not accounting for the type or control.
37+
[Collections.IDictionary]
38+
$AllowedFunctionInOutput = $(@{
39+
int = 'int', 'min', 'max', 'div', 'add', 'mod', 'mul', 'sub', 'copyIndex','length', 'coalesce'
40+
bool = 'equals', 'less', 'lessOrEquals', 'greater', 'greaterOrEquals', 'and', 'or','not', 'true', 'false', 'contains','empty','coalesce','if'
41+
})
2542
)
2643

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

49+
50+
3251
# First, make sure CreateUIDefinition has outputs
3352
if (-not $CreateUIDefinitionObject.parameters.outputs) {
3453
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
5271
# write an error
5372
Write-Error "output $outputName does not exist in template.parameters" -ErrorId CreateUIDefinition.Output.Missing.From.MainTemplate -TargetObject $parameterInfo.outputs
5473
}
74+
75+
$outputParameterType = $TemplateObject.parameters.$outputName.type
76+
if ($outputParameterType -and $outputParameterType -ne 'string') {
77+
$firstOutputFunction = $output.Value | ?<ARM_Template_Function> -Extract | Select-Object -ExpandProperty FunctionName
78+
if ($AllowedFunctionInOutput) {
79+
foreach ($af in $AllowedFunctionInOutput.GetEnumerator()) {
80+
if ($outputParameterType -eq $af.Key -and $firstOutputFunction -notin $af.Value) {
81+
Write-Warning "output $outputName does not return the expected type '$outputParameterType'" -ErrorId CreateUIDefinition.Output.Incorrect -TargetObject $parameterInfo.outputs
82+
}
83+
}
84+
}
85+
}
5586
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"swarmRootdiskSize": {
6+
"type": "int",
7+
"minValue": 30,
8+
"maxValue": 2048,
9+
"defaultValue": 30,
10+
"metadata": {
11+
"description": "Please select the size of the data disk you wish to deploy (value is integer GB)."
12+
}
13+
},
14+
"location": {
15+
"type": "string",
16+
"defaultValue": "[resourceGroup().location]",
17+
"metadata": {
18+
"description": "Location for all resources."
19+
}
20+
}
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
3+
"handler": "Microsoft.Azure.CreateUIDef",
4+
"version": "0.1.2-preview",
5+
"parameters": {
6+
"basics": [],
7+
"steps": [
8+
{
9+
"bladeTitle": "app Configuration",
10+
"elements": [
11+
{
12+
"name": "deployApp",
13+
"type": "Microsoft.Common.OptionsGroup",
14+
"label": "Deploy App",
15+
"defaultValue": "true",
16+
"toolTip": "Optionally select to deploy App",
17+
"constraints": {
18+
"allowedValues": [
19+
{
20+
"label": "true",
21+
"value": "yes"
22+
},
23+
{
24+
"label": "false",
25+
"value": "no"
26+
}
27+
],
28+
"required": true
29+
}
30+
},
31+
{
32+
"name": "rootDiskSize",
33+
"type": "Microsoft.Common.TextBox",
34+
"label": "Swarm instance root disk size",
35+
"defaultValue": "30",
36+
"toolTip": "Provide the size of the Swarm root disk - The size (GB) of the Managed disk.",
37+
"constraints": {
38+
"required": true,
39+
"regex": "^([3-9]\\d{1}\\d*|\\d{3}\\d*)$",
40+
"validationMessage": "Value must be numeric and greater than or equal to 30"
41+
},
42+
"visible": true
43+
}
44+
],
45+
"visible": "[equals(steps('SwarmConfig').deployApp, 'yes')]"
46+
}
47+
],
48+
"outputs": {
49+
"location": "[location()]",
50+
"swarmRootDiskSize": "[int(coalesce(steps('SwarmConfig').vmSettings.rootDiskSize, 30))]"
51+
}
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"parameters": {
5+
"swarmRootdiskSize": {
6+
"type": "int",
7+
"minValue": 30,
8+
"maxValue": 2048,
9+
"defaultValue": 30,
10+
"metadata": {
11+
"description": "Please select the size of the data disk you wish to deploy (value is integer GB)."
12+
}
13+
},
14+
"testBoolean": {
15+
"type": "bool",
16+
"defaultValue": false,
17+
"metadata":{
18+
"description": "A Boolean Parameter"
19+
}
20+
},
21+
"location": {
22+
"type": "string",
23+
"defaultValue": "[resourceGroup().location]",
24+
"metadata": {
25+
"description": "Location for all resources."
26+
}
27+
}
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
3+
"handler": "Microsoft.Azure.CreateUIDef",
4+
"version": "0.1.2-preview",
5+
"parameters": {
6+
"basics": [],
7+
"steps": [
8+
{
9+
"name": "swarmConfig",
10+
"label": "swarmConfig",
11+
"bladeTitle": "app Configuration",
12+
"elements": [
13+
{
14+
"name": "deployApp",
15+
"type": "Microsoft.Common.OptionsGroup",
16+
"label": "Deploy App",
17+
"defaultValue": "true",
18+
"toolTip": "Optionally select to deploy App",
19+
"constraints": {
20+
"allowedValues": [
21+
{
22+
"label": "true",
23+
"value": "yes"
24+
},
25+
{
26+
"label": "false",
27+
"value": "no"
28+
}
29+
],
30+
"required": true
31+
}
32+
},
33+
{
34+
"name": "rootDiskSize",
35+
"type": "Microsoft.Common.TextBox",
36+
"label": "Swarm instance root disk size",
37+
"defaultValue": "30",
38+
"toolTip": "Provide the size of the Swarm root disk - The size (GB) of the Managed disk.",
39+
"constraints": {
40+
"required": true,
41+
"regex": "^([3-9]\\d{1}\\d*|\\d{3}\\d*)$",
42+
"validationMessage": "Value must be numeric and greater than or equal to 30"
43+
},
44+
"visible": true
45+
}
46+
]
47+
}
48+
],
49+
"outputs": {
50+
"location": "[location()]",
51+
"swarmRootDiskSize": "[steps('SwarmConfig').vmSettings.rootDiskSize]",
52+
"testBoolean": "[int('1')]"
53+
}
54+
}
55+
}

unit-tests/arm-ttk.test.functions.ps1

+6
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ function Test-TTKPass {
8888

8989
$ttkResults = Get-Item -Path $testFile.Fullname |
9090
Test-AzTemplate @ttkParams
91+
if ($DebugPreference -in 'inquire', 'continue') {
92+
$ttkResults | Out-Host
93+
}
9194
if (-not $ttkResults) { throw "No Test Results" }
9295
if ($ttkResults | Where-Object { -not $_.Passed}) {
9396
throw "$($ttkResults.Errors | Out-String)"
@@ -121,6 +124,9 @@ function Test-TTKFail {
121124
$ttkResults = Get-Item -Path $testFile.Fullname |
122125
Test-AzTemplate @ttkParams
123126
if (-not $ttkResults) { throw "No Test Results" }
127+
if ($DebugPreference -in 'inquire', 'continue') {
128+
$ttkResults | Out-Host
129+
}
124130
if (-not ($ttkResults | Where-Object {$_.Errors })) {
125131
throw 'Errors were expected'
126132
}

0 commit comments

Comments
 (0)