-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrunner.go
More file actions
122 lines (107 loc) · 2.28 KB
/
runner.go
File metadata and controls
122 lines (107 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package lazytest
import (
"fmt"
"os/exec"
"regexp"
"strings"
"sync"
"sync/atomic"
"time"
)
type testQueue struct {
tests []Batch
}
const (
RunnerIdle int32 = iota
RunnerBusy
)
type TestStatus int8
const (
StatusPending TestStatus = iota
StatusSkipped
StatusFailed
StatusPanicked
StatusPassed
)
type TestReport struct {
Name string
Package string
Status TestStatus
Message string
}
var (
runnerDone chan struct{} = make(chan struct{})
runnerStatus int32
mux sync.Mutex
queue *testQueue = &testQueue{}
rep chan Report
)
type Report []TestReport
func Runner(batch chan Batch) chan Report {
rep = make(chan Report, 50)
go queueTests(batch, rep)
return rep
}
func (t *testQueue) run() {
packageTests := make(map[string][]string)
for _, test := range t.tests {
if _, ok := packageTests[test.Package]; !ok {
packageTests[test.Package] = make([]string, 0)
}
packageTests[test.Package] = append(packageTests[test.Package], regexp.QuoteMeta(test.TestName))
}
for pkg, tests := range packageTests {
cmdStr := []string{"test", "-v", pkg}
if len(tests) > 0 {
testRegexp := fmt.Sprintf("'(%s)'", strings.Join(tests, "|"))
cmdStr = append(cmdStr, "-run", testRegexp)
}
cmd := exec.Command("go", cmdStr...)
out, err := cmd.CombinedOutput()
if err != nil {
log(err.Error())
}
log(string(out))
}
atomic.StoreInt32(&runnerStatus, RunnerIdle)
runnerDone <- struct{}{}
}
func queueTests(batch chan Batch, rep chan Report) {
block := make(chan struct{})
var delay *time.Timer
for {
select {
case b := <-batch:
mux.Lock()
if delay == nil {
log("Filechange detected, running tests...")
delay = time.NewTimer(time.Second * 2)
go func(d *time.Timer) {
<-d.C
block <- struct{}{}
}(delay)
}
if queue.tests == nil {
queue.tests = make([]Batch, 0)
}
queue.tests = append(queue.tests, b)
mux.Unlock()
case <-block:
mux.Lock()
if atomic.CompareAndSwapInt32(&runnerStatus, RunnerIdle, RunnerBusy) {
delay = nil
go queue.run()
queue = &testQueue{}
}
mux.Unlock()
case <-runnerDone:
mux.Lock()
if delay == nil && len(queue.tests) > 0 {
atomic.StoreInt32(&runnerStatus, RunnerBusy)
go queue.run()
queue = &testQueue{}
}
mux.Unlock()
}
}
}