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 }