github.com/sequix/cortex@v1.1.6/pkg/ruler/scheduler_test.go (about) 1 package ruler 2 3 import ( 4 "strconv" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/assert" 9 10 "github.com/prometheus/prometheus/rules" 11 ) 12 13 type fakeHasher struct { 14 data *[]byte 15 } 16 17 func (h *fakeHasher) Write(data []byte) (int, error) { 18 h.data = &data 19 return len(data), nil 20 } 21 func (h *fakeHasher) Reset() { 22 h.data = nil 23 } 24 func (h *fakeHasher) Size() int { 25 return 0 26 } 27 func (h *fakeHasher) BlockSize() int { 28 return 64 29 } 30 func (h *fakeHasher) Sum([]byte) []byte { 31 return []byte{} 32 } 33 func (h *fakeHasher) Sum64() uint64 { 34 i, _ := strconv.ParseUint(string(*h.data), 10, 64) 35 return i 36 } 37 38 func TestSchedulerComputeNextEvalTime(t *testing.T) { 39 h := fakeHasher{} 40 // normal intervals are in seconds; this is nanoseconds for the test 41 s := scheduler{evaluationInterval: 15} 42 evalTime := func(now, hashResult int64) int64 { 43 // We use the fake hasher to give us control over the hash output 44 // so that we can test the wrap-around behaviour of the modulo 45 fakeUserID := strconv.FormatInt(hashResult, 10) 46 return s.computeNextEvalTime(&h, time.Unix(0, now), fakeUserID).UnixNano() 47 } 48 { 49 cycleStartTime := int64(30) 50 cycleOffset := int64(0) // cycleStartTime % s.evaluationInterval 51 // Check simple case where hash >= current cycle position 52 assert.Equal(t, cycleStartTime+0, evalTime(cycleStartTime, cycleOffset+0)) 53 assert.Equal(t, cycleStartTime+1, evalTime(cycleStartTime, cycleOffset+1)) 54 assert.Equal(t, cycleStartTime+14, evalTime(cycleStartTime, cycleOffset+14)) 55 // Check things are cyclic 56 assert.Equal(t, evalTime(cycleStartTime, 0), evalTime(cycleStartTime, int64(s.evaluationInterval))) 57 } 58 { 59 midCycleTime := int64(35) 60 cycleOffset := int64(5) // midCycleTime % s.evaluationInterval 61 // Check case where hash can be either greater or less than current cycle position 62 assert.Equal(t, midCycleTime+0, evalTime(midCycleTime, cycleOffset+0)) 63 assert.Equal(t, midCycleTime+1, evalTime(midCycleTime, cycleOffset+1)) 64 assert.Equal(t, midCycleTime+9, evalTime(midCycleTime, cycleOffset+9)) 65 assert.Equal(t, midCycleTime+10, evalTime(midCycleTime, cycleOffset-5)) 66 assert.Equal(t, midCycleTime+14, evalTime(midCycleTime, cycleOffset-1)) 67 } 68 } 69 70 func TestSchedulerRulesOverlap(t *testing.T) { 71 s := newScheduler(nil, 15, 15, nil, nil) 72 userID := "bob" 73 groupName := "test" 74 next := time.Now() 75 76 ruleSet := []rules.Rule{ 77 nil, 78 } 79 ruleSets := map[string][]rules.Rule{} 80 ruleSets[groupName] = ruleSet 81 82 cfg := userConfig{generation: 1, rules: ruleSets} 83 s.cfgs[userID] = cfg 84 w1 := workItem{userID: userID, groupName: groupName, scheduled: next, generation: cfg.generation} 85 s.workItemDone(w1) 86 item := s.q.Dequeue().(workItem) 87 assert.Equal(t, w1.generation, item.generation) 88 89 w0 := workItem{userID: userID, groupName: groupName, scheduled: next, generation: cfg.generation - 1} 90 s.workItemDone(w1) 91 s.workItemDone(w0) 92 item = s.q.Dequeue().(workItem) 93 assert.Equal(t, w1.generation, item.generation) 94 95 s.q.Close() 96 assert.Equal(t, nil, s.q.Dequeue()) 97 }