Skip to content

Commit

Permalink
First set of job_context tests (#1137)
Browse files Browse the repository at this point in the history
  • Loading branch information
thom-at-redhat authored Sep 5, 2024
1 parent c02da32 commit 58b85cc
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 35 deletions.
70 changes: 35 additions & 35 deletions pkg/utils/job_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,92 +18,92 @@ import (
// A single JobContext can only run one job at a time. If JobContext.NewJob() is called while a job
// is already running, that job will be cancelled and waited on prior to starting the new job.
type JobContext struct {
ctx context.Context
cancel context.CancelFunc
wg *sync.WaitGroup
running bool
runningLock *sync.Mutex
Ctx context.Context
JcCancel context.CancelFunc
Wg *sync.WaitGroup
JcRunning bool
RunningLock *sync.Mutex
}

// NewJob starts a new job with a defined number of workers. If a prior job is running, it is cancelled.
func (mw *JobContext) NewJob(ctx context.Context, workers int, returnIfRunning bool) bool {
if mw.runningLock == nil {
mw.runningLock = &sync.Mutex{}
if mw.RunningLock == nil {
mw.RunningLock = &sync.Mutex{}
}

mw.runningLock.Lock()
for mw.running {
mw.RunningLock.Lock()
for mw.JcRunning {
if returnIfRunning {
mw.runningLock.Unlock()
mw.RunningLock.Unlock()

return false
}
mw.cancel()
mw.runningLock.Unlock()
mw.JcCancel()
mw.RunningLock.Unlock()
mw.Wait()
mw.runningLock.Lock()
mw.RunningLock.Lock()
}

mw.running = true
mw.ctx, mw.cancel = context.WithCancel(ctx)
mw.wg = &sync.WaitGroup{}
mw.wg.Add(workers)
mw.runningLock.Unlock()
mw.JcRunning = true
mw.Ctx, mw.JcCancel = context.WithCancel(ctx)
mw.Wg = &sync.WaitGroup{}
mw.Wg.Add(workers)
mw.RunningLock.Unlock()
go func() {
mw.wg.Wait()
mw.runningLock.Lock()
mw.running = false
mw.cancel()
mw.runningLock.Unlock()
mw.Wg.Wait()
mw.RunningLock.Lock()
mw.JcRunning = false
mw.JcCancel()
mw.RunningLock.Unlock()
}()

return true
}

// WorkerDone signals that a worker is finished, like sync.WaitGroup.Done().
func (mw *JobContext) WorkerDone() {
mw.wg.Done()
mw.Wg.Done()
}

// Wait waits for the current job to complete, like sync.WaitGroup.Wait().
// If no job has been started, always just returns.
func (mw *JobContext) Wait() {
if mw.wg != nil {
mw.wg.Wait()
if mw.Wg != nil {
mw.Wg.Wait()
}
}

// Done implements Context.Done().
func (mw *JobContext) Done() <-chan struct{} {
return mw.ctx.Done()
return mw.Ctx.Done()
}

// Err implements Context.Err().
func (mw *JobContext) Err() error {
return mw.ctx.Err()
return mw.Ctx.Err()
}

// Deadline implements Context.Deadline().
func (mw *JobContext) Deadline() (time time.Time, ok bool) {
return mw.ctx.Deadline()
return mw.Ctx.Deadline()
}

// Value implements Context.Value().
func (mw *JobContext) Value(key interface{}) interface{} {
return mw.ctx.Value(key)
return mw.Ctx.Value(key)
}

// Cancel cancels the JobContext's context. If no job has been started, this does nothing.
func (mw *JobContext) Cancel() {
if mw.cancel != nil {
mw.cancel()
if mw.JcCancel != nil {
mw.JcCancel()
}
}

// Running returns true if a job is currently running.
func (mw *JobContext) Running() bool {
mw.runningLock.Lock()
defer mw.runningLock.Unlock()
mw.RunningLock.Lock()
defer mw.RunningLock.Unlock()

return mw.running
return mw.JcRunning
}
203 changes: 203 additions & 0 deletions pkg/utils/job_context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package utils_test

import (
"context"
"reflect"
"sync"
"testing"
"time"

"github.com/ansible/receptor/pkg/utils"
)

type fields struct {
Ctx context.Context
JcCancel context.CancelFunc
Wg *sync.WaitGroup
JcRunning bool
RunningLock *sync.Mutex
}

func setupGoodFields() fields {
goodCtx, goodCancel := context.WithCancel(context.Background())
goodFields := &fields{
Ctx: goodCtx,
JcCancel: goodCancel,
Wg: &sync.WaitGroup{},
JcRunning: true,
RunningLock: &sync.Mutex{},
}

return *goodFields
}

func TestJobContextRunning(t *testing.T) {
tests := []struct {
name string
fields fields
want bool
}{
{
name: "Positive",
fields: setupGoodFields(),
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mw := &utils.JobContext{
Ctx: tt.fields.Ctx,
JcCancel: tt.fields.JcCancel,
Wg: tt.fields.Wg,
JcRunning: tt.fields.JcRunning,
RunningLock: tt.fields.RunningLock,
}
if got := mw.Running(); got != tt.want {
t.Errorf("JobContext.Running() = %v, want %v", got, tt.want)
}
})
}
}

func TestJobContextCancel(t *testing.T) {
tests := []struct {
name string
fields fields
}{
{
name: "Positive",
fields: setupGoodFields(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mw := &utils.JobContext{
Ctx: tt.fields.Ctx,
JcCancel: tt.fields.JcCancel,
Wg: tt.fields.Wg,
JcRunning: tt.fields.JcRunning,
RunningLock: tt.fields.RunningLock,
}
mw.Cancel()
})
}
}

func TestJobContextValue(t *testing.T) {
type args struct {
key interface{}
}

tests := []struct {
name string
fields fields
args args
want interface{}
}{
{
name: "Positive",
fields: setupGoodFields(),
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mw := &utils.JobContext{
Ctx: tt.fields.Ctx,
JcCancel: tt.fields.JcCancel,
Wg: tt.fields.Wg,
JcRunning: tt.fields.JcRunning,
RunningLock: tt.fields.RunningLock,
}
if got := mw.Value(tt.args.key); !reflect.DeepEqual(got, tt.want) {
t.Errorf("JobContext.Value() = %v, want %v", got, tt.want)
}
})
}
}

func TestJobContextDeadline(t *testing.T) {
tests := []struct {
name string
fields fields
wantTime time.Time
wantOk bool
}{
{
name: "Positive",
fields: setupGoodFields(),
wantTime: time.Time{},
wantOk: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mw := &utils.JobContext{
Ctx: tt.fields.Ctx,
JcCancel: tt.fields.JcCancel,
Wg: tt.fields.Wg,
JcRunning: tt.fields.JcRunning,
RunningLock: tt.fields.RunningLock,
}
gotTime, gotOk := mw.Deadline()
if !reflect.DeepEqual(gotTime, tt.wantTime) {
t.Errorf("JobContext.Deadline() gotTime = %v, want %v", gotTime, tt.wantTime)
}
if gotOk != tt.wantOk {
t.Errorf("JobContext.Deadline() gotOk = %v, want %v", gotOk, tt.wantOk)
}
})
}
}

func TestJobContextErr(t *testing.T) {
tests := []struct {
name string
fields fields
wantErr bool
}{
{
name: "Positive",
fields: setupGoodFields(),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mw := &utils.JobContext{
Ctx: tt.fields.Ctx,
JcCancel: tt.fields.JcCancel,
Wg: tt.fields.Wg,
JcRunning: tt.fields.JcRunning,
RunningLock: tt.fields.RunningLock,
}
if err := mw.Err(); (err != nil) != tt.wantErr {
t.Errorf("JobContext.Err() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestJobContextWait(t *testing.T) {
tests := []struct {
name string
fields fields
}{
{
name: "Positive",
fields: setupGoodFields(),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mw := &utils.JobContext{
Ctx: tt.fields.Ctx,
JcCancel: tt.fields.JcCancel,
Wg: tt.fields.Wg,
JcRunning: tt.fields.JcRunning,
RunningLock: tt.fields.RunningLock,
}
mw.Wait()
})
}
}

0 comments on commit 58b85cc

Please sign in to comment.