
Replace the use of the `t *testing.T` parameter with just plain `panic()` when test setup fails. This makes it easier to call the same functions from other situations, like benchmark functions. No functional changes to Flamenco itself.
202 lines
6.1 KiB
Go
202 lines
6.1 KiB
Go
// Package persistence provides the database interface for Flamenco Manager.
|
|
package persistence
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"projects.blender.org/studio/flamenco/internal/manager/job_compilers"
|
|
"projects.blender.org/studio/flamenco/internal/uuid"
|
|
"projects.blender.org/studio/flamenco/pkg/api"
|
|
)
|
|
|
|
func TestSimpleQuery(t *testing.T) {
|
|
ctx, close, db, job, _ := jobTasksTestFixtures(t)
|
|
defer close()
|
|
|
|
// Sanity check.
|
|
if !assert.Equal(t, api.JobStatusUnderConstruction, job.Status, "check job status is as expected") {
|
|
t.FailNow()
|
|
}
|
|
|
|
// Check empty result when querying for other status.
|
|
result, err := db.QueryJobs(ctx, api.JobsQuery{
|
|
StatusIn: &[]api.JobStatus{api.JobStatusActive, api.JobStatusCanceled},
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Len(t, result, 0)
|
|
|
|
// Check job was returned properly on correct status.
|
|
result, err = db.QueryJobs(ctx, api.JobsQuery{
|
|
StatusIn: &[]api.JobStatus{api.JobStatusUnderConstruction, api.JobStatusCanceled},
|
|
})
|
|
require.NoError(t, err)
|
|
if !assert.Len(t, result, 1) {
|
|
t.FailNow()
|
|
}
|
|
assert.Equal(t, job.ID, result[0].ID)
|
|
|
|
}
|
|
|
|
func TestQueryMetadata(t *testing.T) {
|
|
ctx, close, db := persistenceTestFixtures(0)
|
|
defer close()
|
|
|
|
testJob := persistAuthoredJob(t, ctx, db, createTestAuthoredJobWithTasks())
|
|
|
|
otherAuthoredJob := createTestAuthoredJobWithTasks()
|
|
otherAuthoredJob.Status = api.JobStatusActive
|
|
otherAuthoredJob.Tasks = []job_compilers.AuthoredTask{}
|
|
otherAuthoredJob.JobID = "138678c8-efd0-452b-ac05-397ff4c02b26"
|
|
otherAuthoredJob.Metadata["project"] = "Other Project"
|
|
otherJob := persistAuthoredJob(t, ctx, db, otherAuthoredJob)
|
|
|
|
var (
|
|
result []*Job
|
|
err error
|
|
)
|
|
|
|
// Check empty result when querying for specific metadata:
|
|
result, err = db.QueryJobs(ctx, api.JobsQuery{
|
|
Metadata: &api.JobsQuery_Metadata{
|
|
AdditionalProperties: map[string]string{
|
|
"project": "Secret Future Project",
|
|
}}})
|
|
require.NoError(t, err)
|
|
assert.Len(t, result, 0)
|
|
|
|
// Check job was returned properly when querying for the right project.
|
|
result, err = db.QueryJobs(ctx, api.JobsQuery{
|
|
Metadata: &api.JobsQuery_Metadata{
|
|
AdditionalProperties: map[string]string{
|
|
"project": testJob.Metadata["project"],
|
|
}}})
|
|
require.NoError(t, err)
|
|
if !assert.Len(t, result, 1) {
|
|
t.FailNow()
|
|
}
|
|
assert.Equal(t, testJob.ID, result[0].ID)
|
|
|
|
// Check for the other job
|
|
result, err = db.QueryJobs(ctx, api.JobsQuery{
|
|
Metadata: &api.JobsQuery_Metadata{
|
|
AdditionalProperties: map[string]string{
|
|
"project": otherJob.Metadata["project"],
|
|
}}})
|
|
require.NoError(t, err)
|
|
if !assert.Len(t, result, 1) {
|
|
t.FailNow()
|
|
}
|
|
assert.Equal(t, otherJob.ID, result[0].ID)
|
|
|
|
// Check job was returned properly when querying for empty metadata.
|
|
result, err = db.QueryJobs(ctx, api.JobsQuery{
|
|
OrderBy: &[]string{"status"},
|
|
Metadata: &api.JobsQuery_Metadata{AdditionalProperties: map[string]string{}},
|
|
})
|
|
require.NoError(t, err)
|
|
if !assert.Len(t, result, 2) {
|
|
t.FailNow()
|
|
}
|
|
// 'active' should come before 'under-construction':
|
|
assert.Equal(t, otherJob.ID, result[0].ID, "status is %s", result[0].Status)
|
|
assert.Equal(t, testJob.ID, result[1].ID, "status is %s", result[1].Status)
|
|
}
|
|
|
|
func TestQueryJobTaskSummaries(t *testing.T) {
|
|
ctx, close, db, job, authoredJob := jobTasksTestFixtures(t)
|
|
defer close()
|
|
|
|
expectTaskUUIDs := map[string]bool{}
|
|
for _, task := range authoredJob.Tasks {
|
|
expectTaskUUIDs[task.UUID] = true
|
|
}
|
|
|
|
// Create another test job, just to check we get the right tasks back.
|
|
otherAuthoredJob := createTestAuthoredJobWithTasks()
|
|
otherAuthoredJob.Status = api.JobStatusActive
|
|
for i := range otherAuthoredJob.Tasks {
|
|
otherAuthoredJob.Tasks[i].UUID = uuid.New()
|
|
otherAuthoredJob.Tasks[i].Dependencies = []*job_compilers.AuthoredTask{}
|
|
}
|
|
otherAuthoredJob.JobID = "138678c8-efd0-452b-ac05-397ff4c02b26"
|
|
otherAuthoredJob.Metadata["project"] = "Other Project"
|
|
persistAuthoredJob(t, ctx, db, otherAuthoredJob)
|
|
|
|
// Sanity check for the above code, there should be 6 tasks overall, 3 per job.
|
|
var numTasks int64
|
|
tx := db.gormDB.Model(&Task{}).Count(&numTasks)
|
|
require.NoError(t, tx.Error)
|
|
assert.Equal(t, int64(6), numTasks)
|
|
|
|
// Get the task summaries of a particular job.
|
|
summaries, err := db.QueryJobTaskSummaries(ctx, job.UUID)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, summaries, len(expectTaskUUIDs))
|
|
for _, summary := range summaries {
|
|
assert.True(t, expectTaskUUIDs[summary.UUID], "%q should be in %v", summary.UUID, expectTaskUUIDs)
|
|
}
|
|
}
|
|
|
|
func TestSummarizeJobStatuses(t *testing.T) {
|
|
ctx, close, db, job1, authoredJob1 := jobTasksTestFixtures(t)
|
|
defer close()
|
|
|
|
// Create another job
|
|
authoredJob2 := duplicateJobAndTasks(authoredJob1)
|
|
job2 := persistAuthoredJob(t, ctx, db, authoredJob2)
|
|
|
|
// Test the summary.
|
|
summary, err := db.SummarizeJobStatuses(ctx)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, JobStatusCount{api.JobStatusUnderConstruction: 2}, summary)
|
|
|
|
// Change the jobs so that each has a unique status.
|
|
job1.Status = api.JobStatusQueued
|
|
require.NoError(t, db.SaveJobStatus(ctx, job1))
|
|
job2.Status = api.JobStatusFailed
|
|
require.NoError(t, db.SaveJobStatus(ctx, job2))
|
|
|
|
// Test the summary.
|
|
summary, err = db.SummarizeJobStatuses(ctx)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, JobStatusCount{
|
|
api.JobStatusQueued: 1,
|
|
api.JobStatusFailed: 1,
|
|
}, summary)
|
|
|
|
// Delete all jobs.
|
|
require.NoError(t, db.DeleteJob(ctx, job1.UUID))
|
|
require.NoError(t, db.DeleteJob(ctx, job2.UUID))
|
|
|
|
// Test the summary.
|
|
summary, err = db.SummarizeJobStatuses(ctx)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, JobStatusCount{}, summary)
|
|
}
|
|
|
|
// Check that a context timeout can be detected by inspecting the
|
|
// returned error.
|
|
func TestSummarizeJobStatusesTimeout(t *testing.T) {
|
|
ctx, close, db, _, _ := jobTasksTestFixtures(t)
|
|
defer close()
|
|
|
|
subCtx, subCtxCancel := context.WithTimeout(ctx, 1*time.Nanosecond)
|
|
defer subCtxCancel()
|
|
|
|
// Force a timeout of the context. And yes, even when a nanosecond is quite
|
|
// short, it is still necessary to wait.
|
|
time.Sleep(2 * time.Nanosecond)
|
|
|
|
summary, err := db.SummarizeJobStatuses(subCtx)
|
|
assert.ErrorIs(t, err, context.DeadlineExceeded)
|
|
assert.Nil(t, summary)
|
|
}
|