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