- [维护元信息](#维护元信息)
  - [待测集群的版本号](#待测集群的版本号)
  - [ARM64](#arm64)
  - [测试计划回收站](#测试计划回收站)
- [编写测试计划](#编写测试计划)
  - [YAML](#yaml)
  - [tpl.jsonnet](#tpljsonnet)
  - [ARM64](#arm64-1)
- [更新测试计划](#更新测试计划)
- [测试计划调度策略](#测试计划调度策略)
  - [主干分支](#主干分支)
  - [发版分支](#发版分支)
  - [Hotfix 分支](#hotfix-分支)
  - [Feature 分支](#feature-分支)
- [镜像](#镜像)

## 维护元信息

根目录下存在一个名为 meta.yaml 的配置文件, 用于进行测试计划的相关配置.

> whitelist 和 blacklist 不能同时配置. 根据分支的类型（见后文）选择进行配置.

* whitelist: 白名单配置, 用于生效测试计划。非在白名单中的任务不会被日常调度. 只在非主干分支起作用.
* blacklist: 黑名单配置, 用于失效测试计划。在黑名单中的任务不会被日常调度. 只在主干分支起作用.
* release: 发版白名单配置.
* parameters: 公共变量, 可在测试计划文件中被引用, 例如: `{{meta.parameters.base_image_version}}` 会被替换成 `master`
* resourcePool: 在 CI 提交时，用于覆盖 plan 本身设置的 resourcePool 字段.


```yaml
# only take effect on ghp submit, not working on `tcctl run`
resourcePool:
  - resourcePool: default # 默认用 default 资源池
  - path: transaction/    # 对于 transaction/ 目录下, 使用 test-store 资源池
    resourcePool: test-store
  - path: perftest/       # perftest/ 目录保持 plan 里头配置的资源池不改变
    action: KEEP
whitelist:
    - test-infra/test-infra-001.daily.yaml
#blacklist:
#    - test-infra/test-infra-002.daily.yaml
parameters:
  base_image_version: master
  tiup_target_version: nightly
  ...
```

### 待测集群的版本号

test-plan 采用多分支模式管理不同的 TiDB 版本以及 release 分支的测试计划，不同的分支下的测试计划对应于不同 TiDB 版本的测试，因此需要在测试计划中获取到`待测集群的版本号`。

集群版本号也是通过引用 parameters 定义的变量来传递的，这里定义了两个版本号，分别对应 TIDB_CLUSTER 类型（后端是 tidb-operator 部署的集群） 以及 TiUP 部署的 tidb 集群的版本信息。

* 对于 TIDB_CLUSTER 类型的，请引用 `{{meta.parameters.base_image_version}}` 到测试计划的 testbed 声明中。
* 对于 TiUP 部署的 tidb 集群，引用 `{{meta.parameters.tiup_target_version}}` 到测试计划中。

### ARM64

ARM64 的元信息由名为 meta-arm64.yaml 的配置文件单独配置, 其格式和 meta.yaml 类似.

test-infra 会检索每一个测试计划中使用的镜像是否能够运行在 arm64 架构下, 对于不支持的镜像会在 CI 中进行警告.

此外 test-infra 在索引每个测试计划过程中, 会自动变更执行计划执行的资源池为 arm64, 以保证测试计划能够正常运行.

### 测试计划回收站

在 meta.yaml 以及 meta-arm64.yaml 中, 提供了一个名为 `recycle_bin` 的字段, 用于将无法正常执行的测试计划暂存到其中, 用于让其他测试计划顺利通过 CI 的校验并提交到 test-infra 上.

回收站可用于以下目的, 其他目的请谨慎使用回收站:

* 在 meta-arm64.yaml 中暂存无法运行在 arm64 架构下的测试计划
* 暂存目前没有时间修复的测试计划

```yaml
recycle_bin:
- data-platform/cdc/cdc_only_upgrade_sync.yaml # testbed name `cdc_version` that refers on the step[cdc-only-upgrade-sync] isn't defined on the testbed
```

## 编写测试计划

### YAML

Yaml 格式能够满足大多数场景的测试计划的编写，其基本形式如下。

<details>
  <summary>展开</summary>

  ```yaml
  apiVersion: api/v1
  kind: Plan
  name: test_infra_tidb_001
  type: GITHUB
  schedule: "@daily"
  tags: []
  testbed:
    generateName: test-infra-
    items:
    - name: tc
      type: TIDB_CLUSTER
      spec:
          ...
  steps:
  - name: test-infra-001
    caseName: test_infra_001
    arguments:
    - name: tc
      value: "{{testbed.tc}}"
  failFast: false
  ```
</details>

### tpl.jsonnet

> jsonnet 入门参考 https://jsonnet.org/

对于需要根据参数动态生成测试计划等复杂场景, 提供 tpl.jsonnet 文件后缀格式以动态生成测试计划。

tpl.jsonnet 求值的结果必须为单个 test-plan json 对象或者 json 数组。


<details>
  <summary>展开</summary>

  以升级测试为例，升级测试是多条路径进行的，每一条路径由一个二元组 (source, target) 表示以 source_version 作为初始版本，升级到 target 版本。则可以在 meta.yaml 里头配置一个参数：

  ```yaml
  parameters:
      upgrade_strategy: |
          versions: [v4.0.0,v4.0.16,v5.0.0,v5.0.6,v5.1.0,v5.1.4,v5.2.1,v5.2.3,v5.3.0,v5.4.0]
  ```

  并编写如下 tpl.jsonnet 文件:

  ```jsonnet
  local upgrade_strategy = std.parseYaml("{{meta.parameters.upgrade_strategy}}");

  local gen_upgrade_plans(source, target) =
    local plan_name = "upgrade_test_" + source + "-" + target;
    std.parseYaml(|||
      apiVersion: api/v1
      kind: Plan
      name: %(plan_name)s
      type: GITHUB
      schedule: "@daily"
      tags: []
      testbed:
      ...
  ||| % {
    source: source,
    target: target,
    plan_name: plan_name,
    }
  );

  local lower_version(left, right) = 
    if left == "master" then
      false
    else if right == "master" then
      true
    else left < right
  ;
  
  local current_version = "{{meta.parameters.base_image_version}}";
  
  [ gen_upgrade_plans(source, current_version) for source in upgrade_strategy["versions"] if lower_version(source, current_version) ] +
  [ gen_upgrade_plans(current_version, target) for target in upgrade_strategy["versions"] if lower_version(current_version, target) ]
  ```

</details>

### ARM64

## 更新测试计划

⚠ 本 repo 下的分支和 TiDB 的发版分支是相互对应的，因此除管理员外**不应**在该 repo 下直接创建或推送一个新分支，应基于 fork 的 repo 进行修改，最后提交一个 PR 到该 repo 下。

<details>
  <summary>展开</summary>

  ```text
  # 添加 upstream remote
  git remote add upstream https://github.com/pingcap/test-plan.git

  # 拉取 upstream 上的所有分支
  git fetch upstream

  # 合并 upstream main 的内容到本地
  git rebase upstream/main

  # 创建一个新的分支 XXX 用于提交 PR
  git checkout -b XXX

  修改..., 最后选择要提交的修改

  # 提交

  git commit -sm "xxx"

  git push --set-upstream origin XXX
  ```
</details>


## 测试计划调度策略

### 主干分支

master 分支采用黑名单机制, 不能跑的测试计划需要加到黑名单中。

不在黑名单里的根据测试计划中的 `schedule` 的设定来运行:

* `schedule: @daily`: 每天调度一次
* `schedule: @weekly`: 每周调度一次
* `schedule: '0 0 * * 1,3,5'`: 每周一、三、五调度一次
* `schedule: '0 0 * * 2,4,6'`: 每周二、四、六调度一次
* `schedule: ''`: 或者不设置 schedule: 不调度

**`schedule` 暂不支持其他 cron 表达式**

meta.yaml

```yaml
blacklist:
    - "test-infra/test-infra-001.daily.yaml"
    - "test-infra/test-infra-002.daily.yaml"
```

### 发版分支

发版分支例如 release-4.0, release-5.0, release-5.1 是从主干分支切出来的, 并且不会再 merge 会主干。 和 master 不同的是, 发版分支不会周期性被调度。在发版测试时去触发，根据 meta.yaml 中 release 白名单列表过滤出需要调度的。

### Hotfix 分支

Hotfix 分支从发版分支切出来, 大致上和发版分支相同。

### Feature 分支

Feature 分支从主分支切出来，当开发完成之后，会合并到主分支中。需要 daily run，但是通常只需要运行新增的用例。

因此采用白名单方式来控制 daily run 的任务。

meta.yaml

```yaml
whitelist:
    - "test-infra/test-infra-001.daily.yaml"
    - "test-infra/test-infra-002.daily.yaml"
```

当 feature 分支需要合并到主分支时, 因为 meta.yaml 有更变(main 是黑名单机制, feature 是白名单机制), 因此必须要先 rebase 一下 main 的 meta.yaml。 此时, 白名单设置被移除,
feature 分支不会再被 daily run。

## 镜像

目前同步了一下官网的镜像到内部站点 hub.pingcap.net/qa 上, 如需更多，请联系 @mahjonp

> 高亮显示的 tag 表示构建为 multi-arch, 可以同时在 amd64 和 arm64 测试计划中使用。

> 下表可以通过 `bash hacks/image_stats.sh` 进行更新


| tag | amd64 support component | arm64 support component |
| --- |  --- |  --- |
|v4.0.0|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.1|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.10|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.11|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.12|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.13|  tidb tikv pd tiflash ticdc tidb-binlog | |
|`v4.0.14`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v4.0.15`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v4.0.16`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|v4.0.2|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.3|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.4|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.5|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.6|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.7|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.8|  tidb tikv pd tiflash ticdc tidb-binlog | |
|v4.0.9|  tidb tikv pd tiflash ticdc tidb-binlog | |
|`v5.0.0`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.0.1`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.0.2`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.0.3`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.0.4`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.0.5`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.0.6`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.1.0`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.1.1`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.1.2`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.1.3`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.1.4`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.2.0`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.2.1`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.2.2`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.2.3`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.3.0`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.3.1`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v5.4.0`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |
|`v6.0.0`|  tidb tikv pd tiflash ticdc tidb-binlog dumpling | tidb tikv pd tiflash ticdc tidb-binlog dumpling |

| dm amd64 |
| --- |
|hub.pingcap.net/qa/dm:v2.0.0|
|hub.pingcap.net/qa/dm:v2.0.1|
|hub.pingcap.net/qa/dm:v2.0.2|
|hub.pingcap.net/qa/dm:v2.0.3|
|hub.pingcap.net/qa/dm:v2.0.4|
|hub.pingcap.net/qa/dm:v2.0.5|
|hub.pingcap.net/qa/dm:v2.0.6|
|hub.pingcap.net/qa/dm:v2.0.7|
|hub.pingcap.net/qa/dm:v5.3.0|
|hub.pingcap.net/qa/dm:v5.4.0|
|hub.pingcap.net/qa/dm:v6.0.0|