github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/collection/lscq/lscq_test.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package lscq 16 17 import ( 18 "sync" 19 "testing" 20 "unsafe" 21 22 "github.com/bytedance/gopkg/collection/skipset" 23 "github.com/bytedance/gopkg/lang/fastrand" 24 ) 25 26 func TestBoundedQueue(t *testing.T) { 27 q := newUint64SCQ() 28 s := skipset.NewUint64() 29 30 // Dequeue empty queue. 31 val, ok := q.Dequeue() 32 if ok { 33 t.Fatal(val) 34 } 35 36 // Single goroutine correctness. 37 for i := 0; i < scqsize; i++ { 38 if !q.Enqueue(uint64(i)) { 39 t.Fatal(i) 40 } 41 s.Add(uint64(i)) 42 } 43 44 if q.Enqueue(20) { // queue is full 45 t.Fatal() 46 } 47 48 s.Range(func(value uint64) bool { 49 if val, ok := q.Dequeue(); !ok || val != value { 50 t.Fatal(val, ok, value) 51 } 52 return true 53 }) 54 55 // Dequeue empty queue after previous loop. 56 val, ok = q.Dequeue() 57 if ok { 58 t.Fatal(val) 59 } 60 61 // ---------- MULTIPLE TEST BEGIN ----------. 62 for j := 0; j < 10; j++ { 63 s = skipset.NewUint64() 64 65 // Dequeue empty queue. 66 val, ok = q.Dequeue() 67 if ok { 68 t.Fatal(val) 69 } 70 71 // Single goroutine correctness. 72 for i := 0; i < scqsize; i++ { 73 if !q.Enqueue(uint64(i)) { 74 t.Fatal() 75 } 76 s.Add(uint64(i)) 77 } 78 79 if q.Enqueue(20) { // queue is full 80 t.Fatal() 81 } 82 83 s.Range(func(value uint64) bool { 84 if val, ok := q.Dequeue(); !ok || val != value { 85 t.Fatal(val, ok, value) 86 } 87 return true 88 }) 89 90 // Dequeue empty queue after previous loop. 91 val, ok = q.Dequeue() 92 if ok { 93 t.Fatal(val) 94 } 95 } 96 // ---------- MULTIPLE TEST END ----------. 97 98 // MPMC correctness. 99 var wg sync.WaitGroup 100 s1 := skipset.NewUint64() 101 s2 := skipset.NewUint64() 102 for i := 0; i < 100000; i++ { 103 wg.Add(1) 104 go func() { 105 if fastrand.Uint32n(2) == 0 { 106 r := fastrand.Uint64() 107 if q.Enqueue(r) { 108 s1.Add(r) 109 } 110 } else { 111 val, ok := q.Dequeue() 112 if ok { 113 s2.Add(uint64(val)) 114 } 115 } 116 wg.Done() 117 }() 118 } 119 wg.Wait() 120 121 for { 122 val, ok := q.Dequeue() 123 if !ok { 124 break 125 } 126 s2.Add(uint64(val)) 127 } 128 129 s1.Range(func(value uint64) bool { 130 if !s2.Contains(value) { 131 t.Fatal(value) 132 } 133 return true 134 }) 135 136 if s1.Len() != s2.Len() { 137 t.Fatal("invalid") 138 } 139 } 140 141 func TestUnboundedQueue(t *testing.T) { 142 // MPMC correctness. 143 q := NewUint64() 144 var wg sync.WaitGroup 145 s1 := skipset.NewUint64() 146 s2 := skipset.NewUint64() 147 for i := 0; i < 100000; i++ { 148 wg.Add(1) 149 go func() { 150 if fastrand.Uint32n(2) == 0 { 151 r := fastrand.Uint64() 152 if !s1.Add(r) || !q.Enqueue(r) { 153 panic("invalid") 154 } 155 } else { 156 val, ok := q.Dequeue() 157 if ok { 158 s2.Add(uint64(val)) 159 } 160 } 161 wg.Done() 162 }() 163 } 164 wg.Wait() 165 166 for { 167 val, ok := q.Dequeue() 168 if !ok { 169 break 170 } 171 s2.Add(uint64(val)) 172 } 173 174 s1.Range(func(value uint64) bool { 175 if !s2.Contains(value) { 176 t.Fatal(value) 177 } 178 return true 179 }) 180 181 if s1.Len() != s2.Len() { 182 t.Fatal("invalid") 183 } 184 } 185 186 type foo struct { 187 val int 188 } 189 190 func TestPointerQueue(t *testing.T) { 191 q := NewPointer() 192 193 for i := 0; i < 10; i++ { 194 q.Enqueue(unsafe.Pointer(&foo{val: i})) 195 } 196 197 for i := 0; i < 10; i++ { 198 if p, ok := q.Dequeue(); !ok || (*foo)(p).val != i { 199 t.Fatal("got:", (*foo)(p).val, ok, "expect:", i, true) 200 } 201 } 202 }