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

     1  package v3
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  	"github.com/tj/assert"
    11  
    12  	"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools"
    13  )
    14  
    15  func TestUnmarshalJSONMatchRules(t *testing.T) {
    16  	tests := map[string]struct {
    17  		withError      error
    18  		responseBody   string
    19  		expectedObject MatchRules
    20  	}{
    21  		"invalid MatchRuleXX": {
    22  			responseBody: `
    23  	[
    24          {
    25              "type": "xxMatchRule"
    26          }
    27      ]
    28  `,
    29  			withError: errors.New("unmarshalling MatchRules: unsupported match rule type: xxMatchRule"),
    30  		},
    31  
    32  		"invalid type": {
    33  			withError: errors.New("unmarshalling MatchRules: 'type' field on match rule entry should be a string"),
    34  			responseBody: `
    35  	[
    36          {
    37              "type": 1
    38          }
    39      ]
    40  `,
    41  		},
    42  
    43  		"invalid JSON": {
    44  			withError: errors.New("unexpected end of JSON input"),
    45  			responseBody: `
    46  	[
    47          {
    48              "type": "erMatchRule"
    49          }
    50      
    51  `,
    52  		},
    53  
    54  		"missing type": {
    55  			withError: errors.New("unmarshalling MatchRules: match rule entry should contain 'type' field"),
    56  			responseBody: `
    57  	[
    58          {
    59          }
    60      ]
    61  `,
    62  		},
    63  
    64  		"invalid objectMatchValue type for PR - range": {
    65  			withError: errors.New("unmarshalling MatchRules: unmarshalling MatchCriteriaPR: objectMatchValue has unexpected type: 'range'"),
    66  			responseBody: `
    67  	[
    68          {
    69              "type": "cdMatchRule",
    70              "matches": [
    71                  {
    72                      "caseSensitive": false,
    73                      "matchOperator": "equals",
    74                      "matchType": "method",
    75                      "negate": false,
    76                      "objectMatchValue": {
    77                          "type": "range",
    78                          "value": [
    79                              1,
    80                              50
    81                          ]
    82                      }
    83                  }
    84              ],
    85              "name": "Rule3",
    86              "start": 0
    87          }
    88      ]
    89  `,
    90  		},
    91  
    92  		"invalid objectMatchValue type for ER - range": {
    93  			withError: errors.New("unmarshalling MatchRules: unmarshalling MatchCriteriaER: objectMatchValue has unexpected type: 'range'"),
    94  			responseBody: `
    95  	[
    96          {
    97              "type": "erMatchRule",
    98              "matches": [
    99                  {
   100                      "caseSensitive": false,
   101                      "matchOperator": "equals",
   102                      "matchType": "method",
   103                      "negate": false,
   104                      "objectMatchValue": {
   105                          "type": "range",
   106                          "value": [
   107                              1,
   108                              50
   109                          ]
   110                      }
   111                  }
   112              ],
   113              "name": "Rule3",
   114              "start": 0
   115          }
   116      ]
   117  `,
   118  		},
   119  
   120  		"invalid objectMatchValue type for FR - range": {
   121  			withError: errors.New("unmarshalling MatchRules: unmarshalling MatchCriteriaFR: objectMatchValue has unexpected type: 'range'"),
   122  			responseBody: `
   123  	[
   124          {
   125              "type": "frMatchRule",
   126              "matches": [
   127                  {
   128                      "caseSensitive": false,
   129                      "matchOperator": "equals",
   130                      "matchType": "method",
   131                      "negate": false,
   132                      "objectMatchValue": {
   133                          "type": "range",
   134                          "value": [
   135                              1,
   136                              50
   137                          ]
   138                      }
   139                  }
   140              ],
   141              "name": "Rule3",
   142              "start": 0
   143          }
   144      ]
   145  `,
   146  		},
   147  
   148  		"valid MatchRulePR": {
   149  			responseBody: `
   150  	[
   151          {
   152              "type": "cdMatchRule",
   153              "end": 0,
   154              "id": 0,
   155              "matchURL": null,
   156              "forwardSettings": {
   157                  "originId": "fr_test_krk_dc2",
   158                  "percent": 62
   159              },
   160  			"matches": [
   161                  {
   162                      "caseSensitive": false,
   163                      "matchOperator": "equals",
   164                      "matchType": "protocol",
   165                      "matchValue": "https",
   166                      "negate": false
   167                  },
   168                  {
   169                      "caseSensitive": false,
   170                      "matchOperator": "equals",
   171                      "matchType": "method",
   172                      "negate": false,
   173                      "objectMatchValue": {
   174                          "type": "simple",
   175                          "value": [
   176                              "GET"
   177                          ]
   178                      }
   179                  }
   180              ],
   181              "name": "Rule3",
   182              "start": 0
   183          }
   184      ]
   185  `,
   186  			expectedObject: MatchRules{
   187  				&MatchRulePR{
   188  					Type:     "cdMatchRule",
   189  					End:      0,
   190  					ID:       0,
   191  					MatchURL: "",
   192  					Matches: []MatchCriteriaPR{
   193  						{
   194  							CaseSensitive: false,
   195  							MatchOperator: "equals",
   196  							MatchType:     "protocol",
   197  							MatchValue:    "https",
   198  							Negate:        false,
   199  						},
   200  						{
   201  							CaseSensitive: false,
   202  							MatchOperator: "equals",
   203  							MatchType:     "method",
   204  							Negate:        false,
   205  							ObjectMatchValue: &ObjectMatchValueSimple{
   206  								Type:  "simple",
   207  								Value: []string{"GET"},
   208  							},
   209  						},
   210  					},
   211  					Name:  "Rule3",
   212  					Start: 0,
   213  					ForwardSettings: ForwardSettingsPR{
   214  						OriginID: "fr_test_krk_dc2",
   215  						Percent:  62,
   216  					},
   217  				},
   218  			},
   219  		},
   220  
   221  		"valid MatchRuleFR": {
   222  			responseBody: `
   223  	[
   224          {
   225              "type": "frMatchRule",
   226              "end": 0,
   227              "id": 0,
   228              "matchURL": null,
   229  			"forwardSettings": {},
   230  			"matches": [
   231                  {
   232                      "caseSensitive": false,
   233                      "matchOperator": "equals",
   234                      "matchType": "protocol",
   235                      "matchValue": "https",
   236                      "negate": false
   237                  },
   238                  {
   239                      "caseSensitive": false,
   240                      "matchOperator": "equals",
   241                      "matchType": "method",
   242                      "negate": false,
   243                      "objectMatchValue": {
   244                          "type": "simple",
   245                          "value": [
   246                              "GET"
   247                          ]
   248                      }
   249                  }
   250              ],
   251              "name": "Rule3",
   252              "start": 0
   253          }
   254      ]
   255  `,
   256  			expectedObject: MatchRules{
   257  				&MatchRuleFR{
   258  					Type:     "frMatchRule",
   259  					End:      0,
   260  					ID:       0,
   261  					MatchURL: "",
   262  					Matches: []MatchCriteriaFR{
   263  						{
   264  							CaseSensitive: false,
   265  							MatchOperator: "equals",
   266  							MatchType:     "protocol",
   267  							MatchValue:    "https",
   268  							Negate:        false,
   269  						},
   270  						{
   271  							CaseSensitive: false,
   272  							MatchOperator: "equals",
   273  							MatchType:     "method",
   274  							Negate:        false,
   275  							ObjectMatchValue: &ObjectMatchValueSimple{
   276  								Type:  "simple",
   277  								Value: []string{"GET"},
   278  							},
   279  						},
   280  					},
   281  					Name:  "Rule3",
   282  					Start: 0,
   283  				},
   284  			},
   285  		},
   286  
   287  		"invalid objectMatchValue type for AP - range": {
   288  			withError: errors.New("unmarshalling MatchRules: unmarshalling MatchCriteriaAP: objectMatchValue has unexpected type: 'range'"),
   289  			responseBody: `
   290  	[
   291          {
   292              "type": "apMatchRule",
   293              "matches": [
   294                  {
   295                      "caseSensitive": false,
   296                      "matchOperator": "equals",
   297                      "matchType": "method",
   298                      "negate": false,
   299                      "objectMatchValue": {
   300                          "type": "range",
   301                          "value": [
   302                              1,
   303                              50
   304                          ]
   305                      }
   306                  }
   307              ],
   308              "name": "Rule3",
   309              "start": 0
   310          }
   311      ]
   312  `,
   313  		},
   314  
   315  		"valid MatchRuleAP": {
   316  			responseBody: `
   317  	[
   318          {
   319              "type": "apMatchRule",
   320              "end": 0,
   321              "passThroughPercent": 50.50,
   322              "id": 0,
   323              "matchURL": null,
   324  			"matches": [
   325                  {
   326                      "caseSensitive": false,
   327                      "matchOperator": "equals",
   328                      "matchType": "protocol",
   329                      "matchValue": "https",
   330                      "negate": false
   331                  },
   332                  {
   333                      "caseSensitive": false,
   334                      "matchOperator": "equals",
   335                      "matchType": "method",
   336                      "negate": false,
   337                      "objectMatchValue": {
   338                          "type": "simple",
   339                          "value": [
   340                              "GET"
   341                          ]
   342                      }
   343                  }
   344              ],
   345              "name": "Rule3",
   346              "start": 0
   347          }
   348      ]
   349  `,
   350  			expectedObject: MatchRules{
   351  				&MatchRuleAP{
   352  					Type:               "apMatchRule",
   353  					End:                0,
   354  					PassThroughPercent: tools.Float64Ptr(50.50),
   355  					ID:                 0,
   356  					MatchURL:           "",
   357  					Matches: []MatchCriteriaAP{
   358  						{
   359  							CaseSensitive: false,
   360  							MatchOperator: "equals",
   361  							MatchType:     "protocol",
   362  							MatchValue:    "https",
   363  							Negate:        false,
   364  						},
   365  						{
   366  							CaseSensitive: false,
   367  							MatchOperator: "equals",
   368  							MatchType:     "method",
   369  							Negate:        false,
   370  							ObjectMatchValue: &ObjectMatchValueSimple{
   371  								Type:  "simple",
   372  								Value: []string{"GET"},
   373  							},
   374  						},
   375  					},
   376  					Name:  "Rule3",
   377  					Start: 0,
   378  				},
   379  			},
   380  		},
   381  		"valid MatchRuleAS": {
   382  			responseBody: `
   383  	[
   384  		{
   385              "name": "rule 10",
   386              "type": "asMatchRule",
   387              "matchURL": "http://source.com/test1",
   388  
   389              "forwardSettings": {
   390                  "originId": "origin_remote_1",
   391                  "pathAndQS": "/cpaths/test1.html"
   392              },
   393  
   394              "matches": [
   395                  {
   396                      "matchType": "range",
   397                      "objectMatchValue": {
   398                          "type": "range",
   399                          "value": [  1, 100 ]
   400                      },
   401                      "matchOperator": "equals",
   402                      "negate": false,
   403                      "caseSensitive": false
   404                  },
   405                  {
   406                      "matchType": "header",
   407                      "objectMatchValue": {
   408                          "options": {
   409                              "value": [  "en" ]
   410                          },
   411                          "type": "object",
   412                          "name": "Accept-Charset"
   413                      },
   414                      "matchOperator": "equals",
   415                      "negate": false,
   416                      "caseSensitive": false
   417                  }
   418              ]
   419          }
   420  	]`,
   421  			expectedObject: MatchRules{
   422  				&MatchRuleAS{
   423  					Name:     "rule 10",
   424  					Type:     "asMatchRule",
   425  					MatchURL: "http://source.com/test1",
   426  					ForwardSettings: ForwardSettingsAS{
   427  						OriginID:  "origin_remote_1",
   428  						PathAndQS: "/cpaths/test1.html",
   429  					},
   430  					Matches: []MatchCriteriaAS{
   431  						{
   432  							MatchType: "range",
   433  							ObjectMatchValue: &ObjectMatchValueRange{
   434  								Type:  "range",
   435  								Value: []int64{1, 100},
   436  							},
   437  							MatchOperator: "equals",
   438  							CaseSensitive: false,
   439  							Negate:        false,
   440  						},
   441  						{
   442  							MatchType: "header",
   443  							ObjectMatchValue: &ObjectMatchValueObject{
   444  								Name: "Accept-Charset",
   445  								Type: "object",
   446  								Options: &Options{
   447  									Value: []string{"en"},
   448  								},
   449  							},
   450  							MatchOperator: "equals",
   451  							Negate:        false,
   452  							CaseSensitive: false,
   453  						},
   454  					},
   455  				},
   456  			},
   457  		},
   458  
   459  		"valid MatchRuleRC": {
   460  			responseBody: `
   461  	[
   462  		{
   463  			"type": "igMatchRule",
   464  			"end": 0,
   465  			"allowDeny": "allow",
   466  			"id": 0,
   467  			"matchURL": null,
   468  			"matches": [
   469  				{
   470  					"caseSensitive": false,
   471  					"matchOperator": "equals",
   472  					"matchType": "protocol",
   473  					"matchValue": "https",
   474  					"negate": false
   475  				},
   476  				{
   477  					"caseSensitive": false,
   478  					"matchOperator": "equals",
   479  					"matchType": "method",
   480  					"negate": false,
   481  					"objectMatchValue": {
   482  						"type": "simple",
   483  						"value": [
   484  							"GET"
   485  						]
   486  					}
   487  				}
   488  			],
   489  			"name": "Rule3",
   490  			"start": 0
   491  		}
   492  	]`,
   493  			expectedObject: MatchRules{
   494  				&MatchRuleRC{
   495  					Name:      "Rule3",
   496  					Type:      "igMatchRule",
   497  					AllowDeny: Allow,
   498  					Matches: []MatchCriteriaRC{
   499  						{
   500  							CaseSensitive: false,
   501  							MatchOperator: "equals",
   502  							MatchType:     "protocol",
   503  							MatchValue:    "https",
   504  							Negate:        false,
   505  						},
   506  						{
   507  							CaseSensitive: false,
   508  							MatchOperator: "equals",
   509  							MatchType:     "method",
   510  							Negate:        false,
   511  							ObjectMatchValue: &ObjectMatchValueSimple{
   512  								Type:  "simple",
   513  								Value: []string{"GET"},
   514  							},
   515  						},
   516  					},
   517  				},
   518  			},
   519  		},
   520  
   521  		"invalid objectMatchValue type for RC - range": {
   522  			withError: errors.New("unmarshalling MatchRules: unmarshalling MatchCriteriaRC: objectMatchValue has unexpected type: 'range'"),
   523  			responseBody: `
   524  	[
   525          {
   526              "type": "igMatchRule",
   527  			"allowDeny": "allow",
   528              "matches": [
   529                  {
   530                      "caseSensitive": false,
   531                      "matchOperator": "equals",
   532                      "matchType": "method",
   533                      "negate": false,
   534                      "objectMatchValue": {
   535                          "type": "range",
   536                          "value": [
   537                              1,
   538                              50
   539                          ]
   540                      }
   541                  }
   542              ],
   543              "name": "Rule3",
   544              "start": 0
   545          }
   546      ]
   547  `,
   548  		},
   549  	}
   550  
   551  	for name, test := range tests {
   552  		t.Run(name, func(t *testing.T) {
   553  			var matchRules MatchRules
   554  			err := json.Unmarshal([]byte(test.responseBody), &matchRules)
   555  
   556  			if test.withError != nil {
   557  				assert.Equal(t, test.withError.Error(), err.Error())
   558  				return
   559  			}
   560  			require.NoError(t, err)
   561  			assert.Equal(t, test.expectedObject, matchRules)
   562  		})
   563  	}
   564  }
   565  
   566  func TestGetObjectMatchValueType(t *testing.T) {
   567  	tests := map[string]struct {
   568  		withError error
   569  		input     interface{}
   570  		expected  string
   571  	}{
   572  		"success getting objectMatchValue type": {
   573  			input: map[string]interface{}{
   574  				"type":  "range",
   575  				"value": []int{1, 50},
   576  			},
   577  			expected: "range",
   578  		},
   579  		"error getting objectMatchValue type - invalid type": {
   580  			withError: errors.New("structure of objectMatchValue should be 'map', but was 'string'"),
   581  			input:     "stringType",
   582  		},
   583  		"error getting objectMatchValue type - missing type": {
   584  			withError: errors.New("objectMatchValue should contain 'type' field"),
   585  			input: map[string]interface{}{
   586  				"value": []int{1, 50},
   587  			},
   588  		},
   589  		"error getting objectMatchValue type - type not string": {
   590  			withError: errors.New("'type' should be a string"),
   591  			input: map[string]interface{}{
   592  				"type":  50,
   593  				"value": []int{1, 50},
   594  			},
   595  		},
   596  	}
   597  
   598  	for name, test := range tests {
   599  		t.Run(name, func(t *testing.T) {
   600  			objectMatchValueType, err := getObjectMatchValueType(test.input)
   601  
   602  			if test.withError != nil {
   603  				assert.Equal(t, test.withError.Error(), err.Error())
   604  				return
   605  			}
   606  			require.NoError(t, err)
   607  			assert.Equal(t, test.expected, objectMatchValueType)
   608  		})
   609  	}
   610  }
   611  
   612  func TestConvertObjectMatchValue(t *testing.T) {
   613  	tests := map[string]struct {
   614  		withError bool
   615  		input     map[string]interface{}
   616  		output    interface{}
   617  		expected  interface{}
   618  	}{
   619  		"success converting objectMatchValueRange": {
   620  			input: map[string]interface{}{
   621  				"type":  "range",
   622  				"value": []int{1, 50},
   623  			},
   624  			output: &ObjectMatchValueRange{},
   625  			expected: &ObjectMatchValueRange{
   626  				Type:  "range",
   627  				Value: []int64{1, 50},
   628  			},
   629  		},
   630  		"success converting objectMatchValueSimple": {
   631  			input: map[string]interface{}{
   632  				"type":  "simple",
   633  				"value": []string{"GET"},
   634  			},
   635  			output: &ObjectMatchValueSimple{},
   636  			expected: &ObjectMatchValueSimple{
   637  				Type:  "simple",
   638  				Value: []string{"GET"},
   639  			},
   640  		},
   641  		"success converting objectMatchValueObject": {
   642  			input: map[string]interface{}{
   643  				"type": "object",
   644  				"name": "ER",
   645  				"options": map[string]interface{}{
   646  					"value": []string{
   647  						"text/html*",
   648  						"text/css*",
   649  						"application/x-javascript*",
   650  					},
   651  					"valueHasWildcard": true,
   652  				},
   653  			},
   654  			output: &ObjectMatchValueObject{},
   655  			expected: &ObjectMatchValueObject{
   656  				Type: "object",
   657  				Name: "ER",
   658  				Options: &Options{
   659  					Value: []string{
   660  						"text/html*",
   661  						"text/css*",
   662  						"application/x-javascript*",
   663  					},
   664  					ValueHasWildcard: true,
   665  				},
   666  			},
   667  		},
   668  		"error converting objectMatchValue": {
   669  			withError: true,
   670  			input: map[string]interface{}{
   671  				"type":  "range",
   672  				"value": []int{1, 50},
   673  			},
   674  			output: &ObjectMatchValueSimple{},
   675  		},
   676  	}
   677  
   678  	for name, test := range tests {
   679  		t.Run(name, func(t *testing.T) {
   680  			convertedObjectMatchValue, err := convertObjectMatchValue(test.input, test.output)
   681  
   682  			if test.withError == true {
   683  				require.Error(t, err)
   684  				return
   685  			}
   686  			require.NoError(t, err)
   687  			assert.Equal(t, test.expected, convertedObjectMatchValue)
   688  		})
   689  	}
   690  }
   691  
   692  func TestValidateMatchRules(t *testing.T) {
   693  	tests := map[string]struct {
   694  		input     MatchRules
   695  		withError string
   696  	}{
   697  		"valid match rules AP": {
   698  			input: MatchRules{
   699  				MatchRuleAP{
   700  					Type:               "apMatchRule",
   701  					PassThroughPercent: tools.Float64Ptr(-1),
   702  				},
   703  				MatchRuleAP{
   704  					Type:               "apMatchRule",
   705  					PassThroughPercent: tools.Float64Ptr(50.5),
   706  				},
   707  				MatchRuleAP{
   708  					Type:               "apMatchRule",
   709  					PassThroughPercent: tools.Float64Ptr(0),
   710  				},
   711  				MatchRuleAP{
   712  					Type:               "apMatchRule",
   713  					PassThroughPercent: tools.Float64Ptr(100),
   714  				},
   715  			},
   716  		},
   717  		"invalid match rules AP": {
   718  			input: MatchRules{
   719  				MatchRuleAP{
   720  					Type: "matchRule",
   721  				},
   722  				MatchRuleAP{
   723  					Type:               "apMatchRule",
   724  					PassThroughPercent: tools.Float64Ptr(100.1),
   725  				},
   726  				MatchRuleAP{
   727  					Type:               "apMatchRule",
   728  					PassThroughPercent: tools.Float64Ptr(-1.1),
   729  				},
   730  			},
   731  			withError: `
   732  MatchRules[0]: {
   733  	PassThroughPercent: cannot be blank
   734  	Type: value 'matchRule' is invalid. Must be: 'apMatchRule'
   735  }
   736  MatchRules[1]: {
   737  	PassThroughPercent: must be no greater than 100
   738  }
   739  MatchRules[2]: {
   740  	PassThroughPercent: must be no less than -1
   741  }`,
   742  		},
   743  		"valid match rules AS": {
   744  			input: MatchRules{
   745  				MatchRuleAS{
   746  					Type:  "asMatchRule",
   747  					Start: 0,
   748  					End:   1,
   749  				},
   750  				MatchRuleAS{
   751  					Type: "asMatchRule",
   752  					ForwardSettings: ForwardSettingsAS{
   753  						PathAndQS: "something",
   754  						OriginID:  "something_else",
   755  					},
   756  				},
   757  			},
   758  		},
   759  		"invalid match rules AS": {
   760  			input: MatchRules{
   761  				MatchRuleAS{
   762  					Type: "matchRule",
   763  				},
   764  				MatchRuleAS{
   765  					Type:  "asMatchRule",
   766  					Start: -2,
   767  					End:   -1,
   768  					ForwardSettings: ForwardSettingsAS{
   769  						OriginID: "some_id",
   770  					},
   771  				},
   772  			},
   773  
   774  			withError: `
   775  MatchRules[0]: {
   776  	Type: value 'matchRule' is invalid. Must be: 'asMatchRule'
   777  }
   778  MatchRules[1]: {
   779  	End: must be no less than 0
   780  	Start: must be no less than 0
   781  }`,
   782  		},
   783  		"valid match rules CD": {
   784  			input: MatchRules{
   785  				MatchRulePR{
   786  					Type: "cdMatchRule",
   787  					ForwardSettings: ForwardSettingsPR{
   788  						OriginID: "testOriginID",
   789  						Percent:  100,
   790  					},
   791  				},
   792  				MatchRulePR{
   793  					Type: "cdMatchRule",
   794  					ForwardSettings: ForwardSettingsPR{
   795  						OriginID: "testOriginID",
   796  						Percent:  1,
   797  					},
   798  				},
   799  			},
   800  		},
   801  		"invalid match rules CD": {
   802  			input: MatchRules{
   803  				MatchRulePR{
   804  					Type: "matchRule",
   805  				},
   806  				MatchRulePR{
   807  					Type:            "cdMatchRule",
   808  					ForwardSettings: ForwardSettingsPR{},
   809  				},
   810  				MatchRulePR{
   811  					Type: "cdMatchRule",
   812  					ForwardSettings: ForwardSettingsPR{
   813  						OriginID: "testOriginID",
   814  						Percent:  101,
   815  					},
   816  				},
   817  				MatchRulePR{
   818  					Type: "cdMatchRule",
   819  					ForwardSettings: ForwardSettingsPR{
   820  						OriginID: "testOriginID",
   821  						Percent:  -1,
   822  					},
   823  				},
   824  				MatchRulePR{
   825  					Type: "cdMatchRule",
   826  					ForwardSettings: ForwardSettingsPR{
   827  						OriginID: "testOriginID",
   828  						Percent:  0,
   829  					},
   830  				},
   831  			},
   832  			withError: `
   833  MatchRules[0]: {
   834  	ForwardSettings.OriginID: cannot be blank
   835  	ForwardSettings.Percent: cannot be blank
   836  	Type: value 'matchRule' is invalid. Must be: 'cdMatchRule'
   837  }
   838  MatchRules[1]: {
   839  	ForwardSettings.OriginID: cannot be blank
   840  	ForwardSettings.Percent: cannot be blank
   841  }
   842  MatchRules[2]: {
   843  	ForwardSettings.Percent: must be no greater than 100
   844  }
   845  MatchRules[3]: {
   846  	ForwardSettings.Percent: must be no less than 1
   847  }
   848  MatchRules[4]: {
   849  	ForwardSettings.Percent: cannot be blank
   850  }`,
   851  		},
   852  		"valid match rules ER": {
   853  			input: MatchRules{
   854  				MatchRuleER{
   855  					Type:           "erMatchRule",
   856  					RedirectURL:    "abc.com",
   857  					UseRelativeURL: "none",
   858  					StatusCode:     301,
   859  				},
   860  				MatchRuleER{
   861  					Type:        "erMatchRule",
   862  					RedirectURL: "abc.com",
   863  					StatusCode:  301,
   864  				},
   865  				MatchRuleER{
   866  					Type:          "erMatchRule",
   867  					RedirectURL:   "abc.com",
   868  					MatchesAlways: true,
   869  					StatusCode:    301,
   870  				},
   871  				MatchRuleER{
   872  					Type:        "erMatchRule",
   873  					RedirectURL: "abc.com",
   874  					Matches: []MatchCriteriaER{
   875  						{
   876  							MatchValue: "asd",
   877  						},
   878  					},
   879  					StatusCode: 301,
   880  				},
   881  			},
   882  		},
   883  		"invalid match rules ER": {
   884  			input: MatchRules{
   885  				MatchRuleER{
   886  					Type: "matchRule",
   887  				},
   888  				MatchRuleER{
   889  					Type:           "erMatchRule",
   890  					RedirectURL:    "abc.com",
   891  					UseRelativeURL: "test",
   892  					StatusCode:     404,
   893  				},
   894  				MatchRuleER{
   895  					Type:           "erMatchRule",
   896  					RedirectURL:    "abc.com",
   897  					UseRelativeURL: "none",
   898  					StatusCode:     301,
   899  					MatchesAlways:  true,
   900  					Matches: []MatchCriteriaER{
   901  						{
   902  							MatchValue: "asd",
   903  						},
   904  					},
   905  				},
   906  			},
   907  			withError: `
   908  MatchRules[0]: {
   909  	RedirectURL: cannot be blank
   910  	StatusCode: cannot be blank
   911  	Type: value 'matchRule' is invalid. Must be: 'erMatchRule'
   912  }
   913  MatchRules[1]: {
   914  	StatusCode: value '404' is invalid. Must be one of: 301, 302, 303, 307 or 308
   915  	UseRelativeURL: value 'test' is invalid. Must be one of: 'none', 'copy_scheme_hostname', 'relative_url' or '' (empty)
   916  }
   917  MatchRules[2]: {
   918  	Matches/MatchesAlways: only one of [ "Matches", "MatchesAlways" ] can be specified
   919  }`,
   920  		},
   921  		"valid match rules FR": {
   922  			input: MatchRules{
   923  				MatchRuleFR{
   924  					Type: "frMatchRule",
   925  					ForwardSettings: ForwardSettingsFR{
   926  						PathAndQS: "test",
   927  						OriginID:  "testOriginID",
   928  					},
   929  				},
   930  				MatchRuleFR{
   931  					Type: "frMatchRule",
   932  					ForwardSettings: ForwardSettingsFR{
   933  						PathAndQS: "test",
   934  						OriginID:  "testOriginID",
   935  					},
   936  				},
   937  			},
   938  		},
   939  		"invalid match rules FR": {
   940  			input: MatchRules{
   941  				MatchRuleFR{
   942  					Type: "matchRule",
   943  				},
   944  				MatchRuleFR{
   945  					Type: "frMatchRule",
   946  					ForwardSettings: ForwardSettingsFR{
   947  						OriginID:  "testOriginID",
   948  						PathAndQS: "",
   949  					},
   950  				},
   951  			},
   952  			withError: `
   953  MatchRules[0]: {
   954  	Type: value 'matchRule' is invalid. Must be: 'frMatchRule'
   955  }`,
   956  		},
   957  		"valid match rules RC": {
   958  			input: MatchRules{
   959  				MatchRuleRC{
   960  					Type:      "igMatchRule",
   961  					AllowDeny: Allow,
   962  				},
   963  				MatchRuleRC{
   964  					Type:      "igMatchRule",
   965  					AllowDeny: Deny,
   966  				},
   967  				MatchRuleRC{
   968  					Type:      "igMatchRule",
   969  					AllowDeny: DenyBranded,
   970  				},
   971  			},
   972  		},
   973  		"invalid match rules RC": {
   974  			input: MatchRules{
   975  				MatchRuleRC{
   976  					Type: "invalidMatchRule",
   977  				},
   978  				MatchRuleRC{
   979  					Type:      "igMatchRule",
   980  					AllowDeny: "allowBranded",
   981  				},
   982  				MatchRuleRC{
   983  					Type:          "igMatchRule",
   984  					AllowDeny:     Allow,
   985  					MatchesAlways: true,
   986  					Matches: []MatchCriteriaRC{
   987  						{
   988  							CaseSensitive: false,
   989  							CheckIPs:      "CONNECTING_IP",
   990  							MatchOperator: "equals",
   991  							MatchType:     "clientip",
   992  							MatchValue:    "1.2.3.4",
   993  							Negate:        false,
   994  						},
   995  					},
   996  				},
   997  			},
   998  			withError: `
   999  MatchRules[0]: {
  1000  	AllowDeny: cannot be blank
  1001  	Type: value 'invalidMatchRule' is invalid. Must be: 'igMatchRule'
  1002  }
  1003  MatchRules[1]: {
  1004  	AllowDeny: value 'allowBranded' is invalid. Must be one of: 'allow', 'deny' or 'denybranded'
  1005  }
  1006  MatchRules[2]: {
  1007  	Matches/MatchesAlways: only one of [ "Matches", "MatchesAlways" ] can be specified
  1008  }`,
  1009  		},
  1010  		"valid match criteria - matchValue": {
  1011  			input: MatchRules{
  1012  				MatchRuleER{
  1013  					Type:        "erMatchRule",
  1014  					RedirectURL: "abc.com",
  1015  					StatusCode:  301,
  1016  					Matches: []MatchCriteriaER{
  1017  						{
  1018  							MatchType:     "method",
  1019  							MatchOperator: "equals",
  1020  							CheckIPs:      "CONNECTING_IP",
  1021  							MatchValue:    "https",
  1022  						},
  1023  					},
  1024  				},
  1025  			},
  1026  		},
  1027  		"valid match criteria - object match value": {
  1028  			input: MatchRules{
  1029  				MatchRuleER{
  1030  					Type:        "erMatchRule",
  1031  					RedirectURL: "abc.com",
  1032  					StatusCode:  301,
  1033  					Matches: []MatchCriteriaER{
  1034  						{
  1035  							MatchType:     "header",
  1036  							MatchOperator: "equals",
  1037  							CheckIPs:      "CONNECTING_IP",
  1038  							ObjectMatchValue: &ObjectMatchValueSimple{
  1039  								Type: "simple",
  1040  								Value: []string{
  1041  									"GET",
  1042  								},
  1043  							},
  1044  						},
  1045  					},
  1046  				},
  1047  			},
  1048  		},
  1049  		"invalid match criteria - matchValue and omv combinations": {
  1050  			input: MatchRules{
  1051  				MatchRuleER{
  1052  					Type:        "erMatchRule",
  1053  					RedirectURL: "abc.com",
  1054  					StatusCode:  301,
  1055  					Matches: []MatchCriteriaER{
  1056  						{
  1057  							MatchType:     "header",
  1058  							MatchOperator: "equals",
  1059  							CheckIPs:      "CONNECTING_IP",
  1060  							ObjectMatchValue: &ObjectMatchValueSimple{
  1061  								Type: "simple",
  1062  								Value: []string{
  1063  									"GET",
  1064  								},
  1065  							},
  1066  							MatchValue: "GET",
  1067  						},
  1068  						{
  1069  							MatchType:     "header",
  1070  							MatchOperator: "equals",
  1071  							CheckIPs:      "CONNECTING_IP",
  1072  						},
  1073  					},
  1074  				},
  1075  			},
  1076  			withError: `
  1077  MatchRules[0]: {
  1078  	Matches[0]: {
  1079  		MatchValue: must be blank when ObjectMatchValue is set
  1080  		ObjectMatchValue: must be blank when MatchValue is set
  1081  	}
  1082  	Matches[1]: {
  1083  		MatchValue: cannot be blank when ObjectMatchValue is blank
  1084  		ObjectMatchValue: cannot be blank when MatchValue is blank
  1085  	}
  1086  }`,
  1087  		},
  1088  	}
  1089  
  1090  	for name, test := range tests {
  1091  		t.Run(name, func(t *testing.T) {
  1092  			err := test.input.Validate()
  1093  			if test.withError != "" {
  1094  				require.Error(t, err)
  1095  				assert.Equal(t, strings.TrimPrefix(test.withError, "\n"), err.Error())
  1096  				return
  1097  			}
  1098  			require.NoError(t, err)
  1099  		})
  1100  	}
  1101  }