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