more tests, prevent test hangup

This commit is contained in:
Pavel 2019-12-17 12:16:54 +03:00
parent ee1de01b31
commit 37d815ba34
3 changed files with 196 additions and 52 deletions

View File

@ -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)

View File

@ -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
}

View File

@ -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`")
}