配置 IDT 狀態機 - AWS IoT Greengrass

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

配置 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對象必須包含SucceedFail狀態。如需有效狀態的資訊,請參有效的狀態和狀態定義

有效的狀態和狀態定義

本節介紹 IDT 狀態機中可以使用的所有有效狀態的狀態定義。以下某些狀態支持測試用例級別的配置。但是,除非絕對必要,否則我們建議您在測試組級別而不是在測試用例級別配置狀態轉換規則。

RunTask

所以此RunTask狀態會從測試套件中定義的測試組中運行測試用例。

{ "Type": "RunTask", "Next": "<state-name>", "TestGroup": "<group-id>", "TestCases": [ "<test-id>" ], "ResultVar": "<result-name>" }

如下所述,包含值的所有欄位皆為必要:

Next

在當前狀態下執行動作後,為狀態轉換至的名稱。

TestGroup

選用。要運行的測試組的 ID。如果未指定此值,則 IDT 運行測試運行者選擇的測試組。

TestCases

選用。測試用例 ID 的數組,來自TestGroup。基於TestGroupTestCases,IDT 確定測試執行行為,如下所示:

  • 當兩者TestGroupTestCases時,IDT 將從測試組運行指定的測試用例。

  • 時機TestCases的規則,但TestGroup,則 IDT 運行指定的測試用例。

  • 時機TestGroup被指定,但TestCases,IDT 會執行指定測試組中的所有測試用例。

  • 當兩者都沒有TestGroup或者TestCases時,IDT 運行測試運行者從 IDT CLI 中選擇的測試組中的所有測試用例。要為測試運行者啟用組選擇,必須同時包含RunTaskChoice狀態state_machine.jsonfile. 如需此操作如何執行的範例,請參。範例狀態機器:運行用户選定的測試組

    如需為測試運行者啟用 IDT CLI 命令的詳細資訊,請參啟用 IDT

ResultVar

要使用測試運行結果設置的上下文變量的名稱。如果未指定TestGroup。IDT 設置您在ResultVartrue或者false根據下列的規則:

  • 如果變量名稱為text_text_passed,則該值將設置為第一個測試組中的所有測試是通過還是被跳過。

  • 在所有其他情況下,該值都設置為所有測試組中的所有測試都通過還是跳過。

一般而言,您需要使用RunTask狀態指定測試組 ID,而不指定單個測試用例 ID,以便 IDT 將運行指定測試組中的所有測試用例。由此狀態運行的所有測試用例以隨機順序 parallel 運行。但是,如果所有測試用例都要求設備運行,並且只有一個設備可用,則測試用例將按順序運行。

錯誤處理

如果任何指定的測試組或測試用例 ID 無效,則此狀態會發出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塊來處理此狀態下的錯誤。如果要在遇到錯誤時停止執行狀態機,則必須將FallthroughOnErrorfalse。不過,建議您設定FallthroughOnErrortrue,並根據您的用例,執行下列其中一項:

  • 如果您正在訪問的變量在某些情況下預期不存在,則使用Default和額外Choices塊來指定下一個狀態。

  • 如果您正在訪問的變量應該始終存在,則設置Default狀態Fail

平行

所以此Parallel狀態允許您彼此並行定義和運 parallel 新狀態機。

{ "Type": "Parallel", "Next": "<state-name>", "Branches": [ <state-machine-definition> ] }

如下所述,包含值的所有欄位皆為必要:

Next

在當前狀態下執行動作後,為狀態轉換至的名稱。

Branches

要運行的狀態機定義數組。每個狀態機器定義都必須包含其自己的StartAtSucceed,以及Fail狀態。此數組中的狀態機定義不能引用其自身定義之外的狀態。

注意

由於每個分支狀態機共享相同的狀態機上下文,所以在一個分支中設置變量,然後從另一個分支讀取這些變量可能會導致意外的行為。

所以此Parallel狀態只有在運行所有分支狀態計算機後才會移動到下一個狀態。需要設備的每個狀態都將等待運行,直到設備可用。如果有多個設備可用,則此狀態從多個組並行運 parallel 測試用例。如果沒有足夠的設備,則測試用例將按順序運行。由於測試用例在並行運行時以隨機順序運 parallel,因此可能會使用不同的設備從同一測試組運行測試。

