github.com/ergo-services/ergo@v1.999.224/tests/monitor_test.go (about) 1 package tests 2 3 import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "testing" 8 9 "github.com/ergo-services/ergo" 10 "github.com/ergo-services/ergo/etf" 11 "github.com/ergo-services/ergo/gen" 12 "github.com/ergo-services/ergo/lib" 13 "github.com/ergo-services/ergo/node" 14 ) 15 16 type testMonitor struct { 17 gen.Server 18 v chan interface{} 19 } 20 21 func (tgs *testMonitor) Init(process *gen.ServerProcess, args ...etf.Term) error { 22 tgs.v <- process.Self() 23 return nil 24 } 25 func (tgs *testMonitor) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 26 tgs.v <- message 27 return gen.ServerStatusOK 28 } 29 func (tgs *testMonitor) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) { 30 return message, gen.ServerStatusOK 31 } 32 func (tgs *testMonitor) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 33 tgs.v <- message 34 return gen.ServerStatusOK 35 } 36 37 /* 38 Test cases for Local-Local 39 Monitor 40 by Pid - doesnt_exist, terminate, demonitor 41 by Name - doesnt_exist, terminate, demonitor 42 by Tuple - doesnt_exist, terminate, demonitor 43 */ 44 func TestMonitorLocalLocal(t *testing.T) { 45 fmt.Printf("\n=== Test Monitor Local-Local\n") 46 fmt.Printf("Starting node: nodeM1LocalLocal@localhost: ") 47 node1, _ := ergo.StartNode("nodeM1LocalLocal@localhost", "cookies", node.Options{}) 48 if node1 == nil { 49 t.Fatal("can't start node") 50 } 51 fmt.Println("OK") 52 gs1 := &testMonitor{ 53 v: make(chan interface{}, 2), 54 } 55 gs2 := &testMonitor{ 56 v: make(chan interface{}, 2), 57 } 58 // starting gen servers 59 60 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 61 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 62 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 63 64 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 65 node1gs2, _ := node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 66 waitForResultWithValue(t, gs2.v, node1gs2.Self()) 67 68 // by Pid 69 fmt.Printf("... by Pid Local-Local: gs1 -> gs2. monitor/demonitor: ") 70 ref := node1gs1.MonitorProcess(node1gs2.Self()) 71 72 if !node1gs2.IsMonitor(ref) { 73 t.Fatal("monitor reference has been lost") 74 } 75 node1gs1.DemonitorProcess(ref) 76 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 77 t.Fatal(err) 78 } 79 fmt.Println("OK") 80 81 fmt.Printf("... by Pid Local-Local: gs1 -> gs2. monitor/terminate: ") 82 ref = node1gs1.MonitorProcess(node1gs2.Self()) 83 node1gs2.Exit("normal") 84 result := gen.MessageDown{ 85 Ref: ref, 86 Pid: node1gs2.Self(), 87 Reason: "normal", 88 } 89 waitForResultWithValue(t, gs1.v, result) 90 91 if err := checkCleanProcessRef(node1gs2, ref); err != nil { 92 t.Fatal(err) 93 } 94 95 fmt.Print("... by Pid Local-Local: gs1 -> monitor unknownPid: ") 96 ref = node1gs1.MonitorProcess(node1gs2.Self()) 97 result = gen.MessageDown{ 98 Ref: ref, 99 Pid: node1gs2.Self(), 100 Reason: "noproc", 101 } 102 waitForResultWithValue(t, gs1.v, result) 103 104 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 105 node1gs2, _ = node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 106 waitForResultWithValue(t, gs2.v, node1gs2.Self()) 107 // by Name 108 fmt.Printf("... by Name Local-Local: gs1 -> gs2. monitor/demonitor: ") 109 ref = node1gs1.MonitorProcess("gs2") 110 if err := checkCleanProcessRef(node1gs1, ref); err == nil { 111 t.Fatal("monitor reference has been lost") 112 } 113 node1gs1.DemonitorProcess(ref) 114 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 115 t.Fatal(err) 116 } 117 fmt.Println("OK") 118 119 fmt.Printf("... by Name Local-Local: gs1 -> gs2. monitor/terminate: ") 120 ref = node1gs1.MonitorProcess("gs2") 121 node1gs2.Exit("normal") 122 result = gen.MessageDown{ 123 Ref: ref, 124 ProcessID: gen.ProcessID{Name: "gs2", Node: node1.Name()}, 125 Reason: "normal", 126 } 127 waitForResultWithValue(t, gs1.v, result) 128 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 129 t.Fatal(err) 130 } 131 fmt.Print("... by Name Local-Local: gs1 -> monitor unknown name: ") 132 ref = node1gs1.MonitorProcess("asdfasdf") 133 result = gen.MessageDown{ 134 Ref: ref, 135 ProcessID: gen.ProcessID{Name: "asdfasdf", Node: node1.Name()}, 136 Reason: "noproc", 137 } 138 waitForResultWithValue(t, gs1.v, result) 139 140 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 141 node1gs2, _ = node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 142 waitForResultWithValue(t, gs2.v, node1gs2.Self()) 143 144 // by Name gen.ProcessID{ProcessName, Node} 145 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Local: gs1 -> gs2. demonitor: ") 146 processID := gen.ProcessID{Name: "gs2", Node: node1.Name()} 147 ref = node1gs1.MonitorProcess(processID) 148 if err := checkCleanProcessRef(node1gs1, ref); err == nil { 149 t.Fatal("monitor reference has been lost") 150 } 151 node1gs1.DemonitorProcess(ref) 152 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 153 t.Fatal(err) 154 } 155 fmt.Println("OK") 156 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Local: gs1 -> gs2. terminate: ") 157 ref = node1gs1.MonitorProcess(processID) 158 node1gs2.Exit("normal") 159 result = gen.MessageDown{ 160 Ref: ref, 161 ProcessID: processID, 162 Reason: "normal", 163 } 164 waitForResultWithValue(t, gs1.v, result) 165 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 166 t.Fatal(err) 167 } 168 fmt.Print("... by gen.ProcessID{Name, Node} Local-Local: gs1 -> unknownPid: ") 169 processID = gen.ProcessID{Name: "gs2222", Node: node1.Name()} 170 ref = node1gs1.MonitorProcess(processID) 171 result = gen.MessageDown{ 172 Ref: ref, 173 ProcessID: processID, 174 Reason: "noproc", 175 } 176 waitForResultWithValue(t, gs1.v, result) 177 178 node1.Stop() 179 } 180 181 /* 182 Test cases for Local-Remote 183 Monitor 184 by Pid - doesnt_exist, terminate, demonitor, on_node_down, node_unknown 185 by Tuple - doesnt_exist, terminate, demonitor, on_node_down, node_unknown 186 Link 187 by Pid - doesnt_exist, terminate, unlink, node_down, node_unknown 188 */ 189 190 func TestMonitorLocalRemoteByPid(t *testing.T) { 191 fmt.Printf("\n=== Test Monitor Local-Remote by Pid\n") 192 fmt.Printf("Starting nodes: nodeM1LocalRemoteByPid@localhost, nodeM2LocalRemoteByPid@localhost: ") 193 node1, err1 := ergo.StartNode("nodeM1LocalRemoteByPid@localhost", "cookies", node.Options{}) 194 node2, err2 := ergo.StartNode("nodeM2LocalRemoteByPid@localhost", "cookies", node.Options{}) 195 if err1 != nil { 196 t.Fatal("can't start node1:", err1) 197 } 198 if err2 != nil { 199 t.Fatal("can't start node2:", err2) 200 } 201 202 fmt.Println("OK") 203 204 gs1 := &testMonitor{ 205 v: make(chan interface{}, 2), 206 } 207 gs2 := &testMonitor{ 208 v: make(chan interface{}, 2), 209 } 210 211 // starting gen servers 212 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 213 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 214 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 215 216 fmt.Printf(" wait for start of gs2 on %#v: ", node2.Name()) 217 node2gs2, _ := node2.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 218 waitForResultWithValue(t, gs2.v, node2gs2.Self()) 219 220 // by Pid 221 fmt.Printf("... by Pid Local-Remote: gs1 -> gs2. monitor/demonitor: ") 222 ref := node1gs1.MonitorProcess(node2gs2.Self()) 223 // wait a bit for the MessageDown if something went wrong 224 waitForTimeout(t, gs1.v) 225 if node1gs1.IsMonitor(ref) == false { 226 t.Fatal("monitor reference has been lost on node 1") 227 } 228 if node2gs2.IsMonitor(ref) == false { 229 t.Fatal("monitor reference has been lost on node 2") 230 } 231 if found := node1gs1.DemonitorProcess(ref); found == false { 232 t.Fatal("lost monitoring reference on node1") 233 } 234 // Demonitoring is the async message with nothing as a feedback. 235 // use waitForTimeout just as a short timer 236 waitForTimeout(t, gs1.v) 237 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 238 t.Fatal(err) 239 } 240 if err := checkCleanProcessRef(node2gs2, ref); err != nil { 241 t.Fatal(err) 242 } 243 fmt.Println("OK") 244 245 fmt.Printf("... by Pid Local-Remote: gs1 -> gs2. monitor/terminate: ") 246 ref = node1gs1.MonitorProcess(node2gs2.Self()) 247 // wait a bit for the MessageDown if something went wrong 248 waitForTimeout(t, gs1.v) 249 node2gs2.Exit("normal") 250 result := gen.MessageDown{ 251 Ref: ref, 252 Pid: node2gs2.Self(), 253 Reason: "normal", 254 } 255 waitForResultWithValue(t, gs1.v, result) 256 257 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 258 t.Fatal(err) 259 } 260 if err := checkCleanProcessRef(node2gs2, ref); err != nil { 261 t.Fatal(err) 262 } 263 264 fmt.Printf("... by Pid Local-Remote: gs1 -> monitor unknownPid: ") 265 ref = node1gs1.MonitorProcess(node2gs2.Self()) 266 result = gen.MessageDown{ 267 Ref: ref, 268 Pid: node2gs2.Self(), 269 Reason: "noproc", 270 } 271 waitForResultWithValue(t, gs1.v, result) 272 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 273 t.Fatal(err) 274 } 275 276 fmt.Printf(" wait for start of gs2 on %#v: ", node2.Name()) 277 node2gs2, _ = node2.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 278 waitForResultWithValue(t, gs2.v, node2gs2.Self()) 279 280 fmt.Printf("... by Pid Local-Remote: gs1 -> gs2. monitor/NodeDown: ") 281 ref = node1gs1.MonitorProcess(node2gs2.Self()) 282 // wait a bit for the MessageDown if something went wrong 283 waitForTimeout(t, gs1.v) 284 node1.Disconnect(node2.Name()) 285 node2.Stop() 286 result = gen.MessageDown{ 287 Ref: ref, 288 Pid: node2gs2.Self(), 289 Reason: "noconnection", 290 } 291 waitForResultWithValue(t, gs1.v, result) 292 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 293 t.Fatal(err) 294 } 295 296 fmt.Printf("... by Pid Local-Remote: gs1 -> gs2. monitor unknown node: ") 297 ref = node1gs1.MonitorProcess(node2gs2.Self()) 298 result.Ref = ref 299 waitForResultWithValue(t, gs1.v, result) 300 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 301 t.Fatal(err) 302 } 303 node1.Stop() 304 } 305 306 func TestMonitorLocalRemoteByName(t *testing.T) { 307 fmt.Printf("\n=== Test Monitor Local-Remote by Name\n") 308 fmt.Printf("Starting nodes: nodeM1LocalRemoteByTuple@localhost, nodeM2LocalRemoteByTuple@localhost: ") 309 node1, _ := ergo.StartNode("nodeM1LocalRemoteByTuple@localhost", "cookies", node.Options{}) 310 node2, _ := ergo.StartNode("nodeM2LocalRemoteByTuple@localhost", "cookies", node.Options{}) 311 if node1 == nil || node2 == nil { 312 t.Fatal("can't start nodes") 313 } else { 314 fmt.Println("OK") 315 } 316 317 gs1 := &testMonitor{ 318 v: make(chan interface{}, 2), 319 } 320 gs2 := &testMonitor{ 321 v: make(chan interface{}, 2), 322 } 323 324 // starting gen servers 325 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 326 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 327 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 328 329 fmt.Printf(" wait for start of gs2 on %#v: ", node2.Name()) 330 node2gs2, _ := node2.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 331 waitForResultWithValue(t, gs2.v, node2gs2.Self()) 332 333 processID := gen.ProcessID{Name: "gs2", Node: node2.Name()} 334 335 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Remote: gs1 -> gs2. monitor/demonitor: ") 336 ref := node1gs1.MonitorProcess(processID) 337 // wait a bit for the MessageDown if something went wrong 338 waitForTimeout(t, gs1.v) 339 if err := checkCleanProcessRef(node1gs1, ref); err == nil { 340 t.Fatal("monitor reference has been lost on node 1") 341 } 342 if err := checkCleanProcessRef(node2gs2, ref); err == nil { 343 t.Fatal("monitor reference has been lost on node 2") 344 } 345 if found := node1gs1.DemonitorProcess(ref); found == false { 346 t.Fatal("lost monitoring reference on node1") 347 } 348 // Demonitoring is the async message with nothing as a feedback. 349 // use waitForTimeout just as a short timer 350 waitForTimeout(t, gs1.v) 351 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 352 t.Fatal(err) 353 } 354 if err := checkCleanProcessRef(node2gs2, ref); err != nil { 355 t.Fatal(err) 356 } 357 fmt.Println("OK") 358 359 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Remote: gs1 -> gs2. monitor/terminate: ") 360 ref = node1gs1.MonitorProcess(processID) 361 // wait a bit for the MessageDown if something went wrong 362 waitForTimeout(t, gs1.v) 363 node2gs2.Exit("normal") 364 result := gen.MessageDown{ 365 Ref: ref, 366 ProcessID: processID, 367 Reason: "normal", 368 } 369 waitForResultWithValue(t, gs1.v, result) 370 371 if node1gs1.IsMonitor(ref) { 372 t.Fatal("monitor ref is still alive") 373 } 374 if node2gs2.IsMonitor(ref) { 375 t.Fatal("monitor ref is still alive") 376 } 377 378 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Remote: gs1 -> monitor unknown remote name: ") 379 ref = node1gs1.MonitorProcess(processID) 380 result = gen.MessageDown{ 381 Ref: ref, 382 ProcessID: processID, 383 Reason: "noproc", 384 } 385 waitForResultWithValue(t, gs1.v, result) 386 if node1gs1.IsMonitor(ref) { 387 t.Fatal("monitor ref is still alive") 388 } 389 390 fmt.Printf(" wait for start of gs2 on %#v: ", node2.Name()) 391 node2gs2, _ = node2.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 392 waitForResultWithValue(t, gs2.v, node2gs2.Self()) 393 394 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Remote: gs1 -> gs2. monitor/onNodeDown: ") 395 ref = node1gs1.MonitorProcess(processID) 396 node1.Disconnect(node2.Name()) 397 node2.Stop() 398 result = gen.MessageDown{ 399 Ref: ref, 400 ProcessID: processID, 401 Reason: "noconnection", 402 } 403 waitForResultWithValue(t, gs1.v, result) 404 if node1gs1.IsMonitor(ref) { 405 t.Fatal("monitor ref is still alive") 406 } 407 408 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Remote: gs1 -> gs2. monitor unknown node: ") 409 ref = node1gs1.MonitorProcess(processID) 410 result.Ref = ref 411 waitForResultWithValue(t, gs1.v, result) 412 if node1gs1.IsMonitor(ref) { 413 t.Fatal("monitor ref is still alive") 414 } 415 node1.Stop() 416 } 417 418 func TestMonitorLocalProxyRemoteByPid(t *testing.T) { 419 fmt.Printf("\n=== Test Monitor Remote via Proxy by Pid\n") 420 fmt.Printf("Starting nodes: nodeM1ProxyRemoteByPid@localhost, nodeM2ProxyRemoteByPid@localhost, nodeM3ProxyRemoteByPid@localhost : ") 421 opts1 := node.Options{} 422 opts1.Proxy.Flags = node.DefaultProxyFlags() 423 opts1.Proxy.Flags.EnableMonitor = false 424 node1, err := ergo.StartNode("nodeM1ProxyRemoteByPid@localhost", "cookies", opts1) 425 if err != nil { 426 t.Fatal("can't start node:", err) 427 } 428 opts2 := node.Options{} 429 opts2.Proxy.Transit = true 430 node2, err := ergo.StartNode("nodeM2ProxyRemoteByPid@localhost", "cookies", opts2) 431 if err != nil { 432 t.Fatal("can't start node:", err, node2.Name()) 433 } 434 opts3 := node.Options{} 435 opts3.Proxy.Accept = true 436 node3, err := ergo.StartNode("nodeM3ProxyRemoteByPid@localhost", "cookies", opts3) 437 if err != nil { 438 t.Fatal("can't start node:", err) 439 } 440 441 route := node.ProxyRoute{ 442 Name: node3.Name(), 443 Proxy: node2.Name(), 444 } 445 node1.AddProxyRoute(route) 446 node1.Connect(node3.Name()) 447 fmt.Println("OK") 448 449 gs1 := &testMonitor{ 450 v: make(chan interface{}, 2), 451 } 452 gs3 := &testMonitor{ 453 v: make(chan interface{}, 2), 454 } 455 456 // starting gen servers 457 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 458 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 459 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 460 461 fmt.Printf(" wait for start of gs3 on %#v: ", node3.Name()) 462 node3gs3, _ := node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 463 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 464 465 // by Pid 466 fmt.Printf("... by Pid Local-Proxy-Remote: gs1 -> gs3. monitor/demonitor: ") 467 ref := node1gs1.MonitorProcess(node3gs3.Self()) 468 // wait a bit for the MessageDown if something went wrong 469 waitForTimeout(t, gs1.v) 470 if node1gs1.IsMonitor(ref) == false { 471 t.Fatal("monitor reference has been lost on node 1") 472 } 473 if node3gs3.IsMonitor(ref) == false { 474 t.Fatal("monitor reference has been lost on node 3") 475 } 476 if found := node1gs1.DemonitorProcess(ref); found == false { 477 t.Fatal("lost monitoring reference on node1") 478 } 479 // Demonitoring is the async message with nothing as a feedback. 480 // use waitForTimeout just as a short timer 481 waitForTimeout(t, gs1.v) 482 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 483 t.Fatal(err) 484 } 485 if err := checkCleanProcessRef(node3gs3, ref); err != nil { 486 t.Fatal(err) 487 } 488 fmt.Println("OK") 489 490 fmt.Printf("... by Pid Local-Proxy-Remote: gs1 -> gs3. monitor/terminate: ") 491 ref = node1gs1.MonitorProcess(node3gs3.Self()) 492 // wait a bit for the MessageDown if something went wrong 493 waitForTimeout(t, gs1.v) 494 node3gs3.Exit("normal") 495 result := gen.MessageDown{ 496 Ref: ref, 497 Pid: node3gs3.Self(), 498 Reason: "normal", 499 } 500 waitForResultWithValue(t, gs1.v, result) 501 502 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 503 t.Fatal(err) 504 } 505 if err := checkCleanProcessRef(node3gs3, ref); err != nil { 506 t.Fatal(err) 507 } 508 509 fmt.Printf("... by Pid Local-Proxy-Remote: gs1 -> monitor unknownPid: ") 510 ref = node1gs1.MonitorProcess(node3gs3.Self()) 511 result = gen.MessageDown{ 512 Ref: ref, 513 Pid: node3gs3.Self(), 514 Reason: "noproc", 515 } 516 waitForResultWithValue(t, gs1.v, result) 517 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 518 t.Fatal(err) 519 } 520 521 fmt.Printf(" wait for start of gs3 on %#v: ", node3.Name()) 522 node3gs3, _ = node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 523 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 524 525 fmt.Printf("... by Pid Local-Proxy-Remote: gs3 -> gs1. monitor/(node1: ProxyFlags.EnableMonitor = false): ") 526 527 ref = node3gs3.MonitorProcess(node1gs1.Self()) 528 result = gen.MessageDown{ 529 Ref: ref, 530 Pid: node1gs1.Self(), 531 Reason: "unsupported", 532 } 533 waitForResultWithValue(t, gs3.v, result) 534 535 fmt.Printf("... by Pid Local-Proxy-Remote: gs1 -> gs3. monitor/ProxyDown: ") 536 ref = node1gs1.MonitorProcess(node3gs3.Self()) 537 waitForTimeout(t, gs1.v) 538 node2.Stop() 539 result = gen.MessageDown{ 540 Ref: ref, 541 Pid: node3gs3.Self(), 542 Reason: "noproxy", 543 } 544 waitForResultWithValue(t, gs1.v, result) 545 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 546 t.Fatal(err) 547 } 548 549 node2, err = ergo.StartNode("nodeM2ProxyRemoteByPid@localhost", "cookies", opts2) 550 if err != nil { 551 t.Fatal("can't start node:", err, node2.Name()) 552 } 553 554 fmt.Printf("... by Pid Local-Proxy-Remote: gs1 -> gs3. monitor/NodeDown: ") 555 ref = node1gs1.MonitorProcess(node3gs3.Self()) 556 // wait a bit for the MessageDown if something went wrong 557 waitForTimeout(t, gs1.v) 558 node3.Stop() 559 result = gen.MessageDown{ 560 Ref: ref, 561 Pid: node3gs3.Self(), 562 Reason: "noconnection", 563 } 564 waitForResultWithValue(t, gs1.v, result) 565 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 566 t.Fatal(err) 567 } 568 569 fmt.Printf("... by Pid Local-Proxy-Remote: gs1 -> gs3. monitor unknown node: ") 570 ref = node1gs1.MonitorProcess(node3gs3.Self()) 571 result.Ref = ref 572 waitForResultWithValue(t, gs1.v, result) 573 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 574 t.Fatal(err) 575 } 576 node1.Stop() 577 } 578 579 func TestMonitorLocalProxyRemoteByName(t *testing.T) { 580 fmt.Printf("\n=== Test Monitor Local-Proxy-Remote by Name\n") 581 fmt.Printf("Starting nodes: nodeM1ProxyRemoteByName@localhost, nodeM2RemoteByName@localhost, nodeM3RemoteByName@localhost: ") 582 opts1 := node.Options{} 583 opts1.Proxy.Flags = node.DefaultProxyFlags() 584 opts1.Proxy.Flags.EnableMonitor = false 585 node1, err := ergo.StartNode("nodeM1RemoteByName@localhost", "cookies", opts1) 586 if err != nil { 587 t.Fatal("can't start node:", err) 588 } 589 opts2 := node.Options{} 590 opts2.Proxy.Transit = true 591 node2, err := ergo.StartNode("nodeM2RemoteByName@localhost", "cookies", opts2) 592 if err != nil { 593 t.Fatal("can't start node:", err) 594 } 595 opts3 := node.Options{} 596 opts3.Proxy.Accept = true 597 node3, err := ergo.StartNode("nodeM3RemoteByName@localhost", "cookies", opts3) 598 if err != nil { 599 t.Fatal("can't start node:", err) 600 } 601 route := node.ProxyRoute{ 602 Name: node3.Name(), 603 Proxy: node2.Name(), 604 } 605 node1.AddProxyRoute(route) 606 node1.Connect(node3.Name()) 607 fmt.Println("OK") 608 609 gs1 := &testMonitor{ 610 v: make(chan interface{}, 2), 611 } 612 gs3 := &testMonitor{ 613 v: make(chan interface{}, 2), 614 } 615 616 // starting gen servers 617 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 618 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 619 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 620 621 fmt.Printf(" wait for start of gs3 on %#v: ", node3.Name()) 622 node3gs3, _ := node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 623 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 624 625 processID := gen.ProcessID{Name: "gs3", Node: node3.Name()} 626 627 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Proxy-Remote: gs1 -> gs3. monitor/demonitor: ") 628 ref := node1gs1.MonitorProcess(processID) 629 // wait a bit for the MessageDown if something went wrong 630 waitForTimeout(t, gs1.v) 631 if err := checkCleanProcessRef(node1gs1, ref); err == nil { 632 t.Fatal("monitor reference has been lost on node 1") 633 } 634 if err := checkCleanProcessRef(node3gs3, ref); err == nil { 635 t.Fatal("monitor reference has been lost on node 3") 636 } 637 if found := node1gs1.DemonitorProcess(ref); found == false { 638 t.Fatal("lost monitoring reference on node1") 639 } 640 // Demonitoring is the async message with nothing as a feedback. 641 // use waitForTimeout just as a short timer 642 waitForTimeout(t, gs1.v) 643 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 644 t.Fatal(err) 645 } 646 if err := checkCleanProcessRef(node3gs3, ref); err != nil { 647 t.Fatal(err) 648 } 649 fmt.Println("OK") 650 651 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Proxy-Remote: gs1 -> gs3. monitor/terminate: ") 652 ref = node1gs1.MonitorProcess(processID) 653 // wait a bit for the MessageDown if something went wrong 654 waitForTimeout(t, gs1.v) 655 if node1gs1.IsMonitor(ref) == false { 656 t.Fatal("monitor reference has been lost on node 1") 657 } 658 if node3gs3.IsMonitor(ref) == false { 659 t.Fatal("monitor reference has been lost on node 3") 660 } 661 node3gs3.Exit("normal") 662 result := gen.MessageDown{ 663 Ref: ref, 664 ProcessID: processID, 665 Reason: "normal", 666 } 667 waitForResultWithValue(t, gs1.v, result) 668 669 if node1gs1.IsMonitor(ref) { 670 t.Fatal("monitor ref is still alive") 671 } 672 if node3gs3.IsMonitor(ref) { 673 t.Fatal("monitor ref is still alive") 674 } 675 676 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Proxy-Remote: gs1 -> monitor unknown remote name: ") 677 ref = node1gs1.MonitorProcess(processID) 678 result = gen.MessageDown{ 679 Ref: ref, 680 ProcessID: processID, 681 Reason: "noproc", 682 } 683 waitForResultWithValue(t, gs1.v, result) 684 if node1gs1.IsMonitor(ref) { 685 t.Fatal("monitor ref is still alive") 686 } 687 688 fmt.Printf(" wait for start of gs3 on %#v: ", node3.Name()) 689 node3gs3, _ = node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 690 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 691 692 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Proxy-Remote: gs3 -> gs1. monitor/(node1: ProxyFlags.EnableMonitor = false): ") 693 694 processID1 := gen.ProcessID{Name: node1gs1.Name(), Node: node1.Name()} 695 ref = node3gs3.MonitorProcess(processID1) 696 result = gen.MessageDown{ 697 Ref: ref, 698 ProcessID: processID1, 699 Reason: "unsupported", 700 } 701 waitForResultWithValue(t, gs3.v, result) 702 703 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Proxy-Remote: gs1 -> gs3. monitor/ProxyDown: ") 704 ref = node1gs1.MonitorProcess(processID) 705 waitForTimeout(t, gs1.v) 706 node2.Stop() 707 result = gen.MessageDown{ 708 Ref: ref, 709 ProcessID: processID, 710 Reason: "noproxy", 711 } 712 waitForResultWithValue(t, gs1.v, result) 713 if err := checkCleanProcessRef(node1gs1, ref); err != nil { 714 t.Fatal(err) 715 } 716 717 node2, err = ergo.StartNode("nodeM2RemoteByName@localhost", "cookies", opts2) 718 if err != nil { 719 t.Fatal("can't start node:", err, node2.Name()) 720 } 721 722 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Proxy-Remote: gs1 -> gs3. monitor/NodeDown: ") 723 ref = node1gs1.MonitorProcess(processID) 724 waitForTimeout(t, gs1.v) 725 node3.Stop() 726 result = gen.MessageDown{ 727 Ref: ref, 728 ProcessID: processID, 729 Reason: "noconnection", 730 } 731 waitForResultWithValue(t, gs1.v, result) 732 if node1gs1.IsMonitor(ref) { 733 t.Fatal("monitor ref is still alive") 734 } 735 736 fmt.Printf("... by gen.ProcessID{Name, Node} Local-Proxy-Remote: gs1 -> gs3. monitor unknown node: ") 737 ref = node1gs1.MonitorProcess(processID) 738 result.Ref = ref 739 waitForResultWithValue(t, gs1.v, result) 740 if node1gs1.IsMonitor(ref) { 741 t.Fatal("monitor ref is still alive") 742 } 743 node1.Stop() 744 } 745 746 /* 747 Test cases for Local-Local 748 Link 749 by Pid - equal_pids, already_linked, doesnt_exist, terminate, unlink 750 */ 751 752 func TestLinkLocal(t *testing.T) { 753 fmt.Printf("\n=== Test Link Local\n") 754 fmt.Printf("Starting node: nodeL1LocalLocal@localhost: ") 755 node1, _ := ergo.StartNode("nodeL1LocalLocal@localhost", "cookies", node.Options{}) 756 if node1 == nil { 757 t.Fatal("can't start node") 758 } else { 759 fmt.Println("OK") 760 } 761 gs1 := &testMonitor{ 762 v: make(chan interface{}, 2), 763 } 764 gs2 := &testMonitor{ 765 v: make(chan interface{}, 2), 766 } 767 // starting gen servers 768 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 769 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 770 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 771 772 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 773 node1gs2, _ := node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 774 waitForResultWithValue(t, gs2.v, node1gs2.Self()) 775 776 fmt.Printf("Testing Link process (by Pid only) Local-Local: gs1 -> gs1 (link to itself is not allowed): ") 777 node1gs1.Link(node1gs1.Self()) 778 if err := checkCleanLinkPid(node1gs1, node1gs1.Self()); err != nil { 779 t.Fatal(err) 780 } 781 fmt.Println("OK") 782 783 fmt.Printf("Testing Link process (by Pid only) Local-Local: gs1 -> gs2. link/unlink: ") 784 node1gs1.Link(node1gs2.Self()) 785 786 if err := checkLinkPid(node1gs1, node1gs2.Self()); err != nil { 787 t.Fatal(err) 788 } 789 if err := checkLinkPid(node1gs2, node1gs1.Self()); err != nil { 790 t.Fatal(err) 791 } 792 793 node1gs1.Unlink(node1gs2.Self()) 794 if err := checkCleanLinkPid(node1gs1, node1gs2.Self()); err != nil { 795 t.Fatal(err) 796 } 797 if err := checkCleanLinkPid(node1gs2, node1gs1.Self()); err != nil { 798 t.Fatal(err) 799 } 800 fmt.Println("OK") 801 802 fmt.Printf("Testing Link process (by Pid only) Local-Local: gs1 -> gs2. already_linked: ") 803 node1gs1.Link(node1gs2.Self()) 804 if err := checkLinkPid(node1gs1, node1gs2.Self()); err != nil { 805 t.Fatal(err) 806 } 807 if err := checkLinkPid(node1gs2, node1gs1.Self()); err != nil { 808 t.Fatal("link missing for node1gs2") 809 } 810 gs1links := node1gs1.Links() 811 gs2links := node1gs2.Links() 812 node1gs2.Link(node1gs1.Self()) 813 814 if len(gs1links) != len(node1gs1.Links()) || len(gs2links) != len(node1gs2.Links()) { 815 t.Fatal("number of links has changed on the second Link call") 816 } 817 fmt.Println("OK") 818 819 fmt.Printf("Testing Link process (by Pid only) Local-Local: gs1 -> gs2. terminate (trap_exit = true): ") 820 // do not link these process since they are already linked after the previous test 821 //node1gs1.Link(node1gs2.Self()) 822 823 if checkLinkPid(node1gs1, node1gs2.Self()) != nil { 824 t.Fatal("link missing for node1gs1") 825 } 826 if checkLinkPid(node1gs2, node1gs1.Self()) != nil { 827 t.Fatal("link missing for node1gs2") 828 } 829 830 node1gs1.SetTrapExit(true) 831 node1gs2.Exit("normal") 832 result := gen.MessageExit{Pid: node1gs2.Self(), Reason: "normal"} 833 waitForResultWithValue(t, gs1.v, result) 834 835 if err := checkCleanLinkPid(node1gs2, node1gs1.Self()); err != nil { 836 t.Fatal(err) 837 } 838 if node1gs2.IsAlive() { 839 t.Fatal("node1gs2 must be terminated") 840 } 841 if err := checkCleanLinkPid(node1gs1, node1gs2.Self()); err != nil { 842 t.Fatal(err) 843 } 844 if !node1gs1.IsAlive() { 845 t.Fatal("gs1 should be alive after gs2 exit due to enabled trap exit on gs1") 846 } 847 848 fmt.Printf("Testing Link process (by Pid only) Local-Local: gs1 -> gs2. doesnt_exist: ") 849 node1gs1.Link(node1gs2.Self()) 850 result = gen.MessageExit{Pid: node1gs2.Self(), Reason: "noproc"} 851 waitForResultWithValue(t, gs1.v, result) 852 853 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 854 node1gs2, _ = node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 855 waitForResultWithValue(t, gs2.v, node1gs2.Self()) 856 857 node1gs1.SetTrapExit(false) 858 fmt.Printf("Testing Link process (by Pid only) Local-Local: gs1 -> gs2. terminate (trap_exit = false): ") 859 node1gs1.Link(node1gs2.Self()) 860 861 if checkLinkPid(node1gs2, node1gs1.Self()) != nil { 862 t.Fatal("link missing for node1gs1") 863 } 864 if checkLinkPid(node1gs1, node1gs2.Self()) != nil { 865 t.Fatal("link missing for node1gs2") 866 } 867 868 node1gs2.Exit("normal") 869 870 // wait a bit to make sure if we receive anything (shouldnt receive) 871 waitForTimeout(t, gs1.v) 872 fmt.Println("OK") 873 874 if err := checkCleanLinkPid(node1gs2, node1gs1.Self()); err != nil { 875 t.Fatal(err) 876 } 877 if err := checkCleanLinkPid(node1gs1, node1gs2.Self()); err != nil { 878 t.Fatal(err) 879 } 880 if node1gs1.IsAlive() { 881 t.Fatal("gs1 shouldnt be alive after gs2 exit due to disable trap exit on gs1") 882 } 883 if node1gs2.IsAlive() { 884 t.Fatal("node1gs2 must be terminated") 885 } 886 887 node1.Stop() 888 } 889 890 /* 891 Test cases for Local-Remote 892 Link 893 by Pid - already_linked, doesnt_exist, terminate, unlink, node_down, node_unknown 894 */ 895 func TestLinkRemote(t *testing.T) { 896 fmt.Printf("\n=== Test Link Remote by Pid\n") 897 fmt.Printf("Starting nodes: nodeL1LocalRemoteByPid@localhost, nodeL2LocalRemoteByPid@localhost: ") 898 node1, _ := ergo.StartNode("nodeL1LocalRemoteByPid@localhost", "cookies", node.Options{}) 899 node2, _ := ergo.StartNode("nodeL2LocalRemoteByPid@localhost", "cookies", node.Options{}) 900 if node1 == nil || node2 == nil { 901 t.Fatal("can't start nodes") 902 } else { 903 fmt.Println("OK") 904 } 905 906 gs1 := &testMonitor{ 907 v: make(chan interface{}, 2), 908 } 909 gs2 := &testMonitor{ 910 v: make(chan interface{}, 2), 911 } 912 913 // starting gen servers 914 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 915 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 916 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 917 918 fmt.Printf(" wait for start of gs2 on %#v: ", node2.Name()) 919 node2gs2, _ := node2.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 920 waitForResultWithValue(t, gs2.v, node2gs2.Self()) 921 922 fmt.Printf("Testing Link process (by Pid only) Local-Remote: gs1 -> gs2. unlink: ") 923 node1gs1.Link(node2gs2.Self()) 924 // wait a bit since linking process is async 925 waitForTimeout(t, gs1.v) 926 927 if checkLinkPid(node1gs1, node2gs2.Self()) != nil { 928 t.Fatal("link missing on node1gs1") 929 } 930 if checkLinkPid(node2gs2, node1gs1.Self()) != nil { 931 t.Fatal("link missing on node2gs2 ") 932 } 933 934 node1gs1.Unlink(node2gs2.Self()) 935 // wait a bit since unlinking process is async 936 waitForTimeout(t, gs1.v) 937 if err := checkCleanLinkPid(node1gs1, node2gs2.Self()); err != nil { 938 t.Fatal(err) 939 } 940 if err := checkCleanLinkPid(node2gs2, node1gs1.Self()); err != nil { 941 t.Fatal(err) 942 } 943 fmt.Println("OK") 944 945 fmt.Printf("Testing Link process (by Pid only) Local-Remote: gs1 -> gs2. already_linked: ") 946 node1gs1.Link(node2gs2.Self()) 947 if checkLinkPid(node1gs1, node2gs2.Self()) != nil { 948 t.Fatal("link missing on node1gs1") 949 } 950 // wait a bit since linking process is async 951 waitForTimeout(t, gs1.v) 952 if checkLinkPid(node2gs2, node1gs1.Self()) != nil { 953 t.Fatal("link missing on node2gs2") 954 } 955 ll1 := len(node1gs1.Links()) 956 ll2 := len(node2gs2.Links()) 957 958 node2gs2.Link(node1gs1.Self()) 959 // wait a bit since linking process is async 960 waitForTimeout(t, gs2.v) 961 962 if ll1 != len(node1gs1.Links()) || ll2 != len(node2gs2.Links()) { 963 t.Fatal("number of links has changed on the second Link call") 964 } 965 fmt.Println("OK") 966 967 fmt.Printf("Testing Link process (by Pid only) Local-Remote: gs1 -> gs2. terminate (trap_exit = true): ") 968 // do not link these process since they are already linked after the previous test 969 970 node1gs1.SetTrapExit(true) 971 972 node2gs2.Exit("normal") 973 result := gen.MessageExit{Pid: node2gs2.Self(), Reason: "normal"} 974 waitForResultWithValue(t, gs1.v, result) 975 976 if err := checkCleanLinkPid(node1gs1, node2gs2.Self()); err != nil { 977 t.Fatal(err) 978 } 979 if err := checkCleanLinkPid(node2gs2, node1gs1.Self()); err != nil { 980 t.Fatal(err) 981 } 982 if !node1gs1.IsAlive() { 983 t.Fatal("gs1 should be alive after gs2 exit due to enabled trap exit on gs1") 984 } 985 986 fmt.Printf("Testing Link process (by Pid only) Local-Remote: gs1 -> gs2. doesnt_exist: ") 987 ll1 = len(node1gs1.Links()) 988 node1gs1.Link(node2gs2.Self()) 989 result = gen.MessageExit{Pid: node2gs2.Self(), Reason: "noproc"} 990 waitForResultWithValue(t, gs1.v, result) 991 if ll1 != len(node1gs1.Links()) { 992 t.Fatal("number of links has changed on the second Link call") 993 } 994 995 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 996 node2gs2, _ = node2.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 997 waitForResultWithValue(t, gs2.v, node2gs2.Self()) 998 999 node1gs1.SetTrapExit(false) 1000 fmt.Printf("Testing Link process (by Pid only) Local-Local: gs1 -> gs2. terminate (trap_exit = false): ") 1001 node1gs1.Link(node2gs2.Self()) 1002 waitForTimeout(t, gs2.v) 1003 1004 if checkLinkPid(node1gs1, node2gs2.Self()) != nil { 1005 t.Fatal("link missing on node1gs1") 1006 } 1007 if checkLinkPid(node2gs2, node1gs1.Self()) != nil { 1008 t.Fatal("link missing on node2gs2") 1009 } 1010 1011 node2gs2.Exit("normal") 1012 1013 // wait a bit to make sure if we receive anything (shouldnt receive) 1014 waitForTimeout(t, gs1.v) 1015 1016 if err := checkCleanLinkPid(node1gs1, node2gs2.Self()); err != nil { 1017 t.Fatal(err) 1018 } 1019 if err := checkCleanLinkPid(node2gs2, node1gs1.Self()); err != nil { 1020 t.Fatal(err) 1021 } 1022 if node1gs1.IsAlive() { 1023 t.Fatal("gs1 shouldnt be alive after gs2 exit due to disable trap exit on gs1") 1024 } 1025 if node2gs2.IsAlive() { 1026 t.Fatal("gs2 must be terminated") 1027 } 1028 fmt.Println("OK") 1029 1030 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 1031 node1gs1, _ = node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 1032 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 1033 fmt.Printf(" wait for start of gs2 on %#v: ", node2.Name()) 1034 node2gs2, _ = node2.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 1035 waitForResultWithValue(t, gs2.v, node2gs2.Self()) 1036 1037 node1gs1.SetTrapExit(true) 1038 fmt.Printf("Testing Link process (by Pid only) Local-Remote: gs1 -> gs2. node_down: ") 1039 node1gs1.Link(node2gs2.Self()) 1040 waitForTimeout(t, gs1.v) 1041 1042 if checkLinkPid(node1gs1, node2gs2.Self()) != nil { 1043 t.Fatal("link missing for node1gs1") 1044 } 1045 if checkCleanLinkPid(node2gs2, node1gs1.Self()) == nil { 1046 t.Fatal("link missing for node2gs2") 1047 } 1048 1049 // race conditioned case. 1050 // processing of the process termination (on the remote peer) can be done faster than 1051 // the link termination there, so MessageExit with "kill" reason will be arrived 1052 // earlier. 1053 node2.Stop() 1054 result1 := gen.MessageExit{Pid: node2gs2.Self(), Reason: "noconnection"} 1055 result2 := gen.MessageExit{Pid: node2gs2.Self(), Reason: "kill"} 1056 1057 waitForResultWithValueOrValue(t, gs1.v, result1, result2) 1058 1059 if err := checkCleanLinkPid(node1gs1, node2gs2.Self()); err != nil { 1060 t.Fatal(err) 1061 } 1062 // must wait a bit 1063 waitForTimeout(t, gs1.v) 1064 if err := checkCleanLinkPid(node2gs2, node1gs1.Self()); err != nil { 1065 t.Fatal(err) 1066 } 1067 1068 ll1 = len(node1gs1.Links()) 1069 fmt.Printf("Testing Link process (by Pid only) Local-Remote: gs1 -> gs2. node_unknown: ") 1070 node1gs1.Link(node2gs2.Self()) 1071 result = gen.MessageExit{Pid: node2gs2.Self(), Reason: "noconnection"} 1072 waitForResultWithValue(t, gs1.v, result) 1073 1074 if ll1 != len(node1gs1.Links()) { 1075 t.Fatal("number of links has changed on the second Link call") 1076 } 1077 node1.Stop() 1078 } 1079 1080 func TestLinkRemoteProxy(t *testing.T) { 1081 fmt.Printf("\n=== Test Link Remote Via Proxy\n") 1082 fmt.Printf("Starting nodes: nodeL1RemoteViaProxy@localhost, nodeL2RemoteViaProxy@localhost, nodeL3RemoteViaProxy@localhost: ") 1083 node1, err := ergo.StartNode("nodeL1RemoteViaProxy@localhost", "cookies", node.Options{}) 1084 if err != nil { 1085 t.Fatal(err) 1086 } 1087 node2opts := node.Options{} 1088 node2opts.Proxy.Transit = true 1089 node2, err := ergo.StartNode("nodeL2RemoteViaProxy@localhost", "cookies", node2opts) 1090 if err != nil { 1091 t.Fatal(err) 1092 } 1093 node3opts := node.Options{} 1094 node3opts.Proxy.Accept = true 1095 node3, err := ergo.StartNode("nodeL3RemoteViaProxy@localhost", "cookies", node3opts) 1096 if err != nil { 1097 t.Fatal(err) 1098 } 1099 fmt.Println("OK") 1100 1101 route := node.ProxyRoute{ 1102 Name: node3.Name(), 1103 Proxy: node2.Name(), 1104 } 1105 route.Flags = node.DefaultProxyFlags() 1106 route.Flags.EnableLink = false 1107 node1.AddProxyRoute(route) 1108 1109 fmt.Printf(" check connectivity of %s with %s via proxy %s: ", node1.Name(), node3.Name(), node2.Name()) 1110 if err := node1.Connect(node3.Name()); err != nil { 1111 t.Fatal(err) 1112 } 1113 node1indirect := node1.NodesIndirect() 1114 node3indirect := node3.NodesIndirect() 1115 if len(node1indirect) != 1 || len(node3indirect) != 1 { 1116 t.Fatal("wrong indirect nodes (node1:", node1indirect, "; node3:", node3indirect, ")") 1117 } 1118 if node1indirect[0] != node3.Name() || node3indirect[0] != node1.Name() { 1119 t.Fatal("wrong indirect nodes (node1:", node1indirect, "; node3:", node3indirect, ")") 1120 } 1121 fmt.Println("OK") 1122 gs1 := &testMonitor{ 1123 v: make(chan interface{}, 2), 1124 } 1125 gs3 := &testMonitor{ 1126 v: make(chan interface{}, 2), 1127 } 1128 1129 // starting gen servers 1130 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 1131 node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 1132 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 1133 1134 fmt.Printf(" wait for start of gs3 on %#v: ", node3.Name()) 1135 node3gs3, _ := node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 1136 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 1137 1138 fmt.Printf("Testing Link process Local-Proxy-Remote: gs1 -> gs3. unlink: ") 1139 node1gs1.Link(node3gs3.Self()) 1140 // wait a bit since linking process is async 1141 waitForTimeout(t, gs1.v) 1142 1143 if checkLinkPid(node1gs1, node3gs3.Self()) != nil { 1144 t.Fatal("link missing on node1gs1") 1145 } 1146 if checkLinkPid(node3gs3, node1gs1.Self()) != nil { 1147 t.Fatal("link missing on node3gs3 ") 1148 } 1149 1150 node1gs1.Unlink(node3gs3.Self()) 1151 // wait a bit since unlinking process is async 1152 waitForTimeout(t, gs1.v) 1153 if err := checkCleanLinkPid(node1gs1, node3gs3.Self()); err != nil { 1154 t.Fatal(err) 1155 } 1156 if err := checkCleanLinkPid(node3gs3, node1gs1.Self()); err != nil { 1157 t.Fatal(err) 1158 } 1159 fmt.Println("OK") 1160 1161 fmt.Printf("Testing Link process Local-Proxy-Remote: gs1 -> gs3. already_linked: ") 1162 node1gs1.Link(node3gs3.Self()) 1163 if checkLinkPid(node1gs1, node3gs3.Self()) != nil { 1164 t.Fatal("link missing on node1gs1") 1165 } 1166 // wait a bit since linking process is async 1167 waitForTimeout(t, gs1.v) 1168 if checkLinkPid(node3gs3, node1gs1.Self()) != nil { 1169 t.Fatal("link missing on node3gs3") 1170 } 1171 ll1 := len(node1gs1.Links()) 1172 ll3 := len(node3gs3.Links()) 1173 1174 node3gs3.Link(node1gs1.Self()) 1175 // wait a bit since linking process is async 1176 waitForTimeout(t, gs3.v) 1177 1178 if ll1 != len(node1gs1.Links()) || ll3 != len(node3gs3.Links()) { 1179 t.Fatal("number of links has changed on the second Link call") 1180 } 1181 fmt.Println("OK") 1182 1183 fmt.Printf("Testing Link process Local-Proxy-Remote: gs1 -> gs3. terminate (trap_exit = true): ") 1184 // do not link these process since they are already linked after the previous test 1185 1186 node1gs1.SetTrapExit(true) 1187 1188 node3gs3.Exit("normal") 1189 result := gen.MessageExit{Pid: node3gs3.Self(), Reason: "normal"} 1190 waitForResultWithValue(t, gs1.v, result) 1191 1192 if err := checkCleanLinkPid(node1gs1, node3gs3.Self()); err != nil { 1193 t.Fatal(err) 1194 } 1195 if err := checkCleanLinkPid(node3gs3, node1gs1.Self()); err != nil { 1196 t.Fatal(err) 1197 } 1198 if !node1gs1.IsAlive() { 1199 t.Fatal("gs1 should be alive after gs3 exit due to enabled trap exit on gs1") 1200 } 1201 1202 fmt.Printf("Testing Link process Local-Proxy-Remote: gs1 -> gs3. doesnt_exist: ") 1203 ll1 = len(node1gs1.Links()) 1204 node1gs1.Link(node3gs3.Self()) 1205 result = gen.MessageExit{Pid: node3gs3.Self(), Reason: "noproc"} 1206 waitForResultWithValue(t, gs1.v, result) 1207 if ll1 != len(node1gs1.Links()) { 1208 t.Fatal("number of links has changed on the second Link call") 1209 } 1210 1211 fmt.Printf(" wait for start of gs3 on %#v: ", node1.Name()) 1212 node3gs3, _ = node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 1213 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 1214 1215 node1gs1.SetTrapExit(false) 1216 fmt.Printf("Testing Link process Local-Proxy-Remote: gs1 -> gs3. terminate (trap_exit = false): ") 1217 node1gs1.Link(node3gs3.Self()) 1218 waitForTimeout(t, gs3.v) 1219 1220 if checkLinkPid(node1gs1, node3gs3.Self()) != nil { 1221 t.Fatal("link missing on node1gs1") 1222 } 1223 if checkLinkPid(node3gs3, node1gs1.Self()) != nil { 1224 t.Fatal("link missing on node3gs3") 1225 } 1226 1227 node3gs3.Exit("normal") 1228 1229 // wait a bit to make sure if we receive anything (shouldnt receive) 1230 waitForTimeout(t, gs1.v) 1231 1232 if err := checkCleanLinkPid(node1gs1, node3gs3.Self()); err != nil { 1233 t.Fatal(err) 1234 } 1235 if err := checkCleanLinkPid(node3gs3, node1gs1.Self()); err != nil { 1236 t.Fatal(err) 1237 } 1238 if node1gs1.IsAlive() { 1239 t.Fatal("gs1 shouldnt be alive after gs3 exit due to disable trap exit on gs1") 1240 } 1241 if node3gs3.IsAlive() { 1242 t.Fatal("gs3 must be terminated") 1243 } 1244 fmt.Println("OK") 1245 1246 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 1247 node1gs1, _ = node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 1248 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 1249 fmt.Printf(" wait for start of gs3 on %#v: ", node3.Name()) 1250 node3gs3, _ = node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 1251 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 1252 1253 node1gs1.SetTrapExit(true) 1254 fmt.Printf("Testing Link process Local-Proxy-Remote: gs1 -> gs3. node_down: ") 1255 node1gs1.Link(node3gs3.Self()) 1256 waitForTimeout(t, gs1.v) 1257 1258 if checkLinkPid(node1gs1, node3gs3.Self()) != nil { 1259 t.Fatal("link missing for node1gs1") 1260 } 1261 if checkCleanLinkPid(node3gs3, node1gs1.Self()) == nil { 1262 t.Fatal("link missing for node3gs3") 1263 } 1264 1265 // race conditioned case. 1266 // processing of the process termination (on the remote peer) can be done faster than 1267 // the link termination there, so MessageExit with "kill" reason will be arrived 1268 // earlier. 1269 node3.Stop() 1270 result1 := gen.MessageExit{Pid: node3gs3.Self(), Reason: "noconnection"} 1271 result2 := gen.MessageExit{Pid: node3gs3.Self(), Reason: "kill"} 1272 1273 waitForResultWithValueOrValue(t, gs1.v, result1, result2) 1274 1275 if err := checkCleanLinkPid(node1gs1, node3gs3.Self()); err != nil { 1276 t.Fatal(err) 1277 } 1278 // must wait a bit 1279 waitForTimeout(t, gs1.v) 1280 if err := checkCleanLinkPid(node3gs3, node1gs1.Self()); err != nil { 1281 t.Fatal(err) 1282 } 1283 1284 ll1 = len(node1gs1.Links()) 1285 fmt.Printf("Testing Link process Local-Proxy-Remote: gs1 -> gs3. node_unknown: ") 1286 node1gs1.Link(node3gs3.Self()) 1287 result = gen.MessageExit{Pid: node3gs3.Self(), Reason: "noconnection"} 1288 waitForResultWithValue(t, gs1.v, result) 1289 1290 if ll1 != len(node1gs1.Links()) { 1291 t.Fatal("number of links has changed on the second Link call") 1292 } 1293 1294 node3opts = node.Options{} 1295 node3opts.Proxy.Accept = true 1296 node3, err = ergo.StartNode("nodeL3RemoteViaProxy@localhost", "cookies", node3opts) 1297 fmt.Printf(" starting node: %s", node3.Name()) 1298 if err != nil { 1299 t.Fatal(err) 1300 } 1301 fmt.Println("OK") 1302 fmt.Printf(" wait for start of gs3 on %#v: ", node3.Name()) 1303 node3gs3, _ = node3.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 1304 waitForResultWithValue(t, gs3.v, node3gs3.Self()) 1305 1306 if err := node1.Connect(node3.Name()); err != nil { 1307 t.Fatal(err) 1308 } 1309 1310 node3gs3.SetTrapExit(true) 1311 fmt.Printf("Testing Proxy Local-Proxy-Remote for link gs3 -> gs1 (Node1 ProxyFlags.EnableLink = false): ") 1312 node3gs3.Link(node1gs1.Self()) 1313 result = gen.MessageExit{Pid: node1gs1.Self(), Reason: lib.ErrPeerUnsupported.Error()} 1314 waitForResultWithValue(t, gs3.v, result) 1315 1316 node1gs1.Link(node3gs3.Self()) 1317 waitForTimeout(t, gs1.v) 1318 1319 if checkLinkPid(node1gs1, node3gs3.Self()) != nil { 1320 t.Fatal("link missing for node1gs1") 1321 } 1322 if checkCleanLinkPid(node3gs3, node1gs1.Self()) == nil { 1323 t.Fatal("link missing for node3gs3") 1324 } 1325 fmt.Println("Testing Proxy Down Local-Proxy-Remote for linked gs1 -> gs3 (trap_exit = true): ") 1326 node2.Stop() 1327 1328 fmt.Printf(" wait for MessageExit with reason 'noproxy' on gs1: ") 1329 result = gen.MessageExit{Pid: node3gs3.Self(), Reason: "noproxy"} 1330 waitForResultWithValue(t, gs1.v, result) 1331 1332 fmt.Printf(" wait for MessageExit with reason 'noproxy' on gs3: ") 1333 result = gen.MessageExit{Pid: node1gs1.Self(), Reason: "noproxy"} 1334 waitForResultWithValue(t, gs3.v, result) 1335 1336 node1.Stop() 1337 } 1338 1339 func TestMonitorNode(t *testing.T) { 1340 fmt.Printf("\n=== Test Monitor Node \n") 1341 fmt.Printf("... start nodes A, B, C, D: ") 1342 optsA := node.Options{} 1343 nodeA, e := ergo.StartNode("monitornodeAproxy@localhost", "secret", optsA) 1344 if e != nil { 1345 t.Fatal(e) 1346 } 1347 optsB := node.Options{} 1348 optsB.Proxy.Transit = true 1349 nodeB, e := ergo.StartNode("monitornodeBproxy@localhost", "secret", optsB) 1350 if e != nil { 1351 t.Fatal(e) 1352 } 1353 optsC := node.Options{} 1354 optsC.Proxy.Transit = true 1355 nodeC, e := ergo.StartNode("monitornodeCproxy@localhost", "secret", optsC) 1356 if e != nil { 1357 t.Fatal(e) 1358 } 1359 1360 optsD := node.Options{} 1361 optsD.Proxy.Accept = true 1362 nodeD, e := ergo.StartNode("monitornodeDproxy@localhost", "secret", optsD) 1363 if e != nil { 1364 t.Fatal(e) 1365 } 1366 fmt.Println("OK") 1367 1368 gsA := &testMonitor{ 1369 v: make(chan interface{}, 2), 1370 } 1371 gsB := &testMonitor{ 1372 v: make(chan interface{}, 2), 1373 } 1374 gsD := &testMonitor{ 1375 v: make(chan interface{}, 2), 1376 } 1377 fmt.Printf("... start processA on node A: ") 1378 pA, err := nodeA.Spawn("", gen.ProcessOptions{}, gsA) 1379 if err != nil { 1380 t.Fatal(err) 1381 } 1382 waitForResultWithValue(t, gsA.v, pA.Self()) 1383 fmt.Printf("... start processB on node B: ") 1384 pB, err := nodeB.Spawn("", gen.ProcessOptions{}, gsB) 1385 if err != nil { 1386 t.Fatal(err) 1387 } 1388 waitForResultWithValue(t, gsB.v, pB.Self()) 1389 fmt.Printf("... start processD on node D: ") 1390 pD, err := nodeD.Spawn("", gen.ProcessOptions{}, gsD) 1391 if err != nil { 1392 t.Fatal(err) 1393 } 1394 waitForResultWithValue(t, gsD.v, pD.Self()) 1395 fmt.Printf("... add proxy route on A to the node D via B: ") 1396 routeAtoDviaB := node.ProxyRoute{ 1397 Name: nodeD.Name(), 1398 Proxy: nodeB.Name(), 1399 } 1400 if err := nodeA.AddProxyRoute(routeAtoDviaB); err != nil { 1401 t.Fatal(err) 1402 } 1403 fmt.Println("OK") 1404 1405 fmt.Printf("... add proxy transit route on B to the node D via C: ") 1406 route := node.ProxyRoute{ 1407 Name: nodeD.Name(), 1408 Proxy: nodeC.Name(), 1409 } 1410 if err := nodeB.AddProxyRoute(route); err != nil { 1411 t.Fatal(err) 1412 } 1413 fmt.Println("OK") 1414 1415 fmt.Printf("... monitor D by processA (via proxy connection): ") 1416 refA := pA.MonitorNode(nodeD.Name()) 1417 fmt.Println("OK") 1418 fmt.Printf("... monitor A by processD (via proxy connection): ") 1419 refD := pD.MonitorNode(nodeA.Name()) 1420 fmt.Println("OK") 1421 fmt.Printf("... monitor C by processB (via direct connection): ") 1422 refB := pB.MonitorNode(nodeC.Name()) 1423 fmt.Println("OK") 1424 fmt.Printf("... check connectivity (A -> D via B and C, D -> A via C and B): ") 1425 nodelist := []string{nodeB.Name(), nodeD.Name()} 1426 nodesA := nodeA.Nodes() 1427 sort.Strings(nodesA) 1428 if reflect.DeepEqual(nodesA, nodelist) == false { 1429 t.Fatal("node A has wrong peers", nodeA.Nodes()) 1430 } 1431 if reflect.DeepEqual(nodeA.NodesIndirect(), []string{nodeD.Name()}) == false { 1432 t.Fatal("node A has wrong proxy peer", nodeA.NodesIndirect()) 1433 } 1434 nodelist = []string{nodeA.Name(), nodeC.Name()} 1435 nodesB := nodeB.Nodes() 1436 sort.Strings(nodesB) 1437 if reflect.DeepEqual(nodesB, nodelist) == false { 1438 t.Fatal("node B has wrong peers", nodeB.Nodes()) 1439 } 1440 if reflect.DeepEqual(nodeB.NodesIndirect(), []string{}) == false { 1441 t.Fatal("node B has wrong proxy peer", nodeB.NodesIndirect()) 1442 } 1443 nodelist = []string{nodeB.Name(), nodeD.Name()} 1444 nodesC := nodeC.Nodes() 1445 sort.Strings(nodesC) 1446 if reflect.DeepEqual(nodesC, nodelist) == false { 1447 t.Fatal("node C has wrong peers", nodeC.Nodes()) 1448 } 1449 if reflect.DeepEqual(nodeC.NodesIndirect(), []string{}) == false { 1450 t.Fatal("node C has wrong proxy peer", nodeC.NodesIndirect()) 1451 } 1452 nodelist = []string{nodeA.Name(), nodeC.Name()} 1453 nodesD := nodeD.Nodes() 1454 sort.Strings(nodesD) 1455 if reflect.DeepEqual(nodesD, nodelist) == false { 1456 t.Fatal("node D has wrong peers", nodeD.Nodes()) 1457 } 1458 if reflect.DeepEqual(nodeD.NodesIndirect(), []string{nodeA.Name()}) == false { 1459 t.Fatal("node D has wrong proxy peer", nodeD.NodesIndirect()) 1460 } 1461 fmt.Println("OK") 1462 fmt.Printf("... stop node C : ") 1463 nodeC.Stop() 1464 fmt.Println("OK") 1465 resultMessageProxyDown := gen.MessageProxyDown{Ref: refD, Node: nodeC.Name(), Proxy: nodeD.Name(), Reason: "noconnection"} 1466 fmt.Printf("... processD must receive gen.MessageProxyDown{Node: C, Proxy: D,...}: ") 1467 waitForResultWithValue(t, gsD.v, resultMessageProxyDown) 1468 resultMessageProxyDown = gen.MessageProxyDown{Ref: refA, Node: nodeC.Name(), Proxy: nodeB.Name(), Reason: "noconnection"} 1469 fmt.Printf("... processA must receive gen.MessageProxyDown{Node: C, Proxy: B,...}: ") 1470 waitForResultWithValue(t, gsA.v, resultMessageProxyDown) 1471 resultMessageDown := gen.MessageNodeDown{Ref: refB, Name: nodeC.Name()} 1472 fmt.Printf("... processB must receive gen.MessageDown: ") 1473 waitForResultWithValue(t, gsB.v, resultMessageDown) 1474 1475 fmt.Printf("... check connectivity (A <-> B, C is down, D has no peers): ") 1476 if reflect.DeepEqual(nodeA.Nodes(), []string{nodeB.Name()}) == false { 1477 t.Fatal("node A has wrong peer", nodeA.Nodes()) 1478 } 1479 if reflect.DeepEqual(nodeB.Nodes(), []string{nodeA.Name()}) == false { 1480 t.Fatal("node B has wrong peer", nodeB.Nodes()) 1481 } 1482 if nodeC.IsAlive() == true { 1483 t.Fatal("node C is still alive") 1484 } 1485 if reflect.DeepEqual(nodeC.Nodes(), []string{}) == false { 1486 t.Fatal("node C has peers", nodeC.Nodes()) 1487 } 1488 if reflect.DeepEqual(nodeD.Nodes(), []string{}) == false { 1489 t.Fatal("node D has peers", nodeD.Nodes()) 1490 } 1491 fmt.Println("OK") 1492 nodeD.Stop() 1493 nodeA.Stop() 1494 nodeB.Stop() 1495 } 1496 1497 type testMonitorEvent struct { 1498 gen.Server 1499 v chan interface{} 1500 } 1501 1502 type testEventCmdRegister struct { 1503 event gen.Event 1504 messages []gen.EventMessage 1505 } 1506 type testEventCmdUnregister struct { 1507 event gen.Event 1508 } 1509 type testEventCmdMonitor struct { 1510 event gen.Event 1511 } 1512 type testEventCmdSend struct { 1513 event gen.Event 1514 message gen.EventMessage 1515 } 1516 1517 type testMessageEventA struct { 1518 value string 1519 } 1520 1521 func (tgs *testMonitorEvent) Init(process *gen.ServerProcess, args ...etf.Term) error { 1522 tgs.v <- process.Self() 1523 return nil 1524 } 1525 func (tgs *testMonitorEvent) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 1526 switch cmd := message.(type) { 1527 case testEventCmdRegister: 1528 return nil, process.RegisterEvent(cmd.event, cmd.messages...) 1529 case testEventCmdUnregister: 1530 return nil, process.UnregisterEvent(cmd.event) 1531 case testEventCmdMonitor: 1532 return nil, process.MonitorEvent(cmd.event) 1533 case testEventCmdSend: 1534 return nil, process.SendEventMessage(cmd.event, cmd.message) 1535 1536 default: 1537 return nil, fmt.Errorf("unknown cmd") 1538 1539 } 1540 } 1541 1542 func (tgs *testMonitorEvent) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus { 1543 tgs.v <- message 1544 return gen.ServerStatusOK 1545 } 1546 1547 func TestMonitorEvents(t *testing.T) { 1548 fmt.Printf("\n=== Test Monitor Events\n") 1549 fmt.Printf("Starting node: nodeM1Events@localhost: ") 1550 node1, _ := ergo.StartNode("nodeM1Events@localhost", "cookies", node.Options{}) 1551 if node1 == nil { 1552 t.Fatal("can't start node") 1553 } 1554 defer node1.Stop() 1555 1556 fmt.Println("OK") 1557 gs1 := &testMonitorEvent{ 1558 v: make(chan interface{}, 2), 1559 } 1560 gs2 := &testMonitorEvent{ 1561 v: make(chan interface{}, 2), 1562 } 1563 gs3 := &testMonitorEvent{ 1564 v: make(chan interface{}, 2), 1565 } 1566 // starting gen servers 1567 1568 fmt.Printf(" wait for start of gs1 on %#v: ", node1.Name()) 1569 node1gs1, err := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil) 1570 if err != nil { 1571 t.Fatal(err) 1572 } 1573 waitForResultWithValue(t, gs1.v, node1gs1.Self()) 1574 1575 fmt.Printf(" wait for start of gs2 on %#v: ", node1.Name()) 1576 node1gs2, err := node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil) 1577 if err != nil { 1578 t.Fatal(err) 1579 } 1580 waitForResultWithValue(t, gs2.v, node1gs2.Self()) 1581 1582 fmt.Printf(" wait for start of gs3 on %#v: ", node1.Name()) 1583 node1gs3, err := node1.Spawn("gs3", gen.ProcessOptions{}, gs3, nil) 1584 if err != nil { 1585 t.Fatal(err) 1586 } 1587 waitForResultWithValue(t, gs3.v, node1gs3.Self()) 1588 1589 fmt.Printf("... register new event : ") 1590 cmd := testEventCmdRegister{ 1591 event: "testEvent", 1592 messages: []gen.EventMessage{testMessageEventA{}}, 1593 } 1594 _, err = node1gs1.Direct(cmd) 1595 if err != nil { 1596 t.Fatal(err) 1597 } 1598 fmt.Println("OK") 1599 1600 fmt.Printf("... register new event with the same name: ") 1601 _, err = node1gs1.Direct(cmd) 1602 if err != lib.ErrTaken { 1603 t.Fatal(err) 1604 } 1605 fmt.Println("OK") 1606 1607 fmt.Printf("... unregister unknown event: ") 1608 cmd1 := testEventCmdUnregister{ 1609 event: "unknownEvent", 1610 } 1611 _, err = node1gs1.Direct(cmd1) 1612 if err != lib.ErrEventUnknown { 1613 t.Fatal(err) 1614 } 1615 fmt.Println("OK") 1616 1617 fmt.Printf("... unregister event by not an owner: ") 1618 cmd1 = testEventCmdUnregister{ 1619 event: "testEvent", 1620 } 1621 _, err = node1gs2.Direct(cmd1) 1622 if err != lib.ErrEventOwner { 1623 t.Fatal(err) 1624 } 1625 fmt.Println("OK") 1626 1627 fmt.Printf("... unregister event by the owner: ") 1628 cmd1 = testEventCmdUnregister{ 1629 event: "testEvent", 1630 } 1631 _, err = node1gs1.Direct(cmd1) 1632 if err != nil { 1633 t.Fatal(err) 1634 } 1635 fmt.Println("OK") 1636 1637 fmt.Printf("... monitor unknown event: ") 1638 cmd2 := testEventCmdMonitor{ 1639 event: "testEvent", 1640 } 1641 _, err = node1gs2.Direct(cmd2) 1642 if err != lib.ErrEventUnknown { 1643 t.Fatal(err) 1644 } 1645 fmt.Println("OK") 1646 1647 fmt.Printf("... monitor event: ") 1648 cmd = testEventCmdRegister{ 1649 event: "testEvent", 1650 messages: []gen.EventMessage{testMessageEventA{}}, 1651 } 1652 _, err = node1gs1.Direct(cmd) 1653 if err != nil { 1654 t.Fatal(err) 1655 } 1656 1657 cmd2 = testEventCmdMonitor{ 1658 event: "testEvent", 1659 } 1660 _, err = node1gs2.Direct(cmd2) 1661 if err != nil { 1662 t.Fatal(err) 1663 } 1664 fmt.Println("OK") 1665 1666 fmt.Printf("... monitor event itself: ") 1667 cmd2 = testEventCmdMonitor{ 1668 event: "testEvent", 1669 } 1670 _, err = node1gs1.Direct(cmd2) 1671 if err != lib.ErrEventSelf { 1672 t.Fatal(err) 1673 } 1674 fmt.Println("OK") 1675 1676 fmt.Printf("... send unknown event: ") 1677 msg := testMessageEventA{value: "test"} 1678 cmd3 := testEventCmdSend{ 1679 event: "unknownEvent", 1680 message: msg, 1681 } 1682 _, err = node1gs1.Direct(cmd3) 1683 if err != lib.ErrEventUnknown { 1684 t.Fatal(err) 1685 } 1686 fmt.Println("OK") 1687 1688 fmt.Printf("... send event with wrong message type: ") 1689 msgWrong := "wrong type" 1690 cmd3 = testEventCmdSend{ 1691 event: "testEvent", 1692 message: msgWrong, 1693 } 1694 _, err = node1gs1.Direct(cmd3) 1695 if err != lib.ErrEventMismatch { 1696 t.Fatal(err) 1697 } 1698 fmt.Println("OK") 1699 1700 fmt.Printf("... send event by not an owner: ") 1701 cmd3 = testEventCmdSend{ 1702 event: "testEvent", 1703 message: msg, 1704 } 1705 _, err = node1gs2.Direct(cmd3) 1706 if err != lib.ErrEventOwner { 1707 t.Fatal(err) 1708 } 1709 fmt.Println("OK") 1710 1711 fmt.Printf("... send event: ") 1712 cmd3 = testEventCmdSend{ 1713 event: "testEvent", 1714 message: msg, 1715 } 1716 _, err = node1gs1.Direct(cmd3) 1717 if err != nil { 1718 t.Fatal(err) 1719 } 1720 waitForResultWithValue(t, gs2.v, msg) 1721 1722 fmt.Printf("... monitor event twice: ") 1723 cmd2 = testEventCmdMonitor{ 1724 event: "testEvent", 1725 } 1726 _, err = node1gs2.Direct(cmd2) 1727 if err != nil { 1728 t.Fatal(err) 1729 } 1730 fmt.Println("OK") 1731 1732 fmt.Printf("... send event. must be received twice: ") 1733 cmd3 = testEventCmdSend{ 1734 event: "testEvent", 1735 message: msg, 1736 } 1737 _, err = node1gs1.Direct(cmd3) 1738 if err != nil { 1739 t.Fatal(err) 1740 } 1741 fmt.Println("OK") 1742 fmt.Printf("... receive first event message: ") 1743 waitForResultWithValue(t, gs2.v, msg) 1744 fmt.Printf("... receive second event message: ") 1745 waitForResultWithValue(t, gs2.v, msg) 1746 1747 down := gen.MessageEventDown{ 1748 Event: "testEvent", 1749 Reason: "unregistered", 1750 } 1751 fmt.Printf("... unregister event owner. must be received gen.MessageEventDown twice with reason 'unregistered': ") 1752 cmd1 = testEventCmdUnregister{ 1753 event: "testEvent", 1754 } 1755 _, err = node1gs1.Direct(cmd1) 1756 if err != nil { 1757 t.Fatal(err) 1758 } 1759 fmt.Println("OK") 1760 fmt.Printf("... receive first event down message: ") 1761 waitForResultWithValue(t, gs2.v, down) 1762 fmt.Printf("... receive second event down message: ") 1763 waitForResultWithValue(t, gs2.v, down) 1764 1765 cmd = testEventCmdRegister{ 1766 event: "testEvent", 1767 messages: []gen.EventMessage{testMessageEventA{}}, 1768 } 1769 _, err = node1gs3.Direct(cmd) 1770 if err != nil { 1771 t.Fatal(err) 1772 } 1773 1774 cmd2 = testEventCmdMonitor{ 1775 event: "testEvent", 1776 } 1777 _, err = node1gs2.Direct(cmd2) 1778 if err != nil { 1779 t.Fatal(err) 1780 } 1781 fmt.Printf("... terminate event owner. must be received gen.MessageEventDown with reason 'kill': ") 1782 node1gs3.Kill() 1783 down = gen.MessageEventDown{ 1784 Event: "testEvent", 1785 Reason: "kill", 1786 } 1787 waitForResultWithValue(t, gs2.v, down) 1788 } 1789 1790 // helpers 1791 func checkCleanProcessRef(p gen.Process, ref etf.Ref) error { 1792 if p.IsMonitor(ref) { 1793 return fmt.Errorf("monitor process reference hasn't been cleaned correctly") 1794 } 1795 1796 return nil 1797 } 1798 1799 func checkCleanLinkPid(p gen.Process, pid etf.Pid) error { 1800 for _, l := range p.Links() { 1801 if l == pid { 1802 return fmt.Errorf("process link reference hasn't been cleaned correctly") 1803 } 1804 } 1805 return nil 1806 } 1807 func checkLinkPid(p gen.Process, pid etf.Pid) error { 1808 for _, l := range p.Links() { 1809 if l == pid { 1810 return nil 1811 } 1812 } 1813 return fmt.Errorf("process %s has no link to %s", p.Self(), pid) 1814 }