github.com/dominant-strategies/go-quai@v0.28.2/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/dominant-strategies/go-quai/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  }