github.com/wfusion/gofusion@v1.1.14/test/async/cases/asynq_test.go (about) 1 package cases 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/suite" 11 "go.uber.org/atomic" 12 13 "github.com/wfusion/gofusion/async" 14 "github.com/wfusion/gofusion/common/utils" 15 "github.com/wfusion/gofusion/common/utils/serialize" 16 "github.com/wfusion/gofusion/config" 17 "github.com/wfusion/gofusion/log" 18 "github.com/wfusion/gofusion/redis" 19 "github.com/wfusion/gofusion/test/internal/mock" 20 21 fusCtx "github.com/wfusion/gofusion/context" 22 testAsync "github.com/wfusion/gofusion/test/async" 23 ) 24 25 func TestAsynq(t *testing.T) { 26 testingSuite := &Asynq{Test: new(testAsync.Test)} 27 testingSuite.Init(testingSuite) 28 suite.Run(t, testingSuite) 29 } 30 31 type Asynq struct { 32 *testAsync.Test 33 } 34 35 func (t *Asynq) BeforeTest(suiteName, testName string) { 36 t.Catch(func() { 37 log.Info(context.Background(), "right before %s %s", suiteName, testName) 38 }) 39 } 40 41 func (t *Asynq) AfterTest(suiteName, testName string) { 42 t.Catch(func() { 43 log.Info(context.Background(), "right after %s %s", suiteName, testName) 44 }) 45 } 46 47 func (t *Asynq) TestDefault() { 48 t.Catch(func() { 49 // Given 50 times := 2 51 c := async.C(nameDefault, async.AppName(t.AppName())) 52 p := async.P(nameDefault, async.AppName(t.AppName())) 53 ctx := fusCtx.SetTraceID(context.Background(), utils.NginxID()) 54 t.cleanByQueue(ctx, "") 55 defer t.cleanByQueue(ctx, "") 56 57 ctx, cancel := context.WithTimeout(ctx, time.Minute) 58 defer cancel() 59 60 // When 61 css := make([]*cs, 0) 62 css = append(css, t.testDefault(ctx, c, p, times)) 63 css = append(css, t.testVariadicHandler(ctx, c, p, times)) 64 65 t.NoError(c.Start()) 66 67 // Then 68 wg := new(sync.WaitGroup) 69 for _, item := range css { 70 testCase := item 71 wg.Add(1) 72 go func() { 73 defer wg.Done() 74 testCase.subTest() 75 }() 76 } 77 wg.Wait() 78 }) 79 } 80 81 func (t *Asynq) testDefault(ctx context.Context, c async.Consumable, p async.Producable, times int) *cs { 82 // Given 83 taskName := "testDefault" 84 cnt := atomic.NewInt32(0) 85 expect := time.Duration(times) 86 obj := mock.GenObjBySerializeAlgo(serialize.AlgorithmGob) 87 88 // When 89 c.Handle(taskName, func(ctx context.Context, arg *mock.RandomObj) (err error) { 90 cnt.Add(1) 91 deadline, ok := ctx.Deadline() 92 log.Info(ctx, "testDefault get async task args: ctx(%s,%v)", deadline, ok) 93 t.EqualValues(obj, arg) 94 return 95 }) 96 97 // Then 98 return &cs{ 99 name: "default", 100 subTest: func() { 101 for i := 0; i < int(expect); i++ { 102 t.Require().NoError( 103 p.Send(ctx, taskName, obj), 104 ) 105 } 106 time.Sleep(time.Duration(times) * time.Second) 107 108 t.NotZero(cnt.Load()) 109 t.LessOrEqual(cnt.Load(), int32(expect)) 110 }, 111 } 112 } 113 114 func (t *Asynq) testVariadicHandler(ctx context.Context, c async.Consumable, p async.Producable, times int) *cs { 115 // Given 116 expect := time.Duration(times) 117 cnt := atomic.NewInt32(0) 118 obj1 := mock.GenObjBySerializeAlgo(serialize.AlgorithmGob) 119 obj2 := mock.GenObjBySerializeAlgo(serialize.AlgorithmGob) 120 obj3 := mock.GenObjBySerializeAlgo(serialize.AlgorithmGob) 121 obj4 := 10 122 123 hdr := func(ctx context.Context, a1, a2, a3 *mock.RandomObj, a4 int) (err error) { 124 cnt.Add(1) 125 deadline, ok := ctx.Deadline() 126 log.Info(ctx, "testVariadicHandler get async task args: ctx(%s,%v)", deadline, ok) 127 t.EqualValues(obj1, a1) 128 t.EqualValues(obj2, a2) 129 t.EqualValues(obj3, a3) 130 t.EqualValues(obj4, a4) 131 return 132 } 133 134 // When 135 c.HandleFunc(hdr) 136 137 // Then 138 return &cs{ 139 name: "variadic_handler", 140 subTest: func() { 141 for i := 0; i < int(expect); i++ { 142 t.Require().NoError( 143 p.Goc(ctx, hdr, async.Args(obj1, obj2, obj3, obj4)), 144 ) 145 } 146 time.Sleep(time.Duration(times) * time.Second) 147 148 t.NotZero(cnt.Load()) 149 t.LessOrEqual(cnt.Load(), int32(expect)) 150 }, 151 } 152 } 153 154 func (t *Asynq) TestWithQueue() { 155 t.Catch(func() { 156 // Given 157 queue := "gofusion:async:with_queues" 158 expect := time.Duration(2) 159 cnt := atomic.NewInt32(0) 160 ctx := fusCtx.SetTraceID(context.Background(), utils.NginxID()) 161 t.cleanByQueue(ctx, queue) 162 defer t.cleanByQueue(ctx, queue) 163 164 obj1 := mock.GenObjBySerializeAlgo(serialize.AlgorithmGob) 165 obj2 := mock.GenObjBySerializeAlgo(serialize.AlgorithmGob) 166 obj3 := mock.GenObjBySerializeAlgo(serialize.AlgorithmGob) 167 obj4 := 10 168 169 c := async.C(nameWithQueue, async.AppName(t.AppName())) 170 p := async.P(nameWithQueue, async.AppName(t.AppName())) 171 hdr := func(ctx context.Context, a1, a2, a3 *mock.RandomObj, a4 int) (err error) { 172 cnt.Add(1) 173 deadline, ok := ctx.Deadline() 174 log.Info(ctx, "TestWithQueue get async task args: ctx(%s,%v)", deadline, ok) 175 t.EqualValues(obj1, a1) 176 t.EqualValues(obj2, a2) 177 t.EqualValues(obj3, a3) 178 t.EqualValues(obj4, a4) 179 return 180 } 181 182 c.Handle("TestWithQueue", hdr) 183 ctx, cancel := context.WithTimeout(ctx, time.Minute) 184 defer cancel() 185 for i := 0; i < int(expect); i++ { 186 t.Require().NoError( 187 p.Go(hdr, async.Args(obj1, obj2, obj3, obj4), async.Queue(queue)), 188 ) 189 } 190 191 // When 192 t.NoError(c.Start()) 193 time.Sleep(expect * time.Second) 194 195 // Then 196 t.NotZero(cnt.Load()) 197 t.LessOrEqual(cnt.Load(), int32(expect)) 198 }) 199 } 200 201 func (t *Asynq) cleanByQueue(ctx context.Context, queue string) { 202 pattern := fmt.Sprintf("asynq:{%s}:*", queue) 203 if queue == "" { 204 pattern = fmt.Sprintf("asynq:{%s:async}:*", config.Use(t.AppName()).AppName()) 205 } 206 207 rdsCli := redis.Use(ctx, "default", redis.AppName(t.AppName())) 208 keys, err := rdsCli.Keys(ctx, pattern).Result() 209 t.NoError(err) 210 211 if len(keys) > 0 { 212 rdsCli.Del(ctx, keys...) 213 } 214 }