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  }