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 }