github.com/aergoio/aergo@v1.3.1/p2p/p2putil/mutexpipe_test.go (about)

     1  /*
     2   * @file
     3   * @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package p2putil
     7  
     8  import (
     9  	"fmt"
    10  	"sync"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/aergoio/aergo-lib/log"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestMutexPipe(t *testing.T) {
    19  	const arrSize = 30
    20  	var mos [arrSize]TestItem
    21  	for i := 0; i < arrSize; i++ {
    22  		mos[i] = &testItem{i}
    23  	}
    24  
    25  	logger := log.NewLogger("test")
    26  	tests := []struct {
    27  		name      string
    28  		cap       int
    29  		finishIdx int
    30  
    31  		expectMinOut uint64
    32  		expectConsec uint64
    33  		//expectMinOut uint64
    34  		//expectOut    uint64
    35  	}{
    36  		{"tStall", 10, 0, 2, 18},
    37  		{"tmidStall", 10, 5, 7, 13},
    38  		{"tfast", 10, 1000, arrSize - 10, 0},
    39  		//{"tStall", 10, 1, 2, 2},
    40  		//{"tmidStall", 10, 5, 6, 6},
    41  		//{"tfast", 10, 1000, arrSize - 10, 30},
    42  		// TODO: Add test cases.
    43  	}
    44  
    45  	for _, tt := range tests {
    46  		t.Run(tt.name, func(t *testing.T) {
    47  			doneC := make(chan int, 1)
    48  			statListener := NewStatLister()
    49  			listener := NewMultiListener(statListener, &logListener{logger}, &orderCheckListener{t: t, outId: -1, dropId: -1})
    50  			//c := newMutexPipe(tt.cap, listener)
    51  			c := newMutexPipe(tt.cap, listener)
    52  			c.Open()
    53  			failCount := 0
    54  			go consumeStall(c, tt.finishIdx, arrSize, doneC)
    55  			for _, mo := range mos {
    56  				if !c.Put(mo) {
    57  					failCount++
    58  				}
    59  				time.Sleep(time.Millisecond)
    60  
    61  			}
    62  			consumedCount := <-doneC
    63  			lock := &sync.Mutex{}
    64  			lock.Lock()
    65  			actStat := statListener
    66  			lock.Unlock()
    67  
    68  			fmt.Printf("In %d , out %d , failed count %d\n", actStat.incnt, actStat.outcnt, failCount)
    69  			assert.Equal(t, uint64(arrSize), actStat.incnt)
    70  			assert.True(t, actStat.incnt == arrSize)
    71  			if tt.expectConsec == 0 {
    72  				assert.Equal(t, uint64(consumedCount), actStat.outcnt)
    73  				assert.Equal(t, actStat.incnt, actStat.outcnt)
    74  			} else {
    75  				assert.Equal(t, uint64(consumedCount+1), actStat.outcnt)
    76  				assert.Equal(t, actStat.incnt, actStat.outcnt+actStat.consecdrop+uint64(tt.cap))
    77  			}
    78  
    79  			//c.Close()
    80  		})
    81  	}
    82  }
    83  
    84  func TestMutexPipe_nonBlockWriteChan2(t *testing.T) {
    85  	const arrSize = 30
    86  	var mos [arrSize]TestItem
    87  	for i := 0; i < arrSize; i++ {
    88  		mos[i] = &testItem{i}
    89  	}
    90  	logger := log.NewLogger("test")
    91  
    92  	tests := []struct {
    93  		name     string
    94  		cap      int
    95  		stallIdx int
    96  
    97  		expectMinOut uint64
    98  		expectConsec uint64
    99  	}{
   100  		{"tfast", 10, 1000, arrSize - 10, 0},
   101  		// TODO: Add test cases.
   102  	}
   103  
   104  	for _, tt := range tests {
   105  		t.Run(tt.name, func(t *testing.T) {
   106  			doneC := make(chan int, 1)
   107  			statListener := NewStatLister()
   108  			listener := NewMultiListener(statListener, &logListener{logger}, &orderCheckListener{t: t, outId: -1, dropId: -1})
   109  			c := newMutexPipe(tt.cap, listener)
   110  			c.Open()
   111  
   112  			go consumeStall2(c, tt.stallIdx, arrSize, doneC)
   113  			for _, mo := range mos {
   114  				for !c.Put(mo) {
   115  					time.Sleep(time.Millisecond << 3)
   116  				}
   117  			}
   118  			consumeCount := <-doneC
   119  			lock := &sync.Mutex{}
   120  			lock.Lock()
   121  			actStat := statListener
   122  			lock.Unlock()
   123  
   124  			fmt.Printf("In %d , out %d , consecutive drop %d\n", actStat.incnt, actStat.outcnt, actStat.consecdrop)
   125  			assert.True(t, actStat.incnt == arrSize)
   126  			assert.Equal(t, uint64(consumeCount), actStat.outcnt)
   127  
   128  			c.Close()
   129  		})
   130  	}
   131  }
   132  
   133  func TestMutexPipe_Longterm(t *testing.T) {
   134  	// skip unit test in normal time..
   135  	t.SkipNow()
   136  	const arrSize = 30
   137  	var mos [arrSize]TestItem
   138  	for i := 0; i < arrSize; i++ {
   139  		mos[i] = &testItem{i}
   140  	}
   141  
   142  	logger := log.NewLogger("test")
   143  	tests := []struct {
   144  		name     string
   145  		cap      int
   146  		testTime time.Duration
   147  	}{
   148  		{"tlong", 20, time.Second * 10},
   149  		{"tlong", 20, time.Second * 11},
   150  		{"tlong", 20, time.Second * 12},
   151  		{"tlong", 20, time.Second * 13},
   152  		{"tlong", 20, time.Second * 14},
   153  		{"tlong", 20, time.Second * 15},
   154  		{"tlong", 20, time.Second * 16},
   155  		{"tlong", 20, time.Second * 17},
   156  		{"tlong", 20, time.Second * 18},
   157  		{"tlong", 20, time.Second * 19},
   158  	}
   159  
   160  	for _, tt := range tests {
   161  		t.Run(tt.name, func(t *testing.T) {
   162  			doneC := make(chan int, 1)
   163  			finish := make(chan interface{})
   164  			statListener := NewStatLister()
   165  			listener := NewMultiListener(statListener, &logListener{logger})
   166  			c := newMutexPipe(tt.cap, listener)
   167  			c.Open()
   168  
   169  			go consumeForLongTerm(c, tt.testTime+time.Minute, doneC, finish)
   170  			expire := time.Now().Add(tt.testTime)
   171  
   172  			i := 0
   173  			for time.Now().Before(expire) {
   174  				c.Put(mos[i%arrSize])
   175  				time.Sleep(time.Millisecond * 5)
   176  				i++
   177  
   178  			}
   179  			finish <- struct{}{}
   180  			consumeCount := <-doneC
   181  			lock := &sync.Mutex{}
   182  			lock.Lock()
   183  			actStat := statListener
   184  			rqueue := c.queue
   185  			lock.Unlock()
   186  
   187  			fmt.Printf("In %d , out %d , drop %d, consecutive drop %d\n", actStat.incnt, actStat.outcnt, actStat.dropcnt, actStat.consecdrop)
   188  			assert.Equal(t, actStat.incnt, uint64(i))
   189  			// last one is in channel and not consumed
   190  			assert.Equal(t, uint64(consumeCount+1), actStat.outcnt)
   191  			// in should equal to sum of out, drop, and remained in queue
   192  			assert.Equal(t, actStat.incnt, actStat.outcnt+actStat.dropcnt+uint64(rqueue.Size()))
   193  
   194  			c.Close()
   195  		})
   196  	}
   197  }
   198  
   199  func TestMutexPipe_MultiLoads(t *testing.T) {
   200  	// skip unit test in normal time..
   201  	// t.SkipNow()
   202  	const threadsize = 100
   203  	const arrSize = 30
   204  	var mos [threadsize][arrSize]TestItem
   205  	for j := 0; j < threadsize; j++ {
   206  		for i := 0; i < arrSize; i++ {
   207  			mos[j][i] = &testItem2{testItem{i}, j}
   208  		}
   209  	}
   210  
   211  	// logger := log.NewLogger("test")
   212  	tests := []struct {
   213  		name     string
   214  		cap      int
   215  		testTime time.Duration
   216  	}{
   217  		{"tlong", 20, time.Second},
   218  	}
   219  
   220  	for _, tt := range tests {
   221  		t.Run(tt.name, func(t *testing.T) {
   222  			doneC := make(chan int, 1)
   223  			finish := make(chan interface{})
   224  			statListener := NewStatLister()
   225  			listener := NewMultiListener(statListener)
   226  			c := newDefaultChannelPipe(tt.cap, listener)
   227  			c.Open()
   228  
   229  			go consumeForLongTerm(c, tt.testTime+time.Minute, doneC, finish)
   230  			wg := sync.WaitGroup{}
   231  			expire := time.Now().Add(tt.testTime)
   232  			wg.Add(threadsize)
   233  			for j := 0; j < threadsize; j++ {
   234  				go func(tid int) {
   235  					i := 0
   236  					for time.Now().Before(expire) {
   237  						c.Put(mos[i%arrSize])
   238  						i++
   239  					}
   240  					wg.Done()
   241  				}(j)
   242  			}
   243  			wg.Wait()
   244  			finish <- struct{}{}
   245  			consumeCount := <-doneC
   246  			lock := &sync.Mutex{}
   247  			lock.Lock()
   248  			actStat := statListener
   249  			rqueue := c.queue
   250  			lock.Unlock()
   251  
   252  			fmt.Printf("In %d , out %d , drop %d, consecutive drop %d\n", actStat.incnt, actStat.outcnt, actStat.dropcnt, actStat.consecdrop)
   253  			// There are two cases, one is last one is in channel and not consumed, and another is consumed all items.
   254  			assert.True(t, actStat.outcnt-uint64(consumeCount) <= 1)
   255  			// in should equal to sum of out, drop, and remained in queue
   256  			assert.Equal(t, actStat.incnt, actStat.outcnt+actStat.dropcnt+uint64(rqueue.Size()))
   257  
   258  			c.Close()
   259  		})
   260  	}
   261  }