github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/cloudlets/v3/policy_version_test.go (about)

     1  package v3
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools"
    13  	"github.com/stretchr/testify/require"
    14  	"github.com/tj/assert"
    15  )
    16  
    17  func TestListPolicyVersions(t *testing.T) {
    18  	t.Parallel()
    19  	tests := map[string]struct {
    20  		request          ListPolicyVersionsRequest
    21  		responseStatus   int
    22  		responseBody     string
    23  		expectedPath     string
    24  		expectedResponse *ListPolicyVersions
    25  		withError        func(*testing.T, error)
    26  	}{
    27  		"200 OK": {
    28  			request: ListPolicyVersionsRequest{
    29  				PolicyID: 670790,
    30  			},
    31  			responseStatus: http.StatusOK,
    32  			responseBody: `
    33  {
    34  	"content": [
    35  		{
    36  			"createdBy": "jsmith",
    37  			"createdDate": "2023-10-19T08:50:47.350Z",
    38  			"description": null,
    39  			"id": 6551184,
    40  			"immutable": false,
    41  			"links": [],
    42  			"modifiedBy": "jsmith",
    43  			"modifiedDate": "2023-10-19T08:50:47.350Z",
    44  			"policyId": 670790,
    45  			"version": 3
    46  		},
    47  		{
    48  			"createdBy": "jsmith",
    49  			"createdDate": "2023-10-19T08:50:46.225Z",
    50  			"description": null,
    51  			"id": 6551183,
    52  			"immutable": false,
    53  			"links": [],
    54  			"modifiedBy": "jsmith",
    55  			"modifiedDate": "2023-10-19T08:50:46.225Z",
    56  			"policyId": 670790,
    57  			"version": 2
    58  		},
    59  		{
    60  			"createdBy": "jsmith",
    61  			"createdDate": "2023-10-19T08:44:34.398Z",
    62  			"description": null,
    63  			"id": 6551182,
    64  			"immutable": false,
    65  			"links": [],
    66  			"modifiedBy": "jsmith",
    67  			"modifiedDate": "2023-10-19T08:44:34.398Z",
    68  			"policyId": 670790,
    69  			"version": 1
    70  		}
    71  	],
    72  	"links": [
    73  		{
    74  			"href": "/cloudlets/v3/policies/670790/versions?page=0&size=1000",
    75  			"rel": "self"
    76  		}
    77  	],
    78  	"page": {
    79  		"number": 0,
    80  		"size": 1000,
    81  		"totalElements": 3,
    82  		"totalPages": 1
    83  	}
    84  }`,
    85  			expectedPath: "/cloudlets/v3/policies/670790/versions?page=0",
    86  			expectedResponse: &ListPolicyVersions{
    87  				PolicyVersions: []ListPolicyVersionsItem{
    88  					{
    89  						CreatedBy:     "jsmith",
    90  						CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
    91  						Description:   nil,
    92  						ID:            6551184,
    93  						Immutable:     false,
    94  						Links:         []Link{},
    95  						ModifiedBy:    "jsmith",
    96  						ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
    97  						PolicyID:      670790,
    98  						PolicyVersion: 3,
    99  					},
   100  					{
   101  						CreatedBy:     "jsmith",
   102  						CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:46.225Z"),
   103  						Description:   nil,
   104  						ID:            6551183,
   105  						Immutable:     false,
   106  						Links:         []Link{},
   107  						ModifiedBy:    "jsmith",
   108  						ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:46.225Z"),
   109  						PolicyID:      670790,
   110  						PolicyVersion: 2,
   111  					},
   112  					{
   113  						CreatedBy:     "jsmith",
   114  						CreatedDate:   *newTimeFromString(t, "2023-10-19T08:44:34.398Z"),
   115  						Description:   nil,
   116  						ID:            6551182,
   117  						Immutable:     false,
   118  						Links:         []Link{},
   119  						ModifiedBy:    "jsmith",
   120  						ModifiedDate:  newTimeFromString(t, "2023-10-19T08:44:34.398Z"),
   121  						PolicyID:      670790,
   122  						PolicyVersion: 1,
   123  					},
   124  				},
   125  				Links: []Link{
   126  					{
   127  						Href: "/cloudlets/v3/policies/670790/versions?page=0&size=1000",
   128  						Rel:  "self",
   129  					},
   130  				},
   131  				Page: Page{
   132  					Number:        0,
   133  					Size:          1000,
   134  					TotalElements: 3,
   135  					TotalPages:    1,
   136  				},
   137  			},
   138  		},
   139  		"200 OK with params": {
   140  			request: ListPolicyVersionsRequest{
   141  				PolicyID: 670790,
   142  				Page:     4,
   143  				Size:     10,
   144  			},
   145  			responseStatus: http.StatusOK,
   146  			responseBody: `
   147  {
   148  	"content": [],
   149  	"links": [
   150  		{
   151  			"href": "/cloudlets/v3/policies/670790/versions?page=0&size=10",
   152  			"rel": "first"
   153  		},
   154  		{
   155  			"href": "/cloudlets/v3/policies/670790/versions?page=3&size=10",
   156  			"rel": "prev"
   157  		},
   158  		{
   159  			"href": "/cloudlets/v3/policies/670790/versions?page=4&size=10",
   160  			"rel": "self"
   161  		},
   162  		{
   163  			"href": "/cloudlets/v3/policies/670790/versions?page=0&size=10",
   164  			"rel": "last"
   165  		}
   166  	],
   167  	"page": {
   168  		"number": 4,
   169  		"size": 10,
   170  		"totalElements": 3,
   171  		"totalPages": 1
   172  	}
   173  }`,
   174  			expectedPath: "/cloudlets/v3/policies/670790/versions?page=4&size=10",
   175  			expectedResponse: &ListPolicyVersions{
   176  				PolicyVersions: []ListPolicyVersionsItem{},
   177  				Links: []Link{
   178  					{
   179  						Href: "/cloudlets/v3/policies/670790/versions?page=0&size=10",
   180  						Rel:  "first",
   181  					},
   182  					{
   183  						Href: "/cloudlets/v3/policies/670790/versions?page=3&size=10",
   184  						Rel:  "prev",
   185  					},
   186  					{
   187  						Href: "/cloudlets/v3/policies/670790/versions?page=4&size=10",
   188  						Rel:  "self",
   189  					},
   190  					{
   191  						Href: "/cloudlets/v3/policies/670790/versions?page=0&size=10",
   192  						Rel:  "last",
   193  					},
   194  				},
   195  				Page: Page{
   196  					Number:        4,
   197  					Size:          10,
   198  					TotalElements: 3,
   199  					TotalPages:    1,
   200  				},
   201  			},
   202  		},
   203  		"500 internal server error": {
   204  			request: ListPolicyVersionsRequest{
   205  				PolicyID: 284823,
   206  			},
   207  			responseStatus: http.StatusInternalServerError,
   208  			responseBody: `
   209  		{
   210  			"type": "internal_error",
   211  		   "title": "Internal Server Error",
   212  		   "status": 500
   213  		}`,
   214  			expectedPath: "/cloudlets/v3/policies/284823/versions?page=0",
   215  			withError: func(t *testing.T, err error) {
   216  				want := &Error{
   217  					Type:   "internal_error",
   218  					Title:  "Internal Server Error",
   219  					Status: http.StatusInternalServerError,
   220  				}
   221  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   222  			},
   223  		},
   224  	}
   225  
   226  	for name, test := range tests {
   227  		name, test := name, test
   228  		t.Run(name, func(t *testing.T) {
   229  			t.Parallel()
   230  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   231  				assert.Equal(t, test.expectedPath, r.URL.String())
   232  				assert.Equal(t, http.MethodGet, r.Method)
   233  				w.WriteHeader(test.responseStatus)
   234  				_, err := w.Write([]byte(test.responseBody))
   235  				assert.NoError(t, err)
   236  			}))
   237  			client := mockAPIClient(t, mockServer)
   238  			result, err := client.ListPolicyVersions(context.Background(), test.request)
   239  			if test.withError != nil {
   240  				test.withError(t, err)
   241  				return
   242  			}
   243  			require.NoError(t, err)
   244  			assert.Equal(t, test.expectedResponse, result)
   245  		})
   246  	}
   247  }
   248  
   249  func TestGetPolicyVersion(t *testing.T) {
   250  	t.Parallel()
   251  	tests := map[string]struct {
   252  		request          GetPolicyVersionRequest
   253  		responseStatus   int
   254  		responseBody     string
   255  		expectedPath     string
   256  		expectedResponse *PolicyVersion
   257  		withError        func(*testing.T, error)
   258  	}{
   259  		"200 OK": {
   260  			request: GetPolicyVersionRequest{
   261  				PolicyID:      670798,
   262  				PolicyVersion: 2,
   263  			},
   264  			responseStatus: http.StatusOK,
   265  			responseBody: `
   266  		{
   267  			"createdBy": "jsmith",
   268  			"createdDate": "2023-10-19T09:46:57.395Z",
   269  			"description": "test description",
   270  			"id": 6551191,
   271  			"immutable": false,
   272  			"matchRules": [],
   273  			"matchRulesWarnings": [],
   274  			"modifiedBy": "jsmith",
   275  			"modifiedDate": "2023-10-19T09:46:57.395Z",
   276  			"policyId": 670798,
   277  			"version": 2
   278  		}`,
   279  			expectedPath: "/cloudlets/v3/policies/670798/versions/2",
   280  			expectedResponse: &PolicyVersion{
   281  				CreatedBy:          "jsmith",
   282  				CreatedDate:        *newTimeFromString(t, "2023-10-19T09:46:57.395Z"),
   283  				Description:        tools.StringPtr("test description"),
   284  				ID:                 6551191,
   285  				MatchRules:         nil,
   286  				MatchRulesWarnings: []MatchRulesWarning{},
   287  				ModifiedBy:         "jsmith",
   288  				ModifiedDate:       newTimeFromString(t, "2023-10-19T09:46:57.395Z"),
   289  				PolicyID:           670798,
   290  				PolicyVersion:      2,
   291  			},
   292  		},
   293  		"200 OK, ER with disabled rule": {
   294  			request: GetPolicyVersionRequest{
   295  				PolicyID:      276858,
   296  				PolicyVersion: 1,
   297  			},
   298  			responseStatus: http.StatusOK,
   299  			responseBody: `{
   300  	"createdBy": "jsmith",
   301  	"createdDate": "2023-10-19T10:45:30.619Z",
   302  	"description": null,
   303  	"id": 6551242,
   304  	"immutable": false,
   305  	"matchRules": [
   306  		{
   307  			"type": "erMatchRule",
   308  			"id": 0,
   309  			"name": "er_rule",
   310  			"start": 0,
   311  			"end": 0,
   312  			"matchURL": null,
   313  			"disabled": true,
   314  			"matches": [],
   315  			"akaRuleId": "6d3bbc891fc0d8ce",
   316  			"statusCode": 301,
   317  			"redirectURL": "/path",
   318  			"useIncomingQueryString": false
   319  		}
   320  	],
   321  	"matchRulesWarnings": [],
   322  	"modifiedBy": "jsmith",
   323  	"modifiedDate": "2023-10-19T10:45:30.619Z",
   324  	"policyId": 276858,
   325  	"version": 1
   326  }`,
   327  			expectedPath: "/cloudlets/v3/policies/276858/versions/1",
   328  			expectedResponse: &PolicyVersion{
   329  				CreatedDate:   *newTimeFromString(t, "2023-10-19T10:45:30.619Z"),
   330  				CreatedBy:     "jsmith",
   331  				Description:   nil,
   332  				PolicyID:      276858,
   333  				PolicyVersion: 1,
   334  				ID:            6551242,
   335  				MatchRules: MatchRules{
   336  					&MatchRuleER{
   337  						Type:                   "erMatchRule",
   338  						End:                    0,
   339  						ID:                     0,
   340  						MatchURL:               "",
   341  						Name:                   "er_rule",
   342  						Matches:                []MatchCriteriaER{},
   343  						RedirectURL:            "/path",
   344  						Start:                  0,
   345  						StatusCode:             301,
   346  						UseIncomingQueryString: false,
   347  						Disabled:               true,
   348  					},
   349  				},
   350  				MatchRulesWarnings: []MatchRulesWarning{},
   351  				ModifiedBy:         "jsmith",
   352  				ModifiedDate:       newTimeFromString(t, "2023-10-19T10:45:30.619Z"),
   353  			},
   354  		},
   355  		"200 OK, AS rule with disabled=false": {
   356  			request: GetPolicyVersionRequest{
   357  				PolicyID:      355557,
   358  				PolicyVersion: 2,
   359  			},
   360  			responseStatus: http.StatusOK,
   361  			responseBody: `{
   362  		    "createdDate": "2023-10-19T09:46:57.395Z",
   363  		    "createdBy": "jsmith",
   364  		    "description": "Initial version",
   365  		    "modifiedBy": "jsmith",
   366  		    "modifiedDate": "2023-10-19T10:45:30.619Z",
   367  		    "matchRules": [
   368  		        {
   369  		            "type": "asMatchRule",
   370  		            "akaRuleId": "f58014ee0cc17ce",
   371  		            "end": 0,
   372  		            "forwardSettings": {
   373  		                "originId": "originremote2",
   374  		                "pathAndQS": "/sales/Q1/",
   375  		                "useIncomingQueryString": true
   376  		            },
   377  		            "id": 0,
   378  		            "matches": [
   379  		                {
   380  		                    "caseSensitive": false,
   381  		                    "matchOperator": "equals",
   382  		                    "matchType": "range",
   383  		                    "negate": false,
   384  		                    "objectMatchValue": {
   385  		                        "type": "range",
   386  		                        "value": [
   387  		                            1,
   388  		                            25
   389  		                        ]
   390  		                    }
   391  		                }
   392  		            ],
   393  		            "name": "Q1Sales",
   394  		            "start": 0
   395  		        }
   396  		    ],
   397  		    "policyId": 355557,
   398  		    "version": 2
   399  		}`,
   400  			expectedPath: "/cloudlets/v3/policies/355557/versions/2",
   401  			expectedResponse: &PolicyVersion{
   402  				CreatedBy:   "jsmith",
   403  				CreatedDate: *newTimeFromString(t, "2023-10-19T09:46:57.395Z"),
   404  				Description: tools.StringPtr("Initial version"),
   405  				MatchRules: MatchRules{
   406  					&MatchRuleAS{
   407  						Type: "asMatchRule",
   408  						End:  0,
   409  						ForwardSettings: ForwardSettingsAS{
   410  							OriginID:               "originremote2",
   411  							PathAndQS:              "/sales/Q1/",
   412  							UseIncomingQueryString: true,
   413  						},
   414  						ID: 0,
   415  						Matches: []MatchCriteriaAS{
   416  							{
   417  								CaseSensitive: false,
   418  								MatchOperator: "equals",
   419  								MatchType:     "range",
   420  								Negate:        false,
   421  								ObjectMatchValue: &ObjectMatchValueRange{
   422  									Type: "range",
   423  									Value: []int64{
   424  										1, 25},
   425  								},
   426  							},
   427  						},
   428  						Name:  "Q1Sales",
   429  						Start: 0,
   430  					},
   431  				},
   432  				ModifiedBy:    "jsmith",
   433  				ModifiedDate:  newTimeFromString(t, "2023-10-19T10:45:30.619Z"),
   434  				PolicyID:      355557,
   435  				PolicyVersion: 2,
   436  			},
   437  		},
   438  		"200 OK, PR rule": {
   439  			request: GetPolicyVersionRequest{
   440  				PolicyID:      276858,
   441  				PolicyVersion: 6,
   442  			},
   443  			responseStatus: http.StatusOK,
   444  			responseBody: `{
   445  		    "createdDate": "2023-10-19T09:46:57.395Z",
   446  		    "createdBy": "jsmith",
   447  		    "description": null,
   448  		    "modifiedBy": "jsmith",
   449  		    "modifiedDate": "2023-10-19T09:46:57.395Z",
   450  		    "matchRules": [
   451  		        {
   452  		            "type": "cdMatchRule",
   453  		            "akaRuleId": "b151ca68e51f5a61",
   454  		            "end": 0,
   455  		            "forwardSettings": {
   456  		                "originId": "fr_test_krk_dc2",
   457  		                "percent": 11
   458  		            },
   459  		            "id": 0,
   460  		            "matches": [
   461  		                {
   462  		                    "caseSensitive": false,
   463  		                    "matchOperator": "equals",
   464  		                    "matchType": "method",
   465  		                    "negate": false,
   466  		                    "objectMatchValue": {
   467  		                        "type": "simple",
   468  		                        "value": [
   469  		                            "GET"
   470  		                        ]
   471  		                    }
   472  		                }
   473  		            ],
   474  		            "name": "rule 1",
   475  		            "start": 0
   476  		        }
   477  		    ],
   478  		    "policyId": 325401,
   479  		    "version": 3
   480  		}`,
   481  			expectedPath: "/cloudlets/v3/policies/276858/versions/6",
   482  			expectedResponse: &PolicyVersion{
   483  				CreatedBy:    "jsmith",
   484  				CreatedDate:  *newTimeFromString(t, "2023-10-19T09:46:57.395Z"),
   485  				Description:  nil,
   486  				ModifiedBy:   "jsmith",
   487  				ModifiedDate: newTimeFromString(t, "2023-10-19T09:46:57.395Z"),
   488  				MatchRules: MatchRules{
   489  					&MatchRulePR{
   490  						Type: "cdMatchRule",
   491  						End:  0,
   492  						ForwardSettings: ForwardSettingsPR{
   493  							OriginID: "fr_test_krk_dc2",
   494  							Percent:  11,
   495  						},
   496  						ID: 0,
   497  						Matches: []MatchCriteriaPR{
   498  							{
   499  								CaseSensitive: false,
   500  								MatchOperator: "equals",
   501  								MatchType:     "method",
   502  								Negate:        false,
   503  								ObjectMatchValue: &ObjectMatchValueSimple{
   504  									Type: "simple",
   505  									Value: []string{
   506  										"GET"},
   507  								},
   508  							},
   509  						},
   510  						Name:  "rule 1",
   511  						Start: 0,
   512  					},
   513  				},
   514  				PolicyID:      325401,
   515  				PolicyVersion: 3,
   516  			},
   517  		},
   518  		"200 OK, ER rule with disabled=false": {
   519  			request: GetPolicyVersionRequest{
   520  				PolicyID:      276858,
   521  				PolicyVersion: 6,
   522  			},
   523  			responseStatus: http.StatusOK,
   524  			responseBody: `{
   525  		    "createdDate": "2023-10-19T09:46:57.395Z",
   526  		    "createdBy": "jsmith",
   527  		    "description": null,
   528  		    "modifiedBy": "jsmith",
   529  		    "modifiedDate": "2023-10-19T09:46:57.395Z",
   530  		    "matchRules": [
   531  		        {
   532  		            "type": "erMatchRule",
   533  		            "end": 0,
   534  		            "id": 0,
   535  		            "matchURL": null,
   536  		            "name": "rul3",
   537  		            "redirectURL": "/abc/sss",
   538  		            "start": 0,
   539  		            "statusCode": 307,
   540  		            "useIncomingQueryString": false,
   541  		            "useIncomingSchemeAndHost": true,
   542  		            "useRelativeUrl": "copy_scheme_hostname"
   543  		        }
   544  		    ],
   545  		    "policyId": 276858,
   546  		    "version": 6
   547  		}`,
   548  			expectedPath: "/cloudlets/v3/policies/276858/versions/6",
   549  			expectedResponse: &PolicyVersion{
   550  				CreatedDate:   *newTimeFromString(t, "2023-10-19T09:46:57.395Z"),
   551  				CreatedBy:     "jsmith",
   552  				Description:   nil,
   553  				ModifiedBy:    "jsmith",
   554  				ModifiedDate:  newTimeFromString(t, "2023-10-19T09:46:57.395Z"),
   555  				PolicyID:      276858,
   556  				PolicyVersion: 6,
   557  				MatchRules: MatchRules{
   558  					&MatchRuleER{
   559  						Type:                     "erMatchRule",
   560  						End:                      0,
   561  						ID:                       0,
   562  						MatchURL:                 "",
   563  						Name:                     "rul3",
   564  						RedirectURL:              "/abc/sss",
   565  						Start:                    0,
   566  						StatusCode:               307,
   567  						UseIncomingQueryString:   false,
   568  						UseIncomingSchemeAndHost: true,
   569  						UseRelativeURL:           "copy_scheme_hostname",
   570  						Disabled:                 false,
   571  					},
   572  				},
   573  			},
   574  		},
   575  		"200 OK, FR with disabled rule": {
   576  			request: GetPolicyVersionRequest{
   577  				PolicyID:      276858,
   578  				PolicyVersion: 6,
   579  			},
   580  			responseStatus: http.StatusOK,
   581  			responseBody: `{
   582  		    "createdDate": "2023-10-19T08:50:47.350Z",
   583  		    "createdBy": "jsmith",
   584  		    "description": null,
   585  		    "modifiedBy": "jsmith",
   586  		    "modifiedDate": "2023-10-19T08:50:47.350Z",
   587  		    "matchRules": [{
   588  		        "type": "frMatchRule",
   589  		        "disabled": true,
   590  		        "end": 0,
   591  		        "id": 0,
   592  		        "matchURL": null,
   593  		        "forwardSettings": {
   594  		            "pathAndQS": "/test_images/simpleimg.jpg",
   595  		            "useIncomingQueryString": true,
   596  					"originId": "1234"
   597  				},
   598  		        "name": "rule 1",
   599  		        "start": 0
   600  		    }],
   601  		    "policyId": 276858,
   602  		    "version": 6
   603  		}`,
   604  			expectedPath: "/cloudlets/v3/policies/276858/versions/6",
   605  			expectedResponse: &PolicyVersion{
   606  				CreatedBy:     "jsmith",
   607  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
   608  				Description:   nil,
   609  				PolicyID:      276858,
   610  				PolicyVersion: 6,
   611  				ModifiedBy:    "jsmith",
   612  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
   613  				MatchRules: MatchRules{
   614  					&MatchRuleFR{
   615  						Name:     "rule 1",
   616  						Type:     "frMatchRule",
   617  						Start:    0,
   618  						End:      0,
   619  						ID:       0,
   620  						MatchURL: "",
   621  						ForwardSettings: ForwardSettingsFR{
   622  							PathAndQS:              "/test_images/simpleimg.jpg",
   623  							UseIncomingQueryString: true,
   624  							OriginID:               "1234",
   625  						},
   626  						Disabled: true,
   627  					},
   628  				},
   629  			},
   630  		},
   631  		"500 internal server error": {
   632  			request: GetPolicyVersionRequest{
   633  				PolicyID: 1,
   634  			},
   635  			responseStatus: http.StatusInternalServerError,
   636  			responseBody: `
   637  		{
   638  			"type": "internal_error",
   639  		   "title": "Internal Server Error",
   640  		   "status": 500
   641  		}`,
   642  			expectedPath: "/cloudlets/v3/policies/1/versions/0",
   643  			withError: func(t *testing.T, err error) {
   644  				want := &Error{
   645  					Type:   "internal_error",
   646  					Title:  "Internal Server Error",
   647  					Status: http.StatusInternalServerError,
   648  				}
   649  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   650  			},
   651  		},
   652  	}
   653  
   654  	for name, test := range tests {
   655  		name, test := name, test
   656  		t.Run(name, func(t *testing.T) {
   657  			t.Parallel()
   658  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   659  				assert.Equal(t, test.expectedPath, r.URL.String())
   660  				assert.Equal(t, http.MethodGet, r.Method)
   661  				w.WriteHeader(test.responseStatus)
   662  				_, err := w.Write([]byte(test.responseBody))
   663  				assert.NoError(t, err)
   664  			}))
   665  			client := mockAPIClient(t, mockServer)
   666  			result, err := client.GetPolicyVersion(context.Background(), test.request)
   667  			if test.withError != nil {
   668  				test.withError(t, err)
   669  				return
   670  			}
   671  			require.NoError(t, err)
   672  			assert.Equal(t, test.expectedResponse, result)
   673  		})
   674  	}
   675  }
   676  
   677  func TestCreatePolicyVersion(t *testing.T) {
   678  	t.Parallel()
   679  	tests := map[string]struct {
   680  		request          CreatePolicyVersionRequest
   681  		requestBody      string
   682  		responseStatus   int
   683  		responseBody     string
   684  		expectedPath     string
   685  		expectedResponse *PolicyVersion
   686  		withError        error
   687  	}{
   688  		"201 created, simple ER": {
   689  			request: CreatePolicyVersionRequest{
   690  				CreatePolicyVersion: CreatePolicyVersion{
   691  					Description: tools.StringPtr("Description for the policy"),
   692  				},
   693  				PolicyID: 276858,
   694  			},
   695  			responseStatus: http.StatusCreated,
   696  			responseBody: `
   697  {
   698      "createdDate": "2023-10-19T08:50:47.350Z",
   699      "createdBy": "jsmith",
   700      "description": "Description for the policy",
   701      "modifiedBy": "jsmith",
   702      "modifiedDate": "2023-10-19T08:50:47.350Z",
   703      "matchRules": null,
   704      "policyId": 276858,
   705      "version": 2
   706  }`,
   707  			expectedPath: "/cloudlets/v3/policies/276858/versions",
   708  			expectedResponse: &PolicyVersion{
   709  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
   710  				CreatedBy:     "jsmith",
   711  				Description:   tools.StringPtr("Description for the policy"),
   712  				ModifiedBy:    "jsmith",
   713  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
   714  				MatchRules:    nil,
   715  				PolicyID:      276858,
   716  				PolicyVersion: 2,
   717  			},
   718  		},
   719  		"201 created, complex AS": {
   720  			request: CreatePolicyVersionRequest{
   721  				CreatePolicyVersion: CreatePolicyVersion{
   722  					MatchRules: MatchRules{
   723  						&MatchRuleAS{
   724  							Start: 0,
   725  							End:   0,
   726  							Type:  "asMatchRule",
   727  							Name:  "Q1Sales",
   728  							ID:    0,
   729  							ForwardSettings: ForwardSettingsAS{
   730  								OriginID:               "originremote2",
   731  								PathAndQS:              "/sales/Q1/",
   732  								UseIncomingQueryString: true,
   733  							},
   734  							Matches: []MatchCriteriaAS{
   735  								{
   736  									CaseSensitive: false,
   737  									MatchOperator: "equals",
   738  									MatchType:     "range",
   739  									Negate:        false,
   740  									ObjectMatchValue: &ObjectMatchValueRange{
   741  										Type:  "range",
   742  										Value: []int64{1, 25},
   743  									},
   744  								},
   745  								{
   746  									CaseSensitive: false,
   747  									MatchOperator: "equals",
   748  									MatchType:     "method",
   749  									Negate:        false,
   750  									ObjectMatchValue: &ObjectMatchValueSimple{
   751  										Type:  "simple",
   752  										Value: []string{"GET"},
   753  									},
   754  								},
   755  								{
   756  									MatchOperator: "equals",
   757  									MatchType:     "header",
   758  									Negate:        false,
   759  									ObjectMatchValue: &ObjectMatchValueObject{
   760  										Type: "object",
   761  										Name: "AS",
   762  										Options: &Options{
   763  											Value: []string{
   764  												"text/html*",
   765  												"text/css*",
   766  												"application/x-javascript*",
   767  											},
   768  											ValueHasWildcard: true,
   769  										},
   770  									},
   771  								},
   772  							},
   773  						},
   774  					},
   775  				},
   776  				PolicyID: 355557,
   777  			},
   778  			responseStatus: http.StatusCreated,
   779  			responseBody: `{
   780      "createdDate": "2023-10-19T08:50:47.350Z",
   781      "createdBy": "jsmith",
   782      "description": "Initial version",
   783      "modifiedBy": "jsmith",
   784      "modifiedDate": "2023-10-19T08:50:47.350Z",
   785      "matchRules": [
   786          {
   787              "type": "asMatchRule",
   788              "akaRuleId": "f58014ee0cc17ce",
   789              "end": 0,
   790              "forwardSettings": {
   791                  "originId": "originremote2",
   792                  "pathAndQS": "/sales/Q1/",
   793                  "useIncomingQueryString": true
   794              },
   795              "id": 0,
   796              "matches": [
   797  				{
   798                      "caseSensitive": false,
   799                      "matchOperator": "equals",
   800                      "matchType": "range",
   801                      "negate": false,
   802                      "objectMatchValue": {
   803                          "type": "range",
   804                          "value": [
   805                              1,
   806                              25
   807                          ]
   808                      }
   809                  },
   810  				{
   811                      "caseSensitive": false,
   812                      "matchOperator": "equals",
   813                      "matchType": "method",
   814                      "negate": false,
   815                      "objectMatchValue": {
   816                          "type": "simple",
   817                          "value": [
   818                              "GET"
   819                          ]
   820                      }
   821                  },
   822  				{
   823                      "matchOperator": "equals",
   824                      "matchType": "header",
   825                      "negate": false,
   826  					"objectMatchValue": {
   827  						"type": "object",
   828  						"name": "AS",
   829  						"options": {
   830  							"value": [
   831  								"text/html*",
   832                                  "text/css*",
   833                                  "application/x-javascript*"
   834  							],
   835  							"valueHasWildcard": true
   836  						}
   837  					}
   838                  }
   839              ],
   840              "name": "Q1Sales",
   841              "start": 0
   842          }
   843      ],
   844      "policyId": 355557,
   845      "version": 2
   846  }`,
   847  			expectedPath: "/cloudlets/v3/policies/355557/versions",
   848  			expectedResponse: &PolicyVersion{
   849  				CreatedDate:  *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
   850  				CreatedBy:    "jsmith",
   851  				Description:  tools.StringPtr("Initial version"),
   852  				ModifiedBy:   "jsmith",
   853  				ModifiedDate: newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
   854  				MatchRules: MatchRules{
   855  					&MatchRuleAS{
   856  						Type: "asMatchRule",
   857  						End:  0,
   858  						ForwardSettings: ForwardSettingsAS{
   859  							OriginID:               "originremote2",
   860  							PathAndQS:              "/sales/Q1/",
   861  							UseIncomingQueryString: true,
   862  						},
   863  						ID: 0,
   864  						Matches: []MatchCriteriaAS{
   865  							{
   866  								CaseSensitive: false,
   867  								MatchOperator: "equals",
   868  								MatchType:     "range",
   869  								Negate:        false,
   870  								ObjectMatchValue: &ObjectMatchValueRange{
   871  									Type: "range",
   872  									Value: []int64{
   873  										1, 25},
   874  								},
   875  							},
   876  							{
   877  								CaseSensitive: false,
   878  								MatchOperator: "equals",
   879  								MatchType:     "method",
   880  								Negate:        false,
   881  								ObjectMatchValue: &ObjectMatchValueSimple{
   882  									Type:  "simple",
   883  									Value: []string{"GET"},
   884  								},
   885  							},
   886  							{
   887  								MatchOperator: "equals",
   888  								MatchType:     "header",
   889  								Negate:        false,
   890  								ObjectMatchValue: &ObjectMatchValueObject{
   891  									Type: "object",
   892  									Name: "AS",
   893  									Options: &Options{
   894  										Value: []string{
   895  											"text/html*",
   896  											"text/css*",
   897  											"application/x-javascript*",
   898  										},
   899  										ValueHasWildcard: true,
   900  									},
   901  								},
   902  							},
   903  						},
   904  						Name:  "Q1Sales",
   905  						Start: 0,
   906  					},
   907  				},
   908  				PolicyID:      355557,
   909  				PolicyVersion: 2,
   910  			},
   911  		},
   912  		"201 created, complex PR": {
   913  			request: CreatePolicyVersionRequest{
   914  				CreatePolicyVersion: CreatePolicyVersion{
   915  					MatchRules: MatchRules{
   916  						&MatchRulePR{
   917  							Start: 0,
   918  							End:   0,
   919  							Type:  "cdMatchRule",
   920  							Name:  "rul3",
   921  							ID:    0,
   922  							ForwardSettings: ForwardSettingsPR{
   923  								OriginID: "some_origin",
   924  								Percent:  10,
   925  							},
   926  							Matches: []MatchCriteriaPR{
   927  								{
   928  									MatchType:     "hostname",
   929  									MatchValue:    "3333.dom",
   930  									MatchOperator: "equals",
   931  									CaseSensitive: true,
   932  									Negate:        false,
   933  								},
   934  								{
   935  									MatchType:     "cookie",
   936  									MatchValue:    "cookie=cookievalue",
   937  									MatchOperator: "equals",
   938  									Negate:        false,
   939  									CaseSensitive: false,
   940  								},
   941  								{
   942  									MatchType:     "extension",
   943  									MatchValue:    "txt",
   944  									MatchOperator: "equals",
   945  									Negate:        false,
   946  									CaseSensitive: false,
   947  								},
   948  							},
   949  						},
   950  						&MatchRulePR{
   951  							Start:    0,
   952  							End:      0,
   953  							Type:     "cdMatchRule",
   954  							Name:     "rule 2",
   955  							MatchURL: "ddd.aaa",
   956  							ID:       0,
   957  							ForwardSettings: ForwardSettingsPR{
   958  								OriginID: "some_origin",
   959  								Percent:  10,
   960  							},
   961  						},
   962  						&MatchRulePR{
   963  							Type:     "cdMatchRule",
   964  							ID:       0,
   965  							Name:     "r1",
   966  							Start:    0,
   967  							End:      0,
   968  							MatchURL: "abc.com",
   969  							ForwardSettings: ForwardSettingsPR{
   970  								OriginID: "some_origin",
   971  								Percent:  10,
   972  							},
   973  						},
   974  					},
   975  				},
   976  				PolicyID: 276858,
   977  			},
   978  			responseStatus: http.StatusCreated,
   979  			responseBody: `{
   980      "createdDate": "2023-10-19T08:50:47.350Z",
   981      "createdBy": "jsmith",
   982      "description": null,
   983      "modifiedBy": "jsmith",
   984      "modifiedDate": "2023-10-19T08:50:47.350Z",
   985      "matchRules": [
   986          {
   987              "type": "cdMatchRule",
   988              "end": 0,
   989              "id": 0,
   990              "matchURL": null,
   991              "matches": [
   992                  {
   993                      "caseSensitive": true,
   994                      "matchOperator": "equals",
   995                      "matchType": "hostname",
   996                      "matchValue": "3333.dom",
   997                      "negate": false
   998                  },
   999                  {
  1000                      "caseSensitive": false,
  1001                      "matchOperator": "equals",
  1002                      "matchType": "cookie",
  1003                      "matchValue": "cookie=cookievalue",
  1004                      "negate": false
  1005                  },
  1006                  {
  1007                      "caseSensitive": false,
  1008                      "matchOperator": "equals",
  1009                      "matchType": "extension",
  1010                      "matchValue": "txt",
  1011                      "negate": false
  1012                  }
  1013              ],
  1014              "name": "rul3",
  1015              "redirectURL": "/abc/sss",
  1016              "start": 0,
  1017              "forwardSettings": {
  1018                  "originId": "some_origin",
  1019                  "percent": 10
  1020              }
  1021          },
  1022          {
  1023              "type": "cdMatchRule",
  1024              "end": 0,
  1025              "id": 0,
  1026              "matchURL": "ddd.aaa",
  1027              "name": "rule 2",
  1028              "redirectURL": "sss.com",
  1029              "start": 0,
  1030              "statusCode": 301,
  1031              "useIncomingQueryString": true,
  1032              "useRelativeUrl": "none"
  1033          },
  1034          {
  1035              "type": "cdMatchRule",
  1036              "end": 0,
  1037              "id": 0,
  1038              "matchURL": "abc.com",
  1039              "name": "r1",
  1040              "redirectURL": "/ddd",
  1041              "start": 0,
  1042              "statusCode": 301,
  1043              "useIncomingQueryString": false,
  1044              "useIncomingSchemeAndHost": true,
  1045              "useRelativeUrl": "copy_scheme_hostname"
  1046          }
  1047      ],
  1048      "policyId": 276858,
  1049      "version": 6
  1050  }`,
  1051  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  1052  			expectedResponse: &PolicyVersion{
  1053  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1054  				CreatedBy:     "jsmith",
  1055  				Description:   nil,
  1056  				ModifiedBy:    "jsmith",
  1057  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1058  				PolicyID:      276858,
  1059  				PolicyVersion: 6,
  1060  				MatchRules: MatchRules{
  1061  					&MatchRulePR{
  1062  						Type:     "cdMatchRule",
  1063  						End:      0,
  1064  						ID:       0,
  1065  						MatchURL: "",
  1066  						Name:     "rul3",
  1067  						Start:    0,
  1068  						ForwardSettings: ForwardSettingsPR{
  1069  							OriginID: "some_origin",
  1070  							Percent:  10,
  1071  						},
  1072  						Matches: []MatchCriteriaPR{
  1073  							{
  1074  								MatchType:     "hostname",
  1075  								MatchValue:    "3333.dom",
  1076  								MatchOperator: "equals",
  1077  								CaseSensitive: true,
  1078  								Negate:        false,
  1079  							},
  1080  							{
  1081  								MatchType:     "cookie",
  1082  								MatchValue:    "cookie=cookievalue",
  1083  								MatchOperator: "equals",
  1084  								Negate:        false,
  1085  								CaseSensitive: false,
  1086  							},
  1087  							{
  1088  								MatchType:     "extension",
  1089  								MatchValue:    "txt",
  1090  								MatchOperator: "equals",
  1091  								Negate:        false,
  1092  								CaseSensitive: false,
  1093  							},
  1094  						},
  1095  					},
  1096  					&MatchRulePR{
  1097  						Type:     "cdMatchRule",
  1098  						End:      0,
  1099  						ID:       0,
  1100  						MatchURL: "ddd.aaa",
  1101  						Name:     "rule 2",
  1102  						Start:    0,
  1103  					},
  1104  					&MatchRulePR{
  1105  						Type:     "cdMatchRule",
  1106  						End:      0,
  1107  						ID:       0,
  1108  						MatchURL: "abc.com",
  1109  						Name:     "r1",
  1110  						Start:    0,
  1111  					},
  1112  				},
  1113  			},
  1114  		},
  1115  		"201 created, complex PR with objectMatchValue - simple": {
  1116  			request: CreatePolicyVersionRequest{
  1117  				CreatePolicyVersion: CreatePolicyVersion{
  1118  					MatchRules: MatchRules{
  1119  						&MatchRulePR{
  1120  							Start: 0,
  1121  							End:   0,
  1122  							Type:  "cdMatchRule",
  1123  							Name:  "rul3",
  1124  							ID:    0,
  1125  							ForwardSettings: ForwardSettingsPR{
  1126  								OriginID: "some_origin",
  1127  								Percent:  10,
  1128  							},
  1129  							Matches: []MatchCriteriaPR{
  1130  								{
  1131  									CaseSensitive: true,
  1132  									MatchOperator: "equals",
  1133  									MatchType:     "method",
  1134  									Negate:        false,
  1135  									ObjectMatchValue: &ObjectMatchValueSimple{
  1136  										Type:  "simple",
  1137  										Value: []string{"GET"},
  1138  									},
  1139  								},
  1140  							},
  1141  						},
  1142  					},
  1143  				},
  1144  				PolicyID: 276858,
  1145  			},
  1146  			requestBody:    `{"matchRules":[{"name":"rul3","type":"cdMatchRule","matches":[{"matchType":"method","matchOperator":"equals","caseSensitive":true,"negate":false,"objectMatchValue":{"type":"simple","value":["GET"]}}],"forwardSettings":{"originId":"some_origin","percent":10}}]}`,
  1147  			responseStatus: http.StatusCreated,
  1148  			responseBody: `{
  1149      "createdDate": "2023-10-19T08:50:47.350Z",
  1150      "createdBy": "jsmith",
  1151      "description": null,
  1152      "modifiedBy": "jsmith",
  1153      "modifiedDate": "2023-10-19T08:50:47.350Z",
  1154      "matchRules": [
  1155          {
  1156              "type": "cdMatchRule",
  1157              "end": 0,
  1158              "id": 0,
  1159              "matchURL": null,
  1160              "matches": [
  1161                  {
  1162                      "caseSensitive": true,
  1163                      "matchOperator": "equals",
  1164                      "matchType": "method",
  1165                      "negate": false,
  1166                      "objectMatchValue": {
  1167                          "type": "simple",
  1168                          "value": [
  1169                              "GET"
  1170                          ]
  1171                      }
  1172                  }
  1173              ],
  1174              "name": "rul3",
  1175              "redirectURL": "/abc/sss",
  1176              "start": 0,
  1177              "forwardSettings": {
  1178                  "originId": "some_origin",
  1179                  "percent": 10
  1180              }
  1181          }
  1182      ],
  1183      "policyId": 276858,
  1184      "version": 6
  1185  }`,
  1186  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  1187  			expectedResponse: &PolicyVersion{
  1188  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1189  				CreatedBy:     "jsmith",
  1190  				Description:   nil,
  1191  				ModifiedBy:    "jsmith",
  1192  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1193  				PolicyID:      276858,
  1194  				PolicyVersion: 6,
  1195  				MatchRules: MatchRules{
  1196  					&MatchRulePR{
  1197  						Type:     "cdMatchRule",
  1198  						End:      0,
  1199  						ID:       0,
  1200  						MatchURL: "",
  1201  						Name:     "rul3",
  1202  						Start:    0,
  1203  						ForwardSettings: ForwardSettingsPR{
  1204  							OriginID: "some_origin",
  1205  							Percent:  10,
  1206  						},
  1207  						Matches: []MatchCriteriaPR{
  1208  							{
  1209  								CaseSensitive: true,
  1210  								MatchOperator: "equals",
  1211  								MatchType:     "method",
  1212  								Negate:        false,
  1213  								ObjectMatchValue: &ObjectMatchValueSimple{
  1214  									Type:  "simple",
  1215  									Value: []string{"GET"},
  1216  								},
  1217  							},
  1218  						},
  1219  					},
  1220  				},
  1221  			},
  1222  		},
  1223  		"201 created, complex PR with objectMatchValue - object": {
  1224  			request: CreatePolicyVersionRequest{
  1225  				CreatePolicyVersion: CreatePolicyVersion{
  1226  					MatchRules: MatchRules{
  1227  						&MatchRulePR{
  1228  							Start: 0,
  1229  							End:   0,
  1230  							Type:  "cdMatchRule",
  1231  							Name:  "rul3",
  1232  							ID:    0,
  1233  							ForwardSettings: ForwardSettingsPR{
  1234  								OriginID: "some_origin",
  1235  								Percent:  10,
  1236  							},
  1237  							Matches: []MatchCriteriaPR{
  1238  								{
  1239  									MatchOperator: "equals",
  1240  									MatchType:     "header",
  1241  									Negate:        false,
  1242  									ObjectMatchValue: &ObjectMatchValueObject{
  1243  										Type: "object",
  1244  										Name: "PR",
  1245  										Options: &Options{
  1246  											Value: []string{
  1247  												"text/html*",
  1248  												"text/css*",
  1249  												"application/x-javascript*",
  1250  											},
  1251  											ValueHasWildcard: true,
  1252  										},
  1253  									},
  1254  								},
  1255  							},
  1256  						},
  1257  					},
  1258  				},
  1259  				PolicyID: 276858,
  1260  			},
  1261  			responseStatus: http.StatusCreated,
  1262  			responseBody: `{
  1263      "createdDate": "2023-10-19T08:50:47.350Z",
  1264      "createdBy": "jsmith",
  1265      "description": null,
  1266      "modifiedBy": "jsmith",
  1267      "modifiedDate": "2023-10-19T08:50:47.350Z",
  1268      "matchRules": [
  1269          {
  1270              "type": "cdMatchRule",
  1271              "end": 0,
  1272              "id": 0,
  1273              "matchURL": null,
  1274              "matches": [
  1275                  {
  1276                      "matchOperator": "equals",
  1277                      "matchType": "hostname",
  1278                      "negate": false,
  1279  					"objectMatchValue": {
  1280  						"type": "object",
  1281  						"name": "PR",
  1282  						"options": {
  1283  							"value": [
  1284  								"text/html*",
  1285                                  "text/css*",
  1286                                  "application/x-javascript*"
  1287  							],
  1288  							"valueHasWildcard": true
  1289  						}
  1290  					}
  1291                  }
  1292              ],
  1293              "name": "rul3",
  1294              "redirectURL": "/abc/sss",
  1295              "start": 0,
  1296              "forwardSettings": {
  1297                  "originId": "some_origin",
  1298                  "percent": 10
  1299              }
  1300          }
  1301      ],
  1302      "policyId": 276858,
  1303      "version": 6
  1304  }`,
  1305  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  1306  			expectedResponse: &PolicyVersion{
  1307  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1308  				CreatedBy:     "jsmith",
  1309  				Description:   nil,
  1310  				ModifiedBy:    "jsmith",
  1311  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1312  				PolicyID:      276858,
  1313  				PolicyVersion: 6,
  1314  				MatchRules: MatchRules{
  1315  					&MatchRulePR{
  1316  						Type:     "cdMatchRule",
  1317  						End:      0,
  1318  						ID:       0,
  1319  						MatchURL: "",
  1320  						Name:     "rul3",
  1321  						Start:    0,
  1322  						ForwardSettings: ForwardSettingsPR{
  1323  							OriginID: "some_origin",
  1324  							Percent:  10,
  1325  						},
  1326  						Matches: []MatchCriteriaPR{
  1327  							{
  1328  								MatchOperator: "equals",
  1329  								MatchType:     "hostname",
  1330  								Negate:        false,
  1331  								ObjectMatchValue: &ObjectMatchValueObject{
  1332  									Type: "object",
  1333  									Name: "PR",
  1334  									Options: &Options{
  1335  										Value: []string{
  1336  											"text/html*",
  1337  											"text/css*",
  1338  											"application/x-javascript*",
  1339  										},
  1340  										ValueHasWildcard: true,
  1341  									},
  1342  								},
  1343  							},
  1344  						},
  1345  					},
  1346  				},
  1347  			},
  1348  		},
  1349  		"validation error, complex PR with unavailable objectMatchValue type - range": {
  1350  			request: CreatePolicyVersionRequest{
  1351  				CreatePolicyVersion: CreatePolicyVersion{
  1352  					MatchRules: MatchRules{
  1353  						&MatchRulePR{
  1354  							Start: 0,
  1355  							End:   0,
  1356  							Type:  "cdMatchRule",
  1357  							Name:  "rul3",
  1358  							ID:    0,
  1359  							ForwardSettings: ForwardSettingsPR{
  1360  								OriginID: "some_origin",
  1361  								Percent:  10,
  1362  							},
  1363  							Matches: []MatchCriteriaPR{
  1364  								{
  1365  									MatchOperator: "equals",
  1366  									MatchType:     "header",
  1367  									Negate:        false,
  1368  									ObjectMatchValue: &ObjectMatchValueRange{
  1369  										Type:  "range",
  1370  										Value: []int64{1, 50},
  1371  									},
  1372  								},
  1373  							},
  1374  						},
  1375  					},
  1376  				},
  1377  				PolicyID: 276858,
  1378  			},
  1379  			withError: ErrStructValidation,
  1380  		},
  1381  		"validation error, complex PR missing forwardSettings": {
  1382  			request: CreatePolicyVersionRequest{
  1383  				CreatePolicyVersion: CreatePolicyVersion{
  1384  					MatchRules: MatchRules{
  1385  						&MatchRulePR{
  1386  							Start: 0,
  1387  							End:   0,
  1388  							Type:  "cdMatchRule",
  1389  							Name:  "rul3",
  1390  							ID:    0,
  1391  							ForwardSettings: ForwardSettingsPR{
  1392  								OriginID: "some_origin",
  1393  								Percent:  10,
  1394  							},
  1395  							Matches: []MatchCriteriaPR{
  1396  								{
  1397  									MatchType:     "hostname",
  1398  									MatchValue:    "3333.dom",
  1399  									MatchOperator: "equals",
  1400  									CaseSensitive: true,
  1401  									Negate:        false,
  1402  								},
  1403  								{
  1404  									MatchType:     "cookie",
  1405  									MatchValue:    "cookie=cookievalue",
  1406  									MatchOperator: "equals",
  1407  									Negate:        false,
  1408  									CaseSensitive: false,
  1409  								},
  1410  								{
  1411  									MatchType:     "extension",
  1412  									MatchValue:    "txt",
  1413  									MatchOperator: "equals",
  1414  									Negate:        false,
  1415  									CaseSensitive: false,
  1416  								},
  1417  							},
  1418  						},
  1419  						&MatchRulePR{
  1420  							Start:    0,
  1421  							End:      0,
  1422  							Type:     "cdMatchRule",
  1423  							Name:     "rule 2",
  1424  							MatchURL: "ddd.aaa",
  1425  							ID:       0,
  1426  						},
  1427  						&MatchRulePR{
  1428  							Type:     "cdMatchRule",
  1429  							ID:       0,
  1430  							Name:     "r1",
  1431  							Start:    0,
  1432  							End:      0,
  1433  							MatchURL: "abc.com",
  1434  							ForwardSettings: ForwardSettingsPR{
  1435  								OriginID: "some_origin",
  1436  								Percent:  10,
  1437  							},
  1438  						},
  1439  					},
  1440  				},
  1441  				PolicyID: 276858,
  1442  			},
  1443  			withError: ErrStructValidation,
  1444  		},
  1445  
  1446  		"201 created, complex ER": {
  1447  			request: CreatePolicyVersionRequest{
  1448  				CreatePolicyVersion: CreatePolicyVersion{
  1449  					MatchRules: MatchRules{
  1450  						&MatchRuleER{
  1451  							Start:          0,
  1452  							End:            0,
  1453  							Type:           "erMatchRule",
  1454  							UseRelativeURL: "copy_scheme_hostname",
  1455  							Name:           "rul3",
  1456  							StatusCode:     307,
  1457  							RedirectURL:    "/abc/sss",
  1458  							ID:             0,
  1459  							Matches: []MatchCriteriaER{
  1460  								{
  1461  									MatchType:     "hostname",
  1462  									MatchValue:    "3333.dom",
  1463  									MatchOperator: "equals",
  1464  									CaseSensitive: true,
  1465  									Negate:        false,
  1466  								},
  1467  								{
  1468  									MatchType:     "cookie",
  1469  									MatchValue:    "cookie=cookievalue",
  1470  									MatchOperator: "equals",
  1471  									Negate:        false,
  1472  									CaseSensitive: false,
  1473  								},
  1474  								{
  1475  									MatchType:     "extension",
  1476  									MatchValue:    "txt",
  1477  									MatchOperator: "equals",
  1478  									Negate:        false,
  1479  									CaseSensitive: false,
  1480  								},
  1481  							},
  1482  						},
  1483  						&MatchRuleER{
  1484  							Start:                  0,
  1485  							End:                    0,
  1486  							Type:                   "erMatchRule",
  1487  							UseRelativeURL:         "none",
  1488  							Name:                   "rule 2",
  1489  							MatchURL:               "ddd.aaa",
  1490  							RedirectURL:            "sss.com",
  1491  							StatusCode:             301,
  1492  							UseIncomingQueryString: true,
  1493  							ID:                     0,
  1494  						},
  1495  						&MatchRuleER{
  1496  							Type:                     "erMatchRule",
  1497  							ID:                       0,
  1498  							Name:                     "r1",
  1499  							Start:                    0,
  1500  							End:                      0,
  1501  							MatchURL:                 "abc.com",
  1502  							StatusCode:               301,
  1503  							RedirectURL:              "/ddd",
  1504  							UseIncomingQueryString:   false,
  1505  							UseIncomingSchemeAndHost: true,
  1506  							UseRelativeURL:           "copy_scheme_hostname",
  1507  						},
  1508  					},
  1509  				},
  1510  				PolicyID: 276858,
  1511  			},
  1512  			responseStatus: http.StatusCreated,
  1513  			responseBody: `{
  1514      "createdDate": "2023-10-19T08:50:47.350Z",
  1515      "createdBy": "jsmith",
  1516      "description": null,
  1517      "modifiedBy": "jsmith",
  1518      "modifiedDate": "2023-10-19T08:50:47.350Z",
  1519      "matchRules": [
  1520          {
  1521              "type": "erMatchRule",
  1522              "end": 0,
  1523              "id": 0,
  1524              "matchURL": null,
  1525              "matches": [
  1526                  {
  1527                      "caseSensitive": true,
  1528                      "matchOperator": "equals",
  1529                      "matchType": "hostname",
  1530                      "matchValue": "3333.dom",
  1531                      "negate": false
  1532                  },
  1533                  {
  1534                      "caseSensitive": false,
  1535                      "matchOperator": "equals",
  1536                      "matchType": "cookie",
  1537                      "matchValue": "cookie=cookievalue",
  1538                      "negate": false
  1539                  },
  1540                  {
  1541                      "caseSensitive": false,
  1542                      "matchOperator": "equals",
  1543                      "matchType": "extension",
  1544                      "matchValue": "txt",
  1545                      "negate": false
  1546                  }
  1547              ],
  1548              "name": "rul3",
  1549              "redirectURL": "/abc/sss",
  1550              "start": 0,
  1551              "statusCode": 307,
  1552              "useIncomingQueryString": false,
  1553              "useIncomingSchemeAndHost": true,
  1554              "useRelativeUrl": "copy_scheme_hostname"
  1555          },
  1556          {
  1557              "type": "erMatchRule",
  1558              "end": 0,
  1559              "id": 0,
  1560              "matchURL": "ddd.aaa",
  1561              "name": "rule 2",
  1562              "redirectURL": "sss.com",
  1563              "start": 0,
  1564              "statusCode": 301,
  1565              "useIncomingQueryString": true,
  1566              "useRelativeUrl": "none"
  1567          },
  1568          {
  1569              "type": "erMatchRule",
  1570              "end": 0,
  1571              "id": 0,
  1572              "matchURL": "abc.com",
  1573              "name": "r1",
  1574              "redirectURL": "/ddd",
  1575              "start": 0,
  1576              "statusCode": 301,
  1577              "useIncomingQueryString": false,
  1578              "useIncomingSchemeAndHost": true,
  1579              "useRelativeUrl": "copy_scheme_hostname"
  1580          }
  1581      ],
  1582      "policyId": 276858,
  1583      "version": 6
  1584  }`,
  1585  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  1586  			expectedResponse: &PolicyVersion{
  1587  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1588  				CreatedBy:     "jsmith",
  1589  				Description:   nil,
  1590  				ModifiedBy:    "jsmith",
  1591  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1592  				PolicyID:      276858,
  1593  				PolicyVersion: 6,
  1594  				MatchRules: MatchRules{
  1595  					&MatchRuleER{
  1596  						Type:                     "erMatchRule",
  1597  						End:                      0,
  1598  						ID:                       0,
  1599  						MatchURL:                 "",
  1600  						Name:                     "rul3",
  1601  						RedirectURL:              "/abc/sss",
  1602  						Start:                    0,
  1603  						StatusCode:               307,
  1604  						UseIncomingQueryString:   false,
  1605  						UseIncomingSchemeAndHost: true,
  1606  						UseRelativeURL:           "copy_scheme_hostname",
  1607  						Matches: []MatchCriteriaER{
  1608  							{
  1609  								MatchType:     "hostname",
  1610  								MatchValue:    "3333.dom",
  1611  								MatchOperator: "equals",
  1612  								CaseSensitive: true,
  1613  								Negate:        false,
  1614  							},
  1615  							{
  1616  								MatchType:     "cookie",
  1617  								MatchValue:    "cookie=cookievalue",
  1618  								MatchOperator: "equals",
  1619  								Negate:        false,
  1620  								CaseSensitive: false,
  1621  							},
  1622  							{
  1623  								MatchType:     "extension",
  1624  								MatchValue:    "txt",
  1625  								MatchOperator: "equals",
  1626  								Negate:        false,
  1627  								CaseSensitive: false,
  1628  							},
  1629  						},
  1630  					},
  1631  					&MatchRuleER{
  1632  						Type:                   "erMatchRule",
  1633  						End:                    0,
  1634  						ID:                     0,
  1635  						MatchURL:               "ddd.aaa",
  1636  						Name:                   "rule 2",
  1637  						RedirectURL:            "sss.com",
  1638  						Start:                  0,
  1639  						StatusCode:             301,
  1640  						UseIncomingQueryString: true,
  1641  						UseRelativeURL:         "none",
  1642  					},
  1643  					&MatchRuleER{
  1644  						Type:                     "erMatchRule",
  1645  						End:                      0,
  1646  						ID:                       0,
  1647  						MatchURL:                 "abc.com",
  1648  						Name:                     "r1",
  1649  						RedirectURL:              "/ddd",
  1650  						Start:                    0,
  1651  						StatusCode:               301,
  1652  						UseIncomingQueryString:   false,
  1653  						UseIncomingSchemeAndHost: true,
  1654  						UseRelativeURL:           "copy_scheme_hostname",
  1655  					},
  1656  				},
  1657  			},
  1658  		},
  1659  		"201 created, complex ER with objectMatchValue - simple": {
  1660  			request: CreatePolicyVersionRequest{
  1661  				CreatePolicyVersion: CreatePolicyVersion{
  1662  					MatchRules: MatchRules{
  1663  						&MatchRuleER{
  1664  							Start:          0,
  1665  							End:            0,
  1666  							Type:           "erMatchRule",
  1667  							UseRelativeURL: "copy_scheme_hostname",
  1668  							Name:           "rul3",
  1669  							StatusCode:     307,
  1670  							RedirectURL:    "/abc/sss",
  1671  							ID:             0,
  1672  							Matches: []MatchCriteriaER{
  1673  								{
  1674  									CaseSensitive: true,
  1675  									MatchOperator: "equals",
  1676  									MatchType:     "method",
  1677  									Negate:        false,
  1678  									ObjectMatchValue: &ObjectMatchValueSimple{
  1679  										Type:  "simple",
  1680  										Value: []string{"GET"},
  1681  									},
  1682  								},
  1683  							},
  1684  						},
  1685  					},
  1686  				},
  1687  				PolicyID: 276858,
  1688  			},
  1689  			responseStatus: http.StatusCreated,
  1690  			responseBody: `{
  1691      "createdDate": "2023-10-19T08:50:47.350Z",
  1692      "createdBy": "jsmith",
  1693      "description": null,
  1694      "modifiedBy": "jsmith",
  1695      "modifiedDate": "2023-10-19T08:50:47.350Z",
  1696      "matchRules": [
  1697          {
  1698              "type": "erMatchRule",
  1699              "end": 0,
  1700              "id": 0,
  1701              "matchURL": null,
  1702              "matches": [
  1703                  {
  1704                      "caseSensitive": true,
  1705                      "matchOperator": "equals",
  1706                      "matchType": "method",
  1707                      "negate": false,
  1708                      "objectMatchValue": {
  1709                          "type": "simple",
  1710                          "value": [
  1711                              "GET"
  1712                          ]
  1713                      }
  1714                  }
  1715              ],
  1716              "name": "rul3",
  1717              "redirectURL": "/abc/sss",
  1718              "start": 0,
  1719              "statusCode": 307,
  1720              "useIncomingQueryString": false,
  1721              "useIncomingSchemeAndHost": true,
  1722              "useRelativeUrl": "copy_scheme_hostname"
  1723          }
  1724      ],
  1725      "policyId": 276858,
  1726      "version": 6
  1727  }`,
  1728  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  1729  			expectedResponse: &PolicyVersion{
  1730  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1731  				CreatedBy:     "jsmith",
  1732  				Description:   nil,
  1733  				ModifiedBy:    "jsmith",
  1734  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1735  				PolicyID:      276858,
  1736  				PolicyVersion: 6,
  1737  				MatchRules: MatchRules{
  1738  					&MatchRuleER{
  1739  						Type:                     "erMatchRule",
  1740  						End:                      0,
  1741  						ID:                       0,
  1742  						MatchURL:                 "",
  1743  						Name:                     "rul3",
  1744  						RedirectURL:              "/abc/sss",
  1745  						Start:                    0,
  1746  						StatusCode:               307,
  1747  						UseIncomingQueryString:   false,
  1748  						UseIncomingSchemeAndHost: true,
  1749  						UseRelativeURL:           "copy_scheme_hostname",
  1750  						Matches: []MatchCriteriaER{
  1751  							{
  1752  								CaseSensitive: true,
  1753  								MatchOperator: "equals",
  1754  								MatchType:     "method",
  1755  								Negate:        false,
  1756  								ObjectMatchValue: &ObjectMatchValueSimple{
  1757  									Type:  "simple",
  1758  									Value: []string{"GET"},
  1759  								},
  1760  							},
  1761  						},
  1762  					},
  1763  				},
  1764  			},
  1765  		},
  1766  		"201 created, complex ER with objectMatchValue - object": {
  1767  			request: CreatePolicyVersionRequest{
  1768  				CreatePolicyVersion: CreatePolicyVersion{
  1769  					MatchRules: MatchRules{
  1770  						&MatchRuleER{
  1771  							Start:          0,
  1772  							End:            0,
  1773  							Type:           "erMatchRule",
  1774  							UseRelativeURL: "copy_scheme_hostname",
  1775  							Name:           "rul3",
  1776  							StatusCode:     307,
  1777  							RedirectURL:    "/abc/sss",
  1778  							ID:             0,
  1779  							Matches: []MatchCriteriaER{
  1780  								{
  1781  									MatchOperator: "equals",
  1782  									MatchType:     "header",
  1783  									Negate:        false,
  1784  									ObjectMatchValue: &ObjectMatchValueObject{
  1785  										Type: "object",
  1786  										Name: "ER",
  1787  										Options: &Options{
  1788  											Value: []string{
  1789  												"text/html*",
  1790  												"text/css*",
  1791  												"application/x-javascript*",
  1792  											},
  1793  											ValueHasWildcard: true,
  1794  										},
  1795  									},
  1796  								},
  1797  							},
  1798  						},
  1799  					},
  1800  				},
  1801  				PolicyID: 276858,
  1802  			},
  1803  			responseStatus: http.StatusCreated,
  1804  			responseBody: `{
  1805      "createdDate": "2023-10-19T08:50:47.350Z",
  1806      "createdBy": "jsmith",
  1807      "description": null,
  1808      "modifiedBy": "jsmith",
  1809      "modifiedDate": "2023-10-19T08:50:47.350Z",
  1810      "matchRules": [
  1811          {
  1812              "type": "erMatchRule",
  1813              "end": 0,
  1814              "id": 0,
  1815              "matchURL": null,
  1816              "matches": [
  1817                  {
  1818                      "matchOperator": "equals",
  1819                      "matchType": "hostname",
  1820                      "negate": false,
  1821  					"objectMatchValue": {
  1822  						"type": "object",
  1823  						"name": "ER",
  1824  						"options": {
  1825  							"value": [
  1826  								"text/html*",
  1827                                  "text/css*",
  1828                                  "application/x-javascript*"
  1829  							],
  1830  							"valueHasWildcard": true
  1831  						}
  1832  					}
  1833                  }
  1834              ],
  1835              "name": "rul3",
  1836              "redirectURL": "/abc/sss",
  1837              "start": 0,
  1838              "statusCode": 307,
  1839              "useIncomingQueryString": false,
  1840              "useIncomingSchemeAndHost": true,
  1841              "useRelativeUrl": "copy_scheme_hostname"
  1842          }
  1843      ],
  1844      "policyId": 276858,
  1845      "version": 6
  1846  }`,
  1847  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  1848  			expectedResponse: &PolicyVersion{
  1849  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1850  				CreatedBy:     "jsmith",
  1851  				Description:   nil,
  1852  				ModifiedBy:    "jsmith",
  1853  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1854  				PolicyID:      276858,
  1855  				PolicyVersion: 6,
  1856  				MatchRules: MatchRules{
  1857  					&MatchRuleER{
  1858  						Type:                     "erMatchRule",
  1859  						End:                      0,
  1860  						ID:                       0,
  1861  						MatchURL:                 "",
  1862  						Name:                     "rul3",
  1863  						RedirectURL:              "/abc/sss",
  1864  						Start:                    0,
  1865  						StatusCode:               307,
  1866  						UseIncomingQueryString:   false,
  1867  						UseIncomingSchemeAndHost: true,
  1868  						UseRelativeURL:           "copy_scheme_hostname",
  1869  						Matches: []MatchCriteriaER{
  1870  							{
  1871  								MatchOperator: "equals",
  1872  								MatchType:     "hostname",
  1873  								Negate:        false,
  1874  								ObjectMatchValue: &ObjectMatchValueObject{
  1875  									Type: "object",
  1876  									Name: "ER",
  1877  									Options: &Options{
  1878  										Value: []string{
  1879  											"text/html*",
  1880  											"text/css*",
  1881  											"application/x-javascript*",
  1882  										},
  1883  										ValueHasWildcard: true,
  1884  									},
  1885  								},
  1886  							},
  1887  						},
  1888  					},
  1889  				},
  1890  			},
  1891  		},
  1892  		"201 created, ER with empty/no useRelativeURL": {
  1893  			request: CreatePolicyVersionRequest{
  1894  				CreatePolicyVersion: CreatePolicyVersion{
  1895  					MatchRules: MatchRules{
  1896  						&MatchRuleER{
  1897  							Start:                  0,
  1898  							End:                    0,
  1899  							Type:                   "erMatchRule",
  1900  							Name:                   "rule 2",
  1901  							MatchURL:               "ddd.aaa",
  1902  							RedirectURL:            "sss.com",
  1903  							StatusCode:             301,
  1904  							UseIncomingQueryString: true,
  1905  							ID:                     0,
  1906  						},
  1907  						&MatchRuleER{
  1908  							Type:                     "erMatchRule",
  1909  							ID:                       0,
  1910  							Name:                     "r1",
  1911  							Start:                    0,
  1912  							End:                      0,
  1913  							MatchURL:                 "abc.com",
  1914  							StatusCode:               301,
  1915  							RedirectURL:              "/ddd",
  1916  							UseIncomingQueryString:   false,
  1917  							UseIncomingSchemeAndHost: true,
  1918  							UseRelativeURL:           "",
  1919  						},
  1920  						&MatchRuleER{
  1921  							Start:       0,
  1922  							End:         0,
  1923  							Type:        "erMatchRule",
  1924  							Name:        "rul3",
  1925  							StatusCode:  307,
  1926  							RedirectURL: "/abc/sss",
  1927  							ID:          0,
  1928  						},
  1929  					},
  1930  				},
  1931  				PolicyID: 276858,
  1932  			},
  1933  			responseStatus: http.StatusCreated,
  1934  			responseBody: `{
  1935      "createdDate": "2023-10-19T08:50:47.350Z",
  1936      "createdBy": "jsmith",
  1937      "description": null,
  1938      "modifiedBy": "jsmith",
  1939      "modifiedDate": "2023-10-19T08:50:47.350Z",
  1940      "matchRules": [
  1941          {
  1942              "type": "erMatchRule",
  1943              "end": 0,
  1944              "id": 0,
  1945              "matchURL": "ddd.aaa",
  1946              "name": "rule 2",
  1947              "redirectURL": "sss.com",
  1948              "start": 0,
  1949              "statusCode": 301,
  1950              "useIncomingQueryString": true
  1951          },
  1952          {
  1953              "type": "erMatchRule",
  1954              "end": 0,
  1955              "id": 0,
  1956              "matchURL": "abc.com",
  1957              "name": "r1",
  1958              "redirectURL": "/ddd",
  1959              "start": 0,
  1960              "statusCode": 301,
  1961              "useIncomingQueryString": false,
  1962              "useIncomingSchemeAndHost": true,
  1963              "useRelativeUrl": "copy_scheme_hostname"
  1964          },
  1965  		{
  1966  			"type": "erMatchRule",
  1967              "end": 0,
  1968              "id": 0,
  1969  			"name": "rul3",
  1970  			"redirectURL": "/abc/sss",
  1971  			"start": 0,
  1972  			"statusCode": 307
  1973  		}
  1974      ],
  1975      "policyId": 276858,
  1976      "version": 6
  1977  }`,
  1978  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  1979  			expectedResponse: &PolicyVersion{
  1980  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1981  				CreatedBy:     "jsmith",
  1982  				Description:   nil,
  1983  				ModifiedBy:    "jsmith",
  1984  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  1985  				PolicyID:      276858,
  1986  				PolicyVersion: 6,
  1987  				MatchRules: MatchRules{
  1988  					&MatchRuleER{
  1989  						Type:                   "erMatchRule",
  1990  						End:                    0,
  1991  						ID:                     0,
  1992  						MatchURL:               "ddd.aaa",
  1993  						Name:                   "rule 2",
  1994  						RedirectURL:            "sss.com",
  1995  						Start:                  0,
  1996  						StatusCode:             301,
  1997  						UseIncomingQueryString: true,
  1998  					},
  1999  					&MatchRuleER{
  2000  						Type:                     "erMatchRule",
  2001  						End:                      0,
  2002  						ID:                       0,
  2003  						MatchURL:                 "abc.com",
  2004  						Name:                     "r1",
  2005  						RedirectURL:              "/ddd",
  2006  						Start:                    0,
  2007  						StatusCode:               301,
  2008  						UseIncomingQueryString:   false,
  2009  						UseIncomingSchemeAndHost: true,
  2010  						UseRelativeURL:           "copy_scheme_hostname",
  2011  					},
  2012  					&MatchRuleER{
  2013  						Start:       0,
  2014  						End:         0,
  2015  						Type:        "erMatchRule",
  2016  						Name:        "rul3",
  2017  						StatusCode:  307,
  2018  						RedirectURL: "/abc/sss",
  2019  						ID:          0,
  2020  					},
  2021  				},
  2022  			},
  2023  		},
  2024  		"validation error, complex ER with unavailable objectMatchValue type - range": {
  2025  			request: CreatePolicyVersionRequest{
  2026  				CreatePolicyVersion: CreatePolicyVersion{
  2027  					MatchRules: MatchRules{
  2028  						&MatchRuleER{
  2029  							Start:          0,
  2030  							End:            0,
  2031  							Type:           "erMatchRule",
  2032  							UseRelativeURL: "copy_scheme_hostname",
  2033  							Name:           "rul3",
  2034  							StatusCode:     307,
  2035  							RedirectURL:    "/abc/sss",
  2036  							ID:             0,
  2037  							Matches: []MatchCriteriaER{
  2038  								{
  2039  									MatchOperator: "equals",
  2040  									MatchType:     "header",
  2041  									Negate:        false,
  2042  									ObjectMatchValue: &ObjectMatchValueRange{
  2043  										Type:  "range",
  2044  										Value: []int64{1, 50},
  2045  									},
  2046  								},
  2047  							},
  2048  						},
  2049  					},
  2050  				},
  2051  				PolicyID: 276858,
  2052  			},
  2053  			withError: ErrStructValidation,
  2054  		},
  2055  
  2056  		"201 created, complex FR": {
  2057  			request: CreatePolicyVersionRequest{
  2058  				CreatePolicyVersion: CreatePolicyVersion{
  2059  					MatchRules: MatchRules{
  2060  						&MatchRuleFR{
  2061  							Start: 0,
  2062  							End:   0,
  2063  							Type:  "frMatchRule",
  2064  							Name:  "rul3",
  2065  							ID:    0,
  2066  							Matches: []MatchCriteriaFR{
  2067  								{
  2068  									MatchType:     "hostname",
  2069  									MatchValue:    "3333.dom",
  2070  									MatchOperator: "equals",
  2071  									CaseSensitive: true,
  2072  									Negate:        false,
  2073  								},
  2074  								{
  2075  									MatchType:     "cookie",
  2076  									MatchValue:    "cookie=cookievalue",
  2077  									MatchOperator: "equals",
  2078  									Negate:        false,
  2079  									CaseSensitive: false,
  2080  								},
  2081  								{
  2082  									MatchType:     "extension",
  2083  									MatchValue:    "txt",
  2084  									MatchOperator: "equals",
  2085  									Negate:        false,
  2086  									CaseSensitive: false,
  2087  								},
  2088  							},
  2089  							ForwardSettings: ForwardSettingsFR{
  2090  								PathAndQS:              "/test_images/simpleimg.jpg",
  2091  								UseIncomingQueryString: true,
  2092  								OriginID:               "1234",
  2093  							},
  2094  						},
  2095  						&MatchRuleFR{
  2096  							Name:     "rule 1",
  2097  							Type:     "frMatchRule",
  2098  							Start:    0,
  2099  							End:      0,
  2100  							ID:       0,
  2101  							MatchURL: "ddd.aaa",
  2102  							ForwardSettings: ForwardSettingsFR{
  2103  								PathAndQS:              "/test_images/simpleimg.jpg",
  2104  								UseIncomingQueryString: true,
  2105  								OriginID:               "1234",
  2106  							},
  2107  						},
  2108  						&MatchRuleFR{
  2109  							Name:     "rule 2",
  2110  							Type:     "frMatchRule",
  2111  							Start:    0,
  2112  							End:      0,
  2113  							ID:       0,
  2114  							MatchURL: "abc.com",
  2115  							ForwardSettings: ForwardSettingsFR{
  2116  								PathAndQS:              "/test_images/otherimage.jpg",
  2117  								UseIncomingQueryString: true,
  2118  								OriginID:               "1234",
  2119  							},
  2120  						},
  2121  					},
  2122  				},
  2123  				PolicyID: 276858,
  2124  			},
  2125  			responseStatus: http.StatusCreated,
  2126  			responseBody: `{
  2127      "createdDate": "2023-10-19T08:50:47.350Z",
  2128      "createdBy": "jsmith",
  2129      "description": null,
  2130      "modifiedBy": "jsmith",
  2131      "modifiedDate": "2023-10-19T08:50:47.350Z",
  2132      "matchRules": [
  2133          {
  2134              "type": "frMatchRule",
  2135              "akaRuleId": "893947a3d5a85c1b",
  2136              "end": 0,
  2137              "forwardSettings": {
  2138                  "pathAndQS": "/test_images/otherimage.jpg",
  2139                  "useIncomingQueryString": true,
  2140  				"originId": "1234"
  2141              },
  2142              "id": 0,
  2143              "matchURL": null,
  2144              "matches": [
  2145                  {
  2146                      "caseSensitive": true,
  2147                      "matchOperator": "equals",
  2148                      "matchType": "hostname",
  2149                      "matchValue": "3333.dom",
  2150                      "negate": false
  2151                  },
  2152                  {
  2153                      "caseSensitive": false,
  2154                      "matchOperator": "equals",
  2155                      "matchType": "cookie",
  2156                      "matchValue": "cookie=cookievalue",
  2157                      "negate": false
  2158                  },
  2159                  {
  2160                      "caseSensitive": false,
  2161                      "matchOperator": "equals",
  2162                      "matchType": "extension",
  2163                      "matchValue": "txt",
  2164                      "negate": false
  2165                  }
  2166              ],
  2167              "name": "rul3",
  2168              "start": 0
  2169          },
  2170          {
  2171              "type": "frMatchRule",
  2172              "akaRuleId": "aa379d230efcded0",
  2173              "end": 0,
  2174              "forwardSettings": {
  2175                  "pathAndQS": "/test_images/simpleimg.jpg",
  2176                  "useIncomingQueryString": true,
  2177  				"originId": "1234"
  2178              },
  2179              "id": 0,
  2180              "matchURL": "ddd.aaa",
  2181              "name": "rule 1",
  2182              "start": 0
  2183          },
  2184          {
  2185              "type": "frMatchRule",
  2186              "akaRuleId": "1afe03d843996766",
  2187              "end": 0,
  2188              "forwardSettings": {
  2189                  "pathAndQS": "/test_images/otherimage.jpg",
  2190                  "useIncomingQueryString": true,
  2191  				"originId": "1234"
  2192              },
  2193              "id": 0,
  2194              "matchURL": "abc.com",
  2195              "name": "rule 2",
  2196              "start": 0
  2197          }
  2198      ],
  2199      "policyId": 276858,
  2200      "version": 6
  2201  }`,
  2202  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  2203  			expectedResponse: &PolicyVersion{
  2204  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2205  				CreatedBy:     "jsmith",
  2206  				Description:   nil,
  2207  				ModifiedBy:    "jsmith",
  2208  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2209  				PolicyID:      276858,
  2210  				PolicyVersion: 6,
  2211  				MatchRules: MatchRules{
  2212  					&MatchRuleFR{
  2213  						Type:     "frMatchRule",
  2214  						End:      0,
  2215  						ID:       0,
  2216  						MatchURL: "",
  2217  						Name:     "rul3",
  2218  						Start:    0,
  2219  						Matches: []MatchCriteriaFR{
  2220  							{
  2221  								MatchType:     "hostname",
  2222  								MatchValue:    "3333.dom",
  2223  								MatchOperator: "equals",
  2224  								CaseSensitive: true,
  2225  								Negate:        false,
  2226  							},
  2227  							{
  2228  								MatchType:     "cookie",
  2229  								MatchValue:    "cookie=cookievalue",
  2230  								MatchOperator: "equals",
  2231  								Negate:        false,
  2232  								CaseSensitive: false,
  2233  							},
  2234  							{
  2235  								MatchType:     "extension",
  2236  								MatchValue:    "txt",
  2237  								MatchOperator: "equals",
  2238  								Negate:        false,
  2239  								CaseSensitive: false,
  2240  							},
  2241  						},
  2242  						ForwardSettings: ForwardSettingsFR{
  2243  							PathAndQS:              "/test_images/otherimage.jpg",
  2244  							UseIncomingQueryString: true,
  2245  							OriginID:               "1234",
  2246  						},
  2247  					},
  2248  					&MatchRuleFR{
  2249  						Name:     "rule 1",
  2250  						Type:     "frMatchRule",
  2251  						Start:    0,
  2252  						End:      0,
  2253  						ID:       0,
  2254  						MatchURL: "ddd.aaa",
  2255  						ForwardSettings: ForwardSettingsFR{
  2256  							PathAndQS:              "/test_images/simpleimg.jpg",
  2257  							UseIncomingQueryString: true,
  2258  							OriginID:               "1234",
  2259  						},
  2260  					},
  2261  					&MatchRuleFR{
  2262  						Name:     "rule 2",
  2263  						Type:     "frMatchRule",
  2264  						Start:    0,
  2265  						End:      0,
  2266  						ID:       0,
  2267  						MatchURL: "abc.com",
  2268  						ForwardSettings: ForwardSettingsFR{
  2269  							PathAndQS:              "/test_images/otherimage.jpg",
  2270  							UseIncomingQueryString: true,
  2271  							OriginID:               "1234",
  2272  						},
  2273  					},
  2274  				},
  2275  			},
  2276  		},
  2277  		"201 created, complex FR with objectMatchValue - object": {
  2278  			request: CreatePolicyVersionRequest{
  2279  				CreatePolicyVersion: CreatePolicyVersion{
  2280  					Description: tools.StringPtr("New version 1630480693371"),
  2281  					MatchRules: MatchRules{
  2282  						&MatchRuleFR{
  2283  							ForwardSettings: ForwardSettingsFR{},
  2284  							Matches: []MatchCriteriaFR{
  2285  								{
  2286  									CaseSensitive: false,
  2287  									MatchOperator: "equals",
  2288  									MatchType:     "header",
  2289  									Negate:        false,
  2290  									ObjectMatchValue: &ObjectMatchValueObject{
  2291  										Type:              "object",
  2292  										Name:              "Accept",
  2293  										NameCaseSensitive: false,
  2294  										NameHasWildcard:   false,
  2295  										Options: &Options{
  2296  											Value:              []string{"asd", "qwe"},
  2297  											ValueHasWildcard:   false,
  2298  											ValueCaseSensitive: true,
  2299  											ValueEscaped:       false,
  2300  										},
  2301  									},
  2302  								},
  2303  							},
  2304  							Start: 0,
  2305  							End:   0,
  2306  							Type:  "frMatchRule",
  2307  							Name:  "rul3",
  2308  							ID:    0,
  2309  						},
  2310  					},
  2311  				},
  2312  				PolicyID: 139743,
  2313  			},
  2314  			responseStatus: http.StatusCreated,
  2315  			responseBody: `
  2316  {
  2317      "createdDate": "2023-10-19T08:50:47.350Z",
  2318      "createdBy": "jsmith",
  2319      "description": "New version 1630480693371",
  2320      "modifiedBy": "jsmith",
  2321      "modifiedDate": "2023-10-19T08:50:47.350Z",
  2322      "matchRules": [
  2323          {
  2324              "type": "frMatchRule",
  2325              "akaRuleId": "f2168e71692e6d9f",
  2326              "end": 0,
  2327              "forwardSettings": {},
  2328              "id": 0,
  2329              "matchURL": null,
  2330              "matches": [
  2331                  {
  2332                      "caseSensitive": false,
  2333                      "matchOperator": "equals",
  2334                      "matchType": "header",
  2335                      "negate": false,
  2336                      "objectMatchValue": {
  2337                          "type": "object",
  2338                          "name": "Accept",
  2339                          "options": {
  2340                              "value": [
  2341                                  "asd",
  2342                                  "qwe"
  2343                              ],
  2344                              "valueCaseSensitive": true
  2345                          }
  2346                      }
  2347                  }
  2348              ],
  2349              "name": "rul3",
  2350              "start": 0
  2351          }
  2352      ],
  2353  	"policyId": 139743,
  2354      "version": 798
  2355  }`,
  2356  			expectedPath: "/cloudlets/v3/policies/139743/versions",
  2357  			expectedResponse: &PolicyVersion{
  2358  				CreatedDate:  *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2359  				CreatedBy:    "jsmith",
  2360  				Description:  tools.StringPtr("New version 1630480693371"),
  2361  				ModifiedBy:   "jsmith",
  2362  				ModifiedDate: newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2363  				MatchRules: MatchRules{
  2364  					&MatchRuleFR{
  2365  						ForwardSettings: ForwardSettingsFR{},
  2366  						Matches: []MatchCriteriaFR{
  2367  							{
  2368  								CaseSensitive: false,
  2369  								MatchOperator: "equals",
  2370  								MatchType:     "header",
  2371  								Negate:        false,
  2372  								ObjectMatchValue: &ObjectMatchValueObject{
  2373  									Name:              "Accept",
  2374  									Type:              "object",
  2375  									NameCaseSensitive: false,
  2376  									NameHasWildcard:   false,
  2377  									Options: &Options{
  2378  										Value:              []string{"asd", "qwe"},
  2379  										ValueHasWildcard:   false,
  2380  										ValueCaseSensitive: true,
  2381  										ValueEscaped:       false,
  2382  									},
  2383  								},
  2384  							},
  2385  						},
  2386  						Start: 0,
  2387  						End:   0,
  2388  						Type:  "frMatchRule",
  2389  						Name:  "rul3",
  2390  						ID:    0,
  2391  					},
  2392  				},
  2393  				PolicyID:      139743,
  2394  				PolicyVersion: 798,
  2395  			},
  2396  		},
  2397  		"201 created, complex FR with objectMatchValue - simple": {
  2398  			request: CreatePolicyVersionRequest{
  2399  				CreatePolicyVersion: CreatePolicyVersion{
  2400  					Description: tools.StringPtr("New version 1630480693371"),
  2401  					MatchRules: MatchRules{
  2402  						&MatchRuleFR{
  2403  							ForwardSettings: ForwardSettingsFR{
  2404  								PathAndQS:              "/test_images/otherimage.jpg",
  2405  								UseIncomingQueryString: true,
  2406  							},
  2407  							Matches: []MatchCriteriaFR{
  2408  								{
  2409  									CaseSensitive: false,
  2410  									MatchOperator: "equals",
  2411  									MatchType:     "method",
  2412  									Negate:        false,
  2413  									ObjectMatchValue: &ObjectMatchValueSimple{
  2414  										Type:  "simple",
  2415  										Value: []string{"GET"},
  2416  									},
  2417  								},
  2418  							},
  2419  							Start: 0,
  2420  							End:   0,
  2421  							Type:  "frMatchRule",
  2422  							Name:  "rul3",
  2423  							ID:    0,
  2424  						},
  2425  					},
  2426  				},
  2427  				PolicyID: 139743,
  2428  			},
  2429  			responseStatus: http.StatusCreated,
  2430  			responseBody: `
  2431  {
  2432      "createdDate": "2023-10-19T08:50:47.350Z",
  2433      "createdBy": "jsmith",
  2434      "description": "New version 1630480693371",
  2435      "modifiedBy": "jsmith",
  2436      "modifiedDate": "2023-10-19T08:50:47.350Z",
  2437      "matchRules": [
  2438          {
  2439              "type": "frMatchRule",
  2440              "akaRuleId": "f2168e71692e6d9f",
  2441              "end": 0,
  2442              "forwardSettings": {
  2443                  "pathAndQS": "/test_images/otherimage.jpg",
  2444                  "useIncomingQueryString": true
  2445              },
  2446              "id": 0,
  2447              "matchURL": null,
  2448              "matches": [
  2449                  {
  2450                      "caseSensitive": false,
  2451                      "matchOperator": "equals",
  2452                      "matchType": "method",
  2453                      "negate": false,
  2454                      "objectMatchValue": {
  2455                          "type": "simple",
  2456                          "value": [
  2457                              "GET"
  2458                          ]
  2459                      }
  2460                  }
  2461  			],
  2462              "name": "rul3",
  2463              "start": 0
  2464          }
  2465      ],
  2466  	"policyId": 139743,
  2467      "version": 798
  2468  }`,
  2469  			expectedPath: "/cloudlets/v3/policies/139743/versions",
  2470  			expectedResponse: &PolicyVersion{
  2471  				CreatedDate:  *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2472  				CreatedBy:    "jsmith",
  2473  				Description:  tools.StringPtr("New version 1630480693371"),
  2474  				ModifiedBy:   "jsmith",
  2475  				ModifiedDate: newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2476  				MatchRules: MatchRules{
  2477  					&MatchRuleFR{
  2478  						ForwardSettings: ForwardSettingsFR{
  2479  							PathAndQS:              "/test_images/otherimage.jpg",
  2480  							UseIncomingQueryString: true,
  2481  						},
  2482  						Matches: []MatchCriteriaFR{
  2483  							{
  2484  								CaseSensitive: false,
  2485  								MatchOperator: "equals",
  2486  								MatchType:     "method",
  2487  								Negate:        false,
  2488  								ObjectMatchValue: &ObjectMatchValueSimple{
  2489  									Type:  "simple",
  2490  									Value: []string{"GET"},
  2491  								},
  2492  							},
  2493  						},
  2494  						Start: 0,
  2495  						End:   0,
  2496  						Type:  "frMatchRule",
  2497  						Name:  "rul3",
  2498  						ID:    0,
  2499  					},
  2500  				},
  2501  				PolicyID:      139743,
  2502  				PolicyVersion: 798,
  2503  			},
  2504  		},
  2505  		"201 created, complex AP with objectMatchValue - simple": {
  2506  			request: CreatePolicyVersionRequest{
  2507  				CreatePolicyVersion: CreatePolicyVersion{
  2508  					MatchRules: MatchRules{
  2509  						&MatchRuleAP{
  2510  							Start:              0,
  2511  							End:                0,
  2512  							Type:               "apMatchRule",
  2513  							Name:               "rul3",
  2514  							PassThroughPercent: tools.Float64Ptr(0),
  2515  							ID:                 0,
  2516  							Matches: []MatchCriteriaAP{
  2517  								{
  2518  									CaseSensitive: true,
  2519  									MatchOperator: "equals",
  2520  									MatchType:     "method",
  2521  									Negate:        false,
  2522  									ObjectMatchValue: &ObjectMatchValueSimple{
  2523  										Type:  "simple",
  2524  										Value: []string{"GET"},
  2525  									},
  2526  								},
  2527  							},
  2528  						},
  2529  					},
  2530  				},
  2531  				PolicyID: 276858,
  2532  			},
  2533  			responseStatus: http.StatusCreated,
  2534  			responseBody: `{
  2535      "createdDate": "2023-10-19T08:50:47.350Z",
  2536      "createdBy": "jsmith",
  2537      "description": null,
  2538      "modifiedBy": "jsmith",
  2539      "modifiedDate": "2023-10-19T08:50:47.350Z",
  2540      "matchRules": [
  2541          {
  2542              "type": "apMatchRule",
  2543              "end": 0,
  2544              "id": 0,
  2545              "matchURL": null,
  2546              "matches": [
  2547                  {
  2548                      "caseSensitive": true,
  2549                      "matchOperator": "equals",
  2550                      "matchType": "method",
  2551                      "negate": false,
  2552                      "objectMatchValue": {
  2553                          "type": "simple",
  2554                          "value": [
  2555                              "GET"
  2556                          ]
  2557                      }
  2558                  }
  2559              ],
  2560              "name": "rul3",
  2561              "start": 0,
  2562              "useIncomingQueryString": false,
  2563  			"passThroughPercent": -1
  2564          }
  2565      ],
  2566      "policyId": 276858,
  2567      "version": 6
  2568  }`,
  2569  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  2570  			expectedResponse: &PolicyVersion{
  2571  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2572  				CreatedBy:     "jsmith",
  2573  				Description:   nil,
  2574  				ModifiedBy:    "jsmith",
  2575  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2576  				PolicyID:      276858,
  2577  				PolicyVersion: 6,
  2578  				MatchRules: MatchRules{
  2579  					&MatchRuleAP{
  2580  						Type:               "apMatchRule",
  2581  						End:                0,
  2582  						ID:                 0,
  2583  						MatchURL:           "",
  2584  						Name:               "rul3",
  2585  						PassThroughPercent: tools.Float64Ptr(-1),
  2586  						Start:              0,
  2587  						Matches: []MatchCriteriaAP{
  2588  							{
  2589  								CaseSensitive: true,
  2590  								MatchOperator: "equals",
  2591  								MatchType:     "method",
  2592  								Negate:        false,
  2593  								ObjectMatchValue: &ObjectMatchValueSimple{
  2594  									Type:  "simple",
  2595  									Value: []string{"GET"},
  2596  								},
  2597  							},
  2598  						},
  2599  					},
  2600  				},
  2601  			},
  2602  		},
  2603  		"201 created, complex AP with objectMatchValue - object": {
  2604  			request: CreatePolicyVersionRequest{
  2605  				CreatePolicyVersion: CreatePolicyVersion{
  2606  					MatchRules: MatchRules{
  2607  						&MatchRuleAP{
  2608  							Start:              0,
  2609  							End:                0,
  2610  							Type:               "apMatchRule",
  2611  							Name:               "rul3",
  2612  							PassThroughPercent: tools.Float64Ptr(-1),
  2613  							ID:                 0,
  2614  							Matches: []MatchCriteriaAP{
  2615  								{
  2616  									CaseSensitive: false,
  2617  									MatchOperator: "equals",
  2618  									MatchType:     "header",
  2619  									Negate:        false,
  2620  									ObjectMatchValue: &ObjectMatchValueObject{
  2621  										Type: "object",
  2622  										Name: "AP",
  2623  										Options: &Options{
  2624  											Value:            []string{"y"},
  2625  											ValueHasWildcard: true,
  2626  										},
  2627  									},
  2628  								},
  2629  							},
  2630  						},
  2631  					},
  2632  				},
  2633  				PolicyID: 276858,
  2634  			},
  2635  			responseStatus: http.StatusCreated,
  2636  			responseBody: `{
  2637      "createdDate": "2023-10-19T08:50:47.350Z",
  2638      "createdBy": "jsmith",
  2639      "description": null,
  2640      "modifiedBy": "jsmith",
  2641      "modifiedDate": null,
  2642      "matchRules": [
  2643          {
  2644              "type": "apMatchRule",
  2645              "end": 0,
  2646              "id": 0,
  2647              "matchURL": null,
  2648              "matches": [
  2649                  {
  2650                      "caseSensitive": false,
  2651                      "matchOperator": "equals",
  2652                      "matchType": "header",
  2653                      "negate": false,
  2654                      "objectMatchValue": {
  2655                          "type": "object",
  2656                          "name": "AP",
  2657  						"options": {
  2658                              "value": [
  2659                                  "y"
  2660                              ],
  2661                              "valueHasWildcard": true
  2662                          }
  2663                      }
  2664                  }
  2665              ],
  2666              "name": "rul3",
  2667              "start": 0,
  2668  			"passThroughPercent": -1
  2669          }
  2670      ],
  2671      "policyId": 276858,
  2672      "version": 6
  2673  }`,
  2674  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  2675  			expectedResponse: &PolicyVersion{
  2676  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2677  				CreatedBy:     "jsmith",
  2678  				Description:   nil,
  2679  				ModifiedBy:    "jsmith",
  2680  				ModifiedDate:  nil,
  2681  				PolicyID:      276858,
  2682  				PolicyVersion: 6,
  2683  				MatchRules: MatchRules{
  2684  					&MatchRuleAP{
  2685  						Type:               "apMatchRule",
  2686  						End:                0,
  2687  						ID:                 0,
  2688  						MatchURL:           "",
  2689  						Name:               "rul3",
  2690  						PassThroughPercent: tools.Float64Ptr(-1),
  2691  						Start:              0,
  2692  						Matches: []MatchCriteriaAP{
  2693  							{
  2694  								CaseSensitive: false,
  2695  								MatchOperator: "equals",
  2696  								MatchType:     "header",
  2697  								Negate:        false,
  2698  								ObjectMatchValue: &ObjectMatchValueObject{
  2699  									Type: "object",
  2700  									Name: "AP",
  2701  									Options: &Options{
  2702  										Value:            []string{"y"},
  2703  										ValueHasWildcard: true,
  2704  									},
  2705  								},
  2706  							},
  2707  						},
  2708  					},
  2709  				},
  2710  			},
  2711  		},
  2712  		"201 created, complex RC": {
  2713  			request: CreatePolicyVersionRequest{
  2714  				CreatePolicyVersion: CreatePolicyVersion{
  2715  					MatchRules: MatchRules{
  2716  						&MatchRuleRC{
  2717  							Start:     0,
  2718  							End:       0,
  2719  							Type:      "igMatchRule",
  2720  							Name:      "rul3",
  2721  							AllowDeny: DenyBranded,
  2722  							ID:        0,
  2723  							Matches: []MatchCriteriaRC{
  2724  								{
  2725  									CaseSensitive: false,
  2726  									MatchOperator: "equals",
  2727  									MatchType:     "protocol",
  2728  									MatchValue:    "https",
  2729  									Negate:        false,
  2730  								},
  2731  								{
  2732  									CaseSensitive: true,
  2733  									MatchOperator: "equals",
  2734  									MatchType:     "method",
  2735  									Negate:        false,
  2736  									ObjectMatchValue: &ObjectMatchValueSimple{
  2737  										Type:  "simple",
  2738  										Value: []string{"GET"},
  2739  									},
  2740  								},
  2741  								{
  2742  									MatchOperator: "equals",
  2743  									MatchType:     "header",
  2744  									Negate:        false,
  2745  									ObjectMatchValue: &ObjectMatchValueObject{
  2746  										Type: "object",
  2747  										Name: "RC",
  2748  										Options: &Options{
  2749  											Value: []string{
  2750  												"text/html*",
  2751  												"text/css*",
  2752  												"application/x-javascript*",
  2753  											},
  2754  											ValueHasWildcard: true,
  2755  										},
  2756  									},
  2757  								},
  2758  							},
  2759  						},
  2760  					},
  2761  				},
  2762  				PolicyID: 276858,
  2763  			},
  2764  			responseStatus: http.StatusCreated,
  2765  			responseBody: `{
  2766      "createdDate": "2023-10-19T08:50:47.350Z",
  2767      "createdBy": "jsmith",
  2768      "description": null,
  2769      "modifiedBy": "jsmith",
  2770      "modifiedDate": "2023-10-19T08:50:47.350Z",
  2771      "matchRules": [
  2772          {
  2773              "type": "igMatchRule",
  2774              "end": 0,
  2775              "id": 0,
  2776              "matchesAlways": false,
  2777              "matches": [
  2778  				{
  2779                      "caseSensitive": false,
  2780                      "matchOperator": "equals",
  2781                      "matchType": "protocol",
  2782                      "negate": false,
  2783  					"matchValue": "https"
  2784  				},
  2785                  {
  2786                      "caseSensitive": true,
  2787                      "matchOperator": "equals",
  2788                      "matchType": "method",
  2789                      "negate": false,
  2790                      "objectMatchValue": {
  2791                          "type": "simple",
  2792                          "value": [
  2793                              "GET"
  2794                          ]
  2795                      }
  2796                  },
  2797  				{
  2798                      "matchOperator": "equals",
  2799                      "matchType": "header",
  2800                      "negate": false,
  2801  					"objectMatchValue": {
  2802                          "type": "object",
  2803                          "name": "RC",
  2804  						"options": {
  2805  							"value": [
  2806  								"text/html*",
  2807  								"text/css*",
  2808  								"application/x-javascript*"
  2809                              ],
  2810                              "valueHasWildcard": true
  2811  						}
  2812                      }
  2813  				}
  2814              ],
  2815              "name": "rul3",
  2816              "start": 0,
  2817  			"allowDeny": "denybranded"
  2818          }
  2819      ],
  2820      "policyId": 276858,
  2821      "version": 6
  2822  }`,
  2823  			expectedPath: "/cloudlets/v3/policies/276858/versions",
  2824  			expectedResponse: &PolicyVersion{
  2825  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2826  				CreatedBy:     "jsmith",
  2827  				Description:   nil,
  2828  				ModifiedBy:    "jsmith",
  2829  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  2830  				PolicyID:      276858,
  2831  				PolicyVersion: 6,
  2832  				MatchRules: MatchRules{
  2833  					&MatchRuleRC{
  2834  						Type:          "igMatchRule",
  2835  						End:           0,
  2836  						ID:            0,
  2837  						MatchesAlways: false,
  2838  						Name:          "rul3",
  2839  						AllowDeny:     DenyBranded,
  2840  						Start:         0,
  2841  						Matches: []MatchCriteriaRC{
  2842  							{
  2843  								CaseSensitive: false,
  2844  								MatchOperator: "equals",
  2845  								MatchType:     "protocol",
  2846  								MatchValue:    "https",
  2847  								Negate:        false,
  2848  							},
  2849  							{
  2850  								CaseSensitive: true,
  2851  								MatchOperator: "equals",
  2852  								MatchType:     "method",
  2853  								Negate:        false,
  2854  								ObjectMatchValue: &ObjectMatchValueSimple{
  2855  									Type:  "simple",
  2856  									Value: []string{"GET"},
  2857  								},
  2858  							},
  2859  							{
  2860  								MatchOperator: "equals",
  2861  								MatchType:     "header",
  2862  								Negate:        false,
  2863  								ObjectMatchValue: &ObjectMatchValueObject{
  2864  									Type: "object",
  2865  									Name: "RC",
  2866  									Options: &Options{
  2867  										Value: []string{
  2868  											"text/html*",
  2869  											"text/css*",
  2870  											"application/x-javascript*",
  2871  										},
  2872  										ValueHasWildcard: true,
  2873  									},
  2874  								},
  2875  							},
  2876  						},
  2877  					},
  2878  				},
  2879  			},
  2880  		},
  2881  		"validation error, complex RC with unavailable objectMatchValue type - range": {
  2882  			request: CreatePolicyVersionRequest{
  2883  				CreatePolicyVersion: CreatePolicyVersion{
  2884  					MatchRules: MatchRules{
  2885  						&MatchRuleRC{
  2886  							Start:     0,
  2887  							End:       0,
  2888  							Type:      "igMatchRule",
  2889  							AllowDeny: Allow,
  2890  							Name:      "rul3",
  2891  							ID:        0,
  2892  							Matches: []MatchCriteriaRC{
  2893  								{
  2894  									MatchOperator: "equals",
  2895  									MatchType:     "header",
  2896  									Negate:        false,
  2897  									ObjectMatchValue: &ObjectMatchValueRange{
  2898  										Type:  "range",
  2899  										Value: []int64{1, 50},
  2900  									},
  2901  								},
  2902  							},
  2903  						},
  2904  					},
  2905  				},
  2906  				PolicyID: 276858,
  2907  			},
  2908  			withError: ErrStructValidation,
  2909  		},
  2910  		"validation error, complex AP with unavailable objectMatchValue type - range": {
  2911  			request: CreatePolicyVersionRequest{
  2912  				CreatePolicyVersion: CreatePolicyVersion{
  2913  					MatchRules: MatchRules{
  2914  						&MatchRuleAP{
  2915  							Start:              0,
  2916  							End:                0,
  2917  							Type:               "apMatchRule",
  2918  							PassThroughPercent: tools.Float64Ptr(50.50),
  2919  							Name:               "rul3",
  2920  							ID:                 0,
  2921  							Matches: []MatchCriteriaAP{
  2922  								{
  2923  									MatchOperator: "equals",
  2924  									MatchType:     "header",
  2925  									Negate:        false,
  2926  									ObjectMatchValue: &ObjectMatchValueRange{
  2927  										Type:  "range",
  2928  										Value: []int64{1, 50},
  2929  									},
  2930  								},
  2931  							},
  2932  						},
  2933  					},
  2934  				},
  2935  				PolicyID: 276858,
  2936  			},
  2937  			withError: ErrStructValidation,
  2938  		},
  2939  
  2940  		"validation error, simple RC missing allowDeny": {
  2941  			request: CreatePolicyVersionRequest{
  2942  				CreatePolicyVersion: CreatePolicyVersion{
  2943  					MatchRules: MatchRules{
  2944  						&MatchRuleRC{
  2945  							Start: 0,
  2946  							End:   0,
  2947  							Type:  "igMatchRule",
  2948  							Name:  "rul3",
  2949  							ID:    0,
  2950  						},
  2951  					},
  2952  				},
  2953  				PolicyID: 276858,
  2954  			},
  2955  			withError: ErrStructValidation,
  2956  		},
  2957  
  2958  		"validation error, simple AP missing passThrughPercent": {
  2959  			request: CreatePolicyVersionRequest{
  2960  				CreatePolicyVersion: CreatePolicyVersion{
  2961  					MatchRules: MatchRules{
  2962  						&MatchRuleAP{
  2963  							Start: 0,
  2964  							End:   0,
  2965  							Type:  "apMatchRule",
  2966  							Name:  "rul3",
  2967  							ID:    0,
  2968  						},
  2969  					},
  2970  				},
  2971  				PolicyID: 276858,
  2972  			},
  2973  			withError: ErrStructValidation,
  2974  		},
  2975  
  2976  		"validation error, simple AP passThroughPercent out of range": {
  2977  			request: CreatePolicyVersionRequest{
  2978  				CreatePolicyVersion: CreatePolicyVersion{
  2979  					MatchRules: MatchRules{
  2980  						&MatchRuleAP{
  2981  							Start:              0,
  2982  							End:                0,
  2983  							Type:               "apMatchRule",
  2984  							PassThroughPercent: tools.Float64Ptr(101),
  2985  							Name:               "rul3",
  2986  							ID:                 0,
  2987  						},
  2988  					},
  2989  				},
  2990  				PolicyID: 276858,
  2991  			},
  2992  			withError: ErrStructValidation,
  2993  		},
  2994  
  2995  		"500 internal server error": {
  2996  			request: CreatePolicyVersionRequest{
  2997  				PolicyID: 1,
  2998  			},
  2999  			responseStatus: http.StatusInternalServerError,
  3000  			responseBody: `
  3001  {
  3002    "type": "internal_error",
  3003    "title": "Internal Server Error",
  3004    "status": 500
  3005  }`,
  3006  			expectedPath: "/cloudlets/v3/policies/1/versions",
  3007  			withError: &Error{
  3008  				Type:   "internal_error",
  3009  				Title:  "Internal Server Error",
  3010  				Status: http.StatusInternalServerError,
  3011  			},
  3012  		},
  3013  	}
  3014  
  3015  	for name, test := range tests {
  3016  		name, test := name, test
  3017  		t.Run(name, func(t *testing.T) {
  3018  			t.Parallel()
  3019  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  3020  				assert.Equal(t, test.expectedPath, r.URL.String())
  3021  				assert.Equal(t, http.MethodPost, r.Method)
  3022  				if test.requestBody != "" {
  3023  					buf := new(bytes.Buffer)
  3024  					_, err := buf.ReadFrom(r.Body)
  3025  					assert.NoError(t, err)
  3026  					req := buf.String()
  3027  					assert.Equal(t, test.requestBody, req)
  3028  				}
  3029  				w.WriteHeader(test.responseStatus)
  3030  				_, err := w.Write([]byte(test.responseBody))
  3031  				assert.NoError(t, err)
  3032  			}))
  3033  			client := mockAPIClient(t, mockServer)
  3034  			result, err := client.CreatePolicyVersion(context.Background(), test.request)
  3035  			if test.withError != nil {
  3036  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  3037  				return
  3038  			}
  3039  			require.NoError(t, err)
  3040  			assert.Equal(t, test.expectedResponse, result)
  3041  		})
  3042  	}
  3043  }
  3044  
  3045  func TestDeletePolicyVersion(t *testing.T) {
  3046  	t.Parallel()
  3047  	tests := map[string]struct {
  3048  		request        DeletePolicyVersionRequest
  3049  		responseStatus int
  3050  		responseBody   string
  3051  		expectedPath   string
  3052  		withError      error
  3053  	}{
  3054  		"204 no content": {
  3055  			request: DeletePolicyVersionRequest{
  3056  				PolicyID:      276858,
  3057  				PolicyVersion: 5,
  3058  			},
  3059  			responseStatus: http.StatusNoContent,
  3060  			responseBody:   "",
  3061  			expectedPath:   "/cloudlets/v3/policies/276858/versions/5",
  3062  		},
  3063  
  3064  		"missing required fields": {
  3065  			request:   DeletePolicyVersionRequest{},
  3066  			withError: ErrStructValidation,
  3067  		},
  3068  
  3069  		"500 internal server error": {
  3070  			request: DeletePolicyVersionRequest{
  3071  				PolicyID:      1,
  3072  				PolicyVersion: 2,
  3073  			},
  3074  			responseStatus: http.StatusInternalServerError,
  3075  			responseBody: `
  3076  {
  3077    "type": "internal_error",
  3078    "title": "Internal Server Error",
  3079    "status": 500
  3080  }`,
  3081  			expectedPath: "/cloudlets/v3/policies/1/versions/2",
  3082  			withError: &Error{
  3083  				Type:   "internal_error",
  3084  				Title:  "Internal Server Error",
  3085  				Status: http.StatusInternalServerError,
  3086  			},
  3087  		},
  3088  	}
  3089  
  3090  	for name, test := range tests {
  3091  		name, test := name, test
  3092  		t.Run(name, func(t *testing.T) {
  3093  			t.Parallel()
  3094  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  3095  				assert.Equal(t, test.expectedPath, r.URL.String())
  3096  				assert.Equal(t, http.MethodDelete, r.Method)
  3097  				w.WriteHeader(test.responseStatus)
  3098  				_, err := w.Write([]byte(test.responseBody))
  3099  				assert.NoError(t, err)
  3100  			}))
  3101  			client := mockAPIClient(t, mockServer)
  3102  			err := client.DeletePolicyVersion(context.Background(), test.request)
  3103  			if test.withError != nil {
  3104  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  3105  				return
  3106  			}
  3107  			require.NoError(t, err)
  3108  		})
  3109  	}
  3110  }
  3111  
  3112  func TestUpdatePolicyVersion(t *testing.T) {
  3113  	t.Parallel()
  3114  	tests := map[string]struct {
  3115  		request          UpdatePolicyVersionRequest
  3116  		requestBody      string
  3117  		responseStatus   int
  3118  		responseBody     string
  3119  		expectedPath     string
  3120  		expectedResponse *PolicyVersion
  3121  		withError        error
  3122  	}{
  3123  		"201 updated simple ER": {
  3124  			request: UpdatePolicyVersionRequest{
  3125  				UpdatePolicyVersion: UpdatePolicyVersion{
  3126  					Description: tools.StringPtr("Updated description"),
  3127  				},
  3128  				PolicyID:      276858,
  3129  				PolicyVersion: 5,
  3130  			},
  3131  			responseStatus: http.StatusOK,
  3132  			responseBody: `
  3133  {
  3134      "createdDate": "2023-10-19T08:50:47.350Z",
  3135      "createdBy": "jsmith",
  3136      "description": "Updated description",
  3137      "modifiedBy": "jsmith",
  3138      "modifiedDate": "2023-10-19T08:50:47.350Z",
  3139      "matchRules": null,
  3140      "policyId": 276858,
  3141      "version": 5
  3142  }`,
  3143  			expectedPath: "/cloudlets/v3/policies/276858/versions/5",
  3144  			expectedResponse: &PolicyVersion{
  3145  				CreatedDate:   *newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  3146  				CreatedBy:     "jsmith",
  3147  				Description:   tools.StringPtr("Updated description"),
  3148  				ModifiedBy:    "jsmith",
  3149  				ModifiedDate:  newTimeFromString(t, "2023-10-19T08:50:47.350Z"),
  3150  				MatchRules:    nil,
  3151  				PolicyID:      276858,
  3152  				PolicyVersion: 5,
  3153  			},
  3154  		},
  3155  		"201 updated simple ER with warnings": {
  3156  			request: UpdatePolicyVersionRequest{
  3157  				UpdatePolicyVersion: UpdatePolicyVersion{
  3158  					Description: tools.StringPtr("Updated description"),
  3159  					MatchRules: MatchRules{
  3160  						&MatchRuleER{
  3161  							Name:          "er_rule",
  3162  							Type:          "erMatchRule",
  3163  							Matches:       []MatchCriteriaER{},
  3164  							MatchesAlways: false,
  3165  							StatusCode:    301,
  3166  							RedirectURL:   "/path",
  3167  						},
  3168  					},
  3169  				},
  3170  				PolicyID:      276858,
  3171  				PolicyVersion: 5,
  3172  			},
  3173  			requestBody: `
  3174  {
  3175  	"description": "Updated description",
  3176  	"id": 276858,
  3177  	"matchRules": [
  3178  		{
  3179  			"type": "erMatchRule",
  3180  			"name": "er_rule",
  3181  			"matchURL": null,
  3182  			"statusCode": 301,
  3183  			"redirectURL": "/path",
  3184  			"useIncomingQueryString": false
  3185  		}
  3186  	]
  3187  }`,
  3188  			responseStatus: http.StatusOK,
  3189  			responseBody: `
  3190  {
  3191  	"createdBy": "jsmith",
  3192  	"createdDate": "2023-10-20T09:21:04.180Z",
  3193  	"description": "Updated description",
  3194  	"id": 6552305,
  3195  	"immutable": false,
  3196  	"matchRules": [
  3197  		{
  3198  			"type": "erMatchRule",
  3199  			"id": 0,
  3200  			"name": "er_rule",
  3201  			"start": 0,
  3202  			"end": 0,
  3203  			"matchURL": null,
  3204  			"statusCode": 301,
  3205  			"redirectURL": "/path",
  3206  			"useIncomingQueryString": false
  3207  		}
  3208  	],
  3209  	"matchRulesWarnings": [
  3210  		{
  3211  			"detail": "No match match conditions.",
  3212  			"title": "Missing Match Criteria",
  3213  			"type": "/cloudlets/error-types/missing-match-criteria",
  3214  			"jsonPointer": "/matchRules/0"
  3215  		}
  3216  	],
  3217  	"modifiedBy": "jsmith",
  3218  	"modifiedDate": "2023-10-20T10:32:56.316Z",
  3219  	"policyId": 670831,
  3220  	"version": 3
  3221  }`,
  3222  			expectedPath: "/cloudlets/v3/policies/276858/versions/5",
  3223  			expectedResponse: &PolicyVersion{
  3224  				CreatedDate:  *newTimeFromString(t, "2023-10-20T09:21:04.180Z"),
  3225  				CreatedBy:    "jsmith",
  3226  				Description:  tools.StringPtr("Updated description"),
  3227  				ModifiedBy:   "jsmith",
  3228  				ModifiedDate: newTimeFromString(t, "2023-10-20T10:32:56.316Z"),
  3229  				ID:           6552305,
  3230  				MatchRules: MatchRules{
  3231  					&MatchRuleER{
  3232  						Name:          "er_rule",
  3233  						Type:          "erMatchRule",
  3234  						MatchesAlways: false,
  3235  						StatusCode:    301,
  3236  						RedirectURL:   "/path",
  3237  					},
  3238  				},
  3239  				PolicyID:      670831,
  3240  				PolicyVersion: 3,
  3241  				MatchRulesWarnings: []MatchRulesWarning{
  3242  					{
  3243  						Detail:      "No match match conditions.",
  3244  						Title:       "Missing Match Criteria",
  3245  						Type:        "/cloudlets/error-types/missing-match-criteria",
  3246  						JSONPointer: "/matchRules/0",
  3247  					},
  3248  				},
  3249  			},
  3250  		},
  3251  		"500 internal server error": {
  3252  			request: UpdatePolicyVersionRequest{
  3253  				PolicyID:      276858,
  3254  				PolicyVersion: 3,
  3255  			},
  3256  			responseStatus: http.StatusInternalServerError,
  3257  			responseBody: `
  3258  {
  3259    "type": "internal_error",
  3260    "title": "Internal Server Error",
  3261    "status": 500
  3262  }`,
  3263  			expectedPath: "/cloudlets/v3/policies/276858/versions/3",
  3264  			withError: &Error{
  3265  				Type:   "internal_error",
  3266  				Title:  "Internal Server Error",
  3267  				Status: http.StatusInternalServerError,
  3268  			},
  3269  		},
  3270  		"validation error": {
  3271  			expectedPath: "/cloudlets/v3/policies/0",
  3272  			request: UpdatePolicyVersionRequest{
  3273  				UpdatePolicyVersion: UpdatePolicyVersion{
  3274  					Description: tools.StringPtr(strings.Repeat("A", 256)),
  3275  				},
  3276  			},
  3277  			withError: ErrStructValidation,
  3278  		},
  3279  	}
  3280  
  3281  	for name, test := range tests {
  3282  		name, test := name, test
  3283  		t.Run(name, func(t *testing.T) {
  3284  			t.Parallel()
  3285  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  3286  				assert.Equal(t, test.expectedPath, r.URL.String())
  3287  				assert.Equal(t, http.MethodPut, r.Method)
  3288  				w.WriteHeader(test.responseStatus)
  3289  				_, err := w.Write([]byte(test.responseBody))
  3290  				assert.NoError(t, err)
  3291  			}))
  3292  			client := mockAPIClient(t, mockServer)
  3293  			result, err := client.UpdatePolicyVersion(context.Background(), test.request)
  3294  			if test.withError != nil {
  3295  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  3296  				return
  3297  			}
  3298  			require.NoError(t, err)
  3299  			assert.Equal(t, test.expectedResponse, result)
  3300  		})
  3301  	}
  3302  }