github.com/amazechain/amc@v0.1.3/common/prque/lazyqueue_test.go (about) 1 // Copyright 2023 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package prque 18 19 import ( 20 "github.com/amazechain/amc/common/mclock" 21 "math/rand" 22 "sync" 23 "testing" 24 "time" 25 ) 26 27 const ( 28 testItems = 1000 29 testPriorityStep = 100 30 testSteps = 1000000 31 testStepPeriod = time.Millisecond 32 testQueueRefresh = time.Second 33 testAvgRate = float64(testPriorityStep) / float64(testItems) / float64(testStepPeriod) 34 ) 35 36 type lazyItem struct { 37 p, maxp int64 38 last mclock.AbsTime 39 index int 40 } 41 42 func testPriority(a interface{}) int64 { 43 return a.(*lazyItem).p 44 } 45 46 func testMaxPriority(a interface{}, until mclock.AbsTime) int64 { 47 i := a.(*lazyItem) 48 dt := until - i.last 49 i.maxp = i.p + int64(float64(dt)*testAvgRate) 50 return i.maxp 51 } 52 53 func testSetIndex(a interface{}, i int) { 54 a.(*lazyItem).index = i 55 } 56 57 func TestLazyQueue(t *testing.T) { 58 rand.Seed(time.Now().UnixNano()) 59 clock := &mclock.Simulated{} 60 q := NewLazyQueue(testSetIndex, testPriority, testMaxPriority, clock, testQueueRefresh) 61 62 var ( 63 items [testItems]lazyItem 64 maxPri int64 65 ) 66 67 for i := range items[:] { 68 items[i].p = rand.Int63n(testPriorityStep * 10) 69 if items[i].p > maxPri { 70 maxPri = items[i].p 71 } 72 items[i].index = -1 73 q.Push(&items[i]) 74 } 75 76 var ( 77 lock sync.Mutex 78 wg sync.WaitGroup 79 stopCh = make(chan chan struct{}) 80 ) 81 defer wg.Wait() 82 wg.Add(1) 83 go func() { 84 defer wg.Done() 85 for { 86 select { 87 case <-clock.After(testQueueRefresh): 88 lock.Lock() 89 q.Refresh() 90 lock.Unlock() 91 case <-stopCh: 92 return 93 } 94 } 95 }() 96 97 for c := 0; c < testSteps; c++ { 98 i := rand.Intn(testItems) 99 lock.Lock() 100 items[i].p += rand.Int63n(testPriorityStep*2-1) + 1 101 if items[i].p > maxPri { 102 maxPri = items[i].p 103 } 104 items[i].last = clock.Now() 105 if items[i].p > items[i].maxp { 106 q.Update(items[i].index) 107 } 108 if rand.Intn(100) == 0 { 109 p := q.PopItem().(*lazyItem) 110 if p.p != maxPri { 111 lock.Unlock() 112 close(stopCh) 113 t.Fatalf("incorrect item (best known priority %d, popped %d)", maxPri, p.p) 114 } 115 q.Push(p) 116 } 117 lock.Unlock() 118 clock.Run(testStepPeriod) 119 clock.WaitForTimers(1) 120 } 121 122 close(stopCh) 123 }