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  }