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