github.com/ergo-services/ergo@v1.999.224/tests/server_test.go (about) 1 package tests 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/ergo-services/ergo" 11 "github.com/ergo-services/ergo/etf" 12 "github.com/ergo-services/ergo/gen" 13 "github.com/ergo-services/ergo/lib" 14 "github.com/ergo-services/ergo/node" 15 ) 16 17 type testServer struct { 18 gen.Server 19 res chan interface{} 20 } 21 22 func (tgs *testServer) Init(process *gen.ServerProcess, args ...etf.Term) error { 23 tgs.res <- nil 24 return nil 25 } 26 func (tgs *testServer) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 27 tgs.res <- message 28 return gen.ServerStatusOK 29 } 30 func (tgs *testServer) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 31 return message, gen.ServerStatusOK 32 } 33 func (tgs *testServer) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 34 tgs.res <- message 35 return gen.ServerStatusOK 36 } 37 38 func (tgs *testServer) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 39 switch m := message.(type) { 40 case makeCall: 41 return process.Call(m.to, m.message) 42 case makeCast: 43 return nil, process.Cast(m.to, m.message) 44 45 } 46 return nil, lib.ErrUnsupportedRequest 47 } 48 func (tgs *testServer) Terminate(process *gen.ServerProcess, reason string) { 49 tgs.res <- reason 50 } 51 52 type testServerDirect struct { 53 gen.Server 54 err chan error 55 } 56 57 func (tgsd *testServerDirect) Init(process *gen.ServerProcess, args ...etf.Term) error { 58 tgsd.err <- nil 59 return nil 60 } 61 func (tgsd *testServerDirect) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 62 switch m := message.(type) { 63 case asyncDirect: 64 m.ref = ref 65 process.Cast(process.Self(), m) 66 return nil, gen.DirectStatusIgnore 67 case syncDirect: 68 return m.val, gen.DirectStatusOK 69 } 70 return message, gen.DirectStatusOK 71 } 72 func (tgsd *testServerDirect) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 73 switch m := message.(type) { 74 case asyncDirect: 75 process.Reply(m.ref, m.val, nil) 76 } 77 return gen.ServerStatusOK 78 } 79 80 func TestServer(t *testing.T) { 81 fmt.Printf("\n=== Test Server\n") 82 fmt.Printf("Starting nodes: nodeGS1@localhost, nodeGS2@localhost: ") 83 node1, _ := ergo.StartNode("nodeGS1@localhost", "cookies", node.Options{}) 84 node2, _ := ergo.StartNode("nodeGS2@localhost", "cookies", node.Options{}) 85 if node1 == nil || node2 == nil { 86 t.Fatal("can't start nodes") 87 } else { 88 fmt.Println("OK") 89 } 90 91 gs1 := &testServer{ 92 res: make(chan interface{}, 2), 93 } 94 gs2 := &testServer{ 95 res: make(chan interface{}, 2), 96 } 97 gs3 := &testServer{ 98 res: make(chan interface{}, 2), 99 } 100 gsDirect := &testServerDirect{ 101 err: make(chan error, 2), 102 } 103 104 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 105 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 106 waitForResultWithValue(t, gs1.res, nil) 107 108 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 109 node1gs2, _ := node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 110 waitForResultWithValue(t, gs2.res, nil) 111 112 fmt.Printf(" wait for start of gs3 on %#v: ", node2.Name()) 113 node2gs3, _ := node2.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 114 waitForResultWithValue(t, gs3.res, nil) 115 116 fmt.Printf(" wait for start of gsDirect on %#v: ", node2.Name()) 117 node2gsDirect, _ := node2.Spawn("gsDirect", gen.ProcessOptions{}, gsDirect, nil) 118 waitForResult(t, gsDirect.err) 119 120 fmt.Println("Testing Server process:") 121 122 fmt.Printf(" process.Send (by Pid) local (gs1) -> local (gs2) : ") 123 node1gs1.Send(node1gs2.Self(), etf.Atom("hi")) 124 waitForResultWithValue(t, gs2.res, etf.Atom("hi")) 125 126 cast := makeCast{ 127 to: node1gs2.Self(), 128 message: etf.Atom("hi cast"), 129 } 130 node1gs1.Direct(cast) 131 fmt.Printf(" process.Cast (by Pid) local (gs1) -> local (gs2) : ") 132 waitForResultWithValue(t, gs2.res, etf.Atom("hi cast")) 133 134 fmt.Printf(" process.Call (by Pid) local (gs1) -> local (gs2): ") 135 v := etf.Atom("hi call") 136 call := makeCall{ 137 to: node1gs2.Self(), 138 message: v, 139 } 140 if v1, err := node1gs1.Direct(call); err != nil { 141 t.Fatal(err) 142 } else { 143 if v == v1 { 144 fmt.Println("OK") 145 } else { 146 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 147 t.Fatal(e) 148 } 149 } 150 151 fmt.Printf(" process.Send (by Name) local (gs1) -> local (gs2) : ") 152 node1gs1.Send(etf.Atom("gs2"), etf.Atom("hi")) 153 waitForResultWithValue(t, gs2.res, etf.Atom("hi")) 154 155 cast = makeCast{ 156 to: etf.Atom("gs2"), 157 message: etf.Atom("hi cast"), 158 } 159 node1gs1.Direct(cast) 160 fmt.Printf(" process.Cast (by Name) local (gs1) -> local (gs2) : ") 161 waitForResultWithValue(t, gs2.res, etf.Atom("hi cast")) 162 163 fmt.Printf(" process.Call (by Name) local (gs1) -> local (gs2): ") 164 call = makeCall{ 165 to: etf.Atom("gs2"), 166 message: v, 167 } 168 if v1, err := node1gs1.Direct(call); err != nil { 169 t.Fatal(err) 170 } else { 171 if v == v1 { 172 fmt.Println("OK") 173 } else { 174 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 175 t.Fatal(e) 176 } 177 } 178 alias, err := node1gs2.CreateAlias() 179 if err != nil { 180 t.Fatal(err) 181 } 182 fmt.Printf(" process.Send (by Alias) local (gs1) -> local (gs2) : ") 183 node1gs1.Send(alias, etf.Atom("hi")) 184 waitForResultWithValue(t, gs2.res, etf.Atom("hi")) 185 186 cast = makeCast{ 187 to: alias, 188 message: etf.Atom("hi cast"), 189 } 190 node1gs1.Direct(cast) 191 fmt.Printf(" process.Cast (by Alias) local (gs1) -> local (gs2) : ") 192 waitForResultWithValue(t, gs2.res, etf.Atom("hi cast")) 193 194 fmt.Printf(" process.Call (by Alias) local (gs1) -> local (gs2): ") 195 call = makeCall{ 196 to: alias, 197 message: v, 198 } 199 if v1, err := node1gs1.Direct(call); err != nil { 200 t.Fatal(err) 201 } else { 202 if v == v1 { 203 fmt.Println("OK") 204 } else { 205 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 206 t.Fatal(e) 207 } 208 } 209 210 fmt.Printf(" process.Send (by Pid) local (gs1) -> remote (gs3) : ") 211 node1gs1.Send(node2gs3.Self(), etf.Atom("hi")) 212 waitForResultWithValue(t, gs3.res, etf.Atom("hi")) 213 214 cast = makeCast{ 215 to: node2gs3.Self(), 216 message: etf.Atom("hi cast"), 217 } 218 node1gs1.Direct(cast) 219 fmt.Printf(" process.Cast (by Pid) local (gs1) -> remote (gs3) : ") 220 waitForResultWithValue(t, gs3.res, etf.Atom("hi cast")) 221 222 fmt.Printf(" process.Call (by Pid) local (gs1) -> remote (gs3): ") 223 call = makeCall{ 224 to: node2gs3.Self(), 225 message: v, 226 } 227 if v1, err := node1gs1.Direct(call); err != nil { 228 t.Fatal(err) 229 } else { 230 if v == v1 { 231 fmt.Println("OK") 232 } else { 233 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 234 t.Fatal(e) 235 } 236 } 237 238 fmt.Printf(" process.Send (by Name) local (gs1) -> remote (gs3) : ") 239 processName := gen.ProcessID{Name: "gs3", Node: node2.Name()} 240 node1gs1.Send(processName, etf.Atom("hi")) 241 waitForResultWithValue(t, gs3.res, etf.Atom("hi")) 242 243 cast = makeCast{ 244 to: processName, 245 message: etf.Atom("hi cast"), 246 } 247 node1gs1.Direct(cast) 248 fmt.Printf(" process.Cast (by Name) local (gs1) -> remote (gs3) : ") 249 waitForResultWithValue(t, gs3.res, etf.Atom("hi cast")) 250 251 fmt.Printf(" process.Call (by Name) local (gs1) -> remote (gs3): ") 252 call = makeCall{ 253 to: processName, 254 message: v, 255 } 256 if v1, err := node1gs1.Direct(call); err != nil { 257 t.Fatal(err) 258 } else { 259 if v == v1 { 260 fmt.Println("OK") 261 } else { 262 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 263 t.Fatal(e) 264 } 265 } 266 267 fmt.Printf(" process.Send (by Alias) local (gs1) -> remote (gs3) : ") 268 alias, err = node2gs3.CreateAlias() 269 if err != nil { 270 t.Fatal(err) 271 } 272 273 node1gs1.Send(alias, etf.Atom("hi")) 274 waitForResultWithValue(t, gs3.res, etf.Atom("hi")) 275 276 cast = makeCast{ 277 to: alias, 278 message: etf.Atom("hi cast"), 279 } 280 node1gs1.Direct(cast) 281 fmt.Printf(" process.Cast (by Alias) local (gs1) -> remote (gs3) : ") 282 waitForResultWithValue(t, gs3.res, etf.Atom("hi cast")) 283 284 fmt.Printf(" process.Call (by Alias) local (gs1) -> remote (gs3): ") 285 call = makeCall{ 286 to: alias, 287 message: v, 288 } 289 if v1, err := node1gs1.Direct(call); err != nil { 290 t.Fatal(err) 291 } else { 292 if v == v1 { 293 fmt.Println("OK") 294 } else { 295 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 296 t.Fatal(e) 297 } 298 } 299 300 fmt.Printf(" process.Direct (without HandleDirect implementation): ") 301 if _, err := node1gs1.Direct(nil); err != lib.ErrUnsupportedRequest { 302 t.Fatal("must be ErrUnsupportedRequest") 303 } else { 304 fmt.Println("OK") 305 } 306 fmt.Printf(" process.Direct (with HandleDirect implementation): ") 307 if v1, err := node2gsDirect.Direct(v); err != nil { 308 t.Fatal(err) 309 } else { 310 if v == v1 { 311 fmt.Println("OK") 312 } else { 313 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 314 t.Fatal(e) 315 } 316 } 317 fmt.Printf(" process.Direct (with HandleDirect implementation with async reply): ") 318 319 av := etf.Atom("async direct") 320 if v1, err := node2gsDirect.Direct(asyncDirect{val: av}); err != nil { 321 t.Fatal(err) 322 } else { 323 if av == v1 { 324 fmt.Println("OK") 325 } else { 326 e := fmt.Errorf("expected: %#v , got: %#v", av, v1) 327 t.Fatal(e) 328 } 329 } 330 331 fmt.Printf(" process.SetTrapExit(true) and call process.Exit() gs2: ") 332 node1gs2.SetTrapExit(true) 333 node1gs2.Exit("test trap") 334 waitForResultWithValue(t, gs2.res, gen.MessageExit{Pid: node1gs2.Self(), Reason: "test trap"}) 335 fmt.Printf(" check process.IsAlive gs2 (must be alive): ") 336 if !node1gs2.IsAlive() { 337 t.Fatal("should be alive") 338 } 339 fmt.Println("OK") 340 341 fmt.Printf(" process.SetTrapExit(false) and call process.Exit() gs2: ") 342 node1gs2.SetTrapExit(false) 343 node1gs2.Exit("test trap") 344 waitForResultWithValue(t, gs2.res, "test trap") 345 346 fmt.Printf(" check process.IsAlive gs2 (must be died): ") 347 if node1gs2.IsAlive() { 348 t.Fatal("shouldn't be alive") 349 } 350 fmt.Println("OK") 351 352 fmt.Printf("Stopping nodes: %v, %v\n", node1.Name(), node2.Name()) 353 node1.Stop() 354 node2.Stop() 355 } 356 func TestServerDirect(t *testing.T) { 357 fmt.Printf("\n=== Test Server Direct\n") 358 fmt.Printf("Starting node: nodeGS1Direct@localhost: ") 359 node1, _ := ergo.StartNode("nodeGS1Direct@localhost", "cookies", node.Options{}) 360 if node1 == nil { 361 t.Fatal("can't start nodes") 362 } else { 363 fmt.Println("OK") 364 } 365 defer node1.Stop() 366 367 gsDirect := &testServerDirect{ 368 err: make(chan error, 2), 369 } 370 371 fmt.Printf(" wait for start of gsDirect on %#v: ", node1.Name()) 372 node1gsDirect, _ := node1.Spawn("gsDirect", gen.ProcessOptions{}, gsDirect, nil) 373 waitForResult(t, gsDirect.err) 374 375 var wg sync.WaitGroup 376 377 fmt.Println(" process.Direct with 1000 goroutines:") 378 direct := func() { 379 v := etf.Atom("sync direct") 380 defer wg.Done() 381 repeat: 382 if v1, err := node1gsDirect.Direct(syncDirect{val: v}); err != nil { 383 if err == lib.ErrProcessBusy { 384 goto repeat 385 } 386 t.Fatal(err) 387 } else { 388 if v != v1 { 389 e := fmt.Errorf("expected: %#v , got: %#v", v, v1) 390 t.Fatal(e) 391 } 392 } 393 } 394 n := 1000 395 for i := 0; i < n; i++ { 396 wg.Add(1) 397 go direct() 398 } 399 400 wg.Wait() 401 fmt.Println("OK") 402 } 403 404 type messageOrderGS struct { 405 gen.Server 406 n int 407 res chan interface{} 408 } 409 410 type testCase1 struct { 411 n int 412 } 413 414 type testCase2 struct { 415 n int 416 } 417 type testCase3 struct { 418 n int 419 } 420 421 func (gs *messageOrderGS) Init(process *gen.ServerProcess, args ...etf.Term) error { 422 gs.res <- nil 423 return nil 424 } 425 426 func (gs *messageOrderGS) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 427 switch m := message.(type) { 428 case testCase1: 429 if gs.n+1 != m.n { 430 panic(fmt.Sprintf("Disordered messages on %d (awaited: %d)", m.n, gs.n+1)) 431 } 432 gs.n = m.n 433 434 if gs.n == 100 { 435 gs.res <- 1000 436 } 437 return gen.ServerStatusOK 438 439 case testCase2: 440 if gs.n != m.n { 441 panic(fmt.Sprintf("Disordered messages on %d (awaited: %d)", m.n, gs.n+1)) 442 } 443 gs.n = m.n - 1 444 value, err := process.Call("gs3order", message) 445 if err != nil { 446 panic(err) 447 } 448 if value.(string) != "ok" { 449 panic("wrong result") 450 } 451 452 if gs.n == 0 { 453 gs.res <- 123 454 } 455 return gen.ServerStatusOK 456 } 457 458 return gen.ServerStatusStop 459 } 460 461 func (gs *messageOrderGS) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 462 switch message.(type) { 463 case testCase2: 464 return "ok", gen.ServerStatusOK 465 case testCase3: 466 return "ok", gen.ServerStatusOK 467 } 468 return nil, fmt.Errorf("incorrect call") 469 } 470 471 func (gs *messageOrderGS) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 472 switch m := message.(type) { 473 case testCase3: 474 for i := 0; i < m.n; i++ { 475 value, err := process.Call("gs3order", message) 476 if err != nil { 477 panic(err) 478 } 479 if value.(string) != "ok" { 480 panic("wrong result") 481 } 482 } 483 return nil, gen.DirectStatusOK 484 485 } 486 return nil, fmt.Errorf("incorrect direct call") 487 } 488 489 type GSCallPanic struct { 490 gen.Server 491 } 492 493 func (gs *GSCallPanic) Init(process *gen.ServerProcess, args ...etf.Term) error { 494 return nil 495 } 496 497 func (gs *GSCallPanic) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 498 m := message.(string) 499 if m == "panic" { 500 panic("test") 501 } 502 503 return "ok", gen.ServerStatusOK 504 } 505 506 func (gs *GSCallPanic) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 507 508 pids, ok := message.([]etf.Pid) 509 if !ok { 510 return nil, fmt.Errorf("not a pid") 511 } 512 fmt.Printf(" making a call p1node1 -> p1node2 (panic): ") 513 if _, err := process.CallWithTimeout(pids[0], "panic", 1); err == nil { 514 return nil, fmt.Errorf("must be error here") 515 } else { 516 fmt.Println("OK") 517 } 518 fmt.Printf(" making a call p1node1 -> p2node2: ") 519 v, err := process.Call(pids[1], "test") 520 if err != nil { 521 return nil, err 522 } 523 if v.(string) != "ok" { 524 return nil, fmt.Errorf("wrong result %#v", v) 525 } 526 fmt.Println("OK") 527 528 return nil, gen.DirectStatusOK 529 } 530 531 func TestServerCallServerWithPanic(t *testing.T) { 532 fmt.Printf("\n=== Test Server. Making a Call to Server with panic (issue 86) \n") 533 fmt.Printf("Starting node: nodeGSCallWithPanic1@localhost: ") 534 node1, err1 := ergo.StartNode("nodeGSCallWithPanic1@localhost", "cookies", node.Options{}) 535 if err1 != nil { 536 t.Fatal("can't start node", err1) 537 } else { 538 fmt.Println("OK") 539 } 540 fmt.Printf("Starting node: nodeGSCallWithPanic2@localhost: ") 541 node2, err2 := ergo.StartNode("nodeGSCallWithPanic2@localhost", "cookies", node.Options{}) 542 if err2 != nil { 543 t.Fatal("can't start node", err2) 544 } else { 545 fmt.Println("OK") 546 } 547 548 p1n1, err := node1.Spawn("p1node1", gen.ProcessOptions{}, &GSCallPanic{}) 549 if err != nil { 550 t.Fatal(err) 551 } 552 p1n2, err := node2.Spawn("p1node2", gen.ProcessOptions{}, &GSCallPanic{}) 553 if err != nil { 554 t.Fatal(err) 555 } 556 p2n2, err := node2.Spawn("2node2", gen.ProcessOptions{}, &GSCallPanic{}) 557 if err != nil { 558 t.Fatal(err) 559 } 560 561 pids := []etf.Pid{p1n2.Self(), p2n2.Self()} 562 563 if _, err := p1n1.Direct(pids); err != nil { 564 t.Fatal(err) 565 } 566 } 567 568 func TestServerMessageOrder(t *testing.T) { 569 fmt.Printf("\n=== Test Server message order\n") 570 fmt.Printf("Starting node: nodeGS1MessageOrder@localhost: ") 571 node1, _ := ergo.StartNode("nodeGS1MessageOrder@localhost", "cookies", node.Options{}) 572 if node1 == nil { 573 t.Fatal("can't start nodes") 574 } else { 575 fmt.Println("OK") 576 } 577 578 gs1 := &messageOrderGS{ 579 res: make(chan interface{}, 2), 580 } 581 582 gs2 := &messageOrderGS{ 583 res: make(chan interface{}, 2), 584 } 585 586 gs3 := &messageOrderGS{ 587 res: make(chan interface{}, 2), 588 } 589 590 fmt.Printf(" wait for start of gs1order on %#v: ", node1.Name()) 591 node1gs1, err1 := node1.Spawn("gs1order", gen.ProcessOptions{}, gs1, nil) 592 if err1 != nil { 593 panic(err1) 594 } 595 waitForResultWithValue(t, gs1.res, nil) 596 597 fmt.Printf(" wait for start of gs2order on %#v: ", node1.Name()) 598 node1gs2, err2 := node1.Spawn("gs2order", gen.ProcessOptions{}, gs2, nil) 599 if err2 != nil { 600 panic(err2) 601 } 602 waitForResultWithValue(t, gs2.res, nil) 603 604 fmt.Printf(" wait for start of gs3order on %#v: ", node1.Name()) 605 node1gs3, err3 := node1.Spawn("gs3order", gen.ProcessOptions{}, gs3, nil) 606 if err3 != nil { 607 panic(err3) 608 } 609 waitForResultWithValue(t, gs3.res, nil) 610 611 fmt.Printf(" sending 100 messages from gs1 to gs2. checking the order: ") 612 for i := 1; i < 101; i++ { 613 err := node1gs1.Send(node1gs2.Self(), testCase1{n: i}) 614 if err != nil { 615 t.Fatal(err) 616 } 617 } 618 waitForResultWithValue(t, gs2.res, 1000) 619 620 fmt.Printf(" making Direct call with making a call from gs2 to gs3 1 time: ") 621 _, err := node1gs2.Direct(testCase3{n: 1}) 622 if err != nil { 623 t.Fatal(err) 624 } 625 fmt.Println("OK") 626 fmt.Printf(" making Direct call with making a call from gs2 to gs3 100 times: ") 627 _, err = node1gs2.Direct(testCase3{n: 100}) 628 if err != nil { 629 t.Fatal(err) 630 } 631 fmt.Println("OK") 632 633 gs2.n = 100 634 635 fmt.Printf(" sending 100 messages from gs1 to gs2 with making a call from gs2 to gs3: ") 636 for i := gs2.n; i > 0; i-- { 637 err := node1gs1.Send(node1gs2.Self(), testCase2{n: i}) 638 if err != nil { 639 t.Fatal(err) 640 } 641 } 642 waitForResultWithValue(t, gs2.res, 123) 643 node1gs3.Exit("normal") 644 node1.Stop() 645 node1.Wait() 646 } 647 648 type messageFloodSourceGS struct { 649 gen.Server 650 id int 651 res chan interface{} 652 } 653 654 type messageFlood struct { 655 id int 656 i int 657 } 658 659 func (fl *messageFloodSourceGS) Init(process *gen.ServerProcess, args ...etf.Term) error { 660 fl.res <- nil 661 return nil 662 } 663 664 func (fl *messageFloodSourceGS) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 665 max := message.(int) 666 667 for i := 1; i < max+1; i++ { 668 if err := process.Send("gsdest", messageFlood{id: fl.id - 1, i: i}); err != nil { 669 panic(fmt.Sprintf("err on making a send: %s", err)) 670 } 671 if err := process.Cast("gsdest", messageFlood{id: fl.id - 1, i: i}); err != nil { 672 panic(fmt.Sprintf("err on making a cast: %s", err)) 673 } 674 if _, err := process.Call("gsdest", messageFlood{id: fl.id - 1, i: i}); err != nil { 675 panic(fmt.Sprintf("err on making a call: %s", err)) 676 } 677 678 } 679 680 return gen.ServerStatusStop 681 } 682 683 type messageFloodDestGS struct { 684 gen.Server 685 max int 686 info [5]int 687 cast [5]int 688 call [5]int 689 done int 690 res chan interface{} 691 } 692 693 func (fl *messageFloodDestGS) Init(process *gen.ServerProcess, args ...etf.Term) error { 694 695 fl.res <- nil 696 return nil 697 } 698 699 func (fl *messageFloodDestGS) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 700 switch m := message.(type) { 701 case messageFlood: 702 if fl.call[m.id]+1 != m.i { 703 panic("wrong order") 704 } 705 fl.call[m.id] = m.i 706 if fl.call[m.id] == fl.max { 707 fl.done++ 708 } 709 if fl.done != len(fl.info)*3 { 710 return nil, gen.ServerStatusOK 711 } 712 default: 713 return nil, gen.ServerStatusStop 714 } 715 716 fl.res <- nil 717 return nil, gen.ServerStatusOK 718 } 719 720 func (fl *messageFloodDestGS) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 721 switch m := message.(type) { 722 case messageFlood: 723 if fl.cast[m.id]+1 != m.i { 724 panic("wrong order") 725 } 726 fl.cast[m.id] = m.i 727 if fl.cast[m.id] == fl.max { 728 fl.done++ 729 } 730 if fl.done != len(fl.info)*3 { 731 return gen.ServerStatusOK 732 } 733 default: 734 return gen.ServerStatusStop 735 } 736 737 fl.res <- nil 738 return gen.ServerStatusOK 739 } 740 741 func (fl *messageFloodDestGS) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 742 switch m := message.(type) { 743 case messageFlood: 744 if fl.info[m.id]+1 != m.i { 745 panic("wrong order") 746 } 747 fl.info[m.id] = m.i 748 if fl.info[m.id] == fl.max { 749 fl.done++ 750 } 751 if fl.done != len(fl.info)*3 { 752 return gen.ServerStatusOK 753 } 754 default: 755 return gen.ServerStatusStop 756 } 757 758 fl.res <- nil 759 return gen.ServerStatusOK 760 } 761 762 type testCaseFlood struct { 763 id int 764 } 765 766 func TestServerMessageFlood(t *testing.T) { 767 fmt.Printf("\n=== Test Server message flood \n") 768 fmt.Printf("Starting node: nodeGS1MessageFlood@localhost: ") 769 node1, _ := ergo.StartNode("nodeGS1MessageFlood@localhost", "cookies", node.Options{}) 770 if node1 == nil { 771 t.Fatal("can't start nodes") 772 } else { 773 fmt.Println("OK") 774 } 775 776 gs1source := &messageFloodSourceGS{ 777 id: 1, 778 res: make(chan interface{}, 2), 779 } 780 gs2source := &messageFloodSourceGS{ 781 id: 2, 782 res: make(chan interface{}, 2), 783 } 784 gs3source := &messageFloodSourceGS{ 785 id: 3, 786 res: make(chan interface{}, 2), 787 } 788 gs4source := &messageFloodSourceGS{ 789 id: 4, 790 res: make(chan interface{}, 2), 791 } 792 gs5source := &messageFloodSourceGS{ 793 id: 5, 794 res: make(chan interface{}, 2), 795 } 796 797 gsdest := &messageFloodDestGS{ 798 res: make(chan interface{}, 2), 799 } 800 fmt.Printf(" wait for start of gs1source on %#v: ", node1.Name()) 801 gs1sourceProcess, _ := node1.Spawn("gs1source", gen.ProcessOptions{}, gs1source, nil) 802 waitForResultWithValue(t, gs1source.res, nil) 803 804 fmt.Printf(" wait for start of gs2source on %#v: ", node1.Name()) 805 gs2sourceProcess, _ := node1.Spawn("gs2source", gen.ProcessOptions{}, gs2source, nil) 806 waitForResultWithValue(t, gs2source.res, nil) 807 808 fmt.Printf(" wait for start of gs3source on %#v: ", node1.Name()) 809 gs3sourceProcess, _ := node1.Spawn("gs3source", gen.ProcessOptions{}, gs3source, nil) 810 waitForResultWithValue(t, gs3source.res, nil) 811 812 fmt.Printf(" wait for start of gs4source on %#v: ", node1.Name()) 813 gs4sourceProcess, _ := node1.Spawn("gs4source", gen.ProcessOptions{}, gs4source, nil) 814 waitForResultWithValue(t, gs4source.res, nil) 815 816 fmt.Printf(" wait for start of gs5source on %#v: ", node1.Name()) 817 gs5sourceProcess, _ := node1.Spawn("gs5source", gen.ProcessOptions{}, gs5source, nil) 818 waitForResultWithValue(t, gs5source.res, nil) 819 820 fmt.Printf(" wait for start of gsdest on %#v: ", node1.Name()) 821 node1.Spawn("gsdest", gen.ProcessOptions{}, gsdest, nil) 822 waitForResultWithValue(t, gsdest.res, nil) 823 824 gsdest.max = 1000 825 // start flood 826 gs1sourceProcess.Send(gs1sourceProcess.Self(), gsdest.max) 827 gs2sourceProcess.Send(gs2sourceProcess.Self(), gsdest.max) 828 gs3sourceProcess.Send(gs3sourceProcess.Self(), gsdest.max) 829 gs4sourceProcess.Send(gs4sourceProcess.Self(), gsdest.max) 830 gs5sourceProcess.Send(gs5sourceProcess.Self(), gsdest.max) 831 832 waitForResultWithValue(t, gsdest.res, nil) 833 } 834 835 func waitForResult(t *testing.T, w chan error) { 836 select { 837 case e := <-w: 838 if e == nil { 839 fmt.Println("OK") 840 return 841 } 842 843 t.Fatal(e) 844 845 case <-time.After(time.Second * time.Duration(1)): 846 t.Fatal("result timeout") 847 } 848 } 849 850 func waitForResultWithMultiValue(t *testing.T, w chan interface{}, values etf.List) { 851 852 select { 853 case v := <-w: 854 found := false 855 i := 0 856 for { 857 if reflect.DeepEqual(v, values[i]) { 858 found = true 859 values[i] = values[0] 860 values = values[1:] 861 if len(values) == 0 { 862 return 863 } 864 // i dont care about stack growing since 'values' 865 // usually short 866 waitForResultWithMultiValue(t, w, values) 867 break 868 } 869 i++ 870 if i+1 > len(values) { 871 break 872 } 873 } 874 875 if !found { 876 e := fmt.Errorf("got unexpected value: %#v", v) 877 t.Fatal(e) 878 } 879 880 case <-time.After(time.Second * time.Duration(2)): 881 t.Fatal("result timeout") 882 } 883 fmt.Println("OK") 884 } 885 886 func waitForResultWithValue(t *testing.T, w chan interface{}, value interface{}) { 887 select { 888 case v := <-w: 889 if reflect.DeepEqual(v, value) { 890 fmt.Println("OK") 891 } else { 892 e := fmt.Errorf("expected: %#v , got: %#v", value, v) 893 t.Fatal(e) 894 } 895 896 case <-time.After(time.Second * time.Duration(2)): 897 t.Fatal("result timeout") 898 } 899 } 900 901 func waitForResultWithValueReturnError(t *testing.T, w chan interface{}, value interface{}) error { 902 select { 903 case v := <-w: 904 if reflect.DeepEqual(v, value) { 905 return nil 906 } else { 907 return fmt.Errorf("expected: %#v , got: %#v", value, v) 908 } 909 910 case <-time.After(time.Second * time.Duration(2)): 911 return fmt.Errorf("result timeout") 912 } 913 } 914 915 func waitForResultWithValueOrValue(t *testing.T, w chan interface{}, value1, value2 interface{}) { 916 select { 917 case v := <-w: 918 if reflect.DeepEqual(v, value1) { 919 fmt.Println("OK") 920 } else { 921 if reflect.DeepEqual(v, value2) { 922 fmt.Println("OK") 923 } else { 924 e := fmt.Errorf("expected another value, but got: %#v", v) 925 t.Fatal(e) 926 } 927 } 928 929 case <-time.After(time.Second * time.Duration(2)): 930 t.Fatal("result timeout") 931 } 932 } 933 934 func waitForTimeout(t *testing.T, w chan interface{}) { 935 select { 936 case v := <-w: 937 e := fmt.Errorf("got value we shouldn't receive: %#v", v) 938 t.Fatal(e) 939 940 case <-time.After(time.Millisecond * time.Duration(300)): 941 return 942 } 943 }