jobqueue: Add DeleteJob function

This allows jobs to be deleted from the database.
Currently only implemented by fsjobqueue. The function for
dbjobqueue currently returns nil.

This will remove all the job files used by the root job UUID as long as
no other job depends on them. ie. It starts at the top, and moves down
the dependency tree until it finds a job that is also used by another
job, removes the job to be deleted from its dependants list, and moves
back up the tree only deleting jobs with empty dependants lists.

Related: RHEL-60120
This commit is contained in:
Brian C. Lane 2024-04-16 10:46:28 -07:00 committed by Tomáš Hozza
parent 5961b69caa
commit d8285a0b74
4 changed files with 134 additions and 0 deletions

View file

@ -7,6 +7,7 @@ import (
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/osbuild/osbuild-composer/internal/jobqueue/fsjobqueue"
@ -87,3 +88,82 @@ func TestAllRootJobIDs(t *testing.T) {
sortUUIDs(roots)
require.Equal(t, rootJobs, roots)
}
func TestDeleteJob(t *testing.T) {
dir := t.TempDir()
q, err := fsjobqueue.New(dir)
require.Nil(t, err)
require.NotNil(t, q)
// root with no dependencies
jidRoot1, err := q.Enqueue("oneRoot", nil, nil, "OneRootJob")
require.Nil(t, err)
err = q.DeleteJob(context.TODO(), jidRoot1)
require.Nil(t, err)
jobs, err := q.AllRootJobIDs()
require.Nil(t, err)
require.Equal(t, 0, len(jobs))
// root with 2 dependencies
jid1, err := q.Enqueue("twoDeps", nil, nil, "TwoDepJobs")
require.Nil(t, err)
jid2, err := q.Enqueue("twoDeps", nil, nil, "TwoDepJobs")
require.Nil(t, err)
jidRoot2, err := q.Enqueue("twoDeps", nil, []uuid.UUID{jid1, jid2}, "TwoDepJobs")
require.Nil(t, err)
// root with 2 dependencies, one shared with the previous root
jid3, err := q.Enqueue("sharedDeps", nil, nil, "SharedDepJobs")
require.Nil(t, err)
jidRoot3, err := q.Enqueue("sharedDeps", nil, []uuid.UUID{jid1, jid3}, "SharedDepJobs")
require.Nil(t, err)
// This should only remove jidRoot2 and jid2, leaving jidRoot3, jid1, jid3
err = q.DeleteJob(context.TODO(), jidRoot2)
require.Nil(t, err)
jobs, err = q.AllRootJobIDs()
require.Nil(t, err)
require.Equal(t, 1, len(jobs))
assert.Equal(t, []uuid.UUID{jidRoot3}, jobs)
// This should remove the rest
err = q.DeleteJob(context.TODO(), jidRoot3)
require.Nil(t, err)
jobs, err = q.AllRootJobIDs()
require.Nil(t, err)
require.Equal(t, 0, len(jobs))
// Make sure all the jobs are deleted
allJobs := []uuid.UUID{jidRoot1, jidRoot2, jidRoot3, jid1, jid2, jid3}
for _, jobId := range allJobs {
jobType, _, _, _, err := q.Job(jobId)
assert.Error(t, err, jobType)
}
// root with 2 jobs depending on another (simulates Koji jobs)
kojiOSTree, err := q.Enqueue("ostree", nil, nil, "KojiJob")
require.Nil(t, err)
kojiDepsolve, err := q.Enqueue("depsolve", nil, nil, "KojiJob")
require.Nil(t, err)
kojiManifest, err := q.Enqueue("manifest", nil, []uuid.UUID{kojiOSTree, kojiDepsolve}, "KojiJob")
require.Nil(t, err)
kojiInit, err := q.Enqueue("init", nil, nil, "KojiJob")
require.Nil(t, err)
kojiRoot, err := q.Enqueue("final", nil, []uuid.UUID{kojiInit, kojiManifest, kojiDepsolve}, "KojiJob")
require.Nil(t, err)
// Delete the koji job
err = q.DeleteJob(context.TODO(), kojiRoot)
require.Nil(t, err)
jobs, err = q.AllRootJobIDs()
require.Nil(t, err)
require.Equal(t, 0, len(jobs))
// Make sure all the jobs are deleted
kojiJobs := []uuid.UUID{kojiRoot, kojiInit, kojiOSTree, kojiDepsolve, kojiManifest}
for _, jobId := range kojiJobs {
jobType, _, _, _, err := q.Job(jobId)
assert.Error(t, err, jobType)
}
}