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