github.com/YoungNK/go-ethereum@v1.9.7/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/ethereum/go-ethereum/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{}, now mclock.AbsTime) 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 lock sync.Mutex 78 stopCh := make(chan chan struct{}) 79 go func() { 80 for { 81 select { 82 case <-clock.After(testQueueRefresh): 83 lock.Lock() 84 q.Refresh() 85 lock.Unlock() 86 case stop := <-stopCh: 87 close(stop) 88 return 89 } 90 } 91 }() 92 93 for c := 0; c < testSteps; c++ { 94 i := rand.Intn(testItems) 95 lock.Lock() 96 items[i].p += rand.Int63n(testPriorityStep*2-1) + 1 97 if items[i].p > maxPri { 98 maxPri = items[i].p 99 } 100 items[i].last = clock.Now() 101 if items[i].p > items[i].maxp { 102 q.Update(items[i].index) 103 } 104 if rand.Intn(100) == 0 { 105 p := q.PopItem().(*lazyItem) 106 if p.p != maxPri { 107 t.Fatalf("incorrect item (best known priority %d, popped %d)", maxPri, p.p) 108 } 109 q.Push(p) 110 } 111 lock.Unlock() 112 clock.Run(testStepPeriod) 113 clock.WaitForTimers(1) 114 } 115 116 stop := make(chan struct{}) 117 stopCh <- stop 118 <-stop 119 }