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  }