github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/papi/propertyversion_test.go (about)

     1  package papi
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  
    10  	"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestPapi_GetPropertyVersions(t *testing.T) {
    17  	tests := map[string]struct {
    18  		params           GetPropertyVersionsRequest
    19  		responseStatus   int
    20  		responseBody     string
    21  		expectedPath     string
    22  		expectedResponse *GetPropertyVersionsResponse
    23  		withError        func(*testing.T, error)
    24  	}{
    25  		"200 OK": {
    26  			params: GetPropertyVersionsRequest{
    27  				PropertyID: "propertyID",
    28  				ContractID: "contract",
    29  				GroupID:    "group",
    30  				Limit:      5,
    31  				Offset:     6,
    32  			},
    33  			responseStatus: http.StatusOK,
    34  			responseBody: `
    35  {
    36      "propertyId": "propertyID",
    37      "propertyName": "property_name",
    38      "accountId": "accountID",
    39      "contractId": "contract",
    40      "groupId": "group",
    41      "assetId": "assetID",
    42      "versions": {
    43          "items": [
    44              {
    45                  "propertyVersion": 2,
    46                  "updatedByUser": "user",
    47                  "updatedDate": "2020-09-14T19:06:13Z",
    48                  "productionStatus": "INACTIVE",
    49                  "stagingStatus": "ACTIVE",
    50                  "etag": "etag",
    51                  "productId": "productID",
    52                  "note": "version note"
    53              }
    54          ]
    55      }
    56  }`,
    57  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group&limit=5&offset=6",
    58  			expectedResponse: &GetPropertyVersionsResponse{
    59  				PropertyID:   "propertyID",
    60  				PropertyName: "property_name",
    61  				AccountID:    "accountID",
    62  				ContractID:   "contract",
    63  				GroupID:      "group",
    64  				AssetID:      "assetID",
    65  				Versions: PropertyVersionItems{
    66  					Items: []PropertyVersionGetItem{
    67  						{
    68  							Etag:             "etag",
    69  							Note:             "version note",
    70  							ProductID:        "productID",
    71  							ProductionStatus: "INACTIVE",
    72  							PropertyVersion:  2,
    73  							StagingStatus:    "ACTIVE",
    74  							UpdatedByUser:    "user",
    75  							UpdatedDate:      "2020-09-14T19:06:13Z",
    76  						}}},
    77  			},
    78  		},
    79  		"500 Internal Server Error": {
    80  			params: GetPropertyVersionsRequest{
    81  				PropertyID: "propertyID",
    82  				ContractID: "contract",
    83  				GroupID:    "group",
    84  				Limit:      5,
    85  				Offset:     6,
    86  			},
    87  			responseStatus: http.StatusInternalServerError,
    88  			responseBody: `
    89  {
    90  	"type": "internal_error",
    91      "title": "Internal Server Error",
    92      "detail": "Error fetching property versions",
    93      "status": 505
    94  }`,
    95  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group&limit=5&offset=6",
    96  			withError: func(t *testing.T, err error) {
    97  				want := &Error{
    98  					Type:       "internal_error",
    99  					Title:      "Internal Server Error",
   100  					Detail:     "Error fetching property versions",
   101  					StatusCode: http.StatusInternalServerError,
   102  				}
   103  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   104  			},
   105  		},
   106  		"empty property ID": {
   107  			params: GetPropertyVersionsRequest{
   108  				PropertyID: "",
   109  				ContractID: "contract",
   110  				GroupID:    "group",
   111  			},
   112  			withError: func(t *testing.T, err error) {
   113  				want := ErrStructValidation
   114  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   115  				assert.Contains(t, err.Error(), "PropertyID")
   116  			},
   117  		},
   118  	}
   119  
   120  	for name, test := range tests {
   121  		t.Run(name, func(t *testing.T) {
   122  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   123  				assert.Equal(t, test.expectedPath, r.URL.String())
   124  				assert.Equal(t, http.MethodGet, r.Method)
   125  				w.WriteHeader(test.responseStatus)
   126  				_, err := w.Write([]byte(test.responseBody))
   127  				assert.NoError(t, err)
   128  			}))
   129  			client := mockAPIClient(t, mockServer)
   130  			result, err := client.GetPropertyVersions(context.Background(), test.params)
   131  			if test.withError != nil {
   132  				test.withError(t, err)
   133  				return
   134  			}
   135  			require.NoError(t, err)
   136  			assert.Equal(t, test.expectedResponse, result)
   137  		})
   138  	}
   139  }
   140  
   141  func TestPapi_GetPropertyVersion(t *testing.T) {
   142  	tests := map[string]struct {
   143  		params           GetPropertyVersionRequest
   144  		responseStatus   int
   145  		responseBody     string
   146  		expectedPath     string
   147  		expectedResponse *GetPropertyVersionsResponse
   148  		withError        func(*testing.T, error)
   149  	}{
   150  		"200 OK": {
   151  			params: GetPropertyVersionRequest{
   152  				PropertyID:      "propertyID",
   153  				PropertyVersion: 2,
   154  				ContractID:      "contract",
   155  				GroupID:         "group",
   156  			},
   157  			responseStatus: http.StatusOK,
   158  			responseBody: `
   159  {
   160      "propertyId": "propertyID",
   161      "propertyName": "property_name",
   162      "accountId": "accountID",
   163      "contractId": "contract",
   164      "groupId": "group",
   165      "assetId": "assetID",
   166      "versions": {
   167          "items": [
   168              {
   169                  "propertyVersion": 2,
   170                  "updatedByUser": "user",
   171                  "updatedDate": "2020-09-14T19:06:13Z",
   172                  "productionStatus": "INACTIVE",
   173                  "stagingStatus": "ACTIVE",
   174                  "etag": "etag",
   175                  "productId": "productID",
   176                  "note": "version note"
   177              }
   178          ]
   179      }
   180  }`,
   181  			expectedPath: "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   182  			expectedResponse: &GetPropertyVersionsResponse{
   183  				PropertyID:   "propertyID",
   184  				PropertyName: "property_name",
   185  				AccountID:    "accountID",
   186  				ContractID:   "contract",
   187  				GroupID:      "group",
   188  				AssetID:      "assetID",
   189  				Versions: PropertyVersionItems{
   190  					Items: []PropertyVersionGetItem{
   191  						{
   192  							Etag:             "etag",
   193  							Note:             "version note",
   194  							ProductID:        "productID",
   195  							ProductionStatus: "INACTIVE",
   196  							PropertyVersion:  2,
   197  							StagingStatus:    "ACTIVE",
   198  							UpdatedByUser:    "user",
   199  							UpdatedDate:      "2020-09-14T19:06:13Z",
   200  						}}},
   201  				Version: PropertyVersionGetItem{
   202  
   203  					Etag:             "etag",
   204  					Note:             "version note",
   205  					ProductID:        "productID",
   206  					ProductionStatus: "INACTIVE",
   207  					PropertyVersion:  2,
   208  					StagingStatus:    "ACTIVE",
   209  					UpdatedByUser:    "user",
   210  					UpdatedDate:      "2020-09-14T19:06:13Z",
   211  				},
   212  			},
   213  		},
   214  		"version not found": {
   215  			params: GetPropertyVersionRequest{
   216  				PropertyID:      "propertyID",
   217  				PropertyVersion: 2,
   218  				ContractID:      "contract",
   219  				GroupID:         "group",
   220  			},
   221  			responseStatus: http.StatusOK,
   222  			responseBody: `
   223  {
   224      "propertyId": "propertyID",
   225      "propertyName": "property_name",
   226      "accountId": "accountID",
   227      "contractId": "contract",
   228      "groupId": "group",
   229      "assetId": "assetID",
   230      "versions": {
   231          "items": [
   232          ]
   233      }
   234  }`,
   235  			expectedPath: "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   236  			withError: func(t *testing.T, err error) {
   237  				assert.True(t, errors.Is(err, ErrNotFound), "want: %s; got: %s", ErrNotFound, err)
   238  			},
   239  		},
   240  		"500 Internal Server Error": {
   241  			params: GetPropertyVersionRequest{
   242  				PropertyID:      "propertyID",
   243  				PropertyVersion: 2,
   244  				ContractID:      "contract",
   245  				GroupID:         "group",
   246  			},
   247  			responseStatus: http.StatusInternalServerError,
   248  			responseBody: `
   249  {
   250  	"type": "internal_error",
   251      "title": "Internal Server Error",
   252      "detail": "Error fetching property version",
   253      "status": 505
   254  }`,
   255  			expectedPath: "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   256  			withError: func(t *testing.T, err error) {
   257  				want := &Error{
   258  					Type:       "internal_error",
   259  					Title:      "Internal Server Error",
   260  					Detail:     "Error fetching property version",
   261  					StatusCode: http.StatusInternalServerError,
   262  				}
   263  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   264  			},
   265  		},
   266  		"empty property ID": {
   267  			params: GetPropertyVersionRequest{
   268  				PropertyID:      "",
   269  				PropertyVersion: 2,
   270  				ContractID:      "contract",
   271  				GroupID:         "group",
   272  			},
   273  			withError: func(t *testing.T, err error) {
   274  				want := ErrStructValidation
   275  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   276  				assert.Contains(t, err.Error(), "PropertyID")
   277  			},
   278  		},
   279  		"empty property version": {
   280  			params: GetPropertyVersionRequest{
   281  				PropertyID: "propertyID",
   282  				ContractID: "contract",
   283  				GroupID:    "group",
   284  			},
   285  			withError: func(t *testing.T, err error) {
   286  				want := ErrStructValidation
   287  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   288  				assert.Contains(t, err.Error(), "PropertyVersion")
   289  			},
   290  		},
   291  	}
   292  
   293  	for name, test := range tests {
   294  		t.Run(name, func(t *testing.T) {
   295  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   296  				assert.Equal(t, test.expectedPath, r.URL.String())
   297  				assert.Equal(t, http.MethodGet, r.Method)
   298  				w.WriteHeader(test.responseStatus)
   299  				_, err := w.Write([]byte(test.responseBody))
   300  				assert.NoError(t, err)
   301  			}))
   302  			client := mockAPIClient(t, mockServer)
   303  			result, err := client.GetPropertyVersion(context.Background(), test.params)
   304  			if test.withError != nil {
   305  				test.withError(t, err)
   306  				return
   307  			}
   308  			require.NoError(t, err)
   309  			assert.Equal(t, test.expectedResponse, result)
   310  		})
   311  	}
   312  }
   313  
   314  func TestPapi_CreatePropertyVersion(t *testing.T) {
   315  	tests := map[string]struct {
   316  		params           CreatePropertyVersionRequest
   317  		responseStatus   int
   318  		responseBody     string
   319  		expectedPath     string
   320  		expectedResponse *CreatePropertyVersionResponse
   321  		withError        func(*testing.T, error)
   322  	}{
   323  		"201 Created": {
   324  			params: CreatePropertyVersionRequest{
   325  				PropertyID: "propertyID",
   326  				ContractID: "contract",
   327  				GroupID:    "group",
   328  				Version: PropertyVersionCreate{
   329  					CreateFromVersion: 1,
   330  				},
   331  			},
   332  			responseStatus: http.StatusCreated,
   333  			responseBody: `
   334  		{
   335  		   "versionLink": "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group"
   336  		}`,
   337  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   338  			expectedResponse: &CreatePropertyVersionResponse{
   339  				VersionLink:     "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   340  				PropertyVersion: 2,
   341  			},
   342  		},
   343  		"500 Internal Server Error": {
   344  			params: CreatePropertyVersionRequest{
   345  				PropertyID: "propertyID",
   346  				ContractID: "contract",
   347  				GroupID:    "group",
   348  				Version: PropertyVersionCreate{
   349  					CreateFromVersion: 1,
   350  				},
   351  			},
   352  			responseStatus: http.StatusInternalServerError,
   353  			responseBody: `
   354  		{
   355  			"type": "internal_error",
   356  		   "title": "Internal Server Error",
   357  		   "detail": "Error creating property version",
   358  		   "status": 500
   359  		}`,
   360  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   361  			withError: func(t *testing.T, err error) {
   362  				want := &Error{
   363  					Type:       "internal_error",
   364  					Title:      "Internal Server Error",
   365  					Detail:     "Error creating property version",
   366  					StatusCode: http.StatusInternalServerError,
   367  				}
   368  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   369  			},
   370  		},
   371  		"empty property ID": {
   372  			params: CreatePropertyVersionRequest{
   373  				PropertyID: "",
   374  				ContractID: "contract",
   375  				GroupID:    "group",
   376  				Version: PropertyVersionCreate{
   377  					CreateFromVersion: 1,
   378  				},
   379  			},
   380  			withError: func(t *testing.T, err error) {
   381  				want := ErrStructValidation
   382  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   383  				assert.Contains(t, err.Error(), "PropertyID")
   384  			},
   385  		},
   386  		"empty CreateFromVersion": {
   387  			params: CreatePropertyVersionRequest{
   388  				PropertyID: "propertyID",
   389  				ContractID: "contract",
   390  				GroupID:    "group",
   391  				Version:    PropertyVersionCreate{},
   392  			},
   393  			withError: func(t *testing.T, err error) {
   394  				want := ErrStructValidation
   395  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   396  				assert.Contains(t, err.Error(), "CreateFromVersion")
   397  			},
   398  		},
   399  		"invalid location": {
   400  			params: CreatePropertyVersionRequest{
   401  				PropertyID: "propertyID",
   402  				ContractID: "contract",
   403  				GroupID:    "group",
   404  				Version: PropertyVersionCreate{
   405  					CreateFromVersion: 1,
   406  				},
   407  			},
   408  			responseStatus: http.StatusCreated,
   409  			responseBody: `
   410  {
   411      "versionLink": ":"
   412  }`,
   413  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   414  			withError: func(t *testing.T, err error) {
   415  				want := ErrInvalidResponseLink
   416  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   417  			},
   418  		},
   419  		"invalid version format": {
   420  			params: CreatePropertyVersionRequest{
   421  				PropertyID: "propertyID",
   422  				ContractID: "contract",
   423  				GroupID:    "group",
   424  				Version: PropertyVersionCreate{
   425  					CreateFromVersion: 1,
   426  				},
   427  			},
   428  			responseStatus: http.StatusCreated,
   429  			responseBody: `
   430  {
   431      "versionLink": "/papi/v1/properties/propertyID/versions/abc?contractId=contract&groupId=group"
   432  }`,
   433  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   434  			withError: func(t *testing.T, err error) {
   435  				want := ErrInvalidResponseLink
   436  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   437  			},
   438  		},
   439  	}
   440  
   441  	for name, test := range tests {
   442  		t.Run(name, func(t *testing.T) {
   443  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   444  				assert.Equal(t, test.expectedPath, r.URL.String())
   445  				assert.Equal(t, http.MethodPost, r.Method)
   446  				w.WriteHeader(test.responseStatus)
   447  				_, err := w.Write([]byte(test.responseBody))
   448  				assert.NoError(t, err)
   449  			}))
   450  			client := mockAPIClient(t, mockServer)
   451  			result, err := client.CreatePropertyVersion(context.Background(), test.params)
   452  			if test.withError != nil {
   453  				test.withError(t, err)
   454  				return
   455  			}
   456  			require.NoError(t, err)
   457  			assert.Equal(t, test.expectedResponse, result)
   458  		})
   459  	}
   460  }
   461  
   462  func TestPapi_GetLatestVersion(t *testing.T) {
   463  	tests := map[string]struct {
   464  		params           GetLatestVersionRequest
   465  		responseStatus   int
   466  		responseBody     string
   467  		expectedPath     string
   468  		expectedResponse *GetPropertyVersionsResponse
   469  		withError        func(*testing.T, error)
   470  	}{
   471  		"200 OK": {
   472  			params: GetLatestVersionRequest{
   473  				PropertyID:  "propertyID",
   474  				ActivatedOn: "STAGING",
   475  				ContractID:  "contract",
   476  				GroupID:     "group",
   477  			},
   478  			responseStatus: http.StatusOK,
   479  			expectedPath:   "/papi/v1/properties/propertyID/versions/latest?activatedOn=STAGING&contractId=contract&groupId=group",
   480  			responseBody: `
   481  {
   482      "propertyId": "propertyID",
   483      "propertyName": "property_name",
   484      "accountId": "accountID",
   485      "contractId": "contract",
   486      "groupId": "group",
   487      "assetId": "assetID",
   488      "versions": {
   489          "items": [
   490              {
   491                  "propertyVersion": 2,
   492                  "updatedByUser": "user",
   493                  "updatedDate": "2020-09-14T19:06:13Z",
   494                  "productionStatus": "INACTIVE",
   495                  "stagingStatus": "ACTIVE",
   496                  "etag": "etag",
   497                  "productId": "productID",
   498                  "note": "version note"
   499              }
   500          ]
   501      }
   502  }`,
   503  			expectedResponse: &GetPropertyVersionsResponse{
   504  				PropertyID:   "propertyID",
   505  				PropertyName: "property_name",
   506  				AccountID:    "accountID",
   507  				ContractID:   "contract",
   508  				GroupID:      "group",
   509  				AssetID:      "assetID",
   510  				Versions: PropertyVersionItems{
   511  					Items: []PropertyVersionGetItem{
   512  						{
   513  							Etag:             "etag",
   514  							Note:             "version note",
   515  							ProductID:        "productID",
   516  							ProductionStatus: "INACTIVE",
   517  							PropertyVersion:  2,
   518  							StagingStatus:    "ACTIVE",
   519  							UpdatedByUser:    "user",
   520  							UpdatedDate:      "2020-09-14T19:06:13Z",
   521  						},
   522  					},
   523  				},
   524  				Version: PropertyVersionGetItem{
   525  					Etag:             "etag",
   526  					Note:             "version note",
   527  					ProductID:        "productID",
   528  					ProductionStatus: "INACTIVE",
   529  					PropertyVersion:  2,
   530  					StagingStatus:    "ACTIVE",
   531  					UpdatedByUser:    "user",
   532  					UpdatedDate:      "2020-09-14T19:06:13Z",
   533  				},
   534  			},
   535  		},
   536  		"Version not found": {
   537  			params: GetLatestVersionRequest{
   538  				PropertyID:  "propertyID",
   539  				ActivatedOn: "STAGING",
   540  				ContractID:  "contract",
   541  				GroupID:     "group",
   542  			},
   543  			responseStatus: http.StatusOK,
   544  			expectedPath:   "/papi/v1/properties/propertyID/versions/latest?activatedOn=STAGING&contractId=contract&groupId=group",
   545  			responseBody: `
   546  {
   547      "propertyId": "propertyID",
   548      "propertyName": "property_name",
   549      "accountId": "accountID",
   550      "contractId": "contract",
   551      "groupId": "group",
   552      "assetId": "assetID",
   553      "versions": {
   554          "items": [
   555          ]
   556      }
   557  }`,
   558  			withError: func(t *testing.T, err error) {
   559  				assert.True(t, errors.Is(err, ErrNotFound), "want: %v; got: %v", ErrNotFound, err)
   560  			},
   561  		},
   562  		"500 Internal Server Error": {
   563  			params: GetLatestVersionRequest{
   564  				PropertyID: "propertyID",
   565  				ContractID: "contract",
   566  				GroupID:    "group",
   567  			},
   568  			responseStatus: http.StatusInternalServerError,
   569  			responseBody: `
   570  {
   571  	"type": "internal_error",
   572    "title": "Internal Server Error",
   573    "detail": "Error fetching latest version",
   574    "status": 500
   575  }`,
   576  			expectedPath: "/papi/v1/properties/propertyID/versions/latest?contractId=contract&groupId=group",
   577  			withError: func(t *testing.T, err error) {
   578  				want := &Error{
   579  					Type:       "internal_error",
   580  					Title:      "Internal Server Error",
   581  					Detail:     "Error fetching latest version",
   582  					StatusCode: http.StatusInternalServerError,
   583  				}
   584  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   585  			},
   586  		},
   587  		"empty property ID": {
   588  			params: GetLatestVersionRequest{
   589  				PropertyID:  "",
   590  				ActivatedOn: "STAGING",
   591  				ContractID:  "contract",
   592  				GroupID:     "group",
   593  			},
   594  			withError: func(t *testing.T, err error) {
   595  				want := ErrStructValidation
   596  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   597  				assert.Contains(t, err.Error(), "PropertyID")
   598  			},
   599  		},
   600  		"invalid ActivatedOn": {
   601  			params: GetLatestVersionRequest{
   602  				PropertyID:  "propertyID",
   603  				ActivatedOn: "test",
   604  				ContractID:  "contract",
   605  				GroupID:     "group",
   606  			},
   607  			withError: func(t *testing.T, err error) {
   608  				want := ErrStructValidation
   609  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   610  				assert.Contains(t, err.Error(), "ActivatedOn")
   611  			},
   612  		},
   613  	}
   614  
   615  	for name, test := range tests {
   616  		t.Run(name, func(t *testing.T) {
   617  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   618  				assert.Equal(t, test.expectedPath, r.URL.String())
   619  				assert.Equal(t, http.MethodGet, r.Method)
   620  				w.WriteHeader(test.responseStatus)
   621  				_, err := w.Write([]byte(test.responseBody))
   622  				assert.NoError(t, err)
   623  			}))
   624  			client := mockAPIClient(t, mockServer)
   625  			result, err := client.GetLatestVersion(context.Background(), test.params)
   626  			if test.withError != nil {
   627  				test.withError(t, err)
   628  				return
   629  			}
   630  			require.NoError(t, err)
   631  			assert.Equal(t, test.expectedResponse, result)
   632  		})
   633  	}
   634  }
   635  
   636  func TestPapi_GetAvailableBehaviors(t *testing.T) {
   637  	tests := map[string]struct {
   638  		params           GetAvailableBehaviorsRequest
   639  		responseStatus   int
   640  		responseBody     string
   641  		expectedPath     string
   642  		expectedResponse *GetBehaviorsResponse
   643  		withError        func(*testing.T, error)
   644  	}{
   645  		"200 OK": {
   646  			params: GetAvailableBehaviorsRequest{
   647  				PropertyID:      "propertyID",
   648  				PropertyVersion: 2,
   649  			},
   650  			responseStatus: http.StatusOK,
   651  			expectedPath:   "/papi/v1/properties/propertyID/versions/2/available-behaviors",
   652  			responseBody: `
   653  {
   654      "contractId": "contract",
   655      "groupId": "group",
   656      "productId": "productID",
   657      "ruleFormat": "v2020-09-15",
   658      "behaviors": {
   659          "items": [
   660              {
   661                  "name": "allHttpInCacheHierarchy",
   662                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallHttpInCacheHierarchy"
   663              },
   664              {
   665                  "name": "allowDelete",
   666                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowDelete"
   667              },
   668              {
   669                  "name": "allowOptions",
   670                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowOptions"
   671              }
   672          ]
   673      }
   674  }`,
   675  			expectedResponse: &GetBehaviorsResponse{
   676  				ContractID: "contract",
   677  				GroupID:    "group",
   678  				ProductID:  "productID",
   679  				RuleFormat: "v2020-09-15",
   680  				AvailableBehaviors: AvailableBehaviors{Items: []Behavior{
   681  					{
   682  						Name:       "allHttpInCacheHierarchy",
   683  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallHttpInCacheHierarchy",
   684  					},
   685  					{
   686  						Name:       "allowDelete",
   687  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowDelete",
   688  					},
   689  					{
   690  						Name:       "allowOptions",
   691  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowOptions",
   692  					},
   693  				}},
   694  			},
   695  		},
   696  		"200 OK with query parameters": {
   697  			params: GetAvailableBehaviorsRequest{
   698  				PropertyID:      "propertyID",
   699  				PropertyVersion: 2,
   700  				GroupID:         "groupID",
   701  				ContractID:      "contractID",
   702  			},
   703  			responseStatus: http.StatusOK,
   704  			expectedPath:   "/papi/v1/properties/propertyID/versions/2/available-behaviors?contractId=contractID&groupId=groupID",
   705  			responseBody: `
   706  {
   707      "contractId": "contract",
   708      "groupId": "group",
   709      "productId": "productID",
   710      "ruleFormat": "v2020-09-15",
   711      "behaviors": {
   712          "items": [
   713              {
   714                  "name": "allHttpInCacheHierarchy",
   715                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallHttpInCacheHierarchy"
   716              },
   717              {
   718                  "name": "allowDelete",
   719                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowDelete"
   720              },
   721              {
   722                  "name": "allowOptions",
   723                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowOptions"
   724              }
   725          ]
   726      }
   727  }`,
   728  			expectedResponse: &GetBehaviorsResponse{
   729  				ContractID: "contract",
   730  				GroupID:    "group",
   731  				ProductID:  "productID",
   732  				RuleFormat: "v2020-09-15",
   733  				AvailableBehaviors: AvailableBehaviors{Items: []Behavior{
   734  					{
   735  						Name:       "allHttpInCacheHierarchy",
   736  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallHttpInCacheHierarchy",
   737  					},
   738  					{
   739  						Name:       "allowDelete",
   740  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowDelete",
   741  					},
   742  					{
   743  						Name:       "allowOptions",
   744  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fbehaviors%2FallowOptions",
   745  					},
   746  				}},
   747  			},
   748  		},
   749  		"500 Internal Server Error": {
   750  			params: GetAvailableBehaviorsRequest{
   751  				PropertyID:      "propertyID",
   752  				PropertyVersion: 2,
   753  			},
   754  			responseStatus: http.StatusInternalServerError,
   755  			responseBody: `
   756  {
   757    "type": "internal_error",
   758    "title": "Internal Server Error",
   759    "detail": "Error fetching available behaviors",
   760    "status": 500
   761  }`,
   762  			expectedPath: "/papi/v1/properties/propertyID/versions/2/available-behaviors",
   763  			withError: func(t *testing.T, err error) {
   764  				want := &Error{
   765  					Type:       "internal_error",
   766  					Title:      "Internal Server Error",
   767  					Detail:     "Error fetching available behaviors",
   768  					StatusCode: http.StatusInternalServerError,
   769  				}
   770  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   771  			},
   772  		},
   773  		"empty property ID": {
   774  			params: GetAvailableBehaviorsRequest{
   775  				PropertyID:      "",
   776  				PropertyVersion: 2,
   777  			},
   778  			withError: func(t *testing.T, err error) {
   779  				want := ErrStructValidation
   780  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   781  				assert.Contains(t, err.Error(), "PropertyID")
   782  			},
   783  		},
   784  		"empty property version": {
   785  			params: GetAvailableBehaviorsRequest{
   786  				PropertyID: "propertyID",
   787  			},
   788  			withError: func(t *testing.T, err error) {
   789  				want := ErrStructValidation
   790  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   791  				assert.Contains(t, err.Error(), "PropertyVersion")
   792  			},
   793  		},
   794  	}
   795  
   796  	for name, test := range tests {
   797  		t.Run(name, func(t *testing.T) {
   798  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   799  				assert.Equal(t, test.expectedPath, r.URL.String())
   800  				assert.Equal(t, http.MethodGet, r.Method)
   801  				w.WriteHeader(test.responseStatus)
   802  				_, err := w.Write([]byte(test.responseBody))
   803  				assert.NoError(t, err)
   804  			}))
   805  			client := mockAPIClient(t, mockServer)
   806  			result, err := client.GetAvailableBehaviors(context.Background(), test.params)
   807  			if test.withError != nil {
   808  				test.withError(t, err)
   809  				return
   810  			}
   811  			require.NoError(t, err)
   812  			assert.Equal(t, test.expectedResponse, result)
   813  		})
   814  	}
   815  }
   816  
   817  func TestPapi_GetAvailableCriteria(t *testing.T) {
   818  	tests := map[string]struct {
   819  		params           GetAvailableCriteriaRequest
   820  		responseStatus   int
   821  		responseBody     string
   822  		expectedPath     string
   823  		expectedResponse *GetCriteriaResponse
   824  		withError        func(*testing.T, error)
   825  	}{
   826  		"200 OK": {
   827  			params: GetAvailableCriteriaRequest{
   828  				PropertyID:      "propertyID",
   829  				PropertyVersion: 2,
   830  			},
   831  			responseStatus: http.StatusOK,
   832  			expectedPath:   "/papi/v1/properties/propertyID/versions/2/available-criteria",
   833  			responseBody: `
   834  {
   835      "contractId": "contract",
   836      "groupId": "group",
   837      "productId": "productID",
   838      "ruleFormat": "v2020-09-15",
   839      "criteria": {
   840          "items": [
   841              {
   842                  "name": "bucket",
   843                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fbucket"
   844              },
   845              {
   846                  "name": "cacheability",
   847                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fcacheability"
   848              },
   849              {
   850                  "name": "chinaCdnRegion",
   851                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2FchinaCdnRegion"
   852              }
   853          ]
   854      }
   855  }`,
   856  			expectedResponse: &GetCriteriaResponse{
   857  				ContractID: "contract",
   858  				GroupID:    "group",
   859  				ProductID:  "productID",
   860  				RuleFormat: "v2020-09-15",
   861  				AvailableCriteria: AvailableCriteria{Items: []Criteria{
   862  					{
   863  						Name:       "bucket",
   864  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fbucket",
   865  					},
   866  					{
   867  						Name:       "cacheability",
   868  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fcacheability",
   869  					},
   870  					{
   871  						Name:       "chinaCdnRegion",
   872  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2FchinaCdnRegion",
   873  					},
   874  				}},
   875  			},
   876  		},
   877  		"200 OK with query parameters": {
   878  			params: GetAvailableCriteriaRequest{
   879  				PropertyID:      "propertyID",
   880  				PropertyVersion: 2,
   881  				GroupID:         "groupID",
   882  				ContractID:      "contractID",
   883  			},
   884  			responseStatus: http.StatusOK,
   885  			expectedPath:   "/papi/v1/properties/propertyID/versions/2/available-criteria?contractId=contractID&groupId=groupID",
   886  			responseBody: `
   887  {
   888      "contractId": "contract",
   889      "groupId": "group",
   890      "productId": "productID",
   891      "ruleFormat": "v2020-09-15",
   892      "criteria": {
   893          "items": [
   894              {
   895                  "name": "bucket",
   896                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fbucket"
   897              },
   898              {
   899                  "name": "cacheability",
   900                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fcacheability"
   901              },
   902              {
   903                  "name": "chinaCdnRegion",
   904                  "schemaLink": "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2FchinaCdnRegion"
   905              }
   906          ]
   907      }
   908  }`,
   909  			expectedResponse: &GetCriteriaResponse{
   910  				ContractID: "contract",
   911  				GroupID:    "group",
   912  				ProductID:  "productID",
   913  				RuleFormat: "v2020-09-15",
   914  				AvailableCriteria: AvailableCriteria{Items: []Criteria{
   915  					{
   916  						Name:       "bucket",
   917  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fbucket",
   918  					},
   919  					{
   920  						Name:       "cacheability",
   921  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2Fcacheability",
   922  					},
   923  					{
   924  						Name:       "chinaCdnRegion",
   925  						SchemaLink: "/papi/v0/schemas/products/prd_Rich_Media_Accel/latest#%2Fdefinitions%2Fcatalog%2Fcriteria%2FchinaCdnRegion",
   926  					},
   927  				}},
   928  			},
   929  		},
   930  		"500 Internal Server Error": {
   931  			params: GetAvailableCriteriaRequest{
   932  				PropertyID:      "propertyID",
   933  				PropertyVersion: 2,
   934  			},
   935  			responseStatus: http.StatusInternalServerError,
   936  			responseBody: `
   937  {
   938    "type": "internal_error",
   939    "title": "Internal Server Error",
   940    "detail": "Error fetching available behaviors",
   941    "status": 500
   942  }`,
   943  			expectedPath: "/papi/v1/properties/propertyID/versions/2/available-criteria",
   944  			withError: func(t *testing.T, err error) {
   945  				want := &Error{
   946  					Type:       "internal_error",
   947  					Title:      "Internal Server Error",
   948  					Detail:     "Error fetching available behaviors",
   949  					StatusCode: http.StatusInternalServerError,
   950  				}
   951  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   952  			},
   953  		},
   954  		"empty property ID": {
   955  			params: GetAvailableCriteriaRequest{
   956  				PropertyID:      "",
   957  				PropertyVersion: 2,
   958  			},
   959  			withError: func(t *testing.T, err error) {
   960  				want := ErrStructValidation
   961  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   962  				assert.Contains(t, err.Error(), "PropertyID")
   963  			},
   964  		},
   965  		"empty property version": {
   966  			params: GetAvailableCriteriaRequest{
   967  				PropertyID: "propertyID",
   968  			},
   969  			withError: func(t *testing.T, err error) {
   970  				want := ErrStructValidation
   971  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   972  				assert.Contains(t, err.Error(), "PropertyVersion")
   973  			},
   974  		},
   975  	}
   976  
   977  	for name, test := range tests {
   978  		t.Run(name, func(t *testing.T) {
   979  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   980  				assert.Equal(t, test.expectedPath, r.URL.String())
   981  				assert.Equal(t, http.MethodGet, r.Method)
   982  				w.WriteHeader(test.responseStatus)
   983  				_, err := w.Write([]byte(test.responseBody))
   984  				assert.NoError(t, err)
   985  			}))
   986  			client := mockAPIClient(t, mockServer)
   987  			result, err := client.GetAvailableCriteria(context.Background(), test.params)
   988  			if test.withError != nil {
   989  				test.withError(t, err)
   990  				return
   991  			}
   992  			require.NoError(t, err)
   993  			assert.Equal(t, test.expectedResponse, result)
   994  		})
   995  	}
   996  }
   997  
   998  func TestPapi_ListAvailableIncludes(t *testing.T) {
   999  	tests := map[string]struct {
  1000  		params           ListAvailableIncludesRequest
  1001  		responseStatus   int
  1002  		responseBody     string
  1003  		expectedPath     string
  1004  		expectedResponse *ListAvailableIncludesResponse
  1005  		withError        error
  1006  	}{
  1007  		"200 OK - available includes given ContractID and GroupID": {
  1008  			params: ListAvailableIncludesRequest{
  1009  				PropertyID:      "propertyID",
  1010  				PropertyVersion: 1,
  1011  				ContractID:      "ctr_1",
  1012  				GroupID:         "grp_2",
  1013  			},
  1014  			responseStatus: http.StatusOK,
  1015  			expectedPath:   "/papi/v1/properties/propertyID/versions/1/external-resources?contractId=ctr_1&groupId=grp_2",
  1016  			responseBody: `
  1017  {
  1018      "externalResources": {
  1019          "include": {
  1020              "test_include_id1": {
  1021                  "id": "test_include_id1",
  1022                  "name": "test_include1",
  1023                  "includeType": "MICROSERVICES",
  1024                  "fileName": "test_include1.xml",
  1025                  "productName": "Example_Name",
  1026                  "ruleFormat": "v2020-11-02"
  1027              },
  1028  			"test_include_id2": {
  1029                  "id": "test_include_id2",
  1030                  "name": "test_include2",
  1031                  "includeType": "MICROSERVICES",
  1032                  "fileName": "test_include2.xml",
  1033                  "productName": "Example_Name",
  1034                  "ruleFormat": "v2020-11-02"
  1035              }
  1036  		},
  1037  		"cloudletSharedPolicy": {
  1038  			"123456": {
  1039                  "cloudletType": "TESTCLOUDLETTYPE",
  1040                  "id": 123456,
  1041                  "name": "TestName123456",
  1042                  "policyType": "SHARED"
  1043              }
  1044  		},
  1045  		"availableCnames": [
  1046  			{
  1047                  "id": 123456,
  1048                  "name": "www.example.com",
  1049                  "domain": "example.net",
  1050                  "serialNumber": 123,
  1051                  "slot": null,
  1052                  "status": "Created",
  1053                  "ipv6": false,
  1054                  "useCases": [],
  1055                  "cname": "www.example.example.net",
  1056                  "isSecure": false,
  1057                  "isEdgeIPBindingEnabled": null
  1058              }
  1059  		],
  1060  		"customOverrides": {},
  1061  		"customOverrides": {},
  1062  		"blacklistedCertDomains": [
  1063  			"s3.example.com"
  1064  		],
  1065  		"availableNetStorageGroups": [
  1066  			{
  1067                  "id": 123456,
  1068                  "name": "aa-example",
  1069                  "uploadDomainName": "spm.example.example.com",
  1070                  "downloadDomainName": "spm.example.example.com",
  1071                  "cpCodeList": [
  1072                      {
  1073                          "cpCode": 123456,
  1074                          "g2oToken": null
  1075                      }
  1076                  ]
  1077              }
  1078  		],
  1079      	"availableCpCodes": [
  1080  			{
  1081                  "id": 123123,
  1082                  "description": "example-test-subgroup",
  1083                  "products": [
  1084                      "EXAMPLE"
  1085                  ],
  1086                  "createdDate": 1521566901000,
  1087                  "cpCodeLimits": null,
  1088                  "name": "example-test-subgroup"
  1089              }
  1090  		],
  1091      	"availablePolicies": {
  1092  			"applicationLoadBalancer":[
  1093  				{
  1094                      "id": 123456,
  1095                      "name": "0000000000000000_EXAMPLE_clone"
  1096                  }
  1097  			],
  1098  			"firstPartyMarketingPlus":[
  1099  				{
  1100                      "id": 123456,
  1101                      "name": "Example_Name_123456"
  1102                  }
  1103  			],
  1104  			"firstPartyMarketing":[
  1105  				{
  1106                      "id": 123456,
  1107                      "name": "Example_first_party"
  1108                  }	
  1109  			],
  1110  			"forwardRewrite":[
  1111  				{
  1112                      "id": 123456,
  1113                      "name": "ExampleName"
  1114                  }
  1115  			],
  1116  			"continuousDeployment":[
  1117  				{
  1118                      "id": 123456,
  1119                      "name": "Example_Name_123456"
  1120                  }
  1121  			],
  1122  			"requestControl":[
  1123  				{
  1124                      "id": 123456,
  1125                      "name": "EXAMPLE_MATCH_RULE_SIZE_RC"
  1126                  }
  1127  			],
  1128  			"inputValidation":[
  1129  				{
  1130                      "id": 123456,
  1131                      "name": "example_name"
  1132                  }
  1133  			],
  1134  			"visitorPrioritization":[
  1135  				{
  1136                      "id": 123456,
  1137                      "name": "0000000000000000000000_EXAMPLE"
  1138                  }
  1139  			],
  1140  			"audienceSegmentation":[
  1141  				{
  1142                      "id": 123456,
  1143                      "name": "ExampleTest"
  1144                  }
  1145  			],
  1146  			"apiPrioritization":[
  1147  				{
  1148                      "id": 123456,
  1149                      "name": "APIExampleTest"
  1150                  }
  1151  			],
  1152  			"edgeRedirector":[
  1153  				{
  1154                      "id": 123456,
  1155                      "name": "00000000_EXAMPLE"
  1156                  }
  1157  			]
  1158  		},
  1159      	"cloudletSharedPolicyVirtualWaitingRoom": {
  1160  			"123456": {
  1161                  "cloudletType": "EXAMPLETYPE",
  1162                  "id": 123456,
  1163                  "name": "example_name",
  1164                  "policyType": "SHARED"
  1165              }
  1166  		}
  1167      }
  1168  }`,
  1169  			expectedResponse: &ListAvailableIncludesResponse{
  1170  				AvailableIncludes: []ExternalIncludeData{
  1171  
  1172  					{
  1173  						IncludeID:   "test_include_id1",
  1174  						IncludeName: "test_include1",
  1175  						IncludeType: IncludeTypeMicroServices,
  1176  						FileName:    "test_include1.xml",
  1177  						ProductName: "Example_Name",
  1178  						RuleFormat:  "v2020-11-02",
  1179  					},
  1180  					{
  1181  						IncludeID:   "test_include_id2",
  1182  						IncludeName: "test_include2",
  1183  						IncludeType: IncludeTypeMicroServices,
  1184  						FileName:    "test_include2.xml",
  1185  						ProductName: "Example_Name",
  1186  						RuleFormat:  "v2020-11-02",
  1187  					},
  1188  				},
  1189  			},
  1190  		},
  1191  		"200 OK - available includes given only ContractID": {
  1192  			params: ListAvailableIncludesRequest{
  1193  				PropertyID:      "propertyID",
  1194  				PropertyVersion: 1,
  1195  				ContractID:      "ctr_1",
  1196  			},
  1197  			responseStatus: http.StatusOK,
  1198  			expectedPath:   "/papi/v1/properties/propertyID/versions/1/external-resources?contractId=ctr_1",
  1199  			responseBody: `
  1200  {
  1201      "externalResources": {
  1202          "include": {
  1203              "test_include_id1": {
  1204                  "id": "test_include_id1",
  1205                  "name": "test_include1",
  1206                  "includeType": "MICROSERVICES",
  1207                  "fileName": "test_include1.xml",
  1208                  "productName": "Example_Name",
  1209                  "ruleFormat": "v2020-11-02"
  1210              },
  1211  			"test_include_id2": {
  1212                  "id": "test_include_id2",
  1213                  "name": "test_include2",
  1214                  "includeType": "MICROSERVICES",
  1215                  "fileName": "test_include2.xml",
  1216                  "productName": "Example_Name",
  1217                  "ruleFormat": "v2020-11-02"
  1218              }
  1219  		},
  1220  		"cloudletSharedPolicy": {
  1221  			"123456": {
  1222                  "cloudletType": "TESTCLOUDLETTYPE",
  1223                  "id": 123456,
  1224                  "name": "TestName123456",
  1225                  "policyType": "SHARED"
  1226              }
  1227  		},
  1228  		"availableCnames": [
  1229  			{
  1230                  "id": 123456,
  1231                  "name": "www.example.com",
  1232                  "domain": "example.net",
  1233                  "serialNumber": 123,
  1234                  "slot": null,
  1235                  "status": "Created",
  1236                  "ipv6": false,
  1237                  "useCases": [],
  1238                  "cname": "www.example.example.net",
  1239                  "isSecure": false,
  1240                  "isEdgeIPBindingEnabled": null
  1241              }
  1242  		],
  1243  		"customOverrides": {},
  1244  		"customOverrides": {},
  1245  		"blacklistedCertDomains": [
  1246  			"s3.example.com"
  1247  		],
  1248  		"availableNetStorageGroups": [
  1249  			{
  1250                  "id": 123456,
  1251                  "name": "aa-example",
  1252                  "uploadDomainName": "spm.example.example.com",
  1253                  "downloadDomainName": "spm.example.example.com",
  1254                  "cpCodeList": [
  1255                      {
  1256                          "cpCode": 123456,
  1257                          "g2oToken": null
  1258                      }
  1259                  ]
  1260              }
  1261  		],
  1262      	"availableCpCodes": [
  1263  			{
  1264                  "id": 123123,
  1265                  "description": "example-test-subgroup",
  1266                  "products": [
  1267                      "EXAMPLE"
  1268                  ],
  1269                  "createdDate": 1521566901000,
  1270                  "cpCodeLimits": null,
  1271                  "name": "example-test-subgroup"
  1272              }
  1273  		],
  1274      	"availablePolicies": {
  1275  			"applicationLoadBalancer":[
  1276  				{
  1277                      "id": 123456,
  1278                      "name": "0000000000000000_EXAMPLE_clone"
  1279                  }
  1280  			],
  1281  			"firstPartyMarketingPlus":[
  1282  				{
  1283                      "id": 123456,
  1284                      "name": "Example_Name_123456"
  1285                  }
  1286  			],
  1287  			"firstPartyMarketing":[
  1288  				{
  1289                      "id": 123456,
  1290                      "name": "Example_first_party"
  1291                  }	
  1292  			],
  1293  			"forwardRewrite":[
  1294  				{
  1295                      "id": 123456,
  1296                      "name": "ExampleName"
  1297                  }
  1298  			],
  1299  			"continuousDeployment":[
  1300  				{
  1301                      "id": 123456,
  1302                      "name": "Example_Name_123456"
  1303                  }
  1304  			],
  1305  			"requestControl":[
  1306  				{
  1307                      "id": 123456,
  1308                      "name": "EXAMPLE_MATCH_RULE_SIZE_RC"
  1309                  }
  1310  			],
  1311  			"inputValidation":[
  1312  				{
  1313                      "id": 123456,
  1314                      "name": "example_name"
  1315                  }
  1316  			],
  1317  			"visitorPrioritization":[
  1318  				{
  1319                      "id": 123456,
  1320                      "name": "0000000000000000000000_EXAMPLE"
  1321                  }
  1322  			],
  1323  			"audienceSegmentation":[
  1324  				{
  1325                      "id": 123456,
  1326                      "name": "ExampleTest"
  1327                  }
  1328  			],
  1329  			"apiPrioritization":[
  1330  				{
  1331                      "id": 123456,
  1332                      "name": "APIExampleTest"
  1333                  }
  1334  			],
  1335  			"edgeRedirector":[
  1336  				{
  1337                      "id": 123456,
  1338                      "name": "00000000_EXAMPLE"
  1339                  }
  1340  			]
  1341  		},
  1342      	"cloudletSharedPolicyVirtualWaitingRoom": {
  1343  			"123456": {
  1344                  "cloudletType": "EXAMPLETYPE",
  1345                  "id": 123456,
  1346                  "name": "example_name",
  1347                  "policyType": "SHARED"
  1348              }
  1349  		}
  1350      }
  1351  }`,
  1352  			expectedResponse: &ListAvailableIncludesResponse{
  1353  				AvailableIncludes: []ExternalIncludeData{
  1354  
  1355  					{
  1356  						IncludeID:   "test_include_id1",
  1357  						IncludeName: "test_include1",
  1358  						IncludeType: IncludeTypeMicroServices,
  1359  						FileName:    "test_include1.xml",
  1360  						ProductName: "Example_Name",
  1361  						RuleFormat:  "v2020-11-02",
  1362  					},
  1363  					{
  1364  						IncludeID:   "test_include_id2",
  1365  						IncludeName: "test_include2",
  1366  						IncludeType: IncludeTypeMicroServices,
  1367  						FileName:    "test_include2.xml",
  1368  						ProductName: "Example_Name",
  1369  						RuleFormat:  "v2020-11-02",
  1370  					},
  1371  				},
  1372  			},
  1373  		},
  1374  		"200 OK - available includes given only GroupID": {
  1375  			params: ListAvailableIncludesRequest{
  1376  				PropertyID:      "propertyID",
  1377  				PropertyVersion: 1,
  1378  				GroupID:         "grp_2",
  1379  			},
  1380  			responseStatus: http.StatusOK,
  1381  			expectedPath:   "/papi/v1/properties/propertyID/versions/1/external-resources?groupId=grp_2",
  1382  			responseBody: `
  1383  {
  1384      "externalResources": {
  1385          "include": {
  1386              "test_include_id1": {
  1387                  "id": "test_include_id1",
  1388                  "name": "test_include1",
  1389                  "includeType": "MICROSERVICES",
  1390                  "fileName": "test_include1.xml",
  1391                  "productName": "Example_Name",
  1392                  "ruleFormat": "v2020-11-02"
  1393              },
  1394  			"test_include_id2": {
  1395                  "id": "test_include_id2",
  1396                  "name": "test_include2",
  1397                  "includeType": "MICROSERVICES",
  1398                  "fileName": "test_include2.xml",
  1399                  "productName": "Example_Name",
  1400                  "ruleFormat": "v2020-11-02"
  1401              }
  1402  		},
  1403  		"cloudletSharedPolicy": {
  1404  			"123456": {
  1405                  "cloudletType": "TESTCLOUDLETTYPE",
  1406                  "id": 123456,
  1407                  "name": "TestName123456",
  1408                  "policyType": "SHARED"
  1409              }
  1410  		},
  1411  		"availableCnames": [
  1412  			{
  1413                  "id": 123456,
  1414                  "name": "www.example.com",
  1415                  "domain": "example.net",
  1416                  "serialNumber": 123,
  1417                  "slot": null,
  1418                  "status": "Created",
  1419                  "ipv6": false,
  1420                  "useCases": [],
  1421                  "cname": "www.example.example.net",
  1422                  "isSecure": false,
  1423                  "isEdgeIPBindingEnabled": null
  1424              }
  1425  		],
  1426  		"customOverrides": {},
  1427  		"customOverrides": {},
  1428  		"blacklistedCertDomains": [
  1429  			"s3.example.com"
  1430  		],
  1431  		"availableNetStorageGroups": [
  1432  			{
  1433                  "id": 123456,
  1434                  "name": "aa-example",
  1435                  "uploadDomainName": "spm.example.example.com",
  1436                  "downloadDomainName": "spm.example.example.com",
  1437                  "cpCodeList": [
  1438                      {
  1439                          "cpCode": 123456,
  1440                          "g2oToken": null
  1441                      }
  1442                  ]
  1443              }
  1444  		],
  1445      	"availableCpCodes": [
  1446  			{
  1447                  "id": 123123,
  1448                  "description": "example-test-subgroup",
  1449                  "products": [
  1450                      "EXAMPLE"
  1451                  ],
  1452                  "createdDate": 1521566901000,
  1453                  "cpCodeLimits": null,
  1454                  "name": "example-test-subgroup"
  1455              }
  1456  		],
  1457      	"availablePolicies": {
  1458  			"applicationLoadBalancer":[
  1459  				{
  1460                      "id": 123456,
  1461                      "name": "0000000000000000_EXAMPLE_clone"
  1462                  }
  1463  			],
  1464  			"firstPartyMarketingPlus":[
  1465  				{
  1466                      "id": 123456,
  1467                      "name": "Example_Name_123456"
  1468                  }
  1469  			],
  1470  			"firstPartyMarketing":[
  1471  				{
  1472                      "id": 123456,
  1473                      "name": "Example_first_party"
  1474                  }	
  1475  			],
  1476  			"forwardRewrite":[
  1477  				{
  1478                      "id": 123456,
  1479                      "name": "ExampleName"
  1480                  }
  1481  			],
  1482  			"continuousDeployment":[
  1483  				{
  1484                      "id": 123456,
  1485                      "name": "Example_Name_123456"
  1486                  }
  1487  			],
  1488  			"requestControl":[
  1489  				{
  1490                      "id": 123456,
  1491                      "name": "EXAMPLE_MATCH_RULE_SIZE_RC"
  1492                  }
  1493  			],
  1494  			"inputValidation":[
  1495  				{
  1496                      "id": 123456,
  1497                      "name": "example_name"
  1498                  }
  1499  			],
  1500  			"visitorPrioritization":[
  1501  				{
  1502                      "id": 123456,
  1503                      "name": "0000000000000000000000_EXAMPLE"
  1504                  }
  1505  			],
  1506  			"audienceSegmentation":[
  1507  				{
  1508                      "id": 123456,
  1509                      "name": "ExampleTest"
  1510                  }
  1511  			],
  1512  			"apiPrioritization":[
  1513  				{
  1514                      "id": 123456,
  1515                      "name": "APIExampleTest"
  1516                  }
  1517  			],
  1518  			"edgeRedirector":[
  1519  				{
  1520                      "id": 123456,
  1521                      "name": "00000000_EXAMPLE"
  1522                  }
  1523  			]
  1524  		},
  1525      	"cloudletSharedPolicyVirtualWaitingRoom": {
  1526  			"123456": {
  1527                  "cloudletType": "EXAMPLETYPE",
  1528                  "id": 123456,
  1529                  "name": "example_name",
  1530                  "policyType": "SHARED"
  1531              }
  1532  		}
  1533      }
  1534  }`,
  1535  			expectedResponse: &ListAvailableIncludesResponse{
  1536  				AvailableIncludes: []ExternalIncludeData{
  1537  
  1538  					{
  1539  						IncludeID:   "test_include_id1",
  1540  						IncludeName: "test_include1",
  1541  						IncludeType: IncludeTypeMicroServices,
  1542  						FileName:    "test_include1.xml",
  1543  						ProductName: "Example_Name",
  1544  						RuleFormat:  "v2020-11-02",
  1545  					},
  1546  					{
  1547  						IncludeID:   "test_include_id2",
  1548  						IncludeName: "test_include2",
  1549  						IncludeType: IncludeTypeMicroServices,
  1550  						FileName:    "test_include2.xml",
  1551  						ProductName: "Example_Name",
  1552  						RuleFormat:  "v2020-11-02",
  1553  					},
  1554  				},
  1555  			},
  1556  		},
  1557  		"200 OK - available includes ContractID and GroupID not provided": {
  1558  			params: ListAvailableIncludesRequest{
  1559  				PropertyID:      "propertyID",
  1560  				PropertyVersion: 1,
  1561  			},
  1562  			responseStatus: http.StatusOK,
  1563  			expectedPath:   "/papi/v1/properties/propertyID/versions/1/external-resources",
  1564  			responseBody: `
  1565  {
  1566      "externalResources": {
  1567          "include": {
  1568              "test_include_id1": {
  1569                  "id": "test_include_id1",
  1570                  "name": "test_include1",
  1571                  "includeType": "MICROSERVICES",
  1572                  "fileName": "test_include1.xml",
  1573                  "productName": "Example_Name",
  1574                  "ruleFormat": "v2020-11-02"
  1575              },
  1576  			"test_include_id2": {
  1577                  "id": "test_include_id2",
  1578                  "name": "test_include2",
  1579                  "includeType": "MICROSERVICES",
  1580                  "fileName": "test_include2.xml",
  1581                  "productName": "Example_Name",
  1582                  "ruleFormat": "v2020-11-02"
  1583              }
  1584  		},
  1585  		"cloudletSharedPolicy": {
  1586  			"123456": {
  1587                  "cloudletType": "TESTCLOUDLETTYPE",
  1588                  "id": 123456,
  1589                  "name": "TestName123456",
  1590                  "policyType": "SHARED"
  1591              }
  1592  		},
  1593  		"availableCnames": [
  1594  			{
  1595                  "id": 123456,
  1596                  "name": "www.example.com",
  1597                  "domain": "example.net",
  1598                  "serialNumber": 123,
  1599                  "slot": null,
  1600                  "status": "Created",
  1601                  "ipv6": false,
  1602                  "useCases": [],
  1603                  "cname": "www.example.example.net",
  1604                  "isSecure": false,
  1605                  "isEdgeIPBindingEnabled": null
  1606              }
  1607  		],
  1608  		"customOverrides": {},
  1609  		"customOverrides": {},
  1610  		"blacklistedCertDomains": [
  1611  			"s3.example.com"
  1612  		],
  1613  		"availableNetStorageGroups": [
  1614  			{
  1615                  "id": 123456,
  1616                  "name": "aa-example",
  1617                  "uploadDomainName": "spm.example.example.com",
  1618                  "downloadDomainName": "spm.example.example.com",
  1619                  "cpCodeList": [
  1620                      {
  1621                          "cpCode": 123456,
  1622                          "g2oToken": null
  1623                      }
  1624                  ]
  1625              }
  1626  		],
  1627      	"availableCpCodes": [
  1628  			{
  1629                  "id": 123123,
  1630                  "description": "example-test-subgroup",
  1631                  "products": [
  1632                      "EXAMPLE"
  1633                  ],
  1634                  "createdDate": 1521566901000,
  1635                  "cpCodeLimits": null,
  1636                  "name": "example-test-subgroup"
  1637              }
  1638  		],
  1639      	"availablePolicies": {
  1640  			"applicationLoadBalancer":[
  1641  				{
  1642                      "id": 123456,
  1643                      "name": "0000000000000000_EXAMPLE_clone"
  1644                  }
  1645  			],
  1646  			"firstPartyMarketingPlus":[
  1647  				{
  1648                      "id": 123456,
  1649                      "name": "Example_Name_123456"
  1650                  }
  1651  			],
  1652  			"firstPartyMarketing":[
  1653  				{
  1654                      "id": 123456,
  1655                      "name": "Example_first_party"
  1656                  }	
  1657  			],
  1658  			"forwardRewrite":[
  1659  				{
  1660                      "id": 123456,
  1661                      "name": "ExampleName"
  1662                  }
  1663  			],
  1664  			"continuousDeployment":[
  1665  				{
  1666                      "id": 123456,
  1667                      "name": "Example_Name_123456"
  1668                  }
  1669  			],
  1670  			"requestControl":[
  1671  				{
  1672                      "id": 123456,
  1673                      "name": "EXAMPLE_MATCH_RULE_SIZE_RC"
  1674                  }
  1675  			],
  1676  			"inputValidation":[
  1677  				{
  1678                      "id": 123456,
  1679                      "name": "example_name"
  1680                  }
  1681  			],
  1682  			"visitorPrioritization":[
  1683  				{
  1684                      "id": 123456,
  1685                      "name": "0000000000000000000000_EXAMPLE"
  1686                  }
  1687  			],
  1688  			"audienceSegmentation":[
  1689  				{
  1690                      "id": 123456,
  1691                      "name": "ExampleTest"
  1692                  }
  1693  			],
  1694  			"apiPrioritization":[
  1695  				{
  1696                      "id": 123456,
  1697                      "name": "APIExampleTest"
  1698                  }
  1699  			],
  1700  			"edgeRedirector":[
  1701  				{
  1702                      "id": 123456,
  1703                      "name": "00000000_EXAMPLE"
  1704                  }
  1705  			]
  1706  		},
  1707      	"cloudletSharedPolicyVirtualWaitingRoom": {
  1708  			"123456": {
  1709                  "cloudletType": "EXAMPLETYPE",
  1710                  "id": 123456,
  1711                  "name": "example_name",
  1712                  "policyType": "SHARED"
  1713              }
  1714  		}
  1715      }
  1716  }`,
  1717  			expectedResponse: &ListAvailableIncludesResponse{
  1718  				AvailableIncludes: []ExternalIncludeData{
  1719  
  1720  					{
  1721  						IncludeID:   "test_include_id1",
  1722  						IncludeName: "test_include1",
  1723  						IncludeType: IncludeTypeMicroServices,
  1724  						FileName:    "test_include1.xml",
  1725  						ProductName: "Example_Name",
  1726  						RuleFormat:  "v2020-11-02",
  1727  					},
  1728  					{
  1729  						IncludeID:   "test_include_id2",
  1730  						IncludeName: "test_include2",
  1731  						IncludeType: IncludeTypeMicroServices,
  1732  						FileName:    "test_include2.xml",
  1733  						ProductName: "Example_Name",
  1734  						RuleFormat:  "v2020-11-02",
  1735  					},
  1736  				},
  1737  			},
  1738  		},
  1739  		"500 Internal Server Error": {
  1740  			params: ListAvailableIncludesRequest{
  1741  				PropertyID:      "propertyID",
  1742  				PropertyVersion: 1,
  1743  				ContractID:      "ctr_1",
  1744  				GroupID:         "grp_2",
  1745  			},
  1746  			responseStatus: http.StatusInternalServerError,
  1747  			responseBody: `
  1748  {
  1749    "type": "internal_error",
  1750    "title": "Internal Server Error",
  1751    "detail": "Error fetching available includes",
  1752    "status": 500
  1753  }`,
  1754  			expectedPath: "/papi/v1/properties/propertyID/versions/1/external-resources?contractId=ctr_1&groupId=grp_2",
  1755  			withError: &Error{
  1756  				Type:       "internal_error",
  1757  				Title:      "Internal Server Error",
  1758  				Detail:     "Error fetching available includes",
  1759  				StatusCode: http.StatusInternalServerError,
  1760  			},
  1761  		},
  1762  		"validation error - missing property ID": {
  1763  			params: ListAvailableIncludesRequest{
  1764  				PropertyVersion: 2,
  1765  				ContractID:      "ctr_1",
  1766  				GroupID:         "grp_2",
  1767  			},
  1768  			withError: ErrStructValidation,
  1769  		},
  1770  		"validation error - missing property version": {
  1771  			params: ListAvailableIncludesRequest{
  1772  				PropertyID: "propertyID",
  1773  				ContractID: "ctr_1",
  1774  				GroupID:    "grp_2",
  1775  			},
  1776  			withError: ErrStructValidation,
  1777  		},
  1778  	}
  1779  
  1780  	for name, test := range tests {
  1781  		t.Run(name, func(t *testing.T) {
  1782  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1783  				assert.Equal(t, test.expectedPath, r.URL.String())
  1784  				assert.Equal(t, http.MethodGet, r.Method)
  1785  				w.WriteHeader(test.responseStatus)
  1786  				_, err := w.Write([]byte(test.responseBody))
  1787  				assert.NoError(t, err)
  1788  			}))
  1789  			client := mockAPIClient(t, mockServer)
  1790  			result, err := client.ListAvailableIncludes(context.Background(), test.params)
  1791  			if test.withError != nil {
  1792  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  1793  				return
  1794  			}
  1795  			require.NoError(t, err)
  1796  			assert.Equal(t, len(test.expectedResponse.AvailableIncludes), len(result.AvailableIncludes))
  1797  			for _, element := range test.expectedResponse.AvailableIncludes {
  1798  				assert.Contains(t, result.AvailableIncludes, element)
  1799  			}
  1800  		})
  1801  	}
  1802  }
  1803  
  1804  func TestPapi_ListReferencedIncludes(t *testing.T) {
  1805  	tests := map[string]struct {
  1806  		params           ListReferencedIncludesRequest
  1807  		responseStatus   int
  1808  		responseBody     string
  1809  		expectedPath     string
  1810  		expectedResponse *ListReferencedIncludesResponse
  1811  		withError        error
  1812  	}{
  1813  		"200 OK": {
  1814  			params: ListReferencedIncludesRequest{
  1815  				PropertyID:      "propertyID",
  1816  				PropertyVersion: 1,
  1817  				ContractID:      "ctr_1",
  1818  				GroupID:         "grp_2",
  1819  			},
  1820  			responseStatus: http.StatusOK,
  1821  			expectedPath:   "/papi/v1/properties/propertyID/versions/1/includes?contractId=ctr_1&groupId=grp_2",
  1822  			responseBody: `
  1823  {
  1824      "includes": {
  1825          "items": [
  1826              {
  1827                  "accountId": "test_account",
  1828                  "contractId": "test_contract",
  1829                  "groupId": "test_group",
  1830                  "latestVersion": 1,
  1831                  "stagingVersion": 1,
  1832                  "productionVersion": null,
  1833                  "assetId": "test_asset",
  1834                  "includeId": "inc_123456",
  1835                  "includeName": "test_include",
  1836                  "includeType": "MICROSERVICES"
  1837              }
  1838          ]
  1839      }
  1840  }`,
  1841  			expectedResponse: &ListReferencedIncludesResponse{
  1842  				Includes: IncludeItems{
  1843  					Items: []Include{
  1844  						{
  1845  							AccountID:         "test_account",
  1846  							AssetID:           "test_asset",
  1847  							ContractID:        "test_contract",
  1848  							GroupID:           "test_group",
  1849  							IncludeID:         "inc_123456",
  1850  							IncludeName:       "test_include",
  1851  							IncludeType:       IncludeTypeMicroServices,
  1852  							LatestVersion:     1,
  1853  							ProductionVersion: nil,
  1854  							StagingVersion:    tools.IntPtr(1),
  1855  						},
  1856  					},
  1857  				},
  1858  			},
  1859  		},
  1860  		"500 Internal Server Error": {
  1861  			params: ListReferencedIncludesRequest{
  1862  				PropertyID:      "propertyID",
  1863  				PropertyVersion: 1,
  1864  				ContractID:      "ctr_1",
  1865  				GroupID:         "grp_2",
  1866  			},
  1867  			responseStatus: http.StatusInternalServerError,
  1868  			responseBody: `
  1869  {
  1870    "type": "internal_error",
  1871    "title": "Internal Server Error",
  1872    "detail": "Error fetching referenced includes",
  1873    "status": 500
  1874  }`,
  1875  			expectedPath: "/papi/v1/properties/propertyID/versions/1/includes?contractId=ctr_1&groupId=grp_2",
  1876  			withError: &Error{
  1877  				Type:       "internal_error",
  1878  				Title:      "Internal Server Error",
  1879  				Detail:     "Error fetching referenced includes",
  1880  				StatusCode: http.StatusInternalServerError,
  1881  			},
  1882  		},
  1883  		"validation error - missing property ID": {
  1884  			params: ListReferencedIncludesRequest{
  1885  				PropertyVersion: 1,
  1886  				ContractID:      "ctr_1",
  1887  				GroupID:         "grp_2",
  1888  			},
  1889  			withError: ErrStructValidation,
  1890  		},
  1891  		"validation error - missing property version": {
  1892  			params: ListReferencedIncludesRequest{
  1893  				PropertyID: "propertyID",
  1894  				ContractID: "ctr_1",
  1895  				GroupID:    "grp_2",
  1896  			},
  1897  			withError: ErrStructValidation,
  1898  		},
  1899  		"validation error - missing contractID": {
  1900  			params: ListReferencedIncludesRequest{
  1901  				PropertyID:      "propertyID",
  1902  				PropertyVersion: 1,
  1903  				GroupID:         "grp_2",
  1904  			},
  1905  			withError: ErrStructValidation,
  1906  		},
  1907  		"validation error - missing groupID": {
  1908  			params: ListReferencedIncludesRequest{
  1909  				PropertyID:      "propertyID",
  1910  				PropertyVersion: 1,
  1911  				ContractID:      "ctr_1",
  1912  			},
  1913  			withError: ErrStructValidation,
  1914  		},
  1915  	}
  1916  
  1917  	for name, test := range tests {
  1918  		t.Run(name, func(t *testing.T) {
  1919  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1920  				assert.Equal(t, test.expectedPath, r.URL.String())
  1921  				assert.Equal(t, http.MethodGet, r.Method)
  1922  				w.WriteHeader(test.responseStatus)
  1923  				_, err := w.Write([]byte(test.responseBody))
  1924  				assert.NoError(t, err)
  1925  			}))
  1926  			client := mockAPIClient(t, mockServer)
  1927  			result, err := client.ListReferencedIncludes(context.Background(), test.params)
  1928  			if test.withError != nil {
  1929  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  1930  				return
  1931  			}
  1932  			require.NoError(t, err)
  1933  			assert.Equal(t, test.expectedResponse, result)
  1934  		})
  1935  	}
  1936  }