github.com/wfusion/gofusion@v1.1.14/test/mq/cases/event_test.go (about)

     1  package cases
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/suite"
    10  	"go.uber.org/atomic"
    11  
    12  	"github.com/wfusion/gofusion/common/utils"
    13  	"github.com/wfusion/gofusion/common/utils/serialize"
    14  	"github.com/wfusion/gofusion/log"
    15  	"github.com/wfusion/gofusion/mq"
    16  	"github.com/wfusion/gofusion/test/internal/mock"
    17  
    18  	fusCtx "github.com/wfusion/gofusion/context"
    19  	testMq "github.com/wfusion/gofusion/test/mq"
    20  )
    21  
    22  func TestEvent(t *testing.T) {
    23  	testingSuite := &Event{Test: new(testMq.Test)}
    24  	testingSuite.Init(testingSuite)
    25  	suite.Run(t, testingSuite)
    26  }
    27  
    28  type Event struct {
    29  	*testMq.Test
    30  }
    31  
    32  func (t *Event) BeforeTest(suiteName, testName string) {
    33  	t.Catch(func() {
    34  		log.Info(context.Background(), "right before %s %s", suiteName, testName)
    35  	})
    36  }
    37  
    38  func (t *Event) AfterTest(suiteName, testName string) {
    39  	t.Catch(func() {
    40  		log.Info(context.Background(), "right after %s %s", suiteName, testName)
    41  	})
    42  }
    43  
    44  func (t *Event) TestRabbitmq() {
    45  	t.defaultTest(nameEventRabbitmq)
    46  }
    47  
    48  func (t *Event) TestKafka() {
    49  	t.defaultTest(nameEventKafka)
    50  }
    51  
    52  func (t *Event) TestPulsar() {
    53  	t.defaultTest(nameEventPulsar)
    54  }
    55  
    56  func (t *Event) TestRedis() {
    57  	t.defaultTest(nameEventRedis)
    58  }
    59  
    60  func (t *Event) TestMysql() {
    61  	t.defaultTest(nameEventMysql)
    62  }
    63  
    64  func (t *Event) TestPostgres() {
    65  	t.defaultTest(nameEventPostgres)
    66  }
    67  
    68  func (t *Event) TestGoChannel() {
    69  	t.defaultTest(nameEventGoChannel)
    70  }
    71  
    72  func (t *Event) defaultTest(name string) {
    73  	naming := func(n string) string { return name + "_" + n }
    74  	t.Run(naming("PubSubEvent"), func() { t.testPubSubEvent(name) })
    75  	t.Run(naming("PubHandlerEvent"), func() { t.testPubHandlerEvent(name) })
    76  }
    77  
    78  func (t *Event) testPubSubEvent(name string) {
    79  	t.Catch(func() {
    80  		// Given
    81  		expected := 5
    82  		cnt := atomic.NewInt64(0)
    83  		ctx := context.Background()
    84  		traceID := utils.NginxID()
    85  		ctx = fusCtx.SetTraceID(ctx, traceID)
    86  		ctx, cancel := context.WithTimeout(ctx, time.Duration(expected)*timeout)
    87  		defer func() {
    88  			time.Sleep(ackTimeout) // wait for ack
    89  			cancel()
    90  		}()
    91  
    92  		structObjList := mock.GenObjList[*structCreated](expected)
    93  		structEventType := (*structCreated).EventType(nil)
    94  		structObjMap := utils.SliceToMap(structObjList, func(v *structCreated) string { return v.ID })
    95  
    96  		// When
    97  		wg := new(sync.WaitGroup)
    98  		structSub := mq.NewEventSubscriber[*structCreated](name, mq.AppName(t.AppName()))
    99  		structMsgCh, err := structSub.SubscribeEvent(ctx, mq.ChannelLen(expected))
   100  		t.NoError(err)
   101  
   102  		wg.Add(1)
   103  		go func() {
   104  			defer wg.Done()
   105  			for {
   106  				select {
   107  				case msg := <-structMsgCh:
   108  					cnt.Add(1)
   109  
   110  					t.True(msg.Ack())
   111  					ctx := msg.Context()
   112  					log.Info(ctx, "subscriber get struct created event consumed [event[%s]]", msg.ID())
   113  
   114  					t.NotEmpty(msg.ID())
   115  					t.EqualValues(msg.Type(), structEventType)
   116  					t.EqualValues(structObjMap[msg.ID()], msg.Payload())
   117  					if cnt.Load() == int64(len(structObjList)) {
   118  						return
   119  					}
   120  				case <-ctx.Done():
   121  					return
   122  				}
   123  			}
   124  		}()
   125  		<-mq.Use(name, mq.AppName(t.AppName())).Running()
   126  		t.publishStruct(ctx, name, structObjList, wg)
   127  
   128  		// Then
   129  		wg.Wait()
   130  		t.EqualValues(len(structObjList), cnt.Load())
   131  	})
   132  }
   133  
   134  func (t *Event) testPubHandlerEvent(name string) {
   135  	t.Catch(func() {
   136  		// Given
   137  		expected := 5
   138  		cnt := atomic.NewInt64(0)
   139  		ctx := context.Background()
   140  		traceID := utils.NginxID()
   141  		ctx = fusCtx.SetTraceID(ctx, traceID)
   142  		ctx, cancel := context.WithTimeout(ctx, time.Duration(expected)*timeout)
   143  		defer func() {
   144  			time.Sleep(ackTimeout) // wait for ack
   145  			cancel()
   146  		}()
   147  
   148  		randomObjList := mock.GenObjListBySerializeAlgo(serialize.AlgorithmGob, expected).([]*mock.RandomObj)
   149  		randomEventType := (*mock.RandomObj).EventType(nil)
   150  		randomObjMap := utils.SliceToMap(randomObjList, func(v *mock.RandomObj) string { return v.Str })
   151  
   152  		// When
   153  		wg := new(sync.WaitGroup)
   154  		r := mq.Use(name, mq.AppName(t.AppName()))
   155  		r.Handle(randomEventType, mq.EventHandler(
   156  			func(ctx context.Context, event mq.Event[*mock.RandomObj]) (err error) {
   157  				// Then
   158  				cnt.Add(1)
   159  				t.EqualValues(traceID, fusCtx.GetTraceID(ctx))
   160  				t.EqualValues(event.Type(), randomEventType)
   161  				t.EqualValues(randomObjMap[event.ID()], event.Payload())
   162  
   163  				log.Info(ctx, "router get random event consumed [event[%s]]", event.ID())
   164  				return
   165  			},
   166  		))
   167  		r.Start()
   168  
   169  		<-r.Running()
   170  		t.publishRandom(ctx, name, randomObjList, wg)
   171  
   172  		// Then
   173  		wg.Wait()
   174  	BREAKING:
   175  		for {
   176  			select {
   177  			case <-ctx.Done():
   178  				break BREAKING
   179  			default:
   180  				if cnt.Load() == int64(len(randomObjList)) {
   181  					break BREAKING
   182  				}
   183  			}
   184  		}
   185  		t.EqualValues(len(randomObjList), cnt.Load())
   186  	})
   187  }
   188  
   189  func (t *Event) publishRandom(ctx context.Context, name string, objList []*mock.RandomObj, wg *sync.WaitGroup) {
   190  	// publisher
   191  	p := mq.NewEventPublisher[*mock.RandomObj](name, mq.AppName(t.AppName()))
   192  
   193  	for i := 0; i < len(objList); i++ {
   194  		event := mq.UntimedEvent(objList[i].Str, objList[i])
   195  		wg.Add(1)
   196  		go func() {
   197  			defer wg.Done()
   198  			t.NoError(p.PublishEvent(ctx, mq.Events(event)))
   199  		}()
   200  	}
   201  }
   202  
   203  func (t *Event) publishStruct(ctx context.Context, name string, objList []*structCreated, wg *sync.WaitGroup) {
   204  	// publisher
   205  	p := mq.NewEventPublisher[*structCreated](name, mq.AppName(t.AppName()))
   206  
   207  	for i := 0; i < len(objList); i++ {
   208  		event := mq.UntimedEvent(objList[i].ID, objList[i])
   209  		wg.Add(1)
   210  		go func() {
   211  			defer wg.Done()
   212  			t.NoError(p.PublishEvent(ctx, mq.Events(event)))
   213  		}()
   214  	}
   215  }