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  }