github.com/emate/nomad@v0.8.2-wo-binpacking/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: "Stop", 180 Old: "false", 181 New: "", 182 }, 183 { 184 Type: DiffTypeDeleted, 185 Name: "Type", 186 Old: "batch", 187 New: "", 188 }, 189 }, 190 }, 191 }, 192 { 193 // Primitive only added job 194 Old: nil, 195 New: &Job{ 196 Region: "foo", 197 ID: "foo", 198 Name: "foo", 199 Type: "batch", 200 Priority: 10, 201 AllAtOnce: true, 202 Meta: map[string]string{ 203 "foo": "bar", 204 }, 205 }, 206 Expected: &JobDiff{ 207 Type: DiffTypeAdded, 208 ID: "foo", 209 Fields: []*FieldDiff{ 210 { 211 Type: DiffTypeAdded, 212 Name: "AllAtOnce", 213 Old: "", 214 New: "true", 215 }, 216 { 217 Type: DiffTypeAdded, 218 Name: "Meta[foo]", 219 Old: "", 220 New: "bar", 221 }, 222 { 223 Type: DiffTypeAdded, 224 Name: "Name", 225 Old: "", 226 New: "foo", 227 }, 228 { 229 Type: DiffTypeAdded, 230 Name: "Priority", 231 Old: "", 232 New: "10", 233 }, 234 { 235 Type: DiffTypeAdded, 236 Name: "Region", 237 Old: "", 238 New: "foo", 239 }, 240 { 241 Type: DiffTypeAdded, 242 Name: "Stop", 243 Old: "", 244 New: "false", 245 }, 246 { 247 Type: DiffTypeAdded, 248 Name: "Type", 249 Old: "", 250 New: "batch", 251 }, 252 }, 253 }, 254 }, 255 { 256 // Map diff 257 Old: &Job{ 258 Meta: map[string]string{ 259 "foo": "foo", 260 "bar": "bar", 261 }, 262 }, 263 New: &Job{ 264 Meta: map[string]string{ 265 "bar": "bar", 266 "baz": "baz", 267 }, 268 }, 269 Expected: &JobDiff{ 270 Type: DiffTypeEdited, 271 Fields: []*FieldDiff{ 272 { 273 Type: DiffTypeAdded, 274 Name: "Meta[baz]", 275 Old: "", 276 New: "baz", 277 }, 278 { 279 Type: DiffTypeDeleted, 280 Name: "Meta[foo]", 281 Old: "foo", 282 New: "", 283 }, 284 }, 285 }, 286 }, 287 { 288 // Datacenter diff both added and removed 289 Old: &Job{ 290 Datacenters: []string{"foo", "bar"}, 291 }, 292 New: &Job{ 293 Datacenters: []string{"baz", "bar"}, 294 }, 295 Expected: &JobDiff{ 296 Type: DiffTypeEdited, 297 Objects: []*ObjectDiff{ 298 { 299 Type: DiffTypeEdited, 300 Name: "Datacenters", 301 Fields: []*FieldDiff{ 302 { 303 Type: DiffTypeAdded, 304 Name: "Datacenters", 305 Old: "", 306 New: "baz", 307 }, 308 { 309 Type: DiffTypeDeleted, 310 Name: "Datacenters", 311 Old: "foo", 312 New: "", 313 }, 314 }, 315 }, 316 }, 317 }, 318 }, 319 { 320 // Datacenter diff just added 321 Old: &Job{ 322 Datacenters: []string{"foo", "bar"}, 323 }, 324 New: &Job{ 325 Datacenters: []string{"foo", "bar", "baz"}, 326 }, 327 Expected: &JobDiff{ 328 Type: DiffTypeEdited, 329 Objects: []*ObjectDiff{ 330 { 331 Type: DiffTypeAdded, 332 Name: "Datacenters", 333 Fields: []*FieldDiff{ 334 { 335 Type: DiffTypeAdded, 336 Name: "Datacenters", 337 Old: "", 338 New: "baz", 339 }, 340 }, 341 }, 342 }, 343 }, 344 }, 345 { 346 // Datacenter diff just deleted 347 Old: &Job{ 348 Datacenters: []string{"foo", "bar"}, 349 }, 350 New: &Job{ 351 Datacenters: []string{"foo"}, 352 }, 353 Expected: &JobDiff{ 354 Type: DiffTypeEdited, 355 Objects: []*ObjectDiff{ 356 { 357 Type: DiffTypeDeleted, 358 Name: "Datacenters", 359 Fields: []*FieldDiff{ 360 { 361 Type: DiffTypeDeleted, 362 Name: "Datacenters", 363 Old: "bar", 364 New: "", 365 }, 366 }, 367 }, 368 }, 369 }, 370 }, 371 { 372 // Datacenter contextual no change 373 Contextual: true, 374 Old: &Job{ 375 Datacenters: []string{"foo", "bar"}, 376 }, 377 New: &Job{ 378 Datacenters: []string{"foo", "bar"}, 379 }, 380 Expected: &JobDiff{ 381 Type: DiffTypeNone, 382 }, 383 }, 384 { 385 // Datacenter contextual 386 Contextual: true, 387 Old: &Job{ 388 Datacenters: []string{"foo", "bar"}, 389 }, 390 New: &Job{ 391 Datacenters: []string{"foo", "bar", "baz"}, 392 }, 393 Expected: &JobDiff{ 394 Type: DiffTypeEdited, 395 Objects: []*ObjectDiff{ 396 { 397 Type: DiffTypeAdded, 398 Name: "Datacenters", 399 Fields: []*FieldDiff{ 400 { 401 Type: DiffTypeAdded, 402 Name: "Datacenters", 403 Old: "", 404 New: "baz", 405 }, 406 { 407 Type: DiffTypeNone, 408 Name: "Datacenters", 409 Old: "bar", 410 New: "bar", 411 }, 412 { 413 Type: DiffTypeNone, 414 Name: "Datacenters", 415 Old: "foo", 416 New: "foo", 417 }, 418 }, 419 }, 420 }, 421 }, 422 }, 423 { 424 // Periodic added 425 Old: &Job{}, 426 New: &Job{ 427 Periodic: &PeriodicConfig{ 428 Enabled: false, 429 Spec: "*/15 * * * * *", 430 SpecType: "foo", 431 ProhibitOverlap: false, 432 TimeZone: "Europe/Minsk", 433 }, 434 }, 435 Expected: &JobDiff{ 436 Type: DiffTypeEdited, 437 Objects: []*ObjectDiff{ 438 { 439 Type: DiffTypeAdded, 440 Name: "Periodic", 441 Fields: []*FieldDiff{ 442 { 443 Type: DiffTypeAdded, 444 Name: "Enabled", 445 Old: "", 446 New: "false", 447 }, 448 { 449 Type: DiffTypeAdded, 450 Name: "ProhibitOverlap", 451 Old: "", 452 New: "false", 453 }, 454 { 455 Type: DiffTypeAdded, 456 Name: "Spec", 457 Old: "", 458 New: "*/15 * * * * *", 459 }, 460 { 461 Type: DiffTypeAdded, 462 Name: "SpecType", 463 Old: "", 464 New: "foo", 465 }, 466 { 467 Type: DiffTypeAdded, 468 Name: "TimeZone", 469 Old: "", 470 New: "Europe/Minsk", 471 }, 472 }, 473 }, 474 }, 475 }, 476 }, 477 { 478 // Periodic deleted 479 Old: &Job{ 480 Periodic: &PeriodicConfig{ 481 Enabled: false, 482 Spec: "*/15 * * * * *", 483 SpecType: "foo", 484 ProhibitOverlap: false, 485 TimeZone: "Europe/Minsk", 486 }, 487 }, 488 New: &Job{}, 489 Expected: &JobDiff{ 490 Type: DiffTypeEdited, 491 Objects: []*ObjectDiff{ 492 { 493 Type: DiffTypeDeleted, 494 Name: "Periodic", 495 Fields: []*FieldDiff{ 496 { 497 Type: DiffTypeDeleted, 498 Name: "Enabled", 499 Old: "false", 500 New: "", 501 }, 502 { 503 Type: DiffTypeDeleted, 504 Name: "ProhibitOverlap", 505 Old: "false", 506 New: "", 507 }, 508 { 509 Type: DiffTypeDeleted, 510 Name: "Spec", 511 Old: "*/15 * * * * *", 512 New: "", 513 }, 514 { 515 Type: DiffTypeDeleted, 516 Name: "SpecType", 517 Old: "foo", 518 New: "", 519 }, 520 { 521 Type: DiffTypeDeleted, 522 Name: "TimeZone", 523 Old: "Europe/Minsk", 524 New: "", 525 }, 526 }, 527 }, 528 }, 529 }, 530 }, 531 { 532 // Periodic edited 533 Old: &Job{ 534 Periodic: &PeriodicConfig{ 535 Enabled: false, 536 Spec: "*/15 * * * * *", 537 SpecType: "foo", 538 ProhibitOverlap: false, 539 TimeZone: "Europe/Minsk", 540 }, 541 }, 542 New: &Job{ 543 Periodic: &PeriodicConfig{ 544 Enabled: true, 545 Spec: "* * * * * *", 546 SpecType: "cron", 547 ProhibitOverlap: true, 548 TimeZone: "America/Los_Angeles", 549 }, 550 }, 551 Expected: &JobDiff{ 552 Type: DiffTypeEdited, 553 Objects: []*ObjectDiff{ 554 { 555 Type: DiffTypeEdited, 556 Name: "Periodic", 557 Fields: []*FieldDiff{ 558 { 559 Type: DiffTypeEdited, 560 Name: "Enabled", 561 Old: "false", 562 New: "true", 563 }, 564 { 565 Type: DiffTypeEdited, 566 Name: "ProhibitOverlap", 567 Old: "false", 568 New: "true", 569 }, 570 { 571 Type: DiffTypeEdited, 572 Name: "Spec", 573 Old: "*/15 * * * * *", 574 New: "* * * * * *", 575 }, 576 { 577 Type: DiffTypeEdited, 578 Name: "SpecType", 579 Old: "foo", 580 New: "cron", 581 }, 582 { 583 Type: DiffTypeEdited, 584 Name: "TimeZone", 585 Old: "Europe/Minsk", 586 New: "America/Los_Angeles", 587 }, 588 }, 589 }, 590 }, 591 }, 592 }, 593 { 594 // Periodic edited with context 595 Contextual: true, 596 Old: &Job{ 597 Periodic: &PeriodicConfig{ 598 Enabled: false, 599 Spec: "*/15 * * * * *", 600 SpecType: "foo", 601 ProhibitOverlap: false, 602 TimeZone: "Europe/Minsk", 603 }, 604 }, 605 New: &Job{ 606 Periodic: &PeriodicConfig{ 607 Enabled: true, 608 Spec: "* * * * * *", 609 SpecType: "foo", 610 ProhibitOverlap: false, 611 TimeZone: "Europe/Minsk", 612 }, 613 }, 614 Expected: &JobDiff{ 615 Type: DiffTypeEdited, 616 Objects: []*ObjectDiff{ 617 { 618 Type: DiffTypeEdited, 619 Name: "Periodic", 620 Fields: []*FieldDiff{ 621 { 622 Type: DiffTypeEdited, 623 Name: "Enabled", 624 Old: "false", 625 New: "true", 626 }, 627 { 628 Type: DiffTypeNone, 629 Name: "ProhibitOverlap", 630 Old: "false", 631 New: "false", 632 }, 633 { 634 Type: DiffTypeEdited, 635 Name: "Spec", 636 Old: "*/15 * * * * *", 637 New: "* * * * * *", 638 }, 639 { 640 Type: DiffTypeNone, 641 Name: "SpecType", 642 Old: "foo", 643 New: "foo", 644 }, 645 { 646 Type: DiffTypeNone, 647 Name: "TimeZone", 648 Old: "Europe/Minsk", 649 New: "Europe/Minsk", 650 }, 651 }, 652 }, 653 }, 654 }, 655 }, 656 { 657 // Constraints edited 658 Old: &Job{ 659 Constraints: []*Constraint{ 660 { 661 LTarget: "foo", 662 RTarget: "foo", 663 Operand: "foo", 664 str: "foo", 665 }, 666 { 667 LTarget: "bar", 668 RTarget: "bar", 669 Operand: "bar", 670 str: "bar", 671 }, 672 }, 673 }, 674 New: &Job{ 675 Constraints: []*Constraint{ 676 { 677 LTarget: "foo", 678 RTarget: "foo", 679 Operand: "foo", 680 str: "foo", 681 }, 682 { 683 LTarget: "baz", 684 RTarget: "baz", 685 Operand: "baz", 686 str: "baz", 687 }, 688 }, 689 }, 690 Expected: &JobDiff{ 691 Type: DiffTypeEdited, 692 Objects: []*ObjectDiff{ 693 { 694 Type: DiffTypeAdded, 695 Name: "Constraint", 696 Fields: []*FieldDiff{ 697 { 698 Type: DiffTypeAdded, 699 Name: "LTarget", 700 Old: "", 701 New: "baz", 702 }, 703 { 704 Type: DiffTypeAdded, 705 Name: "Operand", 706 Old: "", 707 New: "baz", 708 }, 709 { 710 Type: DiffTypeAdded, 711 Name: "RTarget", 712 Old: "", 713 New: "baz", 714 }, 715 }, 716 }, 717 { 718 Type: DiffTypeDeleted, 719 Name: "Constraint", 720 Fields: []*FieldDiff{ 721 { 722 Type: DiffTypeDeleted, 723 Name: "LTarget", 724 Old: "bar", 725 New: "", 726 }, 727 { 728 Type: DiffTypeDeleted, 729 Name: "Operand", 730 Old: "bar", 731 New: "", 732 }, 733 { 734 Type: DiffTypeDeleted, 735 Name: "RTarget", 736 Old: "bar", 737 New: "", 738 }, 739 }, 740 }, 741 }, 742 }, 743 }, 744 { 745 // Task groups edited 746 Old: &Job{ 747 TaskGroups: []*TaskGroup{ 748 { 749 Name: "foo", 750 Count: 1, 751 }, 752 { 753 Name: "bar", 754 Count: 1, 755 }, 756 { 757 Name: "baz", 758 Count: 1, 759 }, 760 }, 761 }, 762 New: &Job{ 763 TaskGroups: []*TaskGroup{ 764 { 765 Name: "bar", 766 Count: 1, 767 }, 768 { 769 Name: "baz", 770 Count: 2, 771 }, 772 { 773 Name: "bam", 774 Count: 1, 775 }, 776 }, 777 }, 778 Expected: &JobDiff{ 779 Type: DiffTypeEdited, 780 TaskGroups: []*TaskGroupDiff{ 781 { 782 Type: DiffTypeAdded, 783 Name: "bam", 784 Fields: []*FieldDiff{ 785 { 786 Type: DiffTypeAdded, 787 Name: "Count", 788 Old: "", 789 New: "1", 790 }, 791 }, 792 }, 793 { 794 Type: DiffTypeNone, 795 Name: "bar", 796 }, 797 { 798 Type: DiffTypeEdited, 799 Name: "baz", 800 Fields: []*FieldDiff{ 801 { 802 Type: DiffTypeEdited, 803 Name: "Count", 804 Old: "1", 805 New: "2", 806 }, 807 }, 808 }, 809 { 810 Type: DiffTypeDeleted, 811 Name: "foo", 812 Fields: []*FieldDiff{ 813 { 814 Type: DiffTypeDeleted, 815 Name: "Count", 816 Old: "1", 817 New: "", 818 }, 819 }, 820 }, 821 }, 822 }, 823 }, 824 { 825 // Parameterized Job added 826 Old: &Job{}, 827 New: &Job{ 828 ParameterizedJob: &ParameterizedJobConfig{ 829 Payload: DispatchPayloadRequired, 830 MetaOptional: []string{"foo"}, 831 MetaRequired: []string{"bar"}, 832 }, 833 }, 834 Expected: &JobDiff{ 835 Type: DiffTypeEdited, 836 Objects: []*ObjectDiff{ 837 { 838 Type: DiffTypeAdded, 839 Name: "ParameterizedJob", 840 Fields: []*FieldDiff{ 841 { 842 Type: DiffTypeAdded, 843 Name: "Payload", 844 Old: "", 845 New: DispatchPayloadRequired, 846 }, 847 }, 848 Objects: []*ObjectDiff{ 849 { 850 Type: DiffTypeAdded, 851 Name: "MetaOptional", 852 Fields: []*FieldDiff{ 853 { 854 Type: DiffTypeAdded, 855 Name: "MetaOptional", 856 Old: "", 857 New: "foo", 858 }, 859 }, 860 }, 861 { 862 Type: DiffTypeAdded, 863 Name: "MetaRequired", 864 Fields: []*FieldDiff{ 865 { 866 Type: DiffTypeAdded, 867 Name: "MetaRequired", 868 Old: "", 869 New: "bar", 870 }, 871 }, 872 }, 873 }, 874 }, 875 }, 876 }, 877 }, 878 { 879 // Parameterized Job deleted 880 Old: &Job{ 881 ParameterizedJob: &ParameterizedJobConfig{ 882 Payload: DispatchPayloadRequired, 883 MetaOptional: []string{"foo"}, 884 MetaRequired: []string{"bar"}, 885 }, 886 }, 887 New: &Job{}, 888 Expected: &JobDiff{ 889 Type: DiffTypeEdited, 890 Objects: []*ObjectDiff{ 891 { 892 Type: DiffTypeDeleted, 893 Name: "ParameterizedJob", 894 Fields: []*FieldDiff{ 895 { 896 Type: DiffTypeDeleted, 897 Name: "Payload", 898 Old: DispatchPayloadRequired, 899 New: "", 900 }, 901 }, 902 Objects: []*ObjectDiff{ 903 { 904 Type: DiffTypeDeleted, 905 Name: "MetaOptional", 906 Fields: []*FieldDiff{ 907 { 908 Type: DiffTypeDeleted, 909 Name: "MetaOptional", 910 Old: "foo", 911 New: "", 912 }, 913 }, 914 }, 915 { 916 Type: DiffTypeDeleted, 917 Name: "MetaRequired", 918 Fields: []*FieldDiff{ 919 { 920 Type: DiffTypeDeleted, 921 Name: "MetaRequired", 922 Old: "bar", 923 New: "", 924 }, 925 }, 926 }, 927 }, 928 }, 929 }, 930 }, 931 }, 932 { 933 // Parameterized Job edited 934 Old: &Job{ 935 ParameterizedJob: &ParameterizedJobConfig{ 936 Payload: DispatchPayloadRequired, 937 MetaOptional: []string{"foo"}, 938 MetaRequired: []string{"bar"}, 939 }, 940 }, 941 New: &Job{ 942 ParameterizedJob: &ParameterizedJobConfig{ 943 Payload: DispatchPayloadOptional, 944 MetaOptional: []string{"bam"}, 945 MetaRequired: []string{"bang"}, 946 }, 947 }, 948 Expected: &JobDiff{ 949 Type: DiffTypeEdited, 950 Objects: []*ObjectDiff{ 951 { 952 Type: DiffTypeEdited, 953 Name: "ParameterizedJob", 954 Fields: []*FieldDiff{ 955 { 956 Type: DiffTypeEdited, 957 Name: "Payload", 958 Old: DispatchPayloadRequired, 959 New: DispatchPayloadOptional, 960 }, 961 }, 962 Objects: []*ObjectDiff{ 963 { 964 Type: DiffTypeEdited, 965 Name: "MetaOptional", 966 Fields: []*FieldDiff{ 967 { 968 Type: DiffTypeAdded, 969 Name: "MetaOptional", 970 Old: "", 971 New: "bam", 972 }, 973 { 974 Type: DiffTypeDeleted, 975 Name: "MetaOptional", 976 Old: "foo", 977 New: "", 978 }, 979 }, 980 }, 981 { 982 Type: DiffTypeEdited, 983 Name: "MetaRequired", 984 Fields: []*FieldDiff{ 985 { 986 Type: DiffTypeAdded, 987 Name: "MetaRequired", 988 Old: "", 989 New: "bang", 990 }, 991 { 992 Type: DiffTypeDeleted, 993 Name: "MetaRequired", 994 Old: "bar", 995 New: "", 996 }, 997 }, 998 }, 999 }, 1000 }, 1001 }, 1002 }, 1003 }, 1004 { 1005 // Parameterized Job edited with context 1006 Contextual: true, 1007 Old: &Job{ 1008 ParameterizedJob: &ParameterizedJobConfig{ 1009 Payload: DispatchPayloadRequired, 1010 MetaOptional: []string{"foo"}, 1011 MetaRequired: []string{"bar"}, 1012 }, 1013 }, 1014 New: &Job{ 1015 ParameterizedJob: &ParameterizedJobConfig{ 1016 Payload: DispatchPayloadOptional, 1017 MetaOptional: []string{"foo"}, 1018 MetaRequired: []string{"bar"}, 1019 }, 1020 }, 1021 Expected: &JobDiff{ 1022 Type: DiffTypeEdited, 1023 Objects: []*ObjectDiff{ 1024 { 1025 Type: DiffTypeEdited, 1026 Name: "ParameterizedJob", 1027 Fields: []*FieldDiff{ 1028 { 1029 Type: DiffTypeEdited, 1030 Name: "Payload", 1031 Old: DispatchPayloadRequired, 1032 New: DispatchPayloadOptional, 1033 }, 1034 }, 1035 Objects: []*ObjectDiff{ 1036 { 1037 Type: DiffTypeNone, 1038 Name: "MetaOptional", 1039 Fields: []*FieldDiff{ 1040 { 1041 Type: DiffTypeNone, 1042 Name: "MetaOptional", 1043 Old: "foo", 1044 New: "foo", 1045 }, 1046 }, 1047 }, 1048 { 1049 Type: DiffTypeNone, 1050 Name: "MetaRequired", 1051 Fields: []*FieldDiff{ 1052 { 1053 Type: DiffTypeNone, 1054 Name: "MetaRequired", 1055 Old: "bar", 1056 New: "bar", 1057 }, 1058 }, 1059 }, 1060 }, 1061 }, 1062 }, 1063 }, 1064 }, 1065 } 1066 1067 for i, c := range cases { 1068 actual, err := c.Old.Diff(c.New, c.Contextual) 1069 if c.Error && err == nil { 1070 t.Fatalf("case %d: expected errored", i+1) 1071 } else if err != nil { 1072 if !c.Error { 1073 t.Fatalf("case %d: errored %#v", i+1, err) 1074 } else { 1075 continue 1076 } 1077 } 1078 1079 if !reflect.DeepEqual(actual, c.Expected) { 1080 t.Fatalf("case %d: got:\n%#v\n want:\n%#v\n", 1081 i+1, actual, c.Expected) 1082 } 1083 } 1084 } 1085 1086 func TestTaskGroupDiff(t *testing.T) { 1087 cases := []struct { 1088 Old, New *TaskGroup 1089 Expected *TaskGroupDiff 1090 Error bool 1091 Contextual bool 1092 }{ 1093 { 1094 Old: nil, 1095 New: nil, 1096 Expected: &TaskGroupDiff{ 1097 Type: DiffTypeNone, 1098 }, 1099 }, 1100 { 1101 // Primitive only that has different names 1102 Old: &TaskGroup{ 1103 Name: "foo", 1104 Count: 10, 1105 Meta: map[string]string{ 1106 "foo": "bar", 1107 }, 1108 }, 1109 New: &TaskGroup{ 1110 Name: "bar", 1111 Count: 10, 1112 Meta: map[string]string{ 1113 "foo": "bar", 1114 }, 1115 }, 1116 Error: true, 1117 }, 1118 { 1119 // Primitive only that is the same 1120 Old: &TaskGroup{ 1121 Name: "foo", 1122 Count: 10, 1123 Meta: map[string]string{ 1124 "foo": "bar", 1125 }, 1126 }, 1127 New: &TaskGroup{ 1128 Name: "foo", 1129 Count: 10, 1130 Meta: map[string]string{ 1131 "foo": "bar", 1132 }, 1133 }, 1134 Expected: &TaskGroupDiff{ 1135 Type: DiffTypeNone, 1136 Name: "foo", 1137 }, 1138 }, 1139 { 1140 // Primitive only that has diffs 1141 Old: &TaskGroup{ 1142 Name: "foo", 1143 Count: 10, 1144 Meta: map[string]string{ 1145 "foo": "bar", 1146 }, 1147 }, 1148 New: &TaskGroup{ 1149 Name: "foo", 1150 Count: 100, 1151 Meta: map[string]string{ 1152 "foo": "baz", 1153 }, 1154 }, 1155 Expected: &TaskGroupDiff{ 1156 Type: DiffTypeEdited, 1157 Name: "foo", 1158 Fields: []*FieldDiff{ 1159 { 1160 Type: DiffTypeEdited, 1161 Name: "Count", 1162 Old: "10", 1163 New: "100", 1164 }, 1165 { 1166 Type: DiffTypeEdited, 1167 Name: "Meta[foo]", 1168 Old: "bar", 1169 New: "baz", 1170 }, 1171 }, 1172 }, 1173 }, 1174 { 1175 // Map diff 1176 Old: &TaskGroup{ 1177 Meta: map[string]string{ 1178 "foo": "foo", 1179 "bar": "bar", 1180 }, 1181 }, 1182 New: &TaskGroup{ 1183 Meta: map[string]string{ 1184 "bar": "bar", 1185 "baz": "baz", 1186 }, 1187 }, 1188 Expected: &TaskGroupDiff{ 1189 Type: DiffTypeEdited, 1190 Fields: []*FieldDiff{ 1191 { 1192 Type: DiffTypeAdded, 1193 Name: "Meta[baz]", 1194 Old: "", 1195 New: "baz", 1196 }, 1197 { 1198 Type: DiffTypeDeleted, 1199 Name: "Meta[foo]", 1200 Old: "foo", 1201 New: "", 1202 }, 1203 }, 1204 }, 1205 }, 1206 { 1207 // Constraints edited 1208 Old: &TaskGroup{ 1209 Constraints: []*Constraint{ 1210 { 1211 LTarget: "foo", 1212 RTarget: "foo", 1213 Operand: "foo", 1214 str: "foo", 1215 }, 1216 { 1217 LTarget: "bar", 1218 RTarget: "bar", 1219 Operand: "bar", 1220 str: "bar", 1221 }, 1222 }, 1223 }, 1224 New: &TaskGroup{ 1225 Constraints: []*Constraint{ 1226 { 1227 LTarget: "foo", 1228 RTarget: "foo", 1229 Operand: "foo", 1230 str: "foo", 1231 }, 1232 { 1233 LTarget: "baz", 1234 RTarget: "baz", 1235 Operand: "baz", 1236 str: "baz", 1237 }, 1238 }, 1239 }, 1240 Expected: &TaskGroupDiff{ 1241 Type: DiffTypeEdited, 1242 Objects: []*ObjectDiff{ 1243 { 1244 Type: DiffTypeAdded, 1245 Name: "Constraint", 1246 Fields: []*FieldDiff{ 1247 { 1248 Type: DiffTypeAdded, 1249 Name: "LTarget", 1250 Old: "", 1251 New: "baz", 1252 }, 1253 { 1254 Type: DiffTypeAdded, 1255 Name: "Operand", 1256 Old: "", 1257 New: "baz", 1258 }, 1259 { 1260 Type: DiffTypeAdded, 1261 Name: "RTarget", 1262 Old: "", 1263 New: "baz", 1264 }, 1265 }, 1266 }, 1267 { 1268 Type: DiffTypeDeleted, 1269 Name: "Constraint", 1270 Fields: []*FieldDiff{ 1271 { 1272 Type: DiffTypeDeleted, 1273 Name: "LTarget", 1274 Old: "bar", 1275 New: "", 1276 }, 1277 { 1278 Type: DiffTypeDeleted, 1279 Name: "Operand", 1280 Old: "bar", 1281 New: "", 1282 }, 1283 { 1284 Type: DiffTypeDeleted, 1285 Name: "RTarget", 1286 Old: "bar", 1287 New: "", 1288 }, 1289 }, 1290 }, 1291 }, 1292 }, 1293 }, 1294 { 1295 // RestartPolicy added 1296 Old: &TaskGroup{}, 1297 New: &TaskGroup{ 1298 RestartPolicy: &RestartPolicy{ 1299 Attempts: 1, 1300 Interval: 1 * time.Second, 1301 Delay: 1 * time.Second, 1302 Mode: "fail", 1303 }, 1304 }, 1305 Expected: &TaskGroupDiff{ 1306 Type: DiffTypeEdited, 1307 Objects: []*ObjectDiff{ 1308 { 1309 Type: DiffTypeAdded, 1310 Name: "RestartPolicy", 1311 Fields: []*FieldDiff{ 1312 { 1313 Type: DiffTypeAdded, 1314 Name: "Attempts", 1315 Old: "", 1316 New: "1", 1317 }, 1318 { 1319 Type: DiffTypeAdded, 1320 Name: "Delay", 1321 Old: "", 1322 New: "1000000000", 1323 }, 1324 { 1325 Type: DiffTypeAdded, 1326 Name: "Interval", 1327 Old: "", 1328 New: "1000000000", 1329 }, 1330 { 1331 Type: DiffTypeAdded, 1332 Name: "Mode", 1333 Old: "", 1334 New: "fail", 1335 }, 1336 }, 1337 }, 1338 }, 1339 }, 1340 }, 1341 { 1342 // RestartPolicy deleted 1343 Old: &TaskGroup{ 1344 RestartPolicy: &RestartPolicy{ 1345 Attempts: 1, 1346 Interval: 1 * time.Second, 1347 Delay: 1 * time.Second, 1348 Mode: "fail", 1349 }, 1350 }, 1351 New: &TaskGroup{}, 1352 Expected: &TaskGroupDiff{ 1353 Type: DiffTypeEdited, 1354 Objects: []*ObjectDiff{ 1355 { 1356 Type: DiffTypeDeleted, 1357 Name: "RestartPolicy", 1358 Fields: []*FieldDiff{ 1359 { 1360 Type: DiffTypeDeleted, 1361 Name: "Attempts", 1362 Old: "1", 1363 New: "", 1364 }, 1365 { 1366 Type: DiffTypeDeleted, 1367 Name: "Delay", 1368 Old: "1000000000", 1369 New: "", 1370 }, 1371 { 1372 Type: DiffTypeDeleted, 1373 Name: "Interval", 1374 Old: "1000000000", 1375 New: "", 1376 }, 1377 { 1378 Type: DiffTypeDeleted, 1379 Name: "Mode", 1380 Old: "fail", 1381 New: "", 1382 }, 1383 }, 1384 }, 1385 }, 1386 }, 1387 }, 1388 { 1389 // RestartPolicy edited 1390 Old: &TaskGroup{ 1391 RestartPolicy: &RestartPolicy{ 1392 Attempts: 1, 1393 Interval: 1 * time.Second, 1394 Delay: 1 * time.Second, 1395 Mode: "fail", 1396 }, 1397 }, 1398 New: &TaskGroup{ 1399 RestartPolicy: &RestartPolicy{ 1400 Attempts: 2, 1401 Interval: 2 * time.Second, 1402 Delay: 2 * time.Second, 1403 Mode: "delay", 1404 }, 1405 }, 1406 Expected: &TaskGroupDiff{ 1407 Type: DiffTypeEdited, 1408 Objects: []*ObjectDiff{ 1409 { 1410 Type: DiffTypeEdited, 1411 Name: "RestartPolicy", 1412 Fields: []*FieldDiff{ 1413 { 1414 Type: DiffTypeEdited, 1415 Name: "Attempts", 1416 Old: "1", 1417 New: "2", 1418 }, 1419 { 1420 Type: DiffTypeEdited, 1421 Name: "Delay", 1422 Old: "1000000000", 1423 New: "2000000000", 1424 }, 1425 { 1426 Type: DiffTypeEdited, 1427 Name: "Interval", 1428 Old: "1000000000", 1429 New: "2000000000", 1430 }, 1431 { 1432 Type: DiffTypeEdited, 1433 Name: "Mode", 1434 Old: "fail", 1435 New: "delay", 1436 }, 1437 }, 1438 }, 1439 }, 1440 }, 1441 }, 1442 { 1443 // RestartPolicy edited with context 1444 Contextual: true, 1445 Old: &TaskGroup{ 1446 RestartPolicy: &RestartPolicy{ 1447 Attempts: 1, 1448 Interval: 1 * time.Second, 1449 Delay: 1 * time.Second, 1450 Mode: "fail", 1451 }, 1452 }, 1453 New: &TaskGroup{ 1454 RestartPolicy: &RestartPolicy{ 1455 Attempts: 2, 1456 Interval: 2 * time.Second, 1457 Delay: 1 * time.Second, 1458 Mode: "fail", 1459 }, 1460 }, 1461 Expected: &TaskGroupDiff{ 1462 Type: DiffTypeEdited, 1463 Objects: []*ObjectDiff{ 1464 { 1465 Type: DiffTypeEdited, 1466 Name: "RestartPolicy", 1467 Fields: []*FieldDiff{ 1468 { 1469 Type: DiffTypeEdited, 1470 Name: "Attempts", 1471 Old: "1", 1472 New: "2", 1473 }, 1474 { 1475 Type: DiffTypeNone, 1476 Name: "Delay", 1477 Old: "1000000000", 1478 New: "1000000000", 1479 }, 1480 { 1481 Type: DiffTypeEdited, 1482 Name: "Interval", 1483 Old: "1000000000", 1484 New: "2000000000", 1485 }, 1486 { 1487 Type: DiffTypeNone, 1488 Name: "Mode", 1489 Old: "fail", 1490 New: "fail", 1491 }, 1492 }, 1493 }, 1494 }, 1495 }, 1496 }, 1497 { 1498 // ReschedulePolicy added 1499 Old: &TaskGroup{}, 1500 New: &TaskGroup{ 1501 ReschedulePolicy: &ReschedulePolicy{ 1502 Attempts: 1, 1503 Interval: 15 * time.Second, 1504 Delay: 5 * time.Second, 1505 MaxDelay: 20 * time.Second, 1506 DelayFunction: "exponential", 1507 Unlimited: false, 1508 }, 1509 }, 1510 Expected: &TaskGroupDiff{ 1511 Type: DiffTypeEdited, 1512 Objects: []*ObjectDiff{ 1513 { 1514 Type: DiffTypeAdded, 1515 Name: "ReschedulePolicy", 1516 Fields: []*FieldDiff{ 1517 { 1518 Type: DiffTypeAdded, 1519 Name: "Attempts", 1520 Old: "", 1521 New: "1", 1522 }, 1523 { 1524 Type: DiffTypeAdded, 1525 Name: "Delay", 1526 Old: "", 1527 New: "5000000000", 1528 }, 1529 { 1530 Type: DiffTypeAdded, 1531 Name: "DelayFunction", 1532 Old: "", 1533 New: "exponential", 1534 }, 1535 { 1536 Type: DiffTypeAdded, 1537 Name: "Interval", 1538 Old: "", 1539 New: "15000000000", 1540 }, 1541 { 1542 Type: DiffTypeAdded, 1543 Name: "MaxDelay", 1544 Old: "", 1545 New: "20000000000", 1546 }, 1547 { 1548 Type: DiffTypeAdded, 1549 Name: "Unlimited", 1550 Old: "", 1551 New: "false", 1552 }, 1553 }, 1554 }, 1555 }, 1556 }, 1557 }, 1558 { 1559 // ReschedulePolicy deleted 1560 Old: &TaskGroup{ 1561 ReschedulePolicy: &ReschedulePolicy{ 1562 Attempts: 1, 1563 Interval: 15 * time.Second, 1564 Delay: 5 * time.Second, 1565 MaxDelay: 20 * time.Second, 1566 DelayFunction: "exponential", 1567 Unlimited: false, 1568 }, 1569 }, 1570 New: &TaskGroup{}, 1571 Expected: &TaskGroupDiff{ 1572 Type: DiffTypeEdited, 1573 Objects: []*ObjectDiff{ 1574 { 1575 Type: DiffTypeDeleted, 1576 Name: "ReschedulePolicy", 1577 Fields: []*FieldDiff{ 1578 { 1579 Type: DiffTypeDeleted, 1580 Name: "Attempts", 1581 Old: "1", 1582 New: "", 1583 }, 1584 { 1585 Type: DiffTypeDeleted, 1586 Name: "Delay", 1587 Old: "5000000000", 1588 New: "", 1589 }, 1590 { 1591 Type: DiffTypeDeleted, 1592 Name: "DelayFunction", 1593 Old: "exponential", 1594 New: "", 1595 }, 1596 { 1597 Type: DiffTypeDeleted, 1598 Name: "Interval", 1599 Old: "15000000000", 1600 New: "", 1601 }, 1602 { 1603 Type: DiffTypeDeleted, 1604 Name: "MaxDelay", 1605 Old: "20000000000", 1606 New: "", 1607 }, 1608 { 1609 Type: DiffTypeDeleted, 1610 Name: "Unlimited", 1611 Old: "false", 1612 New: "", 1613 }, 1614 }, 1615 }, 1616 }, 1617 }, 1618 }, 1619 { 1620 // ReschedulePolicy edited 1621 Old: &TaskGroup{ 1622 ReschedulePolicy: &ReschedulePolicy{ 1623 Attempts: 1, 1624 Interval: 1 * time.Second, 1625 DelayFunction: "exponential", 1626 Delay: 20 * time.Second, 1627 MaxDelay: 1 * time.Minute, 1628 Unlimited: false, 1629 }, 1630 }, 1631 New: &TaskGroup{ 1632 ReschedulePolicy: &ReschedulePolicy{ 1633 Attempts: 2, 1634 Interval: 2 * time.Second, 1635 DelayFunction: "constant", 1636 Delay: 30 * time.Second, 1637 MaxDelay: 1 * time.Minute, 1638 Unlimited: true, 1639 }, 1640 }, 1641 Expected: &TaskGroupDiff{ 1642 Type: DiffTypeEdited, 1643 Objects: []*ObjectDiff{ 1644 { 1645 Type: DiffTypeEdited, 1646 Name: "ReschedulePolicy", 1647 Fields: []*FieldDiff{ 1648 { 1649 Type: DiffTypeEdited, 1650 Name: "Attempts", 1651 Old: "1", 1652 New: "2", 1653 }, 1654 { 1655 Type: DiffTypeEdited, 1656 Name: "Delay", 1657 Old: "20000000000", 1658 New: "30000000000", 1659 }, 1660 { 1661 Type: DiffTypeEdited, 1662 Name: "DelayFunction", 1663 Old: "exponential", 1664 New: "constant", 1665 }, 1666 { 1667 Type: DiffTypeEdited, 1668 Name: "Interval", 1669 Old: "1000000000", 1670 New: "2000000000", 1671 }, 1672 { 1673 Type: DiffTypeEdited, 1674 Name: "Unlimited", 1675 Old: "false", 1676 New: "true", 1677 }, 1678 }, 1679 }, 1680 }, 1681 }, 1682 }, { 1683 // ReschedulePolicy edited with context 1684 Contextual: true, 1685 Old: &TaskGroup{ 1686 ReschedulePolicy: &ReschedulePolicy{ 1687 Attempts: 1, 1688 Interval: 1 * time.Second, 1689 }, 1690 }, 1691 New: &TaskGroup{ 1692 ReschedulePolicy: &ReschedulePolicy{ 1693 Attempts: 1, 1694 Interval: 2 * time.Second, 1695 }, 1696 }, 1697 Expected: &TaskGroupDiff{ 1698 Type: DiffTypeEdited, 1699 Objects: []*ObjectDiff{ 1700 { 1701 Type: DiffTypeEdited, 1702 Name: "ReschedulePolicy", 1703 Fields: []*FieldDiff{ 1704 { 1705 Type: DiffTypeNone, 1706 Name: "Attempts", 1707 Old: "1", 1708 New: "1", 1709 }, 1710 { 1711 Type: DiffTypeNone, 1712 Name: "Delay", 1713 Old: "0", 1714 New: "0", 1715 }, 1716 { 1717 Type: DiffTypeNone, 1718 Name: "DelayFunction", 1719 Old: "", 1720 New: "", 1721 }, 1722 { 1723 Type: DiffTypeEdited, 1724 Name: "Interval", 1725 Old: "1000000000", 1726 New: "2000000000", 1727 }, 1728 { 1729 Type: DiffTypeNone, 1730 Name: "MaxDelay", 1731 Old: "0", 1732 New: "0", 1733 }, 1734 { 1735 Type: DiffTypeNone, 1736 Name: "Unlimited", 1737 Old: "false", 1738 New: "false", 1739 }, 1740 }, 1741 }, 1742 }, 1743 }, 1744 }, 1745 { 1746 // Update strategy deleted 1747 Old: &TaskGroup{ 1748 Update: &UpdateStrategy{ 1749 AutoRevert: true, 1750 }, 1751 }, 1752 New: &TaskGroup{}, 1753 Expected: &TaskGroupDiff{ 1754 Type: DiffTypeEdited, 1755 Objects: []*ObjectDiff{ 1756 { 1757 Type: DiffTypeDeleted, 1758 Name: "Update", 1759 Fields: []*FieldDiff{ 1760 { 1761 Type: DiffTypeDeleted, 1762 Name: "AutoRevert", 1763 Old: "true", 1764 New: "", 1765 }, 1766 { 1767 Type: DiffTypeDeleted, 1768 Name: "Canary", 1769 Old: "0", 1770 New: "", 1771 }, 1772 { 1773 Type: DiffTypeDeleted, 1774 Name: "HealthyDeadline", 1775 Old: "0", 1776 New: "", 1777 }, 1778 { 1779 Type: DiffTypeDeleted, 1780 Name: "MaxParallel", 1781 Old: "0", 1782 New: "", 1783 }, 1784 { 1785 Type: DiffTypeDeleted, 1786 Name: "MinHealthyTime", 1787 Old: "0", 1788 New: "", 1789 }, 1790 }, 1791 }, 1792 }, 1793 }, 1794 }, 1795 { 1796 // Update strategy added 1797 Old: &TaskGroup{}, 1798 New: &TaskGroup{ 1799 Update: &UpdateStrategy{ 1800 AutoRevert: true, 1801 }, 1802 }, 1803 Expected: &TaskGroupDiff{ 1804 Type: DiffTypeEdited, 1805 Objects: []*ObjectDiff{ 1806 { 1807 Type: DiffTypeAdded, 1808 Name: "Update", 1809 Fields: []*FieldDiff{ 1810 { 1811 Type: DiffTypeAdded, 1812 Name: "AutoRevert", 1813 Old: "", 1814 New: "true", 1815 }, 1816 { 1817 Type: DiffTypeAdded, 1818 Name: "Canary", 1819 Old: "", 1820 New: "0", 1821 }, 1822 { 1823 Type: DiffTypeAdded, 1824 Name: "HealthyDeadline", 1825 Old: "", 1826 New: "0", 1827 }, 1828 { 1829 Type: DiffTypeAdded, 1830 Name: "MaxParallel", 1831 Old: "", 1832 New: "0", 1833 }, 1834 { 1835 Type: DiffTypeAdded, 1836 Name: "MinHealthyTime", 1837 Old: "", 1838 New: "0", 1839 }, 1840 }, 1841 }, 1842 }, 1843 }, 1844 }, 1845 { 1846 // Update strategy edited 1847 Old: &TaskGroup{ 1848 Update: &UpdateStrategy{ 1849 MaxParallel: 5, 1850 HealthCheck: "foo", 1851 MinHealthyTime: 1 * time.Second, 1852 HealthyDeadline: 30 * time.Second, 1853 AutoRevert: true, 1854 Canary: 2, 1855 }, 1856 }, 1857 New: &TaskGroup{ 1858 Update: &UpdateStrategy{ 1859 MaxParallel: 7, 1860 HealthCheck: "bar", 1861 MinHealthyTime: 2 * time.Second, 1862 HealthyDeadline: 31 * time.Second, 1863 AutoRevert: false, 1864 Canary: 1, 1865 }, 1866 }, 1867 Expected: &TaskGroupDiff{ 1868 Type: DiffTypeEdited, 1869 Objects: []*ObjectDiff{ 1870 { 1871 Type: DiffTypeEdited, 1872 Name: "Update", 1873 Fields: []*FieldDiff{ 1874 { 1875 Type: DiffTypeEdited, 1876 Name: "AutoRevert", 1877 Old: "true", 1878 New: "false", 1879 }, 1880 { 1881 Type: DiffTypeEdited, 1882 Name: "Canary", 1883 Old: "2", 1884 New: "1", 1885 }, 1886 { 1887 Type: DiffTypeEdited, 1888 Name: "HealthCheck", 1889 Old: "foo", 1890 New: "bar", 1891 }, 1892 { 1893 Type: DiffTypeEdited, 1894 Name: "HealthyDeadline", 1895 Old: "30000000000", 1896 New: "31000000000", 1897 }, 1898 { 1899 Type: DiffTypeEdited, 1900 Name: "MaxParallel", 1901 Old: "5", 1902 New: "7", 1903 }, 1904 { 1905 Type: DiffTypeEdited, 1906 Name: "MinHealthyTime", 1907 Old: "1000000000", 1908 New: "2000000000", 1909 }, 1910 }, 1911 }, 1912 }, 1913 }, 1914 }, 1915 { 1916 // Update strategy edited with context 1917 Contextual: true, 1918 Old: &TaskGroup{ 1919 Update: &UpdateStrategy{ 1920 MaxParallel: 5, 1921 HealthCheck: "foo", 1922 MinHealthyTime: 1 * time.Second, 1923 HealthyDeadline: 30 * time.Second, 1924 AutoRevert: true, 1925 Canary: 2, 1926 }, 1927 }, 1928 New: &TaskGroup{ 1929 Update: &UpdateStrategy{ 1930 MaxParallel: 7, 1931 HealthCheck: "foo", 1932 MinHealthyTime: 1 * time.Second, 1933 HealthyDeadline: 30 * time.Second, 1934 AutoRevert: true, 1935 Canary: 2, 1936 }, 1937 }, 1938 Expected: &TaskGroupDiff{ 1939 Type: DiffTypeEdited, 1940 Objects: []*ObjectDiff{ 1941 { 1942 Type: DiffTypeEdited, 1943 Name: "Update", 1944 Fields: []*FieldDiff{ 1945 { 1946 Type: DiffTypeNone, 1947 Name: "AutoRevert", 1948 Old: "true", 1949 New: "true", 1950 }, 1951 { 1952 Type: DiffTypeNone, 1953 Name: "Canary", 1954 Old: "2", 1955 New: "2", 1956 }, 1957 { 1958 Type: DiffTypeNone, 1959 Name: "HealthCheck", 1960 Old: "foo", 1961 New: "foo", 1962 }, 1963 { 1964 Type: DiffTypeNone, 1965 Name: "HealthyDeadline", 1966 Old: "30000000000", 1967 New: "30000000000", 1968 }, 1969 { 1970 Type: DiffTypeEdited, 1971 Name: "MaxParallel", 1972 Old: "5", 1973 New: "7", 1974 }, 1975 { 1976 Type: DiffTypeNone, 1977 Name: "MinHealthyTime", 1978 Old: "1000000000", 1979 New: "1000000000", 1980 }, 1981 }, 1982 }, 1983 }, 1984 }, 1985 }, 1986 { 1987 // EphemeralDisk added 1988 Old: &TaskGroup{}, 1989 New: &TaskGroup{ 1990 EphemeralDisk: &EphemeralDisk{ 1991 Migrate: true, 1992 Sticky: true, 1993 SizeMB: 100, 1994 }, 1995 }, 1996 Expected: &TaskGroupDiff{ 1997 Type: DiffTypeEdited, 1998 Objects: []*ObjectDiff{ 1999 { 2000 Type: DiffTypeAdded, 2001 Name: "EphemeralDisk", 2002 Fields: []*FieldDiff{ 2003 { 2004 Type: DiffTypeAdded, 2005 Name: "Migrate", 2006 Old: "", 2007 New: "true", 2008 }, 2009 { 2010 Type: DiffTypeAdded, 2011 Name: "SizeMB", 2012 Old: "", 2013 New: "100", 2014 }, 2015 { 2016 Type: DiffTypeAdded, 2017 Name: "Sticky", 2018 Old: "", 2019 New: "true", 2020 }, 2021 }, 2022 }, 2023 }, 2024 }, 2025 }, 2026 { 2027 // EphemeralDisk deleted 2028 Old: &TaskGroup{ 2029 EphemeralDisk: &EphemeralDisk{ 2030 Migrate: true, 2031 Sticky: true, 2032 SizeMB: 100, 2033 }, 2034 }, 2035 New: &TaskGroup{}, 2036 Expected: &TaskGroupDiff{ 2037 Type: DiffTypeEdited, 2038 Objects: []*ObjectDiff{ 2039 { 2040 Type: DiffTypeDeleted, 2041 Name: "EphemeralDisk", 2042 Fields: []*FieldDiff{ 2043 { 2044 Type: DiffTypeDeleted, 2045 Name: "Migrate", 2046 Old: "true", 2047 New: "", 2048 }, 2049 { 2050 Type: DiffTypeDeleted, 2051 Name: "SizeMB", 2052 Old: "100", 2053 New: "", 2054 }, 2055 { 2056 Type: DiffTypeDeleted, 2057 Name: "Sticky", 2058 Old: "true", 2059 New: "", 2060 }, 2061 }, 2062 }, 2063 }, 2064 }, 2065 }, 2066 { 2067 // EphemeralDisk edited 2068 Old: &TaskGroup{ 2069 EphemeralDisk: &EphemeralDisk{ 2070 Migrate: true, 2071 Sticky: true, 2072 SizeMB: 150, 2073 }, 2074 }, 2075 New: &TaskGroup{ 2076 EphemeralDisk: &EphemeralDisk{ 2077 Migrate: false, 2078 Sticky: false, 2079 SizeMB: 90, 2080 }, 2081 }, 2082 Expected: &TaskGroupDiff{ 2083 Type: DiffTypeEdited, 2084 Objects: []*ObjectDiff{ 2085 { 2086 Type: DiffTypeEdited, 2087 Name: "EphemeralDisk", 2088 Fields: []*FieldDiff{ 2089 { 2090 Type: DiffTypeEdited, 2091 Name: "Migrate", 2092 Old: "true", 2093 New: "false", 2094 }, 2095 { 2096 Type: DiffTypeEdited, 2097 Name: "SizeMB", 2098 Old: "150", 2099 New: "90", 2100 }, 2101 2102 { 2103 Type: DiffTypeEdited, 2104 Name: "Sticky", 2105 Old: "true", 2106 New: "false", 2107 }, 2108 }, 2109 }, 2110 }, 2111 }, 2112 }, 2113 { 2114 // EphemeralDisk edited with context 2115 Contextual: true, 2116 Old: &TaskGroup{ 2117 EphemeralDisk: &EphemeralDisk{ 2118 Migrate: false, 2119 Sticky: false, 2120 SizeMB: 100, 2121 }, 2122 }, 2123 New: &TaskGroup{ 2124 EphemeralDisk: &EphemeralDisk{ 2125 Migrate: true, 2126 Sticky: true, 2127 SizeMB: 90, 2128 }, 2129 }, 2130 Expected: &TaskGroupDiff{ 2131 Type: DiffTypeEdited, 2132 Objects: []*ObjectDiff{ 2133 { 2134 Type: DiffTypeEdited, 2135 Name: "EphemeralDisk", 2136 Fields: []*FieldDiff{ 2137 { 2138 Type: DiffTypeEdited, 2139 Name: "Migrate", 2140 Old: "false", 2141 New: "true", 2142 }, 2143 { 2144 Type: DiffTypeEdited, 2145 Name: "SizeMB", 2146 Old: "100", 2147 New: "90", 2148 }, 2149 { 2150 Type: DiffTypeEdited, 2151 Name: "Sticky", 2152 Old: "false", 2153 New: "true", 2154 }, 2155 }, 2156 }, 2157 }, 2158 }, 2159 }, 2160 { 2161 // Tasks edited 2162 Old: &TaskGroup{ 2163 Tasks: []*Task{ 2164 { 2165 Name: "foo", 2166 Driver: "docker", 2167 }, 2168 { 2169 Name: "bar", 2170 Driver: "docker", 2171 }, 2172 { 2173 Name: "baz", 2174 ShutdownDelay: 1 * time.Second, 2175 }, 2176 }, 2177 }, 2178 New: &TaskGroup{ 2179 Tasks: []*Task{ 2180 { 2181 Name: "bar", 2182 Driver: "docker", 2183 }, 2184 { 2185 Name: "bam", 2186 Driver: "docker", 2187 }, 2188 { 2189 Name: "baz", 2190 ShutdownDelay: 2 * time.Second, 2191 }, 2192 }, 2193 }, 2194 Expected: &TaskGroupDiff{ 2195 Type: DiffTypeEdited, 2196 Tasks: []*TaskDiff{ 2197 { 2198 Type: DiffTypeAdded, 2199 Name: "bam", 2200 Fields: []*FieldDiff{ 2201 { 2202 Type: DiffTypeAdded, 2203 Name: "Driver", 2204 Old: "", 2205 New: "docker", 2206 }, 2207 { 2208 Type: DiffTypeAdded, 2209 Name: "KillTimeout", 2210 Old: "", 2211 New: "0", 2212 }, 2213 { 2214 Type: DiffTypeAdded, 2215 Name: "Leader", 2216 Old: "", 2217 New: "false", 2218 }, 2219 { 2220 Type: DiffTypeAdded, 2221 Name: "ShutdownDelay", 2222 Old: "", 2223 New: "0", 2224 }, 2225 }, 2226 }, 2227 { 2228 Type: DiffTypeNone, 2229 Name: "bar", 2230 }, 2231 { 2232 Type: DiffTypeEdited, 2233 Name: "baz", 2234 Fields: []*FieldDiff{ 2235 { 2236 Type: DiffTypeEdited, 2237 Name: "ShutdownDelay", 2238 Old: "1000000000", 2239 New: "2000000000", 2240 }, 2241 }, 2242 }, 2243 { 2244 Type: DiffTypeDeleted, 2245 Name: "foo", 2246 Fields: []*FieldDiff{ 2247 { 2248 Type: DiffTypeDeleted, 2249 Name: "Driver", 2250 Old: "docker", 2251 New: "", 2252 }, 2253 { 2254 Type: DiffTypeDeleted, 2255 Name: "KillTimeout", 2256 Old: "0", 2257 New: "", 2258 }, 2259 { 2260 Type: DiffTypeDeleted, 2261 Name: "Leader", 2262 Old: "false", 2263 New: "", 2264 }, 2265 { 2266 Type: DiffTypeDeleted, 2267 Name: "ShutdownDelay", 2268 Old: "0", 2269 New: "", 2270 }, 2271 }, 2272 }, 2273 }, 2274 }, 2275 }, 2276 } 2277 2278 for i, c := range cases { 2279 actual, err := c.Old.Diff(c.New, c.Contextual) 2280 if c.Error && err == nil { 2281 t.Fatalf("case %d: expected errored", i+1) 2282 } else if err != nil { 2283 if !c.Error { 2284 t.Fatalf("case %d: errored %#v", i+1, err) 2285 } else { 2286 continue 2287 } 2288 } 2289 2290 if !reflect.DeepEqual(actual, c.Expected) { 2291 t.Fatalf("case %d: got:\n%#v\n want:\n%#v\n", 2292 i+1, actual, c.Expected) 2293 } 2294 } 2295 } 2296 2297 func TestTaskDiff(t *testing.T) { 2298 cases := []struct { 2299 Name string 2300 Old, New *Task 2301 Expected *TaskDiff 2302 Error bool 2303 Contextual bool 2304 }{ 2305 { 2306 Name: "Empty", 2307 Old: nil, 2308 New: nil, 2309 Expected: &TaskDiff{ 2310 Type: DiffTypeNone, 2311 }, 2312 }, 2313 { 2314 Name: "Primitive only that has different names", 2315 Old: &Task{ 2316 Name: "foo", 2317 Meta: map[string]string{ 2318 "foo": "bar", 2319 }, 2320 }, 2321 New: &Task{ 2322 Name: "bar", 2323 Meta: map[string]string{ 2324 "foo": "bar", 2325 }, 2326 }, 2327 Error: true, 2328 }, 2329 { 2330 Name: "Primitive only that is the same", 2331 Old: &Task{ 2332 Name: "foo", 2333 Driver: "exec", 2334 User: "foo", 2335 Env: map[string]string{ 2336 "FOO": "bar", 2337 }, 2338 Meta: map[string]string{ 2339 "foo": "bar", 2340 }, 2341 KillTimeout: 1 * time.Second, 2342 Leader: true, 2343 }, 2344 New: &Task{ 2345 Name: "foo", 2346 Driver: "exec", 2347 User: "foo", 2348 Env: map[string]string{ 2349 "FOO": "bar", 2350 }, 2351 Meta: map[string]string{ 2352 "foo": "bar", 2353 }, 2354 KillTimeout: 1 * time.Second, 2355 Leader: true, 2356 }, 2357 Expected: &TaskDiff{ 2358 Type: DiffTypeNone, 2359 Name: "foo", 2360 }, 2361 }, 2362 { 2363 Name: "Primitive only that has diffs", 2364 Old: &Task{ 2365 Name: "foo", 2366 Driver: "exec", 2367 User: "foo", 2368 Env: map[string]string{ 2369 "FOO": "bar", 2370 }, 2371 Meta: map[string]string{ 2372 "foo": "bar", 2373 }, 2374 KillTimeout: 1 * time.Second, 2375 Leader: true, 2376 }, 2377 New: &Task{ 2378 Name: "foo", 2379 Driver: "docker", 2380 User: "bar", 2381 Env: map[string]string{ 2382 "FOO": "baz", 2383 }, 2384 Meta: map[string]string{ 2385 "foo": "baz", 2386 }, 2387 KillTimeout: 2 * time.Second, 2388 Leader: false, 2389 }, 2390 Expected: &TaskDiff{ 2391 Type: DiffTypeEdited, 2392 Name: "foo", 2393 Fields: []*FieldDiff{ 2394 { 2395 Type: DiffTypeEdited, 2396 Name: "Driver", 2397 Old: "exec", 2398 New: "docker", 2399 }, 2400 { 2401 Type: DiffTypeEdited, 2402 Name: "Env[FOO]", 2403 Old: "bar", 2404 New: "baz", 2405 }, 2406 { 2407 Type: DiffTypeEdited, 2408 Name: "KillTimeout", 2409 Old: "1000000000", 2410 New: "2000000000", 2411 }, 2412 { 2413 Type: DiffTypeEdited, 2414 Name: "Leader", 2415 Old: "true", 2416 New: "false", 2417 }, 2418 { 2419 Type: DiffTypeEdited, 2420 Name: "Meta[foo]", 2421 Old: "bar", 2422 New: "baz", 2423 }, 2424 { 2425 Type: DiffTypeEdited, 2426 Name: "User", 2427 Old: "foo", 2428 New: "bar", 2429 }, 2430 }, 2431 }, 2432 }, 2433 { 2434 Name: "Map diff", 2435 Old: &Task{ 2436 Meta: map[string]string{ 2437 "foo": "foo", 2438 "bar": "bar", 2439 }, 2440 Env: map[string]string{ 2441 "foo": "foo", 2442 "bar": "bar", 2443 }, 2444 }, 2445 New: &Task{ 2446 Meta: map[string]string{ 2447 "bar": "bar", 2448 "baz": "baz", 2449 }, 2450 Env: map[string]string{ 2451 "bar": "bar", 2452 "baz": "baz", 2453 }, 2454 }, 2455 Expected: &TaskDiff{ 2456 Type: DiffTypeEdited, 2457 Fields: []*FieldDiff{ 2458 { 2459 Type: DiffTypeAdded, 2460 Name: "Env[baz]", 2461 Old: "", 2462 New: "baz", 2463 }, 2464 { 2465 Type: DiffTypeDeleted, 2466 Name: "Env[foo]", 2467 Old: "foo", 2468 New: "", 2469 }, 2470 { 2471 Type: DiffTypeAdded, 2472 Name: "Meta[baz]", 2473 Old: "", 2474 New: "baz", 2475 }, 2476 { 2477 Type: DiffTypeDeleted, 2478 Name: "Meta[foo]", 2479 Old: "foo", 2480 New: "", 2481 }, 2482 }, 2483 }, 2484 }, 2485 { 2486 Name: "Constraints edited", 2487 Old: &Task{ 2488 Constraints: []*Constraint{ 2489 { 2490 LTarget: "foo", 2491 RTarget: "foo", 2492 Operand: "foo", 2493 str: "foo", 2494 }, 2495 { 2496 LTarget: "bar", 2497 RTarget: "bar", 2498 Operand: "bar", 2499 str: "bar", 2500 }, 2501 }, 2502 }, 2503 New: &Task{ 2504 Constraints: []*Constraint{ 2505 { 2506 LTarget: "foo", 2507 RTarget: "foo", 2508 Operand: "foo", 2509 str: "foo", 2510 }, 2511 { 2512 LTarget: "baz", 2513 RTarget: "baz", 2514 Operand: "baz", 2515 str: "baz", 2516 }, 2517 }, 2518 }, 2519 Expected: &TaskDiff{ 2520 Type: DiffTypeEdited, 2521 Objects: []*ObjectDiff{ 2522 { 2523 Type: DiffTypeAdded, 2524 Name: "Constraint", 2525 Fields: []*FieldDiff{ 2526 { 2527 Type: DiffTypeAdded, 2528 Name: "LTarget", 2529 Old: "", 2530 New: "baz", 2531 }, 2532 { 2533 Type: DiffTypeAdded, 2534 Name: "Operand", 2535 Old: "", 2536 New: "baz", 2537 }, 2538 { 2539 Type: DiffTypeAdded, 2540 Name: "RTarget", 2541 Old: "", 2542 New: "baz", 2543 }, 2544 }, 2545 }, 2546 { 2547 Type: DiffTypeDeleted, 2548 Name: "Constraint", 2549 Fields: []*FieldDiff{ 2550 { 2551 Type: DiffTypeDeleted, 2552 Name: "LTarget", 2553 Old: "bar", 2554 New: "", 2555 }, 2556 { 2557 Type: DiffTypeDeleted, 2558 Name: "Operand", 2559 Old: "bar", 2560 New: "", 2561 }, 2562 { 2563 Type: DiffTypeDeleted, 2564 Name: "RTarget", 2565 Old: "bar", 2566 New: "", 2567 }, 2568 }, 2569 }, 2570 }, 2571 }, 2572 }, 2573 { 2574 Name: "LogConfig added", 2575 Old: &Task{}, 2576 New: &Task{ 2577 LogConfig: &LogConfig{ 2578 MaxFiles: 1, 2579 MaxFileSizeMB: 10, 2580 }, 2581 }, 2582 Expected: &TaskDiff{ 2583 Type: DiffTypeEdited, 2584 Objects: []*ObjectDiff{ 2585 { 2586 Type: DiffTypeAdded, 2587 Name: "LogConfig", 2588 Fields: []*FieldDiff{ 2589 { 2590 Type: DiffTypeAdded, 2591 Name: "MaxFileSizeMB", 2592 Old: "", 2593 New: "10", 2594 }, 2595 { 2596 Type: DiffTypeAdded, 2597 Name: "MaxFiles", 2598 Old: "", 2599 New: "1", 2600 }, 2601 }, 2602 }, 2603 }, 2604 }, 2605 }, 2606 { 2607 Name: "LogConfig deleted", 2608 Old: &Task{ 2609 LogConfig: &LogConfig{ 2610 MaxFiles: 1, 2611 MaxFileSizeMB: 10, 2612 }, 2613 }, 2614 New: &Task{}, 2615 Expected: &TaskDiff{ 2616 Type: DiffTypeEdited, 2617 Objects: []*ObjectDiff{ 2618 { 2619 Type: DiffTypeDeleted, 2620 Name: "LogConfig", 2621 Fields: []*FieldDiff{ 2622 { 2623 Type: DiffTypeDeleted, 2624 Name: "MaxFileSizeMB", 2625 Old: "10", 2626 New: "", 2627 }, 2628 { 2629 Type: DiffTypeDeleted, 2630 Name: "MaxFiles", 2631 Old: "1", 2632 New: "", 2633 }, 2634 }, 2635 }, 2636 }, 2637 }, 2638 }, 2639 { 2640 Name: "LogConfig edited", 2641 Old: &Task{ 2642 LogConfig: &LogConfig{ 2643 MaxFiles: 1, 2644 MaxFileSizeMB: 10, 2645 }, 2646 }, 2647 New: &Task{ 2648 LogConfig: &LogConfig{ 2649 MaxFiles: 2, 2650 MaxFileSizeMB: 20, 2651 }, 2652 }, 2653 Expected: &TaskDiff{ 2654 Type: DiffTypeEdited, 2655 Objects: []*ObjectDiff{ 2656 { 2657 Type: DiffTypeEdited, 2658 Name: "LogConfig", 2659 Fields: []*FieldDiff{ 2660 { 2661 Type: DiffTypeEdited, 2662 Name: "MaxFileSizeMB", 2663 Old: "10", 2664 New: "20", 2665 }, 2666 { 2667 Type: DiffTypeEdited, 2668 Name: "MaxFiles", 2669 Old: "1", 2670 New: "2", 2671 }, 2672 }, 2673 }, 2674 }, 2675 }, 2676 }, 2677 { 2678 Name: "LogConfig edited with context", 2679 Contextual: true, 2680 Old: &Task{ 2681 LogConfig: &LogConfig{ 2682 MaxFiles: 1, 2683 MaxFileSizeMB: 10, 2684 }, 2685 }, 2686 New: &Task{ 2687 LogConfig: &LogConfig{ 2688 MaxFiles: 1, 2689 MaxFileSizeMB: 20, 2690 }, 2691 }, 2692 Expected: &TaskDiff{ 2693 Type: DiffTypeEdited, 2694 Objects: []*ObjectDiff{ 2695 { 2696 Type: DiffTypeEdited, 2697 Name: "LogConfig", 2698 Fields: []*FieldDiff{ 2699 { 2700 Type: DiffTypeEdited, 2701 Name: "MaxFileSizeMB", 2702 Old: "10", 2703 New: "20", 2704 }, 2705 { 2706 Type: DiffTypeNone, 2707 Name: "MaxFiles", 2708 Old: "1", 2709 New: "1", 2710 }, 2711 }, 2712 }, 2713 }, 2714 }, 2715 }, 2716 { 2717 Name: "Artifacts edited", 2718 Old: &Task{ 2719 Artifacts: []*TaskArtifact{ 2720 { 2721 GetterSource: "foo", 2722 GetterOptions: map[string]string{ 2723 "foo": "bar", 2724 }, 2725 RelativeDest: "foo", 2726 }, 2727 { 2728 GetterSource: "bar", 2729 GetterOptions: map[string]string{ 2730 "bar": "baz", 2731 }, 2732 GetterMode: "dir", 2733 RelativeDest: "bar", 2734 }, 2735 }, 2736 }, 2737 New: &Task{ 2738 Artifacts: []*TaskArtifact{ 2739 { 2740 GetterSource: "foo", 2741 GetterOptions: map[string]string{ 2742 "foo": "bar", 2743 }, 2744 RelativeDest: "foo", 2745 }, 2746 { 2747 GetterSource: "bam", 2748 GetterOptions: map[string]string{ 2749 "bam": "baz", 2750 }, 2751 GetterMode: "file", 2752 RelativeDest: "bam", 2753 }, 2754 }, 2755 }, 2756 Expected: &TaskDiff{ 2757 Type: DiffTypeEdited, 2758 Objects: []*ObjectDiff{ 2759 { 2760 Type: DiffTypeAdded, 2761 Name: "Artifact", 2762 Fields: []*FieldDiff{ 2763 { 2764 Type: DiffTypeAdded, 2765 Name: "GetterMode", 2766 Old: "", 2767 New: "file", 2768 }, 2769 { 2770 Type: DiffTypeAdded, 2771 Name: "GetterOptions[bam]", 2772 Old: "", 2773 New: "baz", 2774 }, 2775 { 2776 Type: DiffTypeAdded, 2777 Name: "GetterSource", 2778 Old: "", 2779 New: "bam", 2780 }, 2781 { 2782 Type: DiffTypeAdded, 2783 Name: "RelativeDest", 2784 Old: "", 2785 New: "bam", 2786 }, 2787 }, 2788 }, 2789 { 2790 Type: DiffTypeDeleted, 2791 Name: "Artifact", 2792 Fields: []*FieldDiff{ 2793 { 2794 Type: DiffTypeDeleted, 2795 Name: "GetterMode", 2796 Old: "dir", 2797 New: "", 2798 }, 2799 { 2800 Type: DiffTypeDeleted, 2801 Name: "GetterOptions[bar]", 2802 Old: "baz", 2803 New: "", 2804 }, 2805 { 2806 Type: DiffTypeDeleted, 2807 Name: "GetterSource", 2808 Old: "bar", 2809 New: "", 2810 }, 2811 { 2812 Type: DiffTypeDeleted, 2813 Name: "RelativeDest", 2814 Old: "bar", 2815 New: "", 2816 }, 2817 }, 2818 }, 2819 }, 2820 }, 2821 }, 2822 { 2823 Name: "Resources edited (no networks)", 2824 Old: &Task{ 2825 Resources: &Resources{ 2826 CPU: 100, 2827 MemoryMB: 100, 2828 DiskMB: 100, 2829 IOPS: 100, 2830 }, 2831 }, 2832 New: &Task{ 2833 Resources: &Resources{ 2834 CPU: 200, 2835 MemoryMB: 200, 2836 DiskMB: 200, 2837 IOPS: 200, 2838 }, 2839 }, 2840 Expected: &TaskDiff{ 2841 Type: DiffTypeEdited, 2842 Objects: []*ObjectDiff{ 2843 { 2844 Type: DiffTypeEdited, 2845 Name: "Resources", 2846 Fields: []*FieldDiff{ 2847 { 2848 Type: DiffTypeEdited, 2849 Name: "CPU", 2850 Old: "100", 2851 New: "200", 2852 }, 2853 { 2854 Type: DiffTypeEdited, 2855 Name: "DiskMB", 2856 Old: "100", 2857 New: "200", 2858 }, 2859 { 2860 Type: DiffTypeEdited, 2861 Name: "IOPS", 2862 Old: "100", 2863 New: "200", 2864 }, 2865 { 2866 Type: DiffTypeEdited, 2867 Name: "MemoryMB", 2868 Old: "100", 2869 New: "200", 2870 }, 2871 }, 2872 }, 2873 }, 2874 }, 2875 }, 2876 { 2877 Name: "Resources edited (no networks) with context", 2878 Contextual: true, 2879 Old: &Task{ 2880 Resources: &Resources{ 2881 CPU: 100, 2882 MemoryMB: 100, 2883 DiskMB: 100, 2884 IOPS: 100, 2885 }, 2886 }, 2887 New: &Task{ 2888 Resources: &Resources{ 2889 CPU: 200, 2890 MemoryMB: 100, 2891 DiskMB: 200, 2892 IOPS: 100, 2893 }, 2894 }, 2895 Expected: &TaskDiff{ 2896 Type: DiffTypeEdited, 2897 Objects: []*ObjectDiff{ 2898 { 2899 Type: DiffTypeEdited, 2900 Name: "Resources", 2901 Fields: []*FieldDiff{ 2902 { 2903 Type: DiffTypeEdited, 2904 Name: "CPU", 2905 Old: "100", 2906 New: "200", 2907 }, 2908 { 2909 Type: DiffTypeEdited, 2910 Name: "DiskMB", 2911 Old: "100", 2912 New: "200", 2913 }, 2914 { 2915 Type: DiffTypeNone, 2916 Name: "IOPS", 2917 Old: "100", 2918 New: "100", 2919 }, 2920 { 2921 Type: DiffTypeNone, 2922 Name: "MemoryMB", 2923 Old: "100", 2924 New: "100", 2925 }, 2926 }, 2927 }, 2928 }, 2929 }, 2930 }, 2931 { 2932 Name: "Network Resources edited", 2933 Old: &Task{ 2934 Resources: &Resources{ 2935 Networks: []*NetworkResource{ 2936 { 2937 Device: "foo", 2938 CIDR: "foo", 2939 IP: "foo", 2940 MBits: 100, 2941 ReservedPorts: []Port{ 2942 { 2943 Label: "foo", 2944 Value: 80, 2945 }, 2946 }, 2947 DynamicPorts: []Port{ 2948 { 2949 Label: "bar", 2950 }, 2951 }, 2952 }, 2953 }, 2954 }, 2955 }, 2956 New: &Task{ 2957 Resources: &Resources{ 2958 Networks: []*NetworkResource{ 2959 { 2960 Device: "bar", 2961 CIDR: "bar", 2962 IP: "bar", 2963 MBits: 200, 2964 ReservedPorts: []Port{ 2965 { 2966 Label: "foo", 2967 Value: 81, 2968 }, 2969 }, 2970 DynamicPorts: []Port{ 2971 { 2972 Label: "baz", 2973 }, 2974 }, 2975 }, 2976 }, 2977 }, 2978 }, 2979 Expected: &TaskDiff{ 2980 Type: DiffTypeEdited, 2981 Objects: []*ObjectDiff{ 2982 { 2983 Type: DiffTypeEdited, 2984 Name: "Resources", 2985 Objects: []*ObjectDiff{ 2986 { 2987 Type: DiffTypeAdded, 2988 Name: "Network", 2989 Fields: []*FieldDiff{ 2990 { 2991 Type: DiffTypeAdded, 2992 Name: "MBits", 2993 Old: "", 2994 New: "200", 2995 }, 2996 }, 2997 Objects: []*ObjectDiff{ 2998 { 2999 Type: DiffTypeAdded, 3000 Name: "Static Port", 3001 Fields: []*FieldDiff{ 3002 { 3003 Type: DiffTypeAdded, 3004 Name: "Label", 3005 Old: "", 3006 New: "foo", 3007 }, 3008 { 3009 Type: DiffTypeAdded, 3010 Name: "Value", 3011 Old: "", 3012 New: "81", 3013 }, 3014 }, 3015 }, 3016 { 3017 Type: DiffTypeAdded, 3018 Name: "Dynamic Port", 3019 Fields: []*FieldDiff{ 3020 { 3021 Type: DiffTypeAdded, 3022 Name: "Label", 3023 Old: "", 3024 New: "baz", 3025 }, 3026 }, 3027 }, 3028 }, 3029 }, 3030 { 3031 Type: DiffTypeDeleted, 3032 Name: "Network", 3033 Fields: []*FieldDiff{ 3034 { 3035 Type: DiffTypeDeleted, 3036 Name: "MBits", 3037 Old: "100", 3038 New: "", 3039 }, 3040 }, 3041 Objects: []*ObjectDiff{ 3042 { 3043 Type: DiffTypeDeleted, 3044 Name: "Static Port", 3045 Fields: []*FieldDiff{ 3046 { 3047 Type: DiffTypeDeleted, 3048 Name: "Label", 3049 Old: "foo", 3050 New: "", 3051 }, 3052 { 3053 Type: DiffTypeDeleted, 3054 Name: "Value", 3055 Old: "80", 3056 New: "", 3057 }, 3058 }, 3059 }, 3060 { 3061 Type: DiffTypeDeleted, 3062 Name: "Dynamic Port", 3063 Fields: []*FieldDiff{ 3064 { 3065 Type: DiffTypeDeleted, 3066 Name: "Label", 3067 Old: "bar", 3068 New: "", 3069 }, 3070 }, 3071 }, 3072 }, 3073 }, 3074 }, 3075 }, 3076 }, 3077 }, 3078 }, 3079 { 3080 Name: "Config same", 3081 Old: &Task{ 3082 Config: map[string]interface{}{ 3083 "foo": 1, 3084 "bar": "bar", 3085 "bam": []string{"a", "b"}, 3086 "baz": map[string]int{ 3087 "a": 1, 3088 "b": 2, 3089 }, 3090 "boom": &Port{ 3091 Label: "boom_port", 3092 }, 3093 }, 3094 }, 3095 New: &Task{ 3096 Config: map[string]interface{}{ 3097 "foo": 1, 3098 "bar": "bar", 3099 "bam": []string{"a", "b"}, 3100 "baz": map[string]int{ 3101 "a": 1, 3102 "b": 2, 3103 }, 3104 "boom": &Port{ 3105 Label: "boom_port", 3106 }, 3107 }, 3108 }, 3109 Expected: &TaskDiff{ 3110 Type: DiffTypeNone, 3111 }, 3112 }, 3113 { 3114 Name: "Config edited", 3115 Old: &Task{ 3116 Config: map[string]interface{}{ 3117 "foo": 1, 3118 "bar": "baz", 3119 "bam": []string{"a", "b"}, 3120 "baz": map[string]int{ 3121 "a": 1, 3122 "b": 2, 3123 }, 3124 "boom": &Port{ 3125 Label: "boom_port", 3126 }, 3127 }, 3128 }, 3129 New: &Task{ 3130 Config: map[string]interface{}{ 3131 "foo": 2, 3132 "bar": "baz", 3133 "bam": []string{"a", "c", "d"}, 3134 "baz": map[string]int{ 3135 "b": 3, 3136 "c": 4, 3137 }, 3138 "boom": &Port{ 3139 Label: "boom_port2", 3140 }, 3141 }, 3142 }, 3143 Expected: &TaskDiff{ 3144 Type: DiffTypeEdited, 3145 Objects: []*ObjectDiff{ 3146 { 3147 Type: DiffTypeEdited, 3148 Name: "Config", 3149 Fields: []*FieldDiff{ 3150 { 3151 Type: DiffTypeEdited, 3152 Name: "bam[1]", 3153 Old: "b", 3154 New: "c", 3155 }, 3156 { 3157 Type: DiffTypeAdded, 3158 Name: "bam[2]", 3159 Old: "", 3160 New: "d", 3161 }, 3162 { 3163 Type: DiffTypeDeleted, 3164 Name: "baz[a]", 3165 Old: "1", 3166 New: "", 3167 }, 3168 { 3169 Type: DiffTypeEdited, 3170 Name: "baz[b]", 3171 Old: "2", 3172 New: "3", 3173 }, 3174 { 3175 Type: DiffTypeAdded, 3176 Name: "baz[c]", 3177 Old: "", 3178 New: "4", 3179 }, 3180 { 3181 Type: DiffTypeEdited, 3182 Name: "boom.Label", 3183 Old: "boom_port", 3184 New: "boom_port2", 3185 }, 3186 { 3187 Type: DiffTypeEdited, 3188 Name: "foo", 3189 Old: "1", 3190 New: "2", 3191 }, 3192 }, 3193 }, 3194 }, 3195 }, 3196 }, 3197 { 3198 Name: "Config edited with context", 3199 Contextual: true, 3200 Old: &Task{ 3201 Config: map[string]interface{}{ 3202 "foo": 1, 3203 "bar": "baz", 3204 "bam": []string{"a", "b"}, 3205 "baz": map[string]int{ 3206 "a": 1, 3207 "b": 2, 3208 }, 3209 "boom": &Port{ 3210 Label: "boom_port", 3211 }, 3212 }, 3213 }, 3214 New: &Task{ 3215 Config: map[string]interface{}{ 3216 "foo": 2, 3217 "bar": "baz", 3218 "bam": []string{"a", "c", "d"}, 3219 "baz": map[string]int{ 3220 "a": 1, 3221 "b": 2, 3222 }, 3223 "boom": &Port{ 3224 Label: "boom_port", 3225 }, 3226 }, 3227 }, 3228 Expected: &TaskDiff{ 3229 Type: DiffTypeEdited, 3230 Objects: []*ObjectDiff{ 3231 { 3232 Type: DiffTypeEdited, 3233 Name: "Config", 3234 Fields: []*FieldDiff{ 3235 { 3236 Type: DiffTypeNone, 3237 Name: "bam[0]", 3238 Old: "a", 3239 New: "a", 3240 }, 3241 { 3242 Type: DiffTypeEdited, 3243 Name: "bam[1]", 3244 Old: "b", 3245 New: "c", 3246 }, 3247 { 3248 Type: DiffTypeAdded, 3249 Name: "bam[2]", 3250 Old: "", 3251 New: "d", 3252 }, 3253 { 3254 Type: DiffTypeNone, 3255 Name: "bar", 3256 Old: "baz", 3257 New: "baz", 3258 }, 3259 { 3260 Type: DiffTypeNone, 3261 Name: "baz[a]", 3262 Old: "1", 3263 New: "1", 3264 }, 3265 { 3266 Type: DiffTypeNone, 3267 Name: "baz[b]", 3268 Old: "2", 3269 New: "2", 3270 }, 3271 { 3272 Type: DiffTypeNone, 3273 Name: "boom.Label", 3274 Old: "boom_port", 3275 New: "boom_port", 3276 }, 3277 { 3278 Type: DiffTypeNone, 3279 Name: "boom.Value", 3280 Old: "0", 3281 New: "0", 3282 }, 3283 { 3284 Type: DiffTypeEdited, 3285 Name: "foo", 3286 Old: "1", 3287 New: "2", 3288 }, 3289 }, 3290 }, 3291 }, 3292 }, 3293 }, 3294 { 3295 Name: "Services edited (no checks)", 3296 Old: &Task{ 3297 Services: []*Service{ 3298 { 3299 Name: "foo", 3300 PortLabel: "foo", 3301 }, 3302 { 3303 Name: "bar", 3304 PortLabel: "bar", 3305 }, 3306 { 3307 Name: "baz", 3308 PortLabel: "baz", 3309 }, 3310 }, 3311 }, 3312 New: &Task{ 3313 Services: []*Service{ 3314 { 3315 Name: "bar", 3316 PortLabel: "bar", 3317 }, 3318 { 3319 Name: "baz", 3320 PortLabel: "baz2", 3321 }, 3322 { 3323 Name: "bam", 3324 PortLabel: "bam", 3325 }, 3326 }, 3327 }, 3328 Expected: &TaskDiff{ 3329 Type: DiffTypeEdited, 3330 Objects: []*ObjectDiff{ 3331 { 3332 Type: DiffTypeEdited, 3333 Name: "Service", 3334 Fields: []*FieldDiff{ 3335 { 3336 Type: DiffTypeEdited, 3337 Name: "PortLabel", 3338 Old: "baz", 3339 New: "baz2", 3340 }, 3341 }, 3342 }, 3343 { 3344 Type: DiffTypeAdded, 3345 Name: "Service", 3346 Fields: []*FieldDiff{ 3347 { 3348 Type: DiffTypeAdded, 3349 Name: "Name", 3350 Old: "", 3351 New: "bam", 3352 }, 3353 { 3354 Type: DiffTypeAdded, 3355 Name: "PortLabel", 3356 Old: "", 3357 New: "bam", 3358 }, 3359 }, 3360 }, 3361 { 3362 Type: DiffTypeDeleted, 3363 Name: "Service", 3364 Fields: []*FieldDiff{ 3365 { 3366 Type: DiffTypeDeleted, 3367 Name: "Name", 3368 Old: "foo", 3369 New: "", 3370 }, 3371 { 3372 Type: DiffTypeDeleted, 3373 Name: "PortLabel", 3374 Old: "foo", 3375 New: "", 3376 }, 3377 }, 3378 }, 3379 }, 3380 }, 3381 }, 3382 { 3383 Name: "Services edited (no checks) with context", 3384 Contextual: true, 3385 Old: &Task{ 3386 Services: []*Service{ 3387 { 3388 Name: "foo", 3389 PortLabel: "foo", 3390 }, 3391 }, 3392 }, 3393 New: &Task{ 3394 Services: []*Service{ 3395 { 3396 Name: "foo", 3397 PortLabel: "bar", 3398 AddressMode: "driver", 3399 }, 3400 }, 3401 }, 3402 Expected: &TaskDiff{ 3403 Type: DiffTypeEdited, 3404 Objects: []*ObjectDiff{ 3405 { 3406 Type: DiffTypeEdited, 3407 Name: "Service", 3408 Fields: []*FieldDiff{ 3409 { 3410 Type: DiffTypeAdded, 3411 Name: "AddressMode", 3412 New: "driver", 3413 }, 3414 { 3415 Type: DiffTypeNone, 3416 Name: "Name", 3417 Old: "foo", 3418 New: "foo", 3419 }, 3420 { 3421 Type: DiffTypeEdited, 3422 Name: "PortLabel", 3423 Old: "foo", 3424 New: "bar", 3425 }, 3426 }, 3427 }, 3428 }, 3429 }, 3430 }, 3431 { 3432 Name: "Service Checks edited", 3433 Old: &Task{ 3434 Services: []*Service{ 3435 { 3436 Name: "foo", 3437 Checks: []*ServiceCheck{ 3438 { 3439 Name: "foo", 3440 Type: "http", 3441 Command: "foo", 3442 Args: []string{"foo"}, 3443 Path: "foo", 3444 Protocol: "http", 3445 Interval: 1 * time.Second, 3446 Timeout: 1 * time.Second, 3447 Header: map[string][]string{ 3448 "Foo": {"bar"}, 3449 }, 3450 }, 3451 { 3452 Name: "bar", 3453 Type: "http", 3454 Command: "foo", 3455 Args: []string{"foo"}, 3456 Path: "foo", 3457 Protocol: "http", 3458 Interval: 1 * time.Second, 3459 Timeout: 1 * time.Second, 3460 }, 3461 { 3462 Name: "baz", 3463 Type: "http", 3464 Command: "foo", 3465 Args: []string{"foo"}, 3466 Path: "foo", 3467 Protocol: "http", 3468 Interval: 1 * time.Second, 3469 Timeout: 1 * time.Second, 3470 }, 3471 }, 3472 }, 3473 }, 3474 }, 3475 New: &Task{ 3476 Services: []*Service{ 3477 { 3478 Name: "foo", 3479 Checks: []*ServiceCheck{ 3480 { 3481 Name: "bar", 3482 Type: "http", 3483 Command: "foo", 3484 Args: []string{"foo"}, 3485 Path: "foo", 3486 Protocol: "http", 3487 Interval: 1 * time.Second, 3488 Timeout: 1 * time.Second, 3489 }, 3490 { 3491 Name: "baz", 3492 Type: "tcp", 3493 Command: "foo", 3494 Args: []string{"foo"}, 3495 Path: "foo", 3496 Protocol: "http", 3497 Interval: 1 * time.Second, 3498 Timeout: 1 * time.Second, 3499 Header: map[string][]string{ 3500 "Eggs": {"spam"}, 3501 }, 3502 }, 3503 { 3504 Name: "bam", 3505 Type: "http", 3506 Command: "foo", 3507 Args: []string{"foo"}, 3508 Path: "foo", 3509 Protocol: "http", 3510 Interval: 1 * time.Second, 3511 Timeout: 1 * time.Second, 3512 }, 3513 }, 3514 }, 3515 }, 3516 }, 3517 Expected: &TaskDiff{ 3518 Type: DiffTypeEdited, 3519 Objects: []*ObjectDiff{ 3520 { 3521 Type: DiffTypeEdited, 3522 Name: "Service", 3523 Objects: []*ObjectDiff{ 3524 { 3525 Type: DiffTypeEdited, 3526 Name: "Check", 3527 Fields: []*FieldDiff{ 3528 { 3529 Type: DiffTypeEdited, 3530 Name: "Type", 3531 Old: "http", 3532 New: "tcp", 3533 }, 3534 }, 3535 Objects: []*ObjectDiff{ 3536 { 3537 Type: DiffTypeAdded, 3538 Name: "Header", 3539 Fields: []*FieldDiff{ 3540 { 3541 Type: DiffTypeAdded, 3542 Name: "Eggs[0]", 3543 Old: "", 3544 New: "spam", 3545 }, 3546 }, 3547 }, 3548 }, 3549 }, 3550 { 3551 Type: DiffTypeAdded, 3552 Name: "Check", 3553 Fields: []*FieldDiff{ 3554 { 3555 Type: DiffTypeAdded, 3556 Name: "Command", 3557 Old: "", 3558 New: "foo", 3559 }, 3560 { 3561 Type: DiffTypeAdded, 3562 Name: "Interval", 3563 Old: "", 3564 New: "1000000000", 3565 }, 3566 { 3567 Type: DiffTypeAdded, 3568 Name: "Name", 3569 Old: "", 3570 New: "bam", 3571 }, 3572 { 3573 Type: DiffTypeAdded, 3574 Name: "Path", 3575 Old: "", 3576 New: "foo", 3577 }, 3578 { 3579 Type: DiffTypeAdded, 3580 Name: "Protocol", 3581 Old: "", 3582 New: "http", 3583 }, 3584 { 3585 Type: DiffTypeAdded, 3586 Name: "TLSSkipVerify", 3587 Old: "", 3588 New: "false", 3589 }, 3590 { 3591 Type: DiffTypeAdded, 3592 Name: "Timeout", 3593 Old: "", 3594 New: "1000000000", 3595 }, 3596 { 3597 Type: DiffTypeAdded, 3598 Name: "Type", 3599 Old: "", 3600 New: "http", 3601 }, 3602 }, 3603 }, 3604 { 3605 Type: DiffTypeDeleted, 3606 Name: "Check", 3607 Fields: []*FieldDiff{ 3608 { 3609 Type: DiffTypeDeleted, 3610 Name: "Command", 3611 Old: "foo", 3612 New: "", 3613 }, 3614 { 3615 Type: DiffTypeDeleted, 3616 Name: "Interval", 3617 Old: "1000000000", 3618 New: "", 3619 }, 3620 { 3621 Type: DiffTypeDeleted, 3622 Name: "Name", 3623 Old: "foo", 3624 New: "", 3625 }, 3626 { 3627 Type: DiffTypeDeleted, 3628 Name: "Path", 3629 Old: "foo", 3630 New: "", 3631 }, 3632 { 3633 Type: DiffTypeDeleted, 3634 Name: "Protocol", 3635 Old: "http", 3636 New: "", 3637 }, 3638 { 3639 Type: DiffTypeDeleted, 3640 Name: "TLSSkipVerify", 3641 Old: "false", 3642 New: "", 3643 }, 3644 { 3645 Type: DiffTypeDeleted, 3646 Name: "Timeout", 3647 Old: "1000000000", 3648 New: "", 3649 }, 3650 { 3651 Type: DiffTypeDeleted, 3652 Name: "Type", 3653 Old: "http", 3654 New: "", 3655 }, 3656 }, 3657 Objects: []*ObjectDiff{ 3658 { 3659 Type: DiffTypeDeleted, 3660 Name: "Header", 3661 Fields: []*FieldDiff{ 3662 { 3663 Type: DiffTypeDeleted, 3664 Name: "Foo[0]", 3665 Old: "bar", 3666 }, 3667 }, 3668 }, 3669 }, 3670 }, 3671 }, 3672 }, 3673 }, 3674 }, 3675 }, 3676 { 3677 Name: "Service Checks edited with context", 3678 Contextual: true, 3679 Old: &Task{ 3680 Services: []*Service{ 3681 { 3682 Name: "foo", 3683 Checks: []*ServiceCheck{ 3684 { 3685 Name: "foo", 3686 Type: "http", 3687 Command: "foo", 3688 Args: []string{"foo"}, 3689 Path: "foo", 3690 Protocol: "http", 3691 Interval: 1 * time.Second, 3692 Timeout: 1 * time.Second, 3693 InitialStatus: "critical", 3694 Header: map[string][]string{ 3695 "Foo": {"bar"}, 3696 }, 3697 }, 3698 }, 3699 }, 3700 }, 3701 }, 3702 New: &Task{ 3703 Services: []*Service{ 3704 { 3705 Name: "foo", 3706 Checks: []*ServiceCheck{ 3707 { 3708 Name: "foo", 3709 Type: "tcp", 3710 Command: "foo", 3711 Args: []string{"foo"}, 3712 Path: "foo", 3713 Protocol: "http", 3714 Interval: 1 * time.Second, 3715 Timeout: 1 * time.Second, 3716 InitialStatus: "passing", 3717 Method: "POST", 3718 Header: map[string][]string{ 3719 "Foo": {"bar", "baz"}, 3720 "Eggs": {"spam"}, 3721 }, 3722 }, 3723 }, 3724 }, 3725 }, 3726 }, 3727 Expected: &TaskDiff{ 3728 Type: DiffTypeEdited, 3729 Objects: []*ObjectDiff{ 3730 { 3731 Type: DiffTypeEdited, 3732 Name: "Service", 3733 Fields: []*FieldDiff{ 3734 { 3735 Type: DiffTypeNone, 3736 Name: "AddressMode", 3737 Old: "", 3738 New: "", 3739 }, 3740 { 3741 Type: DiffTypeNone, 3742 Name: "Name", 3743 Old: "foo", 3744 New: "foo", 3745 }, 3746 { 3747 Type: DiffTypeNone, 3748 Name: "PortLabel", 3749 Old: "", 3750 New: "", 3751 }, 3752 }, 3753 Objects: []*ObjectDiff{ 3754 { 3755 Type: DiffTypeEdited, 3756 Name: "Check", 3757 Fields: []*FieldDiff{ 3758 { 3759 Type: DiffTypeNone, 3760 Name: "AddressMode", 3761 Old: "", 3762 New: "", 3763 }, 3764 { 3765 Type: DiffTypeNone, 3766 Name: "Command", 3767 Old: "foo", 3768 New: "foo", 3769 }, 3770 { 3771 Type: DiffTypeEdited, 3772 Name: "InitialStatus", 3773 Old: "critical", 3774 New: "passing", 3775 }, 3776 { 3777 Type: DiffTypeNone, 3778 Name: "Interval", 3779 Old: "1000000000", 3780 New: "1000000000", 3781 }, 3782 { 3783 Type: DiffTypeAdded, 3784 Name: "Method", 3785 Old: "", 3786 New: "POST", 3787 }, 3788 { 3789 Type: DiffTypeNone, 3790 Name: "Name", 3791 Old: "foo", 3792 New: "foo", 3793 }, 3794 { 3795 Type: DiffTypeNone, 3796 Name: "Path", 3797 Old: "foo", 3798 New: "foo", 3799 }, 3800 { 3801 Type: DiffTypeNone, 3802 Name: "PortLabel", 3803 Old: "", 3804 New: "", 3805 }, 3806 { 3807 Type: DiffTypeNone, 3808 Name: "Protocol", 3809 Old: "http", 3810 New: "http", 3811 }, 3812 { 3813 Type: DiffTypeNone, 3814 Name: "TLSSkipVerify", 3815 Old: "false", 3816 New: "false", 3817 }, 3818 { 3819 Type: DiffTypeNone, 3820 Name: "Timeout", 3821 Old: "1000000000", 3822 New: "1000000000", 3823 }, 3824 { 3825 Type: DiffTypeEdited, 3826 Name: "Type", 3827 Old: "http", 3828 New: "tcp", 3829 }, 3830 }, 3831 Objects: []*ObjectDiff{ 3832 { 3833 Type: DiffTypeEdited, 3834 Name: "Header", 3835 Fields: []*FieldDiff{ 3836 { 3837 Type: DiffTypeAdded, 3838 Name: "Eggs[0]", 3839 Old: "", 3840 New: "spam", 3841 }, 3842 { 3843 Type: DiffTypeNone, 3844 Name: "Foo[0]", 3845 Old: "bar", 3846 New: "bar", 3847 }, 3848 { 3849 Type: DiffTypeAdded, 3850 Name: "Foo[1]", 3851 Old: "", 3852 New: "baz", 3853 }, 3854 }, 3855 }, 3856 }, 3857 }, 3858 }, 3859 }, 3860 }, 3861 }, 3862 }, 3863 { 3864 Name: "CheckRestart edited", 3865 Old: &Task{ 3866 Services: []*Service{ 3867 { 3868 Name: "foo", 3869 Checks: []*ServiceCheck{ 3870 { 3871 Name: "foo", 3872 Type: "http", 3873 Command: "foo", 3874 Args: []string{"foo"}, 3875 Path: "foo", 3876 Protocol: "http", 3877 Interval: 1 * time.Second, 3878 Timeout: 1 * time.Second, 3879 }, 3880 { 3881 Name: "bar", 3882 Type: "http", 3883 Command: "foo", 3884 Args: []string{"foo"}, 3885 Path: "foo", 3886 Protocol: "http", 3887 Interval: 1 * time.Second, 3888 Timeout: 1 * time.Second, 3889 CheckRestart: &CheckRestart{ 3890 Limit: 2, 3891 Grace: 2 * time.Second, 3892 }, 3893 }, 3894 { 3895 Name: "baz", 3896 Type: "http", 3897 Command: "foo", 3898 Args: []string{"foo"}, 3899 Path: "foo", 3900 Protocol: "http", 3901 Interval: 1 * time.Second, 3902 Timeout: 1 * time.Second, 3903 CheckRestart: &CheckRestart{ 3904 Limit: 3, 3905 Grace: 3 * time.Second, 3906 }, 3907 }, 3908 }, 3909 }, 3910 }, 3911 }, 3912 New: &Task{ 3913 Services: []*Service{ 3914 { 3915 Name: "foo", 3916 Checks: []*ServiceCheck{ 3917 { 3918 Name: "foo", 3919 Type: "http", 3920 Command: "foo", 3921 Args: []string{"foo"}, 3922 Path: "foo", 3923 Protocol: "http", 3924 Interval: 1 * time.Second, 3925 Timeout: 1 * time.Second, 3926 CheckRestart: &CheckRestart{ 3927 Limit: 1, 3928 Grace: 1 * time.Second, 3929 }, 3930 }, 3931 { 3932 Name: "bar", 3933 Type: "http", 3934 Command: "foo", 3935 Args: []string{"foo"}, 3936 Path: "foo", 3937 Protocol: "http", 3938 Interval: 1 * time.Second, 3939 Timeout: 1 * time.Second, 3940 }, 3941 { 3942 Name: "baz", 3943 Type: "http", 3944 Command: "foo", 3945 Args: []string{"foo"}, 3946 Path: "foo", 3947 Protocol: "http", 3948 Interval: 1 * time.Second, 3949 Timeout: 1 * time.Second, 3950 CheckRestart: &CheckRestart{ 3951 Limit: 4, 3952 Grace: 4 * time.Second, 3953 }, 3954 }, 3955 }, 3956 }, 3957 }, 3958 }, 3959 Expected: &TaskDiff{ 3960 Type: DiffTypeEdited, 3961 Objects: []*ObjectDiff{ 3962 { 3963 Type: DiffTypeEdited, 3964 Name: "Service", 3965 Objects: []*ObjectDiff{ 3966 { 3967 Type: DiffTypeEdited, 3968 Name: "Check", 3969 Objects: []*ObjectDiff{ 3970 { 3971 Type: DiffTypeEdited, 3972 Name: "CheckRestart", 3973 Fields: []*FieldDiff{ 3974 { 3975 Type: DiffTypeEdited, 3976 Name: "Grace", 3977 Old: "3000000000", 3978 New: "4000000000", 3979 }, 3980 { 3981 Type: DiffTypeEdited, 3982 Name: "Limit", 3983 Old: "3", 3984 New: "4", 3985 }, 3986 }, 3987 }, 3988 }, 3989 }, 3990 { 3991 Type: DiffTypeEdited, 3992 Name: "Check", 3993 Objects: []*ObjectDiff{ 3994 { 3995 Type: DiffTypeAdded, 3996 Name: "CheckRestart", 3997 Fields: []*FieldDiff{ 3998 { 3999 Type: DiffTypeAdded, 4000 Name: "Grace", 4001 New: "1000000000", 4002 }, 4003 { 4004 Type: DiffTypeAdded, 4005 Name: "IgnoreWarnings", 4006 New: "false", 4007 }, 4008 { 4009 Type: DiffTypeAdded, 4010 Name: "Limit", 4011 New: "1", 4012 }, 4013 }, 4014 }, 4015 }, 4016 }, 4017 { 4018 Type: DiffTypeEdited, 4019 Name: "Check", 4020 Objects: []*ObjectDiff{ 4021 { 4022 Type: DiffTypeDeleted, 4023 Name: "CheckRestart", 4024 Fields: []*FieldDiff{ 4025 { 4026 Type: DiffTypeDeleted, 4027 Name: "Grace", 4028 Old: "2000000000", 4029 }, 4030 { 4031 Type: DiffTypeDeleted, 4032 Name: "IgnoreWarnings", 4033 Old: "false", 4034 }, 4035 { 4036 Type: DiffTypeDeleted, 4037 Name: "Limit", 4038 Old: "2", 4039 }, 4040 }, 4041 }, 4042 }, 4043 }, 4044 }, 4045 }, 4046 }, 4047 }, 4048 }, 4049 { 4050 Name: "Vault added", 4051 Old: &Task{}, 4052 New: &Task{ 4053 Vault: &Vault{ 4054 Policies: []string{"foo", "bar"}, 4055 Env: true, 4056 ChangeMode: "signal", 4057 ChangeSignal: "SIGUSR1", 4058 }, 4059 }, 4060 Expected: &TaskDiff{ 4061 Type: DiffTypeEdited, 4062 Objects: []*ObjectDiff{ 4063 { 4064 Type: DiffTypeAdded, 4065 Name: "Vault", 4066 Fields: []*FieldDiff{ 4067 { 4068 Type: DiffTypeAdded, 4069 Name: "ChangeMode", 4070 Old: "", 4071 New: "signal", 4072 }, 4073 { 4074 Type: DiffTypeAdded, 4075 Name: "ChangeSignal", 4076 Old: "", 4077 New: "SIGUSR1", 4078 }, 4079 { 4080 Type: DiffTypeAdded, 4081 Name: "Env", 4082 Old: "", 4083 New: "true", 4084 }, 4085 }, 4086 Objects: []*ObjectDiff{ 4087 { 4088 Type: DiffTypeAdded, 4089 Name: "Policies", 4090 Fields: []*FieldDiff{ 4091 { 4092 Type: DiffTypeAdded, 4093 Name: "Policies", 4094 Old: "", 4095 New: "bar", 4096 }, 4097 { 4098 Type: DiffTypeAdded, 4099 Name: "Policies", 4100 Old: "", 4101 New: "foo", 4102 }, 4103 }, 4104 }, 4105 }, 4106 }, 4107 }, 4108 }, 4109 }, 4110 { 4111 Name: "Vault deleted", 4112 Old: &Task{ 4113 Vault: &Vault{ 4114 Policies: []string{"foo", "bar"}, 4115 Env: true, 4116 ChangeMode: "signal", 4117 ChangeSignal: "SIGUSR1", 4118 }, 4119 }, 4120 New: &Task{}, 4121 Expected: &TaskDiff{ 4122 Type: DiffTypeEdited, 4123 Objects: []*ObjectDiff{ 4124 { 4125 Type: DiffTypeDeleted, 4126 Name: "Vault", 4127 Fields: []*FieldDiff{ 4128 { 4129 Type: DiffTypeDeleted, 4130 Name: "ChangeMode", 4131 Old: "signal", 4132 New: "", 4133 }, 4134 { 4135 Type: DiffTypeDeleted, 4136 Name: "ChangeSignal", 4137 Old: "SIGUSR1", 4138 New: "", 4139 }, 4140 { 4141 Type: DiffTypeDeleted, 4142 Name: "Env", 4143 Old: "true", 4144 New: "", 4145 }, 4146 }, 4147 Objects: []*ObjectDiff{ 4148 { 4149 Type: DiffTypeDeleted, 4150 Name: "Policies", 4151 Fields: []*FieldDiff{ 4152 { 4153 Type: DiffTypeDeleted, 4154 Name: "Policies", 4155 Old: "bar", 4156 New: "", 4157 }, 4158 { 4159 Type: DiffTypeDeleted, 4160 Name: "Policies", 4161 Old: "foo", 4162 New: "", 4163 }, 4164 }, 4165 }, 4166 }, 4167 }, 4168 }, 4169 }, 4170 }, 4171 { 4172 Name: "Vault edited", 4173 Old: &Task{ 4174 Vault: &Vault{ 4175 Policies: []string{"foo", "bar"}, 4176 Env: true, 4177 ChangeMode: "signal", 4178 ChangeSignal: "SIGUSR1", 4179 }, 4180 }, 4181 New: &Task{ 4182 Vault: &Vault{ 4183 Policies: []string{"bar", "baz"}, 4184 Env: false, 4185 ChangeMode: "restart", 4186 ChangeSignal: "foo", 4187 }, 4188 }, 4189 Expected: &TaskDiff{ 4190 Type: DiffTypeEdited, 4191 Objects: []*ObjectDiff{ 4192 { 4193 Type: DiffTypeEdited, 4194 Name: "Vault", 4195 Fields: []*FieldDiff{ 4196 { 4197 Type: DiffTypeEdited, 4198 Name: "ChangeMode", 4199 Old: "signal", 4200 New: "restart", 4201 }, 4202 { 4203 Type: DiffTypeEdited, 4204 Name: "ChangeSignal", 4205 Old: "SIGUSR1", 4206 New: "foo", 4207 }, 4208 { 4209 Type: DiffTypeEdited, 4210 Name: "Env", 4211 Old: "true", 4212 New: "false", 4213 }, 4214 }, 4215 Objects: []*ObjectDiff{ 4216 { 4217 Type: DiffTypeEdited, 4218 Name: "Policies", 4219 Fields: []*FieldDiff{ 4220 { 4221 Type: DiffTypeAdded, 4222 Name: "Policies", 4223 Old: "", 4224 New: "baz", 4225 }, 4226 { 4227 Type: DiffTypeDeleted, 4228 Name: "Policies", 4229 Old: "foo", 4230 New: "", 4231 }, 4232 }, 4233 }, 4234 }, 4235 }, 4236 }, 4237 }, 4238 }, 4239 { 4240 Name: "Vault edited with context", 4241 Contextual: true, 4242 Old: &Task{ 4243 Vault: &Vault{ 4244 Policies: []string{"foo", "bar"}, 4245 Env: true, 4246 ChangeMode: "signal", 4247 ChangeSignal: "SIGUSR1", 4248 }, 4249 }, 4250 New: &Task{ 4251 Vault: &Vault{ 4252 Policies: []string{"bar", "baz"}, 4253 Env: true, 4254 ChangeMode: "signal", 4255 ChangeSignal: "SIGUSR1", 4256 }, 4257 }, 4258 Expected: &TaskDiff{ 4259 Type: DiffTypeEdited, 4260 Objects: []*ObjectDiff{ 4261 { 4262 Type: DiffTypeEdited, 4263 Name: "Vault", 4264 Fields: []*FieldDiff{ 4265 { 4266 Type: DiffTypeNone, 4267 Name: "ChangeMode", 4268 Old: "signal", 4269 New: "signal", 4270 }, 4271 { 4272 Type: DiffTypeNone, 4273 Name: "ChangeSignal", 4274 Old: "SIGUSR1", 4275 New: "SIGUSR1", 4276 }, 4277 { 4278 Type: DiffTypeNone, 4279 Name: "Env", 4280 Old: "true", 4281 New: "true", 4282 }, 4283 }, 4284 Objects: []*ObjectDiff{ 4285 { 4286 Type: DiffTypeEdited, 4287 Name: "Policies", 4288 Fields: []*FieldDiff{ 4289 { 4290 Type: DiffTypeAdded, 4291 Name: "Policies", 4292 Old: "", 4293 New: "baz", 4294 }, 4295 { 4296 Type: DiffTypeNone, 4297 Name: "Policies", 4298 Old: "bar", 4299 New: "bar", 4300 }, 4301 { 4302 Type: DiffTypeDeleted, 4303 Name: "Policies", 4304 Old: "foo", 4305 New: "", 4306 }, 4307 }, 4308 }, 4309 }, 4310 }, 4311 }, 4312 }, 4313 }, 4314 { 4315 Name: "Template edited", 4316 Old: &Task{ 4317 Templates: []*Template{ 4318 { 4319 SourcePath: "foo", 4320 DestPath: "bar", 4321 EmbeddedTmpl: "baz", 4322 ChangeMode: "bam", 4323 ChangeSignal: "SIGHUP", 4324 Splay: 1, 4325 Perms: "0644", 4326 VaultGrace: 3 * time.Second, 4327 }, 4328 { 4329 SourcePath: "foo2", 4330 DestPath: "bar2", 4331 EmbeddedTmpl: "baz2", 4332 ChangeMode: "bam2", 4333 ChangeSignal: "SIGHUP2", 4334 Splay: 2, 4335 Perms: "0666", 4336 Envvars: true, 4337 VaultGrace: 5 * time.Second, 4338 }, 4339 }, 4340 }, 4341 New: &Task{ 4342 Templates: []*Template{ 4343 { 4344 SourcePath: "foo", 4345 DestPath: "bar", 4346 EmbeddedTmpl: "baz", 4347 ChangeMode: "bam", 4348 ChangeSignal: "SIGHUP", 4349 Splay: 1, 4350 Perms: "0644", 4351 VaultGrace: 3 * time.Second, 4352 }, 4353 { 4354 SourcePath: "foo3", 4355 DestPath: "bar3", 4356 EmbeddedTmpl: "baz3", 4357 ChangeMode: "bam3", 4358 ChangeSignal: "SIGHUP3", 4359 Splay: 3, 4360 Perms: "0776", 4361 VaultGrace: 10 * time.Second, 4362 }, 4363 }, 4364 }, 4365 Expected: &TaskDiff{ 4366 Type: DiffTypeEdited, 4367 Objects: []*ObjectDiff{ 4368 { 4369 Type: DiffTypeAdded, 4370 Name: "Template", 4371 Fields: []*FieldDiff{ 4372 { 4373 Type: DiffTypeAdded, 4374 Name: "ChangeMode", 4375 Old: "", 4376 New: "bam3", 4377 }, 4378 { 4379 Type: DiffTypeAdded, 4380 Name: "ChangeSignal", 4381 Old: "", 4382 New: "SIGHUP3", 4383 }, 4384 { 4385 Type: DiffTypeAdded, 4386 Name: "DestPath", 4387 Old: "", 4388 New: "bar3", 4389 }, 4390 { 4391 Type: DiffTypeAdded, 4392 Name: "EmbeddedTmpl", 4393 Old: "", 4394 New: "baz3", 4395 }, 4396 { 4397 Type: DiffTypeAdded, 4398 Name: "Envvars", 4399 Old: "", 4400 New: "false", 4401 }, 4402 { 4403 Type: DiffTypeAdded, 4404 Name: "Perms", 4405 Old: "", 4406 New: "0776", 4407 }, 4408 { 4409 Type: DiffTypeAdded, 4410 Name: "SourcePath", 4411 Old: "", 4412 New: "foo3", 4413 }, 4414 { 4415 Type: DiffTypeAdded, 4416 Name: "Splay", 4417 Old: "", 4418 New: "3", 4419 }, 4420 { 4421 Type: DiffTypeAdded, 4422 Name: "VaultGrace", 4423 Old: "", 4424 New: "10000000000", 4425 }, 4426 }, 4427 }, 4428 { 4429 Type: DiffTypeDeleted, 4430 Name: "Template", 4431 Fields: []*FieldDiff{ 4432 { 4433 Type: DiffTypeDeleted, 4434 Name: "ChangeMode", 4435 Old: "bam2", 4436 New: "", 4437 }, 4438 { 4439 Type: DiffTypeDeleted, 4440 Name: "ChangeSignal", 4441 Old: "SIGHUP2", 4442 New: "", 4443 }, 4444 { 4445 Type: DiffTypeDeleted, 4446 Name: "DestPath", 4447 Old: "bar2", 4448 New: "", 4449 }, 4450 { 4451 Type: DiffTypeDeleted, 4452 Name: "EmbeddedTmpl", 4453 Old: "baz2", 4454 New: "", 4455 }, 4456 { 4457 Type: DiffTypeDeleted, 4458 Name: "Envvars", 4459 Old: "true", 4460 New: "", 4461 }, 4462 { 4463 Type: DiffTypeDeleted, 4464 Name: "Perms", 4465 Old: "0666", 4466 New: "", 4467 }, 4468 { 4469 Type: DiffTypeDeleted, 4470 Name: "SourcePath", 4471 Old: "foo2", 4472 New: "", 4473 }, 4474 { 4475 Type: DiffTypeDeleted, 4476 Name: "Splay", 4477 Old: "2", 4478 New: "", 4479 }, 4480 { 4481 Type: DiffTypeDeleted, 4482 Name: "VaultGrace", 4483 Old: "5000000000", 4484 New: "", 4485 }, 4486 }, 4487 }, 4488 }, 4489 }, 4490 }, 4491 { 4492 Name: "DispatchPayload added", 4493 Old: &Task{}, 4494 New: &Task{ 4495 DispatchPayload: &DispatchPayloadConfig{ 4496 File: "foo", 4497 }, 4498 }, 4499 Expected: &TaskDiff{ 4500 Type: DiffTypeEdited, 4501 Objects: []*ObjectDiff{ 4502 { 4503 Type: DiffTypeAdded, 4504 Name: "DispatchPayload", 4505 Fields: []*FieldDiff{ 4506 { 4507 Type: DiffTypeAdded, 4508 Name: "File", 4509 Old: "", 4510 New: "foo", 4511 }, 4512 }, 4513 }, 4514 }, 4515 }, 4516 }, 4517 { 4518 Name: "DispatchPayload deleted", 4519 Old: &Task{ 4520 DispatchPayload: &DispatchPayloadConfig{ 4521 File: "foo", 4522 }, 4523 }, 4524 New: &Task{}, 4525 Expected: &TaskDiff{ 4526 Type: DiffTypeEdited, 4527 Objects: []*ObjectDiff{ 4528 { 4529 Type: DiffTypeDeleted, 4530 Name: "DispatchPayload", 4531 Fields: []*FieldDiff{ 4532 { 4533 Type: DiffTypeDeleted, 4534 Name: "File", 4535 Old: "foo", 4536 New: "", 4537 }, 4538 }, 4539 }, 4540 }, 4541 }, 4542 }, 4543 { 4544 Name: "Dispatch payload edited", 4545 Old: &Task{ 4546 DispatchPayload: &DispatchPayloadConfig{ 4547 File: "foo", 4548 }, 4549 }, 4550 New: &Task{ 4551 DispatchPayload: &DispatchPayloadConfig{ 4552 File: "bar", 4553 }, 4554 }, 4555 Expected: &TaskDiff{ 4556 Type: DiffTypeEdited, 4557 Objects: []*ObjectDiff{ 4558 { 4559 Type: DiffTypeEdited, 4560 Name: "DispatchPayload", 4561 Fields: []*FieldDiff{ 4562 { 4563 Type: DiffTypeEdited, 4564 Name: "File", 4565 Old: "foo", 4566 New: "bar", 4567 }, 4568 }, 4569 }, 4570 }, 4571 }, 4572 }, 4573 { 4574 // Place holder for if more fields are added 4575 Name: "DispatchPayload edited with context", 4576 Contextual: true, 4577 Old: &Task{ 4578 DispatchPayload: &DispatchPayloadConfig{ 4579 File: "foo", 4580 }, 4581 }, 4582 New: &Task{ 4583 DispatchPayload: &DispatchPayloadConfig{ 4584 File: "bar", 4585 }, 4586 }, 4587 Expected: &TaskDiff{ 4588 Type: DiffTypeEdited, 4589 Objects: []*ObjectDiff{ 4590 { 4591 Type: DiffTypeEdited, 4592 Name: "DispatchPayload", 4593 Fields: []*FieldDiff{ 4594 { 4595 Type: DiffTypeEdited, 4596 Name: "File", 4597 Old: "foo", 4598 New: "bar", 4599 }, 4600 }, 4601 }, 4602 }, 4603 }, 4604 }, 4605 } 4606 4607 for i, c := range cases { 4608 t.Run(c.Name, func(t *testing.T) { 4609 actual, err := c.Old.Diff(c.New, c.Contextual) 4610 if c.Error && err == nil { 4611 t.Fatalf("case %d: expected errored", i+1) 4612 } else if err != nil { 4613 if !c.Error { 4614 t.Fatalf("case %d: errored %#v", i+1, err) 4615 } else { 4616 return 4617 } 4618 } 4619 4620 if !reflect.DeepEqual(actual, c.Expected) { 4621 t.Errorf("case %d: got:\n%#v\n want:\n%#v\n", 4622 i+1, actual, c.Expected) 4623 } 4624 }) 4625 } 4626 }