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  }