Skip to content

Conversation

@weiliu1031
Copy link
Contributor

@weiliu1031 weiliu1031 commented Jan 15, 2026

issue: #47066, #47067, #47068
related: #44358

Summary

Changes

  1. internal/proxy/task_snapshot.go:

    • Remove empty collection_name validation in listSnapshotsTask.PreExecute
    • Replace simple whitespace check with ValidateSnapshotName() for snapshot name validation
  2. internal/proxy/util.go:

    • Add ValidateSnapshotName() function that reuses standard naming validation
  3. internal/datacoord/snapshot_manager.go:

    • Populate StartTime field in GetRestoreSnapshotJobProgress response
  4. pkg/proto/data_coord.proto:

    • Add start_time field to GetRestoreSnapshotJobProgressResponse
  5. internal/proxy/task_snapshot_test.go:

    • Add comprehensive test cases for new validation logic

Test plan

  • Unit tests added for snapshot name validation
  • Unit tests verify empty collection_name is allowed for list_snapshots
  • Manual testing with Milvus cluster

Signed-off-by: Wei Liu [email protected]

issue: milvus-io#47066, milvus-io#47067, milvus-io#47068
related: milvus-io#44358

- Add standard naming validation for snapshot name in all snapshot
  tasks (create, drop, describe, restore) using ValidateSnapshotName
- Fix list_snapshots() to support empty collection_name for listing
  all snapshots by setting collectionID to 0
- Add start_time field to RestoreSnapshotInfo proto and populate it
  from job.GetStartTs() in buildRestoreInfo
- Add target collection name validation in restoreSnapshotTask
- Add comprehensive unit tests for snapshot name validation

Signed-off-by: Wei Liu <[email protected]>
@sre-ci-robot sre-ci-robot added the size/XXL Denotes a PR that changes 1000+ lines. label Jan 15, 2026
@sre-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: weiliu1031
To complete the pull request process, please assign yanliang567 after the PR has been reviewed.
You can assign the PR to them by writing /assign @yanliang567 in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@gemini-code-assist
Copy link

Summary of Changes

Hello @weiliu1031, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the robustness and usability of Milvus's snapshot management APIs. It addresses several issues by improving validation logic for snapshot and collection names, ensuring consistency across the system. Additionally, it refines the tracking of restore jobs by accurately reporting their start times, providing users with more complete operational insights. These changes collectively lead to a more reliable and predictable snapshot experience.

Highlights

  • Improved list_snapshots() behavior: The API now correctly handles requests with an empty collection_name parameter, allowing it to list snapshots across all collections instead of failing.
  • Enhanced restore job tracking: The get_restore_snapshot_state() API now accurately returns the start_time for restore jobs, providing better visibility into their lifecycle.
  • Stricter snapshot name validation: create_snapshot and drop_snapshot APIs now enforce standard Milvus naming rules for snapshot_name, aligning with collection/partition name validation for consistency and robustness.
  • Added validation for restore_snapshot: The restore_snapshot API now validates both the snapshot name and the target collection name (if provided) using standard naming rules.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@mergify mergify bot added dco-passed DCO check passed. kind/bug Issues or changes related a bug labels Jan 15, 2026
@sre-ci-robot
Copy link
Contributor

[ci-v2-notice]
Notice: New ci-v2 system is enabled for this PR.

To rerun ci-v2 checks, comment with:

  • /ci-rerun-code-check // for ci-v2/code-check
  • /ci-rerun-build // for ci-v2/build
  • /ci-rerun-ut-integration // for ci-v2/ut-integration, will rerun ci-v2/build
  • /ci-rerun-ut-go // for ci-v2/ut-go, will rerun ci-v2/build
  • /ci-rerun-ut-cpp // for ci-v2/ut-cpp
  • /ci-rerun-ut // for all ci-v2/ut-integration, ci-v2/ut-go, ci-v2/ut-cpp, will rerun ci-v2/build
  • /ci-rerun-e2e-arm // for ci-v2/e2e-arm
  • /ci-rerun-e2e-default // for ci-v2/e2e-default

If you have any questions or requests, please contact @zhikunyao.

@mergify
Copy link
Contributor

mergify bot commented Jan 15, 2026

@weiliu1031 Please associate the related issue to the body of your Pull Request. (eg. "issue: #")

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several fixes and improvements related to snapshot management. It adds validation for snapshot names in create, drop, describe, and restore operations, which is a great enhancement for robustness. It also fixes an issue where list_snapshots would not work with an empty collection name, and correctly populates the start_time for restore jobs. The changes are well-implemented and include new unit tests for the validation logic. However, the new validation logic for describeSnapshotTask and restoreSnapshotTask is not covered by tests. I've added a comment to suggest adding these tests.

Comment on lines +648 to +771
// =========================== Validation Tests for Issue #47068 ===========================

