github.com/number571/tendermint@v0.34.11-gost/internal/libs/clist/clist_test.go (about) 1 package clist 2 3 import ( 4 "fmt" 5 mrand "math/rand" 6 "runtime" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestPanicOnMaxLength(t *testing.T) { 15 maxLength := 1000 16 17 l := newWithMax(maxLength) 18 for i := 0; i < maxLength; i++ { 19 l.PushBack(1) 20 } 21 assert.Panics(t, func() { 22 l.PushBack(1) 23 }) 24 } 25 26 func TestSmall(t *testing.T) { 27 l := New() 28 el1 := l.PushBack(1) 29 el2 := l.PushBack(2) 30 el3 := l.PushBack(3) 31 if l.Len() != 3 { 32 t.Error("Expected len 3, got ", l.Len()) 33 } 34 35 // fmt.Printf("%p %v\n", el1, el1) 36 // fmt.Printf("%p %v\n", el2, el2) 37 // fmt.Printf("%p %v\n", el3, el3) 38 39 r1 := l.Remove(el1) 40 41 // fmt.Printf("%p %v\n", el1, el1) 42 // fmt.Printf("%p %v\n", el2, el2) 43 // fmt.Printf("%p %v\n", el3, el3) 44 45 r2 := l.Remove(el2) 46 47 // fmt.Printf("%p %v\n", el1, el1) 48 // fmt.Printf("%p %v\n", el2, el2) 49 // fmt.Printf("%p %v\n", el3, el3) 50 51 r3 := l.Remove(el3) 52 53 if r1 != 1 { 54 t.Error("Expected 1, got ", r1) 55 } 56 if r2 != 2 { 57 t.Error("Expected 2, got ", r2) 58 } 59 if r3 != 3 { 60 t.Error("Expected 3, got ", r3) 61 } 62 if l.Len() != 0 { 63 t.Error("Expected len 0, got ", l.Len()) 64 } 65 66 } 67 68 func TestGCFifo(t *testing.T) { 69 70 const numElements = 1000000 71 l := New() 72 gcCount := 0 73 74 // SetFinalizer doesn't work well with circular structures, 75 // so we construct a trivial non-circular structure to 76 // track. 77 type value struct { 78 Int int 79 } 80 81 gcCh := make(chan struct{}) 82 for i := 0; i < numElements; i++ { 83 v := new(value) 84 v.Int = i 85 l.PushBack(v) 86 runtime.SetFinalizer(v, func(v *value) { 87 gcCh <- struct{}{} 88 }) 89 } 90 91 for el := l.Front(); el != nil; { 92 l.Remove(el) 93 // oldEl := el 94 el = el.Next() 95 // oldEl.DetachPrev() 96 // oldEl.DetachNext() 97 } 98 99 tickerQuitCh := make(chan struct{}) 100 tickerDoneCh := make(chan struct{}) 101 go func() { 102 defer close(tickerDoneCh) 103 ticker := time.NewTicker(time.Second) 104 for { 105 select { 106 case <-ticker.C: 107 runtime.GC() 108 case <-tickerQuitCh: 109 return 110 } 111 } 112 }() 113 114 for i := 0; i < numElements; i++ { 115 <-gcCh 116 gcCount++ 117 } 118 119 close(tickerQuitCh) 120 <-tickerDoneCh 121 122 if gcCount != numElements { 123 t.Errorf("expected gcCount to be %v, got %v", numElements, 124 gcCount) 125 } 126 } 127 128 func TestGCRandom(t *testing.T) { 129 130 const numElements = 1000000 131 l := New() 132 gcCount := 0 133 134 // SetFinalizer doesn't work well with circular structures, 135 // so we construct a trivial non-circular structure to 136 // track. 137 type value struct { 138 Int int 139 } 140 141 gcCh := make(chan struct{}) 142 for i := 0; i < numElements; i++ { 143 v := new(value) 144 v.Int = i 145 l.PushBack(v) 146 runtime.SetFinalizer(v, func(v *value) { 147 gcCh <- struct{}{} 148 }) 149 } 150 151 els := make([]*CElement, 0, numElements) 152 for el := l.Front(); el != nil; el = el.Next() { 153 els = append(els, el) 154 } 155 156 for _, i := range mrand.Perm(numElements) { 157 el := els[i] 158 l.Remove(el) 159 _ = el.Next() 160 } 161 162 tickerQuitCh := make(chan struct{}) 163 tickerDoneCh := make(chan struct{}) 164 go func() { 165 defer close(tickerDoneCh) 166 ticker := time.NewTicker(time.Second) 167 for { 168 select { 169 case <-ticker.C: 170 runtime.GC() 171 case <-tickerQuitCh: 172 return 173 } 174 } 175 }() 176 177 for i := 0; i < numElements; i++ { 178 <-gcCh 179 gcCount++ 180 } 181 182 close(tickerQuitCh) 183 <-tickerDoneCh 184 185 if gcCount != numElements { 186 t.Errorf("expected gcCount to be %v, got %v", numElements, 187 gcCount) 188 } 189 } 190 191 func TestScanRightDeleteRandom(t *testing.T) { 192 193 const numElements = 1000 194 const numTimes = 100 195 const numScanners = 10 196 197 l := New() 198 stop := make(chan struct{}) 199 200 els := make([]*CElement, numElements) 201 for i := 0; i < numElements; i++ { 202 el := l.PushBack(i) 203 els[i] = el 204 } 205 206 // Launch scanner routines that will rapidly iterate over elements. 207 for i := 0; i < numScanners; i++ { 208 go func(scannerID int) { 209 var el *CElement 210 restartCounter := 0 211 counter := 0 212 FOR_LOOP: 213 for { 214 select { 215 case <-stop: 216 fmt.Println("stopped") 217 break FOR_LOOP 218 default: 219 } 220 if el == nil { 221 el = l.FrontWait() 222 restartCounter++ 223 } 224 el = el.Next() 225 counter++ 226 } 227 fmt.Printf("Scanner %v restartCounter: %v counter: %v\n", scannerID, restartCounter, counter) 228 }(i) 229 } 230 231 // Remove an element, push back an element. 232 for i := 0; i < numTimes; i++ { 233 // Pick an element to remove 234 rmElIdx := mrand.Intn(len(els)) 235 rmEl := els[rmElIdx] 236 237 // Remove it 238 l.Remove(rmEl) 239 // fmt.Print(".") 240 241 // Insert a new element 242 newEl := l.PushBack(-1*i - 1) 243 els[rmElIdx] = newEl 244 245 if i%100000 == 0 { 246 fmt.Printf("Pushed %vK elements so far...\n", i/1000) 247 } 248 249 } 250 251 // Stop scanners 252 close(stop) 253 // time.Sleep(time.Second * 1) 254 255 // And remove all the elements. 256 for el := l.Front(); el != nil; el = el.Next() { 257 l.Remove(el) 258 } 259 if l.Len() != 0 { 260 t.Fatal("Failed to remove all elements from CList") 261 } 262 } 263 264 func TestWaitChan(t *testing.T) { 265 l := New() 266 ch := l.WaitChan() 267 268 // 1) add one element to an empty list 269 go l.PushBack(1) 270 <-ch 271 272 // 2) and remove it 273 el := l.Front() 274 v := l.Remove(el) 275 if v != 1 { 276 t.Fatal("where is 1 coming from?") 277 } 278 279 // 3) test iterating forward and waiting for Next (NextWaitChan and Next) 280 el = l.PushBack(0) 281 282 done := make(chan struct{}) 283 pushed := 0 284 go func() { 285 for i := 1; i < 100; i++ { 286 l.PushBack(i) 287 pushed++ 288 time.Sleep(time.Duration(mrand.Intn(25)) * time.Millisecond) 289 } 290 // apply a deterministic pause so the counter has time to catch up 291 time.Sleep(25 * time.Millisecond) 292 close(done) 293 }() 294 295 next := el 296 seen := 0 297 FOR_LOOP: 298 for { 299 select { 300 case <-next.NextWaitChan(): 301 next = next.Next() 302 seen++ 303 if next == nil { 304 t.Fatal("Next should not be nil when waiting on NextWaitChan") 305 } 306 case <-done: 307 break FOR_LOOP 308 case <-time.After(10 * time.Second): 309 t.Fatal("max execution time") 310 } 311 } 312 313 if pushed != seen { 314 t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen) 315 } 316 317 // 4) test iterating backwards (PrevWaitChan and Prev) 318 prev := next 319 seen = 0 320 FOR_LOOP2: 321 for { 322 select { 323 case <-prev.PrevWaitChan(): 324 prev = prev.Prev() 325 seen++ 326 if prev == nil { 327 t.Fatal("expected PrevWaitChan to block forever on nil when reached first elem") 328 } 329 case <-time.After(3 * time.Second): 330 break FOR_LOOP2 331 } 332 } 333 334 if pushed != seen { 335 t.Fatalf("number of pushed items (%d) not equal to number of seen items (%d)", pushed, seen) 336 } 337 } 338 339 func TestRemoved(t *testing.T) { 340 l := New() 341 el1 := l.PushBack(1) 342 el2 := l.PushBack(2) 343 l.Remove(el1) 344 require.True(t, el1.Removed()) 345 require.False(t, el2.Removed()) 346 } 347 348 func TestNextWaitChan(t *testing.T) { 349 l := New() 350 el1 := l.PushBack(1) 351 t.Run("tail element should not have a closed nextWaitChan", func(t *testing.T) { 352 select { 353 case <-el1.NextWaitChan(): 354 t.Fatal("nextWaitChan should not have been closed") 355 default: 356 } 357 }) 358 359 el2 := l.PushBack(2) 360 t.Run("adding element should close tail nextWaitChan", func(t *testing.T) { 361 select { 362 case <-el1.NextWaitChan(): 363 require.NotNil(t, el1.Next()) 364 default: 365 t.Fatal("nextWaitChan should have been closed") 366 } 367 368 select { 369 case <-el2.NextWaitChan(): 370 t.Fatal("nextWaitChan should not have been closed") 371 default: 372 } 373 }) 374 375 t.Run("removing element should close its nextWaitChan", func(t *testing.T) { 376 l.Remove(el2) 377 select { 378 case <-el2.NextWaitChan(): 379 require.Nil(t, el2.Next()) 380 default: 381 t.Fatal("nextWaitChan should have been closed") 382 } 383 }) 384 }