github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/nomad/structs/diff_test.go (about) 1 package structs 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 ) 8 9 func TestJobDiff(t *testing.T) { 10 cases := []struct { 11 Old, New *Job 12 Expected *JobDiff 13 Error bool 14 Contextual bool 15 }{ 16 { 17 Old: nil, 18 New: nil, 19 Expected: &JobDiff{ 20 Type: DiffTypeNone, 21 }, 22 }, 23 { 24 // Different IDs 25 Old: &Job{ 26 ID: "foo", 27 }, 28 New: &Job{ 29 ID: "bar", 30 }, 31 Error: true, 32 }, 33 { 34 // Primitive only that is the same 35 Old: &Job{ 36 Region: "foo", 37 ID: "foo", 38 Name: "foo", 39 Type: "batch", 40 Priority: 10, 41 AllAtOnce: true, 42 Meta: map[string]string{ 43 "foo": "bar", 44 }, 45 }, 46 New: &Job{ 47 Region: "foo", 48 ID: "foo", 49 Name: "foo", 50 Type: "batch", 51 Priority: 10, 52 AllAtOnce: true, 53 Meta: map[string]string{ 54 "foo": "bar", 55 }, 56 }, 57 Expected: &JobDiff{ 58 Type: DiffTypeNone, 59 ID: "foo", 60 }, 61 }, 62 { 63 // Primitive only that is has diffs 64 Old: &Job{ 65 Region: "foo", 66 ID: "foo", 67 Name: "foo", 68 Type: "batch", 69 Priority: 10, 70 AllAtOnce: true, 71 Meta: map[string]string{ 72 "foo": "bar", 73 }, 74 }, 75 New: &Job{ 76 Region: "bar", 77 ID: "foo", 78 Name: "bar", 79 Type: "system", 80 Priority: 100, 81 AllAtOnce: false, 82 Meta: map[string]string{ 83 "foo": "baz", 84 }, 85 }, 86 Expected: &JobDiff{ 87 Type: DiffTypeEdited, 88 ID: "foo", 89 Fields: []*FieldDiff{ 90 { 91 Type: DiffTypeEdited, 92 Name: "AllAtOnce", 93 Old: "true", 94 New: "false", 95 }, 96 { 97 Type: DiffTypeEdited, 98 Name: "Meta[foo]", 99 Old: "bar", 100 New: "baz", 101 }, 102 { 103 Type: DiffTypeEdited, 104 Name: "Name", 105 Old: "foo", 106 New: "bar", 107 }, 108 { 109 Type: DiffTypeEdited, 110 Name: "Priority", 111 Old: "10", 112 New: "100", 113 }, 114 { 115 Type: DiffTypeEdited, 116 Name: "Region", 117 Old: "foo", 118 New: "bar", 119 }, 120 { 121 Type: DiffTypeEdited, 122 Name: "Type", 123 Old: "batch", 124 New: "system", 125 }, 126 }, 127 }, 128 }, 129 { 130 // Primitive only deleted job 131 Old: &Job{ 132 Region: "foo", 133 ID: "foo", 134 Name: "foo", 135 Type: "batch", 136 Priority: 10, 137 AllAtOnce: true, 138 Meta: map[string]string{ 139 "foo": "bar", 140 }, 141 }, 142 New: nil, 143 Expected: &JobDiff{ 144 Type: DiffTypeDeleted, 145 ID: "foo", 146 Fields: []*FieldDiff{ 147 { 148 Type: DiffTypeDeleted, 149 Name: "AllAtOnce", 150 Old: "true", 151 New: "", 152 }, 153 { 154 Type: DiffTypeDeleted, 155 Name: "Meta[foo]", 156 Old: "bar", 157 New: "", 158 }, 159 { 160 Type: DiffTypeDeleted, 161 Name: "Name", 162 Old: "foo", 163 New: "", 164 }, 165 { 166 Type: DiffTypeDeleted, 167 Name: "Priority", 168 Old: "10", 169 New: "", 170 }, 171 { 172 Type: DiffTypeDeleted, 173 Name: "Region", 174 Old: "foo", 175 New: "", 176 }, 177 { 178 Type: DiffTypeDeleted, 179 Name: "Type", 180 Old: "batch", 181 New: "", 182 }, 183 }, 184 Objects: []*ObjectDiff{ 185 { 186 Type: DiffTypeDeleted, 187 Name: "Update", 188 Fields: []*FieldDiff{ 189 { 190 Type: DiffTypeDeleted, 191 Name: "MaxParallel", 192 Old: "0", 193 New: "", 194 }, 195 { 196 Type: DiffTypeDeleted, 197 Name: "Stagger", 198 Old: "0", 199 New: "", 200 }, 201 }, 202 }, 203 }, 204 }, 205 }, 206 { 207 // Primitive only added job 208 Old: nil, 209 New: &Job{ 210 Region: "foo", 211 ID: "foo", 212 Name: "foo", 213 Type: "batch", 214 Priority: 10, 215 AllAtOnce: true, 216 Meta: map[string]string{ 217 "foo": "bar", 218 }, 219 }, 220 Expected: &JobDiff{ 221 Type: DiffTypeAdded, 222 ID: "foo", 223 Fields: []*FieldDiff{ 224 { 225 Type: DiffTypeAdded, 226 Name: "AllAtOnce", 227 Old: "", 228 New: "true", 229 }, 230 { 231 Type: DiffTypeAdded, 232 Name: "Meta[foo]", 233 Old: "", 234 New: "bar", 235 }, 236 { 237 Type: DiffTypeAdded, 238 Name: "Name", 239 Old: "", 240 New: "foo", 241 }, 242 { 243 Type: DiffTypeAdded, 244 Name: "Priority", 245 Old: "", 246 New: "10", 247 }, 248 { 249 Type: DiffTypeAdded, 250 Name: "Region", 251 Old: "", 252 New: "foo", 253 }, 254 { 255 Type: DiffTypeAdded, 256 Name: "Type", 257 Old: "", 258 New: "batch", 259 }, 260 }, 261 Objects: []*ObjectDiff{ 262 { 263 Type: DiffTypeAdded, 264 Name: "Update", 265 Fields: []*FieldDiff{ 266 { 267 Type: DiffTypeAdded, 268 Name: "MaxParallel", 269 Old: "", 270 New: "0", 271 }, 272 { 273 Type: DiffTypeAdded, 274 Name: "Stagger", 275 Old: "", 276 New: "0", 277 }, 278 }, 279 }, 280 }, 281 }, 282 }, 283 { 284 // Map diff 285 Old: &Job{ 286 Meta: map[string]string{ 287 "foo": "foo", 288 "bar": "bar", 289 }, 290 }, 291 New: &Job{ 292 Meta: map[string]string{ 293 "bar": "bar", 294 "baz": "baz", 295 }, 296 }, 297 Expected: &JobDiff{ 298 Type: DiffTypeEdited, 299 Fields: []*FieldDiff{ 300 { 301 Type: DiffTypeAdded, 302 Name: "Meta[baz]", 303 Old: "", 304 New: "baz", 305 }, 306 { 307 Type: DiffTypeDeleted, 308 Name: "Meta[foo]", 309 Old: "foo", 310 New: "", 311 }, 312 }, 313 }, 314 }, 315 { 316 // Datacenter diff both added and removed 317 Old: &Job{ 318 Datacenters: []string{"foo", "bar"}, 319 }, 320 New: &Job{ 321 Datacenters: []string{"baz", "bar"}, 322 }, 323 Expected: &JobDiff{ 324 Type: DiffTypeEdited, 325 Objects: []*ObjectDiff{ 326 { 327 Type: DiffTypeEdited, 328 Name: "Datacenters", 329 Fields: []*FieldDiff{ 330 { 331 Type: DiffTypeAdded, 332 Name: "Datacenters", 333 Old: "", 334 New: "baz", 335 }, 336 { 337 Type: DiffTypeDeleted, 338 Name: "Datacenters", 339 Old: "foo", 340 New: "", 341 }, 342 }, 343 }, 344 }, 345 }, 346 }, 347 { 348 // Datacenter diff just added 349 Old: &Job{ 350 Datacenters: []string{"foo", "bar"}, 351 }, 352 New: &Job{ 353 Datacenters: []string{"foo", "bar", "baz"}, 354 }, 355 Expected: &JobDiff{ 356 Type: DiffTypeEdited, 357 Objects: []*ObjectDiff{ 358 { 359 Type: DiffTypeAdded, 360 Name: "Datacenters", 361 Fields: []*FieldDiff{ 362 { 363 Type: DiffTypeAdded, 364 Name: "Datacenters", 365 Old: "", 366 New: "baz", 367 }, 368 }, 369 }, 370 }, 371 }, 372 }, 373 { 374 // Datacenter diff just deleted 375 Old: &Job{ 376 Datacenters: []string{"foo", "bar"}, 377 }, 378 New: &Job{ 379 Datacenters: []string{"foo"}, 380 }, 381 Expected: &JobDiff{ 382 Type: DiffTypeEdited, 383 Objects: []*ObjectDiff{ 384 { 385 Type: DiffTypeDeleted, 386 Name: "Datacenters", 387 Fields: []*FieldDiff{ 388 { 389 Type: DiffTypeDeleted, 390 Name: "Datacenters", 391 Old: "bar", 392 New: "", 393 }, 394 }, 395 }, 396 }, 397 }, 398 }, 399 { 400 // Update strategy edited 401 Old: &Job{ 402 Update: UpdateStrategy{ 403 Stagger: 10 * time.Second, 404 MaxParallel: 5, 405 }, 406 }, 407 New: &Job{ 408 Update: UpdateStrategy{ 409 Stagger: 60 * time.Second, 410 MaxParallel: 10, 411 }, 412 }, 413 Expected: &JobDiff{ 414 Type: DiffTypeEdited, 415 Objects: []*ObjectDiff{ 416 { 417 Type: DiffTypeEdited, 418 Name: "Update", 419 Fields: []*FieldDiff{ 420 { 421 Type: DiffTypeEdited, 422 Name: "MaxParallel", 423 Old: "5", 424 New: "10", 425 }, 426 { 427 Type: DiffTypeEdited, 428 Name: "Stagger", 429 Old: "10000000000", 430 New: "60000000000", 431 }, 432 }, 433 }, 434 }, 435 }, 436 }, 437 { 438 // Update strategy edited with context 439 Contextual: true, 440 Old: &Job{ 441 Update: UpdateStrategy{ 442 Stagger: 10 * time.Second, 443 MaxParallel: 5, 444 }, 445 }, 446 New: &Job{ 447 Update: UpdateStrategy{ 448 Stagger: 60 * time.Second, 449 MaxParallel: 5, 450 }, 451 }, 452 Expected: &JobDiff{ 453 Type: DiffTypeEdited, 454 Objects: []*ObjectDiff{ 455 { 456 Type: DiffTypeEdited, 457 Name: "Update", 458 Fields: []*FieldDiff{ 459 { 460 Type: DiffTypeNone, 461 Name: "MaxParallel", 462 Old: "5", 463 New: "5", 464 }, 465 { 466 Type: DiffTypeEdited, 467 Name: "Stagger", 468 Old: "10000000000", 469 New: "60000000000", 470 }, 471 }, 472 }, 473 }, 474 }, 475 }, 476 { 477 // Periodic added 478 Old: &Job{}, 479 New: &Job{ 480 Periodic: &PeriodicConfig{ 481 Enabled: false, 482 Spec: "*/15 * * * * *", 483 SpecType: "foo", 484 ProhibitOverlap: false, 485 }, 486 }, 487 Expected: &JobDiff{ 488 Type: DiffTypeEdited, 489 Objects: []*ObjectDiff{ 490 { 491 Type: DiffTypeAdded, 492 Name: "Periodic", 493 Fields: []*FieldDiff{ 494 { 495 Type: DiffTypeAdded, 496 Name: "Enabled", 497 Old: "", 498 New: "false", 499 }, 500 { 501 Type: DiffTypeAdded, 502 Name: "ProhibitOverlap", 503 Old: "", 504 New: "false", 505 }, 506 { 507 Type: DiffTypeAdded, 508 Name: "Spec", 509 Old: "", 510 New: "*/15 * * * * *", 511 }, 512 { 513 Type: DiffTypeAdded, 514 Name: "SpecType", 515 Old: "", 516 New: "foo", 517 }, 518 }, 519 }, 520 }, 521 }, 522 }, 523 { 524 // Periodic deleted 525 Old: &Job{ 526 Periodic: &PeriodicConfig{ 527 Enabled: false, 528 Spec: "*/15 * * * * *", 529 SpecType: "foo", 530 ProhibitOverlap: false, 531 }, 532 }, 533 New: &Job{}, 534 Expected: &JobDiff{ 535 Type: DiffTypeEdited, 536 Objects: []*ObjectDiff{ 537 { 538 Type: DiffTypeDeleted, 539 Name: "Periodic", 540 Fields: []*FieldDiff{ 541 { 542 Type: DiffTypeDeleted, 543 Name: "Enabled", 544 Old: "false", 545 New: "", 546 }, 547 { 548 Type: DiffTypeDeleted, 549 Name: "ProhibitOverlap", 550 Old: "false", 551 New: "", 552 }, 553 { 554 Type: DiffTypeDeleted, 555 Name: "Spec", 556 Old: "*/15 * * * * *", 557 New: "", 558 }, 559 { 560 Type: DiffTypeDeleted, 561 Name: "SpecType", 562 Old: "foo", 563 New: "", 564 }, 565 }, 566 }, 567 }, 568 }, 569 }, 570 { 571 // Periodic edited 572 Old: &Job{ 573 Periodic: &PeriodicConfig{ 574 Enabled: false, 575 Spec: "*/15 * * * * *", 576 SpecType: "foo", 577 ProhibitOverlap: false, 578 }, 579 }, 580 New: &Job{ 581 Periodic: &PeriodicConfig{ 582 Enabled: true, 583 Spec: "* * * * * *", 584 SpecType: "cron", 585 ProhibitOverlap: true, 586 }, 587 }, 588 Expected: &JobDiff{ 589 Type: DiffTypeEdited, 590 Objects: []*ObjectDiff{ 591 { 592 Type: DiffTypeEdited, 593 Name: "Periodic", 594 Fields: []*FieldDiff{ 595 { 596 Type: DiffTypeEdited, 597 Name: "Enabled", 598 Old: "false", 599 New: "true", 600 }, 601 { 602 Type: DiffTypeEdited, 603 Name: "ProhibitOverlap", 604 Old: "false", 605 New: "true", 606 }, 607 { 608 Type: DiffTypeEdited, 609 Name: "Spec", 610 Old: "*/15 * * * * *", 611 New: "* * * * * *", 612 }, 613 { 614 Type: DiffTypeEdited, 615 Name: "SpecType", 616 Old: "foo", 617 New: "cron", 618 }, 619 }, 620 }, 621 }, 622 }, 623 }, 624 { 625 // Periodic edited with context 626 Contextual: true, 627 Old: &Job{ 628 Periodic: &PeriodicConfig{ 629 Enabled: false, 630 Spec: "*/15 * * * * *", 631 SpecType: "foo", 632 ProhibitOverlap: false, 633 }, 634 }, 635 New: &Job{ 636 Periodic: &PeriodicConfig{ 637 Enabled: true, 638 Spec: "* * * * * *", 639 SpecType: "foo", 640 ProhibitOverlap: false, 641 }, 642 }, 643 Expected: &JobDiff{ 644 Type: DiffTypeEdited, 645 Objects: []*ObjectDiff{ 646 { 647 Type: DiffTypeEdited, 648 Name: "Periodic", 649 Fields: []*FieldDiff{ 650 { 651 Type: DiffTypeEdited, 652 Name: "Enabled", 653 Old: "false", 654 New: "true", 655 }, 656 { 657 Type: DiffTypeNone, 658 Name: "ProhibitOverlap", 659 Old: "false", 660 New: "false", 661 }, 662 { 663 Type: DiffTypeEdited, 664 Name: "Spec", 665 Old: "*/15 * * * * *", 666 New: "* * * * * *", 667 }, 668 { 669 Type: DiffTypeNone, 670 Name: "SpecType", 671 Old: "foo", 672 New: "foo", 673 }, 674 }, 675 }, 676 }, 677 }, 678 }, 679 { 680 // Constraints edited 681 Old: &Job{ 682 Constraints: []*Constraint{ 683 { 684 LTarget: "foo", 685 RTarget: "foo", 686 Operand: "foo", 687 str: "foo", 688 }, 689 { 690 LTarget: "bar", 691 RTarget: "bar", 692 Operand: "bar", 693 str: "bar", 694 }, 695 }, 696 }, 697 New: &Job{ 698 Constraints: []*Constraint{ 699 { 700 LTarget: "foo", 701 RTarget: "foo", 702 Operand: "foo", 703 str: "foo", 704 }, 705 { 706 LTarget: "baz", 707 RTarget: "baz", 708 Operand: "baz", 709 str: "baz", 710 }, 711 }, 712 }, 713 Expected: &JobDiff{ 714 Type: DiffTypeEdited, 715 Objects: []*ObjectDiff{ 716 { 717 Type: DiffTypeAdded, 718 Name: "Constraint", 719 Fields: []*FieldDiff{ 720 { 721 Type: DiffTypeAdded, 722 Name: "LTarget", 723 Old: "", 724 New: "baz", 725 }, 726 { 727 Type: DiffTypeAdded, 728 Name: "Operand", 729 Old: "", 730 New: "baz", 731 }, 732 { 733 Type: DiffTypeAdded, 734 Name: "RTarget", 735 Old: "", 736 New: "baz", 737 }, 738 }, 739 }, 740 { 741 Type: DiffTypeDeleted, 742 Name: "Constraint", 743 Fields: []*FieldDiff{ 744 { 745 Type: DiffTypeDeleted, 746 Name: "LTarget", 747 Old: "bar", 748 New: "", 749 }, 750 { 751 Type: DiffTypeDeleted, 752 Name: "Operand", 753 Old: "bar", 754 New: "", 755 }, 756 { 757 Type: DiffTypeDeleted, 758 Name: "RTarget", 759 Old: "bar", 760 New: "", 761 }, 762 }, 763 }, 764 }, 765 }, 766 }, 767 { 768 // Task groups edited 769 Old: &Job{ 770 TaskGroups: []*TaskGroup{ 771 { 772 Name: "foo", 773 Count: 1, 774 }, 775 { 776 Name: "bar", 777 Count: 1, 778 }, 779 { 780 Name: "baz", 781 Count: 1, 782 }, 783 }, 784 }, 785 New: &Job{ 786 TaskGroups: []*TaskGroup{ 787 { 788 Name: "bar", 789 Count: 1, 790 }, 791 { 792 Name: "baz", 793 Count: 2, 794 }, 795 { 796 Name: "bam", 797 Count: 1, 798 }, 799 }, 800 }, 801 Expected: &JobDiff{ 802 Type: DiffTypeEdited, 803 TaskGroups: []*TaskGroupDiff{ 804 { 805 Type: DiffTypeAdded, 806 Name: "bam", 807 Fields: []*FieldDiff{ 808 { 809 Type: DiffTypeAdded, 810 Name: "Count", 811 Old: "", 812 New: "1", 813 }, 814 }, 815 }, 816 { 817 Type: DiffTypeNone, 818 Name: "bar", 819 }, 820 { 821 Type: DiffTypeEdited, 822 Name: "baz", 823 Fields: []*FieldDiff{ 824 { 825 Type: DiffTypeEdited, 826 Name: "Count", 827 Old: "1", 828 New: "2", 829 }, 830 }, 831 }, 832 { 833 Type: DiffTypeDeleted, 834 Name: "foo", 835 Fields: []*FieldDiff{ 836 { 837 Type: DiffTypeDeleted, 838 Name: "Count", 839 Old: "1", 840 New: "", 841 }, 842 }, 843 }, 844 }, 845 }, 846 }, 847 } 848 849 for i, c := range cases { 850 actual, err := c.Old.Diff(c.New, c.Contextual) 851 if c.Error && err == nil { 852 t.Fatalf("case %d: expected errored") 853 } else if err != nil { 854 if !c.Error { 855 t.Fatalf("case %d: errored %#v", i+1, err) 856 } else { 857 continue 858 } 859 } 860 861 if !reflect.DeepEqual(actual, c.Expected) { 862 t.Fatalf("case %d: got:\n%#v\n want:\n%#v\n", 863 i+1, actual, c.Expected) 864 } 865 } 866 } 867 868 func TestTaskGroupDiff(t *testing.T) { 869 cases := []struct { 870 Old, New *TaskGroup 871 Expected *TaskGroupDiff 872 Error bool 873 Contextual bool 874 }{ 875 { 876 Old: nil, 877 New: nil, 878 Expected: &TaskGroupDiff{ 879 Type: DiffTypeNone, 880 }, 881 }, 882 { 883 // Primitive only that has different names 884 Old: &TaskGroup{ 885 Name: "foo", 886 Count: 10, 887 Meta: map[string]string{ 888 "foo": "bar", 889 }, 890 }, 891 New: &TaskGroup{ 892 Name: "bar", 893 Count: 10, 894 Meta: map[string]string{ 895 "foo": "bar", 896 }, 897 }, 898 Error: true, 899 }, 900 { 901 // Primitive only that is the same 902 Old: &TaskGroup{ 903 Name: "foo", 904 Count: 10, 905 Meta: map[string]string{ 906 "foo": "bar", 907 }, 908 }, 909 New: &TaskGroup{ 910 Name: "foo", 911 Count: 10, 912 Meta: map[string]string{ 913 "foo": "bar", 914 }, 915 }, 916 Expected: &TaskGroupDiff{ 917 Type: DiffTypeNone, 918 Name: "foo", 919 }, 920 }, 921 { 922 // Primitive only that has diffs 923 Old: &TaskGroup{ 924 Name: "foo", 925 Count: 10, 926 Meta: map[string]string{ 927 "foo": "bar", 928 }, 929 }, 930 New: &TaskGroup{ 931 Name: "foo", 932 Count: 100, 933 Meta: map[string]string{ 934 "foo": "baz", 935 }, 936 }, 937 Expected: &TaskGroupDiff{ 938 Type: DiffTypeEdited, 939 Name: "foo", 940 Fields: []*FieldDiff{ 941 { 942 Type: DiffTypeEdited, 943 Name: "Count", 944 Old: "10", 945 New: "100", 946 }, 947 { 948 Type: DiffTypeEdited, 949 Name: "Meta[foo]", 950 Old: "bar", 951 New: "baz", 952 }, 953 }, 954 }, 955 }, 956 { 957 // Map diff 958 Old: &TaskGroup{ 959 Meta: map[string]string{ 960 "foo": "foo", 961 "bar": "bar", 962 }, 963 }, 964 New: &TaskGroup{ 965 Meta: map[string]string{ 966 "bar": "bar", 967 "baz": "baz", 968 }, 969 }, 970 Expected: &TaskGroupDiff{ 971 Type: DiffTypeEdited, 972 Fields: []*FieldDiff{ 973 { 974 Type: DiffTypeAdded, 975 Name: "Meta[baz]", 976 Old: "", 977 New: "baz", 978 }, 979 { 980 Type: DiffTypeDeleted, 981 Name: "Meta[foo]", 982 Old: "foo", 983 New: "", 984 }, 985 }, 986 }, 987 }, 988 { 989 // Constraints edited 990 Old: &TaskGroup{ 991 Constraints: []*Constraint{ 992 { 993 LTarget: "foo", 994 RTarget: "foo", 995 Operand: "foo", 996 str: "foo", 997 }, 998 { 999 LTarget: "bar", 1000 RTarget: "bar", 1001 Operand: "bar", 1002 str: "bar", 1003 }, 1004 }, 1005 }, 1006 New: &TaskGroup{ 1007 Constraints: []*Constraint{ 1008 { 1009 LTarget: "foo", 1010 RTarget: "foo", 1011 Operand: "foo", 1012 str: "foo", 1013 }, 1014 { 1015 LTarget: "baz", 1016 RTarget: "baz", 1017 Operand: "baz", 1018 str: "baz", 1019 }, 1020 }, 1021 }, 1022 Expected: &TaskGroupDiff{ 1023 Type: DiffTypeEdited, 1024 Objects: []*ObjectDiff{ 1025 { 1026 Type: DiffTypeAdded, 1027 Name: "Constraint", 1028 Fields: []*FieldDiff{ 1029 { 1030 Type: DiffTypeAdded, 1031 Name: "LTarget", 1032 Old: "", 1033 New: "baz", 1034 }, 1035 { 1036 Type: DiffTypeAdded, 1037 Name: "Operand", 1038 Old: "", 1039 New: "baz", 1040 }, 1041 { 1042 Type: DiffTypeAdded, 1043 Name: "RTarget", 1044 Old: "", 1045 New: "baz", 1046 }, 1047 }, 1048 }, 1049 { 1050 Type: DiffTypeDeleted, 1051 Name: "Constraint", 1052 Fields: []*FieldDiff{ 1053 { 1054 Type: DiffTypeDeleted, 1055 Name: "LTarget", 1056 Old: "bar", 1057 New: "", 1058 }, 1059 { 1060 Type: DiffTypeDeleted, 1061 Name: "Operand", 1062 Old: "bar", 1063 New: "", 1064 }, 1065 { 1066 Type: DiffTypeDeleted, 1067 Name: "RTarget", 1068 Old: "bar", 1069 New: "", 1070 }, 1071 }, 1072 }, 1073 }, 1074 }, 1075 }, 1076 { 1077 // RestartPolicy added 1078 Old: &TaskGroup{}, 1079 New: &TaskGroup{ 1080 RestartPolicy: &RestartPolicy{ 1081 Attempts: 1, 1082 Interval: 1 * time.Second, 1083 Delay: 1 * time.Second, 1084 Mode: "fail", 1085 }, 1086 }, 1087 Expected: &TaskGroupDiff{ 1088 Type: DiffTypeEdited, 1089 Objects: []*ObjectDiff{ 1090 { 1091 Type: DiffTypeAdded, 1092 Name: "RestartPolicy", 1093 Fields: []*FieldDiff{ 1094 { 1095 Type: DiffTypeAdded, 1096 Name: "Attempts", 1097 Old: "", 1098 New: "1", 1099 }, 1100 { 1101 Type: DiffTypeAdded, 1102 Name: "Delay", 1103 Old: "", 1104 New: "1000000000", 1105 }, 1106 { 1107 Type: DiffTypeAdded, 1108 Name: "Interval", 1109 Old: "", 1110 New: "1000000000", 1111 }, 1112 { 1113 Type: DiffTypeAdded, 1114 Name: "Mode", 1115 Old: "", 1116 New: "fail", 1117 }, 1118 }, 1119 }, 1120 }, 1121 }, 1122 }, 1123 { 1124 // RestartPolicy deleted 1125 Old: &TaskGroup{ 1126 RestartPolicy: &RestartPolicy{ 1127 Attempts: 1, 1128 Interval: 1 * time.Second, 1129 Delay: 1 * time.Second, 1130 Mode: "fail", 1131 }, 1132 }, 1133 New: &TaskGroup{}, 1134 Expected: &TaskGroupDiff{ 1135 Type: DiffTypeEdited, 1136 Objects: []*ObjectDiff{ 1137 { 1138 Type: DiffTypeDeleted, 1139 Name: "RestartPolicy", 1140 Fields: []*FieldDiff{ 1141 { 1142 Type: DiffTypeDeleted, 1143 Name: "Attempts", 1144 Old: "1", 1145 New: "", 1146 }, 1147 { 1148 Type: DiffTypeDeleted, 1149 Name: "Delay", 1150 Old: "1000000000", 1151 New: "", 1152 }, 1153 { 1154 Type: DiffTypeDeleted, 1155 Name: "Interval", 1156 Old: "1000000000", 1157 New: "", 1158 }, 1159 { 1160 Type: DiffTypeDeleted, 1161 Name: "Mode", 1162 Old: "fail", 1163 New: "", 1164 }, 1165 }, 1166 }, 1167 }, 1168 }, 1169 }, 1170 { 1171 // RestartPolicy edited 1172 Old: &TaskGroup{ 1173 RestartPolicy: &RestartPolicy{ 1174 Attempts: 1, 1175 Interval: 1 * time.Second, 1176 Delay: 1 * time.Second, 1177 Mode: "fail", 1178 }, 1179 }, 1180 New: &TaskGroup{ 1181 RestartPolicy: &RestartPolicy{ 1182 Attempts: 2, 1183 Interval: 2 * time.Second, 1184 Delay: 2 * time.Second, 1185 Mode: "delay", 1186 }, 1187 }, 1188 Expected: &TaskGroupDiff{ 1189 Type: DiffTypeEdited, 1190 Objects: []*ObjectDiff{ 1191 { 1192 Type: DiffTypeEdited, 1193 Name: "RestartPolicy", 1194 Fields: []*FieldDiff{ 1195 { 1196 Type: DiffTypeEdited, 1197 Name: "Attempts", 1198 Old: "1", 1199 New: "2", 1200 }, 1201 { 1202 Type: DiffTypeEdited, 1203 Name: "Delay", 1204 Old: "1000000000", 1205 New: "2000000000", 1206 }, 1207 { 1208 Type: DiffTypeEdited, 1209 Name: "Interval", 1210 Old: "1000000000", 1211 New: "2000000000", 1212 }, 1213 { 1214 Type: DiffTypeEdited, 1215 Name: "Mode", 1216 Old: "fail", 1217 New: "delay", 1218 }, 1219 }, 1220 }, 1221 }, 1222 }, 1223 }, 1224 { 1225 // RestartPolicy edited with context 1226 Contextual: true, 1227 Old: &TaskGroup{ 1228 RestartPolicy: &RestartPolicy{ 1229 Attempts: 1, 1230 Interval: 1 * time.Second, 1231 Delay: 1 * time.Second, 1232 Mode: "fail", 1233 }, 1234 }, 1235 New: &TaskGroup{ 1236 RestartPolicy: &RestartPolicy{ 1237 Attempts: 2, 1238 Interval: 2 * time.Second, 1239 Delay: 1 * time.Second, 1240 Mode: "fail", 1241 }, 1242 }, 1243 Expected: &TaskGroupDiff{ 1244 Type: DiffTypeEdited, 1245 Objects: []*ObjectDiff{ 1246 { 1247 Type: DiffTypeEdited, 1248 Name: "RestartPolicy", 1249 Fields: []*FieldDiff{ 1250 { 1251 Type: DiffTypeEdited, 1252 Name: "Attempts", 1253 Old: "1", 1254 New: "2", 1255 }, 1256 { 1257 Type: DiffTypeNone, 1258 Name: "Delay", 1259 Old: "1000000000", 1260 New: "1000000000", 1261 }, 1262 { 1263 Type: DiffTypeEdited, 1264 Name: "Interval", 1265 Old: "1000000000", 1266 New: "2000000000", 1267 }, 1268 { 1269 Type: DiffTypeNone, 1270 Name: "Mode", 1271 Old: "fail", 1272 New: "fail", 1273 }, 1274 }, 1275 }, 1276 }, 1277 }, 1278 }, 1279 { 1280 // Tasks edited 1281 Old: &TaskGroup{ 1282 Tasks: []*Task{ 1283 { 1284 Name: "foo", 1285 Driver: "docker", 1286 }, 1287 { 1288 Name: "bar", 1289 Driver: "docker", 1290 }, 1291 { 1292 Name: "baz", 1293 Driver: "docker", 1294 }, 1295 }, 1296 }, 1297 New: &TaskGroup{ 1298 Tasks: []*Task{ 1299 { 1300 Name: "bar", 1301 Driver: "docker", 1302 }, 1303 { 1304 Name: "baz", 1305 Driver: "exec", 1306 }, 1307 { 1308 Name: "bam", 1309 Driver: "docker", 1310 }, 1311 }, 1312 }, 1313 Expected: &TaskGroupDiff{ 1314 Type: DiffTypeEdited, 1315 Tasks: []*TaskDiff{ 1316 { 1317 Type: DiffTypeAdded, 1318 Name: "bam", 1319 Fields: []*FieldDiff{ 1320 { 1321 Type: DiffTypeAdded, 1322 Name: "Driver", 1323 Old: "", 1324 New: "docker", 1325 }, 1326 { 1327 Type: DiffTypeAdded, 1328 Name: "KillTimeout", 1329 Old: "", 1330 New: "0", 1331 }, 1332 }, 1333 }, 1334 { 1335 Type: DiffTypeNone, 1336 Name: "bar", 1337 }, 1338 { 1339 Type: DiffTypeEdited, 1340 Name: "baz", 1341 Fields: []*FieldDiff{ 1342 { 1343 Type: DiffTypeEdited, 1344 Name: "Driver", 1345 Old: "docker", 1346 New: "exec", 1347 }, 1348 }, 1349 }, 1350 { 1351 Type: DiffTypeDeleted, 1352 Name: "foo", 1353 Fields: []*FieldDiff{ 1354 { 1355 Type: DiffTypeDeleted, 1356 Name: "Driver", 1357 Old: "docker", 1358 New: "", 1359 }, 1360 { 1361 Type: DiffTypeDeleted, 1362 Name: "KillTimeout", 1363 Old: "0", 1364 New: "", 1365 }, 1366 }, 1367 }, 1368 }, 1369 }, 1370 }, 1371 } 1372 1373 for i, c := range cases { 1374 actual, err := c.Old.Diff(c.New, c.Contextual) 1375 if c.Error && err == nil { 1376 t.Fatalf("case %d: expected errored") 1377 } else if err != nil { 1378 if !c.Error { 1379 t.Fatalf("case %d: errored %#v", i+1, err) 1380 } else { 1381 continue 1382 } 1383 } 1384 1385 if !reflect.DeepEqual(actual, c.Expected) { 1386 t.Fatalf("case %d: got:\n%#v\n want:\n%#v\n", 1387 i+1, actual, c.Expected) 1388 } 1389 } 1390 } 1391 1392 func TestTaskDiff(t *testing.T) { 1393 cases := []struct { 1394 Old, New *Task 1395 Expected *TaskDiff 1396 Error bool 1397 Contextual bool 1398 }{ 1399 { 1400 Old: nil, 1401 New: nil, 1402 Expected: &TaskDiff{ 1403 Type: DiffTypeNone, 1404 }, 1405 }, 1406 { 1407 // Primitive only that has different names 1408 Old: &Task{ 1409 Name: "foo", 1410 Meta: map[string]string{ 1411 "foo": "bar", 1412 }, 1413 }, 1414 New: &Task{ 1415 Name: "bar", 1416 Meta: map[string]string{ 1417 "foo": "bar", 1418 }, 1419 }, 1420 Error: true, 1421 }, 1422 { 1423 // Primitive only that is the same 1424 Old: &Task{ 1425 Name: "foo", 1426 Driver: "exec", 1427 User: "foo", 1428 Env: map[string]string{ 1429 "FOO": "bar", 1430 }, 1431 Meta: map[string]string{ 1432 "foo": "bar", 1433 }, 1434 KillTimeout: 1 * time.Second, 1435 }, 1436 New: &Task{ 1437 Name: "foo", 1438 Driver: "exec", 1439 User: "foo", 1440 Env: map[string]string{ 1441 "FOO": "bar", 1442 }, 1443 Meta: map[string]string{ 1444 "foo": "bar", 1445 }, 1446 KillTimeout: 1 * time.Second, 1447 }, 1448 Expected: &TaskDiff{ 1449 Type: DiffTypeNone, 1450 Name: "foo", 1451 }, 1452 }, 1453 { 1454 // Primitive only that has diffs 1455 Old: &Task{ 1456 Name: "foo", 1457 Driver: "exec", 1458 User: "foo", 1459 Env: map[string]string{ 1460 "FOO": "bar", 1461 }, 1462 Meta: map[string]string{ 1463 "foo": "bar", 1464 }, 1465 KillTimeout: 1 * time.Second, 1466 }, 1467 New: &Task{ 1468 Name: "foo", 1469 Driver: "docker", 1470 User: "bar", 1471 Env: map[string]string{ 1472 "FOO": "baz", 1473 }, 1474 Meta: map[string]string{ 1475 "foo": "baz", 1476 }, 1477 KillTimeout: 2 * time.Second, 1478 }, 1479 Expected: &TaskDiff{ 1480 Type: DiffTypeEdited, 1481 Name: "foo", 1482 Fields: []*FieldDiff{ 1483 { 1484 Type: DiffTypeEdited, 1485 Name: "Driver", 1486 Old: "exec", 1487 New: "docker", 1488 }, 1489 { 1490 Type: DiffTypeEdited, 1491 Name: "Env[FOO]", 1492 Old: "bar", 1493 New: "baz", 1494 }, 1495 { 1496 Type: DiffTypeEdited, 1497 Name: "KillTimeout", 1498 Old: "1000000000", 1499 New: "2000000000", 1500 }, 1501 { 1502 Type: DiffTypeEdited, 1503 Name: "Meta[foo]", 1504 Old: "bar", 1505 New: "baz", 1506 }, 1507 { 1508 Type: DiffTypeEdited, 1509 Name: "User", 1510 Old: "foo", 1511 New: "bar", 1512 }, 1513 }, 1514 }, 1515 }, 1516 { 1517 // Map diff 1518 Old: &Task{ 1519 Meta: map[string]string{ 1520 "foo": "foo", 1521 "bar": "bar", 1522 }, 1523 Env: map[string]string{ 1524 "foo": "foo", 1525 "bar": "bar", 1526 }, 1527 }, 1528 New: &Task{ 1529 Meta: map[string]string{ 1530 "bar": "bar", 1531 "baz": "baz", 1532 }, 1533 Env: map[string]string{ 1534 "bar": "bar", 1535 "baz": "baz", 1536 }, 1537 }, 1538 Expected: &TaskDiff{ 1539 Type: DiffTypeEdited, 1540 Fields: []*FieldDiff{ 1541 { 1542 Type: DiffTypeAdded, 1543 Name: "Env[baz]", 1544 Old: "", 1545 New: "baz", 1546 }, 1547 { 1548 Type: DiffTypeDeleted, 1549 Name: "Env[foo]", 1550 Old: "foo", 1551 New: "", 1552 }, 1553 { 1554 Type: DiffTypeAdded, 1555 Name: "Meta[baz]", 1556 Old: "", 1557 New: "baz", 1558 }, 1559 { 1560 Type: DiffTypeDeleted, 1561 Name: "Meta[foo]", 1562 Old: "foo", 1563 New: "", 1564 }, 1565 }, 1566 }, 1567 }, 1568 { 1569 // Constraints edited 1570 Old: &Task{ 1571 Constraints: []*Constraint{ 1572 { 1573 LTarget: "foo", 1574 RTarget: "foo", 1575 Operand: "foo", 1576 str: "foo", 1577 }, 1578 { 1579 LTarget: "bar", 1580 RTarget: "bar", 1581 Operand: "bar", 1582 str: "bar", 1583 }, 1584 }, 1585 }, 1586 New: &Task{ 1587 Constraints: []*Constraint{ 1588 { 1589 LTarget: "foo", 1590 RTarget: "foo", 1591 Operand: "foo", 1592 str: "foo", 1593 }, 1594 { 1595 LTarget: "baz", 1596 RTarget: "baz", 1597 Operand: "baz", 1598 str: "baz", 1599 }, 1600 }, 1601 }, 1602 Expected: &TaskDiff{ 1603 Type: DiffTypeEdited, 1604 Objects: []*ObjectDiff{ 1605 { 1606 Type: DiffTypeAdded, 1607 Name: "Constraint", 1608 Fields: []*FieldDiff{ 1609 { 1610 Type: DiffTypeAdded, 1611 Name: "LTarget", 1612 Old: "", 1613 New: "baz", 1614 }, 1615 { 1616 Type: DiffTypeAdded, 1617 Name: "Operand", 1618 Old: "", 1619 New: "baz", 1620 }, 1621 { 1622 Type: DiffTypeAdded, 1623 Name: "RTarget", 1624 Old: "", 1625 New: "baz", 1626 }, 1627 }, 1628 }, 1629 { 1630 Type: DiffTypeDeleted, 1631 Name: "Constraint", 1632 Fields: []*FieldDiff{ 1633 { 1634 Type: DiffTypeDeleted, 1635 Name: "LTarget", 1636 Old: "bar", 1637 New: "", 1638 }, 1639 { 1640 Type: DiffTypeDeleted, 1641 Name: "Operand", 1642 Old: "bar", 1643 New: "", 1644 }, 1645 { 1646 Type: DiffTypeDeleted, 1647 Name: "RTarget", 1648 Old: "bar", 1649 New: "", 1650 }, 1651 }, 1652 }, 1653 }, 1654 }, 1655 }, 1656 { 1657 // LogConfig added 1658 Old: &Task{}, 1659 New: &Task{ 1660 LogConfig: &LogConfig{ 1661 MaxFiles: 1, 1662 MaxFileSizeMB: 10, 1663 }, 1664 }, 1665 Expected: &TaskDiff{ 1666 Type: DiffTypeEdited, 1667 Objects: []*ObjectDiff{ 1668 { 1669 Type: DiffTypeAdded, 1670 Name: "LogConfig", 1671 Fields: []*FieldDiff{ 1672 { 1673 Type: DiffTypeAdded, 1674 Name: "MaxFileSizeMB", 1675 Old: "", 1676 New: "10", 1677 }, 1678 { 1679 Type: DiffTypeAdded, 1680 Name: "MaxFiles", 1681 Old: "", 1682 New: "1", 1683 }, 1684 }, 1685 }, 1686 }, 1687 }, 1688 }, 1689 { 1690 // LogConfig deleted 1691 Old: &Task{ 1692 LogConfig: &LogConfig{ 1693 MaxFiles: 1, 1694 MaxFileSizeMB: 10, 1695 }, 1696 }, 1697 New: &Task{}, 1698 Expected: &TaskDiff{ 1699 Type: DiffTypeEdited, 1700 Objects: []*ObjectDiff{ 1701 { 1702 Type: DiffTypeDeleted, 1703 Name: "LogConfig", 1704 Fields: []*FieldDiff{ 1705 { 1706 Type: DiffTypeDeleted, 1707 Name: "MaxFileSizeMB", 1708 Old: "10", 1709 New: "", 1710 }, 1711 { 1712 Type: DiffTypeDeleted, 1713 Name: "MaxFiles", 1714 Old: "1", 1715 New: "", 1716 }, 1717 }, 1718 }, 1719 }, 1720 }, 1721 }, 1722 { 1723 // LogConfig edited 1724 Old: &Task{ 1725 LogConfig: &LogConfig{ 1726 MaxFiles: 1, 1727 MaxFileSizeMB: 10, 1728 }, 1729 }, 1730 New: &Task{ 1731 LogConfig: &LogConfig{ 1732 MaxFiles: 2, 1733 MaxFileSizeMB: 20, 1734 }, 1735 }, 1736 Expected: &TaskDiff{ 1737 Type: DiffTypeEdited, 1738 Objects: []*ObjectDiff{ 1739 { 1740 Type: DiffTypeEdited, 1741 Name: "LogConfig", 1742 Fields: []*FieldDiff{ 1743 { 1744 Type: DiffTypeEdited, 1745 Name: "MaxFileSizeMB", 1746 Old: "10", 1747 New: "20", 1748 }, 1749 { 1750 Type: DiffTypeEdited, 1751 Name: "MaxFiles", 1752 Old: "1", 1753 New: "2", 1754 }, 1755 }, 1756 }, 1757 }, 1758 }, 1759 }, 1760 { 1761 // LogConfig edited with context 1762 Contextual: true, 1763 Old: &Task{ 1764 LogConfig: &LogConfig{ 1765 MaxFiles: 1, 1766 MaxFileSizeMB: 10, 1767 }, 1768 }, 1769 New: &Task{ 1770 LogConfig: &LogConfig{ 1771 MaxFiles: 1, 1772 MaxFileSizeMB: 20, 1773 }, 1774 }, 1775 Expected: &TaskDiff{ 1776 Type: DiffTypeEdited, 1777 Objects: []*ObjectDiff{ 1778 { 1779 Type: DiffTypeEdited, 1780 Name: "LogConfig", 1781 Fields: []*FieldDiff{ 1782 { 1783 Type: DiffTypeEdited, 1784 Name: "MaxFileSizeMB", 1785 Old: "10", 1786 New: "20", 1787 }, 1788 { 1789 Type: DiffTypeNone, 1790 Name: "MaxFiles", 1791 Old: "1", 1792 New: "1", 1793 }, 1794 }, 1795 }, 1796 }, 1797 }, 1798 }, 1799 { 1800 // Artifacts edited 1801 Old: &Task{ 1802 Artifacts: []*TaskArtifact{ 1803 { 1804 GetterSource: "foo", 1805 GetterOptions: map[string]string{ 1806 "foo": "bar", 1807 }, 1808 RelativeDest: "foo", 1809 }, 1810 { 1811 GetterSource: "bar", 1812 GetterOptions: map[string]string{ 1813 "bar": "baz", 1814 }, 1815 RelativeDest: "bar", 1816 }, 1817 }, 1818 }, 1819 New: &Task{ 1820 Artifacts: []*TaskArtifact{ 1821 { 1822 GetterSource: "foo", 1823 GetterOptions: map[string]string{ 1824 "foo": "bar", 1825 }, 1826 RelativeDest: "foo", 1827 }, 1828 { 1829 GetterSource: "bam", 1830 GetterOptions: map[string]string{ 1831 "bam": "baz", 1832 }, 1833 RelativeDest: "bam", 1834 }, 1835 }, 1836 }, 1837 Expected: &TaskDiff{ 1838 Type: DiffTypeEdited, 1839 Objects: []*ObjectDiff{ 1840 { 1841 Type: DiffTypeAdded, 1842 Name: "Artifact", 1843 Fields: []*FieldDiff{ 1844 { 1845 Type: DiffTypeAdded, 1846 Name: "GetterOptions[bam]", 1847 Old: "", 1848 New: "baz", 1849 }, 1850 { 1851 Type: DiffTypeAdded, 1852 Name: "GetterSource", 1853 Old: "", 1854 New: "bam", 1855 }, 1856 { 1857 Type: DiffTypeAdded, 1858 Name: "RelativeDest", 1859 Old: "", 1860 New: "bam", 1861 }, 1862 }, 1863 }, 1864 { 1865 Type: DiffTypeDeleted, 1866 Name: "Artifact", 1867 Fields: []*FieldDiff{ 1868 { 1869 Type: DiffTypeDeleted, 1870 Name: "GetterOptions[bar]", 1871 Old: "baz", 1872 New: "", 1873 }, 1874 { 1875 Type: DiffTypeDeleted, 1876 Name: "GetterSource", 1877 Old: "bar", 1878 New: "", 1879 }, 1880 { 1881 Type: DiffTypeDeleted, 1882 Name: "RelativeDest", 1883 Old: "bar", 1884 New: "", 1885 }, 1886 }, 1887 }, 1888 }, 1889 }, 1890 }, 1891 { 1892 // Resources edited (no networks) 1893 Old: &Task{ 1894 Resources: &Resources{ 1895 CPU: 100, 1896 MemoryMB: 100, 1897 DiskMB: 100, 1898 IOPS: 100, 1899 }, 1900 }, 1901 New: &Task{ 1902 Resources: &Resources{ 1903 CPU: 200, 1904 MemoryMB: 200, 1905 DiskMB: 200, 1906 IOPS: 200, 1907 }, 1908 }, 1909 Expected: &TaskDiff{ 1910 Type: DiffTypeEdited, 1911 Objects: []*ObjectDiff{ 1912 { 1913 Type: DiffTypeEdited, 1914 Name: "Resources", 1915 Fields: []*FieldDiff{ 1916 { 1917 Type: DiffTypeEdited, 1918 Name: "CPU", 1919 Old: "100", 1920 New: "200", 1921 }, 1922 { 1923 Type: DiffTypeEdited, 1924 Name: "DiskMB", 1925 Old: "100", 1926 New: "200", 1927 }, 1928 { 1929 Type: DiffTypeEdited, 1930 Name: "IOPS", 1931 Old: "100", 1932 New: "200", 1933 }, 1934 { 1935 Type: DiffTypeEdited, 1936 Name: "MemoryMB", 1937 Old: "100", 1938 New: "200", 1939 }, 1940 }, 1941 }, 1942 }, 1943 }, 1944 }, 1945 { 1946 // Resources edited (no networks) with context 1947 Contextual: true, 1948 Old: &Task{ 1949 Resources: &Resources{ 1950 CPU: 100, 1951 MemoryMB: 100, 1952 DiskMB: 100, 1953 IOPS: 100, 1954 }, 1955 }, 1956 New: &Task{ 1957 Resources: &Resources{ 1958 CPU: 200, 1959 MemoryMB: 100, 1960 DiskMB: 200, 1961 IOPS: 100, 1962 }, 1963 }, 1964 Expected: &TaskDiff{ 1965 Type: DiffTypeEdited, 1966 Objects: []*ObjectDiff{ 1967 { 1968 Type: DiffTypeEdited, 1969 Name: "Resources", 1970 Fields: []*FieldDiff{ 1971 { 1972 Type: DiffTypeEdited, 1973 Name: "CPU", 1974 Old: "100", 1975 New: "200", 1976 }, 1977 { 1978 Type: DiffTypeEdited, 1979 Name: "DiskMB", 1980 Old: "100", 1981 New: "200", 1982 }, 1983 { 1984 Type: DiffTypeNone, 1985 Name: "IOPS", 1986 Old: "100", 1987 New: "100", 1988 }, 1989 { 1990 Type: DiffTypeNone, 1991 Name: "MemoryMB", 1992 Old: "100", 1993 New: "100", 1994 }, 1995 }, 1996 }, 1997 }, 1998 }, 1999 }, 2000 { 2001 // Network Resources edited 2002 Old: &Task{ 2003 Resources: &Resources{ 2004 Networks: []*NetworkResource{ 2005 { 2006 Device: "foo", 2007 CIDR: "foo", 2008 IP: "foo", 2009 MBits: 100, 2010 ReservedPorts: []Port{ 2011 { 2012 Label: "foo", 2013 Value: 80, 2014 }, 2015 }, 2016 DynamicPorts: []Port{ 2017 { 2018 Label: "bar", 2019 }, 2020 }, 2021 }, 2022 }, 2023 }, 2024 }, 2025 New: &Task{ 2026 Resources: &Resources{ 2027 Networks: []*NetworkResource{ 2028 { 2029 Device: "bar", 2030 CIDR: "bar", 2031 IP: "bar", 2032 MBits: 200, 2033 ReservedPorts: []Port{ 2034 { 2035 Label: "foo", 2036 Value: 81, 2037 }, 2038 }, 2039 DynamicPorts: []Port{ 2040 { 2041 Label: "baz", 2042 }, 2043 }, 2044 }, 2045 }, 2046 }, 2047 }, 2048 Expected: &TaskDiff{ 2049 Type: DiffTypeEdited, 2050 Objects: []*ObjectDiff{ 2051 { 2052 Type: DiffTypeEdited, 2053 Name: "Resources", 2054 Objects: []*ObjectDiff{ 2055 { 2056 Type: DiffTypeAdded, 2057 Name: "Network", 2058 Fields: []*FieldDiff{ 2059 { 2060 Type: DiffTypeAdded, 2061 Name: "MBits", 2062 Old: "", 2063 New: "200", 2064 }, 2065 }, 2066 Objects: []*ObjectDiff{ 2067 { 2068 Type: DiffTypeAdded, 2069 Name: "Static Port", 2070 Fields: []*FieldDiff{ 2071 { 2072 Type: DiffTypeAdded, 2073 Name: "Label", 2074 Old: "", 2075 New: "foo", 2076 }, 2077 { 2078 Type: DiffTypeAdded, 2079 Name: "Value", 2080 Old: "", 2081 New: "81", 2082 }, 2083 }, 2084 }, 2085 { 2086 Type: DiffTypeAdded, 2087 Name: "Dynamic Port", 2088 Fields: []*FieldDiff{ 2089 { 2090 Type: DiffTypeAdded, 2091 Name: "Label", 2092 Old: "", 2093 New: "baz", 2094 }, 2095 }, 2096 }, 2097 }, 2098 }, 2099 { 2100 Type: DiffTypeDeleted, 2101 Name: "Network", 2102 Fields: []*FieldDiff{ 2103 { 2104 Type: DiffTypeDeleted, 2105 Name: "MBits", 2106 Old: "100", 2107 New: "", 2108 }, 2109 }, 2110 Objects: []*ObjectDiff{ 2111 { 2112 Type: DiffTypeDeleted, 2113 Name: "Static Port", 2114 Fields: []*FieldDiff{ 2115 { 2116 Type: DiffTypeDeleted, 2117 Name: "Label", 2118 Old: "foo", 2119 New: "", 2120 }, 2121 { 2122 Type: DiffTypeDeleted, 2123 Name: "Value", 2124 Old: "80", 2125 New: "", 2126 }, 2127 }, 2128 }, 2129 { 2130 Type: DiffTypeDeleted, 2131 Name: "Dynamic Port", 2132 Fields: []*FieldDiff{ 2133 { 2134 Type: DiffTypeDeleted, 2135 Name: "Label", 2136 Old: "bar", 2137 New: "", 2138 }, 2139 }, 2140 }, 2141 }, 2142 }, 2143 }, 2144 }, 2145 }, 2146 }, 2147 }, 2148 { 2149 // Config same 2150 Old: &Task{ 2151 Config: map[string]interface{}{ 2152 "foo": 1, 2153 "bar": "bar", 2154 "bam": []string{"a", "b"}, 2155 "baz": map[string]int{ 2156 "a": 1, 2157 "b": 2, 2158 }, 2159 "boom": &Port{ 2160 Label: "boom_port", 2161 }, 2162 }, 2163 }, 2164 New: &Task{ 2165 Config: map[string]interface{}{ 2166 "foo": 1, 2167 "bar": "bar", 2168 "bam": []string{"a", "b"}, 2169 "baz": map[string]int{ 2170 "a": 1, 2171 "b": 2, 2172 }, 2173 "boom": &Port{ 2174 Label: "boom_port", 2175 }, 2176 }, 2177 }, 2178 Expected: &TaskDiff{ 2179 Type: DiffTypeNone, 2180 }, 2181 }, 2182 { 2183 // Config edited 2184 Old: &Task{ 2185 Config: map[string]interface{}{ 2186 "foo": 1, 2187 "bar": "baz", 2188 "bam": []string{"a", "b"}, 2189 "baz": map[string]int{ 2190 "a": 1, 2191 "b": 2, 2192 }, 2193 "boom": &Port{ 2194 Label: "boom_port", 2195 }, 2196 }, 2197 }, 2198 New: &Task{ 2199 Config: map[string]interface{}{ 2200 "foo": 2, 2201 "bar": "baz", 2202 "bam": []string{"a", "c", "d"}, 2203 "baz": map[string]int{ 2204 "b": 3, 2205 "c": 4, 2206 }, 2207 "boom": &Port{ 2208 Label: "boom_port2", 2209 }, 2210 }, 2211 }, 2212 Expected: &TaskDiff{ 2213 Type: DiffTypeEdited, 2214 Objects: []*ObjectDiff{ 2215 { 2216 Type: DiffTypeEdited, 2217 Name: "Config", 2218 Fields: []*FieldDiff{ 2219 { 2220 Type: DiffTypeEdited, 2221 Name: "bam[1]", 2222 Old: "b", 2223 New: "c", 2224 }, 2225 { 2226 Type: DiffTypeAdded, 2227 Name: "bam[2]", 2228 Old: "", 2229 New: "d", 2230 }, 2231 { 2232 Type: DiffTypeDeleted, 2233 Name: "baz[a]", 2234 Old: "1", 2235 New: "", 2236 }, 2237 { 2238 Type: DiffTypeEdited, 2239 Name: "baz[b]", 2240 Old: "2", 2241 New: "3", 2242 }, 2243 { 2244 Type: DiffTypeAdded, 2245 Name: "baz[c]", 2246 Old: "", 2247 New: "4", 2248 }, 2249 { 2250 Type: DiffTypeEdited, 2251 Name: "boom.Label", 2252 Old: "boom_port", 2253 New: "boom_port2", 2254 }, 2255 { 2256 Type: DiffTypeEdited, 2257 Name: "foo", 2258 Old: "1", 2259 New: "2", 2260 }, 2261 }, 2262 }, 2263 }, 2264 }, 2265 }, 2266 { 2267 // Config edited with context 2268 Contextual: true, 2269 Old: &Task{ 2270 Config: map[string]interface{}{ 2271 "foo": 1, 2272 "bar": "baz", 2273 "bam": []string{"a", "b"}, 2274 "baz": map[string]int{ 2275 "a": 1, 2276 "b": 2, 2277 }, 2278 "boom": &Port{ 2279 Label: "boom_port", 2280 }, 2281 }, 2282 }, 2283 New: &Task{ 2284 Config: map[string]interface{}{ 2285 "foo": 2, 2286 "bar": "baz", 2287 "bam": []string{"a", "c", "d"}, 2288 "baz": map[string]int{ 2289 "a": 1, 2290 "b": 2, 2291 }, 2292 "boom": &Port{ 2293 Label: "boom_port", 2294 }, 2295 }, 2296 }, 2297 Expected: &TaskDiff{ 2298 Type: DiffTypeEdited, 2299 Objects: []*ObjectDiff{ 2300 { 2301 Type: DiffTypeEdited, 2302 Name: "Config", 2303 Fields: []*FieldDiff{ 2304 { 2305 Type: DiffTypeNone, 2306 Name: "bam[0]", 2307 Old: "a", 2308 New: "a", 2309 }, 2310 { 2311 Type: DiffTypeEdited, 2312 Name: "bam[1]", 2313 Old: "b", 2314 New: "c", 2315 }, 2316 { 2317 Type: DiffTypeAdded, 2318 Name: "bam[2]", 2319 Old: "", 2320 New: "d", 2321 }, 2322 { 2323 Type: DiffTypeNone, 2324 Name: "bar", 2325 Old: "baz", 2326 New: "baz", 2327 }, 2328 { 2329 Type: DiffTypeNone, 2330 Name: "baz[a]", 2331 Old: "1", 2332 New: "1", 2333 }, 2334 { 2335 Type: DiffTypeNone, 2336 Name: "baz[b]", 2337 Old: "2", 2338 New: "2", 2339 }, 2340 { 2341 Type: DiffTypeNone, 2342 Name: "boom.Label", 2343 Old: "boom_port", 2344 New: "boom_port", 2345 }, 2346 { 2347 Type: DiffTypeNone, 2348 Name: "boom.Value", 2349 Old: "0", 2350 New: "0", 2351 }, 2352 { 2353 Type: DiffTypeEdited, 2354 Name: "foo", 2355 Old: "1", 2356 New: "2", 2357 }, 2358 }, 2359 }, 2360 }, 2361 }, 2362 }, 2363 { 2364 // Services edited (no checks) 2365 Old: &Task{ 2366 Services: []*Service{ 2367 { 2368 Name: "foo", 2369 PortLabel: "foo", 2370 }, 2371 { 2372 Name: "bar", 2373 PortLabel: "bar", 2374 }, 2375 { 2376 Name: "baz", 2377 PortLabel: "baz", 2378 }, 2379 }, 2380 }, 2381 New: &Task{ 2382 Services: []*Service{ 2383 { 2384 Name: "bar", 2385 PortLabel: "bar", 2386 }, 2387 { 2388 Name: "baz", 2389 PortLabel: "baz2", 2390 }, 2391 { 2392 Name: "bam", 2393 PortLabel: "bam", 2394 }, 2395 }, 2396 }, 2397 Expected: &TaskDiff{ 2398 Type: DiffTypeEdited, 2399 Objects: []*ObjectDiff{ 2400 { 2401 Type: DiffTypeEdited, 2402 Name: "Service", 2403 Fields: []*FieldDiff{ 2404 { 2405 Type: DiffTypeEdited, 2406 Name: "PortLabel", 2407 Old: "baz", 2408 New: "baz2", 2409 }, 2410 }, 2411 }, 2412 { 2413 Type: DiffTypeAdded, 2414 Name: "Service", 2415 Fields: []*FieldDiff{ 2416 { 2417 Type: DiffTypeAdded, 2418 Name: "Name", 2419 Old: "", 2420 New: "bam", 2421 }, 2422 { 2423 Type: DiffTypeAdded, 2424 Name: "PortLabel", 2425 Old: "", 2426 New: "bam", 2427 }, 2428 }, 2429 }, 2430 { 2431 Type: DiffTypeDeleted, 2432 Name: "Service", 2433 Fields: []*FieldDiff{ 2434 { 2435 Type: DiffTypeDeleted, 2436 Name: "Name", 2437 Old: "foo", 2438 New: "", 2439 }, 2440 { 2441 Type: DiffTypeDeleted, 2442 Name: "PortLabel", 2443 Old: "foo", 2444 New: "", 2445 }, 2446 }, 2447 }, 2448 }, 2449 }, 2450 }, 2451 { 2452 // Services edited (no checks) with context 2453 Contextual: true, 2454 Old: &Task{ 2455 Services: []*Service{ 2456 { 2457 Name: "foo", 2458 PortLabel: "foo", 2459 }, 2460 }, 2461 }, 2462 New: &Task{ 2463 Services: []*Service{ 2464 { 2465 Name: "foo", 2466 PortLabel: "bar", 2467 }, 2468 }, 2469 }, 2470 Expected: &TaskDiff{ 2471 Type: DiffTypeEdited, 2472 Objects: []*ObjectDiff{ 2473 { 2474 Type: DiffTypeEdited, 2475 Name: "Service", 2476 Fields: []*FieldDiff{ 2477 { 2478 Type: DiffTypeNone, 2479 Name: "Name", 2480 Old: "foo", 2481 New: "foo", 2482 }, 2483 { 2484 Type: DiffTypeEdited, 2485 Name: "PortLabel", 2486 Old: "foo", 2487 New: "bar", 2488 }, 2489 }, 2490 }, 2491 }, 2492 }, 2493 }, 2494 { 2495 // Service Checks edited 2496 Old: &Task{ 2497 Services: []*Service{ 2498 { 2499 Name: "foo", 2500 Checks: []*ServiceCheck{ 2501 { 2502 Name: "foo", 2503 Type: "http", 2504 Command: "foo", 2505 Args: []string{"foo"}, 2506 Path: "foo", 2507 Protocol: "http", 2508 Interval: 1 * time.Second, 2509 Timeout: 1 * time.Second, 2510 }, 2511 { 2512 Name: "bar", 2513 Type: "http", 2514 Command: "foo", 2515 Args: []string{"foo"}, 2516 Path: "foo", 2517 Protocol: "http", 2518 Interval: 1 * time.Second, 2519 Timeout: 1 * time.Second, 2520 }, 2521 { 2522 Name: "baz", 2523 Type: "http", 2524 Command: "foo", 2525 Args: []string{"foo"}, 2526 Path: "foo", 2527 Protocol: "http", 2528 Interval: 1 * time.Second, 2529 Timeout: 1 * time.Second, 2530 }, 2531 }, 2532 }, 2533 }, 2534 }, 2535 New: &Task{ 2536 Services: []*Service{ 2537 { 2538 Name: "foo", 2539 Checks: []*ServiceCheck{ 2540 { 2541 Name: "bar", 2542 Type: "http", 2543 Command: "foo", 2544 Args: []string{"foo"}, 2545 Path: "foo", 2546 Protocol: "http", 2547 Interval: 1 * time.Second, 2548 Timeout: 1 * time.Second, 2549 }, 2550 { 2551 Name: "baz", 2552 Type: "tcp", 2553 Command: "foo", 2554 Args: []string{"foo"}, 2555 Path: "foo", 2556 Protocol: "http", 2557 Interval: 1 * time.Second, 2558 Timeout: 1 * time.Second, 2559 }, 2560 { 2561 Name: "bam", 2562 Type: "http", 2563 Command: "foo", 2564 Args: []string{"foo"}, 2565 Path: "foo", 2566 Protocol: "http", 2567 Interval: 1 * time.Second, 2568 Timeout: 1 * time.Second, 2569 }, 2570 }, 2571 }, 2572 }, 2573 }, 2574 Expected: &TaskDiff{ 2575 Type: DiffTypeEdited, 2576 Objects: []*ObjectDiff{ 2577 { 2578 Type: DiffTypeEdited, 2579 Name: "Service", 2580 Objects: []*ObjectDiff{ 2581 { 2582 Type: DiffTypeEdited, 2583 Name: "Check", 2584 Fields: []*FieldDiff{ 2585 { 2586 Type: DiffTypeEdited, 2587 Name: "Type", 2588 Old: "http", 2589 New: "tcp", 2590 }, 2591 }, 2592 }, 2593 { 2594 Type: DiffTypeAdded, 2595 Name: "Check", 2596 Fields: []*FieldDiff{ 2597 { 2598 Type: DiffTypeAdded, 2599 Name: "Command", 2600 Old: "", 2601 New: "foo", 2602 }, 2603 { 2604 Type: DiffTypeAdded, 2605 Name: "Interval", 2606 Old: "", 2607 New: "1000000000", 2608 }, 2609 { 2610 Type: DiffTypeAdded, 2611 Name: "Name", 2612 Old: "", 2613 New: "bam", 2614 }, 2615 { 2616 Type: DiffTypeAdded, 2617 Name: "Path", 2618 Old: "", 2619 New: "foo", 2620 }, 2621 { 2622 Type: DiffTypeAdded, 2623 Name: "Protocol", 2624 Old: "", 2625 New: "http", 2626 }, 2627 { 2628 Type: DiffTypeAdded, 2629 Name: "Timeout", 2630 Old: "", 2631 New: "1000000000", 2632 }, 2633 { 2634 Type: DiffTypeAdded, 2635 Name: "Type", 2636 Old: "", 2637 New: "http", 2638 }, 2639 }, 2640 }, 2641 { 2642 Type: DiffTypeDeleted, 2643 Name: "Check", 2644 Fields: []*FieldDiff{ 2645 { 2646 Type: DiffTypeDeleted, 2647 Name: "Command", 2648 Old: "foo", 2649 New: "", 2650 }, 2651 { 2652 Type: DiffTypeDeleted, 2653 Name: "Interval", 2654 Old: "1000000000", 2655 New: "", 2656 }, 2657 { 2658 Type: DiffTypeDeleted, 2659 Name: "Name", 2660 Old: "foo", 2661 New: "", 2662 }, 2663 { 2664 Type: DiffTypeDeleted, 2665 Name: "Path", 2666 Old: "foo", 2667 New: "", 2668 }, 2669 { 2670 Type: DiffTypeDeleted, 2671 Name: "Protocol", 2672 Old: "http", 2673 New: "", 2674 }, 2675 { 2676 Type: DiffTypeDeleted, 2677 Name: "Timeout", 2678 Old: "1000000000", 2679 New: "", 2680 }, 2681 { 2682 Type: DiffTypeDeleted, 2683 Name: "Type", 2684 Old: "http", 2685 New: "", 2686 }, 2687 }, 2688 }, 2689 }, 2690 }, 2691 }, 2692 }, 2693 }, 2694 { 2695 // Service Checks edited with context 2696 Contextual: true, 2697 Old: &Task{ 2698 Services: []*Service{ 2699 { 2700 Name: "foo", 2701 Checks: []*ServiceCheck{ 2702 { 2703 Name: "foo", 2704 Type: "http", 2705 Command: "foo", 2706 Args: []string{"foo"}, 2707 Path: "foo", 2708 Protocol: "http", 2709 Interval: 1 * time.Second, 2710 Timeout: 1 * time.Second, 2711 }, 2712 }, 2713 }, 2714 }, 2715 }, 2716 New: &Task{ 2717 Services: []*Service{ 2718 { 2719 Name: "foo", 2720 Checks: []*ServiceCheck{ 2721 { 2722 Name: "foo", 2723 Type: "tcp", 2724 Command: "foo", 2725 Args: []string{"foo"}, 2726 Path: "foo", 2727 Protocol: "http", 2728 Interval: 1 * time.Second, 2729 Timeout: 1 * time.Second, 2730 }, 2731 }, 2732 }, 2733 }, 2734 }, 2735 Expected: &TaskDiff{ 2736 Type: DiffTypeEdited, 2737 Objects: []*ObjectDiff{ 2738 { 2739 Type: DiffTypeEdited, 2740 Name: "Service", 2741 Fields: []*FieldDiff{ 2742 { 2743 Type: DiffTypeNone, 2744 Name: "Name", 2745 Old: "foo", 2746 New: "foo", 2747 }, 2748 { 2749 Type: DiffTypeNone, 2750 Name: "PortLabel", 2751 Old: "", 2752 New: "", 2753 }, 2754 }, 2755 Objects: []*ObjectDiff{ 2756 { 2757 Type: DiffTypeEdited, 2758 Name: "Check", 2759 Fields: []*FieldDiff{ 2760 { 2761 Type: DiffTypeNone, 2762 Name: "Command", 2763 Old: "foo", 2764 New: "foo", 2765 }, 2766 { 2767 Type: DiffTypeNone, 2768 Name: "Interval", 2769 Old: "1000000000", 2770 New: "1000000000", 2771 }, 2772 { 2773 Type: DiffTypeNone, 2774 Name: "Name", 2775 Old: "foo", 2776 New: "foo", 2777 }, 2778 { 2779 Type: DiffTypeNone, 2780 Name: "Path", 2781 Old: "foo", 2782 New: "foo", 2783 }, 2784 { 2785 Type: DiffTypeNone, 2786 Name: "Protocol", 2787 Old: "http", 2788 New: "http", 2789 }, 2790 { 2791 Type: DiffTypeNone, 2792 Name: "Timeout", 2793 Old: "1000000000", 2794 New: "1000000000", 2795 }, 2796 { 2797 Type: DiffTypeEdited, 2798 Name: "Type", 2799 Old: "http", 2800 New: "tcp", 2801 }, 2802 }, 2803 }, 2804 }, 2805 }, 2806 }, 2807 }, 2808 }, 2809 } 2810 2811 for i, c := range cases { 2812 actual, err := c.Old.Diff(c.New, c.Contextual) 2813 if c.Error && err == nil { 2814 t.Fatalf("case %d: expected errored") 2815 } else if err != nil { 2816 if !c.Error { 2817 t.Fatalf("case %d: errored %#v", i+1, err) 2818 } else { 2819 continue 2820 } 2821 } 2822 2823 if !reflect.DeepEqual(actual, c.Expected) { 2824 t.Fatalf("case %d: got:\n%#v\n want:\n%#v\n", 2825 i+1, actual, c.Expected) 2826 } 2827 } 2828 }