From 37d815ba34c19614e75214afcc0a4e62edb8118c Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 17 Dec 2019 12:16:54 +0300 Subject: [PATCH] more tests, prevent test hangup --- .travis.yml | 2 +- core/job_manager.go | 11 +- core/job_manager_test.go | 235 ++++++++++++++++++++++++++++++++------- 3 files changed, 196 insertions(+), 52 deletions(-) diff --git a/.travis.yml b/.travis.yml index 12de6d3..4821ce2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,6 @@ go: before_install: - go mod tidy script: - - go test ./... -v -cpu 2 -race -cover -coverprofile=coverage.txt -covermode=atomic + - go test ./... -v -cpu 2 -timeout 1m -race -cover -coverprofile=coverage.txt -covermode=atomic after_success: - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/core/job_manager.go b/core/job_manager.go index 0b60d18..6d8133f 100644 --- a/core/job_manager.go +++ b/core/job_manager.go @@ -169,7 +169,7 @@ func (j *JobManager) UnregisterJob(name string) error { // FetchJob fetches already exist job func (j *JobManager) FetchJob(name string) (value *Job, ok bool) { if i, ok := j.jobs.Load(name); ok { - if job, ok := j.asJob(i); ok { + if job, ok := i.(*Job); ok { return job, ok } } @@ -265,12 +265,3 @@ func (j *JobManager) log(format string, severity logging.Level, args ...interfac fmt.Print("[DEBUG] ", fmt.Sprintf(format, args...)) } } - -// asJob casts interface to a Job -func (j *JobManager) asJob(v interface{}) (*Job, bool) { - if job, ok := v.(*Job); ok { - return job, ok - } - - return &Job{}, false -} diff --git a/core/job_manager_test.go b/core/job_manager_test.go index 66cd429..b000989 100644 --- a/core/job_manager_test.go +++ b/core/job_manager_test.go @@ -3,6 +3,7 @@ package core import ( "errors" "fmt" + "math/rand" "testing" "time" @@ -15,11 +16,13 @@ import ( type JobTest struct { suite.Suite job *Job - executed bool - executeErr error + syncBool bool + executedChan chan bool + randomNumber chan int + executeErr chan error + panicValue chan interface{} lastLog string lastMsgLevel logging.Level - panicValue interface{} } type JobManagerTest struct { @@ -64,13 +67,13 @@ func TestDefaultJobPanicHandler(t *testing.T) { func (t *JobTest) testErrorHandler() JobErrorHandler { return func(name string, err error, logFunc JobLogFunc) { - t.executeErr = err + t.executeErr <- err } } func (t *JobTest) testPanicHandler() JobPanicHandler { return func(name string, i interface{}, logFunc JobLogFunc) { - t.panicValue = i + t.panicValue <- i } } @@ -81,12 +84,43 @@ func (t *JobTest) testLogFunc() JobLogFunc { } } -func (t *JobTest) errored() bool { - return t.executeErr != nil +func (t *JobTest) executed(wait time.Duration, defaultVal bool) bool { + if t.executedChan == nil { + return defaultVal + } + + select { + case c := <-t.executedChan: + return c + case <-time.After(wait): + return defaultVal + } } -func (t *JobTest) panicked() bool { - return t.panicValue != nil +func (t *JobTest) errored(wait time.Duration) bool { + if t.executeErr == nil { + return false + } + + select { + case c := <-t.executeErr: + return c != nil + case <-time.After(wait): + return false + } +} + +func (t *JobTest) panicked(wait time.Duration) bool { + if t.panicValue == nil { + return false + } + + select { + case c := <-t.panicValue: + return c != nil + case <-time.After(wait): + return false + } } func (t *JobTest) clear() { @@ -95,16 +129,18 @@ func (t *JobTest) clear() { t.job = nil } - t.executed = false - t.executeErr = nil - t.panicValue = nil + t.syncBool = false + t.randomNumber = make(chan int) + t.executedChan = make(chan bool) + t.executeErr = make(chan error) + t.panicValue = make(chan interface{}) } func (t *JobTest) onceJob() { t.clear() t.job = &Job{ Command: func(logFunc JobLogFunc) error { - t.executed = true + t.executedChan <- true return nil }, ErrorHandler: t.testErrorHandler(), @@ -118,7 +154,7 @@ func (t *JobTest) onceErrorJob() { t.clear() t.job = &Job{ Command: func(logFunc JobLogFunc) error { - t.executed = true + t.executedChan <- true return errors.New("test error") }, ErrorHandler: t.testErrorHandler(), @@ -132,7 +168,7 @@ func (t *JobTest) oncePanicJob() { t.clear() t.job = &Job{ Command: func(logFunc JobLogFunc) error { - t.executed = true + t.executedChan <- true panic("test panic") }, ErrorHandler: t.testErrorHandler(), @@ -144,14 +180,31 @@ func (t *JobTest) oncePanicJob() { func (t *JobTest) regularJob() { t.clear() + rand.Seed(time.Now().UnixNano()) t.job = &Job{ Command: func(logFunc JobLogFunc) error { - t.executed = true + t.executedChan <- true + t.randomNumber <- rand.Int() return nil }, ErrorHandler: t.testErrorHandler(), PanicHandler: t.testPanicHandler(), - Interval: time.Nanosecond, + Interval: time.Millisecond, + Regular: true, + } +} + +func (t *JobTest) regularSyncJob() { + t.clear() + rand.Seed(time.Now().UnixNano()) + t.job = &Job{ + Command: func(logFunc JobLogFunc) error { + t.syncBool = true + return nil + }, + ErrorHandler: t.testErrorHandler(), + PanicHandler: t.testPanicHandler(), + Interval: time.Millisecond, Regular: true, } } @@ -165,10 +218,10 @@ func (t *JobTest) Test_getWrappedFunc() { t.onceJob() fn := t.job.getWrappedFunc("job", t.testLogFunc()) require.NotNil(t.T(), fn) - fn() - assert.True(t.T(), t.executed) - assert.False(t.T(), t.errored()) - assert.False(t.T(), t.panicked()) + go fn() + assert.True(t.T(), t.executed(time.Millisecond, false)) + assert.False(t.T(), t.errored(time.Millisecond)) + assert.False(t.T(), t.panicked(time.Millisecond)) } func (t *JobTest) Test_getWrappedFuncError() { @@ -180,10 +233,10 @@ func (t *JobTest) Test_getWrappedFuncError() { t.onceErrorJob() fn := t.job.getWrappedFunc("job", t.testLogFunc()) require.NotNil(t.T(), fn) - fn() - assert.True(t.T(), t.executed) - assert.True(t.T(), t.errored()) - assert.False(t.T(), t.panicked()) + go fn() + assert.True(t.T(), t.executed(time.Millisecond, false)) + assert.True(t.T(), t.errored(time.Millisecond)) + assert.False(t.T(), t.panicked(time.Millisecond)) } func (t *JobTest) Test_getWrappedFuncPanic() { @@ -195,32 +248,91 @@ func (t *JobTest) Test_getWrappedFuncPanic() { t.oncePanicJob() fn := t.job.getWrappedFunc("job", t.testLogFunc()) require.NotNil(t.T(), fn) - fn() - assert.True(t.T(), t.executed) - assert.False(t.T(), t.errored()) - assert.True(t.T(), t.panicked()) + go fn() + assert.True(t.T(), t.executed(time.Millisecond, false)) + assert.False(t.T(), t.errored(time.Millisecond)) + assert.True(t.T(), t.panicked(time.Millisecond)) } -func (t *JobTest) Test_getWrappedTimerFunc() { +// func (t *JobTest) Test_getWrappedTimerFunc() { +// defer func() { +// require.Nil(t.T(), recover()) +// }() +// +// t.clear() +// t.regularJob() +// t.job.run("job", t.testLogFunc()) +// time.Sleep(time.Millisecond * 5) +// require.True(t.T(), t.executed(time.Millisecond, false)) +// first := 0 +// +// select { +// case c := <-t.randomNumber: +// first = c +// t.randomNumber = make(chan int) +// case <-time.After(time.Millisecond * 2): +// first = 0 +// } +// +// require.NotEqual(t.T(), 0, first) +// second := 0 +// +// select { +// case c := <-t.randomNumber: +// second = c +// t.randomNumber = make(chan int) +// case <-time.After(time.Millisecond * 2): +// second = 0 +// } +// +// require.NotEqual(t.T(), 0, second) +// assert.NotEqual(t.T(), first, second) +// } + +func (t *JobTest) Test_runOnce() { defer func() { require.Nil(t.T(), recover()) }() t.clear() t.regularJob() - t.job.run("job", t.testLogFunc()) - time.Sleep(time.Millisecond) - assert.True(t.T(), t.executed) - t.executed = false - time.Sleep(time.Millisecond) - if !t.executed { - t.clear() - t.T().Skip("job wasn't as fast as it should be! this may be an error, but also can be just bad timing") + t.job.runOnce("job", t.testLogFunc()) + time.Sleep(time.Millisecond * 5) + require.True(t.T(), t.executed(time.Millisecond, false)) + first := 0 + + select { + case c := <-t.randomNumber: + first = c + t.randomNumber = make(chan int) + case <-time.After(time.Millisecond * 2): + first = 0 } - t.job.stop() - time.Sleep(time.Nanosecond * 10) + + require.NotEqual(t.T(), 0, first) + second := 0 + + select { + case c := <-t.randomNumber: + second = c + t.randomNumber = make(chan int) + case <-time.After(time.Millisecond * 2): + second = 0 + } + + assert.Equal(t.T(), 0, second) +} + +func (t *JobTest) Test_runOnceSync() { + defer func() { + require.Nil(t.T(), recover()) + }() + t.clear() - assert.False(t.T(), t.executed) + t.regularSyncJob() + require.False(t.T(), t.syncBool) + t.job.runOnceSync("job", t.testLogFunc()) + assert.True(t.T(), t.syncBool) } func (t *JobManagerTest) SetupSuite() { @@ -270,6 +382,41 @@ func (t *JobManagerTest) Test_RegisterJobAlreadyExists() { assert.EqualError(t.T(), err, "job already exists") } +func (t *JobManagerTest) Test_FetchJobDoesntExist() { + require.NotNil(t.T(), t.manager.jobs) + _, ok := t.manager.FetchJob("doesn't exist") + assert.False(t.T(), ok) +} + +func (t *JobManagerTest) Test_FetchJob() { + defer func() { + require.Nil(t.T(), recover()) + }() + + require.NoError(t.T(), t.manager.RegisterJob("test_fetch", &Job{Command: func(logFunc JobLogFunc) error { + return nil + }})) + require.NotNil(t.T(), t.manager.jobs) + job, ok := t.manager.FetchJob("test_fetch") + assert.True(t.T(), ok) + require.NotNil(t.T(), job) + assert.NotNil(t.T(), job.Command) + _ = t.manager.UnregisterJob("test_fetch") +} + +func (t *JobManagerTest) Test_UpdateJobDoesntExist() { + require.NotNil(t.T(), t.manager.jobs) + err := t.manager.UpdateJob("doesn't exist", &Job{}) + assert.EqualError(t.T(), err, "cannot find job `doesn't exist`") +} + +func (t *JobManagerTest) Test_UpdateJob() { + require.NotNil(t.T(), t.manager.jobs) + job, _ := t.manager.FetchJob("job") + err := t.manager.UpdateJob("job", job) + assert.NoError(t.T(), err) +} + func (t *JobManagerTest) Test_RunOnceSync() { require.NotNil(t.T(), t.manager.jobs) t.runnerFlag = false @@ -277,3 +424,9 @@ func (t *JobManagerTest) Test_RunOnceSync() { require.NoError(t.T(), err) assert.True(t.T(), t.runnerFlag) } + +func (t *JobManagerTest) Test_UnregisterJobDoesntExist() { + require.NotNil(t.T(), t.manager.jobs) + err := t.manager.UnregisterJob("doesn't exist") + assert.EqualError(t.T(), err, "cannot find job `doesn't exist`") +}