本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
設定 IDT 狀態機器
重要
從 IDT v4.5.1 開始,此狀態機器已棄用。我們強烈建議您使用新的測試協調器。如需詳細資訊,請參閱設定 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 狀態的物件。每個 States.
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 會決定測試執行行為,如下所示:-
同時指定
TestCasesTestGroup和 時,IDT 會從測試群組執行指定的測試案例。 -
TestCases指定TestGroup但未指定 時,IDT 會執行指定的測試案例。 -
指定
TestCases但未指定TestGroup時,IDT 會執行指定測試群組中的所有測試案例。 -
當
TestGroup或TestCases皆未指定時,IDT 會從測試執行器從 IDT CLI 中選取的測試群組中執行所有測試案例。若要啟用測試執行器的群組選擇,您必須在state_machine.json檔案中同時包含RunTask和Choice狀態。如需運作方式的範例,請參閱範例狀態機器:執行使用者選取的測試群組。如需為測試執行器啟用 IDT CLI 命令的詳細資訊,請參閱啟用 IDT CLI 命令。
-
ResultVar-
使用測試執行結果設定的內容變數名稱。如果您未指定 的值,請勿指定此值
TestGroup。IDTfalse會根據下列項目,將您在 中定義的變數值設定為ResultVartrue或 :-
如果變數名稱的格式為
,則值會設定為是否通過或略過第一個測試群組中的所有測試。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 狀態可讓您將產品功能新增至 IDT 產生的awsiotdevicetester_report.xml檔案。
產品功能是有關裝置可能符合的特定條件的使用者定義資訊。例如,MQTT產品功能可以指定裝置正確發佈 MQTT 訊息。在報告中,產品功能會根據是否通過指定的測試,設定為 supportednot-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的下一個狀態。
擷取區塊會依序處理,直到一個相符項目為止。如果沒有錯誤符合 Catch 區塊中列出的錯誤,則狀態機器會繼續執行。由於執行錯誤是不正確狀態定義的結果,我們建議您在狀態遇到執行錯誤時轉換至失敗狀態。
hasExecutionError
當某些狀態遇到執行錯誤時,除了發出錯誤之外,也會在狀態機器內容true中將hasExecutionError值設定為 。您可以使用此值來偵測發生錯誤的時間,然後使用 Choice 狀態將狀態機器轉換為 Fail 狀態。
此方法具有下列特性。
-
狀態機器不會以指派給 的任何值開始
hasExecutionError,而且此值在特定狀態設定之前無法使用。這表示您必須false針對存取此值Choice的狀態,明確FallthroughOnError將 設為 ,以防止狀態機器在未發生執行錯誤時停止。 -
一旦設定為
true,hasExecutionError永遠不會設定為 false 或從內容中移除。這表示此值只有在第一次設定為 時才有用true,而且對於所有後續狀態,它不提供有意義的值。 -
該
hasExecutionError值會與Parallel狀態的所有分支狀態機器共用,這可能會導致非預期的結果,取決於存取它的順序。
由於這些特性,如果您可以改用 Catch 區塊,我們不建議您使用此方法。
狀態機器範例
本節提供一些範例狀態機器組態。
狀態機器範例:執行單一測試群組
此狀態機器:
-
執行 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" } } }