github.com/polarismesh/polaris@v1.17.8/common/timewheel/timewheel_test.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package timewheel 19 20 import ( 21 "fmt" 22 "math" 23 "strconv" 24 "sync" 25 "testing" 26 "time" 27 28 "github.com/stretchr/testify/assert" 29 ) 30 31 // test timewheel task run 32 func TestTaskRun1(t *testing.T) { 33 tw := New(time.Second, 5, "test tw") 34 tw.Start() 35 callback := func(data interface{}) { 36 fmt.Println(data.(string)) 37 } 38 39 t.Logf("add task time:%d", time.Now().Unix()) 40 for i := 0; i < 10; i++ { 41 tw.AddTask(1000, "polaris 1s "+strconv.Itoa(i), callback) 42 } 43 t.Logf("add task time end:%d", time.Now().Unix()) 44 45 time.Sleep(2 * time.Second) 46 t.Logf("add task time:%d", time.Now().Unix()) 47 for i := 0; i < 10; i++ { 48 tw.AddTask(3000, "polaris 3s "+strconv.Itoa(i), callback) 49 } 50 t.Logf("add task time end:%d", time.Now().Unix()) 51 52 time.Sleep(5 * time.Second) 53 t.Logf("add task time:%d", time.Now().Unix()) 54 for i := 0; i < 10; i++ { 55 tw.AddTask(10000, "polaris 10s "+strconv.Itoa(i), callback) 56 } 57 t.Logf("add task time end:%d", time.Now().Unix()) 58 time.Sleep(15 * time.Second) 59 60 tw.Stop() 61 } 62 63 // test timewheel task run 64 func TestTaskRun2(t *testing.T) { 65 tw := New(time.Second, 5, "test tw") 66 tw.Start() 67 callback := func(data interface{}) { 68 now := time.Now().Unix() 69 if now != 3123124121 { 70 _ = fmt.Sprintf("%s%+v", data.(string), time.Now()) 71 } else { 72 _ = fmt.Sprintf("%s%+v", data.(string), time.Now()) 73 } 74 } 75 76 t.Logf("add task time:%d", time.Now().Unix()) 77 for i := 0; i < 50000; i++ { 78 tw.AddTask(3000, "polaris 3s "+strconv.Itoa(i), callback) 79 } 80 t.Logf("add task time end:%d", time.Now().Unix()) 81 time.Sleep(8) 82 83 tw.Stop() 84 } 85 86 // test timewheel task run 87 func TestTaskRunBoth(t *testing.T) { 88 tw := New(time.Second, 5, "test tw") 89 tw.Start() 90 callback := func(data interface{}) { 91 fmt.Println(data.(string)) 92 } 93 94 for i := 0; i < 10; i++ { 95 go tw.AddTask(1000, "polaris 1s_"+strconv.Itoa(i), callback) 96 go tw.AddTask(3000, "polaris 3s_"+strconv.Itoa(i), callback) 97 go tw.AddTask(7000, "polaris 10s_"+strconv.Itoa(i), callback) 98 } 99 time.Sleep(12 * time.Second) 100 tw.Stop() 101 } 102 103 // timewheel task struct 104 type Info struct { 105 id string 106 ttl int 107 ms int64 108 } 109 110 // bench-test timewheel task add 111 func BenchmarkAddTask1(t *testing.B) { 112 tw := New(time.Second, 5, "test tw") 113 info := &Info{ 114 "abcdefghijklmnopqrstuvwxyz", 115 2, 116 time.Now().Unix(), 117 } 118 119 callback := func(data interface{}) { 120 dataInfo := data.(*Info) 121 if dataInfo.ms < time.Now().Unix() { 122 fmt.Println("overtime") 123 } 124 } 125 126 // t.N = 100000 127 t.SetParallelism(10000) 128 t.RunParallel(func(pb *testing.PB) { 129 for pb.Next() { 130 tw.AddTask(2000, info, callback) 131 } 132 }) 133 } 134 135 // bench-test timewheel task add 136 // use 2 slot 137 func BenchmarkAddTask2(t *testing.B) { 138 tw := New(time.Second, 5, "test tw") 139 info := &Info{ 140 "abcdefghijklmnopqrstuvwxyz", 141 2, 142 time.Now().Unix(), 143 } 144 145 callback := func(data interface{}) { 146 dataInfo := data.(*Info) 147 if dataInfo.ms < time.Now().Unix() { 148 fmt.Println("overtime") 149 } 150 } 151 152 t.SetParallelism(10000) 153 t.RunParallel(func(pb *testing.PB) { 154 for pb.Next() { 155 tw.AddTask(2000, info, callback) 156 tw.AddTask(3000, info, callback) 157 } 158 }) 159 } 160 161 // bench-test timewheel task add 162 // use 2 timewheel 163 func BenchmarkAddTask3(t *testing.B) { 164 tw := New(time.Second, 5, "test tw") 165 tw2 := New(time.Second, 5, "test tw") 166 167 info := &Info{ 168 "abcdefghijklmnopqrstuvwxyz", 169 2, 170 time.Now().Unix(), 171 } 172 173 callback := func(data interface{}) { 174 dataInfo := data.(*Info) 175 if dataInfo.ms < time.Now().Unix() { 176 fmt.Println("overtime") 177 } 178 } 179 180 t.SetParallelism(10000) 181 t.RunParallel(func(pb *testing.PB) { 182 for pb.Next() { 183 tw.AddTask(2000, info, callback) 184 tw2.AddTask(2000, info, callback) 185 } 186 }) 187 } 188 189 // result:select random get ch 190 func TestSelect(t *testing.T) { 191 ch := make(chan int, 20) 192 ch2 := make(chan int, 20) 193 stopCh := make(chan bool) 194 195 go func() { 196 for i := 0; i < 10; i++ { 197 ch <- i 198 ch2 <- i + 20 199 } 200 time.Sleep(1 * time.Second) 201 close(stopCh) 202 }() 203 204 for { 205 select { 206 case i := <-ch: 207 fmt.Println(i) 208 time.Sleep(time.Second) 209 case i := <-ch2: 210 fmt.Println(i) 211 time.Sleep(time.Second) 212 case <-stopCh: 213 return 214 } 215 } 216 } 217 218 func TestRotationTask(t *testing.T) { 219 tw := New(time.Second, 5, "") 220 tw.Start() 221 wg := &sync.WaitGroup{} 222 wg.Add(5) 223 t.Run("", func(t *testing.T) { 224 rotationCallback(t, wg, tw, 1, 0, time.Now().UnixMilli()) 225 }) 226 t.Run("", func(t *testing.T) { 227 rotationCallback(t, wg, tw, 3, 0, time.Now().UnixMilli()) 228 }) 229 t.Run("", func(t *testing.T) { 230 rotationCallback(t, wg, tw, 5, 0, time.Now().UnixMilli()) 231 }) 232 t.Run("", func(t *testing.T) { 233 rotationCallback(t, wg, tw, 10, 0, time.Now().UnixMilli()) 234 }) 235 t.Run("", func(t *testing.T) { 236 rotationCallback(t, wg, tw, 12, 0, time.Now().UnixMilli()) 237 }) 238 wg.Wait() 239 tw.Stop() 240 } 241 242 func rotationCallback(t *testing.T, wg *sync.WaitGroup, tw *TimeWheel, intervalSecond int64, runTimes int, lastTime int64) { 243 tw.AddTask(uint32(intervalSecond*time.Second.Milliseconds()), nil, func(i interface{}) { 244 //0.800-1.200 245 fmt.Println(time.Now()) 246 interval := time.Now().UnixMilli() - lastTime 247 if runTimes == 0 { 248 //首次减去时间轮启动的刻度时间 249 interval = interval - tw.interval.Milliseconds() 250 } 251 diff := math.Abs(float64(interval - intervalSecond*1000)) 252 assert.True(t, diff < 200) 253 if runTimes > 3 { 254 wg.Done() 255 return 256 } 257 runTimes++ 258 rotationCallback(t, wg, tw, intervalSecond, runTimes, time.Now().UnixMilli()) 259 }) 260 } 261 262 func TestForceCloseMode(t *testing.T) { 263 a := 1 264 tw := New(time.Second, 5, "force close", WithWaitTaskOnClose(false)) 265 tw.Start() 266 tw.AddTask(uint32(2*time.Second.Milliseconds()), nil, func(i interface{}) { 267 time.Sleep(5 * time.Second) 268 a = 2 269 fmt.Println("run end") 270 }) 271 tw.AddTask(uint32(2*time.Second.Milliseconds()), nil, func(i interface{}) { 272 time.Sleep(6 * time.Second) 273 a = 2 274 fmt.Println("task2 run end") 275 }) 276 time.Sleep(4 * time.Second) 277 tw.Stop() 278 fmt.Println("tw is stop") 279 assert.True(t, a == 1) 280 } 281 282 func TestWaitCloseMode(t *testing.T) { 283 a := 1 284 tw := New(time.Second, 5, "force close") 285 tw.Start() 286 tw.AddTask(uint32(2*time.Second.Milliseconds()), nil, func(i interface{}) { 287 time.Sleep(5 * time.Second) 288 a = 2 289 fmt.Println("task1 run end") 290 }) 291 292 tw.AddTask(uint32(2*time.Second.Milliseconds()), nil, func(i interface{}) { 293 time.Sleep(6 * time.Second) 294 a = 2 295 fmt.Println("task2 run end") 296 }) 297 time.Sleep(4 * time.Second) 298 tw.Stop() 299 fmt.Println("tw is stop") 300 assert.True(t, a == 2) 301 }