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