github.com/Evanesco-Labs/go-evanesco@v1.0.1/common/prque/lazyqueue_test.go (about) 1 // Copyright 2019 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package prque 18 19 import ( 20 "math/rand" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/Evanesco-Labs/go-evanesco/common/mclock" 26 ) 27 28 const ( 29 testItems = 1000 30 testPriorityStep = 100 31 testSteps = 1000000 32 testStepPeriod = time.Millisecond 33 testQueueRefresh = time.Second 34 testAvgRate = float64(testPriorityStep) / float64(testItems) / float64(testStepPeriod) 35 ) 36 37 type lazyItem struct { 38 p, maxp int64 39 last mclock.AbsTime 40 index int 41 } 42 43 func testPriority(a interface{}) int64 { 44 return a.(*lazyItem).p 45 } 46 47 func testMaxPriority(a interface{}, until mclock.AbsTime) int64 { 48 i := a.(*lazyItem) 49 dt := until - i.last 50 i.maxp = i.p + int64(float64(dt)*testAvgRate) 51 return i.maxp 52 } 53 54 func testSetIndex(a interface{}, i int) { 55 a.(*lazyItem).index = i 56 } 57 58 func TestLazyQueue(t *testing.T) { 59 rand.Seed(time.Now().UnixNano()) 60 clock := &mclock.Simulated{} 61 q := NewLazyQueue(testSetIndex, testPriority, testMaxPriority, clock, testQueueRefresh) 62 63 var ( 64 items [testItems]lazyItem 65 maxPri int64 66 ) 67 68 for i := range items[:] { 69 items[i].p = rand.Int63n(testPriorityStep * 10) 70 if items[i].p > maxPri { 71 maxPri = items[i].p 72 } 73 items[i].index = -1 74 q.Push(&items[i]) 75 } 76 77 var ( 78 lock sync.Mutex 79 wg sync.WaitGroup 80 stopCh = make(chan chan struct{}) 81 ) 82 defer wg.Wait() 83 wg.Add(1) 84 go func() { 85 defer wg.Done() 86 for { 87 select { 88 case <-clock.After(testQueueRefresh): 89 lock.Lock() 90 q.Refresh() 91 lock.Unlock() 92 case <-stopCh: 93 return 94 } 95 } 96 }() 97 98 for c := 0; c < testSteps; c++ { 99 i := rand.Intn(testItems) 100 lock.Lock() 101 items[i].p += rand.Int63n(testPriorityStep*2-1) + 1 102 if items[i].p > maxPri { 103 maxPri = items[i].p 104 } 105 items[i].last = clock.Now() 106 if items[i].p > items[i].maxp { 107 q.Update(items[i].index) 108 } 109 if rand.Intn(100) == 0 { 110 p := q.PopItem().(*lazyItem) 111 if p.p != maxPri { 112 lock.Unlock() 113 close(stopCh) 114 t.Fatalf("incorrect item (best known priority %d, popped %d)", maxPri, p.p) 115 } 116 q.Push(p) 117 } 118 lock.Unlock() 119 clock.Run(testStepPeriod) 120 clock.WaitForTimers(1) 121 } 122 123 close(stopCh) 124 }