github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/papi/rule_test.go (about) 1 package papi 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/http" 8 "net/http/httptest" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestPapi_GetRuleTree(t *testing.T) { 16 tests := map[string]struct { 17 params GetRuleTreeRequest 18 responseStatus int 19 responseBody string 20 expectedPath string 21 expectedResponse *GetRuleTreeResponse 22 withError func(*testing.T, error) 23 }{ 24 "200 OK": { 25 params: GetRuleTreeRequest{ 26 PropertyID: "propertyID", 27 PropertyVersion: 2, 28 ContractID: "contract", 29 GroupID: "group", 30 ValidateMode: "fast", 31 ValidateRules: false, 32 }, 33 responseStatus: http.StatusOK, 34 responseBody: ` 35 { 36 "accountId": "accountID", 37 "contractId": "contract", 38 "groupId": "group", 39 "propertyId": "propertyID", 40 "propertyVersion": 2, 41 "etag": "etag", 42 "ruleFormat": "v2020-09-16", 43 "rules": { 44 "name": "default", 45 "criteria": [], 46 "children": [ 47 { 48 "name": "Compress Text Content", 49 "criteria": [ 50 { 51 "name": "contentType", 52 "options": { 53 "matchOperator": "IS_ONE_OF", 54 "matchWildcard": true, 55 "matchCaseSensitive": false, 56 "values": [ 57 "text/html*", 58 "text/css*", 59 "application/x-javascript*" 60 ] 61 } 62 } 63 ], 64 "behaviors": [ 65 { 66 "name": "gzipResponse", 67 "options": { "behavior": "ALWAYS" } 68 } 69 ] 70 } 71 ], 72 "options": { 73 "is_secure": false 74 }, 75 "behaviors": [ 76 { 77 "name": "origin", 78 "options": { 79 "httpPort": 80, 80 "enableTrueClientIp": false, 81 "compress": true, 82 "cacheKeyHostname": "ORIGIN_HOSTNAME", 83 "forwardHostHeader": "REQUEST_HOST_HEADER", 84 "hostname": "origin.test.com", 85 "originType": "CUSTOMER" 86 } 87 }, 88 { 89 "name": "cpCode", 90 "options": { 91 "value": { 92 "id": 12345, 93 "name": "my CP code" 94 } 95 } 96 } 97 ], 98 "customOverride": { 99 "overrideId": "cbo_12345", 100 "name": "mdc" 101 }, 102 "variables": [ 103 { 104 "name": "VAR_NAME", 105 "value": "default value", 106 "description": "This is a sample Property Manager variable.", 107 "hidden": false, 108 "sensitive": false 109 } 110 ] 111 } 112 }`, 113 expectedPath: "/papi/v1/properties/propertyID/versions/2/rules?contractId=contract&groupId=group&validateMode=fast&validateRules=false", 114 expectedResponse: &GetRuleTreeResponse{ 115 Response: Response{ 116 AccountID: "accountID", 117 ContractID: "contract", 118 GroupID: "group", 119 }, 120 PropertyID: "propertyID", 121 PropertyVersion: 2, 122 Etag: "etag", 123 RuleFormat: "v2020-09-16", 124 Rules: Rules{ 125 Behaviors: []RuleBehavior{ 126 { 127 Name: "origin", 128 Options: RuleOptionsMap{ 129 "httpPort": float64(80), 130 "enableTrueClientIp": false, 131 "compress": true, 132 "cacheKeyHostname": "ORIGIN_HOSTNAME", 133 "forwardHostHeader": "REQUEST_HOST_HEADER", 134 "hostname": "origin.test.com", 135 "originType": "CUSTOMER", 136 }, 137 }, 138 { 139 Name: "cpCode", 140 Options: RuleOptionsMap{ 141 "value": map[string]interface{}{ 142 "id": float64(12345), 143 "name": "my CP code", 144 }, 145 }, 146 }, 147 }, 148 Children: []Rules{ 149 { 150 Behaviors: []RuleBehavior{ 151 { 152 Name: "gzipResponse", 153 Options: RuleOptionsMap{ 154 "behavior": "ALWAYS", 155 }, 156 }, 157 }, 158 Criteria: []RuleBehavior{ 159 { 160 Locked: false, 161 Name: "contentType", 162 Options: RuleOptionsMap{ 163 "matchOperator": "IS_ONE_OF", 164 "matchWildcard": true, 165 "matchCaseSensitive": false, 166 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 167 }, 168 }, 169 }, 170 Name: "Compress Text Content", 171 }, 172 }, 173 Criteria: []RuleBehavior{}, 174 Name: "default", 175 Options: RuleOptions{IsSecure: false}, 176 CustomOverride: &RuleCustomOverride{ 177 OverrideID: "cbo_12345", 178 Name: "mdc", 179 }, 180 Variables: []RuleVariable{ 181 { 182 Description: "This is a sample Property Manager variable.", 183 Hidden: false, 184 Name: "VAR_NAME", 185 Sensitive: false, 186 Value: "default value", 187 }, 188 }, 189 }, 190 }, 191 }, 192 "200 OK nested with empty behaviour": { 193 params: GetRuleTreeRequest{ 194 PropertyID: "propertyID", 195 PropertyVersion: 2, 196 ContractID: "contract", 197 GroupID: "group", 198 ValidateMode: "fast", 199 ValidateRules: false, 200 }, 201 responseStatus: http.StatusOK, 202 responseBody: ` 203 { 204 "accountId": "accountID", 205 "contractId": "contract", 206 "groupId": "group", 207 "propertyId": "propertyID", 208 "propertyVersion": 2, 209 "etag": "etag", 210 "ruleFormat": "v2020-09-16", 211 "rules": { 212 "name": "default", 213 "children": [{ 214 "name": "Augment insights", 215 "criteria": [], 216 "children": [{ 217 "name": "Compress Text Content", 218 "criteria": [{ 219 "name": "contentType", 220 "options": { 221 "matchOperator": "IS_ONE_OF", 222 "matchWildcard": true, 223 "matchCaseSensitive": false, 224 "values": [ 225 "text/html*", 226 "text/css*", 227 "application/x-javascript*" 228 ] 229 } 230 }], 231 "behaviors": [] 232 }], 233 "options": { 234 "is_secure": false 235 } 236 }], 237 "behaviors": [{ 238 "name": "origin", 239 "options": { 240 "httpPort": 80, 241 "enableTrueClientIp": false, 242 "compress": true, 243 "cacheKeyHostname": "ORIGIN_HOSTNAME", 244 "forwardHostHeader": "REQUEST_HOST_HEADER", 245 "hostname": "origin.test.com", 246 "originType": "CUSTOMER" 247 } 248 }, 249 { 250 "name": "cpCode", 251 "options": { 252 "value": { 253 "id": 12345, 254 "name": "my CP code" 255 } 256 } 257 } 258 ], 259 "customOverride": { 260 "overrideId": "cbo_12345", 261 "name": "mdc" 262 }, 263 "variables": [{ 264 "name": "VAR_NAME", 265 "value": "default value", 266 "description": "This is a sample Property Manager variable.", 267 "hidden": false, 268 "sensitive": false 269 }] 270 } 271 }`, 272 expectedPath: "/papi/v1/properties/propertyID/versions/2/rules?contractId=contract&groupId=group&validateMode=fast&validateRules=false", 273 expectedResponse: &GetRuleTreeResponse{ 274 Response: Response{ 275 AccountID: "accountID", 276 ContractID: "contract", 277 GroupID: "group", 278 }, 279 PropertyID: "propertyID", 280 PropertyVersion: 2, 281 Etag: "etag", 282 RuleFormat: "v2020-09-16", 283 Rules: Rules{ 284 Behaviors: []RuleBehavior{ 285 { 286 Name: "origin", 287 Options: RuleOptionsMap{ 288 "httpPort": float64(80), 289 "enableTrueClientIp": false, 290 "compress": true, 291 "cacheKeyHostname": "ORIGIN_HOSTNAME", 292 "forwardHostHeader": "REQUEST_HOST_HEADER", 293 "hostname": "origin.test.com", 294 "originType": "CUSTOMER", 295 }, 296 }, 297 { 298 Name: "cpCode", 299 Options: RuleOptionsMap{ 300 "value": map[string]interface{}{ 301 "id": float64(12345), 302 "name": "my CP code", 303 }, 304 }, 305 }, 306 }, 307 Children: []Rules{ 308 { 309 Criteria: []RuleBehavior{}, 310 Name: "Augment insights", 311 312 Children: []Rules{ 313 { 314 Behaviors: []RuleBehavior{}, 315 Criteria: []RuleBehavior{ 316 { 317 Locked: false, 318 Name: "contentType", 319 Options: RuleOptionsMap{ 320 "matchOperator": "IS_ONE_OF", 321 "matchWildcard": true, 322 "matchCaseSensitive": false, 323 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 324 }, 325 }, 326 }, 327 Name: "Compress Text Content"}, 328 }}}, 329 Name: "default", 330 Options: RuleOptions{IsSecure: false}, 331 CustomOverride: &RuleCustomOverride{ 332 OverrideID: "cbo_12345", 333 Name: "mdc", 334 }, 335 Variables: []RuleVariable{ 336 { 337 Description: "This is a sample Property Manager variable.", 338 Hidden: false, 339 Name: "VAR_NAME", 340 Sensitive: false, 341 Value: "default value", 342 }, 343 }, 344 }, 345 }, 346 }, 347 "200 OK nested with empty name": { 348 params: GetRuleTreeRequest{ 349 PropertyID: "propertyID", 350 PropertyVersion: 2, 351 ContractID: "contract", 352 GroupID: "group", 353 ValidateMode: "fast", 354 ValidateRules: false, 355 }, 356 responseStatus: http.StatusOK, 357 responseBody: ` 358 { 359 "accountId": "accountID", 360 "contractId": "contract", 361 "groupId": "group", 362 "propertyId": "propertyID", 363 "propertyVersion": 2, 364 "etag": "etag", 365 "ruleFormat": "v2020-09-16", 366 "rules": { 367 "name": "default", 368 "children": [{ 369 "criteria": [], 370 "children": [{ 371 "name": "Compress Text Content", 372 "criteria": [{ 373 "name": "contentType", 374 "options": { 375 "matchOperator": "IS_ONE_OF", 376 "matchWildcard": true, 377 "matchCaseSensitive": false, 378 "values": [ 379 "text/html*", 380 "text/css*", 381 "application/x-javascript*" 382 ] 383 } 384 }], 385 "behaviors": [] 386 }], 387 "options": { 388 "is_secure": false 389 } 390 }], 391 "behaviors": [{ 392 "name": "origin", 393 "options": { 394 "httpPort": 80, 395 "enableTrueClientIp": false, 396 "compress": true, 397 "cacheKeyHostname": "ORIGIN_HOSTNAME", 398 "forwardHostHeader": "REQUEST_HOST_HEADER", 399 "hostname": "origin.test.com", 400 "originType": "CUSTOMER" 401 } 402 }, 403 { 404 "name": "cpCode", 405 "options": { 406 "value": { 407 "id": 12345, 408 "name": "my CP code" 409 } 410 } 411 } 412 ], 413 "customOverride": { 414 "overrideId": "cbo_12345", 415 "name": "mdc" 416 }, 417 "variables": [{ 418 "name": "VAR_NAME", 419 "value": "default value", 420 "description": "This is a sample Property Manager variable.", 421 "hidden": false, 422 "sensitive": false 423 }] 424 } 425 }`, 426 expectedPath: "/papi/v1/properties/propertyID/versions/2/rules?contractId=contract&groupId=group&validateMode=fast&validateRules=false", 427 expectedResponse: &GetRuleTreeResponse{ 428 Response: Response{ 429 AccountID: "accountID", 430 ContractID: "contract", 431 GroupID: "group", 432 }, 433 PropertyID: "propertyID", 434 PropertyVersion: 2, 435 Etag: "etag", 436 RuleFormat: "v2020-09-16", 437 Rules: Rules{ 438 Behaviors: []RuleBehavior{ 439 { 440 Name: "origin", 441 Options: RuleOptionsMap{ 442 "httpPort": float64(80), 443 "enableTrueClientIp": false, 444 "compress": true, 445 "cacheKeyHostname": "ORIGIN_HOSTNAME", 446 "forwardHostHeader": "REQUEST_HOST_HEADER", 447 "hostname": "origin.test.com", 448 "originType": "CUSTOMER", 449 }, 450 }, 451 { 452 Name: "cpCode", 453 Options: RuleOptionsMap{ 454 "value": map[string]interface{}{ 455 "id": float64(12345), 456 "name": "my CP code", 457 }, 458 }, 459 }, 460 }, 461 Children: []Rules{ 462 { 463 Criteria: []RuleBehavior{}, 464 Children: []Rules{ 465 { 466 Behaviors: []RuleBehavior{}, 467 Criteria: []RuleBehavior{ 468 { 469 Locked: false, 470 Name: "contentType", 471 Options: RuleOptionsMap{ 472 "matchOperator": "IS_ONE_OF", 473 "matchWildcard": true, 474 "matchCaseSensitive": false, 475 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 476 }, 477 }, 478 }, 479 Name: "Compress Text Content"}, 480 }}}, 481 Name: "default", 482 Options: RuleOptions{IsSecure: false}, 483 CustomOverride: &RuleCustomOverride{ 484 OverrideID: "cbo_12345", 485 Name: "mdc", 486 }, 487 Variables: []RuleVariable{ 488 { 489 Description: "This is a sample Property Manager variable.", 490 Hidden: false, 491 Name: "VAR_NAME", 492 Sensitive: false, 493 Value: "default value", 494 }, 495 }, 496 }, 497 }, 498 }, 499 "500 Internal Server Error": { 500 params: GetRuleTreeRequest{ 501 PropertyID: "propertyID", 502 PropertyVersion: 2, 503 ContractID: "contract", 504 GroupID: "group", 505 ValidateMode: "fast", 506 ValidateRules: false, 507 }, 508 responseStatus: http.StatusInternalServerError, 509 responseBody: ` 510 { 511 "type": "internal_error", 512 "title": "Internal Server Error", 513 "detail": "Error fetching rule tree", 514 "status": 500 515 }`, 516 expectedPath: "/papi/v1/properties/propertyID/versions/2/rules?contractId=contract&groupId=group&validateMode=fast&validateRules=false", 517 withError: func(t *testing.T, err error) { 518 want := &Error{ 519 Type: "internal_error", 520 Title: "Internal Server Error", 521 Detail: "Error fetching rule tree", 522 StatusCode: http.StatusInternalServerError, 523 } 524 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 525 }, 526 }, 527 "empty property ID": { 528 params: GetRuleTreeRequest{ 529 PropertyID: "", 530 PropertyVersion: 2, 531 ContractID: "contract", 532 GroupID: "group", 533 ValidateMode: "fast", 534 ValidateRules: false, 535 }, 536 withError: func(t *testing.T, err error) { 537 want := ErrStructValidation 538 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 539 assert.Contains(t, err.Error(), "PropertyID") 540 }, 541 }, 542 "empty property version": { 543 params: GetRuleTreeRequest{ 544 PropertyID: "propertyID", 545 ContractID: "contract", 546 GroupID: "group", 547 ValidateMode: "fast", 548 ValidateRules: false, 549 }, 550 withError: func(t *testing.T, err error) { 551 want := ErrStructValidation 552 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 553 assert.Contains(t, err.Error(), "PropertyVersion") 554 }, 555 }, 556 "invalid validation mode": { 557 params: GetRuleTreeRequest{ 558 PropertyID: "propertyID", 559 PropertyVersion: 2, 560 ContractID: "contract", 561 GroupID: "group", 562 ValidateMode: "test", 563 ValidateRules: false, 564 }, 565 withError: func(t *testing.T, err error) { 566 want := ErrStructValidation 567 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 568 assert.Contains(t, err.Error(), "ValidateMode") 569 }, 570 }, 571 "Accept header with latest ruleFormat": { 572 params: GetRuleTreeRequest{ 573 PropertyID: "1", 574 PropertyVersion: 2, 575 ContractID: "contract", 576 GroupID: "group", 577 ValidateMode: "fast", 578 ValidateRules: false, 579 RuleFormat: "latest", 580 }, 581 responseStatus: http.StatusOK, 582 responseBody: "{}", 583 expectedPath: "/papi/v1/properties/1/versions/2/rules?contractId=contract&groupId=group&validateMode=fast&validateRules=false", 584 expectedResponse: &GetRuleTreeResponse{}, 585 }, 586 "Accept header with versioned ruleFormat": { 587 params: GetRuleTreeRequest{ 588 PropertyID: "1", 589 PropertyVersion: 2, 590 ContractID: "contract", 591 GroupID: "group", 592 ValidateMode: "fast", 593 ValidateRules: false, 594 RuleFormat: "v2021-01-01", 595 }, 596 responseStatus: http.StatusOK, 597 responseBody: "{}", 598 expectedPath: "/papi/v1/properties/1/versions/2/rules?contractId=contract&groupId=group&validateMode=fast&validateRules=false", 599 expectedResponse: &GetRuleTreeResponse{}, 600 }, 601 "Accept header with invalid ruleFormat": { 602 params: GetRuleTreeRequest{ 603 PropertyID: "1", 604 PropertyVersion: 2, 605 ContractID: "contract", 606 GroupID: "group", 607 ValidateMode: "fast", 608 ValidateRules: false, 609 RuleFormat: "invalid", 610 }, 611 responseStatus: http.StatusUnsupportedMediaType, 612 withError: func(t *testing.T, err error) { 613 want := ErrStructValidation 614 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 615 assert.Contains(t, err.Error(), "RuleFormat") 616 }, 617 }, 618 } 619 620 for name, test := range tests { 621 t.Run(name, func(t *testing.T) { 622 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 623 assert.Equal(t, test.expectedPath, r.URL.String()) 624 assert.Equal(t, http.MethodGet, r.Method) 625 w.WriteHeader(test.responseStatus) 626 _, err := w.Write([]byte(test.responseBody)) 627 if test.params.RuleFormat != "" { 628 assert.Equal(t, r.Header.Get("Accept"), fmt.Sprintf("application/vnd.akamai.papirules.%s+json", test.params.RuleFormat)) 629 } 630 assert.NoError(t, err) 631 })) 632 client := mockAPIClient(t, mockServer) 633 result, err := client.GetRuleTree(context.Background(), test.params) 634 if test.withError != nil { 635 test.withError(t, err) 636 return 637 } 638 require.NoError(t, err) 639 assert.Equal(t, test.expectedResponse, result) 640 }) 641 } 642 } 643 644 func TestPapi_UpdateRuleTree(t *testing.T) { 645 tests := map[string]struct { 646 params UpdateRulesRequest 647 responseStatus int 648 responseBody string 649 expectedPath string 650 expectedResponse *UpdateRulesResponse 651 withError func(*testing.T, error) 652 }{ 653 "200 OK": { 654 params: UpdateRulesRequest{ 655 PropertyID: "propertyID", 656 PropertyVersion: 2, 657 ContractID: "contract", 658 GroupID: "group", 659 DryRun: true, 660 ValidateMode: "fast", 661 ValidateRules: false, 662 Rules: RulesUpdate{ 663 Comments: "version comment", 664 Rules: Rules{ 665 Comments: "default comment", 666 Behaviors: []RuleBehavior{ 667 { 668 Name: "origin", 669 Options: RuleOptionsMap{ 670 "httpPort": float64(80), 671 "enableTrueClientIp": false, 672 "compress": true, 673 "cacheKeyHostname": "ORIGIN_HOSTNAME", 674 "forwardHostHeader": "REQUEST_HOST_HEADER", 675 "hostname": "origin.test.com", 676 "originType": "CUSTOMER", 677 }, 678 }, 679 { 680 Name: "cpCode", 681 Options: RuleOptionsMap{ 682 "value": map[string]interface{}{ 683 "id": float64(12345), 684 "name": "my CP code", 685 }, 686 }, 687 }, 688 }, 689 Children: []Rules{ 690 { 691 Behaviors: []RuleBehavior{ 692 { 693 Name: "gzipResponse", 694 Options: RuleOptionsMap{ 695 "behavior": "ALWAYS", 696 }, 697 }, 698 }, 699 Criteria: []RuleBehavior{ 700 { 701 Locked: false, 702 Name: "contentType", 703 Options: RuleOptionsMap{ 704 "matchOperator": "IS_ONE_OF", 705 "matchWildcard": true, 706 "matchCaseSensitive": false, 707 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 708 }, 709 }, 710 }, 711 Name: "Compress Text Content", 712 }, 713 }, 714 Criteria: []RuleBehavior{}, 715 Name: "default", 716 Options: RuleOptions{IsSecure: false}, 717 CustomOverride: &RuleCustomOverride{ 718 OverrideID: "cbo_12345", 719 Name: "mdc", 720 }, 721 Variables: []RuleVariable{ 722 { 723 Description: "This is a sample Property Manager variable.", 724 Hidden: false, 725 Name: "VAR_NAME", 726 Sensitive: false, 727 Value: "default value", 728 }, 729 }, 730 }, 731 }, 732 }, 733 responseStatus: http.StatusOK, 734 responseBody: ` 735 { 736 "accountId": "accountID", 737 "contractId": "contract", 738 "groupId": "group", 739 "propertyId": "propertyID", 740 "propertyVersion": 2, 741 "etag": "etag", 742 "ruleFormat": "v2020-09-16", 743 "comments": "version comment", 744 "rules": { 745 "name": "default", 746 "comments": "default comment", 747 "criteria": [], 748 "children": [ 749 { 750 "name": "Compress Text Content", 751 "criteria": [ 752 { 753 "name": "contentType", 754 "options": { 755 "matchOperator": "IS_ONE_OF", 756 "matchWildcard": true, 757 "matchCaseSensitive": false, 758 "values": [ 759 "text/html*", 760 "text/css*", 761 "application/x-javascript*" 762 ] 763 } 764 } 765 ], 766 "behaviors": [ 767 { 768 "name": "gzipResponse", 769 "options": { "behavior": "ALWAYS" } 770 } 771 ] 772 } 773 ], 774 "options": { 775 "is_secure": false 776 }, 777 "behaviors": [ 778 { 779 "name": "origin", 780 "options": { 781 "httpPort": 80, 782 "enableTrueClientIp": false, 783 "compress": true, 784 "cacheKeyHostname": "ORIGIN_HOSTNAME", 785 "forwardHostHeader": "REQUEST_HOST_HEADER", 786 "hostname": "origin.test.com", 787 "originType": "CUSTOMER" 788 } 789 }, 790 { 791 "name": "cpCode", 792 "options": { 793 "value": { 794 "id": 12345, 795 "name": "my CP code" 796 } 797 } 798 }, 799 { 800 "name": "matchAdvanced", 801 "options": { 802 "value": { 803 "id": 12345, 804 "name": "my advanced match" 805 } 806 }, 807 "locked": true, 808 "uuid": "fd6a63bc-120a-4891-a5f2-c479765d5553", 809 "templateUuid": "bedbac99-4ce1-43a3-96cc-b84c8cd30176" 810 } 811 ], 812 "customOverride": { 813 "overrideId": "cbo_12345", 814 "name": "mdc" 815 }, 816 "templateUuid": "bedbac99-4ce1-43a3-96cc-b84c8cd30176", 817 "templateLink": "/platformtoolkit/service/ruletemplate/30582260/1?accountId=1-1TJZFB&gid=61726&ck=16.3.1.1", 818 "variables": [ 819 { 820 "name": "VAR_NAME", 821 "value": "default value", 822 "description": "This is a sample Property Manager variable.", 823 "hidden": false, 824 "sensitive": false 825 } 826 ] 827 }, 828 "errors": [ 829 { 830 "type": "/papi/v1/errors/validation.required_behavior", 831 "title": "Missing required behavior in default rule", 832 "detail": "In order for this property to work correctly behavior Content Provider Code needs to be present in the default section", 833 "instance": "/papi/v1/properties/prp_173136/versions/3/rules#err_100", 834 "behaviorName": "cpCode" 835 } 836 ] 837 }`, 838 expectedPath: "/papi/v1/properties/propertyID/versions/2/rules?contractId=contract&dryRun=true&groupId=group&validateMode=fast&validateRules=false", 839 expectedResponse: &UpdateRulesResponse{ 840 AccountID: "accountID", 841 ContractID: "contract", 842 GroupID: "group", 843 PropertyID: "propertyID", 844 PropertyVersion: 2, 845 Etag: "etag", 846 RuleFormat: "v2020-09-16", 847 Comments: "version comment", 848 Rules: Rules{ 849 Comments: "default comment", 850 Behaviors: []RuleBehavior{ 851 { 852 Name: "origin", 853 Options: RuleOptionsMap{ 854 "httpPort": float64(80), 855 "enableTrueClientIp": false, 856 "compress": true, 857 "cacheKeyHostname": "ORIGIN_HOSTNAME", 858 "forwardHostHeader": "REQUEST_HOST_HEADER", 859 "hostname": "origin.test.com", 860 "originType": "CUSTOMER", 861 }, 862 }, 863 { 864 Name: "cpCode", 865 Options: RuleOptionsMap{ 866 "value": map[string]interface{}{ 867 "id": float64(12345), 868 "name": "my CP code", 869 }, 870 }, 871 }, 872 { 873 Name: "matchAdvanced", 874 Options: RuleOptionsMap{ 875 "value": map[string]interface{}{ 876 "id": float64(12345), 877 "name": "my advanced match", 878 }, 879 }, 880 Locked: true, 881 UUID: "fd6a63bc-120a-4891-a5f2-c479765d5553", 882 TemplateUuid: "bedbac99-4ce1-43a3-96cc-b84c8cd30176", 883 }, 884 }, 885 Children: []Rules{ 886 { 887 Behaviors: []RuleBehavior{ 888 { 889 Name: "gzipResponse", 890 Options: RuleOptionsMap{ 891 "behavior": "ALWAYS", 892 }, 893 }, 894 }, 895 Criteria: []RuleBehavior{ 896 { 897 Locked: false, 898 Name: "contentType", 899 Options: RuleOptionsMap{ 900 "matchOperator": "IS_ONE_OF", 901 "matchWildcard": true, 902 "matchCaseSensitive": false, 903 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 904 }, 905 }, 906 }, 907 Name: "Compress Text Content", 908 }, 909 }, 910 Criteria: []RuleBehavior{}, 911 Name: "default", 912 Options: RuleOptions{IsSecure: false}, 913 CustomOverride: &RuleCustomOverride{ 914 OverrideID: "cbo_12345", 915 Name: "mdc", 916 }, 917 TemplateUuid: "bedbac99-4ce1-43a3-96cc-b84c8cd30176", 918 TemplateLink: "/platformtoolkit/service/ruletemplate/30582260/1?accountId=1-1TJZFB&gid=61726&ck=16.3.1.1", 919 Variables: []RuleVariable{ 920 { 921 Description: "This is a sample Property Manager variable.", 922 Hidden: false, 923 Name: "VAR_NAME", 924 Sensitive: false, 925 Value: "default value", 926 }, 927 }, 928 }, 929 Errors: []RuleError{ 930 { 931 Type: "/papi/v1/errors/validation.required_behavior", 932 Title: "Missing required behavior in default rule", 933 Detail: "In order for this property to work correctly behavior Content Provider Code needs to be present in the default section", 934 Instance: "/papi/v1/properties/prp_173136/versions/3/rules#err_100", 935 BehaviorName: "cpCode", 936 }, 937 }, 938 }, 939 }, 940 "500 Internal Server Error": { 941 params: UpdateRulesRequest{ 942 PropertyID: "propertyID", 943 PropertyVersion: 2, 944 ContractID: "contract", 945 GroupID: "group", 946 DryRun: true, 947 ValidateMode: "fast", 948 ValidateRules: false, 949 Rules: RulesUpdate{ 950 Rules: Rules{ 951 Behaviors: []RuleBehavior{ 952 { 953 Name: "origin", 954 Options: RuleOptionsMap{ 955 "httpPort": float64(80), 956 "enableTrueClientIp": false, 957 "compress": true, 958 "cacheKeyHostname": "ORIGIN_HOSTNAME", 959 "forwardHostHeader": "REQUEST_HOST_HEADER", 960 "hostname": "origin.test.com", 961 "originType": "CUSTOMER", 962 }, 963 }, 964 { 965 Name: "cpCode", 966 Options: RuleOptionsMap{ 967 "value": map[string]interface{}{ 968 "id": float64(12345), 969 "name": "my CP code", 970 }, 971 }, 972 }, 973 }, 974 Children: []Rules{ 975 { 976 Behaviors: []RuleBehavior{ 977 { 978 Name: "gzipResponse", 979 Options: RuleOptionsMap{ 980 "behavior": "ALWAYS", 981 }, 982 }, 983 }, 984 Criteria: []RuleBehavior{ 985 { 986 Locked: false, 987 Name: "contentType", 988 Options: RuleOptionsMap{ 989 "matchOperator": "IS_ONE_OF", 990 "matchWildcard": true, 991 "matchCaseSensitive": false, 992 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 993 }, 994 }, 995 }, 996 Name: "Compress Text Content", 997 }, 998 }, 999 Criteria: []RuleBehavior{}, 1000 Name: "default", 1001 Options: RuleOptions{IsSecure: false}, 1002 CustomOverride: &RuleCustomOverride{ 1003 OverrideID: "cbo_12345", 1004 Name: "mdc", 1005 }, 1006 Variables: []RuleVariable{ 1007 { 1008 Description: "This is a sample Property Manager variable.", 1009 Hidden: false, 1010 Name: "VAR_NAME", 1011 Sensitive: false, 1012 Value: "default value", 1013 }, 1014 }, 1015 }, 1016 }, 1017 }, 1018 responseStatus: http.StatusInternalServerError, 1019 responseBody: ` 1020 { 1021 "type": "internal_error", 1022 "title": "Internal Server Error", 1023 "detail": "Error updating rule tree", 1024 "status": 500 1025 }`, 1026 expectedPath: "/papi/v1/properties/propertyID/versions/2/rules?contractId=contract&dryRun=true&groupId=group&validateMode=fast&validateRules=false", 1027 withError: func(t *testing.T, err error) { 1028 want := &Error{ 1029 Type: "internal_error", 1030 Title: "Internal Server Error", 1031 Detail: "Error updating rule tree", 1032 StatusCode: http.StatusInternalServerError, 1033 } 1034 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1035 }, 1036 }, 1037 "empty property ID": { 1038 params: UpdateRulesRequest{ 1039 PropertyID: "", 1040 PropertyVersion: 2, 1041 ContractID: "contract", 1042 GroupID: "group", 1043 DryRun: true, 1044 ValidateMode: "fast", 1045 ValidateRules: false, 1046 Rules: RulesUpdate{ 1047 Rules: Rules{ 1048 Behaviors: []RuleBehavior{ 1049 { 1050 Name: "origin", 1051 Options: RuleOptionsMap{ 1052 "httpPort": float64(80), 1053 "enableTrueClientIp": false, 1054 "compress": true, 1055 "cacheKeyHostname": "ORIGIN_HOSTNAME", 1056 "forwardHostHeader": "REQUEST_HOST_HEADER", 1057 "hostname": "origin.test.com", 1058 "originType": "CUSTOMER", 1059 }, 1060 }, 1061 { 1062 Name: "cpCode", 1063 Options: RuleOptionsMap{ 1064 "value": map[string]interface{}{ 1065 "id": float64(12345), 1066 "name": "my CP code", 1067 }, 1068 }, 1069 }, 1070 }, 1071 Children: []Rules{ 1072 { 1073 Behaviors: []RuleBehavior{ 1074 { 1075 Name: "gzipResponse", 1076 Options: RuleOptionsMap{ 1077 "behavior": "ALWAYS", 1078 }, 1079 }, 1080 }, 1081 Criteria: []RuleBehavior{ 1082 { 1083 Locked: false, 1084 Name: "contentType", 1085 Options: RuleOptionsMap{ 1086 "matchOperator": "IS_ONE_OF", 1087 "matchWildcard": true, 1088 "matchCaseSensitive": false, 1089 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 1090 }, 1091 }, 1092 }, 1093 Name: "Compress Text Content", 1094 }, 1095 }, 1096 Criteria: []RuleBehavior{}, 1097 Name: "default", 1098 Options: RuleOptions{IsSecure: false}, 1099 CustomOverride: &RuleCustomOverride{ 1100 OverrideID: "cbo_12345", 1101 Name: "mdc", 1102 }, 1103 Variables: []RuleVariable{ 1104 { 1105 Description: "This is a sample Property Manager variable.", 1106 Hidden: false, 1107 Name: "VAR_NAME", 1108 Sensitive: false, 1109 Value: "default value", 1110 }, 1111 }, 1112 }, 1113 }, 1114 }, 1115 withError: func(t *testing.T, err error) { 1116 want := ErrStructValidation 1117 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1118 assert.Contains(t, err.Error(), "PropertyID") 1119 }, 1120 }, 1121 "empty property version": { 1122 params: UpdateRulesRequest{ 1123 PropertyID: "propertyID", 1124 ContractID: "contract", 1125 GroupID: "group", 1126 DryRun: true, 1127 ValidateMode: "fast", 1128 ValidateRules: false, 1129 Rules: RulesUpdate{ 1130 Rules: Rules{ 1131 Behaviors: []RuleBehavior{ 1132 { 1133 Name: "origin", 1134 Options: RuleOptionsMap{ 1135 "httpPort": float64(80), 1136 "enableTrueClientIp": false, 1137 "compress": true, 1138 "cacheKeyHostname": "ORIGIN_HOSTNAME", 1139 "forwardHostHeader": "REQUEST_HOST_HEADER", 1140 "hostname": "origin.test.com", 1141 "originType": "CUSTOMER", 1142 }, 1143 }, 1144 { 1145 Name: "cpCode", 1146 Options: RuleOptionsMap{ 1147 "value": map[string]interface{}{ 1148 "id": float64(12345), 1149 "name": "my CP code", 1150 }, 1151 }, 1152 }, 1153 }, 1154 Children: []Rules{ 1155 { 1156 Behaviors: []RuleBehavior{ 1157 { 1158 Name: "gzipResponse", 1159 Options: RuleOptionsMap{ 1160 "behavior": "ALWAYS", 1161 }, 1162 }, 1163 }, 1164 Criteria: []RuleBehavior{ 1165 { 1166 Locked: false, 1167 Name: "contentType", 1168 Options: RuleOptionsMap{ 1169 "matchOperator": "IS_ONE_OF", 1170 "matchWildcard": true, 1171 "matchCaseSensitive": false, 1172 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 1173 }, 1174 }, 1175 }, 1176 Name: "Compress Text Content", 1177 }, 1178 }, 1179 Criteria: []RuleBehavior{}, 1180 Name: "default", 1181 Options: RuleOptions{IsSecure: false}, 1182 CustomOverride: &RuleCustomOverride{ 1183 OverrideID: "cbo_12345", 1184 Name: "mdc", 1185 }, 1186 Variables: []RuleVariable{ 1187 { 1188 Description: "This is a sample Property Manager variable.", 1189 Hidden: false, 1190 Name: "VAR_NAME", 1191 Sensitive: false, 1192 Value: "default value", 1193 }, 1194 }, 1195 }, 1196 }, 1197 }, 1198 withError: func(t *testing.T, err error) { 1199 want := ErrStructValidation 1200 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1201 assert.Contains(t, err.Error(), "PropertyVersion") 1202 }, 1203 }, 1204 "invalid validation mode": { 1205 params: UpdateRulesRequest{ 1206 PropertyID: "propertyID", 1207 PropertyVersion: 2, 1208 ContractID: "contract", 1209 GroupID: "group", 1210 DryRun: true, 1211 ValidateMode: "test", 1212 ValidateRules: false, 1213 Rules: RulesUpdate{ 1214 Rules: Rules{ 1215 Behaviors: []RuleBehavior{ 1216 { 1217 Name: "origin", 1218 Options: RuleOptionsMap{ 1219 "httpPort": float64(80), 1220 "enableTrueClientIp": false, 1221 "compress": true, 1222 "cacheKeyHostname": "ORIGIN_HOSTNAME", 1223 "forwardHostHeader": "REQUEST_HOST_HEADER", 1224 "hostname": "origin.test.com", 1225 "originType": "CUSTOMER", 1226 }, 1227 }, 1228 { 1229 Name: "cpCode", 1230 Options: RuleOptionsMap{ 1231 "value": map[string]interface{}{ 1232 "id": float64(12345), 1233 "name": "my CP code", 1234 }, 1235 }, 1236 }, 1237 }, 1238 Children: []Rules{ 1239 { 1240 Behaviors: []RuleBehavior{ 1241 { 1242 Name: "gzipResponse", 1243 Options: RuleOptionsMap{ 1244 "behavior": "ALWAYS", 1245 }, 1246 }, 1247 }, 1248 Criteria: []RuleBehavior{ 1249 { 1250 Locked: false, 1251 Name: "contentType", 1252 Options: RuleOptionsMap{ 1253 "matchOperator": "IS_ONE_OF", 1254 "matchWildcard": true, 1255 "matchCaseSensitive": false, 1256 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 1257 }, 1258 }, 1259 }, 1260 Name: "Compress Text Content", 1261 }, 1262 }, 1263 Criteria: []RuleBehavior{}, 1264 Name: "default", 1265 Options: RuleOptions{IsSecure: false}, 1266 CustomOverride: &RuleCustomOverride{ 1267 OverrideID: "cbo_12345", 1268 Name: "mdc", 1269 }, 1270 Variables: []RuleVariable{ 1271 { 1272 Description: "This is a sample Property Manager variable.", 1273 Hidden: false, 1274 Name: "VAR_NAME", 1275 Sensitive: false, 1276 Value: "default value", 1277 }, 1278 }, 1279 }, 1280 }, 1281 }, 1282 withError: func(t *testing.T, err error) { 1283 want := ErrStructValidation 1284 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1285 assert.Contains(t, err.Error(), "ValidateMode") 1286 }, 1287 }, 1288 "empty name": { 1289 params: UpdateRulesRequest{ 1290 PropertyID: "propertyID", 1291 PropertyVersion: 2, 1292 ContractID: "contract", 1293 GroupID: "group", 1294 DryRun: true, 1295 ValidateMode: "fast", 1296 ValidateRules: false, 1297 Rules: RulesUpdate{ 1298 Rules: Rules{ 1299 Behaviors: []RuleBehavior{ 1300 { 1301 Name: "origin", 1302 Options: RuleOptionsMap{ 1303 "httpPort": float64(80), 1304 "enableTrueClientIp": false, 1305 "compress": true, 1306 "cacheKeyHostname": "ORIGIN_HOSTNAME", 1307 "forwardHostHeader": "REQUEST_HOST_HEADER", 1308 "hostname": "origin.test.com", 1309 "originType": "CUSTOMER", 1310 }, 1311 }, 1312 { 1313 Name: "cpCode", 1314 Options: RuleOptionsMap{ 1315 "value": map[string]interface{}{ 1316 "id": float64(12345), 1317 "name": "my CP code", 1318 }, 1319 }, 1320 }, 1321 }, 1322 Children: []Rules{ 1323 { 1324 Behaviors: []RuleBehavior{ 1325 { 1326 Name: "gzipResponse", 1327 Options: RuleOptionsMap{ 1328 "behavior": "ALWAYS", 1329 }, 1330 }, 1331 }, 1332 Criteria: []RuleBehavior{ 1333 { 1334 Locked: false, 1335 Name: "contentType", 1336 Options: RuleOptionsMap{ 1337 "matchOperator": "IS_ONE_OF", 1338 "matchWildcard": true, 1339 "matchCaseSensitive": false, 1340 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 1341 }, 1342 }, 1343 }, 1344 Name: "Compress Text Content", 1345 }, 1346 }, 1347 Criteria: []RuleBehavior{}, 1348 Name: "", 1349 Options: RuleOptions{IsSecure: false}, 1350 CustomOverride: &RuleCustomOverride{ 1351 OverrideID: "cbo_12345", 1352 Name: "mdc", 1353 }, 1354 Variables: []RuleVariable{ 1355 { 1356 Description: "This is a sample Property Manager variable.", 1357 Hidden: false, 1358 Name: "VAR_NAME", 1359 Sensitive: false, 1360 Value: "default value", 1361 }, 1362 }, 1363 }, 1364 }, 1365 }, 1366 withError: func(t *testing.T, err error) { 1367 want := ErrStructValidation 1368 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1369 assert.Contains(t, err.Error(), "Name") 1370 }, 1371 }, 1372 "empty name in custom override": { 1373 params: UpdateRulesRequest{ 1374 PropertyID: "propertyID", 1375 PropertyVersion: 2, 1376 ContractID: "contract", 1377 GroupID: "group", 1378 DryRun: true, 1379 ValidateMode: "test", 1380 ValidateRules: false, 1381 Rules: RulesUpdate{ 1382 Rules: Rules{ 1383 Behaviors: []RuleBehavior{ 1384 { 1385 Name: "origin", 1386 Options: RuleOptionsMap{ 1387 "httpPort": float64(80), 1388 "enableTrueClientIp": false, 1389 "compress": true, 1390 "cacheKeyHostname": "ORIGIN_HOSTNAME", 1391 "forwardHostHeader": "REQUEST_HOST_HEADER", 1392 "hostname": "origin.test.com", 1393 "originType": "CUSTOMER", 1394 }, 1395 }, 1396 { 1397 Name: "cpCode", 1398 Options: RuleOptionsMap{ 1399 "value": map[string]interface{}{ 1400 "id": float64(12345), 1401 "name": "my CP code", 1402 }, 1403 }, 1404 }, 1405 }, 1406 Children: []Rules{ 1407 { 1408 Behaviors: []RuleBehavior{ 1409 { 1410 Name: "gzipResponse", 1411 Options: RuleOptionsMap{ 1412 "behavior": "ALWAYS", 1413 }, 1414 }, 1415 }, 1416 Criteria: []RuleBehavior{ 1417 { 1418 Locked: false, 1419 Name: "contentType", 1420 Options: RuleOptionsMap{ 1421 "matchOperator": "IS_ONE_OF", 1422 "matchWildcard": true, 1423 "matchCaseSensitive": false, 1424 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 1425 }, 1426 }, 1427 }, 1428 Name: "Compress Text Content", 1429 }, 1430 }, 1431 Criteria: []RuleBehavior{}, 1432 Name: "default", 1433 Options: RuleOptions{IsSecure: false}, 1434 CustomOverride: &RuleCustomOverride{ 1435 OverrideID: "cbo_12345", 1436 Name: "", 1437 }, 1438 Variables: []RuleVariable{ 1439 { 1440 Description: "This is a sample Property Manager variable.", 1441 Hidden: false, 1442 Name: "VAR_NAME", 1443 Sensitive: false, 1444 Value: "default value", 1445 }, 1446 }, 1447 }, 1448 }, 1449 }, 1450 withError: func(t *testing.T, err error) { 1451 want := ErrStructValidation 1452 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1453 assert.Contains(t, err.Error(), "Name") 1454 }, 1455 }, 1456 "invalid overrideID in customOverride": { 1457 params: UpdateRulesRequest{ 1458 PropertyID: "propertyID", 1459 PropertyVersion: 2, 1460 ContractID: "contract", 1461 GroupID: "group", 1462 DryRun: true, 1463 ValidateMode: "test", 1464 ValidateRules: false, 1465 Rules: RulesUpdate{ 1466 Rules: Rules{ 1467 Behaviors: []RuleBehavior{ 1468 { 1469 Name: "origin", 1470 Options: RuleOptionsMap{ 1471 "httpPort": float64(80), 1472 "enableTrueClientIp": false, 1473 "compress": true, 1474 "cacheKeyHostname": "ORIGIN_HOSTNAME", 1475 "forwardHostHeader": "REQUEST_HOST_HEADER", 1476 "hostname": "origin.test.com", 1477 "originType": "CUSTOMER", 1478 }, 1479 }, 1480 { 1481 Name: "cpCode", 1482 Options: RuleOptionsMap{ 1483 "value": map[string]interface{}{ 1484 "id": float64(12345), 1485 "name": "my CP code", 1486 }, 1487 }, 1488 }, 1489 }, 1490 Children: []Rules{ 1491 { 1492 Behaviors: []RuleBehavior{ 1493 { 1494 Name: "gzipResponse", 1495 Options: RuleOptionsMap{ 1496 "behavior": "ALWAYS", 1497 }, 1498 }, 1499 }, 1500 Criteria: []RuleBehavior{ 1501 { 1502 Locked: false, 1503 Name: "contentType", 1504 Options: RuleOptionsMap{ 1505 "matchOperator": "IS_ONE_OF", 1506 "matchWildcard": true, 1507 "matchCaseSensitive": false, 1508 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 1509 }, 1510 }, 1511 }, 1512 Name: "Compress Text Content", 1513 }, 1514 }, 1515 Criteria: []RuleBehavior{}, 1516 Name: "default", 1517 Options: RuleOptions{IsSecure: false}, 1518 CustomOverride: &RuleCustomOverride{ 1519 OverrideID: "", 1520 Name: "mdc", 1521 }, 1522 Variables: []RuleVariable{ 1523 { 1524 Description: "This is a sample Property Manager variable.", 1525 Hidden: false, 1526 Name: "VAR_NAME", 1527 Sensitive: false, 1528 Value: "default value", 1529 }, 1530 }, 1531 }, 1532 }, 1533 }, 1534 withError: func(t *testing.T, err error) { 1535 want := ErrStructValidation 1536 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1537 assert.Contains(t, err.Error(), "OverrideID") 1538 }, 1539 }, 1540 "empty name in variable": { 1541 params: UpdateRulesRequest{ 1542 PropertyID: "propertyID", 1543 PropertyVersion: 2, 1544 ContractID: "contract", 1545 GroupID: "group", 1546 DryRun: true, 1547 ValidateMode: "test", 1548 ValidateRules: false, 1549 Rules: RulesUpdate{ 1550 Rules: Rules{ 1551 Behaviors: []RuleBehavior{ 1552 { 1553 Name: "origin", 1554 Options: RuleOptionsMap{ 1555 "httpPort": float64(80), 1556 "enableTrueClientIp": false, 1557 "compress": true, 1558 "cacheKeyHostname": "ORIGIN_HOSTNAME", 1559 "forwardHostHeader": "REQUEST_HOST_HEADER", 1560 "hostname": "origin.test.com", 1561 "originType": "CUSTOMER", 1562 }, 1563 }, 1564 { 1565 Name: "cpCode", 1566 Options: RuleOptionsMap{ 1567 "value": map[string]interface{}{ 1568 "id": float64(12345), 1569 "name": "my CP code", 1570 }, 1571 }, 1572 }, 1573 }, 1574 Children: []Rules{ 1575 { 1576 Behaviors: []RuleBehavior{ 1577 { 1578 Name: "gzipResponse", 1579 Options: RuleOptionsMap{ 1580 "behavior": "ALWAYS", 1581 }, 1582 }, 1583 }, 1584 Criteria: []RuleBehavior{ 1585 { 1586 Locked: false, 1587 Name: "contentType", 1588 Options: RuleOptionsMap{ 1589 "matchOperator": "IS_ONE_OF", 1590 "matchWildcard": true, 1591 "matchCaseSensitive": false, 1592 "values": []interface{}{"text/html*", "text/css*", "application/x-javascript*"}, 1593 }, 1594 }, 1595 }, 1596 Name: "Compress Text Content", 1597 }, 1598 }, 1599 Criteria: []RuleBehavior{}, 1600 Name: "default", 1601 Options: RuleOptions{IsSecure: false}, 1602 CustomOverride: &RuleCustomOverride{ 1603 OverrideID: "cbo_12345", 1604 Name: "mdc", 1605 }, 1606 Variables: []RuleVariable{ 1607 { 1608 Description: "This is a sample Property Manager variable.", 1609 Hidden: false, 1610 Name: "", 1611 Sensitive: false, 1612 Value: "default value", 1613 }, 1614 }, 1615 }, 1616 }, 1617 }, 1618 withError: func(t *testing.T, err error) { 1619 want := ErrStructValidation 1620 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1621 assert.Contains(t, err.Error(), "Name") 1622 }, 1623 }, 1624 } 1625 1626 for name, test := range tests { 1627 t.Run(name, func(t *testing.T) { 1628 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1629 assert.Equal(t, test.expectedPath, r.URL.String()) 1630 assert.Equal(t, http.MethodPut, r.Method) 1631 w.WriteHeader(test.responseStatus) 1632 _, err := w.Write([]byte(test.responseBody)) 1633 assert.NoError(t, err) 1634 })) 1635 client := mockAPIClient(t, mockServer) 1636 result, err := client.UpdateRuleTree(context.Background(), test.params) 1637 if test.withError != nil { 1638 test.withError(t, err) 1639 return 1640 } 1641 require.NoError(t, err) 1642 assert.Equal(t, test.expectedResponse, result) 1643 }) 1644 } 1645 }