## Why I’m doing
- Tests often enable temporary configs, create transient objects, or invoke external side-effects. When a test fails mid-way, ad-hoc cleanup embedded in the test body may be skipped, leaving residue that causes flakiness and cross-test interference.
- This change provides a first-class, always-run teardown mechanism that executes after each case, regardless of pass/fail, improving test reliability and isolation, and simplifying test authoring.
## What I’m doing
- Introduce a CLEANUP block to SQL-tester that defines statements to run in tearDown for each case.
- Semantics:
- CLEANUP runs unconditionally in tearDown after each case (pass/fail/timeout).
- Results in CLEANUP are not validated; failures are logged but do not prevent later cleanup steps.
- Existing built-in cleanup (e.g., dropping parsed DATABASE/RESOURCE) still runs; CLEANUP is additive.
- In record mode, the CLEANUP block is preserved in-place in the generated R file.
- Syntax and example:
```sql
-- name: my_case
...
CLEANUP {
-- SQL must end with ';'
DROP TABLE IF EXISTS t1;
DROP DATABASE IF EXISTS db_${uuid0};
-- shell and function are allowed
shell: echo "cleanup ${uuid0}"
function: restore_env("arg1")
} END CLEANUP
```
**Code changes**
- test/README.md
- Document the CLEANUP grammar, usage, semantics, and example.
- test/lib/__init__.py
- Add CLEANUP/END CLEANUP flags.
- test/lib/choose_cases.py
- Parse CLEANUP blocks, collect commands, validate format, include in case model, support variable/uuid replacement, and record block in-place during -r mode.
- test/test_sql_cases.py
- Execute collected CLEANUP commands in tearDown unconditionally; keep record-mode output aligned; ensure built-in database/resource cleanup still runs.
Signed-off-by: PengFei Li <lpengfei2016@gmail.com>