本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
設定 IDT 狀態機器
重要
從 IDT v4.5.2 開始,此狀態機器已棄用。我們強烈建議您使用新的測試協調器。如需詳細資訊,請參閱設定IDT測試協調器。
狀態機器是控制測試套件執行流程的建構。它決定測試套件的啟動狀態,根據使用者定義的規則管理狀態轉換,並繼續轉換這些狀態,直到達到結束狀態為止。
如果您的測試套件不包含使用者定義的狀態機器, IDT會為您產生狀態機器。預設狀態機器會執行下列功能:
-
讓測試執行器能夠選取和執行特定測試群組,而不是整個測試套件。
-
如果未選取特定測試群組, 會以隨機順序執行測試套件中的每個測試群組。
-
產生報告並列印主控台摘要,顯示每個測試群組和測試案例的測試結果。
IDT 測試套件的狀態機器必須符合下列條件:
-
每個狀態對應於 IDT要採取的動作,例如執行測試群組或製作報告檔案的產品。
-
轉換為 狀態會執行與 狀態相關聯的動作。
-
每個狀態都會定義下一個狀態的轉換規則。
-
結束狀態必須為
Succeed
或Fail
。
狀態機器格式
您可以使用下列範本來設定自己的
檔案:<custom-test-suite-folder>
/suite/state_machine.json
{ "Comment": "
<description>
", "StartAt": "<state-name>
", "States": { "<state-name>
": { "Type": "<state-type>
", // Additional state configuration } // Required states "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
如下所述,包含值的所有欄位皆為必要:
Comment
-
狀態機器的說明。
StartAt
-
IDT 開始執行測試套件的狀態名稱。的值
StartAt
必須設定為States
物件中列出的其中一個狀態。 States
-
將使用者定義狀態名稱映射至有效IDT狀態的物件。每個狀態。
state-name
物件包含映射至 的有效狀態定義state-name
.States
物件必須包含Succeed
和Fail
狀態。如需有效狀態的資訊,請參閱 有效狀態和狀態定義。
有效狀態和狀態定義
本節說明可在 狀態機器中使用的所有有效IDT狀態的狀態定義。下列某些狀態支援測試案例層級的組態。不過,除非絕對必要,否則建議您在測試群組層級設定狀態轉換規則,而非測試案例層級。
RunTask
RunTask
狀態會從測試套件中定義的測試群組執行測試案例。
{ "Type": "RunTask", "Next": "
<state-name>
", "TestGroup": "<group-id>
", "TestCases": [ "<test-id>
" ], "ResultVar": "<result-name>
" }
如下所述,包含值的所有欄位皆為必要:
Next
-
在目前狀態下執行動作後,要轉換至 的狀態名稱。
TestGroup
-
選用。要執行的測試群組 ID。如果未指定此值,請IDT執行測試執行器選取的測試群組。
TestCases
-
選用。IDs 來自 中指定群組的測試案例陣列
TestGroup
。根據TestGroup
和 的值TestCases
, IDT 決定測試執行行為,如下所示:-
TestCases
指定TestGroup
和 時, 會從測試群組IDT執行指定的測試案例。 -
TestCases
指定TestGroup
但未指定 時, 會IDT執行指定的測試案例。 -
指定
TestCases
但未指定TestGroup
時, 會IDT執行指定測試群組中的所有測試案例。 -
如果沒有指定
TestCases
TestGroup
或 ,請從測試執行器從 中選取的測試群組IDT中執行所有測試案例IDTCLI。若要啟用測試執行器的群組選取,您必須在statemachine.json
檔案中同時包含RunTask
和Choice
狀態。如需如何運作的範例,請參閱 狀態機器範例:執行使用者選取的測試群組 。如需為測試執行器啟用IDTCLI命令的詳細資訊,請參閱 啟用IDTCLI命令。
-
ResultVar
-
使用測試執行結果設定的內容變數名稱。如果您未指定 的值,請勿指定此值
TestGroup
。IDTfalse
會根據下列項目,將您在 中定義的變數值ResultVar
設定為true
或 :-
如果變數名稱為 形式
,則值會設定為是否通過或略過第一個測試群組中的所有測試。text
_text
_passed -
在所有其他情況下,該值會設定為是否所有測試群組中的所有測試都通過或略過。
-
一般而言,您將使用 RunTask
狀態來指定測試群組 ID,而不指定個別測試案例 IDs,以便 IDT執行指定測試群組中的所有測試案例。此狀態執行的所有測試案例都會以隨機順序平行執行。但是,如果所有測試案例都需要裝置才能執行,而且只有單一裝置可用,則測試案例將改為依序執行。
錯誤處理
如果任何指定的測試群組或測試案例IDs無效,則此狀態會發出RunTaskError
執行錯誤。如果狀態遇到執行錯誤,則也會將狀態機器內容中的hasExecutionError
變數設定為 true
。
Choice
Choice
狀態可讓您根據使用者定義的條件,動態設定要轉換至 的下一個狀態。
{ "Type": "Choice", "Default": "
<state-name>
", "FallthroughOnError": true | false, "Choices": [ { "Expression": "<expression>
", "Next": "<state-name>
" } ] }
如下所述,包含值的所有欄位皆為必要:
Default
-
如果無法在 中定義的任何表達式評估為 ,
Choices
則轉換為 的預設狀態true
。 FallthroughOnError
-
選用。指定 狀態在評估表達式時遇到錯誤的行為。
true
如果您想要在評估結果發生錯誤時略過表達式,請設定為 。如果沒有符合的表達式,狀態機器會轉換為Default
狀態。如果未指定FallthroughOnError
值,則預設為false
。 Choices
-
運算式和狀態的陣列,用於決定在目前狀態執行動作後要轉換至哪個狀態。
Choices.Expression
-
評估為布林值的表達式字串。如果表達式評估為
true
,則狀態機器會轉換為 中定義的狀態Choices.Next
。運算式字串會從狀態機器內容擷取值,然後對它們執行操作以得出布林值。如需存取狀態機器內容的相關資訊,請參閱 狀態機器內容。 Choices.Next
-
如果在 中定義的表達式
Choices.Expression
評估為 時,要轉換為 的狀態名稱true
。
錯誤處理
在下列情況下, Choice
狀態可能需要錯誤處理:
-
選擇表達式中的某些變數不存在於狀態機器內容中。
-
表達式的結果不是布林值。
-
JSON 查詢的結果不是字串、數字或布林值。
您無法使用此Catch
區塊來處理此狀態的錯誤。如果您想要在遇到錯誤時停止執行狀態機器,您必須將 FallthroughOnError
設定為 false
。不過,我們建議您將 FallthroughOnError
設定為 true
,並根據您的使用案例執行下列其中一項操作:
-
如果您正在存取的變數在某些情況下預期不存在,則請使用 和其他
Default
Choices
區塊的值來指定下一個狀態。 -
如果您存取的變數應一律存在,請將
Default
狀態設定為Fail
。
平行
Parallel
狀態可讓您彼此平行定義和執行新的狀態機器。
{ "Type": "Parallel", "Next": "
<state-name>
", "Branches": [<state-machine-definition>
] }
如下所述,包含值的所有欄位皆為必要:
Next
-
在目前狀態下執行動作後,要轉換至 的狀態名稱。
Branches
-
要執行的狀態機器定義陣列。每個狀態機器定義都必須包含自己的
StartAt
、Succeed
和Fail
狀態。此陣列中的狀態機器定義無法參考其定義以外的狀態。注意
由於每個分支狀態機器共用相同的狀態機器內容,因此在某個分支中設定變數,然後從另一個分支讀取這些變數可能會導致意外行為。
Parallel
狀態只有在執行所有分支狀態機器之後才會移至下一個狀態。需要裝置的每個狀態都會等待執行,直到裝置可用為止。如果有多個裝置可用,此狀態會從多個群組平行執行測試案例。如果沒有足夠裝置可用,則測試案例將依序執行。由於測試案例在平行執行時以隨機順序執行,因此可能會使用不同的裝置從相同的測試群組執行測試。
錯誤處理
確定分支狀態機器和父狀態機器都會轉換為 Fail
狀態,以處理執行錯誤。
由於分支狀態機器不會將執行錯誤傳輸至父狀態機器,因此您無法使用Catch
區塊來處理分支狀態機器中的執行錯誤。而是在共用狀態機器內容中使用 hasExecutionErrors
值。如需如何運作的範例,請參閱 狀態機器範例:平行執行兩個測試群組。
AddProductFeatures
AddProductFeatures
狀態可讓您將產品功能新增至 產生的awsiotdevicetester_report.xml
檔案IDT。
產品功能是有關裝置可能符合的特定條件的使用者定義資訊。例如,MQTT
產品功能可以指定裝置正確發佈MQTT訊息。在報告中,產品功能會根據是否通過指定的測試,設定為 not-supported
、 supported
或自訂值。
注意
AddProductFeatures
狀態不會自行產生報告。此狀態必須轉換為 Report 狀態才能產生報告。
{ "Type": "Parallel", "Next": "
<state-name>
", "Features": [ { "Feature": "<feature-name>
", "Groups": [ "<group-id>
" ], "OneOfGroups": [ "<group-id>
" ], "TestCases": [ "<test-id>
" ], "IsRequired": true | false, "ExecutionMethods": [ "<execution-method>
" ] } ] }
如下所述,包含值的所有欄位皆為必要:
Next
-
在目前狀態下執行動作後,要轉換至 的狀態名稱。
Features
-
要在
awsiotdevicetester_report.xml
檔案中顯示的產品功能陣列。Feature
-
功能的名稱
FeatureValue
-
選用。要在報告中使用的自訂值,而非
supported
。如果未指定此值,則根據測試結果,功能值會設定為supported
或not-supported
。如果您使用 的自訂值
FeatureValue
,則可以使用不同的條件測試相同的功能,並串IDT連支援條件的功能值。例如,下列摘錄顯示具有兩個不同MyFeature
特徵值的功能:... { "Feature": "MyFeature", "FeatureValue": "first-feature-supported", "Groups": ["first-feature-group"] }, { "Feature": "MyFeature", "FeatureValue": "second-feature-supported", "Groups": ["second-feature-group"] }, ...
如果兩個測試群組都通過,則功能值會設定為
first-feature-supported, second-feature-supported
。 Groups
-
選用。測試群組 的陣列IDs。每個指定測試群組中的所有測試都必須通過,才能支援此功能。
OneOfGroups
-
選用。測試群組 的陣列IDs。至少其中一個指定測試群組中的所有測試都必須通過,才能支援此功能。
TestCases
-
選用。測試案例 的陣列IDs。如果您指定此值,則適用下列條件:
-
所有指定的測試案例都必須通過,才能支援此功能。
-
Groups
只能包含一個測試群組 ID。 -
OneOfGroups
不得指定。
-
IsRequired
-
選用。設定為
false
,以在報告中將此功能標記為選用功能。預設值為true
。 ExecutionMethods
-
選用。符合
device.json
檔案中指定protocol
值的執行方法陣列。如果指定此值,則測試執行器必須指定符合此陣列中其中一個值protocol
的值,才能將 功能包含在報告中。如果未指定此值,則功能一律會包含在報告中。
若要使用 AddProductFeatures
狀態,您必須將 RunTask
狀態ResultVar
中的 值設定為下列其中一個值:
-
如果您指定了個別測試案例 IDs,則將
ResultVar
設定為
。group-id_test-id
_passed -
如果您未指定個別測試案例 IDs,則將
ResultVar
設定為
。group-id
_passed
AddProductFeatures
狀態會以下列方式檢查測試結果:
-
如果您未指定任何測試案例 IDs,則每個測試群組的結果都會根據狀態機器內容中的
變數值來決定。group-id
_passed -
如果您確實指定了測試案例 IDs,則每個測試的結果取決於狀態機器內容中
變數的值。group-id_test-id
_passed
錯誤處理
如果在此狀態下提供的群組 ID 不是有效的群組 ID,則此狀態會導致AddProductFeaturesError
執行錯誤。如果狀態遇到執行錯誤,則也會將狀態機器內容中的hasExecutionErrors
變數設定為 true
。
報告
Report
狀態會產生
和 suite-name
_Report.xmlawsiotdevicetester_report.xml
檔案。此狀態也會將報告串流至主控台。
{ "Type": "Report", "Next": "
<state-name>
" }
如下所述,包含值的所有欄位皆為必要:
Next
-
在目前狀態下執行動作後,要轉換至 的狀態名稱。
您應該一律在測試執行流程結束時轉換為 Report
狀態,以便測試執行器可以檢視測試結果。一般而言,此狀態後的下一個狀態為 Succeed
。
錯誤處理
如果此狀態在產生報告時遇到問題,則會發出ReportError
執行錯誤。
LogMessage
LogMessage
狀態會產生 test_manager.log
檔案,並將日誌訊息串流至主控台。
{ "Type": "LogMessage", "Next": "
<state-name>
" "Level": "info | warn | error" "Message": "<message>
" }
如下所述,包含值的所有欄位皆為必要:
Next
-
在目前狀態下執行動作後,要轉換至 的狀態名稱。
Level
-
建立日誌訊息的錯誤層級。如果您指定無效的層級,此狀態會產生錯誤訊息並捨棄它。
Message
-
要記錄的訊息。
SelectGroup
SelectGroup
狀態會更新狀態機器內容,以指出選取的群組。此狀態設定的值會由任何後續Choice
狀態使用。
{ "Type": "SelectGroup", "Next": "
<state-name>
" "TestGroups": [<group-id>
" ] }
如下所述,包含值的所有欄位皆為必要:
Next
-
在目前狀態下執行動作後,要轉換至 的狀態名稱。
TestGroups
-
將標記為選取的測試群組陣列。對於此陣列中的每個測試群組 ID,
變數會在內容group-id
_selectedtrue
中設定為 。請務必提供有效的測試群組,IDs因為 IDT 不會驗證指定的群組是否存在。
失敗
Fail
狀態表示狀態機器未正確執行。這是狀態機器的結束狀態,且每個狀態機器定義都必須包含此狀態。
{ "Type": "Fail" }
Succeed
Succeed
狀態表示狀態機器正確執行。這是狀態機器的結束狀態,且每個狀態機器定義都必須包含此狀態。
{ "Type": "Succeed" }
狀態機器內容
狀態機器內容是唯讀JSON文件,其中包含狀態機器在執行期間可用的資料。狀態機器內容只能從狀態機器存取,並包含決定測試流程的資訊。例如,您可以使用userdata.json
檔案中測試執行器設定的資訊來判斷是否需要執行特定測試。
狀態機器內容使用下列格式:
{ "pool": {
<device-json-pool-element>
}, "userData": {<userdata-json-content>
}, "config": {<config-json-content>
}, "suiteFailed": true | false, "specificTestGroups": [ "<group-id>" ], "specificTestCases": [ "<test-id>" ], "hasExecutionErrors": true }
pool
-
為測試執行選取的裝置集區的相關資訊。對於選取的裝置集區,此資訊會從
device.json
檔案中定義的對應頂層裝置集區陣列元素擷取。 userData
-
userdata.json
檔案中的資訊。 config
-
資訊固定
config.json
檔案。 suiteFailed
-
狀態機器啟動
false
時,此值會設為 。如果測試群組在RunTask
狀態中失敗,則此值會在狀態機器執行的剩餘持續時間true
內設定為 。 specificTestGroups
-
如果測試執行器選取要執行的特定測試群組,而不是整個測試套件,則會建立此金鑰並包含特定測試群組的清單IDs。
specificTestCases
-
如果測試執行器選取要執行的特定測試案例,而不是整個測試套件,則會建立此金鑰,並包含特定測試案例的清單IDs。
hasExecutionErrors
-
狀態機器啟動時不會結束。如果任何狀態遇到執行錯誤,則會建立此變數並在狀態機器執行的
true
剩餘持續時間內設定為 。
您可以使用JSONPath記號來查詢內容。狀態定義中JSONPath查詢的語法為 {{$.
。您可以在某些狀態下使用JSONPath查詢作為預留位置字串。IDT 會將預留位置字串取代為內容中評估JSONPath查詢的值。您可以使用預留位置作為下列值:query
}}
-
狀態
TestCases
的值RunTask
。 -
Expression
值Choice
狀態。
當您從狀態機器內容存取資料時,請確定符合下列條件:
-
您的JSON路徑必須以 開頭
$.
-
每個值都必須評估為字串、數字或布林值。
如需使用JSONPath註釋從內容存取資料的詳細資訊,請參閱 使用IDT內容。
執行錯誤
執行錯誤是狀態機器在執行狀態時遇到的狀態機器定義錯誤。IDT 會記錄test_manager.log
檔案中每個錯誤的相關資訊,並將日誌訊息串流至主控台。
您可以使用下列方法來處理執行錯誤:
-
在狀態定義中新增Catch區塊。
-
在狀態機器內容中檢查hasExecutionErrors值的值。
擷取
若要使用 Catch
,請將下列項目新增至您的狀態定義:
"Catch": [ { "ErrorEquals": [ "
<error-type>
" ] "Next": "<state-name>
" } ]
如下所述,包含值的所有欄位皆為必要:
Catch.ErrorEquals
-
要擷取的錯誤類型陣列。如果執行錯誤符合其中一個指定的值,狀態機器便會轉換為 中指定的狀態
Catch.Next
。如需其產生的錯誤類型的相關資訊,請參閱每個狀態定義。 Catch.Next
-
如果目前狀態遇到符合 中指定值之一的執行錯誤,則要轉換為
Catch.ErrorEquals
的下一個狀態。
擷取區塊會依序處理,直到有一個相符項目為止。如果沒有錯誤符合擷取區塊中列出的錯誤,則狀態機器會繼續執行。由於執行錯誤是不正確狀態定義的結果,我們建議您在狀態遇到執行錯誤時,轉換為失敗狀態。
hasExecutionError
當某些狀態遇到執行錯誤時,除了發出錯誤之外,也會在狀態機器內容true
中將hasExecutionError
值設定為 。您可以使用此值來偵測何時發生錯誤,然後使用 Choice
狀態將 狀態機器轉換為 Fail
狀態。
此方法具有下列特性。
-
狀態機器不會以指派給 的任何值開始
hasExecutionError
,而且此值在特定狀態設定之前無法使用。這表示您必須false
針對存取此值Choice
的狀態,明確將FallthroughOnError
設為 ,以防止狀態機器在未發生執行錯誤時停止。 -
設定為 後
true
,絕不hasExecutionError
會設定為 false 或從內容中移除。這表示此值只有在第一次設定為 時才有用true
,而且對於所有後續狀態,它不會提供有意義的值。 -
該
hasExecutionError
值會與Parallel
狀態中的所有分支狀態機器共用,這可能會導致意外的結果,具體取決於存取它的順序。
由於這些特性,如果您可以改用擷取區塊,我們不建議您使用此方法。
狀態機器範例
本節提供一些範例狀態機器組態。
狀態機器範例:執行單一測試群組
此狀態機器:
-
執行 ID 為 的測試群組
GroupA
,該 ID 必須存在於group.json
檔案中的 套件中。 -
檢查執行錯誤,如果找到任何
Fail
,則轉換為 。 -
Succeed
如果沒有錯誤,則產生報告並轉換為 ,Fail
否則。
{ "Comment": "Runs a single group and then generates a report.", "StartAt": "RunGroupA", "States": { "RunGroupA": { "Type": "RunTask", "Next": "Report", "TestGroup": "GroupA", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
狀態機器範例:執行使用者選取的測試群組
此狀態機器:
-
檢查測試執行器是否已選取特定測試群組。狀態機器不會檢查特定測試案例,因為測試執行器無法在未選取測試群組的情況下選取測試案例。
-
如果選取測試群組:
-
在選取的測試群組中執行測試案例。為此,狀態機器不會明確指定
RunTask
狀態中的任何測試群組或測試案例。 -
執行所有測試並結束之後產生報告。
-
-
如果未選取測試群組:
-
在測試群組 中執行測試
GroupA
。 -
產生報告並結束。
-
{ "Comment": "Runs specific groups if the test runner chose to do that, otherwise runs GroupA.", "StartAt": "SpecificGroupsCheck", "States": { "SpecificGroupsCheck": { "Type": "Choice", "Default": "RunGroupA", "FallthroughOnError": true, "Choices": [ { "Expression": "{{$.specificTestGroups[0]}} != ''", "Next": "RunSpecificGroups" } ] }, "RunSpecificGroups": { "Type": "RunTask", "Next": "Report", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "RunGroupA": { "Type": "RunTask", "Next": "Report", "TestGroup": "GroupA", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
狀態機器範例:使用產品功能執行單一測試群組
此狀態機器:
-
執行測試群組
GroupA
。 -
檢查執行錯誤,如果找到任何
Fail
,則轉換為 。 -
將
FeatureThatDependsOnGroupA
功能新增至awsiotdevicetester_report.xml
檔案:-
如果
GroupA
通過,則功能會設定為supported
。 -
該功能在報告中不會標記為選用。
-
-
Succeed
如果沒有錯誤,則產生報告並轉換為 ,Fail
否則
{ "Comment": "Runs GroupA and adds product features based on GroupA", "StartAt": "RunGroupA", "States": { "RunGroupA": { "Type": "RunTask", "Next": "AddProductFeatures", "TestGroup": "GroupA", "ResultVar": "GroupA_passed", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "AddProductFeatures": { "Type": "AddProductFeatures", "Next": "Report", "Features": [ { "Feature": "FeatureThatDependsOnGroupA", "Groups": [ "GroupA" ], "IsRequired": true } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }
狀態機器範例:平行執行兩個測試群組
此狀態機器:
-
平行執行
GroupA
和GroupB
測試群組。狀態可使用 分支狀態機器中RunTask
狀態儲存在內容中的ResultVar
變數AddProductFeatures
。 -
檢查執行錯誤,如果找到任何
Fail
,則轉換為 。此狀態機器不會使用Catch
區塊,因為該方法不會偵測分支狀態機器中的執行錯誤。 -
根據傳遞的群組,將功能新增至
awsiotdevicetester_report.xml
檔案-
如果
GroupA
通過,則功能會設定為supported
。 -
該功能在報告中不會標記為選用。
-
-
Succeed
如果沒有錯誤,則產生報告並轉換為 ,Fail
否則
如果在裝置集區中設定了兩個裝置,則 GroupA
和 GroupB
都可以同時執行。不過,如果 GroupA
或 中GroupB
包含多個測試,則兩個裝置可能會配置到這些測試。如果只設定一個裝置,測試群組將依序執行。
{ "Comment": "Runs GroupA and GroupB in parallel", "StartAt": "RunGroupAAndB", "States": { "RunGroupAAndB": { "Type": "Parallel", "Next": "CheckForErrors", "Branches": [ { "Comment": "Run GroupA state machine", "StartAt": "RunGroupA", "States": { "RunGroupA": { "Type": "RunTask", "Next": "Succeed", "TestGroup": "GroupA", "ResultVar": "GroupA_passed", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }, { "Comment": "Run GroupB state machine", "StartAt": "RunGroupB", "States": { "RunGroupA": { "Type": "RunTask", "Next": "Succeed", "TestGroup": "GroupB", "ResultVar": "GroupB_passed", "Catch": [ { "ErrorEquals": [ "RunTaskError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } } ] }, "CheckForErrors": { "Type": "Choice", "Default": "AddProductFeatures", "FallthroughOnError": true, "Choices": [ { "Expression": "{{$.hasExecutionErrors}} == true", "Next": "Fail" } ] }, "AddProductFeatures": { "Type": "AddProductFeatures", "Next": "Report", "Features": [ { "Feature": "FeatureThatDependsOnGroupA", "Groups": [ "GroupA" ], "IsRequired": true }, { "Feature": "FeatureThatDependsOnGroupB", "Groups": [ "GroupB" ], "IsRequired": true } ] }, "Report": { "Type": "Report", "Next": "Succeed", "Catch": [ { "ErrorEquals": [ "ReportError" ], "Next": "Fail" } ] }, "Succeed": { "Type": "Succeed" }, "Fail": { "Type": "Fail" } } }