github.com/alibaba/sentinel-golang@v1.0.4/core/stat/base/atomic_window_wrap_array_test.go (about) 1 // Copyright 1999-2020 Alibaba Group Holding Ltd. 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 base 16 17 import ( 18 "math/rand" 19 "reflect" 20 "sync" 21 "sync/atomic" 22 "testing" 23 "time" 24 25 "github.com/alibaba/sentinel-golang/util" 26 "github.com/stretchr/testify/assert" 27 ) 28 29 func Test_atomicBucketWrapArray_elementOffset(t *testing.T) { 30 type args struct { 31 len int 32 bucketLengthInMs uint32 33 bg BucketGenerator 34 idx int 35 } 36 tests := []struct { 37 name string 38 args args 39 want uintptr 40 }{ 41 { 42 name: "Test_atomicBucketWrapArray_elementOffset", 43 args: args{ 44 len: int(SampleCount), 45 bucketLengthInMs: BucketLengthInMs, 46 bg: &leapArrayMock{}, 47 idx: 9, 48 }, 49 want: 72, 50 }, 51 } 52 for _, tt := range tests { 53 t.Run(tt.name, func(t *testing.T) { 54 now := uint64(1596199310000) 55 aa := NewAtomicBucketWrapArrayWithTime(tt.args.len, tt.args.bucketLengthInMs, now, tt.args.bg) 56 offset, ok := aa.elementOffset(tt.args.idx) 57 assert.True(t, ok) 58 if got := uintptr(offset) - uintptr(aa.base); got != tt.want { 59 t.Errorf("AtomicBucketWrapArray.elementOffset() = %v, want %v \n", got, tt.want) 60 } 61 }) 62 } 63 } 64 65 func Test_atomicBucketWrapArray_get(t *testing.T) { 66 type args struct { 67 len int 68 bucketLengthInMs uint32 69 bg BucketGenerator 70 idx int 71 } 72 tests := []struct { 73 name string 74 args args 75 want *BucketWrap 76 }{ 77 { 78 name: "Test_atomicBucketWrapArray_get", 79 args: args{ 80 len: int(SampleCount), 81 bucketLengthInMs: BucketLengthInMs, 82 bg: &leapArrayMock{}, 83 idx: 9, 84 }, 85 want: nil, 86 }, 87 } 88 for _, tt := range tests { 89 t.Run(tt.name, func(t *testing.T) { 90 now := uint64(1596199310000) 91 aa := NewAtomicBucketWrapArrayWithTime(tt.args.len, tt.args.bucketLengthInMs, now, tt.args.bg) 92 tt.want = aa.data[9] 93 if got := aa.get(tt.args.idx); !reflect.DeepEqual(got, tt.want) { 94 t.Errorf("AtomicBucketWrapArray.get() = %v, want %v", got, tt.want) 95 } 96 }) 97 } 98 } 99 100 func Test_atomicBucketWrapArray_compareAndSet(t *testing.T) { 101 type args struct { 102 len int 103 bucketLengthInMs uint32 104 bg BucketGenerator 105 idx int 106 } 107 tests := []struct { 108 name string 109 args args 110 want bool 111 }{ 112 { 113 name: "Test_atomicBucketWrapArray_compareAndSet", 114 args: args{ 115 len: int(SampleCount), 116 bucketLengthInMs: BucketLengthInMs, 117 bg: &leapArrayMock{}, 118 idx: 9, 119 }, 120 want: true, 121 }, 122 } 123 for _, tt := range tests { 124 t.Run(tt.name, func(t *testing.T) { 125 now := uint64(1596199310000) 126 aa := NewAtomicBucketWrapArrayWithTime(tt.args.len, tt.args.bucketLengthInMs, now, tt.args.bg) 127 update := &BucketWrap{ 128 BucketStart: 8888888888888, 129 Value: atomic.Value{}, 130 } 131 update.Value.Store(int64(666666)) 132 except := aa.get(9) 133 if got := aa.compareAndSet(tt.args.idx, except, update); got != tt.want { 134 t.Errorf("AtomicBucketWrapArray.compareAndSet() = %v, want %v", got, tt.want) 135 } 136 if !reflect.DeepEqual(aa.get(9), update) { 137 t.Errorf("AtomicBucketWrapArray.compareAndSet() update fail") 138 } 139 }) 140 } 141 } 142 143 func taskGet(wg *sync.WaitGroup, at *AtomicBucketWrapArray, t *testing.T) { 144 util.Sleep(time.Millisecond * 3) 145 idx := rand.Int() % 20 146 wwPtr := at.get(idx) 147 vInterface := wwPtr.Value.Load() 148 vp, ok := vInterface.(*int64) 149 if !ok { 150 t.Error("BucketWrap Value assert fail.\n") 151 } 152 v := atomic.LoadInt64(vp) 153 newV := v + 1 154 for !atomic.CompareAndSwapInt64(vp, v, newV) { 155 v = atomic.LoadInt64(vp) 156 newV = v + 1 157 } 158 wg.Done() 159 } 160 161 func Test_atomicBucketWrapArray_Concurrency_Get(t *testing.T) { 162 util.SetClock(util.NewMockClock()) 163 164 now := uint64(1596199310000) 165 ret := NewAtomicBucketWrapArrayWithTime(int(SampleCount), BucketLengthInMs, now, &leapArrayMock{}) 166 for _, ww := range ret.data { 167 c := new(int64) 168 *c = 0 169 ww.Value.Store(c) 170 } 171 const GoroutineNum = 1000 172 wg1 := &sync.WaitGroup{} 173 wg1.Add(GoroutineNum) 174 for i := 0; i < GoroutineNum; i++ { 175 go taskGet(wg1, ret, t) 176 } 177 wg1.Wait() 178 sum := int64(0) 179 for _, ww := range ret.data { 180 val := ww.Value.Load() 181 count, ok := val.(*int64) 182 if !ok { 183 t.Error("assert error") 184 } 185 sum += *count 186 } 187 if sum != GoroutineNum { 188 t.Error("sum error") 189 } 190 t.Log("all done") 191 } 192 193 func taskSet(wg *sync.WaitGroup, at *AtomicBucketWrapArray, t *testing.T) { 194 util.Sleep(time.Millisecond * 3) 195 idx := rand.Int() % 20 196 ww := at.get(idx) 197 bucket := new(int64) 198 *bucket = 100 199 val := atomic.Value{} 200 val.Store(bucket) 201 replace := &BucketWrap{ 202 BucketStart: util.CurrentTimeMillis(), 203 Value: val, 204 } 205 for !at.compareAndSet(idx, ww, replace) { 206 ww = at.get(idx) 207 } 208 wg.Done() 209 } 210 211 func Test_atomicBucketWrapArray_Concurrency_Set(t *testing.T) { 212 util.SetClock(util.NewMockClock()) 213 214 now := uint64(1596199310000) 215 ret := NewAtomicBucketWrapArrayWithTime(int(SampleCount), BucketLengthInMs, now, &leapArrayMock{}) 216 for _, ww := range ret.data { 217 c := new(int64) 218 *c = 0 219 ww.Value.Store(c) 220 } 221 const GoroutineNum = 1000 222 wg2 := &sync.WaitGroup{} 223 wg2.Add(GoroutineNum) 224 225 for i := 0; i < GoroutineNum; i++ { 226 go taskSet(wg2, ret, t) 227 } 228 wg2.Wait() 229 for _, ww := range ret.data { 230 v := ww.Value.Load() 231 val, ok := v.(*int64) 232 if !ok || *val != 100 { 233 t.Error("assert error") 234 } 235 } 236 t.Log("all done") 237 } 238 239 func TestNewAtomicBucketWrapArrayWithTime(t *testing.T) { 240 t.Run("TestNewAtomicBucketWrapArrayWithTime_normal", func(t *testing.T) { 241 now := uint64(1596199317001) 242 arrayStartTime := uint64(1596199316000) 243 idx := int((now - arrayStartTime) / 200) 244 a := NewAtomicBucketWrapArrayWithTime(10, 200, now, &leapArrayMock{}) 245 246 targetTime := arrayStartTime + uint64(idx*200) 247 for i := idx; i < 10; i++ { 248 b := a.get(i) 249 assert.True(t, b.BucketStart == targetTime, "Check start failed") 250 targetTime += 200 251 } 252 for i := 0; i < idx; i++ { 253 b := a.get(i) 254 assert.True(t, b.BucketStart == targetTime, "Check start failed") 255 targetTime += 200 256 } 257 }) 258 259 t.Run("TestNewAtomicBucketWrapArrayWithTime_edge1", func(t *testing.T) { 260 now := uint64(1596199316000) 261 arrayStartTime := uint64(1596199316000) 262 idx := int((now - arrayStartTime) / 200) 263 a := NewAtomicBucketWrapArrayWithTime(10, 200, now, &leapArrayMock{}) 264 265 targetTime := arrayStartTime + uint64(idx*200) 266 for i := idx; i < 10; i++ { 267 b := a.get(i) 268 assert.True(t, b.BucketStart == targetTime, "Check start failed") 269 targetTime += 200 270 } 271 for i := 0; i < idx; i++ { 272 b := a.get(i) 273 assert.True(t, b.BucketStart == targetTime, "Check start failed") 274 targetTime += 200 275 } 276 }) 277 }