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  }