github.com/moleculer-go/moleculer@v0.3.3/transit/amqp/amqp_test.go (about) 1 package amqp 2 3 import ( 4 "sort" 5 "sync" 6 "time" 7 8 "github.com/moleculer-go/moleculer" 9 "github.com/moleculer-go/moleculer/broker" 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 ) 13 14 var queues = []string{ 15 // RPC 16 "MOL.DISCONNECT.test-rpc-client", 17 "MOL.DISCONNECT.test-rpc-worker1", 18 "MOL.DISCONNECT.test-rpc-worker2", 19 "MOL.DISCONNECT.test-rpc-worker3", 20 "MOL.DISCOVER.test-rpc-client", 21 "MOL.DISCOVER.test-rpc-worker1", 22 "MOL.DISCOVER.test-rpc-worker2", 23 "MOL.DISCOVER.test-rpc-worker3", 24 "MOL.EVENT.test-rpc-client", 25 "MOL.EVENT.test-rpc-worker1", 26 "MOL.EVENT.test-rpc-worker2", 27 "MOL.EVENT.test-rpc-worker3", 28 "MOL.HEARTBEAT.test-rpc-client", 29 "MOL.HEARTBEAT.test-rpc-worker1", 30 "MOL.HEARTBEAT.test-rpc-worker2", 31 "MOL.HEARTBEAT.test-rpc-worker3", 32 "MOL.INFO.test-rpc-client", 33 "MOL.INFO.test-rpc-worker1", 34 "MOL.INFO.test-rpc-worker2", 35 "MOL.INFO.test-rpc-worker3", 36 "MOL.PING.test-rpc-client", 37 "MOL.PING.test-rpc-worker1", 38 "MOL.PING.test-rpc-worker2", 39 "MOL.PING.test-rpc-worker3", 40 "MOL.PONG.test-rpc-client", 41 "MOL.PONG.test-rpc-worker1", 42 "MOL.PONG.test-rpc-worker2", 43 "MOL.PONG.test-rpc-worker3", 44 "MOL.REQ.test-rpc-client", 45 "MOL.REQ.test-rpc-worker1", 46 "MOL.REQ.test-rpc-worker2", 47 "MOL.REQ.test-rpc-worker3", 48 "MOL.RES.test-rpc-client", 49 "MOL.RES.test-rpc-worker1", 50 "MOL.RES.test-rpc-worker2", 51 "MOL.RES.test-rpc-worker3", 52 // Emit 53 "MOL.DISCONNECT.test-emit-event-pub", 54 "MOL.DISCONNECT.test-emit-event-sub1", 55 "MOL.DISCONNECT.test-emit-event-sub2", 56 "MOL.DISCONNECT.test-emit-event-sub3", 57 "MOL.DISCOVER.test-emit-event-pub", 58 "MOL.DISCOVER.test-emit-event-sub1", 59 "MOL.DISCOVER.test-emit-event-sub2", 60 "MOL.DISCOVER.test-emit-event-sub3", 61 "MOL.EVENT.test-emit-event-pub", 62 "MOL.EVENT.test-emit-event-sub1", 63 "MOL.EVENT.test-emit-event-sub2", 64 "MOL.EVENT.test-emit-event-sub3", 65 "MOL.HEARTBEAT.test-emit-event-pub", 66 "MOL.HEARTBEAT.test-emit-event-sub1", 67 "MOL.HEARTBEAT.test-emit-event-sub2", 68 "MOL.HEARTBEAT.test-emit-event-sub3", 69 "MOL.INFO.test-emit-event-pub", 70 "MOL.INFO.test-emit-event-sub1", 71 "MOL.INFO.test-emit-event-sub2", 72 "MOL.INFO.test-emit-event-sub3", 73 "MOL.PING.test-emit-event-pub", 74 "MOL.PING.test-emit-event-sub1", 75 "MOL.PING.test-emit-event-sub2", 76 "MOL.PING.test-emit-event-sub3", 77 "MOL.PONG.test-emit-event-pub", 78 "MOL.PONG.test-emit-event-sub1", 79 "MOL.PONG.test-emit-event-sub2", 80 "MOL.PONG.test-emit-event-sub3", 81 "MOL.REQ.test-emit-event-pub", 82 "MOL.REQ.test-emit-event-sub1", 83 "MOL.REQ.test-emit-event-sub2", 84 "MOL.REQ.test-emit-event-sub3", 85 "MOL.RES.test-emit-event-pub", 86 "MOL.RES.test-emit-event-sub1", 87 "MOL.RES.test-emit-event-sub2", 88 "MOL.RES.test-emit-event-sub3", 89 // Broadcast 90 "MOL.REQ.test-broadcast-event-pub", 91 "MOL.REQ.test-broadcast-event-sub1", 92 "MOL.REQ.test-broadcast-event-sub2", 93 "MOL.REQ.test-broadcast-event-sub3", 94 "MOL.RES.test-broadcast-event-pub", 95 "MOL.RES.test-broadcast-event-sub1", 96 "MOL.RES.test-broadcast-event-sub2", 97 "MOL.RES.test-broadcast-event-sub3", 98 "MOL.DISCONNECT.test-broadcast-event-pub", 99 "MOL.DISCONNECT.test-broadcast-event-sub1", 100 "MOL.DISCONNECT.test-broadcast-event-sub2", 101 "MOL.DISCONNECT.test-broadcast-event-sub3", 102 "MOL.DISCOVER.test-broadcast-event-pub", 103 "MOL.DISCOVER.test-broadcast-event-sub1", 104 "MOL.DISCOVER.test-broadcast-event-sub2", 105 "MOL.DISCOVER.test-broadcast-event-sub3", 106 "MOL.EVENT.test-broadcast-event-pub", 107 "MOL.EVENT.test-broadcast-event-sub1", 108 "MOL.EVENT.test-broadcast-event-sub2", 109 "MOL.EVENT.test-broadcast-event-sub3", 110 "MOL.HEARTBEAT.test-broadcast-event-pub", 111 "MOL.HEARTBEAT.test-broadcast-event-sub1", 112 "MOL.HEARTBEAT.test-broadcast-event-sub2", 113 "MOL.HEARTBEAT.test-broadcast-event-sub3", 114 "MOL.INFO.test-broadcast-event-pub", 115 "MOL.INFO.test-broadcast-event-sub1", 116 "MOL.INFO.test-broadcast-event-sub2", 117 "MOL.INFO.test-broadcast-event-sub3", 118 "MOL.PING.test-broadcast-event-pub", 119 "MOL.PING.test-broadcast-event-sub1", 120 "MOL.PING.test-broadcast-event-sub2", 121 "MOL.PING.test-broadcast-event-sub3", 122 "MOL.PONG.test-broadcast-event-pub", 123 "MOL.PONG.test-broadcast-event-sub1", 124 "MOL.PONG.test-broadcast-event-sub2", 125 "MOL.PONG.test-broadcast-event-sub3", 126 } 127 var exchanges = []string{ 128 "MOL.DISCONNECT", 129 "MOL.DISCOVER", 130 "MOL.HEARTBEAT", 131 "MOL.INFO", 132 "MOL.PING", 133 } 134 135 var _ = Describe("Test AMQPTransporter", func() { 136 // Delete all queues and exchanges before and after suite 137 BeforeSuite(func() { 138 purge(queues, exchanges, true) 139 }) 140 AfterSuite(func() { 141 purge(queues, exchanges, true) 142 }) 143 144 // Clear all queues between each test. 145 AfterEach(func() { 146 purge(queues, exchanges, false) 147 }) 148 149 Describe("Test AMQPTransporter RPC with built-in balancer", func() { 150 var logs []map[string]interface{} 151 152 client := createNode("test-rpc", "client", nil) 153 worker1 := createActionWorker(1, &logs) 154 worker2 := createActionWorker(2, &logs) 155 worker3 := createActionWorker(3, &logs) 156 157 brokers := []*broker.ServiceBroker{client, worker1, worker2, worker3} 158 159 callShortDelay := func() chan moleculer.Payload { 160 return client.Call("test.hello", map[string]interface{}{"delay": 20}) 161 } 162 163 BeforeEach(func() { 164 for _, bkr := range brokers { 165 bkr.Start() 166 } 167 time.Sleep(time.Second) 168 }) 169 AfterEach(func() { 170 for _, bkr := range brokers { 171 logs = nil 172 bkr.Stop() 173 } 174 time.Sleep(time.Second) 175 }) 176 177 It("Only one node should receive any given request", func() { 178 // Ensure that messages are not broadcast to individual queues. 179 result := <-callShortDelay() 180 Expect(result.Error()).Should(Succeed()) 181 Expect(logs).Should(HaveLen(2)) 182 Expect(filter(&logs, "receive")).Should(HaveLen(1)) 183 Expect(filter(&logs, "respond")).Should(HaveLen(1)) 184 }) 185 186 It("Should load balance requests to available nodes.", func() { 187 // Ensure that messages are evenly distributed 188 wg := sync.WaitGroup{} 189 res := make([]int, 12) 190 for i := 0; i < 12; i++ { 191 wg.Add(1) 192 go func(index int) { 193 payload := <-callShortDelay() 194 res[index] = payload.Get("worker").Int() 195 wg.Done() 196 }(i) 197 } 198 199 wg.Wait() 200 201 Expect(res).Should(HaveLen(12)) 202 Expect(res).Should(SatisfyAll( 203 ContainElement(1), 204 ContainElement(2), 205 ContainElement(3), 206 )) 207 Expect(res).Should(WithTransform( 208 func(workers []int) []int { 209 sort.Ints(workers) 210 return workers 211 }, Equal([]int{ 212 1, 1, 1, 1, 213 2, 2, 2, 2, 214 3, 3, 3, 3, 215 }), 216 )) 217 }) 218 219 It("Nodes should only receive one request at a time by default", func() { 220 // Ensure that prefetch is working. This relies on message acking happening after the action 221 // handler runs. 222 worker2.Stop() 223 worker3.Stop() 224 225 wg := sync.WaitGroup{} 226 for i := 0; i < 3; i++ { 227 wg.Add(1) 228 go func(index int) { 229 <-callShortDelay() 230 wg.Done() 231 }(i) 232 } 233 wg.Wait() 234 235 for idx, cur := range logs { 236 // All requests should be handled by singe node 237 Expect(cur["worker"]).Should(Equal(1)) 238 239 // Order should go from old -> new 240 if idx+1 < len(logs) { 241 Expect(cur["timestamp"]).Should(BeTemporally("<=", logs[idx+1]["timestamp"].(time.Time))) 242 } 243 244 // If receive and respond don't alternate requests are concurrent 245 if idx%2 == 0 { 246 Expect(cur["type"]).Should(Equal("receive")) 247 } else { 248 Expect(cur["type"]).Should(Equal("respond")) 249 } 250 } 251 }) 252 }) 253 254 XDescribe("Test AMQPTransporter event emit with built-in balancer", func() { 255 var logs []string 256 257 pub := createEmitWorker("pub", "emit-handler", &logs) 258 sub1 := createEmitWorker("sub1", "emit-handler", &logs) 259 sub2 := createEmitWorker("sub2", "emit-handler", &logs) 260 sub3 := createEmitWorker("sub3", "other-handler", &logs) 261 262 brokers := []*broker.ServiceBroker{pub, sub1, sub2, sub3} 263 264 // Reset Flow array and start services 265 BeforeEach(func() { 266 logs = nil 267 268 for _, bkr := range brokers { 269 bkr.Start() 270 } 271 time.Sleep(time.Second) 272 }) 273 274 // Stop services and clear queues 275 AfterEach(func() { 276 for _, bkr := range brokers { 277 bkr.Stop() 278 } 279 logs = nil 280 time.Sleep(time.Second) 281 }) 282 283 It("should send emit event to only one service", func() { 284 for i := 0; i < 6; i++ { 285 pub.Emit("hello.world2", map[string]interface{}{"testing": true}) 286 } 287 288 time.Sleep(2 * time.Second) 289 290 Expect(logs).Should(HaveLen(12)) 291 Expect(logs).Should(SatisfyAll( 292 ContainElement("pub"), 293 // TODO: should uncomment when 'preferLocal' registry parameter will be exposed to config 294 //ContainElement("sub1"), 295 //ContainElement("sub2"), 296 ContainElement("sub3"), 297 )) 298 Expect(logs).Should(WithTransform( 299 func(items []string) []string { 300 var result []string 301 for _, item := range items { 302 if item == "sub3" { 303 result = append(result, item) 304 } 305 } 306 307 return result 308 }, 309 HaveLen(6), 310 )) 311 }) 312 }) 313 314 Describe("Test AMQPTransporter event broadcast with built-in balancer", func() { 315 var logs []string 316 317 pub := createBroadcastWorker("pub", &logs) 318 sub1 := createBroadcastWorker("sub1", &logs) 319 sub2 := createBroadcastWorker("sub2", &logs) 320 sub3 := createBroadcastWorker("sub3", &logs) 321 322 BeforeEach(func() { 323 logs = nil 324 325 go func() { 326 time.Sleep(1500 * time.Millisecond) 327 sub3.Start() 328 }() 329 330 pub.Start() 331 sub1.Start() 332 sub2.Start() 333 334 time.Sleep(time.Second) 335 }) 336 337 AfterEach(func() { 338 pub.Stop() 339 sub1.Stop() 340 sub2.Stop() 341 sub3.Stop() 342 }) 343 344 It("Should send an event to all subscribed nodes.", func() { 345 pub.Broadcast("hello.world", map[string]interface{}{"testing": true}) 346 347 time.Sleep(2 * time.Second) 348 349 Expect(logs).Should(HaveLen(3)) 350 Expect(logs).Should(SatisfyAll( 351 ContainElement("pub"), 352 ContainElement("sub1"), 353 ContainElement("sub2"), 354 )) 355 }, 10) 356 }) 357 })