test: add snapshot lifecycle, alias, and cross-db test cases (#47840)

## Summary

- Add 15 new test cases for snapshot feature covering lifecycle edge
cases, alias support, and cross-database restore
- Verify fix for #47578 (DropSnapshot during active restore)
- All tests verified on latest master image
(`master-20260224-091b147e-amd64`)

### New Test Classes

| Class | Tests | Level | Description |
|-------|-------|-------|-------------|
| `TestMilvusClientSnapshotDropInvalid` | +1 | L1 | Drop during active
restore (#47578) |
| `TestMilvusClientSnapshotLifecycle` | +8 | L2/L3 | Collection
lifecycle + snapshot interactions |
| `TestMilvusClientSnapshotAlias` | +6 | L2 | Snapshot ops via
collection aliases |

### Test Details

**Lifecycle tests (L2):**
- Drop target collection during restore
- Rename source collection after snapshot creation
- Create snapshot on collection being restored to
- Restore failure leaves no resource leak
- Concurrent drop of same snapshot (idempotent)
- Create snapshot during drop of source collection
- Cross-database snapshot restore
- Drop and restore race condition (L3)

**Alias tests (L2):**
- Create snapshot via alias → describe shows real collection name
- List snapshots via alias == list via real name
- Restore from alias-created snapshot with data integrity
- List restore jobs via alias on restored collection
- Dropped alias → create snapshot fails with "not found"
- Alter alias retarget → list snapshots reflects new target

## Test plan

- [x] All 14 L1/L2 tests pass on standalone
(master-20260224-091b147e-amd64)
- [x] L3 race test works but may timeout on standalone due to resource
exhaustion

---------

Signed-off-by: zhuwenxing <wenxing.zhu@zilliz.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
zhuwenxing
2026-04-22 16:09:44 +08:00
committed by GitHub
co-authored by Claude Opus 4.7
parent fab6c33dce
commit e91e8825f7
5 changed files with 3930 additions and 1000 deletions
+95
View File
@@ -0,0 +1,95 @@
# tests/Makefile — lint helpers for Python files under tests/.
#
# All targets operate on the *PR-changed* set: files under tests/**/*.py that
# differ between $(BASE_REF) and HEAD (three-dot diff = since merge-base),
# matching the GitHub Actions "Python Lint (tests/)" workflow.
#
# Usage (run from this tests/ directory):
# make lint # ruff check (CI equivalent)
# make format-check # ruff format --check (CI equivalent)
# make ci # lint + format-check
# make lint-fix # ruff check --fix
# make format # ruff format
#
# Variables:
# BASE_REF diff base ref. Auto-detected from the current branch's open PR
# via `gh pr view`. If no PR exists, you MUST set it explicitly,
# e.g.: make ci BASE_REF=origin/master
# RUFF_VERSION ruff version (default: 0.15.11, pinned to .github/workflows/python-lint.yaml)
#
# Requires `uvx` (ships with `uv`). Ruff is fetched & cached on first run.
# Auto-detection requires `gh` authenticated (`gh auth status`).
RUFF_VERSION ?= 0.15.11
RUFF := uvx ruff@$(RUFF_VERSION)
REPO_ROOT := $(shell git rev-parse --show-toplevel)
# Auto-detect the base ref from the current branch's open PR.
# Steps:
# 1. Read the PR URL (always lives under the base repo) and base branch via gh.
# Extract base repo as "<owner>/<name>" from the URL path.
# 2. Find which local remote points to that base repo (must NOT assume "origin"
# — for forks, "upstream" is typically the base; for direct clones, "origin").
# 3. Emit "<remote>/<baseRefName>".
# Empty when no PR exists, no remote matches, or gh is unauthenticated —
# user must then set BASE_REF explicitly.
BASE_REF ?= $(shell \
pr_url=$$(gh pr view --json url -q .url 2>/dev/null); \
base_branch=$$(gh pr view --json baseRefName -q .baseRefName 2>/dev/null); \
if [ -z "$$pr_url" ] || [ -z "$$base_branch" ]; then exit 0; fi; \
base_repo=$$(echo "$$pr_url" | sed -E 's|^https?://[^/]+/([^/]+/[^/]+)/.*|\1|'); \
if [ -z "$$base_repo" ]; then exit 0; fi; \
remote=$$(git -C $(REPO_ROOT) remote -v | awk -v p="$$base_repo" 'index($$2, p) > 0 && $$3=="(fetch)" {print $$1; exit}'); \
if [ -z "$$remote" ]; then exit 0; fi; \
echo "$$remote/$$base_branch")
CHANGED_FILES_CMD = git -C $(REPO_ROOT) diff --name-only --diff-filter=ACMR $(BASE_REF)...HEAD -- 'tests/**/*.py'
.PHONY: help lint format-check ci lint-fix format _require-base-ref
help:
@echo "tests/ Makefile — lint PR-changed *.py using ruff $(RUFF_VERSION)"
@echo
@echo "Targets:"
@echo " make lint ruff check (CI equivalent)"
@echo " make format-check ruff format --check (CI equivalent)"
@echo " make ci lint + format-check"
@echo " make lint-fix ruff check --fix"
@echo " make format ruff format"
@echo
@echo "BASE_REF: auto-detected from the current branch's open PR via 'gh pr view'."
@echo " When no PR exists, you must set it explicitly:"
@echo " make ci BASE_REF=origin/master"
@if [ -n "$(BASE_REF)" ]; then echo; echo "Currently detected: BASE_REF=$(BASE_REF)"; \
else echo; echo "Currently: BASE_REF is unset (no open PR detected)."; fi
_require-base-ref:
@if [ -z "$(BASE_REF)" ]; then \
echo "Error: BASE_REF is not set."; \
echo " No open PR detected for the current branch via 'gh pr view'."; \
echo " Set it explicitly, e.g.:"; \
echo " make $(or $(MAKECMDGOALS),ci) BASE_REF=origin/master"; \
exit 1; \
fi
lint: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) check $$files; fi
format-check: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) format --check --diff $$files; fi
ci: lint format-check
lint-fix: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) check --fix $$files; fi
format: _require-base-ref
@files=$$($(CHANGED_FILES_CMD)); \
if [ -z "$$files" ]; then echo "No changed Python files under tests/ (base: $(BASE_REF))."; \
else cd $(REPO_ROOT) && $(RUFF) format $$files; fi
+35
View File
@@ -108,3 +108,38 @@ $ uv run ruff format --check . # format check only (CI-friendly)
Rules enabled: `E`, `F`, `W`, `I`, `UP`. Target Python version: `3.10`.
#### Lint only PR-changed files (Python Lint CI parity)
The GitHub Actions workflow `.github/workflows/python-lint.yaml` (job
**"Python Lint (tests/) / Ruff (changed files only)"**) runs `ruff check`
and `ruff format --check` against the *changed* `tests/**/*.py` set on
every PR. Running `uv run ruff check .` over the whole tree is too coarse
because the historical contents of many files predate the lint config and
will fail unrelated rules.
To reproduce the CI step locally, use the `Makefile` shipped in this directory:
```shell
$ cd tests/
$ make ci # ruff check + format --check on PR-changed *.py (CI equivalent)
$ make lint-fix # ruff check --fix on PR-changed *.py
$ make format # ruff format on PR-changed *.py
$ make help # show all targets and the detected BASE_REF
```
`BASE_REF` is auto-detected from the current branch's open PR via `gh pr view`:
the PR URL is parsed to discover the base `<owner>/<repo>` and matched against
your local git remotes, producing e.g. `upstream/master`, `upstream/2.x`, or
`origin/main` for direct clones.
If no open PR exists for the branch, you **must** set `BASE_REF` explicitly
(no guessing — a wrong base diffs against unrelated commits):
```shell
$ make ci BASE_REF=upstream/master
```
Requires `uv` (provides `uvx`) and `gh` authenticated against GitHub
(`gh auth status`). The ruff version is pinned in the `Makefile` via
`RUFF_VERSION` to match the workflow.
+34
View File
@@ -108,3 +108,37 @@ $ uv run ruff format --check . # 只检查不修改 (CI 友好)
启用的规则:`E``F``W``I``UP`;目标 Python 版本:`3.10`
#### 仅检查 PR 修改的文件 (与 Python Lint CI 一致)
GitHub Actions workflow `.github/workflows/python-lint.yaml`
job **"Python Lint (tests/) / Ruff (changed files only)"**
只对 PR 修改的 `tests/**/*.py` 文件跑 `ruff check``ruff format --check`
直接对整个 `tests/` 目录执行 `uv run ruff check .` 太粗——很多历史文件早于
当前 lint 配置,会因为无关规则失败。
要在本地复现 CI 这一步,使用本目录下的 `Makefile`
```shell
$ cd tests/
$ make ci # 对 PR 修改文件跑 ruff check + format --check(与 CI 等价)
$ make lint-fix # 对 PR 修改文件跑 ruff check --fix
$ make format # 对 PR 修改文件跑 ruff format
$ make help # 显示所有 target 以及当前自动检测到的 BASE_REF
```
`BASE_REF` 通过 `gh pr view` 从当前分支的开放 PR 中自动检测:
解析 PR URL 得到 base `<owner>/<repo>`,再匹配本地 git remotes
得到形如 `upstream/master``upstream/2.x` 或(直接 clone 主仓库时的)
`origin/main`
如果当前分支没有开放 PR,**必须**显式设置 `BASE_REF`
(不再做猜测——base 选错会 diff 出无关 commit):
```shell
$ make ci BASE_REF=upstream/master
```
需要本地已安装 `uv`(提供 `uvx`)和已认证的 `gh`
`gh auth status`)。Makefile 通过 `RUFF_VERSION` 锁定与
workflow 一致的 ruff 版本。
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff