github.com/cloudwego/kitex@v0.9.0/pkg/utils/ring_test.go (about) 1 /* 2 * Copyright 2021 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package utils 18 19 import ( 20 "sync" 21 "sync/atomic" 22 "testing" 23 24 "github.com/cloudwego/kitex/internal/test" 25 ) 26 27 // TestNewRing test new a ring object 28 func TestNewRing(t *testing.T) { 29 r := NewRing(10) 30 31 obj1 := r.Pop() 32 test.Assert(t, obj1 == nil) 33 34 obj2 := "test string" 35 err := r.Push(obj2) 36 test.Assert(t, err == nil) 37 38 obj3 := r.Pop() 39 test.Assert(t, obj3.(string) == obj2) 40 41 r = NewRing(1) 42 test.Assert(t, r.length == 1) 43 44 test.Panic(t, func() { 45 r = NewRing(0) 46 }) 47 } 48 49 // TestRing_Push test ring push 50 func TestRing_Push(t *testing.T) { 51 var err error 52 // size > 0 53 r := NewRing(10) 54 for i := 0; i < 20; i++ { 55 err = r.Push(i) 56 57 if i < 10 { 58 test.Assert(t, err == nil) 59 } else { 60 test.Assert(t, err != nil) 61 } 62 } 63 64 // size == 1 65 r = NewRing(1) 66 err = r.Push(1) 67 test.Assert(t, err == nil) 68 } 69 70 // TestRing_Pop test ring pop 71 func TestRing_Pop(t *testing.T) { 72 // size > 0 73 r := NewRing(10) 74 for i := 0; i < 10; i++ { 75 err := r.Push(i) 76 test.Assert(t, err == nil) 77 } 78 79 for i := 0; i < 20; i++ { 80 if i < 10 { 81 elem := r.Pop() 82 test.Assert(t, elem != nil) 83 } else { 84 elem := r.Pop() 85 test.Assert(t, elem == nil) 86 } 87 } 88 89 // size == 1 90 r = NewRing(1) 91 err := r.Push(1) 92 test.Assert(t, err == nil) 93 elem := r.Pop() 94 test.Assert(t, elem != nil) 95 } 96 97 // TestRing_Dump test dump data of a ring 98 func TestRing_Dump(t *testing.T) { 99 elemTotal := 97 100 r := NewRing(elemTotal) 101 for i := 0; i < elemTotal; i++ { 102 err := r.Push(i) 103 test.Assert(t, err == nil) 104 } 105 106 dumpRet := r.Dump().(*ringDump) 107 test.Assert(t, dumpRet != nil) 108 test.Assert(t, dumpRet.Len == elemTotal) 109 test.Assert(t, dumpRet.Cap >= elemTotal) 110 for i := 0; i < elemTotal; i++ { 111 test.Assert(t, dumpRet.Array[i].(int) == i) 112 } 113 } 114 115 // TestRing_SingleDump test dump data of a ring node 116 func TestRing_SingleDump(t *testing.T) { 117 elemTotal := 10 118 r := NewRing(elemTotal) 119 for i := 0; i < elemTotal; i++ { 120 err := r.Push(i) 121 test.Assert(t, err == nil) 122 } 123 124 singleDump := &ringDump{} 125 r.rings[0].Dump(singleDump) 126 test.Assert(t, singleDump != nil) 127 test.Assert(t, singleDump.Cap == r.rings[0].size+1) 128 test.Assert(t, singleDump.Len == r.rings[0].size) 129 for i := 0; i < singleDump.Len; i++ { 130 test.Assert(t, singleDump.Array[i].(int) == r.rings[0].arr[i]) 131 } 132 } 133 134 func TestRing_Parallel(t *testing.T) { 135 r := NewRing(10) 136 var wg sync.WaitGroup 137 138 flag := make([]bool, 100) 139 var errCount int64 140 for i := 0; i < 100; i++ { 141 wg.Add(1) 142 go func(v int) { 143 defer wg.Done() 144 if err := r.Push(v); err != nil { 145 atomic.AddInt64(&errCount, 1) 146 } else { 147 flag[v] = true 148 } 149 }(i) 150 } 151 wg.Wait() 152 test.Assert(t, errCount == 90) 153 154 for i := 0; i < 100; i++ { 155 wg.Add(1) 156 go func() { 157 defer wg.Done() 158 if x := r.Pop(); x != nil { 159 j, ok := x.(int) 160 test.Assert(t, ok) 161 test.Assert(t, flag[j]) 162 } 163 }() 164 } 165 wg.Wait() 166 } 167 168 func BenchmarkRing(b *testing.B) { 169 size := 1024 170 r := NewRing(size) 171 for i := 0; i < size; i++ { 172 r.Push(struct{}{}) 173 } 174 175 // benchmark 176 b.ReportAllocs() 177 b.ResetTimer() 178 for i := 0; i < b.N; i++ { 179 obj := r.Pop() 180 r.Push(obj) 181 } 182 } 183 184 func BenchmarkRing_Dump(b *testing.B) { 185 size := 1000000 186 r := NewRing(size) 187 for i := 0; i < size; i++ { 188 r.Push(struct{}{}) 189 } 190 191 // benchmark 192 b.ReportAllocs() 193 b.ResetTimer() 194 for i := 0; i < b.N; i++ { 195 _ = r.Dump() 196 } 197 } 198 199 func BenchmarkRing_Parallel(b *testing.B) { 200 size := 1024 201 r := NewRing(size) 202 for i := 0; i < size; i++ { 203 r.Push(struct{}{}) 204 } 205 206 // benchmark 207 b.ReportAllocs() 208 b.SetParallelism(128) 209 b.ResetTimer() 210 b.RunParallel(func(pb *testing.PB) { 211 for pb.Next() { 212 obj := r.Pop() 213 r.Push(obj) 214 } 215 }) 216 }