func TestCreateSnapshotTask_PreExecute_InvalidName(t *testing.T) {
testCases := []struct {
name string
snapshotName string
expectedErrMsg string
}{
// Empty/whitespace cases
{"empty string", "", "snapshot name should be not empty"},
{"single space", " ", "snapshot name should be not empty"},
{"multiple spaces", " ", "snapshot name should be not empty"},
{"tab character", "\t", "snapshot name should be not empty"},
// Invalid first character
{"starts with number", "123snapshot", "the first character of snapshot name must be an underscore or letter"},
{"starts with special char", "$snapshot", "the first character of snapshot name must be an underscore or letter"},
{"starts with hyphen", "-snapshot", "the first character of snapshot name must be an underscore or letter"},
// Invalid characters in name
{"contains space", "snap shot", "snapshot name can only contain"},
{"contains special char", "snap@shot", "snapshot name can only contain"},
{"contains chinese", "快照test", "the first character of snapshot name must be an underscore or letter"},
// Too long name (exceeds 255 characters)
{"too long name", strings.Repeat("a", 256), "the length of snapshot name must be not greater than limit"},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
task := &createSnapshotTask{
req: &milvuspb.CreateSnapshotRequest{
Name: tc.snapshotName,
DbName: "default",
CollectionName: "test_collection",
},
}

err := task.PreExecute(context.Background())

assert.Error(t, err)
assert.Contains(t, err.Error(), tc.expectedErrMsg)
})
}
}

func TestDropSnapshotTask_PreExecute_InvalidName(t *testing.T) {
testCases := []struct {
name string
snapshotName string
expectedErrMsg string
}{
// Empty/whitespace cases
{"empty string", "", "snapshot name should be not empty"},
{"single space", " ", "snapshot name should be not empty"},
// Invalid first character
{"starts with number", "123snapshot", "the first character of snapshot name must be an underscore or letter"},
// Invalid characters
{"contains space", "snap shot", "snapshot name can only contain"},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
task := &dropSnapshotTask{
req: &milvuspb.DropSnapshotRequest{
Name: tc.snapshotName,
},
}

err := task.PreExecute(context.Background())

assert.Error(t, err)
assert.Contains(t, err.Error(), tc.expectedErrMsg)
})
}
}

func TestCreateSnapshotTask_PreExecute_ValidName(t *testing.T) {
testCases := []struct {
name string
snapshotName string
}{
{"simple name", "snapshot"},
{"with underscore prefix", "_snapshot"},
{"with numbers", "snapshot123"},
{"mixed", "_snap_shot_123"},
{"uppercase", "Snapshot"},
{"with dollar sign", "snapshot$test"}, // $ is allowed by default config
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
task := &createSnapshotTask{
req: &milvuspb.CreateSnapshotRequest{
Name: tc.snapshotName,
DbName: "default",
CollectionName: "test_collection",
},
}

// Mock globalMetaCache
globalMetaCache = &MetaCache{}
mockGetCollectionID := mockey.Mock((*MetaCache).GetCollectionID).Return(int64(100), nil).Build()
defer mockGetCollectionID.UnPatch()

err := task.PreExecute(context.Background())

assert.NoError(t, err)
})
}
}

// =========================== Test for Issue #47066 ===========================

func TestListSnapshotsTask_PreExecute_EmptyCollectionName(t *testing.T) {
task := &listSnapshotsTask{
req: &milvuspb.ListSnapshotsRequest{
DbName: "default",
CollectionName: "", // Empty collection name should list all snapshots
},
}

err := task.PreExecute(context.Background())

assert.NoError(t, err)
assert.Equal(t, int64(0), task.collectionID) // collectionID should be 0 for listing all
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new validation logic for createSnapshotTask and dropSnapshotTask is well-tested. However, the PR also adds similar validation to describeSnapshotTask and restoreSnapshotTask, but there are no corresponding tests for these tasks. To ensure the validation works as expected across all snapshot operations, please add tests for invalid snapshot names for describeSnapshotTask and restoreSnapshotTask as well. You can follow the pattern of TestCreateSnapshotTask_PreExecute_InvalidName.

@codecov
Copy link

codecov bot commented Jan 15, 2026

Codecov Report

❌ Patch coverage is 53.33333% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.41%. Comparing base (a66efdd) to head (145c180).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
internal/proxy/task_snapshot.go 48.14% 14 Missing ⚠️

❌ Your patch check has failed because the patch coverage (53.33%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.
❌ Your project check has failed because the head coverage (76.41%) is below the target coverage (77.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #47096      +/-   ##
==========================================
- Coverage   76.54%   76.41%   -0.14%     
==========================================
  Files        2016     2016              
  Lines      326966   326365     -601     
==========================================
- Hits       250278   249383     -895     
- Misses      68716    68980     +264     
- Partials     7972     8002      +30     
Components Coverage Δ
Client 75.68% <ø> (ø)
Core 82.95% <ø> (ø)
Go 74.73% <53.33%> (-0.21%) ⬇️
Files with missing lines Coverage Δ
internal/datacoord/snapshot_manager.go 43.20% <100.00%> (+0.09%) ⬆️
internal/proxy/util.go 78.97% <100.00%> (+0.01%) ⬆️
internal/proxy/task_snapshot.go 45.77% <48.14%> (+0.43%) ⬆️

... and 31 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-passed DCO check passed. kind/bug Issues or changes related a bug size/XXL Denotes a PR that changes 1000+ lines.

Projects

None yet

2 participants