

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 开发和运行自己的 IDT 测试套件
<a name="idt-custom-tests"></a>

<a name="idt-byotc-idt"></a>从 IDT v4.0.0 开始，适用于 FreeRTOS 的 IDT 将标准化配置设置和结果格式与测试套件环境相结合，使您能够为设备和设备软件开发自定义测试套件。您可以添加自定义测试来用于自己的内部验证，也可以将其提供给客户进行设备验证。

使用 IDT 开发和运行自定义测试套件，如下所示：

****开发自定义测试套件****  
+ 使用自定义测试逻辑为要测试的设备创建测试套件。
+ 向 IDT 提供您的自定义测试套件以供测试运行器使用。包括有关测试套件的特定设置配置的信息。

****运行自定义测试套件****  
+ 设置要测试的设备。
+ 根据要使用的测试套件的要求实现设置配置。
+ 使用 IDT 运行您的自定义测试套件。
+ 查看 IDT 运行的测试的测试结果和执行日志。

## 下载最新版本的 Free AWS IoT RTOS 设备测试器
<a name="install-dev-tst-afr"></a>

下载 IDT 的[最新版本](dev-test-versions-afr.md#idt-latest-version-afr)并将软件提取到文件系统中您具有读取和写入权限的位置。

**注意**  
<a name="unzip-package-to-local-drive"></a>IDT 不支持由多个用户从共享位置（如 NFS 目录或 Windows 网络共享文件夹）运行。建议您将 IDT 包解压缩到本地驱动器，并在本地工作站上运行 IDT 二进制文件。  
Windows 的路径长度限制为 260 个字符。如果您使用的是 Windows，请将 IDT 提取到根目录（如 `C:\ ` 或 `D:\`）以使路径长度不超过 260 个字符的限制。

## 测试套件工作流
<a name="custom-test-workflow"></a>

测试套件由三种类型的文件组成：
+ 提供有关如何执行测试套件的信息的配置文件。
+ 测试 IDT 用来运行测试用例的可执行文件。
+ 运行测试所需的其他文件。

完成以下基本步骤来创建自定义 IDT 测试：

1. 为测试套件[创建配置文件](idt-json-config.md)。

1. [创建包含测试套件测试逻辑的测试用例可执行文件](test-executables.md)。

1. 验证并记录[测试运行器运行测试套件所需的配置信息](set-config-custom.md)。

1. 验证 IDT 能否按预期运行您的测试套件并生成[测试结果](run-tests-custom.md)。

要快速构建示例自定义套件并运行它，请按照 [教程：构建和运行示例 IDT 测试套件](build-sample-suite.md) 中的说明进行操作。

要开始使用 Python 创建自定义测试套件，请参阅[教程：开发一个简单的 IDT 测试套件](create-custom-tests.md)。

# 教程：构建和运行示例 IDT 测试套件
<a name="build-sample-suite"></a>

 AWS IoT Device Tester 下载内容包括示例测试套件的源代码。您可以完成本教程来构建和运行示例测试套件，以了解如何使用 AWS IoT Device Tester FreeRTOS 来运行自定义测试套件。尽管本教程使用 SSH，但学习如何在 FreeRTOS 设备上使用还是很有 AWS IoT Device Tester 用的。

 在本教程中，您将完成以下步骤：

1. [构建示例测试套件](build-sample.md)

1. [使用 IDT 运行示例测试套件](run-sample.md)

**Topics**
+ [

# 设置示例测试套件的先决条件
](prereqs-tutorial-sample.md)
+ [

# 配置 IDT 的设备信息
](configure-idt-sample.md)
+ [

# 构建示例测试套件
](build-sample.md)
+ [

# 使用 IDT 运行示例测试套件
](run-sample.md)
+ [

# 排查错误
](tutorial-troubleshooting-custom.md)

# 设置示例测试套件的先决条件
<a name="prereqs-tutorial-sample"></a>

要完成本教程，您需要：
+ 

  **主机要求**
  + 最新版本的 AWS IoT Device Tester
  + [Python](https://docs.python.org/3/) 3.7 或更高版本

    要检查您计算机安装的 Python 版本，请运行以下命令：

    ```
    python3 --version
    ```

    在 Windows 上，如果运行此命令时返回错误，则可改用 `python --version`。如果返回的版本号为 3.7 或更高版本，则可通过在 Powershell 终端中运行以下命令将 `python3` 设置为 `python` 命令的别名。

    ```
    Set-Alias -Name "python3" -Value "python"
    ```

    如果没有返回版本信息，或者版本号小于 3.7，则按照[下载 Python](https://wiki.python.org/moin/BeginnersGuide/Download) 中的说明安装 Python 3.7\$1。有关更多信息，请参阅 [Python 文档](https://docs.python.org/3/)。
  + [urllib3](https://urllib3.readthedocs.io/en/latest/)

    要验证 `urllib3` 是否已正确安装，请运行以下命令：

    ```
    python3 -c 'import urllib3'
    ```

    如果未安装 `urllib3`，请运行以下命令进行安装：

    ```
    python3 -m pip install urllib3
    ```
+ 

  **设备要求**
  + 一种运行 Linux 操作系统的设备，其网络连接到与您主机相同的网络。

    我们建议您使用搭载 Raspberry Pi 操作系统的 [Raspberry Pi](https://www.raspberrypi.org/)。请确保您设置 Raspberry Pi 上的 [SSH](https://www.raspberrypi.com/documentation/computers/remote-access.html) 才能远程连接到它。

# 配置 IDT 的设备信息
<a name="configure-idt-sample"></a>

配置您的设备信息，以便 IDT 运行测试。您必须使用以下信息，更新位于 `<device-tester-extract-location>/configs` 文件夹中的 `device.json` 模板。

```
[
  {
    "id": "pool",
    "sku": "N/A",
    "devices": [
      {
        "id": "<device-id>",
        "connectivity": {
          "protocol": "ssh",
          "ip": "<ip-address>",
          "port": "<port>",
          "auth": {
            "method": "pki | password",
            "credentials": {
              "user": "<user-name>",
              "privKeyPath": "/path/to/private/key",
              "password": "<password>"
            }
          }
        }
      }
    ]
  }
]
```

在 `devices` 对象中，提供以下信息：

**`id`**  
专属于您设备的用户定义唯一标识符。

**`connectivity.ip`**  
您设备的 IP 地址。

**`connectivity.port`**  
可选。用于通过 SSH 连接到您的设备的端口号。

**`connectivity.auth`**  
连接的身份验证信息。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。    
**`connectivity.auth.method`**  
用于通过给定的连接协议访问设备的身份验证方法。  
支持的值为：  
+ `pki`
+ `password`  
**`connectivity.auth.credentials`**  
用于身份验证的凭证。    
**`connectivity.auth.credentials.user`**  
用于登录您的设备的用户名。  
**`connectivity.auth.credentials.privKeyPath`**  
用于登录您设备的私有密钥的完整路径。  
此值仅在 `connectivity.auth.method` 设置为 `pki` 时适用。  
**`devices.connectivity.auth.credentials.password`**  
该密码用于登录到您的设备。  
此值仅在 `connectivity.auth.method` 设置为 `password` 时适用。

**注意**  
只有当 `method` 设置为 `pki` 时才指定 `privKeyPath`。  
只有当 `method` 设置为 `password` 时才指定 `password`。

# 构建示例测试套件
<a name="build-sample"></a>

`<device-tester-extract-location>/samples/python` 文件夹包含示例配置文件、源代码和 IDT 客户端软件开发工具包，您可以使用提供的构建脚本将其组合成一个测试套件。以下目录树显示了这些示例文件的位置：

```
<device-tester-extract-location>
├── ...
├── tests
├── samples
│   ├── ...
│   └── python
│       ├── configuration
│       ├── src
│       └── build-scripts
│           ├── build.sh
│           └── build.ps1
└── sdks
    ├── ...
    └── python
        └── idt_client
```

要构建测试套件，请在主机上运行以下命令：

------
#### [ Windows ]

```
cd <device-tester-extract-location>/samples/python/build-scripts
./build.ps1
```

------
#### [ Linux, macOS, or UNIX ]

```
cd <device-tester-extract-location>/samples/python/build-scripts
./build.sh
```

------

这将在该 `<device-tester-extract-location>/tests` 文件夹下的 `IDTSampleSuitePython_1.0.0` 文件夹中创建示例测试套件。检查 `IDTSampleSuitePython_1.0.0`文件夹中的文件，以了解示例测试套件的结构，并查看测试用例可执行文件和测试配置文件的各种示例。

**注意**  
示例测试套件包含 python 源代码。请勿在测试套件代码中包含敏感信息。

下一步：使用 IDT [运行您创建的示例测试套件](run-sample.md)。

# 使用 IDT 运行示例测试套件
<a name="run-sample"></a>

要运行示例测试套件，请在主机上运行以下命令：

```
cd <device-tester-extract-location>/bin
./devicetester_[linux | mac | win_x86-64] run-suite --suite-id IDTSampleSuitePython
```

IDT 会运行示例测试套件，并将结果流式传输到控制台。测试运行完毕后，您会看到以下信息：

```
========== Test Summary ==========
Execution Time:         5s
Tests Completed:        4
Tests Passed:           4
Tests Failed:           0
Tests Skipped:          0
----------------------------------
Test Groups:
    sample_group:       PASSED
----------------------------------
Path to AWS IoT Device Tester Report: /path/to/devicetester/results/87e673c6-1226-11eb-9269-8c8590419f30/awsiotdevicetester_report.xml
Path to Test Execution Logs: /path/to/devicetester/results/87e673c6-1226-11eb-9269-8c8590419f30/logs
Path to Aggregated JUnit Report: /path/to/devicetester/results/87e673c6-1226-11eb-9269-8c8590419f30/IDTSampleSuitePython_Report.xml
```

# 排查错误
<a name="tutorial-troubleshooting-custom"></a>

使用以下信息，以帮助解决在完成本教程时遇到的任何问题。

**测试用例未成功运行**
+ 如果测试运行失败，IDT 会将错误日志流式传输到控制台，以帮助您对测试运行进行故障排除。请确保满足本教程的所有[先决条件](prereqs-tutorial-sample.md)。

**无法连接到被测设备**

请验证以下内容：
+ 您的 `device.json` 文件包含正确的 IP 地址、端口和身份验证信息。
+ 您可以通过 SSH 从主机连接到您的设备。

# 教程：开发一个简单的 IDT 测试套件
<a name="create-custom-tests"></a>

测试套件结合了以下内容：
+ 包含测试逻辑的测试可执行文件
+ 描述测试套件的配置文件

本教程向您展示如何使用适用于 FreeRTOS 的 IDT 来开发包含单个测试用例的 Python 测试套件。尽管本教程使用 SSH，但学习如何在 FreeRTOS 设备上使用还是很有 AWS IoT Device Tester 用的。

在本教程中，您将完成以下步骤：

1. [创建测试套件目录](test-suite-dir.md)

1. [创建配置文件](test-suite-json.md)

1. [创建测试用例可执行文件](test-suite-exe.md)

1. [运行测试套件](run-test-suite.md)

按照以下步骤完成开发简单 IDT 测试套件的教程。

**Topics**
+ [

# 设置简单 IDT 测试套件的先决条件
](prereqs-tutorial-custom.md)
+ [

# 创建测试套件目录
](test-suite-dir.md)
+ [

# 创建配置文件
](test-suite-json.md)
+ [

# 获取 IDT 客户端 SDK
](add-idt-sdk.md)
+ [

# 创建测试用例可执行文件
](test-suite-exe.md)
+ [

# 配置 IDT 的设备信息
](configure-idt-sample2.md)
+ [

# 运行测试套件
](run-test-suite.md)
+ [

# 排查错误
](tutorial-troubleshooting.md)
+ [

# 创建 IDT 测试套件配置文件
](idt-json-config.md)
+ [

# 配置 IDT 测试编排工具
](idt-test-orchestrator.md)
+ [

# 配置 IDT 状态机
](idt-state-machine.md)
+ [

# 创建 IDT 测试用例可执行文件
](test-executables.md)
+ [

# 使用 IDT 上下文
](idt-context.md)
+ [

# 为测试运行器配置设置
](set-config-custom.md)
+ [

# 调试和运行自定义测试套件
](run-tests-custom.md)
+ [

# 查看 IDT 测试结果和日志
](idt-review-results-logs.md)
+ [

# 提交 IDT 使用情况指标
](idt-usage-metrics.md)

# 设置简单 IDT 测试套件的先决条件
<a name="prereqs-tutorial-custom"></a>

要完成本教程，您需要：
+ 

  **主机要求**
  + 最新版本的 AWS IoT Device Tester
  + [Python](https://www.python.org/downloads/) 3.7 或更高版本

    要检查您计算机安装的 Python 版本，请运行以下命令：

    ```
    python3 --version
    ```

    在 Windows 上，如果运行此命令时返回错误，则可改用 `python --version`。如果返回的版本号为 3.7 或更高版本，则可通过在 Powershell 终端中运行以下命令将 `python3` 设置为 `python` 命令的别名。

    ```
    Set-Alias -Name "python3" -Value "python"
    ```

    如果没有返回版本信息，或者版本号小于 3.7，则按照[下载 Python](https://wiki.python.org/moin/BeginnersGuide/Download) 中的说明安装 Python 3.7\$1。有关更多信息，请参阅 [Python 文档](https://docs.python.org/3/)。
  + [urllib3](https://urllib3.readthedocs.io/en/latest/)

    要验证 `urllib3` 是否已正确安装，请运行以下命令：

    ```
    python3 -c 'import urllib3'
    ```

    如果未安装 `urllib3`，请运行以下命令进行安装：

    ```
    python3 -m pip install urllib3
    ```
+ 

  **设备要求**
  + 一种运行 Linux 操作系统的设备，其网络连接到与您主机相同的网络。

    我们建议您使用搭载 Raspberry Pi 操作系统的 [Raspberry Pi](https://www.raspberrypi.org/)。请确保您设置 Raspberry Pi 上的 [SSH](https://www.raspberrypi.com/documentation/computers/remote-access.html) 才能远程连接到它。

# 创建测试套件目录
<a name="test-suite-dir"></a>

IDT 在逻辑上将测试用例分成每个测试套件中的测试组。每个测试用例都必须位于测试组中。在本教程中，创建一个名为 `MyTestSuite_1.0.0` 的文件夹，并在此文件夹中创建以下目录树：

```
MyTestSuite_1.0.0
└── suite
    └── myTestGroup
        └── myTestCase
```

# 创建配置文件
<a name="test-suite-json"></a>

您的测试套件必须包含以下必需的[配置文件](idt-json-config.md)：

**所需的文件**

**`suite.json`**  
包含有关测试套件的信息。请参阅[配置 suite.json](idt-json-config.md#suite-json)。

**`group.json`**  
包含有关测试组的信息。您必须为测试套件中的每个测试组创建一个 `group.json` 文件。请参阅[配置 group.json](idt-json-config.md#group-json)。

**`test.json`**  
包含有关测试用例的信息。您必须为测试套件中的每个测试用例创建一个 `test.json` 文件。请参阅[配置 test.json](idt-json-config.md#test-json)。

1. 在 `MyTestSuite_1.0.0/suite` 文件夹中，创建以下文件夹结构的 `suite.json`：

   ```
   {
       "id": "MyTestSuite_1.0.0",
       "title": "My Test Suite",
       "details": "This is my test suite.",
       "userDataRequired": false
   }
   ```

1. 在 `MyTestSuite_1.0.0/myTestGroup` 文件夹中，创建以下文件夹结构的 `group.json`：

   ```
   {
       "id": "MyTestGroup",
       "title": "My Test Group",
       "details": "This is my test group.",
       "optional": false
   }
   ```

1. 在 `MyTestSuite_1.0.0/myTestGroup/myTestCase` 文件夹中，创建以下文件夹结构的 `test.json`：

   ```
   {
       "id": "MyTestCase",
       "title": "My Test Case",
       "details": "This is my test case.",
       "execution": {
           "timeout": 300000,
           "linux": {
               "cmd": "python3",
               "args": [
                   "myTestCase.py"
               ]
           },
           "mac": {
               "cmd": "python3",
               "args": [
                   "myTestCase.py"
               ]
           },
           "win": {
               "cmd": "python3",
               "args": [
                   "myTestCase.py"
               ]
           }
       }
   }
   ```

您的 `MyTestSuite_1.0.0` 文件夹应类似于以下内容：

```
MyTestSuite_1.0.0
└── suite
    ├── suite.json
    └── myTestGroup
        ├── group.json
        └── myTestCase
            └── test.json
```

# 获取 IDT 客户端 SDK
<a name="add-idt-sdk"></a>

您可以使用 [IDT 客户端 SDK](test-executables.md#idt-client-sdk) 让 IDT 与被测设备进行交互并报告测试结果。在本教程中，您将使用 Python 版本的软件开发工具包。

从 `<device-tester-extract-location>/sdks/python/` 文件夹，将 `idt_client` 文件夹复制到您的 `MyTestSuite_1.0.0/suite/myTestGroup/myTestCase` 文件夹。

要验证 SDK 是否复制，可以运行以下命令。

```
cd MyTestSuite_1.0.0/suite/myTestGroup/myTestCase
python3 -c 'import idt_client'
```

# 创建测试用例可执行文件
<a name="test-suite-exe"></a>

测试用例可执行文件包含要运行的测试逻辑。一个测试套件可以包含多个测试用例可执行文件。在本教程中，您将只创建一个测试用例可执行文件。

1. 创建测试套件文件。

   在 `MyTestSuite_1.0.0/suite/myTestGroup/myTestCase` 文件夹中，创建使用以下内容的 `myTestCase.py` 文件：

   ```
   from idt_client import *
   
   def main():
       # Use the client SDK to communicate with IDT
       client = Client()
   
   if __name__ == "__main__":
       main()
   ```

1. 使用客户端 SDK 函数将以下测试逻辑添加到您的 `myTestCase.py` 文件中：

   1. 在被测设备上运行 SSH 命令。

      ```
      from idt_client import *
      
      def main():
          # Use the client SDK to communicate with IDT
          client = Client()
          
          # Create an execute on device request
          exec_req = ExecuteOnDeviceRequest(ExecuteOnDeviceCommand("echo 'hello world'"))
          
          # Run the command
          exec_resp = client.execute_on_device(exec_req)
          
          # Print the standard output
          print(exec_resp.stdout)
      
      if __name__ == "__main__":
          main()
      ```

   1. 将测试结果发送给 IDT。

      ```
      from idt_client import *
      
      def main():
          # Use the client SDK to communicate with IDT
          client = Client()
          
          # Create an execute on device request
          exec_req = ExecuteOnDeviceRequest(ExecuteOnDeviceCommand("echo 'hello world'"))
          
          # Run the command
          exec_resp = client.execute_on_device(exec_req)
          
          # Print the standard output
          print(exec_resp.stdout)
      
          # Create a send result request
          sr_req = SendResultRequest(TestResult(passed=True))
           
          # Send the result
          client.send_result(sr_req)
             
      if __name__ == "__main__":
          main()
      ```

# 配置 IDT 的设备信息
<a name="configure-idt-sample2"></a>

配置您的设备信息，以便 IDT 运行测试。您必须使用以下信息，更新位于 `<device-tester-extract-location>/configs` 文件夹中的 `device.json` 模板。

```
[
  {
    "id": "pool",
    "sku": "N/A",
    "devices": [
      {
        "id": "<device-id>",
        "connectivity": {
          "protocol": "ssh",
          "ip": "<ip-address>",
          "port": "<port>",
          "auth": {
            "method": "pki | password",
            "credentials": {
              "user": "<user-name>",
              "privKeyPath": "/path/to/private/key",
              "password": "<password>"
            }
          }
        }
      }
    ]
  }
]
```

在 `devices` 对象中，提供以下信息：

**`id`**  
专属于您设备的用户定义唯一标识符。

**`connectivity.ip`**  
您设备的 IP 地址。

**`connectivity.port`**  
可选。用于通过 SSH 连接到您的设备的端口号。

**`connectivity.auth`**  
连接的身份验证信息。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。    
**`connectivity.auth.method`**  
用于通过给定的连接协议访问设备的身份验证方法。  
支持的值为：  
+ `pki`
+ `password`  
**`connectivity.auth.credentials`**  
用于身份验证的凭证。    
**`connectivity.auth.credentials.user`**  
用于登录您的设备的用户名。  
**`connectivity.auth.credentials.privKeyPath`**  
用于登录您设备的私有密钥的完整路径。  
此值仅在 `connectivity.auth.method` 设置为 `pki` 时适用。  
**`devices.connectivity.auth.credentials.password`**  
该密码用于登录到您的设备。  
此值仅在 `connectivity.auth.method` 设置为 `password` 时适用。

**注意**  
只有当 `method` 设置为 `pki` 时才指定 `privKeyPath`。  
只有当 `method` 设置为 `password` 时才指定 `password`。

# 运行测试套件
<a name="run-test-suite"></a>

创建测试套件后，您需要确保其按预期运行。要使用现有设备池运行测试套件，请完成以下步骤。

1. 将您的 `MyTestSuite_1.0.0` 文件夹复制到 `<device-tester-extract-location>/tests`。

1. 运行以下 命令：

   ```
   cd <device-tester-extract-location>/bin
   ./devicetester_[linux | mac | win_x86-64] run-suite --suite-id MyTestSuite
   ```

IDT 会运行您的测试套件，并将结果流式传输到控制台。测试运行完毕后，您会看到以下信息：

```
time="2020-10-19T09:24:47-07:00" level=info msg=Using pool: pool
time="2020-10-19T09:24:47-07:00" level=info msg=Using test suite "MyTestSuite_1.0.0" for execution
time="2020-10-19T09:24:47-07:00" level=info msg=b'hello world\n' suiteId=MyTestSuite groupId=myTestGroup testCaseId=myTestCase deviceId=my-device executionId=9a52f362-1227-11eb-86c9-8c8590419f30
time="2020-10-19T09:24:47-07:00" level=info msg=All tests finished. executionId=9a52f362-1227-11eb-86c9-8c8590419f30
time="2020-10-19T09:24:48-07:00" level=info msg=

========== Test Summary ==========
Execution Time:         1s
Tests Completed:        1
Tests Passed:           1
Tests Failed:           0
Tests Skipped:          0
----------------------------------
Test Groups:
    myTestGroup:        PASSED
----------------------------------
Path to AWS IoT Device Tester Report: /path/to/devicetester/results/9a52f362-1227-11eb-86c9-8c8590419f30/awsiotdevicetester_report.xml
Path to Test Execution Logs: /path/to/devicetester/results/9a52f362-1227-11eb-86c9-8c8590419f30/logs
Path to Aggregated JUnit Report: /path/to/devicetester/results/9a52f362-1227-11eb-86c9-8c8590419f30/MyTestSuite_Report.xml
```

# 排查错误
<a name="tutorial-troubleshooting"></a>

使用以下信息，以帮助解决在完成本教程时遇到的任何问题。

**测试用例未成功运行**

如果测试运行失败，IDT 会将错误日志流式传输到控制台，以帮助您对测试运行进行故障排除。检查错误日志之前，请验证以下内容：
+ IDT 客户端 SDK 位于[获取 IDT 客户端 SDK](add-idt-sdk.md) 中所述的正确文件夹中。
+ 您已满足本教程的所有先决条件。有关更多信息，请参阅 [设置简单 IDT 测试套件的先决条件](prereqs-tutorial-custom.md)。

**无法连接到被测设备**

请验证以下内容：
+ 您的 `device.json` 文件包含正确的 IP 地址、端口和身份验证信息。
+ 您可以通过 SSH 从主机连接到您的设备。

# 创建 IDT 测试套件配置文件
<a name="idt-json-config"></a>

本节介绍创建配置文件时使用的格式，您在编写自定义测试套件时包含了这些文件。

**必需配置文件**

**`suite.json`**  
包含有关测试套件的信息。请参阅[配置 suite.json](#suite-json)。

**`group.json`**  
包含有关测试组的信息。您必须为测试套件中的每个测试组创建一个 `group.json` 文件。请参阅[配置 group.json](#group-json)。

**`test.json`**  
包含有关测试用例的信息。您必须为测试套件中的每个测试用例创建一个 `test.json` 文件。请参阅[配置 test.json](#test-json)。

**可选配置文件**

**`test_orchestrator.yaml` 或 `state_machine.json`**  
定义 IDT 运行测试套件时如何运行测试。 SSe [配置 test\$1orchestrator.yaml](#test-orchestrator-config)。  
从 IDT v4.5.2 开始，您可以使用 `test_orchestrator.yaml` 文件来定义测试工作流程。在以前版本的 IDT 中，请使用 `state_machine.json` 文件。有关状态机的信息，请参阅[配置 IDT 状态机](idt-state-machine.md)。

**`userdata_schema.json`**  
定义测试运行器可以在其设置配置中包含的[`userdata.json`文件](set-config-custom.md#userdata-config-custom)架构。`userdata.json` 文件用于存储运行测试所需但 `device.json` 文件中不存在的任何其他配置信息。请参阅[配置 userdata\$1schema.json](#userdata-schema-json)。

配置文件放置在您的 `<custom-test-suite-folder>` 中，如下所示。

```
<custom-test-suite-folder>
└── suite
    ├── suite.json
    ├── test_orchestrator.yaml
    ├── userdata_schema.json
    ├── <test-group-folder>
        ├── group.json
        ├── <test-case-folder>
            └── test.json
```

## 配置 suite.json
<a name="suite-json"></a>

`suite.json` 文件设置环境变量并确定运行测试套件是否需要用户数据。使用以下模板来配置您的 `<custom-test-suite-folder>/suite/suite.json` 文件：

```
{
    "id": "<suite-name>_<suite-version>",
    "title": "<suite-title>",
    "details": "<suite-details>",
    "userDataRequired": true | false,
    "environmentVariables": [
        {
            "key": "<name>",
            "value": "<value>",
        },
        ...
        {
            "key": "<name>",
            "value": "<value>",
        }
    ]
}
```

包含值的所有字段都为必填字段，如下所述：

**`id`**  
测试套件的唯一用户定义 ID。`id` 的值必须与 `suite.json` 文件所在的测试套件文件夹的名称相匹配。套件名称和套件版本还必须满足以下要求：  
+ `<suite-name>` 不可以包含下划线。
+ `<suite-version>` 表示为 `x.x.x`，其中 `x` 为数字。
ID 显示在 IDT 生成的测试报告中。

**`title`**  
此测试套件正在测试的产品或功能的用户定义名称。该名称显示在 IDT CLI 中供测试运行器使用。

**`details`**  
测试套件用途的简短描述。

**`userDataRequired`**  
定义测试运行器是否需要在 `userdata.json` 文件中包含自定义信息。如果将此值设置为 `true`，还必须将[`userdata_schema.json` 文件](#userdata-schema-json)包含在测试套件文件夹中。

**`environmentVariables`**  
可选。一组要为此测试套件设置的环境变量。    
**`environmentVariables.key`**  
环境变量的名称。  
**`environmentVariables.value`**  
环境变量的值。

## 配置 group.json
<a name="group-json"></a>

`group.json` 文件定义测试组是必需的还是可选的。使用以下模板来配置您的 `<custom-test-suite-folder>/suite/<test-group>/group.json` 文件：

```
{
    "id": "<group-id>",
    "title": "<group-title>",
    "details": "<group-details>",
    "optional": true | false,
}
```

包含值的所有字段都为必填字段，如下所述：

**`id`**  
测试组的唯一用户定义 ID。`id` 的值必须与 `group.json` 文件所在的测试组文件夹的名称相匹配，并且不得包含下划线 (`_`)。ID 用于 IDT 生成的测试报告中。

**`title`**  
测试组的描述性名称。该名称显示在 IDT CLI 中供测试运行器使用。

**`details`**  
测试组用途的简短描述。

**`optional`**  
可选。设置为 `true` 以便在 IDT 完成运行所需测试后，将此测试组显示为可选组。默认值为 `false`。

## 配置 test.json
<a name="test-json"></a>

`test.json` 文件确定测试用例的可执行文件和测试用例使用的环境变量。有关创建测试用例可执行文件的更多信息，请参阅 [创建 IDT 测试用例可执行文件](test-executables.md)。

使用以下模板来配置您的 `<custom-test-suite-folder>/suite/<test-group>/<test-case>/test.json` 文件：

```
{
    "id": "<test-id>",
    "title": "<test-title>",
    "details": "<test-details>",
    "requireDUT": true | false,
    "requiredResources": [
        {
            "name": "<resource-name>",
            "features": [
                {
                    "name": "<feature-name>",
                    "version": "<feature-version>",
                    "jobSlots": <job-slots>
                }
            ]
        }
    ],
    "execution": {
        "timeout": <timeout>,
        "mac": {
            "cmd": "/path/to/executable",
            "args": [
                "<argument>"
            ],
        },
        "linux": {
            "cmd": "/path/to/executable",
            "args": [
                "<argument>"
            ],
        },
        "win": {
            "cmd": "/path/to/executable",
            "args": [
                "<argument>"
            ]
        }
    },
    "environmentVariables": [
        {
            "key": "<name>",
            "value": "<value>",
        }
    ]
}
```

包含值的所有字段都为必填字段，如下所述：

**`id`**  
测试用例的唯一用户定义 ID。`id` 的值必须与 `test.json` 文件所在的测试用例文件夹的名称相匹配，并且不得包含下划线 (`_`)。ID 用于 IDT 生成的测试报告中。

**`title`**  
测试用例的描述性名称。该名称显示在 IDT CLI 中供测试运行器使用。

**`details`**  
测试用例用途的简短描述。

**`requireDUT`**  
可选。如果需要设备才能运行此测试，则设置为 `true`，否则设置为 `false`。默认值为 `true`。测试运行器将在其 `device.json` 文件中配置将用来运行测试的设备。

**`requiredResources`**  
可选。一个阵列，提供有关运行此测试所需资源设备的信息。    
**`requiredResources.name`**  
运行此测试时为资源设备提供的唯一名称。  
**`requiredResources.features`**  
一系列用户定义的资源设备功能。    
**`requiredResources.features.name`**  
功能的名称。您要使用此设备的设备功能。此名称与 `resource.json` 文件中测试运行器提供的功能名称相匹配。  
**`requiredResources.features.version`**  
可选。功能的版本。此值与 `resource.json` 文件中测试运行器提供的功能版本相匹配。如果未提供版本，则不检查该功能。如果功能不需要版本号，请将此字段留为空白。  
**`requiredResources.features.jobSlots`**  
可选。此功能可以支持的同时测试的数量。默认值为 `1`。如果您希望 IDT 使用不同的设备来实现各项功能，我们建议您将此值设置为 `1`。

**`execution.timeout`**  
IDT 等待测试完成运行的时间长度（以毫秒为单位）。有关设置该值的更多信息，请参阅 [创建 IDT 测试用例可执行文件](test-executables.md)。

**`execution.os`**  
要运行的测试用例可执行文件基于运行 IDT 的主机操作系统。支持的值有`linux`、`mac`和`win`。    
**`execution.os.cmd`**  
要在指定操作系统上运行的测试用例可执行文件的路径。此位置必须位于系统路径中。  
**`execution.os.args`**  
可选。为运行测试用例可执行文件而提供的参数。

**`environmentVariables`**  
可选。一组要为此测试用例设置的环境变量。    
**`environmentVariables.key`**  
环境变量的名称。  
**`environmentVariables.value`**  
环境变量的值。
如果在 `test.json` 文件和 `suite.json` 文件中指定相同的环境变量，则 `test.json` 文件中的值优先。

## 配置 test\$1orchestrator.yaml
<a name="test-orchestrator-config"></a>

测试编排工具是一种控制测试套件执行流程的构造。它决定测试套件的起始状态，根据用户定义的规则管理状态转换，并继续在这些状态之间进行转换，直到达到结束状态。

如果您的测试套件不包含用户定义的测试编排工具，IDT 将为您生成一个测试编排工具。

默认测试编排工具执行以下功能：
+ 使测试运行器能够选择和运行特定的测试组，而不是整个测试套件。
+ 如果未选择特定的测试组，则按随机顺序运行测试套件中的每个测试组。
+ 生成报告并打印控制台摘要，其中显示每个测试组和测试用例的测试结果。

有关 IDT 测试编排工具工作原理的更多信息，请参阅[配置 IDT 测试编排工具](idt-test-orchestrator.md)。

## 配置 userdata\$1schema.json
<a name="userdata-schema-json"></a>

`userdata_schema.json` 文件确定了测试运行器提供用户数据的架构。如果您的测试套件需要 `device.json` 文件中不存在的信息，则需要用户数据。例如，您的测试可能需要 Wi-Fi 网络凭证、特定的开放端口或用户必须提供的证书。此信息可提供给 IDT，作为用户在其 `<device-tester-extract-location>/config` 文件夹中创建的输入参数，称为 `userdata`，其值是一个 `userdata.json` 文件。`userdata.json` 文件的格式取决于您在测试套件中包含的 `userdata_schema.json` 文件。

要指示测试运行器必须提供 `userdata.json` 文件：

1. 在 `suite.json` 文件中设置 `userDataRequired` 为 `true`。

1. 在您的 `<custom-test-suite-folder>` 中，创建一个 `userdata_schema.json` 文件。

1. 编辑 `userdata_schema.json` 文件以创建有效的 [IETF 草稿 v4 JSON 架构](https://json-schema.org/specification-links#draft-4)。

当 IDT 运行您的测试套件时，它会自动读取架构并使用它来验证测试运行器提供的 `userdata.json` 文件。如果有效，则 `userdata.json` 文件的内容在 [IDT 上下文](idt-context.md)和[测试编排工具上下文](idt-test-orchestrator.md#idt-test-orchestrator-context)中均可用。

# 配置 IDT 测试编排工具
<a name="idt-test-orchestrator"></a>

从 IDT v4.5.2 开始，IDT 包括一个新的*测试编排工具*组件。测试编排工具是一个 IDT 组件，用于控制测试套件的执行流程，并在 IDT 完成运行所有测试后生成测试报告。测试编排工具根据用户定义的规则确定测试选择和测试的运行顺序。

如果您的测试套件不包含用户定义的测试编排工具，IDT 将为您生成一个测试编排工具。

默认测试编排工具执行以下功能：
+ 使测试运行器能够选择和运行特定的测试组，而不是整个测试套件。
+ 如果未选择特定的测试组，则按随机顺序运行测试套件中的每个测试组。
+ 生成报告并打印控制台摘要，其中显示每个测试组和测试用例的测试结果。

测试编排工具用于取代 IDT 状态机。我们强烈建议您使用测试编排工具来开发测试套件，而不是使用 IDT 状态机。测试编排工具提供了以下改进功能：
+ IDT 状态机使用命令式格式，而该工具使用声明式格式。这允许您指定要运行哪些测试以及何时运行它们。
+ 管理特定的组处理、报告生成、错误处理和结果跟踪，让您无需手动管理这些操作。
+ 使用 YAML 格式，该格式默认支持注释。
+ 定义相同的工作流程所需的磁盘空间比测试编排工具少 80%。
+ 添加测试前验证，以验证您的工作流程定义不包含不正确的测试 IDs 或循环依赖关系。

## 测试编排工具格式
<a name="idt-test-orchestrator-format"></a>

您可以使用以下模板来配置自己的`custom-test-suite-folder/suite/test_orchestrator.yaml`文件：

```
Aliases:
  string: context-expression

ConditionalTests:
  - Condition: context-expression
    Tests:
      - test-descriptor

Order:
  - - group-descriptor
    - group-descriptor

Features:
  - Name: feature-name
    Value: support-description
    Condition: context-expression
    Tests:
        - test-descriptor
    OneOfTests:
        - test-descriptor
    IsRequired: boolean
```

包含值的所有字段都为必填字段，如下所述：

`Aliases`  
可选。映射到上下文表达式的用户定义字符串。别名允许您生成友好的名称，以便识别测试编排工具配置中的上下文表达式。如果您要创建复杂的上下文表达式或在多个位置使用的表达式，则此功能特别有用。  
您可以使用上下文表达式来存储上下文查询，从而允许您访问其他 IDT 配置中的数据。有关更多信息，请参阅 [在上下文中访问数据](idt-context.md#accessing-context-data)。  

**Example**  
**示例**  

```
Aliases:
    FizzChosen: "'{{$pool.features[?(@.name == 'Fizz')].value[0]}}' == 'yes'"    
    BuzzChosen: "'{{$pool.features[?(@.name == 'Buzz')].value[0]}}' == 'yes'"    
    FizzBuzzChosen: "'{{$aliases.FizzChosen}}' && '{{$aliases.BuzzChosen}}'"
```

`ConditionalTests`  
可选。条件列表以及满足每个条件时运行的相应测试用例。每个条件可以有多个测试用例；但是，您只能将给定测试用例分配给一个条件。  
默认情况下，IDT 会运行任何未分配给此列表中的条件的测试用例。如果您未指定此部分，IDT 将运行测试套件中的所有测试组。  
`ConditionalTests` 列表中的每个项目都包含以下参数：    
`Condition`  
计算结果为布尔值的上下文字符串。如果计算值为 true，IDT 将运行 `Tests` 参数中指定的测试用例。  
`Tests`  
测试描述符列表。  
每个测试描述符使用测试组 ID 和一个或多个测试用例 IDs 来标识要从特定测试组运行的单个测试。测试描述符使用以下格式：  

```
GroupId: group-id
CaseIds: [test-id, test-id] # optional
```

**Example**  
**示例**  
以下示例使用可定义为 `Aliases` 的通用上下文表达式。  

```
ConditionalTests:
    - Condition: "{{$aliases.Condition1}}"
      Tests:
          - GroupId: A
          - GroupId: B
    - Condition: "{{$aliases.Condition2}}"
      Tests:
          - GroupId: D
    - Condition: "{{$aliases.Condition1}} || {{$aliases.Condition2}}"
      Tests:
          - GroupId: C
```

IDT 根据定义的条件选择测试组，如下所示：
+ 如果 `Condition1` 为 true，IDT 将在测试组 A、B 和 C 中运行测试。
+ 如果 `Condition2` 为 true，IDT 将在测试组 C 和 D 中运行测试。

`Order`  
可选。运行测试的顺序。您可以在测试组级别指定测试顺序。如果未指定此部分，IDT 将按随机顺序运行所有适用的测试组。`Order` 的值是组描述符列表的列表。未在 `Order` 中列出的任何测试组都可以与列出的任何其他测试组并行运行。  

每个组描述符列表都包含一个或多个组描述符，并标识每个描述符中指定的组的运行顺序。您可以使用以下格式定义单个组描述符：
+ `group-id` – 现有测试组的组 ID。
+ `[group-id, group-id]` – 可按相对于彼此的任意顺序运行的测试组列表。
+ `"*"` – 通配符。这等同于所有尚未在当前组描述符列表中指定的测试组的列表。

`Order` 的值必须满足以下要求：
+ 您在组 IDs 描述符中指定的测试组必须存在于您的测试套件中。
+ 每个组描述符列表必须包含至少一个测试组。
+ 每个组描述符列表必须包含唯一的组 IDs。不能在单个组描述符中使用重复的测试组 ID。
+ 一个组描述符列表最多可以有一个通配符组描述符。通配符组描述符必须是列表中的第一项或最后一项。

**Example**  
**示例**  
对于包含测试组 A、B、C、D 和 E 的测试套件，以下示例列表显示了指定 IDT 应先运行测试组 A，然后运行测试组 B，然后按任意顺序运行测试组 C、D 和 E 的不同方法。  
+ 

  ```
  Order:
      - - A
        - B
        - [C, D, E]
  ```
+ 

  ```
  Order:
      - - A
        - B
        - "*"
  ```
+ 

  ```
  Order:
      - - A
        - B
      
      - - B
        - C
      
      - - B
        - D
      
      - - B
        - E
  ```

`Features`  
可选。您希望将 IDT 添加到 `awsiotdevicetester_report.xml` 文件中的产品功能列表。如果未指定此部分，则 IDT 不会将任何产品功能添加到报告中。  
产品功能是关于设备可能符合的特定标准的用户定义信息。例如，MQTT 产品功能可以指定设备正确发布 MQTT 消息。在 `awsiotdevicetester_report.xml` 中，根据指定的测试是否通过，将产品功能设置为 `supported`、`not-supported` 或自定义的用户定义值。  
`Features` 列表中的每个项目都包含以下参数：    
`Name`  
特征的名称。  
`Value`  
可选。要在报告中使用的自定义值，而不是 `supported`。如果未指定此值，则根据测试结果，IDT 将特征值设置为 `supported` 或 `not-supported`。如果您使用不同的条件测试相同的功能，则可以在 `Features` 列表中为该特征的各个实例使用自定义值，而 IDT 会将支持条件的特征值串联起来。有关更多信息，请参阅   
`Condition`  
计算结果为布尔值的上下文字符串。如果计算值为 true，IDT 将在运行完测试套件后将该功能添加到测试报告中。如果计算值为 false，则不会将测试包含在报告中。  
`Tests`  
可选。测试描述符列表。必须通过在此列表中指定的所有测试才能支持该功能。  
此列表中的每个测试描述符都使用测试组 ID 和一个或多个测试用例 IDs 来标识要从特定测试组运行的单个测试。测试描述符使用以下格式：  

```
GroupId: group-id
CaseIds: [test-id, test-id] # optional
```
必须为 `Features` 列表中的每个特征指定 `Tests` 或 `OneOfTests`。  
`OneOfTests`  
可选。测试描述符列表。必须通过在此列表中指定的至少一个测试才能支持该功能。  
此列表中的每个测试描述符都使用测试组 ID 和一个或多个测试用例 IDs 来标识要从特定测试组运行的单个测试。测试描述符使用以下格式：  

```
GroupId: group-id
CaseIds: [test-id, test-id] # optional
```
必须为 `Features` 列表中的每个特征指定 `Tests` 或 `OneOfTests`。  
`IsRequired`  
用于定义测试报告中是否需要该功能的布尔值。默认值为 `false`。

## 测试编排工具上下文
<a name="idt-test-orchestrator-context"></a>

测试编排工具上下文是一个只读 JSON 文档，其中包含在执行期间可供测试编排工具使用的数据。测试编排工具上下文只能从测试编排工具访问，其中包含决定测试流程的信息。例如，您可以使用 `userdata.json` 文件中测试运行器配置的信息来确定是否需要运行特定的测试。

测试编排工具上下文使用以下格式：

```
{
    "pool": {
        <device-json-pool-element>
    },
    "userData": {
        <userdata-json-content>
    },
    "config": {
        <config-json-content>
    }
}
```

`pool`  
有关为测试运行选择的设备池的信息。对于选定的设备池，此信息将从 `device.json` 文件中定义的相应顶级设备池阵列元素中检索。

`userData`  
`userdata.json` 文件中的信息

`config`  
`config.json` 文件中的信息

您可以使用 JSONPath 符号查询上下文。状态定义中 JSONPath查询的语法是`{{query}}`。从测试编排工具上下文访问数据时，请确保每个值的计算结果都为字符串、数字或布尔值。

有关使用 JSONPath 符号从上下文访问数据的更多信息，请参阅[使用 IDT 上下文](idt-context.md)。

# 配置 IDT 状态机
<a name="idt-state-machine"></a>

**重要**  
从 IDT v4.5.2 开始，此状态机已弃用。我们强烈建议您使用新的测试编排工具。有关更多信息，请参阅 [配置 IDT 测试编排工具](idt-test-orchestrator.md)。

状态机是一种控制测试套件执行流程的构造。它决定测试套件的起始状态，根据用户定义的规则管理状态转换，并继续在这些状态之间进行转换，直到达到结束状态。

如果您的测试套件不包含用户定义的状态机，IDT 将为您生成状态机。默认状态机执行以下功能：
+ 使测试运行器能够选择和运行特定的测试组，而不是整个测试套件。
+ 如果未选择特定的测试组，则按随机顺序运行测试套件中的每个测试组。
+ 生成报告并打印控制台摘要，其中显示每个测试组和测试用例的测试结果。

IDT 测试套件的状态机必须满足以下条件：
+ 每个状态都对应于 IDT 要采取的操作，例如运行测试组或产品报告文件。
+ 过渡到状态会执行与该状态关联的操作。
+ 每个状态都定义了下一个状态的过渡规则。
+ 结束状态必须为 `Succeed` 或 `Fail`。

## 状态机格式
<a name="state-machine-format"></a>

您可以使用以下模板来配置自己的`<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` 状态。有关有效状态的信息，请参阅[有效状态和状态定义](#valid-states)。

## 有效状态和状态定义
<a name="valid-states"></a>

本节介绍可在 IDT 状态机中使用的所有有效状态的状态定义。以下某些状态支持测试用例级别的配置。但是，除非绝对必要，否则我们建议您在测试组级别而不是测试用例级别配置状态转换规则。

**Topics**
+ [

### RunTask
](#state-runtask)
+ [

### Choice
](#state-choice)
+ [

### Parallel
](#state-parallel)
+ [

### AddProductFeatures
](#state-addproductfeatures)
+ [

### 报告
](#state-report)
+ [

### LogMessage
](#state-logmessage)
+ [

### SelectGroup
](#state-selectgroup)
+ [

### Fail
](#state-fail)
+ [

### Succeed
](#state-succeed)

### RunTask
<a name="state-runtask"></a>

`RunTask` 状态运行测试套件中定义的测试组中的测试用例。

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

包含值的所有字段都为必填字段，如下所述：

**`Next`**  
在当前状态下执行操作后要过渡到的状态的名称。

**`TestGroup`**  
可选。要运行的测试组的 ID。如果未指定此值，则 IDT 将运行测试运行器选择的测试组。

**`TestCases`**  
可选。 IDs 来自中指定组的测试用例数组`TestGroup`。IDT 根据 `TestGroup` 和 `TestCases` 的值确定测试执行行为，如下所示：  
+ 同时指定 `TestGroup` 和 `TestCases` 时，IDT 会运行测试组中的指定测试用例。
+ 如果 `TestCases` 已指定但 `TestGroup` 未指定，IDT 将运行指定的测试用例。
+ 如果 `TestGroup` 已指定但 `TestCases` 未指定，则 IDT 将运行指定测试组中的所有测试用例。
+ 如果未指定 `TestGroup` 或 `TestCases`，IDT 将运行测试运行器从 IDT CLI 中选择的测试组中的所有测试用例。要为测试运行器启用组选择，必须在 `statemachine.json` 文件中同时包含 `RunTask` 和 `Choice` 状态。有关其工作原理的示例，请参阅[状态机示例：运行用户选择的测试组](#allow-specific-groups)。

  有关为测试运行器启用 IDT CLI 命令的更多信息，请参阅 [启用 IDT CLI 命令](test-executables.md#idt-cli-coop)。

**`ResultVar`**  
要与测试运行结果一起设置的上下文变量的名称。如果您没有为指定值，请不要指定此值 `TestGroup`。基于以下内容，IDT 将您在 `ResultVar` 中定义的变量的值设置为 `true` 或 `false`：  
+ 如果变量名称的形式为 `text_text_passed`，则该值设置为第一个测试组中的所有测试均已通过或跳过。
+ 在所有其他情况下，该值设置为所有测试组中的所有测试已通过或跳过。

通常，您将使用`RunTask`状态来指定测试组 ID，而不指定单个测试用例 IDs，这样 IDT 将运行指定测试组中的所有测试用例。在此状态下运行的所有测试用例均按随机顺序并行运行。但是，如果所有测试用例都需要一台设备运行，并且只有一台设备可用，则测试用例将按顺序运行。

**错误处理**

如果任何指定的测试组或测试用例 IDs 无效，则此状态会发出`RunTaskError`执行错误。如果状态遇到执行错误，则它还会将状态机上下文中的 `hasExecutionError` 变量设置为 `true`。

### Choice
<a name="state-choice"></a>

`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` 中定义的状态。表达式字符串从状态机上下文中检索值，然后对它们执行操作以得出布尔值。有关访问状态机上下文的信息，请参阅[状态机上下文](#state-machine-context)。  
**`Choices.Next`**  
如果 `Choices.Expression` 中定义的表达式的评估结果为 `true`，则设置要过渡到的状态的名称。

**错误处理**

在以下情况下，`Choice` 状态可能需要错误处理：
+ 选择表达式中的某些变量在状态机上下文中不存在。
+ 表达式的结果不是布尔值。
+ JSON 查询的结果不是字符串、数字或布尔值。

在这种状态下，不能使用 `Catch` 数据块来处理错误。如果要在状态机遇到错误时停止执行它，则必须将 `FallthroughOnError` 设置为 `false`。但是，建议您将 `FallthroughOnError` 设置为 `true`，并根据您的用例，执行以下操作之一：
+ 如果您正在访问的变量预计在某些情况下不存在，则使用的值 `Default` 和其他 `Choices` 数据块来指定下一个状态。
+ 如果您正在访问的变量应始终存在，则将 `Default` 状态设置为 `Fail`。

### Parallel
<a name="state-parallel"></a>

`Parallel` 状态允许您并行地定义和运行新的状态机。

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

包含值的所有字段都为必填字段，如下所述：

**`Next`**  
在当前状态下执行操作后要过渡到的状态的名称。

**`Branches`**  
要运行的状态机定义阵列。每个状态机定义都必须包含自己的`StartAt`、`Succeed` 和 `Fail` 状态。此阵列中的状态机定义不能引用其自身定义之外的状态。  
由于每个分支状态机共享相同的状态机上下文，因此在一个分支中设置变量然后从另一个分支读取这些变量可能会导致意外行为。

只有在 `Parallel` 运行所有分支状态机之后，该状态才会移动到下一个状态。每种需要设备的状态都将等到设备可用后才运行。如果有多个设备可用，则此状态会并行运行来自多个组的测试用例。如果没有足够的设备可用，则测试用例将按顺序运行。由于测试用例在并行运行时按随机顺序运行，因此可能会使用不同的设备来运行来自同一个测试组的测试。

**错误处理**

确保分支状态机和父状态机都过渡到 `Fail` 状态以处理执行错误。

由于分支状态机不会将执行错误传输到父状态机，因此您不能使用 `Catch` 数据块来处理分支状态机中的执行错误。相反，在共享状态机上下文中使用 `hasExecutionErrors` 值。有关如何执行此操作的示例，请参阅 [状态机示例：并行运行两个测试组](#run-in-parallel)。

### AddProductFeatures
<a name="state-addproductfeatures"></a>

`AddProductFeatures` 状态允许您将产品功能添加到 IDT 生成的 `awsiotdevicetester_report.xml` 文件中。

产品功能是关于设备可能符合的特定标准的用户定义信息。例如，`MQTT` 产品功能可以指定设备正确发布 MQTT 消息。在报告中，根据指定的测试是否通过，将产品功能设置为 `supported`、`not-supported` 或自定义值。



**注意**  
`AddProductFeatures` 状态本身不生成报告。此状态必须过渡到[`Report`状态](#state-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`。

### 报告
<a name="state-report"></a>

`Report` 状态会生成 `suite-name_Report.xml` 和 `awsiotdevicetester_report.xml` 文件。此状态还会将报告流式传输到控制台。

```
{
    "Type": "Report",
    "Next": "<state-name>"
}
```

包含值的所有字段都为必填字段，如下所述：

**`Next`**  
在当前状态下执行操作后要过渡到的状态的名称。

您应始终过渡到测试执行流程即将结束时的 `Report` 状态，以便测试运行器可以查看测试结果。通常，此状态之后的下一个状态是 `Succeed`。

**错误处理**

如果此状态在生成报告时遇到问题，则会发出 `ReportError` 执行错误。

### LogMessage
<a name="state-logmessage"></a>

`LogMessage` 状态生成 `test_manager.log` 文件并将日志消息流式传输到控制台。

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

包含值的所有字段都为必填字段，如下所述：

**`Next`**  
在当前状态下执行操作后要过渡到的状态的名称。

**`Level`**  
创建日志消息的错误级别。如果您指定的级别无效，则此状态会生成一条错误消息并将其丢弃。

**`Message`**  
要记入日志的消息。

### SelectGroup
<a name="state-selectgroup"></a>

`SelectGroup` 状态会更新状态机上下文以指示选择了哪些组。任何后续 `Choice` 状态都使用此状态设置的值。

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

包含值的所有字段都为必填字段，如下所述：

**`Next`**  
在当前状态下执行操作后要过渡到的状态的名称。

**`TestGroups`**  
一组将被标记为选中的测试组。对于此阵列中的每个测试组 ID，`group-id_selected` 变量在上下文中都设置为 `true`。请确保提供有效的测试组， IDs 因为 IDT 不会验证指定的组是否存在。

### Fail
<a name="state-fail"></a>

`Fail` 状态表示状态机未正确执行。这是状态机的结束状态，每个状态机定义都必须包含此状态。

```
{
    "Type": "Fail"
}
```

### Succeed
<a name="state-succeed"></a>

`Succeed` 状态表示状态机已正确执行。这是状态机的结束状态，每个状态机定义都必须包含此状态。

```
{
    "Type": "Succeed"
}
```

## 状态机上下文
<a name="state-machine-context"></a>

状态机上下文是一个只读 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查询的语法是`{{$.query}}`。在某些状态下，您可以将 JSONPath查询用作占位符字符串。IDT 将占位符字符串替换为来自上下文的已评估 JSONPath 查询的值。您可以对占位符使用以下值：
+ `RunTask`状态的 `TestCases` 值。
+ `Expression` 值 `Choice` 状态。

当您访问状态机上下文中的数据时，请确保满足以下条件：
+ JSON 路径必须以 `$.` 开头
+ 每个值的计算结果必须为字符串、数字或布尔值。

有关使用 JSONPath 符号从上下文访问数据的更多信息，请参阅[使用 IDT 上下文](idt-context.md)。

## 执行错误
<a name="execution-errors"></a>

执行错误是状态机在执行状态时遇到的状态机定义中的错误。IDT 在 `test_manager.log` 文件中记录有关每个错误的信息，并将日志消息流式传输到控制台。

您可以使用以下方法来处理执行错误：
+ 在状态定义中添加一个[`Catch` 数据块](#catch)。
+ 在状态机上下文中检查 [`hasExecutionErrors`值](#context)。

### 捕获
<a name="catch"></a>

要使用 `Catch`，请将以下内容添加到您的状态定义中：

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

包含值的所有字段都为必填字段，如下所述：

**`Catch.ErrorEquals`**  
要捕获的错误类型的数组。如果执行错误与其中一个指定值匹配，则状态机将转换为 `Catch.Next` 中指定的状态。有关其产生的错误类型的信息，请参阅每个状态定义。

**`Catch.Next`**  
当前状态遇到与 `Catch.ErrorEquals` 中指定值之一相匹配的执行错误时，设置要过渡到的下一个状态。

捕获数据块按顺序处理，直到匹配。如果没有错误与捕获数据块中列出的错误相匹配，则状态机将继续执行。由于执行错误是由状态定义不正确造成的，因此我们建议您在状态遇到执行错误时过渡到失败状态。

### hasExecutionError
<a name="context"></a>

当某些状态遇到执行错误时，除了发出错误外，它们还会在状态机上下文中将 `hasExecutionError` 值设置为 `true`。您可以使用此值来检测何时发生错误，然后使用 `Choice` 状态将状态机过渡到 `Fail` 状态。

该方式具有以下特征。
+ 状态机不以分配给 `hasExecutionError` 的任何值启动，并且在特定状态设置该值之前，该值不可用。这意味着必须将访问此值的 `Choice` 状态的 `FallthroughOnError` 明确设置为 `false`，以防止在没有发生执行错误时状态机停止。
+ 一旦将其设置为 `true`，`hasExecutionError` 就永远不会设置为 false 或将其从上下文中删除。这意味着该值仅在首次设置为 `true` 时才有用，并且对于所有后续状态，它不会提供有意义的值。
+ `hasExecutionError` 值与处于 `Parallel` 状态的所有分支状态机共享，这可能会导致意想不到的结果，具体取决于访问该值的顺序。

由于这些特性，如果您可以改用捕获数据块，我们不建议您使用此方法。

## 示例状态机
<a name="state-machine-examples"></a>

本部分提供了一些状态机配置示例。

**Topics**
+ [

### 状态机示例：运行单个测试组
](#single-test-group)
+ [

### 状态机示例：运行用户选择的测试组
](#allow-specific-groups)
+ [

### 状态机示例：使用产品功能运行单个测试组
](#run-with-product-features)
+ [

### 状态机示例：并行运行两个测试组
](#run-in-parallel)

### 状态机示例：运行单个测试组
<a name="single-test-group"></a>

该状态机：
+ 运行带有 id `GroupA` 的测试组，该组必须以 `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"
        }
    }
}
```

### 状态机示例：运行用户选择的测试组
<a name="allow-specific-groups"></a>

该状态机：
+ 检查测试运行器是否选择了特定的测试组。状态机不检查特定的测试用例，因为如果不选择测试组，测试运行器就无法选择测试用例。
+ 如果选择了测试组：
  + 在选定的测试组中运行测试用例。为此，状态机不会明确指定处于 `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"
        }
    }
}
```

### 状态机示例：使用产品功能运行单个测试组
<a name="run-with-product-features"></a>

该状态机：
+ 运行测试组 `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"
        }
    }
}
```

### 状态机示例：并行运行两个测试组
<a name="run-in-parallel"></a>

该状态机：
+ 并行运行 `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"
        }
    }
}
```

# 创建 IDT 测试用例可执行文件
<a name="test-executables"></a>

您可以通过以下方式，创建测试用例可执行文件并将其放在测试套件文件夹中：
+ 如果测试套件使用 `test.json` 文件中的参数或环境变量来确定要运行哪些测试，您可以为整个测试套件创建一个测试用例可执行文件，也可为测试套件中的每个测试组分别创建一个测试可执行文件。
+ 对于要基于指定命令运行特定测试的测试套件，您可以为测试套件中的每个测试用例创建一个测试用例可执行文件。

作为测试编写者，您可以决定哪一种方法适合您的用例，并相应地构建测试用例可执行文件。请确保在每个 `test.json` 文件中提供正确的测试用例可执行文件路径，并且指定的可执行文件能够正确地运行。

当所有设备都准备好运行测试用例时，IDT 将会读取以下文件：
+ 所选测试用例的 `test.json` 决定了要启动的进程以及要设置的环境变量。
+ 测试套件的 `suite.json` 决定了要设置的环境变量。

IDT 根据 `test.json` 文件中指定的命令和参数启动所需的测试可执行文件进程，并将必要的环境变量传递给这个进程。

## 使用 IDT 客户端软件开发工具包
<a name="idt-client-sdk"></a>

IDT 客户端 SDKs 允许您使用 API 命令简化在测试可执行文件中编写测试逻辑的方式，这些命令可用于与 IDT 和被测设备交互。IDT 目前提供以下内容： SDKs
+ 适用于 Python 的 IDT 客户端软件开发工具包
+ 适用于 Go 的 IDT 客户端软件开发工具包
+ 适用于 Java 的 IDT 客户端软件开发工具包

 SDKs 它们位于`<device-tester-extract-location>/sdks`文件夹中。创建新的测试用例可执行文件时，您必须将要使用的软件开发工具包复制到包含测试用例可执行文件的文件夹中，并在代码中引用这个软件开发工具包。本节简要描述了可以在测试用例可执行文件中使用的 API 命令。

**Topics**
+ [

### 设备交互
](#api-device-interaction)
+ [

### IDT 交互
](#api-idt-interaction)
+ [

### 主机交互
](#api-host-interaction)

### 设备交互
<a name="api-device-interaction"></a>

通过运行以下命令，您无需实施任何其他设备交互和连接管理功能，即可与被测设备通信。

**`ExecuteOnDevice`**  
允许测试套件在支持 SSH 或 Docker shell 连接的设备上运行 shell 命令。

**`CopyToDevice`**  
允许测试套件将本地文件从运行 IDT 的主机复制到支持 SSH 或 Docker shell 连接的设备上的指定位置。

**`ReadFromDevice`**  
允许测试套件从支持 UART 连接的设备的串行端口进行读取。

**注意**  
由于 IDT 不管理使用上下文中设备访问信息与设备建立的直接连接，因此我们建议在测试用例可执行文件中使用这些设备交互 API 命令。但是，如果这些命令不满足测试用例要求，您可以从 IDT 环境中检索设备访问信息，并使用该信息从测试套件建立与设备的直接连接。  
要建立直接连接，请分别在 `device.connectivity` 和 `resource.devices.connectivity` 字段中检索被测设备和资源设备的信息。有关使用 IDT 上下文的更多信息，请参阅 [使用 IDT 上下文](idt-context.md)。

### IDT 交互
<a name="api-idt-interaction"></a>

您可以通过运行以下命令，使测试套件与 IDT 进行通信。

**`PollForNotifications`**  
允许测试套件检查来自 IDT 的通知。

**`GetContextValue ` 和 `GetContextString`**  
允许测试套件从 IDT 上下文中检索值。有关更多信息，请参阅 [使用 IDT 上下文](idt-context.md)。

**`SendResult`**  
允许测试套件向 IDT 报告测试用例结果。此命令必须在测试套件中每个测试用例结束时进行调用。

### 主机交互
<a name="api-host-interaction"></a>

您可以通过运行以下命令，使测试套件与主机进行通信。

**`PollForNotifications`**  
允许测试套件检查来自 IDT 的通知。

**`GetContextValue` 和 `GetContextString`**  
允许测试套件从 IDT 上下文中检索值。有关更多信息，请参阅 [使用 IDT 上下文](idt-context.md)。

**`ExecuteOnHost`**  
允许测试套件在本地计算机上运行命令，并使 IDT 能够管理测试用例可执行文件的生命周期。

## 启用 IDT CLI 命令
<a name="idt-cli-coop"></a>

IDT CLI `run-suite` 命令提供了多个选项，允许测试运行器自定义测试执行。要允许测试运行器使用这些选项来运行您的自定义测试套件，您需要实施对 IDT CLI 的支持。如果您不实施支持，测试运行器仍然可以运行测试，但是某些 CLI 选项将无法正常运作。为了提供理想的客户体验，我们建议您在 IDT CLI 中实施对以下 `run-suite` 命令参数的支持：

**`timeout-multiplier`**  
指定一个大于 1.0 的值，该值将应用于测试运行期间的所有超时。  
测试运行器可以使用此参数来延长他们想要运行的测试用例的超时时间。测试运行器在其 `run-suite` 命令中指定此参数后，IDT 会使用它来计算 IDT\$1TEST\$1TIMEOUT 环境变量的值，并在 IDT 上下文中设置 `config.timeoutMultiplier` 字段。要支持这个参数，您必须执行以下操作：  
+ 读取 IDT\$1TEST\$1TIMEOUT 环境变量来获取正确计算的超时值，而不是直接使用 `test.json` 文件中的超时值。
+ 从 IDT 上下文中检索 `config.timeoutMultiplier` 值，并将其应用于长时间运行的超时。
有关因超时事件而提前退出的更多信息，请参阅[指定退出行为](#test-exec-exiting)。

**`stop-on-first-failure`**  
指定 IDT 在遇到故障时应当停止运行所有测试。  
测试运行器在其 `run-suite` 命令中指定此参数后，IDT 会在遇到故障时立即停止运行测试。但是，如果测试用例是并行运行的，可能会导致意外的结果。要实施支持，请确保当 IDT 遇到此事件时，您的测试逻辑会指示所有运行中的测试用例停止运行、清理临时资源并向 IDT 报告测试结果。有关失败时提早退出的更多信息，请参阅 [指定退出行为](#test-exec-exiting)。

**`group-id` 和 `test-id`**  
指定 IDT 应当仅运行选定的测试组或测试用例。  
测试运行器可以在 `run-suite` 命令中使用这些参数来指定以下测试执行行为：  
+ 在指定的测试组中运行所有测试。
+ 运行一组来自指定测试组的测试。
为了支持这些参数，测试套件的状态机必须在状态机中包含一组特定的 `RunTask` 和 `Choice` 状态。如果您不使用自定义状态机，默认 IDT 状态机包含了所需的状态，您无需采取其他操作。但是，如果您要使用自定义状态机，则可以将 [状态机示例：运行用户选择的测试组](idt-state-machine.md#allow-specific-groups) 作为示例，在状态机中添加所需的状态。

有关 IDT CLI 命令的更多信息，请参阅 [调试和运行自定义测试套件](run-tests-custom.md)。

## 写入事件日志
<a name="test-exec-logs"></a>

在测试运行期间，您可以通过向 `stdout` 和 `stderr` 发送数据，将事件日志和错误消息写入控制台。有关控制台消息格式的信息，请参阅 [控制台消息格式](idt-review-results-logs.md#idt-console-format)。

IDT 运行完测试套件后，也可以在 `<devicetester-extract-location>/results/<execution-id>/logs` 文件夹下的 `test_manager.log` 文件中找到此信息。

您可以将每个测试用例配置为将其测试运行的日志（包括来自被测设备的日志）写入 `<device-tester-extract-location>/results/execution-id/logs` 文件夹下的 `<group-id>_<test-id>` 文件中。为此，请使用 `testData.logFilePath` 查询从 IDT 上下文中检索日志文件的路径，在该路径上创建一个文件，然后将所需的内容写入这个文件中。IDT 会根据正在运行的测试用例来自动更新路径。如果您选择不为测试用例创建日志文件，则不会为该测试用例生成任何文件。

此外，也可将文本可执行文件设置为按需在 `<device-tester-extract-location>/logs` 文件夹中创建其他日志文件。我们建议您为日志文件名指定唯一的前缀，以避免您的文件被覆盖。

## 向 IDT 报告结果
<a name="test-exec-results"></a>

IDT 将测试结果写入 `awsiotdevicetester_report.xml` 和 `suite-name_report.xml` 文件中。这些报告文件位于 `<device-tester-extract-location>/results/<execution-id>/` 下。两个报告都捕获测试套件执行的结果。有关 IDT 用于这些报告的架构的更多信息，请参阅 [查看 IDT 测试结果和日志](idt-review-results-logs.md)

要在 `suite-name_report.xml` 文件中填充内容，您必须在测试执行结束前使用 `SendResult` 命令向 IDT 报告测试结果。如果 IDT 找不到测试结果，则会针对该测试用例发出错误。以下 Python 摘录显示了用于向 IDT 发送测试结果的命令：

```
request-variable = SendResultRequest(TestResult(result))
client.send_result(request-variable)
```

如果您不通过 API 报告结果，IDT 会在测试构件文件夹中查找测试结果。此文件夹的路径存储在 IDT 上下文中的 `testData.testArtifactsPath` 文件中。在此文件夹中，IDT 将找到的第一个按字母顺序排序的 XML 文件用作测试结果。

如果您的测试逻辑生成 JUnit XML 结果，则可以将测试结果写入 artifacts 文件夹中的 XML 文件中，直接向 IDT 提供结果，而不必解析结果然后使用 API 将其提交给 IDT。

如果使用此方法，请确保您的测试逻辑准确汇总了测试结果，并将结果文件格式化为与 `suite-name_report.xml` 文件相同的格式。IDT 不会对您提供的数据进行任何验证，但以下情况除外：
+ IDT 会忽略 `testsuites` 标签的所有属性。相反，它会从其他报告的测试组结果计算标签属性。
+ `testsuites` 中必须至少存在一个 `testsuite` 标签。

IDT 对所有测试用例使用相同的构件文件夹，并且不会在两次测试运行之间删除结果文件。因此，如果 IDT 读取了错误的文件，此方法也可能会导致错误的报告。我们建议您在所有测试用例中对生成的 XML 结果文件使用相同的名称，以覆盖每个测试用例的结果，并将正确的结果提供给 IDT 使用。您可以在测试套件中使用混合方法来进行报告，即：对某些测试用例使用 XML 结果文件，同时通过 API 提交其他测试用例的结果。但是，我们不建议采用这种方法。

## 指定退出行为
<a name="test-exec-exiting"></a>

将您的文本可执行文件配置为始终以退出代码 0 退出，即使测试用例报告失败或错误结果时也不例外。仅使用非零退出代码来表示测试用例未运行，或者表示测试用例可执行文件无法向 IDT 传达任何结果。当 IDT 收到非零退出代码时，这表示测试用例遇到了阻碍其运行的错误。

在以下事件中，IDT 可能会请求或期望测试用例在完成之前停止运行。您可以使用此信息来配置测试用例可执行文件，以检测测试用例中的每个事件：

****超时****  
当测试用例的运行时间超过 `test.json` 文件中指定的超时值时发生。如果测试运行器使用 `timeout-multiplier` 参数来指定超时乘数，则 IDT 会使用该乘数来计算超时值。  
要检测此事件，请使用 IDT\$1TEST\$1TIMEOUT 环境变量。当测试运行器启动测试时，IDT 会将 IDT\$1TEST\$1TIMEOUT 环境变量的值设置为计算得出的超时值（以秒为单位），并将该变量传递给测试用例可执行文件。您可以读取变量值来设置相应的计时器。

****中断****  
在测试运行器中断 IDT 时发生。例如，按下 Ctrl\$1C。  
终端会将信号传播到所有子进程，因此您只需在测试用例中配置信号处理程序来检测中断信号即可。  
或者，也可以定期轮询 API 以检查 `PollForNotifications` API 响应中 `CancellationRequested` 布尔值的值。当 IDT 收到中断信号时，它会将 `CancellationRequested` 布尔值设置为 `true`。

****首次失败时停止****  
发生的条件为：与当前测试用例并行运行的测试用例失败，并且测试运行器使用了 `stop-on-first-failure` 参数来指定 IDT 应当在遇到任何失败时停止运行。  
要检测此事件，您可以定期轮询 API 以检查 `PollForNotifications` API 响应中 `CancellationRequested` 布尔值的值。如果 IDT 遇到故障并且已配置为在首次失败时停止，它会将 `CancellationRequested` 布尔值设置为 `true`。

发生其中任何一个事件时，IDT 会等待 5 分钟，让当前正在运行的测试用例完成运行。如果所有正在运行的测试用例未能在 5 分钟内退出，IDT 会强制停止它们的每个进程。如果 IDT 没有在进程结束之前收到测试结果，它会将测试用例标记为已超时。作为一种最佳实践，您应确保测试用例在遇到其中一个事件时执行以下操作：

1. 停止运行正常的测试逻辑。

1. 清理所有的临时资源，例如被测设备上的测试构件。

1. 向 IDT 报告测试结果，例如测试失败或错误。

1. 退出。

# 使用 IDT 上下文
<a name="idt-context"></a>

IDT 运行测试套件时，测试套件可以访问一组数据，这些数据可用于确定每个测试的运行方式。这些数据被称为 IDT 上下文。例如，测试运行器在 `userdata.json` 文件中提供的用户数据配置可用于 IDT 环境中的测试套件。

IDT 上下文可以被视为只读 JSON 文档。测试套件可以使用对象、阵列、数字等标准 JSON 数据类型从上下文中检索数据并将数据写入上下文。

## 上下文架构
<a name="idt-context-schema"></a>

IDT 上下文采用以下格式：

```
{
    "config": {
        <config-json-content>
        "timeoutMultiplier": timeout-multiplier,
        "idtRootPath": <path/to/IDT/root>
    },
    "device": {
        <device-json-device-element>
    },
    "devicePool": {
        <device-json-pool-element>
    },
    "resource": {
        "devices": [
            {
                <resource-json-device-element>
                "name": "<resource-name>"
            }
        ]
    },
    "testData": {
        "awsCredentials": {
            "awsAccessKeyId": "<access-key-id>",
            "awsSecretAccessKey": "<secret-access-key>",
            "awsSessionToken": "<session-token>"
        },
        "logFilePath": "/path/to/log/file"
    },
    "userData": {
        <userdata-json-content>
    }
}
```

**`config`**  
[`config.json`文件](set-config-custom.md#config-json-custom)中的信息。`config` 字段还包含以下附加字段：    
**`config.timeoutMultiplier`**  
测试套件使用的任何超时值的乘数。此值由 IDT CLI 中的测试运行器指定。默认值为 `1`。  
**`config.idRootPath`**  
此值是配置 `userdata.json` 文件时 IDT 的绝对路径值的占位符。编译命令和刷写命令会使用此值。

**`device`**  
有关为测试运行选择的设备的信息。此信息等同于所选设备[`device.json`文件](set-config-custom.md#device-config-custom)中的 `devices` 阵列元素。

**`devicePool`**  
有关为测试运行选择的设备池的信息。此信息等同于 `device.json` 文件中为所选设备池定义的顶级设备池阵列元素。

**`resource`**  
`resource.json` 文件中有关资源设备的信息。    
**`resource.devices`**  
此信息等同于 `resource.json` 文件中定义的 `devices` 阵列。每个 `devices` 元素都包括以下附加字段：    
**`resource.device.name`**  
资源的名称。此值设置为 `test.json` 文件中的 `requiredResource.name` 值。

**`testData.awsCredentials`**  
测试用于连接到 AWS 云的 AWS 凭据。此信息是从 `config.json` 文件中获得的。

**`testData.logFilePath`**  
测试用例写入日志消息的日志文件的路径。如果日志文件不存在，则会创建。

**`userData`**  
[`userdata.json`文件](set-config-custom.md#userdata-config-custom)中由测试运行器提供的信息。

## 在上下文中访问数据
<a name="accessing-context-data"></a>

您可以使用配置文件中的 JSONPath 符号以及带有和的文本可执行文件中的符号来查询上下文`GetContextString` APIs。`GetContextValue`用于访问 IDT 上下文的 JSONPath 字符串的语法各不相同，如下所示：
+ 在 `suite.json` 和`test.json` 中，使用 `{{query}}`。也就是说，不要使用根元素 `$.` 开始表达式。
+ 在 `statemachine.json` 中，使用 `{{$.query}}`。
+ 在 API 命令中，根据命令的不同，您可以使用 `query` 或 `{{$.query}}`。有关更多信息，请参阅中的内联文档 SDKs。

下表描述了典型的 foobar JSONPath 表达式中的运算符：


| 运算符  | 说明  | 
| --- | --- | 
| \$1 | 根元素。由于 IDT 的顶级上下文值是一个对象，因此，您通常会使用 \$1. 来启动查询。 | 
| .childName | 使用来自对象的名称 childName 访问子元素。如果应用到数组，则生成一个新数组，并将此运算符应用到每个元素。该元素名称区分大小写。例如，访问 config 对象中 awsRegion 值的查询是 \$1.config.awsRegion。 | 
| [start:end] | 筛选数组中的元素，检索从 start 索引开始直到 end 索引的项目（包括首尾）。 | 
| [index1, index2, ... , indexN] | 筛选数组中的元素，仅从指定索引检索项目。 | 
| [?(expr)] | 使用 expr 表达式筛选数组中的元素。该表达式的计算结果必须为布尔值。 | 

要创建筛选表达式，请使用以下语法：

```
<jsonpath> | <value> operator <jsonpath> | <value> 
```

在此语法中：
+ `jsonpath`是 JSONPath 使用标准 JSON 语法的。
+ `value` 是使用标准 JSON 语法的任何自定义值。
+ `operator` 下列运算符之一：
  + `<`（小于）
  + `<=`（小于或等于）
  + `==`（等于）

    如果表达式中的 JSONPath 或值是数组、布尔值或对象值，则这是您可以使用的唯一支持的二进制运算符。
  + `>=`（大于或等于）
  + `>`（大于）
  + `=~`（正则表达式匹配）。要在筛选表达式中使用此运算符，表达式左侧的 JSONPath 或值必须计算为字符串，而右侧的值必须是遵循该[RE2语法](https://github.com/google/re2/wiki/Syntax)的模式值。

您可以使用 \$1\$1*query*\$1\$1 形式的 JSONPath 查询作为文件`args`和`environmentVariables`字段中的占位符字符串，也可以在`test.json`文件中的字段中使用占位符字符串。`environmentVariables` `suite.json`IDT 执行上下文查找，并使用查询的评估值填充字段。例如，在 `suite.json` 文件中，您可以使用占位符字符串来指定随每个测试用例而变化的环境变量值，IDT 将使用每个测试用例的正确值填充环境变量。但是，当您在 `test.json` 和 `suite.json` 文件中使用占位符字符串时，以下注意事项适用于您的查询：
+ 查询中每次出现的 `devicePool` 密钥都必须全部使用小写字母。也就是说，改用 `devicepool`。
+ 对于数组，只能使用字符串数组。此外，数组使用非标准 `item1, item2,...,itemN` 格式。如果数组仅包含一个元素，则将其序列化为 `item`，使其与字符串字段没有区别。
+ 不能使用占位符从上下文中检索对象。

出于这些考虑，我们建议您尽可能使用 API 来访问测试逻辑中的上下文，而不是 `test.json` 和 `suite.json` 文件中的占位符字符串。但是，在某些情况下，使用 JSONPath 占位符检索要设置为环境变量的单个字符串可能会更方便。

# 为测试运行器配置设置
<a name="set-config-custom"></a>

要运行自定义测试套件，测试运行器必须根据他们要运行的测试套件配置设置。设置是根据位于该 `<device-tester-extract-location>/configs/` 文件夹中的配置文件模板指定的。如果需要，测试运行者还必须设置 IDT 用于连接 AWS 云的 AWS 凭据。

作为测试编写者，您需要配置这些文件来[调试您的测试套件](run-tests-custom.md)。您必须向测试运行器提供说明，以便他们可以根据需要配置以下设置来运行您的测试套件。

## 配置 device.json
<a name="device-config-custom"></a>

`device.json` 文件包含有关运行测试的设备的信息（例如，IP 地址、登录信息、操作系统和 CPU 架构）。

测试运行器可以使用位于 `<device-tester-extract-location>/configs/` 文件夹中的以下模板 `device.json` 文件来提供此信息。

```
[
    {
        "id": "<pool-id>",
        "sku": "<pool-sku>",
        "features": [
            {
                "name": "<feature-name>",             
                "value": "<feature-value>",                
                "configs": [
                    {
                        "name": "<config-name>",                    
                        "value": "<config-value>"
                    }
                ],
            }
        ],     
        "devices": [
            {
                "id": "<device-id>",    
                "pairedResource": "<device-id>", //used for no-op protocol
                "connectivity": {
                    "protocol": "ssh | uart | docker | no-op",                   
                    // ssh
                    "ip": "<ip-address>",
                    "port": <port-number>,
                    "publicKeyPath": "<public-key-path>",
                    "auth": {
                        "method": "pki | password",
                        "credentials": {
                            "user": "<user-name>", 
                            // pki
                            "privKeyPath": "/path/to/private/key",
                                         
                            // password
                            "password": "<password>",
                        }
                    },
                    
                    // uart
                    "serialPort": "<serial-port>",
                    
                    // docker
                    "containerId": "<container-id>",
                    "containerUser": "<container-user-name>",
                }
            }
        ]
    }
]
```

包含值的所有字段都为必填字段，如下所述：

**`id`**  
一个用户定义的字母数字 ID，用于唯一地标识称作*设备池*的设备集合。属于池的设备必须具有相同的硬件。运行一组测试时，池中的设备将用于对工作负载进行并行化处理。多个设备用于运行不同测试。

**`sku`**  
唯一标识所测试设备的字母数字值。该 SKU 用于跟踪符合条件的设备。  
如果您想在 AWS 合作伙伴设备目录中发布您的主板，则在此处指定的 SKU 必须与您在发布过程中使用的 SKU 相匹配。

**`features`**  
可选。包含设备支持的功能的数组。设备功能是您在测试套件中配置的用户定义值。您必须向测试运行器提供有关要包含在 `device.json` 文件中的功能名称和值的信息。例如，如果您想测试一台可充当其他设备的 MQTT 服务器的设备，则可以配置测试逻辑来验证名为 `MQTT_QoS` 的功能的特定支持级别。测试运行器提供此功能名称，并将该功能值设置为其设备支持的 QoS 级别。您可以通过查询从 [IDT 上下文](idt-context.md)中检索所提供的信息，也可以通过`devicePool.features`查询从[状态机上下文](idt-state-machine.md#state-machine-context)中检索所`pool.features`提供的信息。    
**`features.name`**  
功能的名称。  
**`features.value`**  
支持的功能值。  
**`features.configs`**  
该功能的配置设置（如果需要）。    
**`features.config.name`**  
配置设置的名称。  
**`features.config.value`**  
支持的设置值。

**`devices`**  
池中待测试的设备阵列。至少需要选择一个设备。    
**`devices.id`**  
用户定义的测试的设备的唯一标识符。  
**`devices.pairedResource`**  
用户定义的资源设备的唯一标识符。使用 `no-op` 连接协议测试设备时，此值是必需的。  
**`connectivity.protocol`**  
用于与此设备通信的通信协议。池中的每台设备都必须使用相同的协议。  
当前，支持的值只包括适用于物理设备的 `ssh` 和 `uart`、适用于 Docker 容器的 `docker` 以及适用于设备的 `no-op`，这些设备与 IDT 主机没有直接连接，但需要将资源设备作为物理中间件才能与主机通信。  
对于无操作设备，您可以在 `devices.pairedResource` 中配置资源设备 ID。您还必须在 `resource.json` 文件中指定此 ID。已配对的设备必须是与待测设备进行物理配对的设备。IDT 识别并连接到配对的资源设备后，根据 `test.json` 文件中描述的功能，IDT 将不会连接到其他资源设备。  
**`connectivity.ip`**  
测试的设备 IP 地址。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。  
**`connectivity.port`**  
可选。用于 SSH 连接的端口号。  
默认值为 22。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。  
**`connectivity.publicKeyPath`**  
 可选。用于验证待测设备连接的公有密钥的完整路径。如果指定 `publicKeyPath`，IDT 会在与待测设备建立 SSH 连接时验证设备的公有密钥。如果未指定此值，IDT 将创建 SSH 连接，但不验证设备的公有密钥。  
我们强烈建议您指定公有密钥的路径，并使用安全的方法来获取此公有密钥。对于基于标准命令行的 SSH 客户端，`known_hosts` 文件中提供了公有密钥。如果您指定单独的公有密钥文件，则该文件必须使用与 `known_hosts` 文件相同的格式，即 `ip-address key-type public-key`。  
**`connectivity.auth`**  
连接的身份验证信息。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。    
**`connectivity.auth.method`**  
用于通过给定的连接协议访问设备的身份验证方法。  
支持的值为：  
+ `pki`
+ `password`  
**`connectivity.auth.credentials`**  
用于身份验证的凭证。    
**`connectivity.auth.credentials.password`**  
该密码用于登录到正在测试的设备。  
此值仅在 `connectivity.auth.method` 设置为 `password` 时适用。  
**`connectivity.auth.credentials.privKeyPath`**  
用于登录所测试设备的私有密钥的完整路径。  
此值仅在 `connectivity.auth.method` 设置为 `pki` 时适用。  
**`connectivity.auth.credentials.user`**  
用于登录所测试设备的用户名。  
**`connectivity.serialPort`**  
可选。设备所连接的串行端口。  
此属性仅在 `connectivity.protocol` 设置为 `uart` 时适用。  
**`connectivity.containerId`**  
所测试的 Docker 容器的容器 ID 或名称。  
此属性仅在 `connectivity.protocol` 设置为 `docker` 时适用。  
**`connectivity.containerUser`**  
可选。容器内用户对用户的名称。默认值为 Dockerfile 中提供的用户。  
默认值为 22。  
此属性仅在 `connectivity.protocol` 设置为 `docker` 时适用。
要检查测试运行器是否为测试配置了错误的设备连接，可以从状态机上下文中检索 `pool.Devices[0].Connectivity.Protocol`，并将其与 `Choice` 状态下的预期值进行比较。如果使用的协议不正确，则使用 `LogMessage` 状态打印一条消息并过渡到 `Fail` 状态。  
或者，您可以使用错误处理代码来报告错误设备类型的测试失败。

## （可选）配置 userdata.json
<a name="userdata-config-custom"></a>

`userdata.json` 文件包含测试套件所需但 `device.json` 文件中未指定的任何其他信息。此文件的格式取决于测试套件中定义的[`userdata_scheme.json`文件](idt-json-config.md#userdata-schema-json)。如果您是测试编写者，请务必将此信息提供给将运行您编写的测试套件的用户。

## （可选）配置 resource.json
<a name="resource-config-custom"></a>

`resource.json` 文件包含有关将用作资源设备的所有设备的信息。资源设备是测试被测设备的某些功能所需的设备。例如，要测试设备的蓝牙功能，您可以使用资源设备来测试您的设备能否成功连接到该设备。资源设备是可选的，您可以根据需要任意数量的资源设备。作为测试编写者，您可以使用 [test.json 文件](idt-json-config.md#test-json)来定义测试所需的资源设备功能。然后，测试运行器使用 `resource.json` 文件提供具有所需功能的资源设备池。请务必将此信息提供给将运行您编写的测试套件的用户。

测试运行器可以使用位于 `<device-tester-extract-location>/configs/` 文件夹中的以下模板 `resource.json` 文件来提供此信息。

```
[
    {
        "id": "<pool-id>",
        "features": [
            {
                "name": "<feature-name>",             
                "version": "<feature-value>",                
                "jobSlots": <job-slots>
            }
        ],     
        "devices": [
            {
                "id": "<device-id>",              
                "connectivity": {
                    "protocol": "ssh | uart | docker",                   
                    // ssh
                    "ip": "<ip-address>",
                    "port": <port-number>,
                    "publicKeyPath": "<public-key-path>",
                    "auth": {
                        "method": "pki | password",
                        "credentials": {
                            "user": "<user-name>", 
                            // pki
                            "privKeyPath": "/path/to/private/key",
                                         
                            // password
                            "password": "<password>",
                        }
                    },
                    
                    // uart
                    "serialPort": "<serial-port>",
                    
                    // docker
                    "containerId": "<container-id>",
                    "containerUser": "<container-user-name>",
                }
            }
        ]
    }
]
```

包含值的所有字段都为必填字段，如下所述：

**`id`**  
一个用户定义的字母数字 ID，用于唯一地标识称作*设备池*的设备集合。属于池的设备必须具有相同的硬件。运行一组测试时，池中的设备将用于对工作负载进行并行化处理。多个设备用于运行不同测试。

**`features`**  
可选。包含设备支持的功能的数组。此字段中所需的信息在测试套件的 [test.json 文件](idt-json-config.md#test-json)中定义，这些信息用于确定要运行哪些测试以及如何运行这些测试。如果测试套件不需要任何功能，则此字段不是必填字段。    
**`features.name`**  
功能的名称。  
**`features.version`**  
功能版本。  
**`features.jobSlots`**  
用于指明可以同时使用该设备的测试次数的设置。默认值为 `1`。

**`devices`**  <a name="device-array"></a>
池中待测试的设备阵列。至少需要选择一个设备。    
**`devices.id`**  
用户定义的测试的设备的唯一标识符。  
**`connectivity.protocol`**  
用于与此设备通信的通信协议。池中的每台设备都必须使用相同的协议。  
目前，唯一支持的值，对于物理设备为 `ssh` 和 `uart`，对于 Docker 容器为 `docker`。  
**`connectivity.ip`**  
测试的设备 IP 地址。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。  
**`connectivity.port`**  
可选。用于 SSH 连接的端口号。  
默认值为 22。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。  
**`connectivity.publicKeyPath`**  
 可选。用于验证待测设备连接的公有密钥的完整路径。如果指定 `publicKeyPath`，IDT 会在与待测设备建立 SSH 连接时验证设备的公有密钥。如果未指定此值，IDT 将创建 SSH 连接，但不验证设备的公有密钥。  
我们强烈建议您指定公有密钥的路径，并使用安全的方法来获取此公有密钥。对于基于标准命令行的 SSH 客户端，`known_hosts` 文件中提供了公有密钥。如果您指定单独的公有密钥文件，则该文件必须使用与 `known_hosts` 文件相同的格式，即 `ip-address key-type public-key`。  
**`connectivity.auth`**  
连接的身份验证信息。  
此属性仅在 `connectivity.protocol` 设置为 `ssh` 时适用。    
**`connectivity.auth.method`**  
用于通过给定的连接协议访问设备的身份验证方法。  
支持的值为：  
+ `pki`
+ `password`  
**`connectivity.auth.credentials`**  
用于身份验证的凭证。    
**`connectivity.auth.credentials.password`**  
该密码用于登录到正在测试的设备。  
此值仅在 `connectivity.auth.method` 设置为 `password` 时适用。  
**`connectivity.auth.credentials.privKeyPath`**  
用于登录所测试设备的私有密钥的完整路径。  
此值仅在 `connectivity.auth.method` 设置为 `pki` 时适用。  
**`connectivity.auth.credentials.user`**  
用于登录所测试设备的用户名。  
**`connectivity.serialPort`**  
可选。设备所连接的串行端口。  
此属性仅在 `connectivity.protocol` 设置为 `uart` 时适用。  
**`connectivity.containerId`**  
所测试的 Docker 容器的容器 ID 或名称。  
此属性仅在 `connectivity.protocol` 设置为 `docker` 时适用。  
**`connectivity.containerUser`**  
可选。容器内用户对用户的名称。默认值为 Dockerfile 中提供的用户。  
默认值为 22。  
此属性仅在 `connectivity.protocol` 设置为 `docker` 时适用。

## （可选）配置 config.json
<a name="config-json-custom"></a>

`config.json` 文件包含 IDT 的配置信息。通常，测试运行者无需修改此文件，除非提供他们的 IDT AWS 用户凭证和 AWS 区域（可选）。如果提供了具有所需权限的 AWS 证书，则 AWS IoT Device Tester 收集使用情况指标并将其提交给 AWS。这是一项可选功能，用来改进 IDT 功能。有关更多信息，请参阅 [提交 IDT 使用情况指标](idt-usage-metrics.md)。

测试运行者可以通过以下方式之一配置其 AWS 凭证：
+ **凭证文件**

  IDT 使用与 AWS CLI相同的凭证文件。有关更多信息，请参阅[配置和凭证文件](https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html)。

  凭证文件的位置因您使用的操作系统而异：
  + macOS、Linux：`~/.aws/credentials`
  + Windows：`C:\Users\UserName\.aws\credentials`
+ **环境变量**

  环境变量是由操作系统维护且由系统命令使用的变量。在 SSH 会话期间定义的变量在该会话关闭后不可用。IDT 可使用 `AWS_ACCESS_KEY_ID` 和 `AWS_SECRET_ACCESS_KEY` 环境变量来存储 AWS 凭证

  要在 Linux、macOS 或 Unix 上设置这些变量，请使用 **export**：

  ```
  export AWS_ACCESS_KEY_ID=<your_access_key_id>
  export AWS_SECRET_ACCESS_KEY=<your_secret_access_key>
  ```

  要在 Windows 上设置这些变量，请使用 **set**：

  ```
  set AWS_ACCESS_KEY_ID=<your_access_key_id>
  set AWS_SECRET_ACCESS_KEY=<your_secret_access_key>
  ```

要配置 IDT 的 AWS 凭据，测试运行者需要编辑该`<device-tester-extract-location>/configs/`文件夹中`config.json`文件中的`auth`部分。

```
{
    "log": {
        "location": "logs"
    },
    "configFiles": {
        "root": "configs",
        "device": "configs/device.json"
    },
    "testPath": "tests",
    "reportPath": "results",
    "awsRegion": "<region>",
    "auth": {
        "method": "file | environment",
        "credentials": {
            "profile": "<profile-name>"
        }
    }
}
]
```

包含值的所有字段都为必填字段，如下所述：

**注意**  
此文件中的所有路径都是相对于定义的*<device-tester-extract-location>*。

**`log.location`**  
中日志文件夹的路径*<device-tester-extract-location>*。

**`configFiles.root`**  
包含配置文件的文件夹的路径。

**`configFiles.device`**  
`device.json` 文件的路径。

**`testPath`**  
包含测试套件的文件夹的路径。

**`reportPath`**  
IDT 运行测试套件后将包含测试结果的文件夹的路径。

**`awsRegion`**  
可选。测试套件将使用的 AWS 区域。如果未设置，则测试套件将使用每个测试套件中指定的默认区域。

**`auth.method`**  
IDT 用于检索 AWS 凭证的方法。支持的值是用于从凭证文件中检索凭证的 `file`，以及使用环境变量检索凭证的 `environment`。

**`auth.credentials.profile`**  
要从凭证文件中使用的凭证配置文件。此属性仅在 `auth.method` 设置为 `file` 时适用。

# 调试和运行自定义测试套件
<a name="run-tests-custom"></a>

设置[所需的配置](set-config-custom.md)后，IDT 就可以运行您的测试套件了。完整测试套件的运行时取决于硬件和测试套件的组成。作为参考，在 Raspberry Pi 3B 上完成完整的 FreeRTOS 资格认证测试套件大约需要 30 分钟。

在编写测试套件时，您可以使用 IDT 在调试模式下运行测试套件，以便在运行代码之前检查代码或将其提供给测试运行器。

## 在调试模式下运行 IDT
<a name="idt-debug-mode"></a>

由于测试套件依赖于 IDT 来与设备交互、提供上下文和接收结果，因此如果没有任何 IDT 交互，您就无法在 IDE 中简单地调试测试套件。为此，IDT CLI 提供了 `debug-test-suite` 命令，供您用于在调试模式下运行 IDT。运行以下命令以查看 `debug-test-suite` 的可用选项：

```
devicetester_[linux | mac | win_x86-64] debug-test-suite -h
```

当您在调试模式下运行 IDT 时，IDT 实际上并不启动测试套件或运行编排工具；相反，它会与您的 IDE 交互以响应在 IDE 中运行的测试套件所发出的请求，并将日志输出到控制台。IDT 不会超时，而会等待退出，直到手动中断。在调试模式下，IDT 也不运行测试编排工具，也不会生成任何报告文件。要调试测试套件，您必须使用 IDE 来提供 IDT 通常从配置文件中获得的一些信息。务必提供以下信息：
+ 每个测试的环境变量和参数。IDT 不会从 `test.json` 或 `suite.json` 中读取此信息。
+ 用于选择资源设备的参数。IDT 不会从 `test.json` 中读取此信息。

要调试您的测试套件，请完成以下步骤：

1.  创建运行测试套件所需的设置配置文件。例如，如果您的测试套件需要 `device.json`、`resource.json` 和 `user data.json`，请确保根据需要来配置所有测试套件。

1. 运行以下命令将 IDT 置于调试模式，然后选择运行测试需要的所有设备。

   ```
   devicetester_[linux | mac | win_x86-64] debug-test-suite [options]
   ```

   运行此命令后，IDT 会等待来自测试套件的请求，然后响应这些请求。IDT 还会生成 IDT 客户端软件开发工具包案例处理所需的环境变量。

1. 在您的 IDE 中，使用 `run` 或 `debug` 配置来执行以下操作：

   1. 设置 IDT 生成的环境变量的值。

   1. 设置您在 `test.json` 和 `suite.json` 文件中指定的任何环境变量或参数的值。

   1. 根据需要设置断点。

1. 在 IDE 中运行测试套件。

   您可以根据需要多次调试和重新运行测试套件。IDT 在调试模式下不会超时。

1.  完成调试后，请中断 IDT 以退出调试模式。

## 用于运行测试的 IDT CLI 命令
<a name="idt-cli-commands"></a>

以下小节介绍了 IDT CLI 命令。

------
#### [ IDT v4.0.0 ]

**`help`**  <a name="idt-command-help"></a>
列出有关指定命令的信息。

**`list-groups`**  <a name="idt-command-list-groups"></a>
列出给定测试套件中的组。

**`list-suites`**  <a name="idt-command-list-suites"></a>
列出可用的测试套件。

**`list-supported-products`**  
列出您的 IDT 版本的受支持产品（在本例中为 FreeRTOS 版本）和当前 IDT 版本的 FreeRTOS 资格认证测试套件版本。

**`list-test-cases`**  
列出给定测试组中的测试用例。支持以下选项：  
+ `group-id`. 要搜索的测试组。此选项是必需的，必须指定单个组。

**`run-suite`**  
对某个设备池运行一组测试。以下是一些常用的选项：  
+ `suite-id`. 要运行的测试套件版本。如果未指定，IDT 将使用 `tests` 文件夹中的最新版本。
+ `group-id`. 要以逗号分隔的列表形式运行的测试组。如果未指定，IDT 将运行测试套件中的所有测试组。
+ `test-id`. 要以逗号分隔的列表形式运行的测试用例。指定后，`group-id` 必须指定单个组。
+ `pool-id`. 要测试的设备池。如果您在 `device.json` 文件中定义了多个设备池，则测试运行器必须指定一个池。
+ `timeout-multiplier`。将 IDT 配置为使用用户定义的乘数来修改 `test.json` 文件中为测试指定的测试执行超时。
+ `stop-on-first-failure`. 将 IDT 配置为在第一次失败时停止执行。应将此选项与 `group-id` 结合使用来调试指定的测试组。
+ `userdata`。设置包含运行测试套件所需用户数据信息的文件。只有在测试套件的 `suite.json` 文件中 `userdataRequired` 被设置为 true 时，才需要这样做。
有关 `run-suite` 选项的更多信息，请使用 `help` 选项：  

```
devicetester_[linux | mac | win_x86-64] run-suite -h
```

**`debug-test-suite`**  
在调试模式下运行测试套件。有关更多信息，请参阅 [在调试模式下运行 IDT](#idt-debug-mode)。

------

# 查看 IDT 测试结果和日志
<a name="idt-review-results-logs"></a>

本节介绍 IDT 生成控制台日志和测试报告的格式。

## 控制台消息格式
<a name="idt-console-format"></a>

AWS IoT Device Tester 使用标准格式在启动测试套件时向控制台打印消息。以下摘录显示了一个由 IDT 生成的控制台消息示例。

```
[INFO] [2000-01-02 03:04:05]: Using suite: MyTestSuite_1.0.0 executionId=9a52f362-1227-11eb-86c9-8c8590419f30
```

大多数控制台消息都包含以下字段：

**`time`**  
所记录事件的完整 ISO 8601 时间戳。

**`level`**  
所记录事件的消息级别。通常，记录的消息级别为 `info`、`warn` 或 `error`。如果遇到导致其提前退出的预期事件，IDT 会发出 `fatal` 或 `panic` 消息。

**`msg`**  
记录的消息。

**`executionId`**  
当前 IDT 流程的唯一 ID 字符串。此 ID 用于区分各个 IDT 运行。

测试套件生成的控制台消息提供了有关被测设备以及 IDT 运行的测试套件、测试组和测试用例的更多信息。以下摘录显示了从测试套件生成的控制台消息的示例。

```
[INFO] [2000-01-02 03:04:05]: Hello world! suiteId=MyTestSuitegroupId=myTestGroup testCaseId=myTestCase deviceId=my-deviceexecutionId=9a52f362-1227-11eb-86c9-8c8590419f30
```

控制台消息中特定于测试套件的部分包含以下字段：

**`suiteId`**  
当前正在运行的测试套件的名称。

**`groupId`**  
当前正在运行的测试组的 ID。

**`testCaseId`**  
当前正在运行的测试用例的 ID。

**`deviceId`**  
当前测试用例正在使用的被测设备的 ID。

测试摘要包含有关测试套件、每个已运行组的测试结果以及生成的日志和报告文件位置的信息。以下示例显示了测试摘要消息。

```
========== Test Summary ==========
Execution Time:     5m00s
Tests Completed:    4
Tests Passed:       3
Tests Failed:       1
Tests Skipped:      0
----------------------------------
Test Groups:
    GroupA:         PASSED
    GroupB:         FAILED
----------------------------------
Failed Tests:
    Group Name: GroupB
        Test Name: TestB1
            Reason: Something bad happened
----------------------------------
Path to AWS IoT Device Tester Report: /path/to/awsiotdevicetester_report.xml
Path to Test Execution Logs: /path/to/logs
Path to Aggregated JUnit Report: /path/to/MyTestSuite_Report.xml
```

## AWS IoT Device Tester 报告架构
<a name="idt-report"></a>

 `awsiotdevicetester_report.xml` 是一份包含以下信息的签名报告：
+ IDT 版本。
+ 测试套件版本。
+ 用于对报告进行签名的报告签名和密钥。
+ `device.json` 文件中指定的设备 SKU 和设备池名称。
+ 经过测试的产品版本和设备功能。
+ 测试结果的摘要汇总。此信息与 `suite-name_report.xml` 文件中包含的信息相同。

```
<apnreport>
    <awsiotdevicetesterversion>idt-version</awsiotdevicetesterversion>
    <testsuiteversion>test-suite-version</testsuiteversion>
    <signature>signature</signature>
    <keyname>keyname</keyname>
    <session>
        <testsession>execution-id</testsession>
        <starttime>start-time</starttime>
        <endtime>end-time</endtime>
    </session>
    <awsproduct>
        <name>product-name</name>
        <version>product-version</version>
        <features>
            <feature name="<feature-name>" value="supported | not-supported | <feature-value>" type="optional | required"/>
        </features>
    </awsproduct>
    <device>
        <sku>device-sku</sku>
        <name>device-name</name>
        <features>
            <feature name="<feature-name>" value="<feature-value>"/>
        </features>
        <executionMethod>ssh | uart | docker</executionMethod>
    </device>
    <devenvironment>
        <os name="<os-name>"/>
    </devenvironment>
    <report>
        <suite-name-report-contents>
    </report>
</apnreport>
```

`awsiotdevicetester_report.xml` 文件包含一个 `<awsproduct>` 标签，其中包含有关正测试的产品以及在运行测试套件后验证的产品功能的信息。

**`<awsproduct>` 标签中使用的属性**

**`name`**  
所测试的产品的名称。

**`version`**  
所测试的产品的版本。

**`features`**  
验证的功能。标记为 `required` 的功能是测试套件验证设备所必需的。以下代码段演示了此信息在 `awsiotdevicetester_report.xml` 文件中的显示方式。  

```
<feature name="ssh" value="supported" type="required"></feature>
```
标记为 `optional` 的功能不是验证所必需的。以下代码段显示了可选功能。  

```
<feature name="hsi" value="supported" type="optional"></feature>
<feature name="mqtt" value="not-supported" type="optional"></feature>
```

## 测试套件报告架构
<a name="suite-report"></a>

该`suite-name_Result.xml`报告采用 [JUnit XML 格式](https://llg.cubic.org/docs/junit/)。您可以将它集成到持续集成和开发平台，例如 [Jenkins](https://jenkins.io/)、[Bamboo](https://www.atlassian.com/software/bamboo) 等。报告包含测试结果的摘要汇总。

```
<testsuites name="<suite-name> results" time="<run-duration>" tests="<number-of-test>" failures="<number-of-tests>" skipped="<number-of-tests>" errors="<number-of-tests>" disabled="0">
    <testsuite name="<test-group-id>" package="" tests="<number-of-tests>" failures="<number-of-tests>" skipped="<number-of-tests>" errors="<number-of-tests>" disabled="0">
        <!--success-->
        <testcase classname="<classname>" name="<name>" time="<run-duration>"/>
        <!--failure-->
        <testcase classname="<classname>" name="<name>" time="<run-duration>">
            <failure type="<failure-type>">
                reason
            </failure>
        </testcase>
        <!--skipped-->
        <testcase classname="<classname>" name="<name>" time="<run-duration>">
            <skipped>
                reason
            </skipped>
        </testcase>
        <!--error-->
        <testcase classname="<classname>" name="<name>" time="<run-duration>">
            <error>
                reason
            </error>
        </testcase>
    </testsuite>
</testsuites>
```

`awsiotdevicetester_report.xml` 或 `suite-name_report.xml` 中的报告部分列出了运行的测试以及结果。

第一个 XML 标签 `<testsuites>` 包含测试执行情况的摘要。例如：

```
<testsuites name="MyTestSuite results" time="2299" tests="28" failures="0" errors="0" disabled="0">
```

**`<testsuites>` 标签中使用的属性**

**`name`**  
测试套件的名称。

**`time`**  
运行测试套件所用的时间（以秒为单位）。

**`tests`**  
执行的测试数。

**`failures`**  
已运行但未通过的测试数。

**`errors`**  
IDT 无法执行的测试数。

**`disabled`**  
此属性未使用，可以忽略。

如果出现测试失败或错误，则可以通过检查 `<testsuites>` XML 标签来确定失败的测试。`<testsuites>` 标签内的 `<testsuite>` XML 标签显示了测试组的测试结果摘要。例如：

```
<testsuite name="combination" package="" tests="1" failures="0" time="161" disabled="0" errors="0" skipped="0">
```

其格式与 `<testsuites>` 标签类似，但包含一个未使用并可忽略的 `skipped` 属性。在每个 `<testsuite>` XML 标签内部，对于一个测试组，所执行的每个测试都有 `<testcase>` 标签。例如：

```
<testcase classname="Security Test" name="IP Change Tests" attempts="1"></testcase>
```

**`<testcase>` 标签中使用的属性**

**`name`**  
测试的名称。

**`attempts`**  
IDT 执行测试用例的次数。

当测试失败或出现错误时，将会在 `<testcase>` 标签中添加包含用于故障排除的信息的 `<failure>` 或 `<error>` 标签。例如：

```
<testcase classname="mcu.Full_MQTT" name="MQTT_TestCase" attempts="1">
	<failure type="Failure">Reason for the test failure</failure>
	<error>Reason for the test execution error</error>
</testcase>
```

# 提交 IDT 使用情况指标
<a name="idt-usage-metrics"></a>

如果您提供具有所需权限的 AWS 证书，则 AWS IoT Device Tester 会收集使用情况指标并将其提交给 AWS。这是一项可选功能，用来改进 IDT 功能。IDT 将收集以下信息：
+ 用于运行 IDT 的 AWS 账户 ID
+  用于运行测试的 IDT CLI 命令
+ 正在运行的测试套件
+ *<device-tester-extract-location>*文件夹中的测试套件
+ 设备池中配置的设备数量
+ 测试用例名称和运行时间
+ 测试结果信息，例如测试是通过、失败、遇到错误，还是已被跳过
+ 测试的产品功能
+ IDT 退出行为，例如意外退出或提前退出 

 IDT 发送的所有信息也会记录到 `<device-tester-extract-location>/results/<execution-id>/` 文件夹下的 `metrics.log` 文件中。您可以查看日志文件以检查在测试运行期间收集的信息。只有选择了收集使用量指标后，才会生成此文件。

要禁用指标收集，您无需采取其他操作。请不要存储您的 AWS 凭证，如果您确实存储了 AWS 凭据，也不要将`config.json`文件配置为访问它们。

## 注册获取 AWS 账户
<a name="sign-up-for-aws"></a>

如果您没有 AWS 账户，请完成以下步骤来创建一个。

**要注册 AWS 账户**

1. 打开[https://portal.aws.amazon.com/billing/注册。](https://portal.aws.amazon.com/billing/signup)

1. 按照屏幕上的说明操作。

   在注册时，将接到电话或收到短信，要求使用电话键盘输入一个验证码。

   当您注册时 AWS 账户，就会创建*AWS 账户根用户*一个。根用户有权访问该账户中的所有 AWS 服务 和资源。作为最佳安全实践，请为用户分配管理访问权限，并且只使用根用户来执行[需要根用户访问权限的任务](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#root-user-tasks)。

AWS 注册过程完成后会向您发送一封确认电子邮件。您可以随时前往 [https://aws.amazon.com/](https://aws.amazon.com/)并选择 “**我的账户”，查看您当前的账户活动并管理您的账户**。

## 创建具有管理访问权限的用户
<a name="create-an-admin"></a>

注册后，请保护您的安全 AWS 账户 AWS 账户根用户 AWS IAM Identity Center，启用并创建管理用户，这样您就不会使用 root 用户执行日常任务。

**保护你的 AWS 账户根用户**

1.  选择 **Root 用户**并输入您的 AWS 账户 电子邮件地址，以账户所有者的身份登录。[AWS 管理控制台](https://console.aws.amazon.com/)在下一页上，输入您的密码。

   要获取使用根用户登录方面的帮助，请参阅《AWS 登录 用户指南》**中的 [Signing in as the root user](https://docs.aws.amazon.com/signin/latest/userguide/console-sign-in-tutorials.html#introduction-to-root-user-sign-in-tutorial)。

1. 为您的根用户启用多重身份验证（MFA）。

   有关说明，请参阅 I [A *M* 用户指南中的为 AWS 账户 根用户启用虚拟 MFA 设备（控制台）](https://docs.aws.amazon.com/IAM/latest/UserGuide/enable-virt-mfa-for-root.html)。

**创建具有管理访问权限的用户**

1. 启用 IAM Identity Center。

   有关说明，请参阅**《AWS IAM Identity Center 用户指南》中的[启用 AWS IAM Identity Center](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-set-up-for-idc.html)。

1. 在 IAM Identity Center 中，为用户授予管理访问权限。

   有关使用 IAM Identity Center 目录 作为身份源的教程，请参阅《[用户*指南》 IAM Identity Center 目录中的使用默认设置配置AWS IAM Identity Center 用户*访问权限](https://docs.aws.amazon.com//singlesignon/latest/userguide/quick-start-default-idc.html)。

**以具有管理访问权限的用户身份登录**
+ 要使用您的 IAM Identity Center 用户身份登录，请使用您在创建 IAM Identity Center 用户时发送到您的电子邮件地址的登录 URL。

  有关使用 IAM Identity Center 用户[登录的帮助，请参阅*AWS 登录 用户指南*中的登录 AWS 访问门户](https://docs.aws.amazon.com/signin/latest/userguide/iam-id-center-sign-in-tutorial.html)。

**将访问权限分配给其他用户**

1. 在 IAM Identity Center 中，创建一个权限集，该权限集遵循应用最低权限的最佳做法。

   有关说明，请参阅《AWS IAM Identity Center 用户指南》**中的 [Create a permission set](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-started-create-a-permission-set.html)。

1. 将用户分配到一个组，然后为该组分配单点登录访问权限。

   有关说明，请参阅《AWS IAM Identity Center 用户指南》**中的 [Add groups](https://docs.aws.amazon.com//singlesignon/latest/userguide/addgroups.html)。

要提供访问权限，请为您的用户、组或角色添加权限：
+ 中的用户和群组 AWS IAM Identity Center：

  创建权限集合。按照《AWS IAM Identity Center 用户指南》**中[创建权限集](https://docs.aws.amazon.com//singlesignon/latest/userguide/howtocreatepermissionset.html)的说明进行操作。
+ 通过身份提供商在 IAM 中托管的用户：

  创建适用于身份联合验证的角色。按照《IAM 用户指南》**中[针对第三方身份提供商创建角色（联合身份验证）](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_create_for-idp.html)的说明进行操作。
+ IAM 用户：
  + 创建您的用户可以担任的角色。按照《IAM 用户指南》**中[为 IAM 用户创建角色](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_create_for-user.html)的说明进行操作。
  + （不推荐使用）将策略直接附加到用户或将用户添加到用户组。按照《IAM 用户指南》**中[向用户添加权限（控制台）](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_users_change-permissions.html#users_change_permissions-add-console)中的说明进行操作。

## 向 ID AWS T 提供凭证
<a name="idt-metrics-creds"></a>

要允许 IDT 访问您的 AWS 凭证并向其提交指标 AWS，请执行以下操作：

1. 将您的 IAM 用户的 AWS 证书存储为环境变量或存储在证书文件中：

   1. 要使用环境变量，请运行以下命令：

      ```
      AWS_ACCESS_KEY_ID=access-key
      AWS_SECRET_ACCESS_KEY=secret-access-key
      ```

   1. 要使用凭证文件，请将以下信息添加到 `.aws/credentials file:`：

      ```
      [profile-name]
      aws_access_key_id=access-key
      aws_secret_access_key=secret-access-key
      ```

1. 配置 `config.json` 文件的 `auth` 部分。有关更多信息，请参阅 [（可选）配置 config.json](set-config-custom.md#config-json-custom)。