錯誤處理

確保分支狀態機和父狀態機都轉換到Fail狀態來處理執行錯誤。

由於分支狀態計算機不會將執行錯誤傳輸到父狀態機,因此不能使用Catch塊來處理分支狀態計算機中的執行錯誤。而是使用hasExecutionErrors值在共享狀態機上下文中。如需此操作如何執行的範例,請參。範例狀態機器:parallel 行運行兩個測試組

添加產品功能

所以此AddProductFeatures狀態允許您將產品功能添加到awsiotdevicetester_report.xml文件由 IDT 生成。

產品功能是用户定義的有關設備可能滿足的特定條件的信息。例如,MQTT產品功能可以指定設備正確發佈 MQTT 消息。在報告中,產品功能設置為supportednot-supported或自定義值,具體取決於是否通過指定的測試。

注意

所以此AddProductFeatures狀態不會自行生成報告。此狀態必須轉換為Reportstate以生成報告。

{ "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.xmlfile.

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

選用。測試組 ID 陣列。每個指定測試組中的所有測試都必須通過,才能支持該功能。

OneOfGroups

選用。測試組 ID 陣列。至少一個指定測試組中的所有測試必須通過,才能支持該功能。

TestCases

選用。測試用例 ID 陣列。如果指定此值,則以下內容適用:

  • 必須通過所有指定的測試用例,才能支持該功能。

  • Groups必須僅包含一個測試組 ID。

  • OneOfGroups必須指定。

IsRequired

選用。設定為false將此功能標記為報告中的可選功能。預設值為 true

ExecutionMethods

選用。一個執行方法的數組,它們匹配protocol中指定的值。device.jsonfile. 如果指定了此值,則測試運行者必須指定protocol值,該值與此數組中的某個值匹配,以便在報告中包含該功能。如果未指定此值,則該功能將始終包含在報告中。

若要使用 AWS for WordPressAddProductFeatures狀態,則必須將ResultVar中的RunTask狀態設定為下列其中一個值:

  • 如果您指定了單個測試用例 ID,則設置ResultVargroup-id_test-id_passed

  • 如果未指定單個測試用例 ID,則將ResultVargroup-id_passed

所以此AddProductFeatures狀態會按以下方式檢查測試結果:

  • 如果未指定任何測試用例 ID,則每個測試組的結果將根據group-id_passed變量在狀態機上下文中。

  • 如果您確實指定了測試用例 ID,則每個測試的結果由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狀態會生成test_manager.log並將日誌訊息流式傳輸到主控台。

{ "Type": "LogMessage", "Next": "<state-name>" "Level": "info | warn | error" "Message": "<message>" }

如下所述,包含值的所有欄位皆為必要:

Next

在當前狀態下執行動作後,為狀態轉換至的名稱。

Level

創建日誌消息的錯誤級別。如果指定的級別無效,此狀態將生成一條錯誤消息並將其丟棄。

Message

要記錄的消息。

選擇組

所以此SelectGroup狀態會更新狀態機上下文以指示選擇哪些組。由此狀態設置的值由任何後續的Choice狀態。

{ "Type": "SelectGroup", "Next": "<state-name>" "TestGroups": [ <group-id>" ] }

如下所述,包含值的所有欄位皆為必要:

Next

在當前狀態下執行動作後,為狀態轉換至的名稱。

TestGroups

將標記為選定的測試組的數組。對於此陣列中的每個測試組 ID,group-id_selected變量設置為true在情況下。請確保您提供有效的測試組 ID,因為 IDT 不會驗證指定的組是否存在。

Fail

所以此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.jsonfile.

userData

中的資訊userdata.jsonfile.

config

信息固定config.jsonfile.

suiteFailed

值設定為false狀態機器啟動時。如果測試組在RunTask狀態,則此值將設置為true,用於狀態機器執行的剩餘持續時間。

specificTestGroups

如果測試運行者選擇要運行的特定測試組而不是整個測試套件,則會創建此項並包含特定測試組 ID 的列表。

specificTestCases

如果測試運行者選擇要運行的特定測試用例而不是整個測試套件,則會創建此密鑰並包含特定測試用例 ID 的列表。

hasExecutionErrors

狀態機啟動時不退出。如果任何狀態遇到執行錯誤,則會創建此變量並將其設置為true,用於狀態機器執行的剩餘持續時間。

您可以使用 JSONPath 表示法查詢上下文。狀態定義中的 JSONPath 查詢的語法是{{$.query}}。您可以在某些狀態中使用 JSONPath 查詢作為佔位符字符串。IDT 將佔位符字符串替換為上下文中評估的 JSONPath 查詢的值。您可以使用佔位符作為下列值:

  • 所以此TestCases中的值RunTask狀態。

  • 所以此ExpressionChoice狀態。

當您從狀態機器上下文訪問資料時,請確保滿足下列條件:

  • JSON 路徑必須以$.

  • 每個值都必須計算為字符串、數字或布爾值。

如需使用 JSONPath 符號來訪問上下文中的資料的詳細資訊,請參。使用 IDT 上下文

執行錯誤

執行錯誤是狀態機在執行狀態時遇到的狀態機定義中的錯誤。IDT 將有關每個錯誤的信息記錄在test_manager.log並將日誌訊息流式傳輸到主控台。

您可以使用下列方式來處理執行錯誤:

捕獲

使用Catch中,將以下內容添加到狀態定義中:

"Catch": [ { "ErrorEquals": [ "<error-type>" ] "Next": "<state-name>" } ]

如下所述,包含值的所有欄位皆為必要:

Catch.ErrorEquals

要 catch 的錯誤類型陣列。如果執行錯誤與指定的其中一個值匹配,則狀態機器會轉換到Catch.Next。有關其產生的錯誤類型的信息,請參閲每個狀態定義。

Catch.Next

如果當前狀態遇到與中指定的值之一匹配的執行錯誤,則轉換為的下一個狀態Catch.ErrorEquals

Catch 塊按順序處理,直到一個匹配。如果沒有錯誤與 Catch 塊中列出的錯誤匹配,則狀態計算機將繼續執行。由於執行錯誤是由不正確的狀態定義導致的,因此建議您在狀態遇到執行錯誤時轉換為「失敗」狀態。

哈希執行錯誤

當某些狀態遇到執行錯誤時,除了發出錯誤之外,它們還會設置hasExecutionError值設定為true在狀態機器上下文中。您可以使用此值檢測錯誤何時發生,然後使用Choice狀態將狀態機轉換為Fail狀態。

此方法具有下列特性:

  • 狀態機不以分配給hasExecutionError,並且在特定狀態設置之前,此值不可用。這表示您必須明確設定FallthroughOnErrorfalse(針對)Choice狀態訪問此值,以防止狀態機在沒有發生執行錯誤時停止。

  • 一旦它被設置為truehasExecutionError永遠不會設置為 false 或從上下文中刪除。這意味着此值僅在第一次設置為true,並且對於所有後續狀態,它不提供有意義的值。

  • 所以此hasExecutionError值與所有分支狀態計算機共享Parallel狀態,這可能會導致意外的結果,具體取決於訪問它的順序。

由於這些特性,如果您可以使用 Catch 塊,我們不建議您使用此方法。

範例狀態機器

本節將提供狀態機器配置範例。

範例狀態機器:運行單個測試組

此狀態機器:

  • 運行 ID 的測試組GroupA,它必須出現在group.jsonfile.

  • 檢查執行錯誤和轉換到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" } } }

範例狀態機器:parallel 行運行兩個測試組

此狀態機器:

  • 執行GroupAGroupB測試組並 parallel。所以此ResultVar變量存儲在上下文中的RunTask狀態可用於AddProductFeatures狀態。

  • 檢查執行錯誤和轉換到Fail(如果找到任何)。此狀態機不使用Catch塊,因為該方法不檢測分支狀態計算機中的執行錯誤。

  • 將要素添加到awsiotdevicetester_report.xml文件基於傳遞

    • 如果GroupA通道,則要素會設定為supported

    • 該功能在報告中未標記為可選。

  • 生成報告並過渡到Succeed如果沒有錯誤,Fail否則

如果在設備池中配置了兩個設備,則GroupAGroupB可以同時執行。但是,如果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" } } }