github.com/ergo-services/ergo@v1.999.224/tests/node_test.go (about) 1 package tests 2 3 import ( 4 "context" 5 "crypto/md5" 6 "crypto/tls" 7 "fmt" 8 "math/rand" 9 "net" 10 "reflect" 11 "sync" 12 "testing" 13 "time" 14 15 "github.com/ergo-services/ergo" 16 "github.com/ergo-services/ergo/etf" 17 "github.com/ergo-services/ergo/gen" 18 "github.com/ergo-services/ergo/lib" 19 "github.com/ergo-services/ergo/node" 20 "github.com/ergo-services/ergo/proto/dist" 21 ) 22 23 type benchCase struct { 24 name string 25 value etf.Term 26 } 27 28 func TestNode(t *testing.T) { 29 ctx := context.Background() 30 listener := node.Listener{ 31 Listen: 25001, 32 } 33 opts := node.Options{ 34 Listeners: []node.Listener{listener}, 35 Registrar: dist.CreateRegistrarWithLocalEPMD("", 24999), 36 } 37 38 node1, _ := ergo.StartNodeWithContext(ctx, "node123@localhost", "cookies", opts) 39 optsTaken := node.Options{ 40 Registrar: dist.CreateRegistrarWithLocalEPMD("", 24999), 41 } 42 if _, err := ergo.StartNodeWithContext(ctx, "node123@localhost", "cookies", optsTaken); err == nil { 43 t.Fatal("must be failed here") 44 } 45 46 if conn, err := net.Dial("tcp", ":25001"); err != nil { 47 fmt.Println("Connect to the node' listening port FAILED") 48 t.Fatal(err) 49 } else { 50 defer conn.Close() 51 } 52 53 if conn, err := net.Dial("tcp", ":24999"); err != nil { 54 fmt.Println("Connect to the node' listening EPMD port FAILED") 55 t.Fatal(err) 56 } else { 57 defer conn.Close() 58 } 59 60 gs1 := &testServer{ 61 res: make(chan interface{}, 2), 62 } 63 p, e := node1.Spawn("", gen.ProcessOptions{}, gs1) 64 if e != nil { 65 t.Fatal(e) 66 } 67 68 if !p.IsAlive() { 69 t.Fatal("IsAlive: expect 'true', but got 'false'") 70 } 71 72 _, ee := node1.ProcessInfo(p.Self()) 73 if ee != nil { 74 t.Fatal(ee) 75 } 76 77 node1.Stop() 78 } 79 80 type testFragmentationGS struct { 81 gen.Server 82 } 83 84 func (f *testFragmentationGS) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 85 md5original := message.(etf.Tuple)[0].(string) 86 blob := message.(etf.Tuple)[1].([]byte) 87 88 result := etf.Atom("ok") 89 md5 := fmt.Sprint(md5.Sum(blob)) 90 if !reflect.DeepEqual(md5original, md5) { 91 result = etf.Atom("mismatch") 92 } 93 94 return result, gen.ServerStatusOK 95 } 96 97 type makeCall struct { 98 to interface{} 99 message interface{} 100 } 101 type makeCast struct { 102 to interface{} 103 message interface{} 104 } 105 106 type asyncDirect struct { 107 ref etf.Ref 108 val etf.Term 109 } 110 111 type syncDirect struct { 112 val etf.Term 113 } 114 115 func (f *testFragmentationGS) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 116 switch m := message.(type) { 117 case makeCall: 118 return process.Call(m.to, m.message) 119 } 120 return nil, lib.ErrUnsupportedRequest 121 } 122 123 func TestNodeFragmentation(t *testing.T) { 124 var wg sync.WaitGroup 125 126 blob := make([]byte, 1024*1024) 127 rand.Read(blob) 128 md5 := fmt.Sprint(md5.Sum(blob)) 129 message := etf.Tuple{md5, blob} 130 131 node1, _ := ergo.StartNode("nodeT1Fragmentation@localhost", "secret", node.Options{}) 132 node2, _ := ergo.StartNode("nodeT2Fragmentation@localhost", "secret", node.Options{}) 133 134 tgs := &testFragmentationGS{} 135 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, tgs) 136 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, tgs) 137 138 if e1 != nil { 139 t.Fatal(e1) 140 } 141 if e2 != nil { 142 t.Fatal(e2) 143 } 144 145 // check single call 146 call := makeCall{ 147 to: p2.Self(), 148 message: message, 149 } 150 check, e := p1.Direct(call) 151 if e != nil { 152 t.Fatal(e) 153 } 154 if check != etf.Atom("ok") { 155 t.Fatal("md5sum mismatch") 156 } 157 158 for i := 0; i < 10; i++ { 159 wg.Add(1) 160 go func() { 161 p1, _ := node1.Spawn("", gen.ProcessOptions{}, tgs) 162 p2, _ := node2.Spawn("", gen.ProcessOptions{}, tgs) 163 defer wg.Done() 164 for k := 0; k < 100; k++ { 165 call := makeCall{ 166 to: p2.Self(), 167 message: message, 168 } 169 check, e := p1.Direct(call) 170 if e != nil { 171 panic("err on call") 172 } 173 if check != etf.Atom("ok") { 174 panic("md5sum mismatch") 175 } 176 } 177 178 }() 179 } 180 wg.Wait() 181 } 182 183 func TestNodeStaticRoute(t *testing.T) { 184 nodeName1 := "nodeT1StaticRoute@localhost" 185 nodeName2 := "nodeT2StaticRoute@localhost" 186 nodeStaticPort := uint16(9876) 187 188 node1, e1 := ergo.StartNode(nodeName1, "secret", node.Options{}) 189 if e1 != nil { 190 t.Fatal(e1) 191 } 192 defer node1.Stop() 193 194 node2, e2 := ergo.StartNode(nodeName2, "secret", node.Options{}) 195 if e2 != nil { 196 t.Fatal(e2) 197 } 198 defer node2.Stop() 199 200 nr, err := node1.Resolve(nodeName2) 201 if err != nil { 202 t.Fatal("Can't resolve port number for ", nodeName2, err) 203 } 204 205 // override route for nodeName2 with static port 206 e := node1.AddStaticRoutePort(nodeName2, nodeStaticPort, node.RouteOptions{}) 207 if e != nil { 208 t.Fatal(e) 209 } 210 // should be overrided by the new value of nodeStaticPort 211 if r, err := node1.Resolve(nodeName2); err != nil || r.Port != nodeStaticPort { 212 t.Fatal("Wrong port number after adding static route. Got", r.Port, "Expected", nodeStaticPort) 213 } 214 215 node1.RemoveStaticRoute(nodeName2) 216 217 // should be resolved into the original port number 218 if nr2, err := node1.Resolve(nodeName2); err != nil || nr.Port != nr2.Port { 219 t.Fatal("Wrong port number after removing static route") 220 } 221 } 222 223 type handshakeGenServer struct { 224 gen.Server 225 } 226 227 func (h *handshakeGenServer) Init(process *gen.ServerProcess, args ...etf.Term) error { 228 return nil 229 } 230 231 func (h *handshakeGenServer) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 232 return "pass", gen.ServerStatusOK 233 } 234 func (h *handshakeGenServer) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 235 switch m := message.(type) { 236 case makeCall: 237 return process.Call(m.to, m.message) 238 } 239 return nil, lib.ErrUnsupportedRequest 240 } 241 242 func TestNodeDistHandshake(t *testing.T) { 243 fmt.Printf("\n=== Test Node Handshake versions\n") 244 245 cert, err := lib.GenerateSelfSignedCert("localhost") 246 if err != nil { 247 t.Fatal(err) 248 } 249 250 // handshake version 5 251 handshake5options := dist.HandshakeOptions{ 252 Version: dist.HandshakeVersion5, 253 } 254 255 // handshake version 6 256 handshake6options := dist.HandshakeOptions{ 257 Version: dist.HandshakeVersion6, 258 } 259 260 hgs := &handshakeGenServer{} 261 262 type Pair struct { 263 name string 264 nodeA node.Node 265 nodeB node.Node 266 } 267 node1Options5 := node.Options{ 268 Handshake: dist.CreateHandshake(handshake5options), 269 } 270 node1, e1 := ergo.StartNode("node1Handshake5@localhost", "secret", node1Options5) 271 if e1 != nil { 272 t.Fatal(e1) 273 } 274 node2Options5 := node.Options{ 275 Handshake: dist.CreateHandshake(handshake5options), 276 } 277 node2, e2 := ergo.StartNode("node2Handshake5@localhost", "secret", node2Options5) 278 if e2 != nil { 279 t.Fatal(e2) 280 } 281 node3Options5 := node.Options{ 282 Handshake: dist.CreateHandshake(handshake5options), 283 } 284 node3, e3 := ergo.StartNode("node3Handshake5@localhost", "secret", node3Options5) 285 if e3 != nil { 286 t.Fatal(e3) 287 } 288 node4Options6 := node.Options{ 289 Handshake: dist.CreateHandshake(handshake6options), 290 } 291 node4, e4 := ergo.StartNode("node4Handshake6@localhost", "secret", node4Options6) 292 if e4 != nil { 293 t.Fatal(e4) 294 } 295 // node5, _ := ergo.StartNode("node5Handshake6@localhost", "secret", nodeOptions6) 296 // node6, _ := ergo.StartNode("node6Handshake5@localhost", "secret", nodeOptions5) 297 node7Options6 := node.Options{ 298 Handshake: dist.CreateHandshake(handshake6options), 299 } 300 node7, e7 := ergo.StartNode("node7Handshake6@localhost", "secret", node7Options6) 301 if e7 != nil { 302 t.Fatal(e7) 303 } 304 node8Options6 := node.Options{ 305 Handshake: dist.CreateHandshake(handshake6options), 306 } 307 node8, e8 := ergo.StartNode("node8Handshake6@localhost", "secret", node8Options6) 308 if e8 != nil { 309 t.Fatal(e8) 310 } 311 node9Options5WithTLS := node.Options{ 312 Handshake: dist.CreateHandshake(handshake5options), 313 TLS: &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}, 314 } 315 node9, e9 := ergo.StartNode("node9Handshake5@localhost", "secret", node9Options5WithTLS) 316 if e9 != nil { 317 t.Fatal(e9) 318 } 319 node10Options5WithTLS := node.Options{ 320 Handshake: dist.CreateHandshake(handshake5options), 321 TLS: &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}, 322 } 323 node10, e10 := ergo.StartNode("node10Handshake5@localhost", "secret", node10Options5WithTLS) 324 if e10 != nil { 325 t.Fatal(e10) 326 } 327 node11Options5WithTLS := node.Options{ 328 Handshake: dist.CreateHandshake(handshake5options), 329 TLS: &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}, 330 } 331 node11, e11 := ergo.StartNode("node11Handshake5@localhost", "secret", node11Options5WithTLS) 332 if e11 != nil { 333 t.Fatal(e11) 334 } 335 node12Options6WithTLS := node.Options{ 336 Handshake: dist.CreateHandshake(handshake6options), 337 TLS: &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}, 338 } 339 node12, e12 := ergo.StartNode("node12Handshake6@localhost", "secret", node12Options6WithTLS) 340 if e12 != nil { 341 t.Fatal(e12) 342 } 343 // node13, _ := ergo.StartNode("node13Handshake6@localhost", "secret", nodeOptions6WithTLS) 344 // node14, _ := ergo.StartNode("node14Handshake5@localhost", "secret", nodeOptions5WithTLS) 345 node15Options6WithTLS := node.Options{ 346 Handshake: dist.CreateHandshake(handshake6options), 347 TLS: &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}, 348 } 349 node15, e15 := ergo.StartNode("node15Handshake6@localhost", "secret", node15Options6WithTLS) 350 if e15 != nil { 351 t.Fatal(e15) 352 } 353 node16Options6WithTLS := node.Options{ 354 Handshake: dist.CreateHandshake(handshake6options), 355 TLS: &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}, 356 } 357 node16, e16 := ergo.StartNode("node16Handshake6@localhost", "secret", node16Options6WithTLS) 358 if e16 != nil { 359 t.Fatal(e16) 360 } 361 362 nodes := []Pair{ 363 {"No TLS. version 5 -> version 5", node1, node2}, 364 {"No TLS. version 5 -> version 6", node3, node4}, 365 //Pair{ "No TLS. version 6 -> version 5", node5, node6 }, 366 {"No TLS. version 6 -> version 6", node7, node8}, 367 {"With TLS. version 5 -> version 5", node9, node10}, 368 {"With TLS. version 5 -> version 6", node11, node12}, 369 //Pair{ "With TLS. version 6 -> version 5", node13, node14 }, 370 {"With TLS. version 6 -> version 6", node15, node16}, 371 } 372 373 defer func(nodes []Pair) { 374 for i := range nodes { 375 nodes[i].nodeA.Stop() 376 nodes[i].nodeB.Stop() 377 } 378 }(nodes) 379 380 var pA, pB gen.Process 381 var e error 382 var result etf.Term 383 for i := range nodes { 384 pair := nodes[i] 385 fmt.Printf(" %s %s -> %s: ", pair.name, pair.nodeA.Name(), pair.nodeB.Name()) 386 pA, e = pair.nodeA.Spawn("", gen.ProcessOptions{}, hgs) 387 if e != nil { 388 t.Fatal(e) 389 } 390 pB, e = pair.nodeB.Spawn("", gen.ProcessOptions{}, hgs) 391 if e != nil { 392 t.Fatal(e) 393 } 394 395 call := makeCall{ 396 to: pB.Self(), 397 message: "test", 398 } 399 result, e = pA.Direct(call) 400 if e != nil { 401 t.Fatal(e) 402 } 403 if r, ok := result.(string); !ok || r != "pass" { 404 t.Fatal("wrong result") 405 } 406 fmt.Println("OK") 407 } 408 } 409 410 func TestNodeRemoteSpawn(t *testing.T) { 411 fmt.Printf("\n=== Test Node Remote Spawn\n") 412 node1opts := node.Options{} 413 node1opts.Proxy.Flags = node.DefaultProxyFlags() 414 node1opts.Proxy.Flags.EnableRemoteSpawn = false 415 416 node1, _ := ergo.StartNode("node1remoteSpawn@localhost", "secret", node1opts) 417 node2opts := node.Options{} 418 node2opts.Proxy.Transit = true 419 node2, _ := ergo.StartNode("node2remoteSpawn@localhost", "secret", node2opts) 420 node3opts := node.Options{} 421 node3opts.Proxy.Accept = true 422 node3, _ := ergo.StartNode("node3remoteSpawn@localhost", "secret", node3opts) 423 route := node.ProxyRoute{ 424 Name: node3.Name(), 425 Proxy: node2.Name(), 426 } 427 node1.AddProxyRoute(route) 428 defer node1.Stop() 429 defer node2.Stop() 430 defer node3.Stop() 431 432 if err := node1.Connect(node3.Name()); err != nil { 433 t.Fatal(err) 434 } 435 436 node2.ProvideRemoteSpawn("remote", &handshakeGenServer{}) 437 process, err := node1.Spawn("gs1", gen.ProcessOptions{}, &handshakeGenServer{}) 438 if err != nil { 439 t.Fatal(err) 440 } 441 442 opts := gen.RemoteSpawnOptions{ 443 Name: "remote", 444 } 445 fmt.Printf(" process gs1@node1 request to spawn new process on node2 and register this process with name 'remote': ") 446 gotPid, err := process.RemoteSpawn(node2.Name(), "remote", opts, 1, 2, 3) 447 if err != nil { 448 t.Fatal(err) 449 } 450 p := node2.ProcessByName("remote") 451 if p == nil { 452 t.Fatal("can't find process 'remote' on node2") 453 } 454 if gotPid != p.Self() { 455 t.Fatal("process pid mismatch") 456 } 457 fmt.Println("OK") 458 459 fmt.Printf(" process gs1@node1 request to spawn new process on node2 with the same name (must be failed): ") 460 _, err = process.RemoteSpawn(node2.Name(), "remote", opts, 1, 2, 3) 461 if err != lib.ErrTaken { 462 t.Fatal(err) 463 } 464 fmt.Println("OK") 465 fmt.Printf(" process gs1@node1 request to spawn new process on node2 with unregistered behavior name (must be failed): ") 466 _, err = process.RemoteSpawn(node2.Name(), "randomname", opts, 1, 2, 3) 467 if err != lib.ErrBehaviorUnknown { 468 t.Fatal(err) 469 } 470 fmt.Println("OK") 471 472 fmt.Printf(" process gs1@node1 request to spawn new process on node3 via proxy node2 and register this process with name 'remote': ") 473 node3.ProvideRemoteSpawn("remote", &handshakeGenServer{}) 474 gotPid, err = process.RemoteSpawn(node3.Name(), "remote", opts, 1, 2, 3) 475 if err != nil { 476 t.Fatal(err) 477 } 478 p = node3.ProcessByName("remote") 479 if p == nil { 480 t.Fatal("can't find process 'remote' on node2") 481 } 482 if gotPid != p.Self() { 483 t.Fatal("process pid mismatch") 484 } 485 fmt.Println("OK") 486 fmt.Printf(" process gs3@node3 request to spawn new process on node1 via proxy node2 (node1 ProxyFlags.RemoteSpawn: false): ") 487 process3, err := node3.Spawn("gs3", gen.ProcessOptions{}, &handshakeGenServer{}) 488 if err != nil { 489 t.Fatal(err) 490 } 491 gotPid, err = process3.RemoteSpawn(node1.Name(), "remote", opts, 1, 2, 3) 492 if err != lib.ErrPeerUnsupported { 493 t.Fatal(err) 494 } 495 fmt.Println("OK") 496 } 497 498 func TestNodeResolveExtra(t *testing.T) { 499 cert, err := lib.GenerateSelfSignedCert("localhost") 500 if err != nil { 501 t.Fatal(err) 502 } 503 fmt.Printf("\n=== Test Node Resolve Extra \n") 504 fmt.Printf("... starting node1 with disabled TLS: ") 505 opts1 := node.Options{ 506 TLS: &tls.Config{InsecureSkipVerify: true}, 507 } 508 node1, err := ergo.StartNode("node1resolveExtra@localhost", "secret", opts1) 509 if err != nil { 510 t.Fatal(err) 511 } 512 defer node1.Stop() 513 fmt.Println("OK") 514 opts2 := node.Options{ 515 TLS: &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}, 516 } 517 fmt.Printf("... starting node2 with enabled TLS: ") 518 node2, err := ergo.StartNode("node2resolveExtra@localhost", "secret", opts2) 519 if err != nil { 520 t.Fatal(err) 521 } 522 defer node2.Stop() 523 fmt.Println("OK") 524 525 fmt.Printf("... node1 resolves node2 with enabled TLS: ") 526 route1, err := node1.Resolve("node2resolveExtra@localhost") 527 if err != nil { 528 t.Fatal(err) 529 } 530 if route1.Options.TLS == nil { 531 t.Fatal("expected TLS value") 532 } 533 fmt.Println("OK") 534 535 fmt.Printf("... node2 resolves node1 with disabled TLS: ") 536 route2, err := node2.Resolve("node1resolveExtra@localhost") 537 if err != nil { 538 t.Fatal(err) 539 } 540 if route2.Options.TLS != nil { 541 t.Fatal("expected nil value for TLS") 542 } 543 fmt.Println("OK") 544 545 fmt.Printf("... node1 connect to node2: ") 546 if err := node1.Connect(node2.Name()); err != nil { 547 t.Fatal(err) 548 } 549 if len(node1.Nodes()) != 1 { 550 t.Fatal("no peers") 551 } 552 if node1.Nodes()[0] != node2.Name() { 553 t.Fatal("wrong peer") 554 } 555 fmt.Println("OK") 556 557 fmt.Printf("... disconnecting nodes: ") 558 time.Sleep(300 * time.Millisecond) 559 if err := node1.Disconnect(node2.Name()); err != nil { 560 t.Fatal(err) 561 } 562 if len(node1.Nodes()) > 0 { 563 t.Fatal("still connected") 564 } 565 fmt.Println("OK") 566 567 fmt.Printf("... node2 connect to node1: ") 568 if err := node2.Connect(node1.Name()); err != nil { 569 t.Fatal(err) 570 } 571 if len(node2.Nodes()) != 1 { 572 t.Fatal("no peers") 573 } 574 if node2.Nodes()[0] != node1.Name() { 575 t.Fatal("wrong peer") 576 } 577 fmt.Println("OK") 578 } 579 580 type failoverServer struct { 581 gen.Server 582 v chan interface{} 583 } 584 585 func (f *failoverServer) Init(process *gen.ServerProcess, args ...etf.Term) error { 586 return nil 587 } 588 func (f *failoverServer) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 589 if _, yes := gen.IsMessageFallback(message); yes { 590 f.v <- message 591 return gen.ServerStatusOK 592 } 593 time.Sleep(300 * time.Millisecond) 594 return gen.ServerStatusOK 595 } 596 func TestNodeProcessFallback(t *testing.T) { 597 fmt.Printf("\n=== Test Node Process Fallback\n") 598 fmt.Printf("... start node1: ") 599 node1, e := ergo.StartNode("node1processfallback@localhost", "secret", node.Options{}) 600 if e != nil { 601 t.Fatal(e) 602 } 603 defer node1.Stop() 604 fmt.Println("OK") 605 popts1 := gen.ProcessOptions{ 606 MailboxSize: 2, 607 Fallback: gen.ProcessFallback{ 608 Name: "fp", 609 Tag: "test_tag", 610 }, 611 } 612 gsf := &failoverServer{ 613 v: make(chan interface{}, 2), 614 } 615 616 fmt.Printf("... start process p1 (with mailbox size = 2 and fallback process = \"fp\"): ") 617 p1, err := node1.Spawn("", popts1, &failoverServer{}) 618 if err != nil { 619 t.Fatal(e) 620 } 621 fmt.Println("OK") 622 fmt.Printf("... start failover process p2 (with name = \"fp\"): ") 623 _, err = node1.Spawn("fp", gen.ProcessOptions{}, gsf) 624 if err != nil { 625 t.Fatal(e) 626 } 627 fmt.Println("OK") 628 fmt.Printf("... sending 4 messages to p1 (4th must wrapped into gen.MessageFallback and forwarded to \"fp\" ): ") 629 p1.Send(p1.Self(), "m1") 630 p1.Send(p1.Self(), "m2") 631 p1.Send(p1.Self(), "m3") 632 // bellow message must be forwarded 633 p1.Send(p1.Self(), "m4") 634 635 result := gen.MessageFallback{Process: p1.Self(), Tag: "test_tag", Message: "m4"} 636 waitForResultWithValue(t, gsf.v, result) 637 } 638 639 type compressionServer struct { 640 gen.Server 641 } 642 643 func (c *compressionServer) Init(process *gen.ServerProcess, args ...etf.Term) error { 644 return nil 645 } 646 647 func (c *compressionServer) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 648 blob := message.(etf.Tuple)[1].([]byte) 649 md5original := message.(etf.Tuple)[0].(string) 650 md5sum := fmt.Sprint(md5.Sum(blob)) 651 result := etf.Atom("ok") 652 if !reflect.DeepEqual(md5original, md5sum) { 653 result = etf.Atom("mismatch") 654 } 655 return result, gen.ServerStatusOK 656 } 657 func (c *compressionServer) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 658 switch m := message.(type) { 659 case makeCall: 660 return process.Call(m.to, m.message) 661 } 662 return nil, lib.ErrUnsupportedRequest 663 } 664 func TestNodeCompression(t *testing.T) { 665 fmt.Printf("\n=== Test Node Compression \n") 666 opts1 := node.Options{} 667 opts1.Compression.Enable = true 668 // need 1 handler to make Atom cache work 669 protoOptions := node.DefaultProtoOptions() 670 protoOptions.NumHandlers = 1 671 opts1.Proto = dist.CreateProto(protoOptions) 672 node1, e := ergo.StartNode("node1compression@localhost", "secret", opts1) 673 if e != nil { 674 t.Fatal(e) 675 } 676 defer node1.Stop() 677 node2, e := ergo.StartNode("node2compression@localhost", "secret", node.Options{}) 678 if e != nil { 679 t.Fatal(e) 680 } 681 defer node2.Stop() 682 683 n1p1, err := node1.Spawn("", gen.ProcessOptions{}, &compressionServer{}) 684 if err != nil { 685 t.Fatal(err) 686 } 687 n2p1, err := node2.Spawn("", gen.ProcessOptions{}, &compressionServer{}) 688 if err != nil { 689 t.Fatal(err) 690 } 691 692 fmt.Printf("... send 1MB compressed. no fragmentation: ") 693 // empty data (no fragmentation) 694 blob := make([]byte, 1024*1024) 695 md5sum := fmt.Sprint(md5.Sum(blob)) 696 message := etf.Tuple{md5sum, blob} 697 698 // send 3 times. that is how atom cache is working - 699 // atoms are encoding from cache on 2nd or 3rd sending 700 call := makeCall{ 701 to: n2p1.Self(), 702 message: message, 703 } 704 for i := 0; i < 3; i++ { 705 result, e := n1p1.Direct(call) 706 if e != nil { 707 t.Fatal(e) 708 } 709 if result != etf.Atom("ok") { 710 t.Fatal(result) 711 } 712 } 713 fmt.Println("OK") 714 715 fmt.Printf("... send 1MB compressed. with fragmentation: ") 716 // will be fragmented 717 rnd := lib.RandomString(1024 * 1024) 718 blob = []byte(rnd) // compression rate for random string around 50% 719 //rand.Read(blob[:66000]) // compression rate for 1MB of random data - 0 % (entropy too big) 720 md5sum = fmt.Sprint(md5.Sum(blob)) 721 message = etf.Tuple{md5sum, blob} 722 723 call = makeCall{ 724 to: n2p1.Self(), 725 message: message, 726 } 727 for i := 0; i < 3; i++ { 728 result, e := n1p1.Direct(call) 729 if e != nil { 730 t.Fatal(e) 731 } 732 if result != etf.Atom("ok") { 733 t.Fatal(result) 734 } 735 } 736 fmt.Println("OK") 737 } 738 739 func TestNodeProxyConnect(t *testing.T) { 740 fmt.Printf("\n=== Test Node Proxy\n") 741 fmt.Printf("... connect NodeA to NodeC via NodeB: ") 742 optsA := node.Options{} 743 nodeA, e := ergo.StartNode("nodeAproxy@localhost", "secret", optsA) 744 if e != nil { 745 t.Fatal(e) 746 } 747 defer nodeA.Stop() 748 749 route := node.ProxyRoute{ 750 Name: "nodeCproxy@localhost", 751 Proxy: "nodeBproxy@localhost", 752 } 753 nodeA.AddProxyRoute(route) 754 755 optsB := node.Options{} 756 optsB.Proxy.Transit = true 757 nodeB, e := ergo.StartNode("nodeBproxy@localhost", "secret", optsB) 758 if e != nil { 759 t.Fatal(e) 760 } 761 defer nodeB.Stop() 762 optsC := node.Options{} 763 optsC.Proxy.Accept = true 764 nodeC, e := ergo.StartNode("nodeCproxy@localhost", "secret", optsC) 765 if e != nil { 766 t.Fatal(e) 767 } 768 defer nodeC.Stop() 769 770 if err := nodeA.Connect("nodeCproxy@localhost"); err != nil { 771 t.Fatal(err) 772 } 773 774 indirectNodes := nodeA.NodesIndirect() 775 if len(indirectNodes) != 1 { 776 t.Fatal("wrong result:", indirectNodes) 777 } 778 if indirectNodes[0] != "nodeCproxy@localhost" { 779 t.Fatal("wrong result:", indirectNodes) 780 } 781 indirectNodes = nodeC.NodesIndirect() 782 if len(indirectNodes) != 1 { 783 t.Fatal("wrong result:", indirectNodes) 784 } 785 if indirectNodes[0] != "nodeAproxy@localhost" { 786 t.Fatal("wrong result:", indirectNodes) 787 } 788 if len(nodeB.NodesIndirect()) > 0 { 789 t.Fatal("wrong result:", nodeB.NodesIndirect()) 790 } 791 fmt.Println("OK") 792 793 fmt.Printf("... disconnect NodeC from NodeA: ") 794 nodeC.Disconnect("nodeAproxy@localhost") 795 if len(nodeC.NodesIndirect()) > 0 { 796 t.Fatal("wrong result:", nodeC.NodesIndirect()) 797 } 798 799 time.Sleep(100 * time.Millisecond) 800 if len(nodeA.NodesIndirect()) > 0 { 801 t.Fatal("wrong result:", nodeA.NodesIndirect()) 802 } 803 fmt.Println("OK") 804 nodeB.Stop() 805 optsB.Proxy.Transit = false 806 nodeB, e = ergo.StartNode("nodeBproxy@localhost", "secret", optsB) 807 if e != nil { 808 t.Fatal(e) 809 } 810 fmt.Printf("... connect NodeA to NodeC via NodeB(transit proxy disabled): ") 811 e = nodeA.Connect("nodeCproxy@localhost") 812 if e == nil { 813 t.Fatal("must be error here") 814 } 815 errMessage := "[nodeBproxy@localhost] proxy feature disabled" 816 if e.Error() != errMessage { 817 t.Fatal(e) 818 } 819 fmt.Println("OK") 820 nodeB.Stop() 821 nodeC.Stop() 822 823 nodeB.Stop() 824 optsB.Proxy.Transit = true 825 nodeB, e = ergo.StartNode("nodeBproxy@localhost", "secret", optsB) 826 if e != nil { 827 t.Fatal(e) 828 } 829 830 optsC.Flags = node.DefaultFlags() 831 optsC.Flags.EnableProxy = false 832 nodeC, e = ergo.StartNode("nodeCproxy@localhost", "secret", optsC) 833 if e != nil { 834 t.Fatal(e) 835 } 836 fmt.Printf("... connect NodeA to NodeC (proxy feature support disabled) via NodeB: ") 837 e = nodeA.Connect("nodeCproxy@localhost") 838 if e == nil { 839 t.Fatal("must be error here") 840 } 841 errMessage = "[nodeBproxy@localhost] peer does not support this feature" 842 if e.Error() != errMessage { 843 t.Fatal(e) 844 } 845 fmt.Println("OK") 846 nodeC.Stop() 847 848 optsC = node.Options{} 849 optsC.Proxy.Cookie = "123" 850 optsC.Proxy.Accept = true 851 nodeC, e = ergo.StartNode("nodeCproxy@localhost", "secret", optsC) 852 if e != nil { 853 t.Fatal(e) 854 } 855 fmt.Printf("... connect NodeA to NodeC (with wrong cookie) via NodeB: ") 856 e = nodeA.Connect("nodeCproxy@localhost") 857 if e == nil { 858 t.Fatal("must be error here") 859 } 860 errMessage = "[nodeCproxy@localhost] can't establish proxy connection" 861 if e.Error() != errMessage { 862 t.Fatal(e) 863 } 864 fmt.Println("OK") 865 866 fmt.Printf("... connect NodeA to NodeC (with correct cookie) via NodeB: ") 867 if nodeA.RemoveProxyRoute("nodeCproxy@localhost") == false { 868 t.Fatal("proxy route not found") 869 } 870 route = node.ProxyRoute{ 871 Name: "nodeCproxy@localhost", 872 Proxy: "nodeBproxy@localhost", 873 Cookie: "123", 874 } 875 nodeA.AddProxyRoute(route) 876 877 e = nodeA.Connect("nodeCproxy@localhost") 878 if e != nil { 879 t.Fatal(e) 880 } 881 fmt.Println("OK") 882 883 fmt.Printf("... connect NodeA to NodeD (with enabled encryption) via NodeB: ") 884 optsD := node.Options{} 885 optsD.Proxy.Cookie = "123" 886 optsD.Proxy.Accept = true 887 optsD.Proxy.Flags = node.DefaultProxyFlags() 888 optsD.Proxy.Flags.EnableEncryption = true 889 nodeD, e := ergo.StartNode("nodeDproxy@localhost", "secret", optsD) 890 if e != nil { 891 t.Fatal(e) 892 } 893 defer nodeD.Stop() 894 895 route = node.ProxyRoute{ 896 Name: "nodeDproxy@localhost", 897 Proxy: "nodeBproxy@localhost", 898 Cookie: "123", 899 } 900 nodeA.AddProxyRoute(route) 901 e = nodeA.Connect("nodeDproxy@localhost") 902 if e != nil { 903 t.Fatal(e) 904 } 905 fmt.Println("OK") 906 907 // use gen serv from test_monitor 908 gsA := &testMonitor{ 909 v: make(chan interface{}, 2), 910 } 911 gsC := &testMonitor{ 912 v: make(chan interface{}, 2), 913 } 914 gsD := &testMonitor{ 915 v: make(chan interface{}, 2), 916 } 917 fmt.Printf("... start processA on NodeA: ") 918 pA, err := nodeA.Spawn("", gen.ProcessOptions{}, gsA) 919 if err != nil { 920 t.Fatal(err) 921 } 922 waitForResultWithValue(t, gsA.v, pA.Self()) 923 fmt.Printf("... start processC on NodeC: ") 924 pC, err := nodeC.Spawn("", gen.ProcessOptions{}, gsC) 925 if err != nil { 926 t.Fatal(err) 927 } 928 waitForResultWithValue(t, gsC.v, pC.Self()) 929 fmt.Printf("... start processD on NodeD: ") 930 pD, err := nodeD.Spawn("", gen.ProcessOptions{}, gsD) 931 if err != nil { 932 t.Fatal(err) 933 } 934 waitForResultWithValue(t, gsD.v, pD.Self()) 935 936 fmt.Printf("... processA send short message to processC: ") 937 if e := pA.Send(pC.Self(), "test"); e != nil { 938 t.Fatal(e) 939 } 940 waitForResultWithValue(t, gsC.v, "test") 941 942 fmt.Printf("... processA send short message to processD (encrypted): ") 943 pA.Send(pD.Self(), "test") 944 waitForResultWithValue(t, gsD.v, "test") 945 946 randomString := []byte(lib.RandomString(1024 * 10)) 947 pA.SetCompression(true) 948 fmt.Printf("... processA send 10K message to processC (compressed): ") 949 pA.Send(pC.Self(), randomString) 950 waitForResultWithValue(t, gsC.v, randomString) 951 952 fmt.Printf("... processA send 10K message to processD (compressed, encrypted): ") 953 pA.Send(pD.Self(), randomString) 954 waitForResultWithValue(t, gsD.v, randomString) 955 956 pA.SetCompression(false) 957 randomString = []byte(lib.RandomString(1024 * 100)) 958 fmt.Printf("... processA send 100K message to processC (fragmented): ") 959 pA.Send(pC.Self(), randomString) 960 waitForResultWithValue(t, gsC.v, randomString) 961 962 fmt.Printf("... processA send 100K message to processD (fragmented, encrypted): ") 963 pA.Send(pD.Self(), randomString) 964 waitForResultWithValue(t, gsD.v, randomString) 965 966 pA.SetCompression(true) 967 randomString = []byte(lib.RandomString(1024 * 1024)) 968 fmt.Printf("... processA send 1M message to processC (fragmented, compressed): ") 969 pA.Send(pC.Self(), randomString) 970 waitForResultWithValue(t, gsC.v, randomString) 971 972 fmt.Printf("... processA send 1M message to processD (fragmented, compressed, encrypted): ") 973 pA.Send(pD.Self(), randomString) 974 waitForResultWithValue(t, gsD.v, randomString) 975 } 976 977 func TestNodeIncarnation(t *testing.T) { 978 fmt.Printf("\n=== Test Node Incarnation\n") 979 fmt.Printf("... start nodes: ") 980 optsA := node.Options{} 981 nodeA, e := ergo.StartNode("nodeAincarnation@localhost", "secret", optsA) 982 if e != nil { 983 t.Fatal(e) 984 } 985 defer nodeA.Stop() 986 route := node.ProxyRoute{ 987 Name: "nodeCincarnation@localhost", 988 Proxy: "nodeBincarnation@localhost", 989 } 990 nodeA.AddProxyRoute(route) 991 // add sleep to get Creation different value for the next node 992 optsB := node.Options{} 993 optsB.Proxy.Transit = true 994 nodeB, e := ergo.StartNode("nodeBincarnation@localhost", "secret", optsB) 995 if e != nil { 996 t.Fatal(e) 997 } 998 defer nodeB.Stop() 999 optsC := node.Options{ 1000 Creation: 1234, 1001 } 1002 optsC.Proxy.Accept = true 1003 nodeC, e := ergo.StartNode("nodeCincarnation@localhost", "secret", optsC) 1004 if e != nil { 1005 t.Fatal(e) 1006 } 1007 defer nodeC.Stop() 1008 1009 if err := nodeA.Connect("nodeCincarnation@localhost"); err != nil { 1010 t.Fatal(err) 1011 } 1012 1013 indirectNodes := nodeA.NodesIndirect() 1014 if len(indirectNodes) != 1 { 1015 t.Fatal("wrong result:", indirectNodes) 1016 } 1017 if indirectNodes[0] != "nodeCincarnation@localhost" { 1018 t.Fatal("wrong result:", indirectNodes) 1019 } 1020 indirectNodes = nodeC.NodesIndirect() 1021 if len(indirectNodes) != 1 { 1022 t.Fatal("wrong result:", indirectNodes) 1023 } 1024 if indirectNodes[0] != "nodeAincarnation@localhost" { 1025 t.Fatal("wrong result:", indirectNodes) 1026 } 1027 if len(nodeB.NodesIndirect()) > 0 { 1028 t.Fatal("wrong result:", nodeB.NodesIndirect()) 1029 } 1030 fmt.Println("OK") 1031 1032 // use gen serv from test_monitor 1033 gsA := &testMonitor{ 1034 v: make(chan interface{}, 2), 1035 } 1036 gsB := &testMonitor{ 1037 v: make(chan interface{}, 2), 1038 } 1039 gsC := &testMonitor{ 1040 v: make(chan interface{}, 2), 1041 } 1042 fmt.Printf("... start processA on NodeA: ") 1043 pA, err := nodeA.Spawn("", gen.ProcessOptions{}, gsA) 1044 if err != nil { 1045 t.Fatal(err) 1046 } 1047 waitForResultWithValue(t, gsA.v, pA.Self()) 1048 1049 fmt.Printf("... start processB on NodeB: ") 1050 pB, err := nodeB.Spawn("", gen.ProcessOptions{}, gsB) 1051 if err != nil { 1052 t.Fatal(err) 1053 } 1054 waitForResultWithValue(t, gsB.v, pB.Self()) 1055 1056 fmt.Printf("... start processC on NodeC: ") 1057 pC, err := nodeC.Spawn("", gen.ProcessOptions{}, gsC) 1058 if err != nil { 1059 t.Fatal(err) 1060 } 1061 waitForResultWithValue(t, gsC.v, pC.Self()) 1062 1063 pidC := pC.Self() 1064 1065 fmt.Printf("... processA send a message to processC (via proxy): ") 1066 if e := pA.Send(pidC, "test"); e != nil { 1067 t.Fatal(e) 1068 } 1069 waitForResultWithValue(t, gsC.v, "test") 1070 fmt.Printf("... processB send short message to processC: ") 1071 if e := pB.Send(pidC, "test"); e != nil { 1072 t.Fatal(e) 1073 } 1074 waitForResultWithValue(t, gsC.v, "test") 1075 fmt.Printf("... restart nodeC and processC: ") 1076 nodeC.Stop() 1077 nodeC.Wait() 1078 1079 optsC.Creation = 12345 1080 nodeC, e = ergo.StartNode("nodeCincarnation@localhost", "secret", optsC) 1081 if e != nil { 1082 t.Fatal(e) 1083 } 1084 1085 if err := nodeA.Connect("nodeCincarnation@localhost"); err != nil { 1086 t.Fatal(err) 1087 } 1088 pC, err = nodeC.Spawn("", gen.ProcessOptions{}, gsC) 1089 if err != nil { 1090 t.Fatal(err) 1091 } 1092 waitForResultWithValue(t, gsC.v, pC.Self()) 1093 1094 fmt.Printf("... processA send a message to previous incarnation of processC (via proxy): ") 1095 if e := pA.Send(pidC, "test"); e != lib.ErrProcessIncarnation { 1096 t.Fatal("must be ErrProcessIncarnation here", e) 1097 } 1098 fmt.Println("OK") 1099 fmt.Printf("... processB send short message to previous incarnation of processC: ") 1100 if e := pB.Send(pidC, "test"); e != lib.ErrProcessIncarnation { 1101 t.Fatal(e) 1102 } 1103 fmt.Println("OK") 1104 1105 indirectNodes = nodeA.NodesIndirect() 1106 if len(indirectNodes) != 1 { 1107 t.Fatal("wrong result:", indirectNodes) 1108 } 1109 if indirectNodes[0] != "nodeCincarnation@localhost" { 1110 t.Fatal("wrong result:", indirectNodes) 1111 } 1112 indirectNodes = nodeC.NodesIndirect() 1113 if len(indirectNodes) != 1 { 1114 t.Fatal("wrong result:", indirectNodes) 1115 } 1116 if indirectNodes[0] != "nodeAincarnation@localhost" { 1117 t.Fatal("wrong result:", indirectNodes) 1118 } 1119 if len(nodeB.NodesIndirect()) > 0 { 1120 t.Fatal("wrong result:", nodeB.NodesIndirect()) 1121 } 1122 } 1123 1124 func BenchmarkNodeCompressionDisabled1MBempty(b *testing.B) { 1125 node1name := fmt.Sprintf("nodeB1compressionDis_%d@localhost", b.N) 1126 node2name := fmt.Sprintf("nodeB2compressionDis_%d@localhost", b.N) 1127 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1128 node2, _ := ergo.StartNode(node2name, "bench", node.Options{}) 1129 defer node1.Stop() 1130 defer node2.Stop() 1131 if err := node1.Connect(node2.Name()); err != nil { 1132 b.Fatal(err) 1133 } 1134 1135 bgs := &benchGS{} 1136 1137 var empty [1024 * 1024]byte 1138 b.SetParallelism(15) 1139 b.RunParallel(func(pb *testing.PB) { 1140 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1141 if e1 != nil { 1142 b.Fatal(e1) 1143 } 1144 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1145 if e2 != nil { 1146 b.Fatal(e2) 1147 } 1148 b.ResetTimer() 1149 for pb.Next() { 1150 call := makeCall{ 1151 to: p2.Self(), 1152 message: empty, 1153 } 1154 _, e := p1.DirectWithTimeout(call, 30) 1155 if e != nil { 1156 b.Fatal(e) 1157 } 1158 } 1159 1160 }) 1161 } 1162 func BenchmarkNodeCompressionEnabled1MBempty(b *testing.B) { 1163 node1name := fmt.Sprintf("nodeB1compressionEn_%d@localhost", b.N) 1164 node2name := fmt.Sprintf("nodeB2compressionEn_%d@localhost", b.N) 1165 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1166 node2, _ := ergo.StartNode(node2name, "bench", node.Options{}) 1167 defer node1.Stop() 1168 defer node2.Stop() 1169 if err := node1.Connect(node2.Name()); err != nil { 1170 b.Fatal(err) 1171 } 1172 1173 bgs := &benchGS{} 1174 1175 var empty [1024 * 1024]byte 1176 //b.SetParallelism(15) 1177 b.RunParallel(func(pb *testing.PB) { 1178 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1179 if e1 != nil { 1180 b.Fatal(e1) 1181 } 1182 p1.SetCompression(true) 1183 p1.SetCompressionLevel(5) 1184 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1185 if e2 != nil { 1186 b.Fatal(e2) 1187 } 1188 b.ResetTimer() 1189 for pb.Next() { 1190 call := makeCall{ 1191 to: p2.Self(), 1192 message: empty, 1193 } 1194 _, e := p1.DirectWithTimeout(call, 30) 1195 if e != nil { 1196 b.Fatal(e) 1197 } 1198 } 1199 1200 }) 1201 } 1202 1203 func BenchmarkNodeCompressionEnabled1MBstring(b *testing.B) { 1204 node1name := fmt.Sprintf("nodeB1compressionEnStr_%d@localhost", b.N) 1205 node2name := fmt.Sprintf("nodeB2compressionEnStr_%d@localhost", b.N) 1206 node1, e := ergo.StartNode(node1name, "bench", node.Options{}) 1207 if e != nil { 1208 b.Fatal(e) 1209 } 1210 node2, e := ergo.StartNode(node2name, "bench", node.Options{}) 1211 if e != nil { 1212 b.Fatal(e) 1213 } 1214 defer node1.Stop() 1215 defer node2.Stop() 1216 if err := node1.Connect(node2.Name()); err != nil { 1217 b.Fatal(err) 1218 } 1219 1220 bgs := &benchGS{} 1221 1222 randomString := []byte(lib.RandomString(1024 * 1024)) 1223 b.SetParallelism(15) 1224 b.RunParallel(func(pb *testing.PB) { 1225 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1226 if e1 != nil { 1227 b.Fatal(e1) 1228 } 1229 p1.SetCompression(true) 1230 p1.SetCompressionLevel(5) 1231 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1232 if e2 != nil { 1233 b.Fatal(e2) 1234 } 1235 b.ResetTimer() 1236 for pb.Next() { 1237 call := makeCall{ 1238 to: p2.Self(), 1239 message: randomString, 1240 } 1241 _, e := p1.DirectWithTimeout(call, 30) 1242 if e != nil { 1243 b.Fatal(e) 1244 } 1245 } 1246 1247 }) 1248 } 1249 1250 type benchGS struct { 1251 gen.Server 1252 } 1253 1254 func (b *benchGS) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 1255 return etf.Atom("ok"), gen.ServerStatusOK 1256 } 1257 func (b *benchGS) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 1258 switch m := message.(type) { 1259 case makeCall: 1260 return process.CallWithTimeout(m.to, m.message, 30) 1261 } 1262 return nil, lib.ErrUnsupportedRequest 1263 } 1264 1265 func BenchmarkNodeSequentialNetwork(b *testing.B) { 1266 1267 node1name := fmt.Sprintf("nodeB1_%d@localhost", b.N) 1268 node2name := fmt.Sprintf("nodeB2_%d@localhost", b.N) 1269 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1270 node2, _ := ergo.StartNode(node2name, "bench", node.Options{}) 1271 1272 bgs := &benchGS{} 1273 1274 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1275 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1276 1277 if e1 != nil { 1278 b.Fatal(e1) 1279 } 1280 if e2 != nil { 1281 b.Fatal(e2) 1282 } 1283 1284 call := makeCall{ 1285 to: p2.Self(), 1286 message: 1, 1287 } 1288 if _, e := p1.Direct(call); e != nil { 1289 b.Fatal("single ping", e) 1290 } 1291 1292 b.ResetTimer() 1293 for _, c := range benchCases() { 1294 b.Run(c.name, func(b *testing.B) { 1295 for i := 0; i < b.N; i++ { 1296 call := makeCall{ 1297 to: p2.Self(), 1298 message: c.value, 1299 } 1300 _, e := p1.Direct(call) 1301 if e != nil { 1302 b.Fatal(e, i) 1303 } 1304 } 1305 }) 1306 } 1307 } 1308 1309 func BenchmarkNodeSequentialLocal(b *testing.B) { 1310 1311 node1name := fmt.Sprintf("nodeB1Local_%d@localhost", b.N) 1312 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1313 1314 bgs := &benchGS{} 1315 1316 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1317 p2, e2 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1318 1319 if e1 != nil { 1320 b.Fatal(e1) 1321 } 1322 if e2 != nil { 1323 b.Fatal(e2) 1324 } 1325 1326 call := makeCall{ 1327 to: p2.Self(), 1328 message: 1, 1329 } 1330 if _, e := p1.Direct(call); e != nil { 1331 b.Fatal("single ping", e) 1332 } 1333 1334 b.ResetTimer() 1335 for _, c := range benchCases() { 1336 b.Run(c.name, func(b *testing.B) { 1337 for i := 0; i < b.N; i++ { 1338 call := makeCall{ 1339 to: p2.Self(), 1340 message: c.value, 1341 } 1342 _, e := p1.Direct(call) 1343 if e != nil { 1344 b.Fatal(e, i) 1345 } 1346 } 1347 }) 1348 } 1349 } 1350 1351 func BenchmarkNodeParallel(b *testing.B) { 1352 1353 node1name := fmt.Sprintf("nodeB1Parallel_%d@localhost", b.N) 1354 node2name := fmt.Sprintf("nodeB2Parallel_%d@localhost", b.N) 1355 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1356 node2, _ := ergo.StartNode(node2name, "bench", node.Options{}) 1357 1358 bgs := &benchGS{} 1359 1360 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1361 if e1 != nil { 1362 b.Fatal(e1) 1363 } 1364 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1365 if e2 != nil { 1366 b.Fatal(e2) 1367 } 1368 1369 call := makeCall{ 1370 to: p2.Self(), 1371 message: "hi", 1372 } 1373 if _, e := p1.Direct(call); e != nil { 1374 b.Fatal("single ping", e) 1375 } 1376 1377 b.SetParallelism(15) 1378 b.RunParallel(func(pb *testing.PB) { 1379 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1380 if e1 != nil { 1381 b.Fatal(e1) 1382 } 1383 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1384 if e2 != nil { 1385 b.Fatal(e2) 1386 } 1387 b.ResetTimer() 1388 for pb.Next() { 1389 call := makeCall{ 1390 to: p2.Self(), 1391 message: etf.Atom("ping"), 1392 } 1393 _, e := p1.Direct(call) 1394 if e != nil { 1395 b.Fatal(e) 1396 } 1397 } 1398 1399 }) 1400 } 1401 1402 func BenchmarkNodeParallelSingleNode(b *testing.B) { 1403 1404 node1name := fmt.Sprintf("nodeB1ParallelLocal_%d@localhost", b.N) 1405 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1406 1407 bgs := &benchGS{} 1408 1409 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1410 if e1 != nil { 1411 b.Fatal(e1) 1412 } 1413 p2, e2 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1414 if e2 != nil { 1415 b.Fatal(e2) 1416 } 1417 1418 call := makeCall{ 1419 to: p2.Self(), 1420 message: "hi", 1421 } 1422 if _, e := p1.Direct(call); e != nil { 1423 b.Fatal("single ping", e) 1424 } 1425 b.SetParallelism(15) 1426 b.RunParallel(func(pb *testing.PB) { 1427 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1428 if e1 != nil { 1429 b.Fatal(e1) 1430 } 1431 p2, e2 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1432 if e2 != nil { 1433 b.Fatal(e2) 1434 } 1435 b.ResetTimer() 1436 for pb.Next() { 1437 call := makeCall{ 1438 to: p2.Self(), 1439 message: etf.Atom("ping"), 1440 } 1441 _, e := p1.Direct(call) 1442 if e != nil { 1443 b.Fatal(e) 1444 } 1445 } 1446 1447 }) 1448 } 1449 1450 func BenchmarkNodeProxy_NodeA_to_NodeC_direct_Message_1K(b *testing.B) { 1451 node1name := fmt.Sprintf("nodeB1ProxyDisabled%d@localhost", b.N) 1452 node2name := fmt.Sprintf("nodeB2ProxyDisabled%d@localhost", b.N) 1453 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1454 node2, _ := ergo.StartNode(node2name, "bench", node.Options{}) 1455 defer node1.Stop() 1456 defer node2.Stop() 1457 1458 bgs := &benchGS{} 1459 1460 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1461 if e1 != nil { 1462 b.Fatal(e1) 1463 } 1464 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1465 if e2 != nil { 1466 b.Fatal(e2) 1467 } 1468 1469 call := makeCall{ 1470 to: p2.Self(), 1471 message: "hi", 1472 } 1473 if _, e := p1.Direct(call); e != nil { 1474 b.Fatal("single ping", e) 1475 } 1476 1477 randomString := []byte(lib.RandomString(1024)) 1478 b.SetParallelism(15) 1479 b.RunParallel(func(pb *testing.PB) { 1480 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1481 if e1 != nil { 1482 b.Fatal(e1) 1483 } 1484 p2, e2 := node2.Spawn("", gen.ProcessOptions{}, bgs) 1485 if e2 != nil { 1486 b.Fatal(e2) 1487 } 1488 b.ResetTimer() 1489 for pb.Next() { 1490 call := makeCall{ 1491 to: p2.Self(), 1492 message: randomString, 1493 } 1494 _, e := p1.Direct(call) 1495 if e != nil { 1496 b.Fatal(e) 1497 } 1498 } 1499 1500 }) 1501 } 1502 func BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1K(b *testing.B) { 1503 node1name := fmt.Sprintf("nodeB1ProxyEnabled1K%d@localhost", b.N) 1504 node2name := fmt.Sprintf("nodeB2ProxyEnabled1K%d@localhost", b.N) 1505 node3name := fmt.Sprintf("nodeB3ProxyEnabled1K%d@localhost", b.N) 1506 node1, _ := ergo.StartNode(node1name, "bench", node.Options{}) 1507 opts2 := node.Options{} 1508 opts2.Proxy.Transit = true 1509 node2, _ := ergo.StartNode(node2name, "bench", opts2) 1510 node3, _ := ergo.StartNode(node3name, "bench", node.Options{}) 1511 defer node1.Stop() 1512 defer node2.Stop() 1513 defer node3.Stop() 1514 route := node.ProxyRoute{ 1515 Name: node3.Name(), 1516 Proxy: node2.Name(), 1517 } 1518 node1.AddProxyRoute(route) 1519 1520 bgs := &benchGS{} 1521 1522 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1523 if e1 != nil { 1524 b.Fatal(e1) 1525 } 1526 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1527 if e3 != nil { 1528 b.Fatal(e3) 1529 } 1530 1531 call := makeCall{ 1532 to: p3.Self(), 1533 message: "hi", 1534 } 1535 if _, e := p1.Direct(call); e != nil { 1536 b.Fatal("single ping", e) 1537 } 1538 1539 randomString := []byte(lib.RandomString(1024)) 1540 b.SetParallelism(15) 1541 b.RunParallel(func(pb *testing.PB) { 1542 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1543 if e1 != nil { 1544 b.Fatal(e1) 1545 } 1546 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1547 if e3 != nil { 1548 b.Fatal(e3) 1549 } 1550 b.ResetTimer() 1551 for pb.Next() { 1552 call := makeCall{ 1553 to: p3.Self(), 1554 message: randomString, 1555 } 1556 _, e := p1.Direct(call) 1557 if e != nil { 1558 b.Fatal(e) 1559 } 1560 } 1561 1562 }) 1563 } 1564 1565 func BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1K_Encrypted(b *testing.B) { 1566 node1name := fmt.Sprintf("nodeB1ProxyEnabled1K%d@localhost", b.N) 1567 node2name := fmt.Sprintf("nodeB2ProxyEnabled1K%d@localhost", b.N) 1568 node3name := fmt.Sprintf("nodeB3ProxyEnabled1K%d@localhost", b.N) 1569 opts1 := node.Options{} 1570 opts1.Proxy.Flags = node.DefaultProxyFlags() 1571 opts1.Proxy.Flags.EnableEncryption = true 1572 node1, _ := ergo.StartNode(node1name, "bench", opts1) 1573 opts2 := node.Options{} 1574 opts2.Proxy.Transit = true 1575 node2, _ := ergo.StartNode(node2name, "bench", opts2) 1576 node3, _ := ergo.StartNode(node3name, "bench", node.Options{}) 1577 defer node1.Stop() 1578 defer node2.Stop() 1579 defer node3.Stop() 1580 route := node.ProxyRoute{ 1581 Name: node3.Name(), 1582 Proxy: node2.Name(), 1583 } 1584 node1.AddProxyRoute(route) 1585 1586 bgs := &benchGS{} 1587 1588 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1589 if e1 != nil { 1590 b.Fatal(e1) 1591 } 1592 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1593 if e3 != nil { 1594 b.Fatal(e3) 1595 } 1596 1597 call := makeCall{ 1598 to: p3.Self(), 1599 message: "hi", 1600 } 1601 if _, e := p1.Direct(call); e != nil { 1602 b.Fatal("single ping", e) 1603 } 1604 1605 randomString := []byte(lib.RandomString(1024)) 1606 b.SetParallelism(15) 1607 b.RunParallel(func(pb *testing.PB) { 1608 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1609 if e1 != nil { 1610 b.Fatal(e1) 1611 } 1612 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1613 if e3 != nil { 1614 b.Fatal(e3) 1615 } 1616 b.ResetTimer() 1617 for pb.Next() { 1618 call := makeCall{ 1619 to: p3.Self(), 1620 message: randomString, 1621 } 1622 _, e := p1.Direct(call) 1623 if e != nil { 1624 b.Fatal(e) 1625 } 1626 } 1627 1628 }) 1629 } 1630 1631 func BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1M_Compressed(b *testing.B) { 1632 node1name := fmt.Sprintf("nodeB1ProxyEnabled1K%d@localhost", b.N) 1633 node2name := fmt.Sprintf("nodeB2ProxyEnabled1K%d@localhost", b.N) 1634 node3name := fmt.Sprintf("nodeB3ProxyEnabled1K%d@localhost", b.N) 1635 opts1 := node.Options{} 1636 opts1.Proxy.Flags = node.DefaultProxyFlags() 1637 opts1.Proxy.Flags.EnableEncryption = false 1638 node1, _ := ergo.StartNode(node1name, "bench", opts1) 1639 opts2 := node.Options{} 1640 opts2.Proxy.Transit = true 1641 node2, _ := ergo.StartNode(node2name, "bench", opts2) 1642 node3, _ := ergo.StartNode(node3name, "bench", node.Options{}) 1643 defer node1.Stop() 1644 defer node2.Stop() 1645 defer node3.Stop() 1646 route := node.ProxyRoute{ 1647 Name: node3.Name(), 1648 Proxy: node2.Name(), 1649 } 1650 node1.AddProxyRoute(route) 1651 1652 bgs := &benchGS{} 1653 1654 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1655 if e1 != nil { 1656 b.Fatal(e1) 1657 } 1658 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1659 if e3 != nil { 1660 b.Fatal(e3) 1661 } 1662 1663 call := makeCall{ 1664 to: p3.Self(), 1665 message: "hi", 1666 } 1667 if _, e := p1.Direct(call); e != nil { 1668 b.Fatal("single ping", e) 1669 } 1670 1671 randomString := []byte(lib.RandomString(1024 * 1024)) 1672 b.SetParallelism(15) 1673 b.RunParallel(func(pb *testing.PB) { 1674 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1675 if e1 != nil { 1676 b.Fatal(e1) 1677 } 1678 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1679 if e3 != nil { 1680 b.Fatal(e3) 1681 } 1682 b.ResetTimer() 1683 for pb.Next() { 1684 call := makeCall{ 1685 to: p3.Self(), 1686 message: randomString, 1687 } 1688 _, e := p1.Direct(call) 1689 if e != nil { 1690 b.Fatal(e) 1691 } 1692 } 1693 1694 }) 1695 } 1696 1697 func BenchmarkNodeProxy_NodeA_to_NodeC_via_NodeB_Message_1M_CompressedEncrypted(b *testing.B) { 1698 node1name := fmt.Sprintf("nodeB1ProxyEnabled1K%d@localhost", b.N) 1699 node2name := fmt.Sprintf("nodeB2ProxyEnabled1K%d@localhost", b.N) 1700 node3name := fmt.Sprintf("nodeB3ProxyEnabled1K%d@localhost", b.N) 1701 opts1 := node.Options{} 1702 opts1.Proxy.Flags = node.DefaultProxyFlags() 1703 opts1.Proxy.Flags.EnableEncryption = true 1704 node1, _ := ergo.StartNode(node1name, "bench", opts1) 1705 opts2 := node.Options{} 1706 opts2.Proxy.Transit = true 1707 node2, _ := ergo.StartNode(node2name, "bench", opts2) 1708 node3, _ := ergo.StartNode(node3name, "bench", node.Options{}) 1709 defer node1.Stop() 1710 defer node2.Stop() 1711 defer node3.Stop() 1712 route := node.ProxyRoute{ 1713 Name: node3.Name(), 1714 Proxy: node2.Name(), 1715 } 1716 node1.AddProxyRoute(route) 1717 1718 bgs := &benchGS{} 1719 1720 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1721 if e1 != nil { 1722 b.Fatal(e1) 1723 } 1724 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1725 if e3 != nil { 1726 b.Fatal(e3) 1727 } 1728 1729 call := makeCall{ 1730 to: p3.Self(), 1731 message: "hi", 1732 } 1733 if _, e := p1.Direct(call); e != nil { 1734 b.Fatal("single ping", e) 1735 } 1736 1737 randomString := []byte(lib.RandomString(1024 * 1024)) 1738 b.SetParallelism(15) 1739 b.RunParallel(func(pb *testing.PB) { 1740 p1, e1 := node1.Spawn("", gen.ProcessOptions{}, bgs) 1741 if e1 != nil { 1742 b.Fatal(e1) 1743 } 1744 p1.SetCompression(true) 1745 p3, e3 := node3.Spawn("", gen.ProcessOptions{}, bgs) 1746 if e3 != nil { 1747 b.Fatal(e3) 1748 } 1749 b.ResetTimer() 1750 for pb.Next() { 1751 call := makeCall{ 1752 to: p3.Self(), 1753 message: randomString, 1754 } 1755 _, e := p1.Direct(call) 1756 if e != nil { 1757 b.Fatal(e) 1758 } 1759 } 1760 1761 }) 1762 } 1763 1764 func benchCases() []benchCase { 1765 return []benchCase{ 1766 {"number", 12345}, 1767 {"string", "hello world"}, 1768 {"tuple (PID)", 1769 etf.Pid{ 1770 Node: "node@localhost", 1771 ID: 1000, 1772 Creation: 1, 1773 }, 1774 }, 1775 {"binary 1MB", make([]byte, 1024*1024)}, 1776 } 1777 }