blob: b2ecb32a04eaf7746c1ea334722cdcefdd665edf [file] [log] [blame]
package types
import (
"bytes"
"encoding/gob"
"fmt"
"sort"
"testing"
"time"
assert "github.com/stretchr/testify/require"
"go.skia.org/infra/go/deepequal"
"go.skia.org/infra/go/testutils"
)
func TestJobCopy(t *testing.T) {
testutils.SmallTest(t)
v := MakeFullJob(time.Now())
deepequal.AssertCopy(t, v, v.Copy())
}
// Test that sort.Sort(JobSlice(...)) works correctly.
func TestJobSort(t *testing.T) {
testutils.SmallTest(t)
jobs := []*Job{}
addJob := func(ts time.Time) {
job := &Job{
Created: ts,
}
jobs = append(jobs, job)
}
// Add jobs with various creation timestamps.
addJob(time.Date(2008, time.August, 8, 8, 8, 8, 8, time.UTC)) // 0
addJob(time.Date(1776, time.July, 4, 13, 0, 0, 0, time.UTC)) // 1
addJob(time.Date(2016, time.December, 31, 23, 59, 59, 999999999, time.UTC)) // 2
addJob(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)) // 3
// Manually sort.
expected := []*Job{jobs[1], jobs[3], jobs[0], jobs[2]}
sort.Sort(JobSlice(jobs))
deepequal.AssertDeepEqual(t, expected, jobs)
}
func TestJobEncoder(t *testing.T) {
testutils.SmallTest(t)
// TODO(benjaminwagner): Is there any way to cause an error?
e := JobEncoder{}
expectedJobs := map[*Job][]byte{}
for i := 0; i < 25; i++ {
job := &Job{}
job.Id = fmt.Sprintf("Id-%d", i)
job.Name = "Bingo-was-his-name-o"
job.Dependencies = map[string][]string{}
job.Tasks = map[string][]*TaskSummary{}
var buf bytes.Buffer
err := gob.NewEncoder(&buf).Encode(job)
assert.NoError(t, err)
expectedJobs[job] = buf.Bytes()
assert.True(t, e.Process(job))
}
actualJobs := map[*Job][]byte{}
for job, serialized, err := e.Next(); job != nil; job, serialized, err = e.Next() {
assert.NoError(t, err)
actualJobs[job] = serialized
}
deepequal.AssertDeepEqual(t, expectedJobs, actualJobs)
}
func TestJobEncoderNoJobs(t *testing.T) {
testutils.SmallTest(t)
e := JobEncoder{}
job, serialized, err := e.Next()
assert.NoError(t, err)
assert.Nil(t, job)
assert.Nil(t, serialized)
}
func TestJobDecoder(t *testing.T) {
testutils.SmallTest(t)
d := NewJobDecoder()
expectedJobs := map[string]*Job{}
for i := 0; i < 250; i++ {
job := &Job{}
job.Id = fmt.Sprintf("Id-%d", i)
job.Name = "Bingo-was-his-name-o"
job.Dependencies = map[string][]string{}
job.Tasks = map[string][]*TaskSummary{}
var buf bytes.Buffer
err := gob.NewEncoder(&buf).Encode(job)
assert.NoError(t, err)
expectedJobs[job.Id] = job
assert.True(t, d.Process(buf.Bytes()))
}
actualJobs := map[string]*Job{}
result, err := d.Result()
assert.NoError(t, err)
assert.Equal(t, len(expectedJobs), len(result))
for _, job := range result {
actualJobs[job.Id] = job
}
deepequal.AssertDeepEqual(t, expectedJobs, actualJobs)
}
func TestJobDecoderNoJobs(t *testing.T) {
testutils.SmallTest(t)
d := NewJobDecoder()
result, err := d.Result()
assert.NoError(t, err)
assert.Equal(t, 0, len(result))
}
func TestJobDecoderError(t *testing.T) {
testutils.SmallTest(t)
job := &Job{}
job.Id = "Id"
var buf bytes.Buffer
err := gob.NewEncoder(&buf).Encode(job)
assert.NoError(t, err)
serialized := buf.Bytes()
invalid := append([]byte("Hi Mom!"), serialized...)
d := NewJobDecoder()
// Process should return true before it encounters an invalid result.
assert.True(t, d.Process(serialized))
assert.True(t, d.Process(serialized))
// Process may return true or false after encountering an invalid value.
_ = d.Process(invalid)
for i := 0; i < 250; i++ {
_ = d.Process(serialized)
}
// Result should return error.
result, err := d.Result()
assert.Error(t, err)
assert.Equal(t, 0, len(result))
}
func TestJobDeriveStatus(t *testing.T) {
testutils.SmallTest(t)
// No tasks for the Job: in progress.
j1 := &Job{
Dependencies: map[string][]string{"test": {"build"}, "build": {}},
Name: "j1",
RepoState: RepoState{
Repo: "my-repo",
Revision: "my-revision",
},
}
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Test empty vs nil j1.Tasks.
j1.Tasks = map[string][]*TaskSummary{}
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Add a task for the job. It's still in progress.
t1 := &TaskSummary{Status: TASK_STATUS_RUNNING}
j1.Tasks = map[string][]*TaskSummary{"build": {t1}}
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Okay, it succeeded.
t1.Status = TASK_STATUS_SUCCESS
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Or, maybe the first task failed, but we still have a retry.
t1.Status = TASK_STATUS_FAILURE
t1.MaxAttempts = 2
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Or maybe it was a mishap, but we still have a retry.
t1.Status = TASK_STATUS_MISHAP
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Now a retry has been triggered.
t2 := &TaskSummary{Status: TASK_STATUS_PENDING}
j1.Tasks["build"] = append(j1.Tasks["build"], t2)
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Now it's running.
t2.Status = TASK_STATUS_RUNNING
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// It failed, and there aren't any retries left!
t2.Status = TASK_STATUS_FAILURE
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_FAILURE)
// Or it was a mishap.
t2.Status = TASK_STATUS_MISHAP
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_MISHAP)
// No, it succeeded.
t2.Status = TASK_STATUS_SUCCESS
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// Add the test task.
t3 := &TaskSummary{Status: TASK_STATUS_RUNNING}
j1.Tasks["test"] = []*TaskSummary{t3}
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_IN_PROGRESS)
// It succeeded!
t3.Status = TASK_STATUS_SUCCESS
assert.Equal(t, j1.DeriveStatus(), JOB_STATUS_SUCCESS)
}