-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent pruning and reaping of TaggedVersion jobs #23983
Changes from 4 commits
d37b004
94674a7
63caddf
bb1b5d2
201b9db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2901,6 +2901,111 @@ func TestStateStore_DeleteJobTxn_BatchDeletes(t *testing.T) { | |
require.Equal(t, deletionIndex, index) | ||
} | ||
|
||
// TestStatestore_JobTaggedVersion tests that job versions which are tagged | ||
// do not count against the configured server.job_tracked_versions count, | ||
// do not get deleted when new versions are created, | ||
// and *do* get deleted immediately when its tag is removed. | ||
func TestStatestore_JobTaggedVersion(t *testing.T) { | ||
ci.Parallel(t) | ||
|
||
state := testStateStore(t) | ||
|
||
job := mock.MinJob() | ||
job.Stable = true | ||
|
||
// add job and fill the versions bucket | ||
state.config.JobTrackedVersions = 5 | ||
for range state.config.JobTrackedVersions { | ||
must.NoError(t, state.UpsertJob(structs.MsgTypeTestSetup, nextIndex(state), nil, job.Copy())) | ||
} | ||
|
||
// tag versions 0-2 | ||
for x := range 3 { | ||
v := uint64(x) | ||
name := fmt.Sprintf("v%d", x) | ||
desc := fmt.Sprintf("version %d", x) | ||
|
||
// apply tag | ||
must.NoError(t, state.UpdateJobVersionTag(nextIndex(state), job.Namespace, &structs.JobApplyTagRequest{ | ||
JobID: job.ID, | ||
Name: name, | ||
Tag: &structs.JobTaggedVersion{ | ||
Name: name, | ||
Description: desc, | ||
}, | ||
Version: v, | ||
})) | ||
|
||
// confirm | ||
got, err := state.JobVersionByTagName(nil, job.Namespace, job.ID, name) | ||
must.NoError(t, err) | ||
must.Eq(t, name, got.TaggedVersion.Name) | ||
must.Eq(t, desc, got.TaggedVersion.Description) | ||
} | ||
|
||
// take a little detour to test error conditions with the setup so far | ||
t.Run("errors", func(t *testing.T) { | ||
// job does not exist | ||
err := state.UpdateJobVersionTag(nextIndex(state), job.Namespace, &structs.JobApplyTagRequest{ | ||
JobID: "non-existent-job", | ||
Tag: &structs.JobTaggedVersion{Name: "tag name"}, | ||
Version: 0, | ||
}) | ||
must.ErrorContains(t, err, `job "non-existent-job" version 0 not found`) | ||
|
||
// version does not exist | ||
err = state.UpdateJobVersionTag(nextIndex(state), job.Namespace, &structs.JobApplyTagRequest{ | ||
JobID: job.ID, | ||
Tag: &structs.JobTaggedVersion{Name: "tag name"}, | ||
Version: 999, | ||
}) | ||
must.ErrorContains(t, err, fmt.Sprintf("job %q version 999 not found", job.ID)) | ||
|
||
// tag name already exists | ||
err = state.UpdateJobVersionTag(nextIndex(state), job.Namespace, &structs.JobApplyTagRequest{ | ||
JobID: job.ID, | ||
Tag: &structs.JobTaggedVersion{Name: "v0"}, | ||
Version: 3, | ||
}) | ||
must.ErrorContains(t, err, fmt.Sprintf(`"v0" already exists on a different version of job %q`, job.ID)) | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's hard to tell because the PRs for this feature have been running for a while now, but don't we already have test assertions for these state store methods in the PR that introduced them? Re-testing them doesn't seem useful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah it's a bit tricky to hold it all in mind, but I don't believe any of the parent branches/PRs have any test coverage at this layer (I don't see |
||
|
||
// make some more jobs; they should replace 3-4 but leave 0-2 alone | ||
for range 10 { | ||
must.NoError(t, state.UpsertJob(structs.MsgTypeTestSetup, nextIndex(state), nil, job.Copy())) | ||
} | ||
|
||
assertVersions := func(t *testing.T, expect []uint64) { | ||
t.Helper() | ||
jobs, err := state.JobVersionsByID(nil, job.Namespace, job.ID) | ||
must.NoError(t, err) | ||
vs := make([]uint64, len(jobs)) | ||
for i, j := range jobs { | ||
vs[i] = j.Version | ||
} | ||
must.Eq(t, expect, vs) | ||
} | ||
|
||
// there should be this many: JobTrackedVersions + # of tagged versions | ||
// we tagged 3 of them, so 5 + 3 = 8 | ||
assertVersions(t, []uint64{14, 13, 12, 11, 10, 2, 1, 0}) | ||
|
||
// untag version 1 - it should get deleted immediately, | ||
// since we have more than JobTrackedVersions. | ||
must.NoError(t, state.UpdateJobVersionTag(nextIndex(state), job.Namespace, &structs.JobApplyTagRequest{ | ||
JobID: job.ID, | ||
Name: "v1", | ||
Tag: nil, // this triggers unset | ||
})) | ||
assertVersions(t, []uint64{14, 13, 12, 11, 10, 2, 0}) | ||
|
||
// deleting all versions should also delete tagged versions | ||
txn := state.db.WriteTxn(nextIndex(state)) | ||
must.NoError(t, state.deleteJobVersions(nextIndex(state), job, txn)) | ||
must.NoError(t, txn.Commit()) | ||
assertVersions(t, []uint64{}) | ||
} | ||
|
||
func TestStateStore_DeleteJob_MultipleVersions(t *testing.T) { | ||
ci.Parallel(t) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're testing the cases where we've got a "full" tracked versions when we tag, but not when we don't. It might make more sense to insert < max tracked, tag one, insert the rest, and then tag again. That'll make sure we've covered both paths.