/
scheduler_test.go
155 lines (127 loc) · 3.32 KB
/
scheduler_test.go
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package scheduler
import (
"flag"
"fmt"
"github.com/opinionated/utils/log"
"math/rand"
"os"
"testing"
"time"
)
// Type used for testing the scheduler
type TestSchedulable struct {
start time.Time
delay float64
msg int
c chan int
}
// simple factory function
func MakeTestSchedulable(delay int, id int, i chan int) TestSchedulable {
return TestSchedulable{time.Now(), float64(delay), id, i}
}
// double check we implement all the interfaces
var _ Schedulable = (*TestSchedulable)(nil)
// check if we are ready to run
func (schedulable TestSchedulable) TimeRemaining() int {
// convert this to ms (doesn't have a ms for whatever reason
del := schedulable.delay - time.Since(schedulable.start).Seconds()*1000
if del < 500 {
return 0
}
return int(del)
}
func (schedulable TestSchedulable) SetTimeRemaining(_ int) {}
func (schedulable TestSchedulable) ResetTimer() {
schedulable.start = time.Now()
}
// run the task
func (schedulable TestSchedulable) Run(scheduler *Scheduler) {
schedulable.c <- schedulable.msg
//diff := schedulable.delay - time.Since(schedulable.start).Seconds()*1000
since := time.Since(schedulable.start).Seconds() * 1000
fmt.Println("doing ", schedulable.msg, "at time:", since)
}
func expectResponse(id int, runtimes chan int, t *testing.T) {
select {
case got := <-runtimes:
if got != id {
t.Errorf("expected: %d got: %d", id, got)
}
}
}
func expectNow(id int, runtimes chan int, t *testing.T) {
select {
case got := <-runtimes:
if got != id {
t.Errorf("expected: %d got: %d", id, got)
}
default:
t.Errorf("task %d did not hit on time", id)
}
}
func expectAfter(id int, runtimes chan int, t *testing.T, after int) {
waiter := time.After(time.Duration(after) * time.Millisecond)
select {
case got := <-runtimes:
if got != id {
t.Errorf("expected: %d got: %d", id, got)
}
case <-waiter:
t.Errorf("task %d took too long", id)
}
}
func randomizeAdds(tasks []Schedulable, s *Scheduler) {
for i := range rand.Perm(len(tasks)) {
go s.Add(tasks[i])
}
}
func expectEmpty(c chan int, t *testing.T) {
select {
case got := <-c:
t.Errorf("expected empty but got: %d", got)
default:
}
}
func TestMain(m *testing.M) {
flag.Parse()
log.InitStd()
os.Exit(m.Run())
}
// check that the scheduler removes the tasks one by one properly
func TestSchedulerOneByOne(t *testing.T) {
s := MakeScheduler(5, 3)
s.SetCycleTime(1)
runtimes := make(chan int)
go s.Add(MakeTestSchedulable(1000, 1, runtimes))
go s.Add(MakeTestSchedulable(2000, 2, runtimes))
go s.Add(MakeTestSchedulable(3000, 3, runtimes))
go s.Add(MakeTestSchedulable(4000, 4, runtimes))
s.Start()
ticker := time.NewTicker(1 * time.Second)
for i := 0; i < 4; i++ {
<-ticker.C
expectResponse(i+1, runtimes, t)
}
close(runtimes)
}
func TestSchedulerPairs(t *testing.T) {
s := MakeScheduler(5, 3)
s.SetCycleTime(1)
runtimes := make(chan int)
go randomizeAdds([]Schedulable{
MakeTestSchedulable(600, 1, runtimes),
MakeTestSchedulable(2000, 2, runtimes),
MakeTestSchedulable(3000, 3, runtimes),
MakeTestSchedulable(4000, 4, runtimes),
}, s)
s.Start()
expectAfter(1, runtimes, t, 1200)
expectEmpty(runtimes, t)
expectAfter(2, runtimes, t, 1100)
expectEmpty(runtimes, t)
expectAfter(3, runtimes, t, 1100)
expectEmpty(runtimes, t)
expectAfter(4, runtimes, t, 1100)
expectEmpty(runtimes, t)
close(runtimes)
}