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