## Background link

See https://pingcap.feishu.cn/wiki/IZ3iw0H0liZXOdksGQKcpPSinsd

## Design details

The whole e2e test is built by two parts -- `cases` and `envs`.

`Cases` are real test cases defined in `e2e/cases`. All `cases` should be readonly which means `cases` should not "change" the `env` so that they can be run in parallel in a specified `env`.

`Envs` are built in a DAG order. They are defined in `e2e/env`.

Now we have defined these `env`:

- [AWS:Config]: config for test in aws
- [AWS:Network]: create a new network or reuse an existing one
- [AWS:EndUser]: create a peered vpc for end user action(e.g. ping tidb)
- [AWS:Cluster]: create a tidb cluster
- [GCP:Config]: config for test in gcp
- [GCP:Network]: create a new network or reuse an existing one
- ...

## How to run it

```
make -C tests
```

Now we should run this to clean whole env.(TODO: It will be auto cleaned soon.)

```
make -C tests clean
```

## How to add a new case

### Define a new struct

```
type NewTestCase struct {
    ...
}
```

Optional: define some vars from env

```
type NewTestCase struct {
    VarFromParent string
}
```

The var with same name in env can be auto injected by framework.(TODO: inject var by field tag)

### Write `Test` func

```
func (c *NewTestCase) Test(t *testing.T) {
    ...
}
```

The `Test` should have no side effect. If some create or update actions are necessary, defining a new env is more reasonable.

A pure test case can be easily reused in differnet env and run in parallel. And a complex test case can be separated into many smaller cases.

### Return envs where this case will run

```
func (c *NewTestCase) Envs() []string {
    ...
}
```

### Register this case

```
func init() {
    suite.AddCase(
		label.New[dag.Case](&NewTestCase{}, "this is a new test case", label.NewLabel("key1", "val1"), label.NewLabel("key2", "val2")),
    )
}
```
