github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/nomad/node_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/hashicorp/net-rpc-msgpackrpc" 9 "github.com/hashicorp/nomad/nomad/mock" 10 "github.com/hashicorp/nomad/nomad/structs" 11 "github.com/hashicorp/nomad/testutil" 12 ) 13 14 func TestClientEndpoint_Register(t *testing.T) { 15 s1 := testServer(t, nil) 16 defer s1.Shutdown() 17 codec := rpcClient(t, s1) 18 testutil.WaitForLeader(t, s1.RPC) 19 20 // Create the register request 21 node := mock.Node() 22 req := &structs.NodeRegisterRequest{ 23 Node: node, 24 WriteRequest: structs.WriteRequest{Region: "global"}, 25 } 26 27 // Fetch the response 28 var resp structs.GenericResponse 29 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil { 30 t.Fatalf("err: %v", err) 31 } 32 if resp.Index == 0 { 33 t.Fatalf("bad index: %d", resp.Index) 34 } 35 36 // Check for the node in the FSM 37 state := s1.fsm.State() 38 out, err := state.NodeByID(node.ID) 39 if err != nil { 40 t.Fatalf("err: %v", err) 41 } 42 if out == nil { 43 t.Fatalf("expected node") 44 } 45 if out.CreateIndex != resp.Index { 46 t.Fatalf("index mis-match") 47 } 48 } 49 50 func TestClientEndpoint_Deregister(t *testing.T) { 51 s1 := testServer(t, nil) 52 defer s1.Shutdown() 53 codec := rpcClient(t, s1) 54 testutil.WaitForLeader(t, s1.RPC) 55 56 // Create the register request 57 node := mock.Node() 58 reg := &structs.NodeRegisterRequest{ 59 Node: node, 60 WriteRequest: structs.WriteRequest{Region: "global"}, 61 } 62 63 // Fetch the response 64 var resp structs.GenericResponse 65 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 66 t.Fatalf("err: %v", err) 67 } 68 69 // Deregister 70 dereg := &structs.NodeDeregisterRequest{ 71 NodeID: node.ID, 72 WriteRequest: structs.WriteRequest{Region: "global"}, 73 } 74 var resp2 structs.GenericResponse 75 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp2); err != nil { 76 t.Fatalf("err: %v", err) 77 } 78 if resp2.Index == 0 { 79 t.Fatalf("bad index: %d", resp2.Index) 80 } 81 82 // Check for the node in the FSM 83 state := s1.fsm.State() 84 out, err := state.NodeByID(node.ID) 85 if err != nil { 86 t.Fatalf("err: %v", err) 87 } 88 if out != nil { 89 t.Fatalf("unexpected node") 90 } 91 } 92 93 func TestClientEndpoint_UpdateStatus(t *testing.T) { 94 s1 := testServer(t, nil) 95 defer s1.Shutdown() 96 codec := rpcClient(t, s1) 97 testutil.WaitForLeader(t, s1.RPC) 98 99 // Create the register request 100 node := mock.Node() 101 reg := &structs.NodeRegisterRequest{ 102 Node: node, 103 WriteRequest: structs.WriteRequest{Region: "global"}, 104 } 105 106 // Fetch the response 107 var resp structs.NodeUpdateResponse 108 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 109 t.Fatalf("err: %v", err) 110 } 111 112 // Check for heartbeat interval 113 ttl := resp.HeartbeatTTL 114 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 115 t.Fatalf("bad: %#v", ttl) 116 } 117 118 // Update the status 119 dereg := &structs.NodeUpdateStatusRequest{ 120 NodeID: node.ID, 121 Status: structs.NodeStatusInit, 122 WriteRequest: structs.WriteRequest{Region: "global"}, 123 } 124 var resp2 structs.NodeUpdateResponse 125 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 126 t.Fatalf("err: %v", err) 127 } 128 if resp2.Index == 0 { 129 t.Fatalf("bad index: %d", resp2.Index) 130 } 131 132 // Check for heartbeat interval 133 ttl = resp2.HeartbeatTTL 134 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 135 t.Fatalf("bad: %#v", ttl) 136 } 137 138 // Check for the node in the FSM 139 state := s1.fsm.State() 140 out, err := state.NodeByID(node.ID) 141 if err != nil { 142 t.Fatalf("err: %v", err) 143 } 144 if out == nil { 145 t.Fatalf("expected node") 146 } 147 if out.ModifyIndex != resp2.Index { 148 t.Fatalf("index mis-match") 149 } 150 } 151 152 func TestClientEndpoint_UpdateStatus_GetEvals(t *testing.T) { 153 s1 := testServer(t, nil) 154 defer s1.Shutdown() 155 codec := rpcClient(t, s1) 156 testutil.WaitForLeader(t, s1.RPC) 157 158 // Register a system job. 159 job := mock.SystemJob() 160 state := s1.fsm.State() 161 if err := state.UpsertJob(1, job); err != nil { 162 t.Fatalf("err: %v", err) 163 } 164 165 // Create the register request 166 node := mock.Node() 167 node.Status = structs.NodeStatusInit 168 reg := &structs.NodeRegisterRequest{ 169 Node: node, 170 WriteRequest: structs.WriteRequest{Region: "global"}, 171 } 172 173 // Fetch the response 174 var resp structs.NodeUpdateResponse 175 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 176 t.Fatalf("err: %v", err) 177 } 178 179 // Check for heartbeat interval 180 ttl := resp.HeartbeatTTL 181 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 182 t.Fatalf("bad: %#v", ttl) 183 } 184 185 // Update the status 186 update := &structs.NodeUpdateStatusRequest{ 187 NodeID: node.ID, 188 Status: structs.NodeStatusReady, 189 WriteRequest: structs.WriteRequest{Region: "global"}, 190 } 191 var resp2 structs.NodeUpdateResponse 192 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", update, &resp2); err != nil { 193 t.Fatalf("err: %v", err) 194 } 195 if resp2.Index == 0 { 196 t.Fatalf("bad index: %d", resp2.Index) 197 } 198 199 // Check for an eval caused by the system job. 200 if len(resp2.EvalIDs) != 1 { 201 t.Fatalf("expected one eval; got %#v", resp2.EvalIDs) 202 } 203 204 evalID := resp2.EvalIDs[0] 205 eval, err := state.EvalByID(evalID) 206 if err != nil { 207 t.Fatalf("could not get eval %v", evalID) 208 } 209 210 if eval.Type != "system" { 211 t.Fatalf("unexpected eval type; got %v; want %q", eval.Type, "system") 212 } 213 214 // Check for heartbeat interval 215 ttl = resp2.HeartbeatTTL 216 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 217 t.Fatalf("bad: %#v", ttl) 218 } 219 220 // Check for the node in the FSM 221 out, err := state.NodeByID(node.ID) 222 if err != nil { 223 t.Fatalf("err: %v", err) 224 } 225 if out == nil { 226 t.Fatalf("expected node") 227 } 228 if out.ModifyIndex != resp2.Index { 229 t.Fatalf("index mis-match") 230 } 231 } 232 233 func TestClientEndpoint_UpdateStatus_HeartbeatOnly(t *testing.T) { 234 s1 := testServer(t, nil) 235 defer s1.Shutdown() 236 codec := rpcClient(t, s1) 237 testutil.WaitForLeader(t, s1.RPC) 238 239 // Create the register request 240 node := mock.Node() 241 reg := &structs.NodeRegisterRequest{ 242 Node: node, 243 WriteRequest: structs.WriteRequest{Region: "global"}, 244 } 245 246 // Fetch the response 247 var resp structs.NodeUpdateResponse 248 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 249 t.Fatalf("err: %v", err) 250 } 251 252 // Check for heartbeat interval 253 ttl := resp.HeartbeatTTL 254 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 255 t.Fatalf("bad: %#v", ttl) 256 } 257 258 // Update the status, static state 259 dereg := &structs.NodeUpdateStatusRequest{ 260 NodeID: node.ID, 261 Status: node.Status, 262 WriteRequest: structs.WriteRequest{Region: "global"}, 263 } 264 var resp2 structs.NodeUpdateResponse 265 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 266 t.Fatalf("err: %v", err) 267 } 268 if resp2.Index != 0 { 269 t.Fatalf("bad index: %d", resp2.Index) 270 } 271 272 // Check for heartbeat interval 273 ttl = resp2.HeartbeatTTL 274 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 275 t.Fatalf("bad: %#v", ttl) 276 } 277 } 278 279 func TestClientEndpoint_UpdateDrain(t *testing.T) { 280 s1 := testServer(t, nil) 281 defer s1.Shutdown() 282 codec := rpcClient(t, s1) 283 testutil.WaitForLeader(t, s1.RPC) 284 285 // Create the register request 286 node := mock.Node() 287 reg := &structs.NodeRegisterRequest{ 288 Node: node, 289 WriteRequest: structs.WriteRequest{Region: "global"}, 290 } 291 292 // Fetch the response 293 var resp structs.NodeUpdateResponse 294 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 295 t.Fatalf("err: %v", err) 296 } 297 298 // Update the status 299 dereg := &structs.NodeUpdateDrainRequest{ 300 NodeID: node.ID, 301 Drain: true, 302 WriteRequest: structs.WriteRequest{Region: "global"}, 303 } 304 var resp2 structs.NodeDrainUpdateResponse 305 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp2); err != nil { 306 t.Fatalf("err: %v", err) 307 } 308 if resp2.Index == 0 { 309 t.Fatalf("bad index: %d", resp2.Index) 310 } 311 312 // Check for the node in the FSM 313 state := s1.fsm.State() 314 out, err := state.NodeByID(node.ID) 315 if err != nil { 316 t.Fatalf("err: %v", err) 317 } 318 if !out.Drain { 319 t.Fatalf("bad: %#v", out) 320 } 321 } 322 323 func TestClientEndpoint_GetNode(t *testing.T) { 324 s1 := testServer(t, nil) 325 defer s1.Shutdown() 326 codec := rpcClient(t, s1) 327 testutil.WaitForLeader(t, s1.RPC) 328 329 // Create the register request 330 node := mock.Node() 331 reg := &structs.NodeRegisterRequest{ 332 Node: node, 333 WriteRequest: structs.WriteRequest{Region: "global"}, 334 } 335 336 // Fetch the response 337 var resp structs.GenericResponse 338 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 339 t.Fatalf("err: %v", err) 340 } 341 node.CreateIndex = resp.Index 342 node.ModifyIndex = resp.Index 343 344 // Lookup the node 345 get := &structs.NodeSpecificRequest{ 346 NodeID: node.ID, 347 QueryOptions: structs.QueryOptions{Region: "global"}, 348 } 349 var resp2 structs.SingleNodeResponse 350 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil { 351 t.Fatalf("err: %v", err) 352 } 353 if resp2.Index != resp.Index { 354 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 355 } 356 357 if !reflect.DeepEqual(node, resp2.Node) { 358 t.Fatalf("bad: %#v %#v", node, resp2.Node) 359 } 360 361 // Lookup non-existing node 362 get.NodeID = "foobarbaz" 363 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil { 364 t.Fatalf("err: %v", err) 365 } 366 if resp2.Index != resp.Index { 367 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 368 } 369 if resp2.Node != nil { 370 t.Fatalf("unexpected node") 371 } 372 } 373 374 func TestClientEndpoint_GetAllocs(t *testing.T) { 375 s1 := testServer(t, nil) 376 defer s1.Shutdown() 377 codec := rpcClient(t, s1) 378 testutil.WaitForLeader(t, s1.RPC) 379 380 // Create the register request 381 node := mock.Node() 382 reg := &structs.NodeRegisterRequest{ 383 Node: node, 384 WriteRequest: structs.WriteRequest{Region: "global"}, 385 } 386 387 // Fetch the response 388 var resp structs.GenericResponse 389 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 390 t.Fatalf("err: %v", err) 391 } 392 node.CreateIndex = resp.Index 393 node.ModifyIndex = resp.Index 394 395 // Inject fake evaluations 396 alloc := mock.Alloc() 397 alloc.NodeID = node.ID 398 state := s1.fsm.State() 399 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 400 if err != nil { 401 t.Fatalf("err: %v", err) 402 } 403 404 // Lookup the allocs 405 get := &structs.NodeSpecificRequest{ 406 NodeID: node.ID, 407 QueryOptions: structs.QueryOptions{Region: "global"}, 408 } 409 var resp2 structs.NodeAllocsResponse 410 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil { 411 t.Fatalf("err: %v", err) 412 } 413 if resp2.Index != 100 { 414 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 415 } 416 417 if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID { 418 t.Fatalf("bad: %#v", resp2.Allocs) 419 } 420 421 // Lookup non-existing node 422 get.NodeID = "foobarbaz" 423 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil { 424 t.Fatalf("err: %v", err) 425 } 426 if resp2.Index != 100 { 427 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 428 } 429 if len(resp2.Allocs) != 0 { 430 t.Fatalf("unexpected node") 431 } 432 } 433 434 func TestClientEndpoint_GetAllocs_Blocking(t *testing.T) { 435 s1 := testServer(t, nil) 436 defer s1.Shutdown() 437 codec := rpcClient(t, s1) 438 testutil.WaitForLeader(t, s1.RPC) 439 440 // Create the register request 441 node := mock.Node() 442 reg := &structs.NodeRegisterRequest{ 443 Node: node, 444 WriteRequest: structs.WriteRequest{Region: "global"}, 445 } 446 447 // Fetch the response 448 var resp structs.GenericResponse 449 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 450 t.Fatalf("err: %v", err) 451 } 452 node.CreateIndex = resp.Index 453 node.ModifyIndex = resp.Index 454 455 // Inject fake evaluations async 456 alloc := mock.Alloc() 457 alloc.NodeID = node.ID 458 state := s1.fsm.State() 459 start := time.Now() 460 go func() { 461 time.Sleep(100 * time.Millisecond) 462 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 463 if err != nil { 464 t.Fatalf("err: %v", err) 465 } 466 }() 467 468 // Lookup the allocs in a blocking query 469 get := &structs.NodeSpecificRequest{ 470 NodeID: node.ID, 471 QueryOptions: structs.QueryOptions{ 472 Region: "global", 473 MinQueryIndex: 50, 474 MaxQueryTime: time.Second, 475 }, 476 } 477 var resp2 structs.NodeAllocsResponse 478 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil { 479 t.Fatalf("err: %v", err) 480 } 481 482 // Should block at least 100ms 483 if time.Since(start) < 100*time.Millisecond { 484 t.Fatalf("too fast") 485 } 486 487 if resp2.Index != 100 { 488 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 489 } 490 491 if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID { 492 t.Fatalf("bad: %#v", resp2.Allocs) 493 } 494 } 495 496 func TestClientEndpoint_UpdateAlloc(t *testing.T) { 497 s1 := testServer(t, nil) 498 defer s1.Shutdown() 499 codec := rpcClient(t, s1) 500 testutil.WaitForLeader(t, s1.RPC) 501 502 // Create the register request 503 node := mock.Node() 504 reg := &structs.NodeRegisterRequest{ 505 Node: node, 506 WriteRequest: structs.WriteRequest{Region: "global"}, 507 } 508 509 // Fetch the response 510 var resp structs.GenericResponse 511 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 512 t.Fatalf("err: %v", err) 513 } 514 515 // Inject fake evaluations 516 alloc := mock.Alloc() 517 alloc.NodeID = node.ID 518 state := s1.fsm.State() 519 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 520 if err != nil { 521 t.Fatalf("err: %v", err) 522 } 523 524 // Attempt update 525 clientAlloc := new(structs.Allocation) 526 *clientAlloc = *alloc 527 clientAlloc.ClientStatus = structs.AllocClientStatusFailed 528 529 // Update the alloc 530 update := &structs.AllocUpdateRequest{ 531 Alloc: []*structs.Allocation{clientAlloc}, 532 WriteRequest: structs.WriteRequest{Region: "global"}, 533 } 534 var resp2 structs.NodeAllocsResponse 535 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateAlloc", update, &resp2); err != nil { 536 t.Fatalf("err: %v", err) 537 } 538 if resp2.Index == 0 { 539 t.Fatalf("Bad index: %d", resp2.Index) 540 } 541 542 // Lookup the alloc 543 out, err := state.AllocByID(alloc.ID) 544 if err != nil { 545 t.Fatalf("err: %v", err) 546 } 547 if out.ClientStatus != structs.AllocClientStatusFailed { 548 t.Fatalf("Bad: %#v", out) 549 } 550 } 551 552 func TestClientEndpoint_CreateNodeEvals(t *testing.T) { 553 s1 := testServer(t, nil) 554 defer s1.Shutdown() 555 testutil.WaitForLeader(t, s1.RPC) 556 557 // Inject fake evaluations 558 alloc := mock.Alloc() 559 state := s1.fsm.State() 560 if err := state.UpsertAllocs(1, []*structs.Allocation{alloc}); err != nil { 561 t.Fatalf("err: %v", err) 562 } 563 564 // Inject a fake system job. 565 job := mock.SystemJob() 566 if err := state.UpsertJob(1, job); err != nil { 567 t.Fatalf("err: %v", err) 568 } 569 570 // Create some evaluations 571 ids, index, err := s1.endpoints.Node.createNodeEvals(alloc.NodeID, 1) 572 if err != nil { 573 t.Fatalf("err: %v", err) 574 } 575 if index == 0 { 576 t.Fatalf("bad: %d", index) 577 } 578 if len(ids) != 2 { 579 t.Fatalf("bad: %s", ids) 580 } 581 582 // Lookup the evaluations 583 evalByType := make(map[string]*structs.Evaluation, 2) 584 for _, id := range ids { 585 eval, err := state.EvalByID(id) 586 if err != nil { 587 t.Fatalf("err: %v", err) 588 } 589 if eval == nil { 590 t.Fatalf("expected eval") 591 } 592 593 if old, ok := evalByType[eval.Type]; ok { 594 t.Fatalf("multiple evals of the same type: %v and %v", old, eval) 595 } 596 597 evalByType[eval.Type] = eval 598 } 599 600 if len(evalByType) != 2 { 601 t.Fatalf("Expected a service and system job; got %#v", evalByType) 602 } 603 604 // Ensure the evals are correct. 605 for schedType, eval := range evalByType { 606 expPriority := alloc.Job.Priority 607 expJobID := alloc.JobID 608 if schedType == "system" { 609 expPriority = job.Priority 610 expJobID = job.ID 611 } 612 613 if eval.CreateIndex != index { 614 t.Fatalf("CreateIndex mis-match on type %v: %#v", schedType, eval) 615 } 616 if eval.TriggeredBy != structs.EvalTriggerNodeUpdate { 617 t.Fatalf("TriggeredBy incorrect on type %v: %#v", schedType, eval) 618 } 619 if eval.NodeID != alloc.NodeID { 620 t.Fatalf("NodeID incorrect on type %v: %#v", schedType, eval) 621 } 622 if eval.NodeModifyIndex != 1 { 623 t.Fatalf("NodeModifyIndex incorrect on type %v: %#v", schedType, eval) 624 } 625 if eval.Status != structs.EvalStatusPending { 626 t.Fatalf("Status incorrect on type %v: %#v", schedType, eval) 627 } 628 if eval.Priority != expPriority { 629 t.Fatalf("Priority incorrect on type %v: %#v", schedType, eval) 630 } 631 if eval.JobID != expJobID { 632 t.Fatalf("JobID incorrect on type %v: %#v", schedType, eval) 633 } 634 } 635 } 636 637 func TestClientEndpoint_Evaluate(t *testing.T) { 638 s1 := testServer(t, func(c *Config) { 639 c.NumSchedulers = 0 // Prevent automatic dequeue 640 }) 641 defer s1.Shutdown() 642 codec := rpcClient(t, s1) 643 testutil.WaitForLeader(t, s1.RPC) 644 645 // Inject fake evaluations 646 alloc := mock.Alloc() 647 node := mock.Node() 648 node.ID = alloc.NodeID 649 state := s1.fsm.State() 650 err := state.UpsertNode(1, node) 651 if err != nil { 652 t.Fatalf("err: %v", err) 653 } 654 err = state.UpsertAllocs(2, []*structs.Allocation{alloc}) 655 if err != nil { 656 t.Fatalf("err: %v", err) 657 } 658 659 // Re-evaluate 660 req := &structs.NodeEvaluateRequest{ 661 NodeID: alloc.NodeID, 662 WriteRequest: structs.WriteRequest{Region: "global"}, 663 } 664 665 // Fetch the response 666 var resp structs.NodeUpdateResponse 667 if err := msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp); err != nil { 668 t.Fatalf("err: %v", err) 669 } 670 if resp.Index == 0 { 671 t.Fatalf("bad index: %d", resp.Index) 672 } 673 674 // Create some evaluations 675 ids := resp.EvalIDs 676 if len(ids) != 1 { 677 t.Fatalf("bad: %s", ids) 678 } 679 680 // Lookup the evaluation 681 eval, err := state.EvalByID(ids[0]) 682 if err != nil { 683 t.Fatalf("err: %v", err) 684 } 685 if eval == nil { 686 t.Fatalf("expected eval") 687 } 688 if eval.CreateIndex != resp.Index { 689 t.Fatalf("index mis-match") 690 } 691 692 if eval.Priority != alloc.Job.Priority { 693 t.Fatalf("bad: %#v", eval) 694 } 695 if eval.Type != alloc.Job.Type { 696 t.Fatalf("bad: %#v", eval) 697 } 698 if eval.TriggeredBy != structs.EvalTriggerNodeUpdate { 699 t.Fatalf("bad: %#v", eval) 700 } 701 if eval.JobID != alloc.JobID { 702 t.Fatalf("bad: %#v", eval) 703 } 704 if eval.NodeID != alloc.NodeID { 705 t.Fatalf("bad: %#v", eval) 706 } 707 if eval.NodeModifyIndex != 1 { 708 t.Fatalf("bad: %#v", eval) 709 } 710 if eval.Status != structs.EvalStatusPending { 711 t.Fatalf("bad: %#v", eval) 712 } 713 } 714 715 func TestClientEndpoint_ListNodes(t *testing.T) { 716 s1 := testServer(t, nil) 717 defer s1.Shutdown() 718 codec := rpcClient(t, s1) 719 testutil.WaitForLeader(t, s1.RPC) 720 721 // Create the register request 722 node := mock.Node() 723 reg := &structs.NodeRegisterRequest{ 724 Node: node, 725 WriteRequest: structs.WriteRequest{Region: "global"}, 726 } 727 728 // Fetch the response 729 var resp structs.GenericResponse 730 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 731 t.Fatalf("err: %v", err) 732 } 733 node.CreateIndex = resp.Index 734 node.ModifyIndex = resp.Index 735 736 // Lookup the node 737 get := &structs.NodeListRequest{ 738 QueryOptions: structs.QueryOptions{Region: "global"}, 739 } 740 var resp2 structs.NodeListResponse 741 if err := msgpackrpc.CallWithCodec(codec, "Node.List", get, &resp2); err != nil { 742 t.Fatalf("err: %v", err) 743 } 744 if resp2.Index != resp.Index { 745 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 746 } 747 748 if len(resp2.Nodes) != 1 { 749 t.Fatalf("bad: %#v", resp2.Nodes) 750 } 751 if resp2.Nodes[0].ID != node.ID { 752 t.Fatalf("bad: %#v", resp2.Nodes[0]) 753 } 754 }