github.com/hspak/nomad@v0.7.2-0.20180309000617-bc4ae22a39a5/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 }, 1505 }, 1506 Expected: &TaskGroupDiff{ 1507 Type: DiffTypeEdited, 1508 Objects: []*ObjectDiff{ 1509 { 1510 Type: DiffTypeAdded, 1511 Name: "ReschedulePolicy", 1512 Fields: []*FieldDiff{ 1513 { 1514 Type: DiffTypeAdded, 1515 Name: "Attempts", 1516 Old: "", 1517 New: "1", 1518 }, 1519 { 1520 Type: DiffTypeAdded, 1521 Name: "Interval", 1522 Old: "", 1523 New: "15000000000", 1524 }, 1525 }, 1526 }, 1527 }, 1528 }, 1529 }, 1530 { 1531 // ReschedulePolicy deleted 1532 Old: &TaskGroup{ 1533 ReschedulePolicy: &ReschedulePolicy{ 1534 Attempts: 1, 1535 Interval: 15 * time.Second, 1536 }, 1537 }, 1538 New: &TaskGroup{}, 1539 Expected: &TaskGroupDiff{ 1540 Type: DiffTypeEdited, 1541 Objects: []*ObjectDiff{ 1542 { 1543 Type: DiffTypeDeleted, 1544 Name: "ReschedulePolicy", 1545 Fields: []*FieldDiff{ 1546 { 1547 Type: DiffTypeDeleted, 1548 Name: "Attempts", 1549 Old: "1", 1550 New: "", 1551 }, 1552 { 1553 Type: DiffTypeDeleted, 1554 Name: "Interval", 1555 Old: "15000000000", 1556 New: "", 1557 }, 1558 }, 1559 }, 1560 }, 1561 }, 1562 }, 1563 { 1564 // ReschedulePolicy edited 1565 Old: &TaskGroup{ 1566 ReschedulePolicy: &ReschedulePolicy{ 1567 Attempts: 1, 1568 Interval: 1 * time.Second, 1569 }, 1570 }, 1571 New: &TaskGroup{ 1572 ReschedulePolicy: &ReschedulePolicy{ 1573 Attempts: 2, 1574 Interval: 2 * time.Second, 1575 }, 1576 }, 1577 Expected: &TaskGroupDiff{ 1578 Type: DiffTypeEdited, 1579 Objects: []*ObjectDiff{ 1580 { 1581 Type: DiffTypeEdited, 1582 Name: "ReschedulePolicy", 1583 Fields: []*FieldDiff{ 1584 { 1585 Type: DiffTypeEdited, 1586 Name: "Attempts", 1587 Old: "1", 1588 New: "2", 1589 }, 1590 { 1591 Type: DiffTypeEdited, 1592 Name: "Interval", 1593 Old: "1000000000", 1594 New: "2000000000", 1595 }, 1596 }, 1597 }, 1598 }, 1599 }, 1600 }, { 1601 // ReschedulePolicy edited with context 1602 Contextual: true, 1603 Old: &TaskGroup{ 1604 ReschedulePolicy: &ReschedulePolicy{ 1605 Attempts: 1, 1606 Interval: 1 * time.Second, 1607 }, 1608 }, 1609 New: &TaskGroup{ 1610 ReschedulePolicy: &ReschedulePolicy{ 1611 Attempts: 1, 1612 Interval: 2 * time.Second, 1613 }, 1614 }, 1615 Expected: &TaskGroupDiff{ 1616 Type: DiffTypeEdited, 1617 Objects: []*ObjectDiff{ 1618 { 1619 Type: DiffTypeEdited, 1620 Name: "ReschedulePolicy", 1621 Fields: []*FieldDiff{ 1622 { 1623 Type: DiffTypeNone, 1624 Name: "Attempts", 1625 Old: "1", 1626 New: "1", 1627 }, 1628 { 1629 Type: DiffTypeEdited, 1630 Name: "Interval", 1631 Old: "1000000000", 1632 New: "2000000000", 1633 }, 1634 }, 1635 }, 1636 }, 1637 }, 1638 }, 1639 { 1640 // Update strategy deleted 1641 Old: &TaskGroup{ 1642 Update: &UpdateStrategy{ 1643 AutoRevert: true, 1644 }, 1645 }, 1646 New: &TaskGroup{}, 1647 Expected: &TaskGroupDiff{ 1648 Type: DiffTypeEdited, 1649 Objects: []*ObjectDiff{ 1650 { 1651 Type: DiffTypeDeleted, 1652 Name: "Update", 1653 Fields: []*FieldDiff{ 1654 { 1655 Type: DiffTypeDeleted, 1656 Name: "AutoRevert", 1657 Old: "true", 1658 New: "", 1659 }, 1660 { 1661 Type: DiffTypeDeleted, 1662 Name: "Canary", 1663 Old: "0", 1664 New: "", 1665 }, 1666 { 1667 Type: DiffTypeDeleted, 1668 Name: "HealthyDeadline", 1669 Old: "0", 1670 New: "", 1671 }, 1672 { 1673 Type: DiffTypeDeleted, 1674 Name: "MaxParallel", 1675 Old: "0", 1676 New: "", 1677 }, 1678 { 1679 Type: DiffTypeDeleted, 1680 Name: "MinHealthyTime", 1681 Old: "0", 1682 New: "", 1683 }, 1684 }, 1685 }, 1686 }, 1687 }, 1688 }, 1689 { 1690 // Update strategy added 1691 Old: &TaskGroup{}, 1692 New: &TaskGroup{ 1693 Update: &UpdateStrategy{ 1694 AutoRevert: true, 1695 }, 1696 }, 1697 Expected: &TaskGroupDiff{ 1698 Type: DiffTypeEdited, 1699 Objects: []*ObjectDiff{ 1700 { 1701 Type: DiffTypeAdded, 1702 Name: "Update", 1703 Fields: []*FieldDiff{ 1704 { 1705 Type: DiffTypeAdded, 1706 Name: "AutoRevert", 1707 Old: "", 1708 New: "true", 1709 }, 1710 { 1711 Type: DiffTypeAdded, 1712 Name: "Canary", 1713 Old: "", 1714 New: "0", 1715 }, 1716 { 1717 Type: DiffTypeAdded, 1718 Name: "HealthyDeadline", 1719 Old: "", 1720 New: "0", 1721 }, 1722 { 1723 Type: DiffTypeAdded, 1724 Name: "MaxParallel", 1725 Old: "", 1726 New: "0", 1727 }, 1728 { 1729 Type: DiffTypeAdded, 1730 Name: "MinHealthyTime", 1731 Old: "", 1732 New: "0", 1733 }, 1734 }, 1735 }, 1736 }, 1737 }, 1738 }, 1739 { 1740 // Update strategy edited 1741 Old: &TaskGroup{ 1742 Update: &UpdateStrategy{ 1743 MaxParallel: 5, 1744 HealthCheck: "foo", 1745 MinHealthyTime: 1 * time.Second, 1746 HealthyDeadline: 30 * time.Second, 1747 AutoRevert: true, 1748 Canary: 2, 1749 }, 1750 }, 1751 New: &TaskGroup{ 1752 Update: &UpdateStrategy{ 1753 MaxParallel: 7, 1754 HealthCheck: "bar", 1755 MinHealthyTime: 2 * time.Second, 1756 HealthyDeadline: 31 * time.Second, 1757 AutoRevert: false, 1758 Canary: 1, 1759 }, 1760 }, 1761 Expected: &TaskGroupDiff{ 1762 Type: DiffTypeEdited, 1763 Objects: []*ObjectDiff{ 1764 { 1765 Type: DiffTypeEdited, 1766 Name: "Update", 1767 Fields: []*FieldDiff{ 1768 { 1769 Type: DiffTypeEdited, 1770 Name: "AutoRevert", 1771 Old: "true", 1772 New: "false", 1773 }, 1774 { 1775 Type: DiffTypeEdited, 1776 Name: "Canary", 1777 Old: "2", 1778 New: "1", 1779 }, 1780 { 1781 Type: DiffTypeEdited, 1782 Name: "HealthCheck", 1783 Old: "foo", 1784 New: "bar", 1785 }, 1786 { 1787 Type: DiffTypeEdited, 1788 Name: "HealthyDeadline", 1789 Old: "30000000000", 1790 New: "31000000000", 1791 }, 1792 { 1793 Type: DiffTypeEdited, 1794 Name: "MaxParallel", 1795 Old: "5", 1796 New: "7", 1797 }, 1798 { 1799 Type: DiffTypeEdited, 1800 Name: "MinHealthyTime", 1801 Old: "1000000000", 1802 New: "2000000000", 1803 }, 1804 }, 1805 }, 1806 }, 1807 }, 1808 }, 1809 { 1810 // Update strategy edited with context 1811 Contextual: true, 1812 Old: &TaskGroup{ 1813 Update: &UpdateStrategy{ 1814 MaxParallel: 5, 1815 HealthCheck: "foo", 1816 MinHealthyTime: 1 * time.Second, 1817 HealthyDeadline: 30 * time.Second, 1818 AutoRevert: true, 1819 Canary: 2, 1820 }, 1821 }, 1822 New: &TaskGroup{ 1823 Update: &UpdateStrategy{ 1824 MaxParallel: 7, 1825 HealthCheck: "foo", 1826 MinHealthyTime: 1 * time.Second, 1827 HealthyDeadline: 30 * time.Second, 1828 AutoRevert: true, 1829 Canary: 2, 1830 }, 1831 }, 1832 Expected: &TaskGroupDiff{ 1833 Type: DiffTypeEdited, 1834 Objects: []*ObjectDiff{ 1835 { 1836 Type: DiffTypeEdited, 1837 Name: "Update", 1838 Fields: []*FieldDiff{ 1839 { 1840 Type: DiffTypeNone, 1841 Name: "AutoRevert", 1842 Old: "true", 1843 New: "true", 1844 }, 1845 { 1846 Type: DiffTypeNone, 1847 Name: "Canary", 1848 Old: "2", 1849 New: "2", 1850 }, 1851 { 1852 Type: DiffTypeNone, 1853 Name: "HealthCheck", 1854 Old: "foo", 1855 New: "foo", 1856 }, 1857 { 1858 Type: DiffTypeNone, 1859 Name: "HealthyDeadline", 1860 Old: "30000000000", 1861 New: "30000000000", 1862 }, 1863 { 1864 Type: DiffTypeEdited, 1865 Name: "MaxParallel", 1866 Old: "5", 1867 New: "7", 1868 }, 1869 { 1870 Type: DiffTypeNone, 1871 Name: "MinHealthyTime", 1872 Old: "1000000000", 1873 New: "1000000000", 1874 }, 1875 }, 1876 }, 1877 }, 1878 }, 1879 }, 1880 { 1881 // EphemeralDisk added 1882 Old: &TaskGroup{}, 1883 New: &TaskGroup{ 1884 EphemeralDisk: &EphemeralDisk{ 1885 Migrate: true, 1886 Sticky: true, 1887 SizeMB: 100, 1888 }, 1889 }, 1890 Expected: &TaskGroupDiff{ 1891 Type: DiffTypeEdited, 1892 Objects: []*ObjectDiff{ 1893 { 1894 Type: DiffTypeAdded, 1895 Name: "EphemeralDisk", 1896 Fields: []*FieldDiff{ 1897 { 1898 Type: DiffTypeAdded, 1899 Name: "Migrate", 1900 Old: "", 1901 New: "true", 1902 }, 1903 { 1904 Type: DiffTypeAdded, 1905 Name: "SizeMB", 1906 Old: "", 1907 New: "100", 1908 }, 1909 { 1910 Type: DiffTypeAdded, 1911 Name: "Sticky", 1912 Old: "", 1913 New: "true", 1914 }, 1915 }, 1916 }, 1917 }, 1918 }, 1919 }, 1920 { 1921 // EphemeralDisk deleted 1922 Old: &TaskGroup{ 1923 EphemeralDisk: &EphemeralDisk{ 1924 Migrate: true, 1925 Sticky: true, 1926 SizeMB: 100, 1927 }, 1928 }, 1929 New: &TaskGroup{}, 1930 Expected: &TaskGroupDiff{ 1931 Type: DiffTypeEdited, 1932 Objects: []*ObjectDiff{ 1933 { 1934 Type: DiffTypeDeleted, 1935 Name: "EphemeralDisk", 1936 Fields: []*FieldDiff{ 1937 { 1938 Type: DiffTypeDeleted, 1939 Name: "Migrate", 1940 Old: "true", 1941 New: "", 1942 }, 1943 { 1944 Type: DiffTypeDeleted, 1945 Name: "SizeMB", 1946 Old: "100", 1947 New: "", 1948 }, 1949 { 1950 Type: DiffTypeDeleted, 1951 Name: "Sticky", 1952 Old: "true", 1953 New: "", 1954 }, 1955 }, 1956 }, 1957 }, 1958 }, 1959 }, 1960 { 1961 // EphemeralDisk edited 1962 Old: &TaskGroup{ 1963 EphemeralDisk: &EphemeralDisk{ 1964 Migrate: true, 1965 Sticky: true, 1966 SizeMB: 150, 1967 }, 1968 }, 1969 New: &TaskGroup{ 1970 EphemeralDisk: &EphemeralDisk{ 1971 Migrate: false, 1972 Sticky: false, 1973 SizeMB: 90, 1974 }, 1975 }, 1976 Expected: &TaskGroupDiff{ 1977 Type: DiffTypeEdited, 1978 Objects: []*ObjectDiff{ 1979 { 1980 Type: DiffTypeEdited, 1981 Name: "EphemeralDisk", 1982 Fields: []*FieldDiff{ 1983 { 1984 Type: DiffTypeEdited, 1985 Name: "Migrate", 1986 Old: "true", 1987 New: "false", 1988 }, 1989 { 1990 Type: DiffTypeEdited, 1991 Name: "SizeMB", 1992 Old: "150", 1993 New: "90", 1994 }, 1995 1996 { 1997 Type: DiffTypeEdited, 1998 Name: "Sticky", 1999 Old: "true", 2000 New: "false", 2001 }, 2002 }, 2003 }, 2004 }, 2005 }, 2006 }, 2007 { 2008 // EphemeralDisk edited with context 2009 Contextual: true, 2010 Old: &TaskGroup{ 2011 EphemeralDisk: &EphemeralDisk{ 2012 Migrate: false, 2013 Sticky: false, 2014 SizeMB: 100, 2015 }, 2016 }, 2017 New: &TaskGroup{ 2018 EphemeralDisk: &EphemeralDisk{ 2019 Migrate: true, 2020 Sticky: true, 2021 SizeMB: 90, 2022 }, 2023 }, 2024 Expected: &TaskGroupDiff{ 2025 Type: DiffTypeEdited, 2026 Objects: []*ObjectDiff{ 2027 { 2028 Type: DiffTypeEdited, 2029 Name: "EphemeralDisk", 2030 Fields: []*FieldDiff{ 2031 { 2032 Type: DiffTypeEdited, 2033 Name: "Migrate", 2034 Old: "false", 2035 New: "true", 2036 }, 2037 { 2038 Type: DiffTypeEdited, 2039 Name: "SizeMB", 2040 Old: "100", 2041 New: "90", 2042 }, 2043 { 2044 Type: DiffTypeEdited, 2045 Name: "Sticky", 2046 Old: "false", 2047 New: "true", 2048 }, 2049 }, 2050 }, 2051 }, 2052 }, 2053 }, 2054 { 2055 // Tasks edited 2056 Old: &TaskGroup{ 2057 Tasks: []*Task{ 2058 { 2059 Name: "foo", 2060 Driver: "docker", 2061 }, 2062 { 2063 Name: "bar", 2064 Driver: "docker", 2065 }, 2066 { 2067 Name: "baz", 2068 ShutdownDelay: 1 * time.Second, 2069 }, 2070 }, 2071 }, 2072 New: &TaskGroup{ 2073 Tasks: []*Task{ 2074 { 2075 Name: "bar", 2076 Driver: "docker", 2077 }, 2078 { 2079 Name: "bam", 2080 Driver: "docker", 2081 }, 2082 { 2083 Name: "baz", 2084 ShutdownDelay: 2 * time.Second, 2085 }, 2086 }, 2087 }, 2088 Expected: &TaskGroupDiff{ 2089 Type: DiffTypeEdited, 2090 Tasks: []*TaskDiff{ 2091 { 2092 Type: DiffTypeAdded, 2093 Name: "bam", 2094 Fields: []*FieldDiff{ 2095 { 2096 Type: DiffTypeAdded, 2097 Name: "Driver", 2098 Old: "", 2099 New: "docker", 2100 }, 2101 { 2102 Type: DiffTypeAdded, 2103 Name: "KillTimeout", 2104 Old: "", 2105 New: "0", 2106 }, 2107 { 2108 Type: DiffTypeAdded, 2109 Name: "Leader", 2110 Old: "", 2111 New: "false", 2112 }, 2113 { 2114 Type: DiffTypeAdded, 2115 Name: "ShutdownDelay", 2116 Old: "", 2117 New: "0", 2118 }, 2119 }, 2120 }, 2121 { 2122 Type: DiffTypeNone, 2123 Name: "bar", 2124 }, 2125 { 2126 Type: DiffTypeEdited, 2127 Name: "baz", 2128 Fields: []*FieldDiff{ 2129 { 2130 Type: DiffTypeEdited, 2131 Name: "ShutdownDelay", 2132 Old: "1000000000", 2133 New: "2000000000", 2134 }, 2135 }, 2136 }, 2137 { 2138 Type: DiffTypeDeleted, 2139 Name: "foo", 2140 Fields: []*FieldDiff{ 2141 { 2142 Type: DiffTypeDeleted, 2143 Name: "Driver", 2144 Old: "docker", 2145 New: "", 2146 }, 2147 { 2148 Type: DiffTypeDeleted, 2149 Name: "KillTimeout", 2150 Old: "0", 2151 New: "", 2152 }, 2153 { 2154 Type: DiffTypeDeleted, 2155 Name: "Leader", 2156 Old: "false", 2157 New: "", 2158 }, 2159 { 2160 Type: DiffTypeDeleted, 2161 Name: "ShutdownDelay", 2162 Old: "0", 2163 New: "", 2164 }, 2165 }, 2166 }, 2167 }, 2168 }, 2169 }, 2170 } 2171 2172 for i, c := range cases { 2173 actual, err := c.Old.Diff(c.New, c.Contextual) 2174 if c.Error && err == nil { 2175 t.Fatalf("case %d: expected errored", i+1) 2176 } else if err != nil { 2177 if !c.Error { 2178 t.Fatalf("case %d: errored %#v", i+1, err) 2179 } else { 2180 continue 2181 } 2182 } 2183 2184 if !reflect.DeepEqual(actual, c.Expected) { 2185 t.Fatalf("case %d: got:\n%#v\n want:\n%#v\n", 2186 i+1, actual, c.Expected) 2187 } 2188 } 2189 } 2190 2191 func TestTaskDiff(t *testing.T) { 2192 cases := []struct { 2193 Name string 2194 Old, New *Task 2195 Expected *TaskDiff 2196 Error bool 2197 Contextual bool 2198 }{ 2199 { 2200 Name: "Empty", 2201 Old: nil, 2202 New: nil, 2203 Expected: &TaskDiff{ 2204 Type: DiffTypeNone, 2205 }, 2206 }, 2207 { 2208 Name: "Primitive only that has different names", 2209 Old: &Task{ 2210 Name: "foo", 2211 Meta: map[string]string{ 2212 "foo": "bar", 2213 }, 2214 }, 2215 New: &Task{ 2216 Name: "bar", 2217 Meta: map[string]string{ 2218 "foo": "bar", 2219 }, 2220 }, 2221 Error: true, 2222 }, 2223 { 2224 Name: "Primitive only that is the same", 2225 Old: &Task{ 2226 Name: "foo", 2227 Driver: "exec", 2228 User: "foo", 2229 Env: map[string]string{ 2230 "FOO": "bar", 2231 }, 2232 Meta: map[string]string{ 2233 "foo": "bar", 2234 }, 2235 KillTimeout: 1 * time.Second, 2236 Leader: true, 2237 }, 2238 New: &Task{ 2239 Name: "foo", 2240 Driver: "exec", 2241 User: "foo", 2242 Env: map[string]string{ 2243 "FOO": "bar", 2244 }, 2245 Meta: map[string]string{ 2246 "foo": "bar", 2247 }, 2248 KillTimeout: 1 * time.Second, 2249 Leader: true, 2250 }, 2251 Expected: &TaskDiff{ 2252 Type: DiffTypeNone, 2253 Name: "foo", 2254 }, 2255 }, 2256 { 2257 Name: "Primitive only that has diffs", 2258 Old: &Task{ 2259 Name: "foo", 2260 Driver: "exec", 2261 User: "foo", 2262 Env: map[string]string{ 2263 "FOO": "bar", 2264 }, 2265 Meta: map[string]string{ 2266 "foo": "bar", 2267 }, 2268 KillTimeout: 1 * time.Second, 2269 Leader: true, 2270 }, 2271 New: &Task{ 2272 Name: "foo", 2273 Driver: "docker", 2274 User: "bar", 2275 Env: map[string]string{ 2276 "FOO": "baz", 2277 }, 2278 Meta: map[string]string{ 2279 "foo": "baz", 2280 }, 2281 KillTimeout: 2 * time.Second, 2282 Leader: false, 2283 }, 2284 Expected: &TaskDiff{ 2285 Type: DiffTypeEdited, 2286 Name: "foo", 2287 Fields: []*FieldDiff{ 2288 { 2289 Type: DiffTypeEdited, 2290 Name: "Driver", 2291 Old: "exec", 2292 New: "docker", 2293 }, 2294 { 2295 Type: DiffTypeEdited, 2296 Name: "Env[FOO]", 2297 Old: "bar", 2298 New: "baz", 2299 }, 2300 { 2301 Type: DiffTypeEdited, 2302 Name: "KillTimeout", 2303 Old: "1000000000", 2304 New: "2000000000", 2305 }, 2306 { 2307 Type: DiffTypeEdited, 2308 Name: "Leader", 2309 Old: "true", 2310 New: "false", 2311 }, 2312 { 2313 Type: DiffTypeEdited, 2314 Name: "Meta[foo]", 2315 Old: "bar", 2316 New: "baz", 2317 }, 2318 { 2319 Type: DiffTypeEdited, 2320 Name: "User", 2321 Old: "foo", 2322 New: "bar", 2323 }, 2324 }, 2325 }, 2326 }, 2327 { 2328 Name: "Map diff", 2329 Old: &Task{ 2330 Meta: map[string]string{ 2331 "foo": "foo", 2332 "bar": "bar", 2333 }, 2334 Env: map[string]string{ 2335 "foo": "foo", 2336 "bar": "bar", 2337 }, 2338 }, 2339 New: &Task{ 2340 Meta: map[string]string{ 2341 "bar": "bar", 2342 "baz": "baz", 2343 }, 2344 Env: map[string]string{ 2345 "bar": "bar", 2346 "baz": "baz", 2347 }, 2348 }, 2349 Expected: &TaskDiff{ 2350 Type: DiffTypeEdited, 2351 Fields: []*FieldDiff{ 2352 { 2353 Type: DiffTypeAdded, 2354 Name: "Env[baz]", 2355 Old: "", 2356 New: "baz", 2357 }, 2358 { 2359 Type: DiffTypeDeleted, 2360 Name: "Env[foo]", 2361 Old: "foo", 2362 New: "", 2363 }, 2364 { 2365 Type: DiffTypeAdded, 2366 Name: "Meta[baz]", 2367 Old: "", 2368 New: "baz", 2369 }, 2370 { 2371 Type: DiffTypeDeleted, 2372 Name: "Meta[foo]", 2373 Old: "foo", 2374 New: "", 2375 }, 2376 }, 2377 }, 2378 }, 2379 { 2380 Name: "Constraints edited", 2381 Old: &Task{ 2382 Constraints: []*Constraint{ 2383 { 2384 LTarget: "foo", 2385 RTarget: "foo", 2386 Operand: "foo", 2387 str: "foo", 2388 }, 2389 { 2390 LTarget: "bar", 2391 RTarget: "bar", 2392 Operand: "bar", 2393 str: "bar", 2394 }, 2395 }, 2396 }, 2397 New: &Task{ 2398 Constraints: []*Constraint{ 2399 { 2400 LTarget: "foo", 2401 RTarget: "foo", 2402 Operand: "foo", 2403 str: "foo", 2404 }, 2405 { 2406 LTarget: "baz", 2407 RTarget: "baz", 2408 Operand: "baz", 2409 str: "baz", 2410 }, 2411 }, 2412 }, 2413 Expected: &TaskDiff{ 2414 Type: DiffTypeEdited, 2415 Objects: []*ObjectDiff{ 2416 { 2417 Type: DiffTypeAdded, 2418 Name: "Constraint", 2419 Fields: []*FieldDiff{ 2420 { 2421 Type: DiffTypeAdded, 2422 Name: "LTarget", 2423 Old: "", 2424 New: "baz", 2425 }, 2426 { 2427 Type: DiffTypeAdded, 2428 Name: "Operand", 2429 Old: "", 2430 New: "baz", 2431 }, 2432 { 2433 Type: DiffTypeAdded, 2434 Name: "RTarget", 2435 Old: "", 2436 New: "baz", 2437 }, 2438 }, 2439 }, 2440 { 2441 Type: DiffTypeDeleted, 2442 Name: "Constraint", 2443 Fields: []*FieldDiff{ 2444 { 2445 Type: DiffTypeDeleted, 2446 Name: "LTarget", 2447 Old: "bar", 2448 New: "", 2449 }, 2450 { 2451 Type: DiffTypeDeleted, 2452 Name: "Operand", 2453 Old: "bar", 2454 New: "", 2455 }, 2456 { 2457 Type: DiffTypeDeleted, 2458 Name: "RTarget", 2459 Old: "bar", 2460 New: "", 2461 }, 2462 }, 2463 }, 2464 }, 2465 }, 2466 }, 2467 { 2468 Name: "LogConfig added", 2469 Old: &Task{}, 2470 New: &Task{ 2471 LogConfig: &LogConfig{ 2472 MaxFiles: 1, 2473 MaxFileSizeMB: 10, 2474 }, 2475 }, 2476 Expected: &TaskDiff{ 2477 Type: DiffTypeEdited, 2478 Objects: []*ObjectDiff{ 2479 { 2480 Type: DiffTypeAdded, 2481 Name: "LogConfig", 2482 Fields: []*FieldDiff{ 2483 { 2484 Type: DiffTypeAdded, 2485 Name: "MaxFileSizeMB", 2486 Old: "", 2487 New: "10", 2488 }, 2489 { 2490 Type: DiffTypeAdded, 2491 Name: "MaxFiles", 2492 Old: "", 2493 New: "1", 2494 }, 2495 }, 2496 }, 2497 }, 2498 }, 2499 }, 2500 { 2501 Name: "LogConfig deleted", 2502 Old: &Task{ 2503 LogConfig: &LogConfig{ 2504 MaxFiles: 1, 2505 MaxFileSizeMB: 10, 2506 }, 2507 }, 2508 New: &Task{}, 2509 Expected: &TaskDiff{ 2510 Type: DiffTypeEdited, 2511 Objects: []*ObjectDiff{ 2512 { 2513 Type: DiffTypeDeleted, 2514 Name: "LogConfig", 2515 Fields: []*FieldDiff{ 2516 { 2517 Type: DiffTypeDeleted, 2518 Name: "MaxFileSizeMB", 2519 Old: "10", 2520 New: "", 2521 }, 2522 { 2523 Type: DiffTypeDeleted, 2524 Name: "MaxFiles", 2525 Old: "1", 2526 New: "", 2527 }, 2528 }, 2529 }, 2530 }, 2531 }, 2532 }, 2533 { 2534 Name: "LogConfig edited", 2535 Old: &Task{ 2536 LogConfig: &LogConfig{ 2537 MaxFiles: 1, 2538 MaxFileSizeMB: 10, 2539 }, 2540 }, 2541 New: &Task{ 2542 LogConfig: &LogConfig{ 2543 MaxFiles: 2, 2544 MaxFileSizeMB: 20, 2545 }, 2546 }, 2547 Expected: &TaskDiff{ 2548 Type: DiffTypeEdited, 2549 Objects: []*ObjectDiff{ 2550 { 2551 Type: DiffTypeEdited, 2552 Name: "LogConfig", 2553 Fields: []*FieldDiff{ 2554 { 2555 Type: DiffTypeEdited, 2556 Name: "MaxFileSizeMB", 2557 Old: "10", 2558 New: "20", 2559 }, 2560 { 2561 Type: DiffTypeEdited, 2562 Name: "MaxFiles", 2563 Old: "1", 2564 New: "2", 2565 }, 2566 }, 2567 }, 2568 }, 2569 }, 2570 }, 2571 { 2572 Name: "LogConfig edited with context", 2573 Contextual: true, 2574 Old: &Task{ 2575 LogConfig: &LogConfig{ 2576 MaxFiles: 1, 2577 MaxFileSizeMB: 10, 2578 }, 2579 }, 2580 New: &Task{ 2581 LogConfig: &LogConfig{ 2582 MaxFiles: 1, 2583 MaxFileSizeMB: 20, 2584 }, 2585 }, 2586 Expected: &TaskDiff{ 2587 Type: DiffTypeEdited, 2588 Objects: []*ObjectDiff{ 2589 { 2590 Type: DiffTypeEdited, 2591 Name: "LogConfig", 2592 Fields: []*FieldDiff{ 2593 { 2594 Type: DiffTypeEdited, 2595 Name: "MaxFileSizeMB", 2596 Old: "10", 2597 New: "20", 2598 }, 2599 { 2600 Type: DiffTypeNone, 2601 Name: "MaxFiles", 2602 Old: "1", 2603 New: "1", 2604 }, 2605 }, 2606 }, 2607 }, 2608 }, 2609 }, 2610 { 2611 Name: "Artifacts edited", 2612 Old: &Task{ 2613 Artifacts: []*TaskArtifact{ 2614 { 2615 GetterSource: "foo", 2616 GetterOptions: map[string]string{ 2617 "foo": "bar", 2618 }, 2619 RelativeDest: "foo", 2620 }, 2621 { 2622 GetterSource: "bar", 2623 GetterOptions: map[string]string{ 2624 "bar": "baz", 2625 }, 2626 GetterMode: "dir", 2627 RelativeDest: "bar", 2628 }, 2629 }, 2630 }, 2631 New: &Task{ 2632 Artifacts: []*TaskArtifact{ 2633 { 2634 GetterSource: "foo", 2635 GetterOptions: map[string]string{ 2636 "foo": "bar", 2637 }, 2638 RelativeDest: "foo", 2639 }, 2640 { 2641 GetterSource: "bam", 2642 GetterOptions: map[string]string{ 2643 "bam": "baz", 2644 }, 2645 GetterMode: "file", 2646 RelativeDest: "bam", 2647 }, 2648 }, 2649 }, 2650 Expected: &TaskDiff{ 2651 Type: DiffTypeEdited, 2652 Objects: []*ObjectDiff{ 2653 { 2654 Type: DiffTypeAdded, 2655 Name: "Artifact", 2656 Fields: []*FieldDiff{ 2657 { 2658 Type: DiffTypeAdded, 2659 Name: "GetterMode", 2660 Old: "", 2661 New: "file", 2662 }, 2663 { 2664 Type: DiffTypeAdded, 2665 Name: "GetterOptions[bam]", 2666 Old: "", 2667 New: "baz", 2668 }, 2669 { 2670 Type: DiffTypeAdded, 2671 Name: "GetterSource", 2672 Old: "", 2673 New: "bam", 2674 }, 2675 { 2676 Type: DiffTypeAdded, 2677 Name: "RelativeDest", 2678 Old: "", 2679 New: "bam", 2680 }, 2681 }, 2682 }, 2683 { 2684 Type: DiffTypeDeleted, 2685 Name: "Artifact", 2686 Fields: []*FieldDiff{ 2687 { 2688 Type: DiffTypeDeleted, 2689 Name: "GetterMode", 2690 Old: "dir", 2691 New: "", 2692 }, 2693 { 2694 Type: DiffTypeDeleted, 2695 Name: "GetterOptions[bar]", 2696 Old: "baz", 2697 New: "", 2698 }, 2699 { 2700 Type: DiffTypeDeleted, 2701 Name: "GetterSource", 2702 Old: "bar", 2703 New: "", 2704 }, 2705 { 2706 Type: DiffTypeDeleted, 2707 Name: "RelativeDest", 2708 Old: "bar", 2709 New: "", 2710 }, 2711 }, 2712 }, 2713 }, 2714 }, 2715 }, 2716 { 2717 Name: "Resources edited (no networks)", 2718 Old: &Task{ 2719 Resources: &Resources{ 2720 CPU: 100, 2721 MemoryMB: 100, 2722 DiskMB: 100, 2723 IOPS: 100, 2724 }, 2725 }, 2726 New: &Task{ 2727 Resources: &Resources{ 2728 CPU: 200, 2729 MemoryMB: 200, 2730 DiskMB: 200, 2731 IOPS: 200, 2732 }, 2733 }, 2734 Expected: &TaskDiff{ 2735 Type: DiffTypeEdited, 2736 Objects: []*ObjectDiff{ 2737 { 2738 Type: DiffTypeEdited, 2739 Name: "Resources", 2740 Fields: []*FieldDiff{ 2741 { 2742 Type: DiffTypeEdited, 2743 Name: "CPU", 2744 Old: "100", 2745 New: "200", 2746 }, 2747 { 2748 Type: DiffTypeEdited, 2749 Name: "DiskMB", 2750 Old: "100", 2751 New: "200", 2752 }, 2753 { 2754 Type: DiffTypeEdited, 2755 Name: "IOPS", 2756 Old: "100", 2757 New: "200", 2758 }, 2759 { 2760 Type: DiffTypeEdited, 2761 Name: "MemoryMB", 2762 Old: "100", 2763 New: "200", 2764 }, 2765 }, 2766 }, 2767 }, 2768 }, 2769 }, 2770 { 2771 Name: "Resources edited (no networks) with context", 2772 Contextual: true, 2773 Old: &Task{ 2774 Resources: &Resources{ 2775 CPU: 100, 2776 MemoryMB: 100, 2777 DiskMB: 100, 2778 IOPS: 100, 2779 }, 2780 }, 2781 New: &Task{ 2782 Resources: &Resources{ 2783 CPU: 200, 2784 MemoryMB: 100, 2785 DiskMB: 200, 2786 IOPS: 100, 2787 }, 2788 }, 2789 Expected: &TaskDiff{ 2790 Type: DiffTypeEdited, 2791 Objects: []*ObjectDiff{ 2792 { 2793 Type: DiffTypeEdited, 2794 Name: "Resources", 2795 Fields: []*FieldDiff{ 2796 { 2797 Type: DiffTypeEdited, 2798 Name: "CPU", 2799 Old: "100", 2800 New: "200", 2801 }, 2802 { 2803 Type: DiffTypeEdited, 2804 Name: "DiskMB", 2805 Old: "100", 2806 New: "200", 2807 }, 2808 { 2809 Type: DiffTypeNone, 2810 Name: "IOPS", 2811 Old: "100", 2812 New: "100", 2813 }, 2814 { 2815 Type: DiffTypeNone, 2816 Name: "MemoryMB", 2817 Old: "100", 2818 New: "100", 2819 }, 2820 }, 2821 }, 2822 }, 2823 }, 2824 }, 2825 { 2826 Name: "Network Resources edited", 2827 Old: &Task{ 2828 Resources: &Resources{ 2829 Networks: []*NetworkResource{ 2830 { 2831 Device: "foo", 2832 CIDR: "foo", 2833 IP: "foo", 2834 MBits: 100, 2835 ReservedPorts: []Port{ 2836 { 2837 Label: "foo", 2838 Value: 80, 2839 }, 2840 }, 2841 DynamicPorts: []Port{ 2842 { 2843 Label: "bar", 2844 }, 2845 }, 2846 }, 2847 }, 2848 }, 2849 }, 2850 New: &Task{ 2851 Resources: &Resources{ 2852 Networks: []*NetworkResource{ 2853 { 2854 Device: "bar", 2855 CIDR: "bar", 2856 IP: "bar", 2857 MBits: 200, 2858 ReservedPorts: []Port{ 2859 { 2860 Label: "foo", 2861 Value: 81, 2862 }, 2863 }, 2864 DynamicPorts: []Port{ 2865 { 2866 Label: "baz", 2867 }, 2868 }, 2869 }, 2870 }, 2871 }, 2872 }, 2873 Expected: &TaskDiff{ 2874 Type: DiffTypeEdited, 2875 Objects: []*ObjectDiff{ 2876 { 2877 Type: DiffTypeEdited, 2878 Name: "Resources", 2879 Objects: []*ObjectDiff{ 2880 { 2881 Type: DiffTypeAdded, 2882 Name: "Network", 2883 Fields: []*FieldDiff{ 2884 { 2885 Type: DiffTypeAdded, 2886 Name: "MBits", 2887 Old: "", 2888 New: "200", 2889 }, 2890 }, 2891 Objects: []*ObjectDiff{ 2892 { 2893 Type: DiffTypeAdded, 2894 Name: "Static Port", 2895 Fields: []*FieldDiff{ 2896 { 2897 Type: DiffTypeAdded, 2898 Name: "Label", 2899 Old: "", 2900 New: "foo", 2901 }, 2902 { 2903 Type: DiffTypeAdded, 2904 Name: "Value", 2905 Old: "", 2906 New: "81", 2907 }, 2908 }, 2909 }, 2910 { 2911 Type: DiffTypeAdded, 2912 Name: "Dynamic Port", 2913 Fields: []*FieldDiff{ 2914 { 2915 Type: DiffTypeAdded, 2916 Name: "Label", 2917 Old: "", 2918 New: "baz", 2919 }, 2920 }, 2921 }, 2922 }, 2923 }, 2924 { 2925 Type: DiffTypeDeleted, 2926 Name: "Network", 2927 Fields: []*FieldDiff{ 2928 { 2929 Type: DiffTypeDeleted, 2930 Name: "MBits", 2931 Old: "100", 2932 New: "", 2933 }, 2934 }, 2935 Objects: []*ObjectDiff{ 2936 { 2937 Type: DiffTypeDeleted, 2938 Name: "Static Port", 2939 Fields: []*FieldDiff{ 2940 { 2941 Type: DiffTypeDeleted, 2942 Name: "Label", 2943 Old: "foo", 2944 New: "", 2945 }, 2946 { 2947 Type: DiffTypeDeleted, 2948 Name: "Value", 2949 Old: "80", 2950 New: "", 2951 }, 2952 }, 2953 }, 2954 { 2955 Type: DiffTypeDeleted, 2956 Name: "Dynamic Port", 2957 Fields: []*FieldDiff{ 2958 { 2959 Type: DiffTypeDeleted, 2960 Name: "Label", 2961 Old: "bar", 2962 New: "", 2963 }, 2964 }, 2965 }, 2966 }, 2967 }, 2968 }, 2969 }, 2970 }, 2971 }, 2972 }, 2973 { 2974 Name: "Config same", 2975 Old: &Task{ 2976 Config: map[string]interface{}{ 2977 "foo": 1, 2978 "bar": "bar", 2979 "bam": []string{"a", "b"}, 2980 "baz": map[string]int{ 2981 "a": 1, 2982 "b": 2, 2983 }, 2984 "boom": &Port{ 2985 Label: "boom_port", 2986 }, 2987 }, 2988 }, 2989 New: &Task{ 2990 Config: map[string]interface{}{ 2991 "foo": 1, 2992 "bar": "bar", 2993 "bam": []string{"a", "b"}, 2994 "baz": map[string]int{ 2995 "a": 1, 2996 "b": 2, 2997 }, 2998 "boom": &Port{ 2999 Label: "boom_port", 3000 }, 3001 }, 3002 }, 3003 Expected: &TaskDiff{ 3004 Type: DiffTypeNone, 3005 }, 3006 }, 3007 { 3008 Name: "Config edited", 3009 Old: &Task{ 3010 Config: map[string]interface{}{ 3011 "foo": 1, 3012 "bar": "baz", 3013 "bam": []string{"a", "b"}, 3014 "baz": map[string]int{ 3015 "a": 1, 3016 "b": 2, 3017 }, 3018 "boom": &Port{ 3019 Label: "boom_port", 3020 }, 3021 }, 3022 }, 3023 New: &Task{ 3024 Config: map[string]interface{}{ 3025 "foo": 2, 3026 "bar": "baz", 3027 "bam": []string{"a", "c", "d"}, 3028 "baz": map[string]int{ 3029 "b": 3, 3030 "c": 4, 3031 }, 3032 "boom": &Port{ 3033 Label: "boom_port2", 3034 }, 3035 }, 3036 }, 3037 Expected: &TaskDiff{ 3038 Type: DiffTypeEdited, 3039 Objects: []*ObjectDiff{ 3040 { 3041 Type: DiffTypeEdited, 3042 Name: "Config", 3043 Fields: []*FieldDiff{ 3044 { 3045 Type: DiffTypeEdited, 3046 Name: "bam[1]", 3047 Old: "b", 3048 New: "c", 3049 }, 3050 { 3051 Type: DiffTypeAdded, 3052 Name: "bam[2]", 3053 Old: "", 3054 New: "d", 3055 }, 3056 { 3057 Type: DiffTypeDeleted, 3058 Name: "baz[a]", 3059 Old: "1", 3060 New: "", 3061 }, 3062 { 3063 Type: DiffTypeEdited, 3064 Name: "baz[b]", 3065 Old: "2", 3066 New: "3", 3067 }, 3068 { 3069 Type: DiffTypeAdded, 3070 Name: "baz[c]", 3071 Old: "", 3072 New: "4", 3073 }, 3074 { 3075 Type: DiffTypeEdited, 3076 Name: "boom.Label", 3077 Old: "boom_port", 3078 New: "boom_port2", 3079 }, 3080 { 3081 Type: DiffTypeEdited, 3082 Name: "foo", 3083 Old: "1", 3084 New: "2", 3085 }, 3086 }, 3087 }, 3088 }, 3089 }, 3090 }, 3091 { 3092 Name: "Config edited with context", 3093 Contextual: true, 3094 Old: &Task{ 3095 Config: map[string]interface{}{ 3096 "foo": 1, 3097 "bar": "baz", 3098 "bam": []string{"a", "b"}, 3099 "baz": map[string]int{ 3100 "a": 1, 3101 "b": 2, 3102 }, 3103 "boom": &Port{ 3104 Label: "boom_port", 3105 }, 3106 }, 3107 }, 3108 New: &Task{ 3109 Config: map[string]interface{}{ 3110 "foo": 2, 3111 "bar": "baz", 3112 "bam": []string{"a", "c", "d"}, 3113 "baz": map[string]int{ 3114 "a": 1, 3115 "b": 2, 3116 }, 3117 "boom": &Port{ 3118 Label: "boom_port", 3119 }, 3120 }, 3121 }, 3122 Expected: &TaskDiff{ 3123 Type: DiffTypeEdited, 3124 Objects: []*ObjectDiff{ 3125 { 3126 Type: DiffTypeEdited, 3127 Name: "Config", 3128 Fields: []*FieldDiff{ 3129 { 3130 Type: DiffTypeNone, 3131 Name: "bam[0]", 3132 Old: "a", 3133 New: "a", 3134 }, 3135 { 3136 Type: DiffTypeEdited, 3137 Name: "bam[1]", 3138 Old: "b", 3139 New: "c", 3140 }, 3141 { 3142 Type: DiffTypeAdded, 3143 Name: "bam[2]", 3144 Old: "", 3145 New: "d", 3146 }, 3147 { 3148 Type: DiffTypeNone, 3149 Name: "bar", 3150 Old: "baz", 3151 New: "baz", 3152 }, 3153 { 3154 Type: DiffTypeNone, 3155 Name: "baz[a]", 3156 Old: "1", 3157 New: "1", 3158 }, 3159 { 3160 Type: DiffTypeNone, 3161 Name: "baz[b]", 3162 Old: "2", 3163 New: "2", 3164 }, 3165 { 3166 Type: DiffTypeNone, 3167 Name: "boom.Label", 3168 Old: "boom_port", 3169 New: "boom_port", 3170 }, 3171 { 3172 Type: DiffTypeNone, 3173 Name: "boom.Value", 3174 Old: "0", 3175 New: "0", 3176 }, 3177 { 3178 Type: DiffTypeEdited, 3179 Name: "foo", 3180 Old: "1", 3181 New: "2", 3182 }, 3183 }, 3184 }, 3185 }, 3186 }, 3187 }, 3188 { 3189 Name: "Services edited (no checks)", 3190 Old: &Task{ 3191 Services: []*Service{ 3192 { 3193 Name: "foo", 3194 PortLabel: "foo", 3195 }, 3196 { 3197 Name: "bar", 3198 PortLabel: "bar", 3199 }, 3200 { 3201 Name: "baz", 3202 PortLabel: "baz", 3203 }, 3204 }, 3205 }, 3206 New: &Task{ 3207 Services: []*Service{ 3208 { 3209 Name: "bar", 3210 PortLabel: "bar", 3211 }, 3212 { 3213 Name: "baz", 3214 PortLabel: "baz2", 3215 }, 3216 { 3217 Name: "bam", 3218 PortLabel: "bam", 3219 }, 3220 }, 3221 }, 3222 Expected: &TaskDiff{ 3223 Type: DiffTypeEdited, 3224 Objects: []*ObjectDiff{ 3225 { 3226 Type: DiffTypeEdited, 3227 Name: "Service", 3228 Fields: []*FieldDiff{ 3229 { 3230 Type: DiffTypeEdited, 3231 Name: "PortLabel", 3232 Old: "baz", 3233 New: "baz2", 3234 }, 3235 }, 3236 }, 3237 { 3238 Type: DiffTypeAdded, 3239 Name: "Service", 3240 Fields: []*FieldDiff{ 3241 { 3242 Type: DiffTypeAdded, 3243 Name: "Name", 3244 Old: "", 3245 New: "bam", 3246 }, 3247 { 3248 Type: DiffTypeAdded, 3249 Name: "PortLabel", 3250 Old: "", 3251 New: "bam", 3252 }, 3253 }, 3254 }, 3255 { 3256 Type: DiffTypeDeleted, 3257 Name: "Service", 3258 Fields: []*FieldDiff{ 3259 { 3260 Type: DiffTypeDeleted, 3261 Name: "Name", 3262 Old: "foo", 3263 New: "", 3264 }, 3265 { 3266 Type: DiffTypeDeleted, 3267 Name: "PortLabel", 3268 Old: "foo", 3269 New: "", 3270 }, 3271 }, 3272 }, 3273 }, 3274 }, 3275 }, 3276 { 3277 Name: "Services edited (no checks) with context", 3278 Contextual: true, 3279 Old: &Task{ 3280 Services: []*Service{ 3281 { 3282 Name: "foo", 3283 PortLabel: "foo", 3284 }, 3285 }, 3286 }, 3287 New: &Task{ 3288 Services: []*Service{ 3289 { 3290 Name: "foo", 3291 PortLabel: "bar", 3292 AddressMode: "driver", 3293 }, 3294 }, 3295 }, 3296 Expected: &TaskDiff{ 3297 Type: DiffTypeEdited, 3298 Objects: []*ObjectDiff{ 3299 { 3300 Type: DiffTypeEdited, 3301 Name: "Service", 3302 Fields: []*FieldDiff{ 3303 { 3304 Type: DiffTypeAdded, 3305 Name: "AddressMode", 3306 New: "driver", 3307 }, 3308 { 3309 Type: DiffTypeNone, 3310 Name: "Name", 3311 Old: "foo", 3312 New: "foo", 3313 }, 3314 { 3315 Type: DiffTypeEdited, 3316 Name: "PortLabel", 3317 Old: "foo", 3318 New: "bar", 3319 }, 3320 }, 3321 }, 3322 }, 3323 }, 3324 }, 3325 { 3326 Name: "Service Checks edited", 3327 Old: &Task{ 3328 Services: []*Service{ 3329 { 3330 Name: "foo", 3331 Checks: []*ServiceCheck{ 3332 { 3333 Name: "foo", 3334 Type: "http", 3335 Command: "foo", 3336 Args: []string{"foo"}, 3337 Path: "foo", 3338 Protocol: "http", 3339 Interval: 1 * time.Second, 3340 Timeout: 1 * time.Second, 3341 Header: map[string][]string{ 3342 "Foo": {"bar"}, 3343 }, 3344 }, 3345 { 3346 Name: "bar", 3347 Type: "http", 3348 Command: "foo", 3349 Args: []string{"foo"}, 3350 Path: "foo", 3351 Protocol: "http", 3352 Interval: 1 * time.Second, 3353 Timeout: 1 * time.Second, 3354 }, 3355 { 3356 Name: "baz", 3357 Type: "http", 3358 Command: "foo", 3359 Args: []string{"foo"}, 3360 Path: "foo", 3361 Protocol: "http", 3362 Interval: 1 * time.Second, 3363 Timeout: 1 * time.Second, 3364 }, 3365 }, 3366 }, 3367 }, 3368 }, 3369 New: &Task{ 3370 Services: []*Service{ 3371 { 3372 Name: "foo", 3373 Checks: []*ServiceCheck{ 3374 { 3375 Name: "bar", 3376 Type: "http", 3377 Command: "foo", 3378 Args: []string{"foo"}, 3379 Path: "foo", 3380 Protocol: "http", 3381 Interval: 1 * time.Second, 3382 Timeout: 1 * time.Second, 3383 }, 3384 { 3385 Name: "baz", 3386 Type: "tcp", 3387 Command: "foo", 3388 Args: []string{"foo"}, 3389 Path: "foo", 3390 Protocol: "http", 3391 Interval: 1 * time.Second, 3392 Timeout: 1 * time.Second, 3393 Header: map[string][]string{ 3394 "Eggs": {"spam"}, 3395 }, 3396 }, 3397 { 3398 Name: "bam", 3399 Type: "http", 3400 Command: "foo", 3401 Args: []string{"foo"}, 3402 Path: "foo", 3403 Protocol: "http", 3404 Interval: 1 * time.Second, 3405 Timeout: 1 * time.Second, 3406 }, 3407 }, 3408 }, 3409 }, 3410 }, 3411 Expected: &TaskDiff{ 3412 Type: DiffTypeEdited, 3413 Objects: []*ObjectDiff{ 3414 { 3415 Type: DiffTypeEdited, 3416 Name: "Service", 3417 Objects: []*ObjectDiff{ 3418 { 3419 Type: DiffTypeEdited, 3420 Name: "Check", 3421 Fields: []*FieldDiff{ 3422 { 3423 Type: DiffTypeEdited, 3424 Name: "Type", 3425 Old: "http", 3426 New: "tcp", 3427 }, 3428 }, 3429 Objects: []*ObjectDiff{ 3430 { 3431 Type: DiffTypeAdded, 3432 Name: "Header", 3433 Fields: []*FieldDiff{ 3434 { 3435 Type: DiffTypeAdded, 3436 Name: "Eggs[0]", 3437 Old: "", 3438 New: "spam", 3439 }, 3440 }, 3441 }, 3442 }, 3443 }, 3444 { 3445 Type: DiffTypeAdded, 3446 Name: "Check", 3447 Fields: []*FieldDiff{ 3448 { 3449 Type: DiffTypeAdded, 3450 Name: "Command", 3451 Old: "", 3452 New: "foo", 3453 }, 3454 { 3455 Type: DiffTypeAdded, 3456 Name: "Interval", 3457 Old: "", 3458 New: "1000000000", 3459 }, 3460 { 3461 Type: DiffTypeAdded, 3462 Name: "Name", 3463 Old: "", 3464 New: "bam", 3465 }, 3466 { 3467 Type: DiffTypeAdded, 3468 Name: "Path", 3469 Old: "", 3470 New: "foo", 3471 }, 3472 { 3473 Type: DiffTypeAdded, 3474 Name: "Protocol", 3475 Old: "", 3476 New: "http", 3477 }, 3478 { 3479 Type: DiffTypeAdded, 3480 Name: "TLSSkipVerify", 3481 Old: "", 3482 New: "false", 3483 }, 3484 { 3485 Type: DiffTypeAdded, 3486 Name: "Timeout", 3487 Old: "", 3488 New: "1000000000", 3489 }, 3490 { 3491 Type: DiffTypeAdded, 3492 Name: "Type", 3493 Old: "", 3494 New: "http", 3495 }, 3496 }, 3497 }, 3498 { 3499 Type: DiffTypeDeleted, 3500 Name: "Check", 3501 Fields: []*FieldDiff{ 3502 { 3503 Type: DiffTypeDeleted, 3504 Name: "Command", 3505 Old: "foo", 3506 New: "", 3507 }, 3508 { 3509 Type: DiffTypeDeleted, 3510 Name: "Interval", 3511 Old: "1000000000", 3512 New: "", 3513 }, 3514 { 3515 Type: DiffTypeDeleted, 3516 Name: "Name", 3517 Old: "foo", 3518 New: "", 3519 }, 3520 { 3521 Type: DiffTypeDeleted, 3522 Name: "Path", 3523 Old: "foo", 3524 New: "", 3525 }, 3526 { 3527 Type: DiffTypeDeleted, 3528 Name: "Protocol", 3529 Old: "http", 3530 New: "", 3531 }, 3532 { 3533 Type: DiffTypeDeleted, 3534 Name: "TLSSkipVerify", 3535 Old: "false", 3536 New: "", 3537 }, 3538 { 3539 Type: DiffTypeDeleted, 3540 Name: "Timeout", 3541 Old: "1000000000", 3542 New: "", 3543 }, 3544 { 3545 Type: DiffTypeDeleted, 3546 Name: "Type", 3547 Old: "http", 3548 New: "", 3549 }, 3550 }, 3551 Objects: []*ObjectDiff{ 3552 { 3553 Type: DiffTypeDeleted, 3554 Name: "Header", 3555 Fields: []*FieldDiff{ 3556 { 3557 Type: DiffTypeDeleted, 3558 Name: "Foo[0]", 3559 Old: "bar", 3560 }, 3561 }, 3562 }, 3563 }, 3564 }, 3565 }, 3566 }, 3567 }, 3568 }, 3569 }, 3570 { 3571 Name: "Service Checks edited with context", 3572 Contextual: true, 3573 Old: &Task{ 3574 Services: []*Service{ 3575 { 3576 Name: "foo", 3577 Checks: []*ServiceCheck{ 3578 { 3579 Name: "foo", 3580 Type: "http", 3581 Command: "foo", 3582 Args: []string{"foo"}, 3583 Path: "foo", 3584 Protocol: "http", 3585 Interval: 1 * time.Second, 3586 Timeout: 1 * time.Second, 3587 InitialStatus: "critical", 3588 Header: map[string][]string{ 3589 "Foo": {"bar"}, 3590 }, 3591 }, 3592 }, 3593 }, 3594 }, 3595 }, 3596 New: &Task{ 3597 Services: []*Service{ 3598 { 3599 Name: "foo", 3600 Checks: []*ServiceCheck{ 3601 { 3602 Name: "foo", 3603 Type: "tcp", 3604 Command: "foo", 3605 Args: []string{"foo"}, 3606 Path: "foo", 3607 Protocol: "http", 3608 Interval: 1 * time.Second, 3609 Timeout: 1 * time.Second, 3610 InitialStatus: "passing", 3611 Method: "POST", 3612 Header: map[string][]string{ 3613 "Foo": {"bar", "baz"}, 3614 "Eggs": {"spam"}, 3615 }, 3616 }, 3617 }, 3618 }, 3619 }, 3620 }, 3621 Expected: &TaskDiff{ 3622 Type: DiffTypeEdited, 3623 Objects: []*ObjectDiff{ 3624 { 3625 Type: DiffTypeEdited, 3626 Name: "Service", 3627 Fields: []*FieldDiff{ 3628 { 3629 Type: DiffTypeNone, 3630 Name: "AddressMode", 3631 Old: "", 3632 New: "", 3633 }, 3634 { 3635 Type: DiffTypeNone, 3636 Name: "Name", 3637 Old: "foo", 3638 New: "foo", 3639 }, 3640 { 3641 Type: DiffTypeNone, 3642 Name: "PortLabel", 3643 Old: "", 3644 New: "", 3645 }, 3646 }, 3647 Objects: []*ObjectDiff{ 3648 { 3649 Type: DiffTypeEdited, 3650 Name: "Check", 3651 Fields: []*FieldDiff{ 3652 { 3653 Type: DiffTypeNone, 3654 Name: "AddressMode", 3655 Old: "", 3656 New: "", 3657 }, 3658 { 3659 Type: DiffTypeNone, 3660 Name: "Command", 3661 Old: "foo", 3662 New: "foo", 3663 }, 3664 { 3665 Type: DiffTypeEdited, 3666 Name: "InitialStatus", 3667 Old: "critical", 3668 New: "passing", 3669 }, 3670 { 3671 Type: DiffTypeNone, 3672 Name: "Interval", 3673 Old: "1000000000", 3674 New: "1000000000", 3675 }, 3676 { 3677 Type: DiffTypeAdded, 3678 Name: "Method", 3679 Old: "", 3680 New: "POST", 3681 }, 3682 { 3683 Type: DiffTypeNone, 3684 Name: "Name", 3685 Old: "foo", 3686 New: "foo", 3687 }, 3688 { 3689 Type: DiffTypeNone, 3690 Name: "Path", 3691 Old: "foo", 3692 New: "foo", 3693 }, 3694 { 3695 Type: DiffTypeNone, 3696 Name: "PortLabel", 3697 Old: "", 3698 New: "", 3699 }, 3700 { 3701 Type: DiffTypeNone, 3702 Name: "Protocol", 3703 Old: "http", 3704 New: "http", 3705 }, 3706 { 3707 Type: DiffTypeNone, 3708 Name: "TLSSkipVerify", 3709 Old: "false", 3710 New: "false", 3711 }, 3712 { 3713 Type: DiffTypeNone, 3714 Name: "Timeout", 3715 Old: "1000000000", 3716 New: "1000000000", 3717 }, 3718 { 3719 Type: DiffTypeEdited, 3720 Name: "Type", 3721 Old: "http", 3722 New: "tcp", 3723 }, 3724 }, 3725 Objects: []*ObjectDiff{ 3726 { 3727 Type: DiffTypeEdited, 3728 Name: "Header", 3729 Fields: []*FieldDiff{ 3730 { 3731 Type: DiffTypeAdded, 3732 Name: "Eggs[0]", 3733 Old: "", 3734 New: "spam", 3735 }, 3736 { 3737 Type: DiffTypeNone, 3738 Name: "Foo[0]", 3739 Old: "bar", 3740 New: "bar", 3741 }, 3742 { 3743 Type: DiffTypeAdded, 3744 Name: "Foo[1]", 3745 Old: "", 3746 New: "baz", 3747 }, 3748 }, 3749 }, 3750 }, 3751 }, 3752 }, 3753 }, 3754 }, 3755 }, 3756 }, 3757 { 3758 Name: "CheckRestart edited", 3759 Old: &Task{ 3760 Services: []*Service{ 3761 { 3762 Name: "foo", 3763 Checks: []*ServiceCheck{ 3764 { 3765 Name: "foo", 3766 Type: "http", 3767 Command: "foo", 3768 Args: []string{"foo"}, 3769 Path: "foo", 3770 Protocol: "http", 3771 Interval: 1 * time.Second, 3772 Timeout: 1 * time.Second, 3773 }, 3774 { 3775 Name: "bar", 3776 Type: "http", 3777 Command: "foo", 3778 Args: []string{"foo"}, 3779 Path: "foo", 3780 Protocol: "http", 3781 Interval: 1 * time.Second, 3782 Timeout: 1 * time.Second, 3783 CheckRestart: &CheckRestart{ 3784 Limit: 2, 3785 Grace: 2 * time.Second, 3786 }, 3787 }, 3788 { 3789 Name: "baz", 3790 Type: "http", 3791 Command: "foo", 3792 Args: []string{"foo"}, 3793 Path: "foo", 3794 Protocol: "http", 3795 Interval: 1 * time.Second, 3796 Timeout: 1 * time.Second, 3797 CheckRestart: &CheckRestart{ 3798 Limit: 3, 3799 Grace: 3 * time.Second, 3800 }, 3801 }, 3802 }, 3803 }, 3804 }, 3805 }, 3806 New: &Task{ 3807 Services: []*Service{ 3808 { 3809 Name: "foo", 3810 Checks: []*ServiceCheck{ 3811 { 3812 Name: "foo", 3813 Type: "http", 3814 Command: "foo", 3815 Args: []string{"foo"}, 3816 Path: "foo", 3817 Protocol: "http", 3818 Interval: 1 * time.Second, 3819 Timeout: 1 * time.Second, 3820 CheckRestart: &CheckRestart{ 3821 Limit: 1, 3822 Grace: 1 * time.Second, 3823 }, 3824 }, 3825 { 3826 Name: "bar", 3827 Type: "http", 3828 Command: "foo", 3829 Args: []string{"foo"}, 3830 Path: "foo", 3831 Protocol: "http", 3832 Interval: 1 * time.Second, 3833 Timeout: 1 * time.Second, 3834 }, 3835 { 3836 Name: "baz", 3837 Type: "http", 3838 Command: "foo", 3839 Args: []string{"foo"}, 3840 Path: "foo", 3841 Protocol: "http", 3842 Interval: 1 * time.Second, 3843 Timeout: 1 * time.Second, 3844 CheckRestart: &CheckRestart{ 3845 Limit: 4, 3846 Grace: 4 * time.Second, 3847 }, 3848 }, 3849 }, 3850 }, 3851 }, 3852 }, 3853 Expected: &TaskDiff{ 3854 Type: DiffTypeEdited, 3855 Objects: []*ObjectDiff{ 3856 { 3857 Type: DiffTypeEdited, 3858 Name: "Service", 3859 Objects: []*ObjectDiff{ 3860 { 3861 Type: DiffTypeEdited, 3862 Name: "Check", 3863 Objects: []*ObjectDiff{ 3864 { 3865 Type: DiffTypeEdited, 3866 Name: "CheckRestart", 3867 Fields: []*FieldDiff{ 3868 { 3869 Type: DiffTypeEdited, 3870 Name: "Grace", 3871 Old: "3000000000", 3872 New: "4000000000", 3873 }, 3874 { 3875 Type: DiffTypeEdited, 3876 Name: "Limit", 3877 Old: "3", 3878 New: "4", 3879 }, 3880 }, 3881 }, 3882 }, 3883 }, 3884 { 3885 Type: DiffTypeEdited, 3886 Name: "Check", 3887 Objects: []*ObjectDiff{ 3888 { 3889 Type: DiffTypeAdded, 3890 Name: "CheckRestart", 3891 Fields: []*FieldDiff{ 3892 { 3893 Type: DiffTypeAdded, 3894 Name: "Grace", 3895 New: "1000000000", 3896 }, 3897 { 3898 Type: DiffTypeAdded, 3899 Name: "IgnoreWarnings", 3900 New: "false", 3901 }, 3902 { 3903 Type: DiffTypeAdded, 3904 Name: "Limit", 3905 New: "1", 3906 }, 3907 }, 3908 }, 3909 }, 3910 }, 3911 { 3912 Type: DiffTypeEdited, 3913 Name: "Check", 3914 Objects: []*ObjectDiff{ 3915 { 3916 Type: DiffTypeDeleted, 3917 Name: "CheckRestart", 3918 Fields: []*FieldDiff{ 3919 { 3920 Type: DiffTypeDeleted, 3921 Name: "Grace", 3922 Old: "2000000000", 3923 }, 3924 { 3925 Type: DiffTypeDeleted, 3926 Name: "IgnoreWarnings", 3927 Old: "false", 3928 }, 3929 { 3930 Type: DiffTypeDeleted, 3931 Name: "Limit", 3932 Old: "2", 3933 }, 3934 }, 3935 }, 3936 }, 3937 }, 3938 }, 3939 }, 3940 }, 3941 }, 3942 }, 3943 { 3944 Name: "Vault added", 3945 Old: &Task{}, 3946 New: &Task{ 3947 Vault: &Vault{ 3948 Policies: []string{"foo", "bar"}, 3949 Env: true, 3950 ChangeMode: "signal", 3951 ChangeSignal: "SIGUSR1", 3952 }, 3953 }, 3954 Expected: &TaskDiff{ 3955 Type: DiffTypeEdited, 3956 Objects: []*ObjectDiff{ 3957 { 3958 Type: DiffTypeAdded, 3959 Name: "Vault", 3960 Fields: []*FieldDiff{ 3961 { 3962 Type: DiffTypeAdded, 3963 Name: "ChangeMode", 3964 Old: "", 3965 New: "signal", 3966 }, 3967 { 3968 Type: DiffTypeAdded, 3969 Name: "ChangeSignal", 3970 Old: "", 3971 New: "SIGUSR1", 3972 }, 3973 { 3974 Type: DiffTypeAdded, 3975 Name: "Env", 3976 Old: "", 3977 New: "true", 3978 }, 3979 }, 3980 Objects: []*ObjectDiff{ 3981 { 3982 Type: DiffTypeAdded, 3983 Name: "Policies", 3984 Fields: []*FieldDiff{ 3985 { 3986 Type: DiffTypeAdded, 3987 Name: "Policies", 3988 Old: "", 3989 New: "bar", 3990 }, 3991 { 3992 Type: DiffTypeAdded, 3993 Name: "Policies", 3994 Old: "", 3995 New: "foo", 3996 }, 3997 }, 3998 }, 3999 }, 4000 }, 4001 }, 4002 }, 4003 }, 4004 { 4005 Name: "Vault deleted", 4006 Old: &Task{ 4007 Vault: &Vault{ 4008 Policies: []string{"foo", "bar"}, 4009 Env: true, 4010 ChangeMode: "signal", 4011 ChangeSignal: "SIGUSR1", 4012 }, 4013 }, 4014 New: &Task{}, 4015 Expected: &TaskDiff{ 4016 Type: DiffTypeEdited, 4017 Objects: []*ObjectDiff{ 4018 { 4019 Type: DiffTypeDeleted, 4020 Name: "Vault", 4021 Fields: []*FieldDiff{ 4022 { 4023 Type: DiffTypeDeleted, 4024 Name: "ChangeMode", 4025 Old: "signal", 4026 New: "", 4027 }, 4028 { 4029 Type: DiffTypeDeleted, 4030 Name: "ChangeSignal", 4031 Old: "SIGUSR1", 4032 New: "", 4033 }, 4034 { 4035 Type: DiffTypeDeleted, 4036 Name: "Env", 4037 Old: "true", 4038 New: "", 4039 }, 4040 }, 4041 Objects: []*ObjectDiff{ 4042 { 4043 Type: DiffTypeDeleted, 4044 Name: "Policies", 4045 Fields: []*FieldDiff{ 4046 { 4047 Type: DiffTypeDeleted, 4048 Name: "Policies", 4049 Old: "bar", 4050 New: "", 4051 }, 4052 { 4053 Type: DiffTypeDeleted, 4054 Name: "Policies", 4055 Old: "foo", 4056 New: "", 4057 }, 4058 }, 4059 }, 4060 }, 4061 }, 4062 }, 4063 }, 4064 }, 4065 { 4066 Name: "Vault edited", 4067 Old: &Task{ 4068 Vault: &Vault{ 4069 Policies: []string{"foo", "bar"}, 4070 Env: true, 4071 ChangeMode: "signal", 4072 ChangeSignal: "SIGUSR1", 4073 }, 4074 }, 4075 New: &Task{ 4076 Vault: &Vault{ 4077 Policies: []string{"bar", "baz"}, 4078 Env: false, 4079 ChangeMode: "restart", 4080 ChangeSignal: "foo", 4081 }, 4082 }, 4083 Expected: &TaskDiff{ 4084 Type: DiffTypeEdited, 4085 Objects: []*ObjectDiff{ 4086 { 4087 Type: DiffTypeEdited, 4088 Name: "Vault", 4089 Fields: []*FieldDiff{ 4090 { 4091 Type: DiffTypeEdited, 4092 Name: "ChangeMode", 4093 Old: "signal", 4094 New: "restart", 4095 }, 4096 { 4097 Type: DiffTypeEdited, 4098 Name: "ChangeSignal", 4099 Old: "SIGUSR1", 4100 New: "foo", 4101 }, 4102 { 4103 Type: DiffTypeEdited, 4104 Name: "Env", 4105 Old: "true", 4106 New: "false", 4107 }, 4108 }, 4109 Objects: []*ObjectDiff{ 4110 { 4111 Type: DiffTypeEdited, 4112 Name: "Policies", 4113 Fields: []*FieldDiff{ 4114 { 4115 Type: DiffTypeAdded, 4116 Name: "Policies", 4117 Old: "", 4118 New: "baz", 4119 }, 4120 { 4121 Type: DiffTypeDeleted, 4122 Name: "Policies", 4123 Old: "foo", 4124 New: "", 4125 }, 4126 }, 4127 }, 4128 }, 4129 }, 4130 }, 4131 }, 4132 }, 4133 { 4134 Name: "Vault edited with context", 4135 Contextual: true, 4136 Old: &Task{ 4137 Vault: &Vault{ 4138 Policies: []string{"foo", "bar"}, 4139 Env: true, 4140 ChangeMode: "signal", 4141 ChangeSignal: "SIGUSR1", 4142 }, 4143 }, 4144 New: &Task{ 4145 Vault: &Vault{ 4146 Policies: []string{"bar", "baz"}, 4147 Env: true, 4148 ChangeMode: "signal", 4149 ChangeSignal: "SIGUSR1", 4150 }, 4151 }, 4152 Expected: &TaskDiff{ 4153 Type: DiffTypeEdited, 4154 Objects: []*ObjectDiff{ 4155 { 4156 Type: DiffTypeEdited, 4157 Name: "Vault", 4158 Fields: []*FieldDiff{ 4159 { 4160 Type: DiffTypeNone, 4161 Name: "ChangeMode", 4162 Old: "signal", 4163 New: "signal", 4164 }, 4165 { 4166 Type: DiffTypeNone, 4167 Name: "ChangeSignal", 4168 Old: "SIGUSR1", 4169 New: "SIGUSR1", 4170 }, 4171 { 4172 Type: DiffTypeNone, 4173 Name: "Env", 4174 Old: "true", 4175 New: "true", 4176 }, 4177 }, 4178 Objects: []*ObjectDiff{ 4179 { 4180 Type: DiffTypeEdited, 4181 Name: "Policies", 4182 Fields: []*FieldDiff{ 4183 { 4184 Type: DiffTypeAdded, 4185 Name: "Policies", 4186 Old: "", 4187 New: "baz", 4188 }, 4189 { 4190 Type: DiffTypeNone, 4191 Name: "Policies", 4192 Old: "bar", 4193 New: "bar", 4194 }, 4195 { 4196 Type: DiffTypeDeleted, 4197 Name: "Policies", 4198 Old: "foo", 4199 New: "", 4200 }, 4201 }, 4202 }, 4203 }, 4204 }, 4205 }, 4206 }, 4207 }, 4208 { 4209 Name: "Template edited", 4210 Old: &Task{ 4211 Templates: []*Template{ 4212 { 4213 SourcePath: "foo", 4214 DestPath: "bar", 4215 EmbeddedTmpl: "baz", 4216 ChangeMode: "bam", 4217 ChangeSignal: "SIGHUP", 4218 Splay: 1, 4219 Perms: "0644", 4220 VaultGrace: 3 * time.Second, 4221 }, 4222 { 4223 SourcePath: "foo2", 4224 DestPath: "bar2", 4225 EmbeddedTmpl: "baz2", 4226 ChangeMode: "bam2", 4227 ChangeSignal: "SIGHUP2", 4228 Splay: 2, 4229 Perms: "0666", 4230 Envvars: true, 4231 VaultGrace: 5 * time.Second, 4232 }, 4233 }, 4234 }, 4235 New: &Task{ 4236 Templates: []*Template{ 4237 { 4238 SourcePath: "foo", 4239 DestPath: "bar", 4240 EmbeddedTmpl: "baz", 4241 ChangeMode: "bam", 4242 ChangeSignal: "SIGHUP", 4243 Splay: 1, 4244 Perms: "0644", 4245 VaultGrace: 3 * time.Second, 4246 }, 4247 { 4248 SourcePath: "foo3", 4249 DestPath: "bar3", 4250 EmbeddedTmpl: "baz3", 4251 ChangeMode: "bam3", 4252 ChangeSignal: "SIGHUP3", 4253 Splay: 3, 4254 Perms: "0776", 4255 VaultGrace: 10 * time.Second, 4256 }, 4257 }, 4258 }, 4259 Expected: &TaskDiff{ 4260 Type: DiffTypeEdited, 4261 Objects: []*ObjectDiff{ 4262 { 4263 Type: DiffTypeAdded, 4264 Name: "Template", 4265 Fields: []*FieldDiff{ 4266 { 4267 Type: DiffTypeAdded, 4268 Name: "ChangeMode", 4269 Old: "", 4270 New: "bam3", 4271 }, 4272 { 4273 Type: DiffTypeAdded, 4274 Name: "ChangeSignal", 4275 Old: "", 4276 New: "SIGHUP3", 4277 }, 4278 { 4279 Type: DiffTypeAdded, 4280 Name: "DestPath", 4281 Old: "", 4282 New: "bar3", 4283 }, 4284 { 4285 Type: DiffTypeAdded, 4286 Name: "EmbeddedTmpl", 4287 Old: "", 4288 New: "baz3", 4289 }, 4290 { 4291 Type: DiffTypeAdded, 4292 Name: "Envvars", 4293 Old: "", 4294 New: "false", 4295 }, 4296 { 4297 Type: DiffTypeAdded, 4298 Name: "Perms", 4299 Old: "", 4300 New: "0776", 4301 }, 4302 { 4303 Type: DiffTypeAdded, 4304 Name: "SourcePath", 4305 Old: "", 4306 New: "foo3", 4307 }, 4308 { 4309 Type: DiffTypeAdded, 4310 Name: "Splay", 4311 Old: "", 4312 New: "3", 4313 }, 4314 { 4315 Type: DiffTypeAdded, 4316 Name: "VaultGrace", 4317 Old: "", 4318 New: "10000000000", 4319 }, 4320 }, 4321 }, 4322 { 4323 Type: DiffTypeDeleted, 4324 Name: "Template", 4325 Fields: []*FieldDiff{ 4326 { 4327 Type: DiffTypeDeleted, 4328 Name: "ChangeMode", 4329 Old: "bam2", 4330 New: "", 4331 }, 4332 { 4333 Type: DiffTypeDeleted, 4334 Name: "ChangeSignal", 4335 Old: "SIGHUP2", 4336 New: "", 4337 }, 4338 { 4339 Type: DiffTypeDeleted, 4340 Name: "DestPath", 4341 Old: "bar2", 4342 New: "", 4343 }, 4344 { 4345 Type: DiffTypeDeleted, 4346 Name: "EmbeddedTmpl", 4347 Old: "baz2", 4348 New: "", 4349 }, 4350 { 4351 Type: DiffTypeDeleted, 4352 Name: "Envvars", 4353 Old: "true", 4354 New: "", 4355 }, 4356 { 4357 Type: DiffTypeDeleted, 4358 Name: "Perms", 4359 Old: "0666", 4360 New: "", 4361 }, 4362 { 4363 Type: DiffTypeDeleted, 4364 Name: "SourcePath", 4365 Old: "foo2", 4366 New: "", 4367 }, 4368 { 4369 Type: DiffTypeDeleted, 4370 Name: "Splay", 4371 Old: "2", 4372 New: "", 4373 }, 4374 { 4375 Type: DiffTypeDeleted, 4376 Name: "VaultGrace", 4377 Old: "5000000000", 4378 New: "", 4379 }, 4380 }, 4381 }, 4382 }, 4383 }, 4384 }, 4385 { 4386 Name: "DispatchPayload added", 4387 Old: &Task{}, 4388 New: &Task{ 4389 DispatchPayload: &DispatchPayloadConfig{ 4390 File: "foo", 4391 }, 4392 }, 4393 Expected: &TaskDiff{ 4394 Type: DiffTypeEdited, 4395 Objects: []*ObjectDiff{ 4396 { 4397 Type: DiffTypeAdded, 4398 Name: "DispatchPayload", 4399 Fields: []*FieldDiff{ 4400 { 4401 Type: DiffTypeAdded, 4402 Name: "File", 4403 Old: "", 4404 New: "foo", 4405 }, 4406 }, 4407 }, 4408 }, 4409 }, 4410 }, 4411 { 4412 Name: "DispatchPayload deleted", 4413 Old: &Task{ 4414 DispatchPayload: &DispatchPayloadConfig{ 4415 File: "foo", 4416 }, 4417 }, 4418 New: &Task{}, 4419 Expected: &TaskDiff{ 4420 Type: DiffTypeEdited, 4421 Objects: []*ObjectDiff{ 4422 { 4423 Type: DiffTypeDeleted, 4424 Name: "DispatchPayload", 4425 Fields: []*FieldDiff{ 4426 { 4427 Type: DiffTypeDeleted, 4428 Name: "File", 4429 Old: "foo", 4430 New: "", 4431 }, 4432 }, 4433 }, 4434 }, 4435 }, 4436 }, 4437 { 4438 Name: "Dispatch payload edited", 4439 Old: &Task{ 4440 DispatchPayload: &DispatchPayloadConfig{ 4441 File: "foo", 4442 }, 4443 }, 4444 New: &Task{ 4445 DispatchPayload: &DispatchPayloadConfig{ 4446 File: "bar", 4447 }, 4448 }, 4449 Expected: &TaskDiff{ 4450 Type: DiffTypeEdited, 4451 Objects: []*ObjectDiff{ 4452 { 4453 Type: DiffTypeEdited, 4454 Name: "DispatchPayload", 4455 Fields: []*FieldDiff{ 4456 { 4457 Type: DiffTypeEdited, 4458 Name: "File", 4459 Old: "foo", 4460 New: "bar", 4461 }, 4462 }, 4463 }, 4464 }, 4465 }, 4466 }, 4467 { 4468 // Place holder for if more fields are added 4469 Name: "DispatchPayload edited with context", 4470 Contextual: true, 4471 Old: &Task{ 4472 DispatchPayload: &DispatchPayloadConfig{ 4473 File: "foo", 4474 }, 4475 }, 4476 New: &Task{ 4477 DispatchPayload: &DispatchPayloadConfig{ 4478 File: "bar", 4479 }, 4480 }, 4481 Expected: &TaskDiff{ 4482 Type: DiffTypeEdited, 4483 Objects: []*ObjectDiff{ 4484 { 4485 Type: DiffTypeEdited, 4486 Name: "DispatchPayload", 4487 Fields: []*FieldDiff{ 4488 { 4489 Type: DiffTypeEdited, 4490 Name: "File", 4491 Old: "foo", 4492 New: "bar", 4493 }, 4494 }, 4495 }, 4496 }, 4497 }, 4498 }, 4499 } 4500 4501 for i, c := range cases { 4502 t.Run(c.Name, func(t *testing.T) { 4503 actual, err := c.Old.Diff(c.New, c.Contextual) 4504 if c.Error && err == nil { 4505 t.Fatalf("case %d: expected errored", i+1) 4506 } else if err != nil { 4507 if !c.Error { 4508 t.Fatalf("case %d: errored %#v", i+1, err) 4509 } else { 4510 return 4511 } 4512 } 4513 4514 if !reflect.DeepEqual(actual, c.Expected) { 4515 t.Errorf("case %d: got:\n%#v\n want:\n%#v\n", 4516 i+1, actual, c.Expected) 4517 } 4518 }) 4519 } 4520 }