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: before_install:
- go mod tidy - go mod tidy
script: 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: after_success:
- bash <(curl -s https://codecov.io/bash) - 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 // FetchJob fetches already exist job
func (j *JobManager) FetchJob(name string) (value *Job, ok bool) { func (j *JobManager) FetchJob(name string) (value *Job, ok bool) {
if i, ok := j.jobs.Load(name); ok { if i, ok := j.jobs.Load(name); ok {
if job, ok := j.asJob(i); ok { if job, ok := i.(*Job); ok {
return 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...)) 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 ( import (
"errors" "errors"
"fmt" "fmt"
"math/rand"
"testing" "testing"
"time" "time"
@ -15,11 +16,13 @@ import (
type JobTest struct { type JobTest struct {
suite.Suite suite.Suite
job *Job job *Job
executed bool syncBool bool
executeErr error executedChan chan bool
randomNumber chan int
executeErr chan error
panicValue chan interface{}
lastLog string lastLog string
lastMsgLevel logging.Level lastMsgLevel logging.Level
panicValue interface{}
} }
type JobManagerTest struct { type JobManagerTest struct {
@ -64,13 +67,13 @@ func TestDefaultJobPanicHandler(t *testing.T) {
func (t *JobTest) testErrorHandler() JobErrorHandler { func (t *JobTest) testErrorHandler() JobErrorHandler {
return func(name string, err error, logFunc JobLogFunc) { return func(name string, err error, logFunc JobLogFunc) {
t.executeErr = err t.executeErr <- err
} }
} }
func (t *JobTest) testPanicHandler() JobPanicHandler { func (t *JobTest) testPanicHandler() JobPanicHandler {
return func(name string, i interface{}, logFunc JobLogFunc) { 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 { func (t *JobTest) executed(wait time.Duration, defaultVal bool) bool {
return t.executeErr != nil if t.executedChan == nil {
return defaultVal
}
select {
case c := <-t.executedChan:
return c
case <-time.After(wait):
return defaultVal
}
} }
func (t *JobTest) panicked() bool { func (t *JobTest) errored(wait time.Duration) bool {
return t.panicValue != nil 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() { func (t *JobTest) clear() {
@ -95,16 +129,18 @@ func (t *JobTest) clear() {
t.job = nil t.job = nil
} }
t.executed = false t.syncBool = false
t.executeErr = nil t.randomNumber = make(chan int)
t.panicValue = nil t.executedChan = make(chan bool)
t.executeErr = make(chan error)
t.panicValue = make(chan interface{})
} }
func (t *JobTest) onceJob() { func (t *JobTest) onceJob() {
t.clear() t.clear()
t.job = &Job{ t.job = &Job{
Command: func(logFunc JobLogFunc) error { Command: func(logFunc JobLogFunc) error {
t.executed = true t.executedChan <- true
return nil return nil
}, },
ErrorHandler: t.testErrorHandler(), ErrorHandler: t.testErrorHandler(),
@ -118,7 +154,7 @@ func (t *JobTest) onceErrorJob() {
t.clear() t.clear()
t.job = &Job{ t.job = &Job{
Command: func(logFunc JobLogFunc) error { Command: func(logFunc JobLogFunc) error {
t.executed = true t.executedChan <- true
return errors.New("test error") return errors.New("test error")
}, },
ErrorHandler: t.testErrorHandler(), ErrorHandler: t.testErrorHandler(),
@ -132,7 +168,7 @@ func (t *JobTest) oncePanicJob() {
t.clear() t.clear()
t.job = &Job{ t.job = &Job{
Command: func(logFunc JobLogFunc) error { Command: func(logFunc JobLogFunc) error {
t.executed = true t.executedChan <- true
panic("test panic") panic("test panic")
}, },
ErrorHandler: t.testErrorHandler(), ErrorHandler: t.testErrorHandler(),
@ -144,14 +180,31 @@ func (t *JobTest) oncePanicJob() {
func (t *JobTest) regularJob() { func (t *JobTest) regularJob() {
t.clear() t.clear()
rand.Seed(time.Now().UnixNano())
t.job = &Job{ t.job = &Job{
Command: func(logFunc JobLogFunc) error { Command: func(logFunc JobLogFunc) error {
t.executed = true t.executedChan <- true
t.randomNumber <- rand.Int()
return nil return nil
}, },
ErrorHandler: t.testErrorHandler(), ErrorHandler: t.testErrorHandler(),
PanicHandler: t.testPanicHandler(), 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, Regular: true,
} }
} }
@ -165,10 +218,10 @@ func (t *JobTest) Test_getWrappedFunc() {
t.onceJob() t.onceJob()
fn := t.job.getWrappedFunc("job", t.testLogFunc()) fn := t.job.getWrappedFunc("job", t.testLogFunc())
require.NotNil(t.T(), fn) require.NotNil(t.T(), fn)
fn() go fn()
assert.True(t.T(), t.executed) assert.True(t.T(), t.executed(time.Millisecond, false))
assert.False(t.T(), t.errored()) assert.False(t.T(), t.errored(time.Millisecond))
assert.False(t.T(), t.panicked()) assert.False(t.T(), t.panicked(time.Millisecond))
} }
func (t *JobTest) Test_getWrappedFuncError() { func (t *JobTest) Test_getWrappedFuncError() {
@ -180,10 +233,10 @@ func (t *JobTest) Test_getWrappedFuncError() {
t.onceErrorJob() t.onceErrorJob()
fn := t.job.getWrappedFunc("job", t.testLogFunc()) fn := t.job.getWrappedFunc("job", t.testLogFunc())
require.NotNil(t.T(), fn) require.NotNil(t.T(), fn)
fn() go fn()
assert.True(t.T(), t.executed) assert.True(t.T(), t.executed(time.Millisecond, false))
assert.True(t.T(), t.errored()) assert.True(t.T(), t.errored(time.Millisecond))
assert.False(t.T(), t.panicked()) assert.False(t.T(), t.panicked(time.Millisecond))
} }
func (t *JobTest) Test_getWrappedFuncPanic() { func (t *JobTest) Test_getWrappedFuncPanic() {
@ -195,32 +248,91 @@ func (t *JobTest) Test_getWrappedFuncPanic() {
t.oncePanicJob() t.oncePanicJob()
fn := t.job.getWrappedFunc("job", t.testLogFunc()) fn := t.job.getWrappedFunc("job", t.testLogFunc())
require.NotNil(t.T(), fn) require.NotNil(t.T(), fn)
fn() go fn()
assert.True(t.T(), t.executed) assert.True(t.T(), t.executed(time.Millisecond, false))
assert.False(t.T(), t.errored()) assert.False(t.T(), t.errored(time.Millisecond))
assert.True(t.T(), t.panicked()) 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() { defer func() {
require.Nil(t.T(), recover()) require.Nil(t.T(), recover())
}() }()
t.clear() t.clear()
t.regularJob() t.regularJob()
t.job.run("job", t.testLogFunc()) t.job.runOnce("job", t.testLogFunc())
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond * 5)
assert.True(t.T(), t.executed) require.True(t.T(), t.executed(time.Millisecond, false))
t.executed = false first := 0
time.Sleep(time.Millisecond)
if !t.executed { select {
t.clear() case c := <-t.randomNumber:
t.T().Skip("job wasn't as fast as it should be! this may be an error, but also can be just bad timing") 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() 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() { func (t *JobManagerTest) SetupSuite() {
@ -270,6 +382,41 @@ func (t *JobManagerTest) Test_RegisterJobAlreadyExists() {
assert.EqualError(t.T(), err, "job already exists") 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() { func (t *JobManagerTest) Test_RunOnceSync() {
require.NotNil(t.T(), t.manager.jobs) require.NotNil(t.T(), t.manager.jobs)
t.runnerFlag = false t.runnerFlag = false
@ -277,3 +424,9 @@ func (t *JobManagerTest) Test_RunOnceSync() {
require.NoError(t.T(), err) require.NoError(t.T(), err)
assert.True(t.T(), t.runnerFlag) 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`")
}