github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.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/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestPapi_GetPropertyVersions(t *testing.T) {
    15  	tests := map[string]struct {
    16  		params           GetPropertyVersionsRequest
    17  		responseStatus   int
    18  		responseBody     string
    19  		expectedPath     string
    20  		expectedResponse *GetPropertyVersionsResponse
    21  		withError        func(*testing.T, error)
    22  	}{
    23  		"200 OK": {
    24  			params: GetPropertyVersionsRequest{
    25  				PropertyID: "propertyID",
    26  				ContractID: "contract",
    27  				GroupID:    "group",
    28  				Limit:      5,
    29  				Offset:     6,
    30  			},
    31  			responseStatus: http.StatusOK,
    32  			responseBody: `
    33  {
    34      "propertyId": "propertyID",
    35      "propertyName": "property_name",
    36      "accountId": "accountID",
    37      "contractId": "contract",
    38      "groupId": "group",
    39      "assetId": "assetID",
    40      "versions": {
    41          "items": [
    42              {
    43                  "propertyVersion": 2,
    44                  "updatedByUser": "user",
    45                  "updatedDate": "2020-09-14T19:06:13Z",
    46                  "productionStatus": "INACTIVE",
    47                  "stagingStatus": "ACTIVE",
    48                  "etag": "etag",
    49                  "productId": "productID",
    50                  "note": "version note"
    51              }
    52          ]
    53      }
    54  }`,
    55  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group&limit=5&offset=6",
    56  			expectedResponse: &GetPropertyVersionsResponse{
    57  				PropertyID:   "propertyID",
    58  				PropertyName: "property_name",
    59  				AccountID:    "accountID",
    60  				ContractID:   "contract",
    61  				GroupID:      "group",
    62  				AssetID:      "assetID",
    63  				Versions: PropertyVersionItems{
    64  					Items: []PropertyVersionGetItem{
    65  						{
    66  							Etag:             "etag",
    67  							Note:             "version note",
    68  							ProductID:        "productID",
    69  							ProductionStatus: "INACTIVE",
    70  							PropertyVersion:  2,
    71  							StagingStatus:    "ACTIVE",
    72  							UpdatedByUser:    "user",
    73  							UpdatedDate:      "2020-09-14T19:06:13Z",
    74  						}}},
    75  			},
    76  		},
    77  		"500 Internal Server Error": {
    78  			params: GetPropertyVersionsRequest{
    79  				PropertyID: "propertyID",
    80  				ContractID: "contract",
    81  				GroupID:    "group",
    82  				Limit:      5,
    83  				Offset:     6,
    84  			},
    85  			responseStatus: http.StatusInternalServerError,
    86  			responseBody: `
    87  {
    88  	"type": "internal_error",
    89      "title": "Internal Server Error",
    90      "detail": "Error fetching property versions",
    91      "status": 505
    92  }`,
    93  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group&limit=5&offset=6",
    94  			withError: func(t *testing.T, err error) {
    95  				want := &Error{
    96  					Type:       "internal_error",
    97  					Title:      "Internal Server Error",
    98  					Detail:     "Error fetching property versions",
    99  					StatusCode: http.StatusInternalServerError,
   100  				}
   101  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   102  			},
   103  		},
   104  		"empty property ID": {
   105  			params: GetPropertyVersionsRequest{
   106  				PropertyID: "",
   107  				ContractID: "contract",
   108  				GroupID:    "group",
   109  			},
   110  			withError: func(t *testing.T, err error) {
   111  				want := ErrStructValidation
   112  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   113  				assert.Contains(t, err.Error(), "PropertyID")
   114  			},
   115  		},
   116  	}
   117  
   118  	for name, test := range tests {
   119  		t.Run(name, func(t *testing.T) {
   120  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   121  				assert.Equal(t, test.expectedPath, r.URL.String())
   122  				assert.Equal(t, http.MethodGet, r.Method)
   123  				w.WriteHeader(test.responseStatus)
   124  				_, err := w.Write([]byte(test.responseBody))
   125  				assert.NoError(t, err)
   126  			}))
   127  			client := mockAPIClient(t, mockServer)
   128  			result, err := client.GetPropertyVersions(context.Background(), test.params)
   129  			if test.withError != nil {
   130  				test.withError(t, err)
   131  				return
   132  			}
   133  			require.NoError(t, err)
   134  			assert.Equal(t, test.expectedResponse, result)
   135  		})
   136  	}
   137  }
   138  
   139  func TestPapi_GetPropertyVersion(t *testing.T) {
   140  	tests := map[string]struct {
   141  		params           GetPropertyVersionRequest
   142  		responseStatus   int
   143  		responseBody     string
   144  		expectedPath     string
   145  		expectedResponse *GetPropertyVersionsResponse
   146  		withError        func(*testing.T, error)
   147  	}{
   148  		"200 OK": {
   149  			params: GetPropertyVersionRequest{
   150  				PropertyID:      "propertyID",
   151  				PropertyVersion: 2,
   152  				ContractID:      "contract",
   153  				GroupID:         "group",
   154  			},
   155  			responseStatus: http.StatusOK,
   156  			responseBody: `
   157  {
   158      "propertyId": "propertyID",
   159      "propertyName": "property_name",
   160      "accountId": "accountID",
   161      "contractId": "contract",
   162      "groupId": "group",
   163      "assetId": "assetID",
   164      "versions": {
   165          "items": [
   166              {
   167                  "propertyVersion": 2,
   168                  "updatedByUser": "user",
   169                  "updatedDate": "2020-09-14T19:06:13Z",
   170                  "productionStatus": "INACTIVE",
   171                  "stagingStatus": "ACTIVE",
   172                  "etag": "etag",
   173                  "productId": "productID",
   174                  "note": "version note"
   175              }
   176          ]
   177      }
   178  }`,
   179  			expectedPath: "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   180  			expectedResponse: &GetPropertyVersionsResponse{
   181  				PropertyID:   "propertyID",
   182  				PropertyName: "property_name",
   183  				AccountID:    "accountID",
   184  				ContractID:   "contract",
   185  				GroupID:      "group",
   186  				AssetID:      "assetID",
   187  				Versions: PropertyVersionItems{
   188  					Items: []PropertyVersionGetItem{
   189  						{
   190  							Etag:             "etag",
   191  							Note:             "version note",
   192  							ProductID:        "productID",
   193  							ProductionStatus: "INACTIVE",
   194  							PropertyVersion:  2,
   195  							StagingStatus:    "ACTIVE",
   196  							UpdatedByUser:    "user",
   197  							UpdatedDate:      "2020-09-14T19:06:13Z",
   198  						}}},
   199  				Version: PropertyVersionGetItem{
   200  
   201  					Etag:             "etag",
   202  					Note:             "version note",
   203  					ProductID:        "productID",
   204  					ProductionStatus: "INACTIVE",
   205  					PropertyVersion:  2,
   206  					StagingStatus:    "ACTIVE",
   207  					UpdatedByUser:    "user",
   208  					UpdatedDate:      "2020-09-14T19:06:13Z",
   209  				},
   210  			},
   211  		},
   212  		"version not found": {
   213  			params: GetPropertyVersionRequest{
   214  				PropertyID:      "propertyID",
   215  				PropertyVersion: 2,
   216  				ContractID:      "contract",
   217  				GroupID:         "group",
   218  			},
   219  			responseStatus: http.StatusOK,
   220  			responseBody: `
   221  {
   222      "propertyId": "propertyID",
   223      "propertyName": "property_name",
   224      "accountId": "accountID",
   225      "contractId": "contract",
   226      "groupId": "group",
   227      "assetId": "assetID",
   228      "versions": {
   229          "items": [
   230          ]
   231      }
   232  }`,
   233  			expectedPath: "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   234  			withError: func(t *testing.T, err error) {
   235  				assert.True(t, errors.Is(err, ErrNotFound), "want: %s; got: %s", ErrNotFound, err)
   236  			},
   237  		},
   238  		"500 Internal Server Error": {
   239  			params: GetPropertyVersionRequest{
   240  				PropertyID:      "propertyID",
   241  				PropertyVersion: 2,
   242  				ContractID:      "contract",
   243  				GroupID:         "group",
   244  			},
   245  			responseStatus: http.StatusInternalServerError,
   246  			responseBody: `
   247  {
   248  	"type": "internal_error",
   249      "title": "Internal Server Error",
   250      "detail": "Error fetching property version",
   251      "status": 505
   252  }`,
   253  			expectedPath: "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   254  			withError: func(t *testing.T, err error) {
   255  				want := &Error{
   256  					Type:       "internal_error",
   257  					Title:      "Internal Server Error",
   258  					Detail:     "Error fetching property version",
   259  					StatusCode: http.StatusInternalServerError,
   260  				}
   261  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   262  			},
   263  		},
   264  		"empty property ID": {
   265  			params: GetPropertyVersionRequest{
   266  				PropertyID:      "",
   267  				PropertyVersion: 2,
   268  				ContractID:      "contract",
   269  				GroupID:         "group",
   270  			},
   271  			withError: func(t *testing.T, err error) {
   272  				want := ErrStructValidation
   273  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   274  				assert.Contains(t, err.Error(), "PropertyID")
   275  			},
   276  		},
   277  		"empty property version": {
   278  			params: GetPropertyVersionRequest{
   279  				PropertyID: "propertyID",
   280  				ContractID: "contract",
   281  				GroupID:    "group",
   282  			},
   283  			withError: func(t *testing.T, err error) {
   284  				want := ErrStructValidation
   285  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   286  				assert.Contains(t, err.Error(), "PropertyVersion")
   287  			},
   288  		},
   289  	}
   290  
   291  	for name, test := range tests {
   292  		t.Run(name, func(t *testing.T) {
   293  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   294  				assert.Equal(t, test.expectedPath, r.URL.String())
   295  				assert.Equal(t, http.MethodGet, r.Method)
   296  				w.WriteHeader(test.responseStatus)
   297  				_, err := w.Write([]byte(test.responseBody))
   298  				assert.NoError(t, err)
   299  			}))
   300  			client := mockAPIClient(t, mockServer)
   301  			result, err := client.GetPropertyVersion(context.Background(), test.params)
   302  			if test.withError != nil {
   303  				test.withError(t, err)
   304  				return
   305  			}
   306  			require.NoError(t, err)
   307  			assert.Equal(t, test.expectedResponse, result)
   308  		})
   309  	}
   310  }
   311  
   312  func TestPapi_CreatePropertyVersion(t *testing.T) {
   313  	tests := map[string]struct {
   314  		params           CreatePropertyVersionRequest
   315  		responseStatus   int
   316  		responseBody     string
   317  		expectedPath     string
   318  		expectedResponse *CreatePropertyVersionResponse
   319  		withError        func(*testing.T, error)
   320  	}{
   321  		"201 Created": {
   322  			params: CreatePropertyVersionRequest{
   323  				PropertyID: "propertyID",
   324  				ContractID: "contract",
   325  				GroupID:    "group",
   326  				Version: PropertyVersionCreate{
   327  					CreateFromVersion: 1,
   328  				},
   329  			},
   330  			responseStatus: http.StatusCreated,
   331  			responseBody: `
   332  		{
   333  		   "versionLink": "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group"
   334  		}`,
   335  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   336  			expectedResponse: &CreatePropertyVersionResponse{
   337  				VersionLink:     "/papi/v1/properties/propertyID/versions/2?contractId=contract&groupId=group",
   338  				PropertyVersion: 2,
   339  			},
   340  		},
   341  		"500 Internal Server Error": {
   342  			params: CreatePropertyVersionRequest{
   343  				PropertyID: "propertyID",
   344  				ContractID: "contract",
   345  				GroupID:    "group",
   346  				Version: PropertyVersionCreate{
   347  					CreateFromVersion: 1,
   348  				},
   349  			},
   350  			responseStatus: http.StatusInternalServerError,
   351  			responseBody: `
   352  		{
   353  			"type": "internal_error",
   354  		   "title": "Internal Server Error",
   355  		   "detail": "Error creating property version",
   356  		   "status": 500
   357  		}`,
   358  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   359  			withError: func(t *testing.T, err error) {
   360  				want := &Error{
   361  					Type:       "internal_error",
   362  					Title:      "Internal Server Error",
   363  					Detail:     "Error creating property version",
   364  					StatusCode: http.StatusInternalServerError,
   365  				}
   366  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   367  			},
   368  		},
   369  		"empty property ID": {
   370  			params: CreatePropertyVersionRequest{
   371  				PropertyID: "",
   372  				ContractID: "contract",
   373  				GroupID:    "group",
   374  				Version: PropertyVersionCreate{
   375  					CreateFromVersion: 1,
   376  				},
   377  			},
   378  			withError: func(t *testing.T, err error) {
   379  				want := ErrStructValidation
   380  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   381  				assert.Contains(t, err.Error(), "PropertyID")
   382  			},
   383  		},
   384  		"empty CreateFromVersion": {
   385  			params: CreatePropertyVersionRequest{
   386  				PropertyID: "propertyID",
   387  				ContractID: "contract",
   388  				GroupID:    "group",
   389  				Version:    PropertyVersionCreate{},
   390  			},
   391  			withError: func(t *testing.T, err error) {
   392  				want := ErrStructValidation
   393  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   394  				assert.Contains(t, err.Error(), "CreateFromVersion")
   395  			},
   396  		},
   397  		"invalid location": {
   398  			params: CreatePropertyVersionRequest{
   399  				PropertyID: "propertyID",
   400  				ContractID: "contract",
   401  				GroupID:    "group",
   402  				Version: PropertyVersionCreate{
   403  					CreateFromVersion: 1,
   404  				},
   405  			},
   406  			responseStatus: http.StatusCreated,
   407  			responseBody: `
   408  {
   409      "versionLink": ":"
   410  }`,
   411  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   412  			withError: func(t *testing.T, err error) {
   413  				want := ErrInvalidResponseLink
   414  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   415  			},
   416  		},
   417  		"invalid version format": {
   418  			params: CreatePropertyVersionRequest{
   419  				PropertyID: "propertyID",
   420  				ContractID: "contract",
   421  				GroupID:    "group",
   422  				Version: PropertyVersionCreate{
   423  					CreateFromVersion: 1,
   424  				},
   425  			},
   426  			responseStatus: http.StatusCreated,
   427  			responseBody: `
   428  {
   429      "versionLink": "/papi/v1/properties/propertyID/versions/abc?contractId=contract&groupId=group"
   430  }`,
   431  			expectedPath: "/papi/v1/properties/propertyID/versions?contractId=contract&groupId=group",
   432  			withError: func(t *testing.T, err error) {
   433  				want := ErrInvalidResponseLink
   434  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   435  			},
   436  		},
   437  	}
   438  
   439  	for name, test := range tests {
   440  		t.Run(name, func(t *testing.T) {
   441  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   442  				assert.Equal(t, test.expectedPath, r.URL.String())
   443  				assert.Equal(t, http.MethodPost, r.Method)
   444  				w.WriteHeader(test.responseStatus)
   445  				_, err := w.Write([]byte(test.responseBody))
   446  				assert.NoError(t, err)
   447  			}))
   448  			client := mockAPIClient(t, mockServer)
   449  			result, err := client.CreatePropertyVersion(context.Background(), test.params)
   450  			if test.withError != nil {
   451  				test.withError(t, err)
   452  				return
   453  			}
   454  			require.NoError(t, err)
   455  			assert.Equal(t, test.expectedResponse, result)
   456  		})
   457  	}
   458  }
   459  
   460  func TestPapi_GetLatestVersion(t *testing.T) {
   461  	tests := map[string]struct {
   462  		params           GetLatestVersionRequest
   463  		responseStatus   int
   464  		responseBody     string
   465  		expectedPath     string
   466  		expectedResponse *GetPropertyVersionsResponse
   467  		withError        func(*testing.T, error)
   468  	}{
   469  		"200 OK": {
   470  			params: GetLatestVersionRequest{
   471  				PropertyID:  "propertyID",
   472  				ActivatedOn: "STAGING",
   473  				ContractID:  "contract",
   474  				GroupID:     "group",
   475  			},
   476  			responseStatus: http.StatusOK,
   477  			expectedPath:   "/papi/v1/properties/propertyID/versions/latest?activatedOn=STAGING&contractId=contract&groupId=group",
   478  			responseBody: `
   479  {
   480      "propertyId": "propertyID",
   481      "propertyName": "property_name",
   482      "accountId": "accountID",
   483      "contractId": "contract",
   484      "groupId": "group",
   485      "assetId": "assetID",
   486      "versions": {
   487          "items": [
   488              {
   489                  "propertyVersion": 2,
   490                  "updatedByUser": "user",
   491                  "updatedDate": "2020-09-14T19:06:13Z",
   492                  "productionStatus": "INACTIVE",
   493                  "stagingStatus": "ACTIVE",
   494                  "etag": "etag",
   495                  "productId": "productID",
   496                  "note": "version note"
   497              }
   498          ]
   499      }
   500  }`,
   501  			expectedResponse: &GetPropertyVersionsResponse{
   502  				PropertyID:   "propertyID",
   503  				PropertyName: "property_name",
   504  				AccountID:    "accountID",
   505  				ContractID:   "contract",
   506  				GroupID:      "group",
   507  				AssetID:      "assetID",
   508  				Versions: PropertyVersionItems{
   509  					Items: []PropertyVersionGetItem{
   510  						{
   511  							Etag:             "etag",
   512  							Note:             "version note",
   513  							ProductID:        "productID",
   514  							ProductionStatus: "INACTIVE",
   515  							PropertyVersion:  2,
   516  							StagingStatus:    "ACTIVE",
   517  							UpdatedByUser:    "user",
   518  							UpdatedDate:      "2020-09-14T19:06:13Z",
   519  						},
   520  					},
   521  				},
   522  				Version: PropertyVersionGetItem{
   523  					Etag:             "etag",
   524  					Note:             "version note",
   525  					ProductID:        "productID",
   526  					ProductionStatus: "INACTIVE",
   527  					PropertyVersion:  2,
   528  					StagingStatus:    "ACTIVE",
   529  					UpdatedByUser:    "user",
   530  					UpdatedDate:      "2020-09-14T19:06:13Z",
   531  				},
   532  			},
   533  		},
   534  		"Version not found": {
   535  			params: GetLatestVersionRequest{
   536  				PropertyID:  "propertyID",
   537  				ActivatedOn: "STAGING",
   538  				ContractID:  "contract",
   539  				GroupID:     "group",
   540  			},
   541  			responseStatus: http.StatusOK,
   542  			expectedPath:   "/papi/v1/properties/propertyID/versions/latest?activatedOn=STAGING&contractId=contract&groupId=group",
   543  			responseBody: `
   544  {
   545      "propertyId": "propertyID",
   546      "propertyName": "property_name",
   547      "accountId": "accountID",
   548      "contractId": "contract",
   549      "groupId": "group",
   550      "assetId": "assetID",
   551      "versions": {
   552          "items": [
   553          ]
   554      }
   555  }`,
   556  			withError: func(t *testing.T, err error) {
   557  				assert.True(t, errors.Is(err, ErrNotFound), "want: %v; got: %v", ErrNotFound, err)
   558  			},
   559  		},
   560  		"500 Internal Server Error": {
   561  			params: GetLatestVersionRequest{
   562  				PropertyID: "propertyID",
   563  				ContractID: "contract",
   564  				GroupID:    "group",
   565  			},
   566  			responseStatus: http.StatusInternalServerError,
   567  			responseBody: `
   568  {
   569  	"type": "internal_error",
   570    "title": "Internal Server Error",
   571    "detail": "Error fetching latest version",
   572    "status": 500
   573  }`,
   574  			expectedPath: "/papi/v1/properties/propertyID/versions/latest?contractId=contract&groupId=group",
   575  			withError: func(t *testing.T, err error) {
   576  				want := &Error{
   577  					Type:       "internal_error",
   578  					Title:      "Internal Server Error",
   579  					Detail:     "Error fetching latest version",
   580  					StatusCode: http.StatusInternalServerError,
   581  				}
   582  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   583  			},
   584  		},
   585  		"empty property ID": {
   586  			params: GetLatestVersionRequest{
   587  				PropertyID:  "",
   588  				ActivatedOn: "STAGING",
   589  				ContractID:  "contract",
   590  				GroupID:     "group",
   591  			},
   592  			withError: func(t *testing.T, err error) {
   593  				want := ErrStructValidation
   594  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   595  				assert.Contains(t, err.Error(), "PropertyID")
   596  			},
   597  		},
   598  		"invalid ActivatedOn": {
   599  			params: GetLatestVersionRequest{
   600  				PropertyID:  "propertyID",
   601  				ActivatedOn: "test",
   602  				ContractID:  "contract",
   603  				GroupID:     "group",
   604  			},
   605  			withError: func(t *testing.T, err error) {
   606  				want := ErrStructValidation
   607  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   608  				assert.Contains(t, err.Error(), "ActivatedOn")
   609  			},
   610  		},
   611  	}
   612  
   613  	for name, test := range tests {
   614  		t.Run(name, func(t *testing.T) {
   615  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   616  				assert.Equal(t, test.expectedPath, r.URL.String())
   617  				assert.Equal(t, http.MethodGet, r.Method)
   618  				w.WriteHeader(test.responseStatus)
   619  				_, err := w.Write([]byte(test.responseBody))
   620  				assert.NoError(t, err)
   621  			}))
   622  			client := mockAPIClient(t, mockServer)
   623  			result, err := client.GetLatestVersion(context.Background(), test.params)
   624  			if test.withError != nil {
   625  				test.withError(t, err)
   626  				return
   627  			}
   628  			require.NoError(t, err)
   629  			assert.Equal(t, test.expectedResponse, result)
   630  		})
   631  	}
   632  }
   633  
   634  func TestPapi_GetAvailableBehaviors(t *testing.T) {
   635  	tests := map[string]struct {
   636  		params           GetFeaturesRequest
   637  		responseStatus   int
   638  		responseBody     string
   639  		expectedPath     string
   640  		expectedResponse *GetFeaturesCriteriaResponse
   641  		withError        func(*testing.T, error)
   642  	}{
   643  		"200 OK": {
   644  			params: GetFeaturesRequest{
   645  				PropertyID:      "propertyID",
   646  				PropertyVersion: 2,
   647  				ContractID:      "contract",
   648  				GroupID:         "group",
   649  			},
   650  			responseStatus: http.StatusOK,
   651  			expectedPath:   "/papi/v1/properties/propertyID/versions/2/available-behaviors?contractId=contract&groupId=group",
   652  			responseBody: `
   653  {
   654      "contractId": "contract",
   655      "groupId": "group",
   656      "productId": "productID",
   657      "ruleFormat": "v2020-09-15",
   658      "availableBehaviors": {
   659          "items": [
   660              {
   661                  "name": "cpCode",
   662                  "schemaLink": "/papi/v1/schemas/products/prd_Alta/latest#/definitions/catalog/behaviors/cpCode"
   663              }
   664          ]
   665      }
   666  }`,
   667  			expectedResponse: &GetFeaturesCriteriaResponse{
   668  				ContractID: "contract",
   669  				GroupID:    "group",
   670  				ProductID:  "productID",
   671  				RuleFormat: "v2020-09-15",
   672  				AvailableBehaviors: AvailableFeatureItems{Items: []AvailableFeature{
   673  					{
   674  						Name:       "cpCode",
   675  						SchemaLink: "/papi/v1/schemas/products/prd_Alta/latest#/definitions/catalog/behaviors/cpCode",
   676  					},
   677  				}},
   678  			},
   679  		},
   680  		"500 Internal Server Error": {
   681  			params: GetFeaturesRequest{
   682  				PropertyID:      "propertyID",
   683  				PropertyVersion: 2,
   684  				ContractID:      "contract",
   685  				GroupID:         "group",
   686  			},
   687  			responseStatus: http.StatusInternalServerError,
   688  			responseBody: `
   689  {
   690    "type": "internal_error",
   691    "title": "Internal Server Error",
   692    "detail": "Error fetching available behaviors",
   693    "status": 500
   694  }`,
   695  			expectedPath: "/papi/v1/properties/propertyID/versions/2/available-behaviors?contractId=contract&groupId=group",
   696  			withError: func(t *testing.T, err error) {
   697  				want := &Error{
   698  					Type:       "internal_error",
   699  					Title:      "Internal Server Error",
   700  					Detail:     "Error fetching available behaviors",
   701  					StatusCode: http.StatusInternalServerError,
   702  				}
   703  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   704  			},
   705  		},
   706  		"empty property ID": {
   707  			params: GetFeaturesRequest{
   708  				PropertyID:      "",
   709  				PropertyVersion: 2,
   710  				ContractID:      "contract",
   711  				GroupID:         "group",
   712  			},
   713  			withError: func(t *testing.T, err error) {
   714  				want := ErrStructValidation
   715  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   716  				assert.Contains(t, err.Error(), "PropertyID")
   717  			},
   718  		},
   719  		"empty property version": {
   720  			params: GetFeaturesRequest{
   721  				PropertyID: "propertyID",
   722  				ContractID: "contract",
   723  				GroupID:    "group",
   724  			},
   725  			withError: func(t *testing.T, err error) {
   726  				want := ErrStructValidation
   727  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   728  				assert.Contains(t, err.Error(), "PropertyVersion")
   729  			},
   730  		},
   731  	}
   732  
   733  	for name, test := range tests {
   734  		t.Run(name, func(t *testing.T) {
   735  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   736  				assert.Equal(t, test.expectedPath, r.URL.String())
   737  				assert.Equal(t, http.MethodGet, r.Method)
   738  				w.WriteHeader(test.responseStatus)
   739  				_, err := w.Write([]byte(test.responseBody))
   740  				assert.NoError(t, err)
   741  			}))
   742  			client := mockAPIClient(t, mockServer)
   743  			result, err := client.GetAvailableBehaviors(context.Background(), test.params)
   744  			if test.withError != nil {
   745  				test.withError(t, err)
   746  				return
   747  			}
   748  			require.NoError(t, err)
   749  			assert.Equal(t, test.expectedResponse, result)
   750  		})
   751  	}
   752  }
   753  
   754  func TestPapi_GetAvailableCriteria(t *testing.T) {
   755  	tests := map[string]struct {
   756  		params           GetFeaturesRequest
   757  		responseStatus   int
   758  		responseBody     string
   759  		expectedPath     string
   760  		expectedResponse *GetFeaturesCriteriaResponse
   761  		withError        func(*testing.T, error)
   762  	}{
   763  		"200 OK": {
   764  			params: GetFeaturesRequest{
   765  				PropertyID:      "propertyID",
   766  				PropertyVersion: 2,
   767  				ContractID:      "contract",
   768  				GroupID:         "group",
   769  			},
   770  			responseStatus: http.StatusOK,
   771  			expectedPath:   "/papi/v1/properties/propertyID/versions/2/available-criteria?contractId=contract&groupId=group",
   772  			responseBody: `
   773  {
   774      "contractId": "contract",
   775      "groupId": "group",
   776      "productId": "productID",
   777      "ruleFormat": "v2020-09-15",
   778      "availableBehaviors": {
   779          "items": [
   780              {
   781                  "name": "cpCode",
   782                  "schemaLink": "/papi/v1/schemas/products/prd_Alta/latest#/definitions/catalog/behaviors/cpCode"
   783              }
   784          ]
   785      }
   786  }`,
   787  			expectedResponse: &GetFeaturesCriteriaResponse{
   788  				ContractID: "contract",
   789  				GroupID:    "group",
   790  				ProductID:  "productID",
   791  				RuleFormat: "v2020-09-15",
   792  				AvailableBehaviors: AvailableFeatureItems{Items: []AvailableFeature{
   793  					{
   794  						Name:       "cpCode",
   795  						SchemaLink: "/papi/v1/schemas/products/prd_Alta/latest#/definitions/catalog/behaviors/cpCode",
   796  					},
   797  				}},
   798  			},
   799  		},
   800  		"500 Internal Server Error": {
   801  			params: GetFeaturesRequest{
   802  				PropertyID:      "propertyID",
   803  				PropertyVersion: 2,
   804  				ContractID:      "contract",
   805  				GroupID:         "group",
   806  			},
   807  			responseStatus: http.StatusInternalServerError,
   808  			responseBody: `
   809  {
   810    "type": "internal_error",
   811    "title": "Internal Server Error",
   812    "detail": "Error fetching available behaviors",
   813    "status": 500
   814  }`,
   815  			expectedPath: "/papi/v1/properties/propertyID/versions/2/available-criteria?contractId=contract&groupId=group",
   816  			withError: func(t *testing.T, err error) {
   817  				want := &Error{
   818  					Type:       "internal_error",
   819  					Title:      "Internal Server Error",
   820  					Detail:     "Error fetching available behaviors",
   821  					StatusCode: http.StatusInternalServerError,
   822  				}
   823  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   824  			},
   825  		},
   826  		"empty property ID": {
   827  			params: GetFeaturesRequest{
   828  				PropertyID:      "",
   829  				PropertyVersion: 2,
   830  				ContractID:      "contract",
   831  				GroupID:         "group",
   832  			},
   833  			withError: func(t *testing.T, err error) {
   834  				want := ErrStructValidation
   835  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   836  				assert.Contains(t, err.Error(), "PropertyID")
   837  			},
   838  		},
   839  		"empty property version": {
   840  			params: GetFeaturesRequest{
   841  				PropertyID: "propertyID",
   842  				ContractID: "contract",
   843  				GroupID:    "group",
   844  			},
   845  			withError: func(t *testing.T, err error) {
   846  				want := ErrStructValidation
   847  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   848  				assert.Contains(t, err.Error(), "PropertyVersion")
   849  			},
   850  		},
   851  	}
   852  
   853  	for name, test := range tests {
   854  		t.Run(name, func(t *testing.T) {
   855  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   856  				assert.Equal(t, test.expectedPath, r.URL.String())
   857  				assert.Equal(t, http.MethodGet, r.Method)
   858  				w.WriteHeader(test.responseStatus)
   859  				_, err := w.Write([]byte(test.responseBody))
   860  				assert.NoError(t, err)
   861  			}))
   862  			client := mockAPIClient(t, mockServer)
   863  			result, err := client.GetAvailableCriteria(context.Background(), test.params)
   864  			if test.withError != nil {
   865  				test.withError(t, err)
   866  				return
   867  			}
   868  			require.NoError(t, err)
   869  			assert.Equal(t, test.expectedResponse, result)
   870  		})
   871  	}
   872  }