mirror of https://github.com/stashapp/stash.git
346 lines
7.1 KiB
Go
346 lines
7.1 KiB
Go
package job
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
const sleepTime time.Duration = 10 * time.Millisecond
|
|
|
|
type testExec struct {
|
|
started chan struct{}
|
|
finish chan struct{}
|
|
cancelled bool
|
|
progress *Progress
|
|
}
|
|
|
|
func newTestExec(finish chan struct{}) *testExec {
|
|
return &testExec{
|
|
started: make(chan struct{}),
|
|
finish: finish,
|
|
}
|
|
}
|
|
|
|
func (e *testExec) Execute(ctx context.Context, p *Progress) error {
|
|
e.progress = p
|
|
close(e.started)
|
|
|
|
if e.finish != nil {
|
|
<-e.finish
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
e.cancelled = true
|
|
default:
|
|
// fall through
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func TestAdd(t *testing.T) {
|
|
m := NewManager()
|
|
|
|
const jobName = "test job"
|
|
exec1 := newTestExec(make(chan struct{}))
|
|
jobID := m.Add(context.Background(), jobName, exec1)
|
|
|
|
// expect jobID to be the first ID
|
|
assert := assert.New(t)
|
|
assert.Equal(1, jobID)
|
|
|
|
// wait a tiny bit
|
|
time.Sleep(sleepTime)
|
|
|
|
// expect job to have started
|
|
select {
|
|
case <-exec1.started:
|
|
// ok
|
|
default:
|
|
t.Error("exec was not started")
|
|
}
|
|
|
|
// expect status to be running
|
|
j := m.GetJob(jobID)
|
|
|
|
assert.Equal(StatusRunning, j.Status)
|
|
|
|
// expect description to be set
|
|
assert.Equal(jobName, j.Description)
|
|
|
|
// expect startTime and addTime to be set
|
|
assert.NotNil(j.StartTime)
|
|
assert.NotNil(j.AddTime)
|
|
|
|
// expect endTime to not be set
|
|
assert.Nil(j.EndTime)
|
|
|
|
// add another job to the queue
|
|
const otherJobName = "other job name"
|
|
exec2 := newTestExec(make(chan struct{}))
|
|
job2ID := m.Add(context.Background(), otherJobName, exec2)
|
|
|
|
// expect status to be ready
|
|
j2 := m.GetJob(job2ID)
|
|
|
|
assert.Equal(StatusReady, j2.Status)
|
|
|
|
// expect addTime to be set
|
|
assert.NotNil(j2.AddTime)
|
|
|
|
// expect startTime and endTime to not be set
|
|
assert.Nil(j2.StartTime)
|
|
assert.Nil(j2.EndTime)
|
|
|
|
// allow first job to finish
|
|
close(exec1.finish)
|
|
|
|
// wait a tiny bit
|
|
time.Sleep(sleepTime)
|
|
|
|
// expect first job to be finished
|
|
j = m.GetJob(jobID)
|
|
assert.Equal(StatusFinished, j.Status)
|
|
|
|
// expect end time to be set
|
|
assert.NotNil(j.EndTime)
|
|
|
|
// expect second job to have started
|
|
select {
|
|
case <-exec2.started:
|
|
// ok
|
|
default:
|
|
t.Error("exec was not started")
|
|
}
|
|
|
|
// expect status to be running
|
|
j2 = m.GetJob(job2ID)
|
|
|
|
assert.Equal(StatusRunning, j2.Status)
|
|
|
|
// expect startTime to be set
|
|
assert.NotNil(j2.StartTime)
|
|
}
|
|
|
|
func TestCancel(t *testing.T) {
|
|
m := NewManager()
|
|
|
|
// add two jobs
|
|
const jobName = "test job"
|
|
exec1 := newTestExec(make(chan struct{}))
|
|
jobID := m.Add(context.Background(), jobName, exec1)
|
|
|
|
const otherJobName = "other job"
|
|
exec2 := newTestExec(make(chan struct{}))
|
|
job2ID := m.Add(context.Background(), otherJobName, exec2)
|
|
|
|
// wait a tiny bit
|
|
time.Sleep(sleepTime)
|
|
|
|
m.CancelJob(job2ID)
|
|
|
|
// expect job to be cancelled
|
|
assert := assert.New(t)
|
|
j := m.GetJob(job2ID)
|
|
assert.Equal(StatusCancelled, j.Status)
|
|
|
|
// expect end time not to be set
|
|
assert.Nil(j.EndTime)
|
|
|
|
// expect job to be removed from the queue
|
|
assert.Len(m.GetQueue(), 1)
|
|
|
|
// expect job to have not have been started
|
|
select {
|
|
case <-exec2.started:
|
|
t.Error("cancelled exec was started")
|
|
default:
|
|
}
|
|
|
|
// cancel running job
|
|
m.CancelJob(jobID)
|
|
|
|
// wait a tiny bit
|
|
time.Sleep(sleepTime)
|
|
|
|
// expect status to be stopping
|
|
j = m.GetJob(jobID)
|
|
assert.Equal(StatusStopping, j.Status)
|
|
|
|
// expect job to still be in the queue
|
|
assert.Len(m.GetQueue(), 1)
|
|
|
|
// allow first job to finish
|
|
close(exec1.finish)
|
|
|
|
// wait a tiny bit
|
|
time.Sleep(sleepTime)
|
|
|
|
// expect job to be removed from the queue
|
|
assert.Len(m.GetQueue(), 0)
|
|
|
|
// expect job to be cancelled
|
|
j = m.GetJob(jobID)
|
|
assert.Equal(StatusCancelled, j.Status)
|
|
|
|
// expect endtime to be set
|
|
assert.NotNil(j.EndTime)
|
|
|
|
// expect job to have been cancelled via context
|
|
assert.True(exec1.cancelled)
|
|
}
|
|
|
|
func TestCancelAll(t *testing.T) {
|
|
m := NewManager()
|
|
|
|
// add two jobs
|
|
const jobName = "test job"
|
|
exec1 := newTestExec(make(chan struct{}))
|
|
jobID := m.Add(context.Background(), jobName, exec1)
|
|
|
|
const otherJobName = "other job"
|
|
exec2 := newTestExec(make(chan struct{}))
|
|
job2ID := m.Add(context.Background(), otherJobName, exec2)
|
|
|
|
// wait a tiny bit
|
|
time.Sleep(sleepTime)
|
|
|
|
m.CancelAll()
|
|
|
|
// allow first job to finish
|
|
close(exec1.finish)
|
|
|
|
// wait a tiny bit
|
|
time.Sleep(sleepTime)
|
|
|
|
// expect all jobs to be cancelled
|
|
assert := assert.New(t)
|
|
j := m.GetJob(job2ID)
|
|
assert.Equal(StatusCancelled, j.Status)
|
|
|
|
j = m.GetJob(jobID)
|
|
assert.Equal(StatusCancelled, j.Status)
|
|
|
|
// expect all jobs to be removed from the queue
|
|
assert.Len(m.GetQueue(), 0)
|
|
|
|
// expect job to have not have been started
|
|
select {
|
|
case <-exec2.started:
|
|
t.Error("cancelled exec was started")
|
|
default:
|
|
}
|
|
}
|
|
|
|
func TestSubscribe(t *testing.T) {
|
|
m := NewManager()
|
|
|
|
m.updateThrottleLimit = time.Millisecond * 100
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
s := m.Subscribe(ctx)
|
|
|
|
// add a job
|
|
const jobName = "test job"
|
|
exec1 := newTestExec(make(chan struct{}))
|
|
jobID := m.Add(context.Background(), jobName, exec1)
|
|
|
|
assert := assert.New(t)
|
|
|
|
select {
|
|
case newJob := <-s.NewJob:
|
|
assert.Equal(jobID, newJob.ID)
|
|
assert.Equal(jobName, newJob.Description)
|
|
assert.Equal(StatusReady, newJob.Status)
|
|
case <-time.After(time.Second):
|
|
t.Error("new job was not received")
|
|
}
|
|
|
|
// should receive an update when the job begins to run
|
|
select {
|
|
case updatedJob := <-s.UpdatedJob:
|
|
assert.Equal(jobID, updatedJob.ID)
|
|
assert.Equal(jobName, updatedJob.Description)
|
|
assert.Equal(StatusRunning, updatedJob.Status)
|
|
case <-time.After(time.Second):
|
|
t.Error("updated job was not received")
|
|
}
|
|
|
|
// wait for it to start
|
|
select {
|
|
case <-exec1.started:
|
|
// ok
|
|
case <-time.After(time.Second):
|
|
t.Error("exec was not started")
|
|
}
|
|
|
|
// test update throttling
|
|
exec1.progress.SetPercent(0.1)
|
|
|
|
// first update should be immediate
|
|
select {
|
|
case updatedJob := <-s.UpdatedJob:
|
|
assert.Equal(0.1, updatedJob.Progress)
|
|
case <-time.After(m.updateThrottleLimit):
|
|
t.Error("updated job was not received")
|
|
}
|
|
|
|
exec1.progress.SetPercent(0.2)
|
|
exec1.progress.SetPercent(0.3)
|
|
|
|
// should only receive a single update with the second status
|
|
select {
|
|
case updatedJob := <-s.UpdatedJob:
|
|
assert.Equal(0.3, updatedJob.Progress)
|
|
case <-time.After(time.Second):
|
|
t.Error("updated job was not received")
|
|
}
|
|
|
|
select {
|
|
case <-s.UpdatedJob:
|
|
t.Error("received an additional updatedJob")
|
|
default:
|
|
}
|
|
|
|
// allow job to finish
|
|
close(exec1.finish)
|
|
|
|
select {
|
|
case removedJob := <-s.RemovedJob:
|
|
assert.Equal(jobID, removedJob.ID)
|
|
assert.Equal(jobName, removedJob.Description)
|
|
assert.Equal(StatusFinished, removedJob.Status)
|
|
case <-time.After(time.Second):
|
|
t.Error("removed job was not received")
|
|
}
|
|
|
|
// should not receive another update
|
|
select {
|
|
case <-s.UpdatedJob:
|
|
t.Error("updated job was received after update")
|
|
case <-time.After(m.updateThrottleLimit):
|
|
}
|
|
|
|
// add another job and cancel it
|
|
exec2 := newTestExec(make(chan struct{}))
|
|
jobID = m.Add(context.Background(), jobName, exec2)
|
|
|
|
m.CancelJob(jobID)
|
|
|
|
select {
|
|
case removedJob := <-s.RemovedJob:
|
|
assert.Equal(jobID, removedJob.ID)
|
|
assert.Equal(jobName, removedJob.Description)
|
|
assert.Equal(StatusCancelled, removedJob.Status)
|
|
case <-time.After(time.Second):
|
|
t.Error("cancelled job was not received")
|
|
}
|
|
|
|
cancel()
|
|
}
|