github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/papi/cpcode_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  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestPapi_GetCPCodes(t *testing.T) {
    16  	tests := map[string]struct {
    17  		params           GetCPCodesRequest
    18  		responseStatus   int
    19  		responseBody     string
    20  		expectedPath     string
    21  		expectedResponse *GetCPCodesResponse
    22  		withError        func(*testing.T, error)
    23  	}{
    24  		"200 OK": {
    25  			params: GetCPCodesRequest{
    26  				ContractID: "contract",
    27  				GroupID:    "group",
    28  			},
    29  			responseStatus: http.StatusOK,
    30  			responseBody: `
    31  {
    32      "accountId": "acc",
    33      "contractId": "contract",
    34      "groupId": "group",
    35      "cpcodes": {
    36          "items": [
    37              {
    38                  "cpcodeId": "cpcode_id",
    39                  "cpcodeName": "cpcode_name",
    40                  "createdDate": "2020-09-10T15:06:13Z",
    41                  "productIds": [
    42                      "prd_Web_App_Accel"
    43                  ]
    44              }
    45          ]
    46      }
    47  }`,
    48  			expectedPath: "/papi/v1/cpcodes?contractId=contract&groupId=group",
    49  			expectedResponse: &GetCPCodesResponse{
    50  				AccountID:  "acc",
    51  				ContractID: "contract",
    52  				GroupID:    "group",
    53  				CPCodes: CPCodeItems{Items: []CPCode{
    54  					{
    55  						ID:          "cpcode_id",
    56  						Name:        "cpcode_name",
    57  						CreatedDate: "2020-09-10T15:06:13Z",
    58  						ProductIDs:  []string{"prd_Web_App_Accel"},
    59  					},
    60  				}},
    61  			},
    62  		},
    63  		"500 internal server error": {
    64  			params: GetCPCodesRequest{
    65  				ContractID: "contract",
    66  				GroupID:    "group",
    67  			},
    68  			responseStatus: http.StatusInternalServerError,
    69  			responseBody: `
    70  {
    71  	"type": "internal_error",
    72      "title": "Internal Server Error",
    73      "detail": "Error fetching cp codes",
    74      "status": 500
    75  }`,
    76  			expectedPath: "/papi/v1/cpcodes?contractId=contract&groupId=group",
    77  			withError: func(t *testing.T, err error) {
    78  				want := &Error{
    79  					Type:       "internal_error",
    80  					Title:      "Internal Server Error",
    81  					Detail:     "Error fetching cp codes",
    82  					StatusCode: http.StatusInternalServerError,
    83  				}
    84  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
    85  			},
    86  		},
    87  		"empty group ID": {
    88  			params: GetCPCodesRequest{
    89  				ContractID: "contract",
    90  				GroupID:    "",
    91  			},
    92  			withError: func(t *testing.T, err error) {
    93  				want := ErrStructValidation
    94  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
    95  				assert.Contains(t, err.Error(), "GroupID")
    96  			},
    97  		},
    98  		"empty contract ID": {
    99  			params: GetCPCodesRequest{
   100  				ContractID: "",
   101  				GroupID:    "group",
   102  			},
   103  			withError: func(t *testing.T, err error) {
   104  				want := ErrStructValidation
   105  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   106  				assert.Contains(t, err.Error(), "ContractID")
   107  			},
   108  		},
   109  	}
   110  
   111  	for name, test := range tests {
   112  		t.Run(name, func(t *testing.T) {
   113  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   114  				assert.Equal(t, test.expectedPath, r.URL.String())
   115  				assert.Equal(t, http.MethodGet, r.Method)
   116  				w.WriteHeader(test.responseStatus)
   117  				_, err := w.Write([]byte(test.responseBody))
   118  				assert.NoError(t, err)
   119  			}))
   120  			client := mockAPIClient(t, mockServer)
   121  			result, err := client.GetCPCodes(context.Background(), test.params)
   122  			if test.withError != nil {
   123  				test.withError(t, err)
   124  				return
   125  			}
   126  			require.NoError(t, err)
   127  			assert.Equal(t, test.expectedResponse, result)
   128  		})
   129  	}
   130  }
   131  
   132  func TestPapi_GetCPCode(t *testing.T) {
   133  	tests := map[string]struct {
   134  		params           GetCPCodeRequest
   135  		responseStatus   int
   136  		responseBody     string
   137  		expectedPath     string
   138  		expectedResponse *GetCPCodesResponse
   139  		withError        func(*testing.T, error)
   140  	}{
   141  		"200 OK": {
   142  			params: GetCPCodeRequest{
   143  				ContractID: "contract",
   144  				GroupID:    "group",
   145  				CPCodeID:   "cpcodeID",
   146  			},
   147  			responseStatus: http.StatusOK,
   148  			responseBody: `
   149  {
   150      "accountId": "acc",
   151      "contractId": "contract",
   152      "groupId": "group",
   153      "cpcodes": {
   154          "items": [
   155              {
   156                  "cpcodeId": "cpcodeID",
   157                  "cpcodeName": "cpcode_name",
   158                  "createdDate": "2020-09-10T15:06:13Z",
   159                  "productIds": [
   160                      "prd_Web_App_Accel"
   161                  ]
   162              }
   163          ]
   164      }
   165  }`,
   166  			expectedPath: "/papi/v1/cpcodes/cpcodeID?contractId=contract&groupId=group",
   167  			expectedResponse: &GetCPCodesResponse{
   168  				AccountID:  "acc",
   169  				ContractID: "contract",
   170  				GroupID:    "group",
   171  				CPCodes: CPCodeItems{Items: []CPCode{
   172  					{
   173  						ID:          "cpcodeID",
   174  						Name:        "cpcode_name",
   175  						CreatedDate: "2020-09-10T15:06:13Z",
   176  						ProductIDs:  []string{"prd_Web_App_Accel"},
   177  					},
   178  				}},
   179  				CPCode: CPCode{
   180  					ID:          "cpcodeID",
   181  					Name:        "cpcode_name",
   182  					CreatedDate: "2020-09-10T15:06:13Z",
   183  					ProductIDs:  []string{"prd_Web_App_Accel"},
   184  				},
   185  			},
   186  		},
   187  		"CP Code not found": {
   188  			params: GetCPCodeRequest{
   189  				ContractID: "contract",
   190  				GroupID:    "group",
   191  				CPCodeID:   "cpcodeID",
   192  			},
   193  			responseStatus: http.StatusOK,
   194  			responseBody: `
   195  {
   196      "accountId": "acc",
   197      "contractId": "contract",
   198      "groupId": "group",
   199      "cpcodes": {
   200          "items": [
   201          ]
   202      }
   203  }`,
   204  			expectedPath: "/papi/v1/cpcodes/cpcodeID?contractId=contract&groupId=group",
   205  			withError: func(t *testing.T, err error) {
   206  				assert.True(t, errors.Is(err, ErrNotFound), "want: %v; got: %v", ErrNotFound, err)
   207  			},
   208  		},
   209  		"500 internal server error": {
   210  			params: GetCPCodeRequest{
   211  				ContractID: "contract",
   212  				GroupID:    "group",
   213  				CPCodeID:   "cpcodeID",
   214  			},
   215  			responseStatus: http.StatusInternalServerError,
   216  			responseBody: `
   217  {
   218  	"type": "internal_error",
   219      "title": "Internal Server Error",
   220      "detail": "Error fetching cp codes",
   221      "status": 500
   222  }`,
   223  			expectedPath: "/papi/v1/cpcodes/cpcodeID?contractId=contract&groupId=group",
   224  			withError: func(t *testing.T, err error) {
   225  				want := &Error{
   226  					Type:       "internal_error",
   227  					Title:      "Internal Server Error",
   228  					Detail:     "Error fetching cp codes",
   229  					StatusCode: http.StatusInternalServerError,
   230  				}
   231  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   232  			},
   233  		},
   234  		"empty cpcode ID": {
   235  			params: GetCPCodeRequest{
   236  				ContractID: "contract",
   237  				GroupID:    "group",
   238  				CPCodeID:   "",
   239  			},
   240  			withError: func(t *testing.T, err error) {
   241  				want := ErrStructValidation
   242  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   243  				assert.Contains(t, err.Error(), "CPCodeID")
   244  			},
   245  		},
   246  		"empty group ID": {
   247  			params: GetCPCodeRequest{
   248  				ContractID: "contract",
   249  				GroupID:    "",
   250  				CPCodeID:   "cpcodeID",
   251  			},
   252  			withError: func(t *testing.T, err error) {
   253  				want := ErrStructValidation
   254  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   255  				assert.Contains(t, err.Error(), "GroupID")
   256  			},
   257  		},
   258  		"empty contract ID": {
   259  			params: GetCPCodeRequest{
   260  				ContractID: "",
   261  				GroupID:    "group",
   262  				CPCodeID:   "cpcodeID",
   263  			},
   264  			withError: func(t *testing.T, err error) {
   265  				want := ErrStructValidation
   266  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   267  				assert.Contains(t, err.Error(), "ContractID")
   268  			},
   269  		},
   270  	}
   271  
   272  	for name, test := range tests {
   273  		t.Run(name, func(t *testing.T) {
   274  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   275  				assert.Equal(t, test.expectedPath, r.URL.String())
   276  				assert.Equal(t, http.MethodGet, r.Method)
   277  				w.WriteHeader(test.responseStatus)
   278  				_, err := w.Write([]byte(test.responseBody))
   279  				assert.NoError(t, err)
   280  			}))
   281  			client := mockAPIClient(t, mockServer)
   282  			result, err := client.GetCPCode(context.Background(), test.params)
   283  			if test.withError != nil {
   284  				test.withError(t, err)
   285  				return
   286  			}
   287  			require.NoError(t, err)
   288  			assert.Equal(t, test.expectedResponse, result)
   289  		})
   290  	}
   291  }
   292  
   293  func TestGetCPCodeDetail(t *testing.T) {
   294  	tests := map[string]struct {
   295  		id               int
   296  		responseStatus   int
   297  		responseBody     string
   298  		expectedPath     string
   299  		expectedResponse *CPCodeDetailResponse
   300  		withError        func(*testing.T, error)
   301  	}{
   302  		"200 OK": {
   303  			id:             123,
   304  			responseStatus: http.StatusOK,
   305  			responseBody: `
   306  {
   307      "cpcodeId": 123,
   308      "cpcodeName": "test-cp-code",
   309      "purgeable": true,
   310      "accountId": "test-account-id",
   311      "defaultTimezone": "GMT 0 (Greenwich Mean Time)",
   312      "overrideTimezone": {
   313          "timezoneId": "0",
   314          "timezoneValue": "GMT 0 (Greenwich Mean Time)"
   315      },
   316      "type": "Regular",
   317      "contracts": [
   318          {
   319              "contractId": "test-contract-id",
   320              "status": "ongoing"
   321          }
   322      ],
   323      "products": [
   324          {
   325              "productId": "test-product-id",
   326              "productName": "test-product-name"
   327          }
   328      ],
   329      "accessGroup": {
   330          "groupId": null,
   331          "contractId": "test-contract-id"
   332      }
   333  }`,
   334  			expectedPath: "/cprg/v1/cpcodes/123",
   335  			expectedResponse: &CPCodeDetailResponse{
   336  				ID:              123,
   337  				Name:            "test-cp-code",
   338  				Purgeable:       true,
   339  				AccountID:       "test-account-id",
   340  				DefaultTimeZone: "GMT 0 (Greenwich Mean Time)",
   341  				OverrideTimeZone: CPCodeTimeZone{
   342  					TimeZoneID:    "0",
   343  					TimeZoneValue: "GMT 0 (Greenwich Mean Time)",
   344  				},
   345  				Type: "Regular",
   346  				Contracts: []CPCodeContract{
   347  					{
   348  						ContractID: "test-contract-id",
   349  						Status:     "ongoing",
   350  					},
   351  				},
   352  				Products: []CPCodeProduct{
   353  					{
   354  						ProductID:   "test-product-id",
   355  						ProductName: "test-product-name",
   356  					},
   357  				},
   358  			},
   359  		},
   360  		"500 internal server error": {
   361  			id:             123,
   362  			responseStatus: http.StatusInternalServerError,
   363  			responseBody: `
   364  {
   365  	"type": "internal_error",
   366      "title": "Server Error",
   367      "detail": "Error fetching cp codes",
   368      "status": 500
   369  }`,
   370  			expectedPath: "/cprg/v1/cpcodes/123",
   371  			withError: func(t *testing.T, err error) {
   372  				want := &Error{
   373  					Type:       "internal_error",
   374  					Title:      "Server Error",
   375  					Detail:     "Error fetching cp codes",
   376  					StatusCode: http.StatusInternalServerError,
   377  				}
   378  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   379  			},
   380  		},
   381  	}
   382  
   383  	for name, test := range tests {
   384  		t.Run(name, func(t *testing.T) {
   385  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   386  				assert.Equal(t, test.expectedPath, r.URL.String())
   387  				assert.Equal(t, http.MethodGet, r.Method)
   388  				w.WriteHeader(test.responseStatus)
   389  				_, err := w.Write([]byte(test.responseBody))
   390  				assert.NoError(t, err)
   391  			}))
   392  			client := mockAPIClient(t, mockServer)
   393  			result, err := client.GetCPCodeDetail(context.Background(), test.id)
   394  			if test.withError != nil {
   395  				test.withError(t, err)
   396  				return
   397  			}
   398  			require.NoError(t, err)
   399  			assert.Equal(t, test.expectedResponse, result)
   400  		})
   401  	}
   402  }
   403  
   404  func TestPapi_CreateCPCode(t *testing.T) {
   405  	tests := map[string]struct {
   406  		params         CreateCPCodeRequest
   407  		responseStatus int
   408  		responseBody   string
   409  		expectedPath   string
   410  		expected       *CreateCPCodeResponse
   411  		withError      func(*testing.T, error)
   412  	}{
   413  		"201 Created": {
   414  			params: CreateCPCodeRequest{
   415  				ContractID: "contract",
   416  				GroupID:    "group",
   417  				CPCode: CreateCPCode{
   418  					ProductID:  "productID",
   419  					CPCodeName: "cpcodeName",
   420  				},
   421  			},
   422  			responseStatus: http.StatusCreated,
   423  			responseBody: `
   424  {
   425      "cpcodeLink": "/papi/v1/cpcodes/123?contractId=contract-1TJZFW&groupId=group"
   426  }`,
   427  			expectedPath: "/papi/v1/cpcodes?contractId=contract&groupId=group",
   428  			expected: &CreateCPCodeResponse{
   429  				CPCodeLink: "/papi/v1/cpcodes/123?contractId=contract-1TJZFW&groupId=group",
   430  				CPCodeID:   "123",
   431  			},
   432  		},
   433  		"500 Internal Server Error": {
   434  			params: CreateCPCodeRequest{
   435  				ContractID: "contract",
   436  				GroupID:    "group",
   437  				CPCode: CreateCPCode{
   438  					ProductID:  "productID",
   439  					CPCodeName: "cpcodeName",
   440  				},
   441  			},
   442  			responseStatus: http.StatusInternalServerError,
   443  			responseBody: `
   444  {
   445  	"type": "internal_error",
   446      "title": "Internal Server Error",
   447      "detail": "Error fetching cp codes",
   448      "status": 500
   449  }`,
   450  			expectedPath: "/papi/v1/cpcodes?contractId=contract&groupId=group",
   451  			withError: func(t *testing.T, err error) {
   452  				want := &Error{
   453  					Type:       "internal_error",
   454  					Title:      "Internal Server Error",
   455  					Detail:     "Error fetching cp codes",
   456  					StatusCode: http.StatusInternalServerError,
   457  				}
   458  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   459  			},
   460  		},
   461  		"empty group ID": {
   462  			params: CreateCPCodeRequest{
   463  				ContractID: "contract",
   464  				GroupID:    "",
   465  				CPCode: CreateCPCode{
   466  					ProductID:  "productID",
   467  					CPCodeName: "cpCodeName",
   468  				},
   469  			},
   470  			withError: func(t *testing.T, err error) {
   471  				want := ErrStructValidation
   472  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   473  				assert.Contains(t, err.Error(), "GroupID")
   474  			},
   475  		},
   476  		"empty contract ID": {
   477  			params: CreateCPCodeRequest{
   478  				ContractID: "",
   479  				GroupID:    "group",
   480  				CPCode: CreateCPCode{
   481  					ProductID:  "productID",
   482  					CPCodeName: "cpCodeName",
   483  				},
   484  			},
   485  			withError: func(t *testing.T, err error) {
   486  				want := ErrStructValidation
   487  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   488  				assert.Contains(t, err.Error(), "ContractID")
   489  			},
   490  		},
   491  		"empty product ID": {
   492  			params: CreateCPCodeRequest{
   493  				ContractID: "contractID",
   494  				GroupID:    "group",
   495  				CPCode: CreateCPCode{
   496  					ProductID:  "",
   497  					CPCodeName: "cpCodeName",
   498  				},
   499  			},
   500  			withError: func(t *testing.T, err error) {
   501  				want := ErrStructValidation
   502  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   503  				assert.Contains(t, err.Error(), "ProductID")
   504  			},
   505  		},
   506  		"empty cp code name": {
   507  			params: CreateCPCodeRequest{
   508  				ContractID: "",
   509  				GroupID:    "group",
   510  				CPCode: CreateCPCode{
   511  					ProductID:  "productID",
   512  					CPCodeName: "",
   513  				},
   514  			},
   515  			withError: func(t *testing.T, err error) {
   516  				want := ErrStructValidation
   517  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   518  				assert.Contains(t, err.Error(), "CPCodeName")
   519  			},
   520  		},
   521  		"invalid response location": {
   522  			params: CreateCPCodeRequest{
   523  				ContractID: "contract",
   524  				GroupID:    "group",
   525  				CPCode: CreateCPCode{
   526  					ProductID:  "productID",
   527  					CPCodeName: "cpcodeName",
   528  				},
   529  			},
   530  			responseStatus: http.StatusCreated,
   531  			responseBody: `
   532  {
   533      "cpcodeLink": ":"
   534  }`,
   535  			expectedPath: "/papi/v1/cpcodes?contractId=contract&groupId=group",
   536  			withError: func(t *testing.T, err error) {
   537  				want := ErrInvalidResponseLink
   538  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   539  			},
   540  		},
   541  	}
   542  
   543  	for name, test := range tests {
   544  		t.Run(name, func(t *testing.T) {
   545  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   546  				assert.Equal(t, test.expectedPath, r.URL.String())
   547  				assert.Equal(t, http.MethodPost, r.Method)
   548  				w.WriteHeader(test.responseStatus)
   549  				_, err := w.Write([]byte(test.responseBody))
   550  				assert.NoError(t, err)
   551  			}))
   552  			client := mockAPIClient(t, mockServer)
   553  			result, err := client.CreateCPCode(context.Background(), test.params)
   554  			if test.withError != nil {
   555  				test.withError(t, err)
   556  				return
   557  			}
   558  			require.NoError(t, err)
   559  			assert.Equal(t, test.expected, result)
   560  		})
   561  	}
   562  }
   563  
   564  func TestUpdateCPCode(t *testing.T) {
   565  	tests := map[string]struct {
   566  		params           UpdateCPCodeRequest
   567  		responseStatus   int
   568  		responseBody     string
   569  		expectedPath     string
   570  		expectedResponse *CPCodeDetailResponse
   571  		withError        func(*testing.T, error)
   572  	}{
   573  		"200 OK Update name": {
   574  			params: UpdateCPCodeRequest{
   575  				ID:   123,
   576  				Name: "test-cp-code-updated",
   577  				Contracts: []CPCodeContract{
   578  					{
   579  						ContractID: "test-contract-id",
   580  						Status:     "ongoing",
   581  					},
   582  				},
   583  				Products: []CPCodeProduct{
   584  					{
   585  						ProductID:   "test-product-id",
   586  						ProductName: "test-product-name",
   587  					},
   588  				},
   589  			},
   590  			responseStatus: http.StatusOK,
   591  			responseBody: `
   592  {
   593      "cpcodeId": 123,
   594      "cpcodeName": "test-cp-code-updated",
   595      "purgeable": true,
   596      "accountId": "test-account-id",
   597      "defaultTimezone": "GMT 0 (Greenwich Mean Time)",
   598      "overrideTimezone": {
   599          "timezoneId": "0",
   600          "timezoneValue": "GMT 0 (Greenwich Mean Time)"
   601      },
   602      "type": "Regular",
   603      "contracts": [
   604          {
   605              "contractId": "test-contract-id",
   606              "status": "ongoing"
   607          }
   608      ],
   609      "products": [
   610          {
   611              "productId": "test-product-id",
   612              "productName": "test-product-name"
   613          }
   614      ],
   615      "accessGroup": {
   616          "groupId": null,
   617          "contractId": "test-contract-id"
   618      }
   619  }`,
   620  			expectedPath: "/cprg/v1/cpcodes/123",
   621  			expectedResponse: &CPCodeDetailResponse{
   622  				ID:              123,
   623  				Name:            "test-cp-code-updated",
   624  				Purgeable:       true,
   625  				AccountID:       "test-account-id",
   626  				DefaultTimeZone: "GMT 0 (Greenwich Mean Time)",
   627  				OverrideTimeZone: CPCodeTimeZone{
   628  					TimeZoneID:    "0",
   629  					TimeZoneValue: "GMT 0 (Greenwich Mean Time)",
   630  				},
   631  				Type: "Regular",
   632  				Contracts: []CPCodeContract{
   633  					{
   634  						ContractID: "test-contract-id",
   635  						Status:     "ongoing",
   636  					},
   637  				},
   638  				Products: []CPCodeProduct{
   639  					{
   640  						ProductID:   "test-product-id",
   641  						ProductName: "test-product-name",
   642  					},
   643  				},
   644  			},
   645  		},
   646  		"200 OK Update time zone": {
   647  			params: UpdateCPCodeRequest{
   648  				ID:   123,
   649  				Name: "test-cp-code",
   650  				OverrideTimeZone: &CPCodeTimeZone{
   651  					TimeZoneID:    "1",
   652  					TimeZoneValue: "GMT + 1",
   653  				},
   654  				Contracts: []CPCodeContract{
   655  					{
   656  						ContractID: "test-contract-id",
   657  						Status:     "ongoing",
   658  					},
   659  				},
   660  				Products: []CPCodeProduct{
   661  					{
   662  						ProductID:   "test-product-id",
   663  						ProductName: "test-product-name",
   664  					},
   665  				},
   666  			},
   667  			responseStatus: http.StatusOK,
   668  			responseBody: `
   669  {
   670      "cpcodeId": 123,
   671      "cpcodeName": "test-cp-code-updated",
   672      "purgeable": true,
   673      "accountId": "test-account-id",
   674      "defaultTimezone": "GMT 0 (Greenwich Mean Time)",
   675      "overrideTimezone": {
   676          "timezoneId": "1",
   677          "timezoneValue": "GMT + 1"
   678      },
   679      "type": "Regular",
   680      "contracts": [
   681          {
   682              "contractId": "test-contract-id",
   683              "status": "ongoing"
   684          }
   685      ],
   686      "products": [
   687          {
   688              "productId": "test-product-id",
   689              "productName": "test-product-name"
   690          }
   691      ],
   692      "accessGroup": {
   693          "groupId": null,
   694          "contractId": "test-contract-id"
   695      }
   696  }`,
   697  			expectedPath: "/cprg/v1/cpcodes/123",
   698  			expectedResponse: &CPCodeDetailResponse{
   699  				ID:              123,
   700  				Name:            "test-cp-code-updated",
   701  				Purgeable:       true,
   702  				AccountID:       "test-account-id",
   703  				DefaultTimeZone: "GMT 0 (Greenwich Mean Time)",
   704  				OverrideTimeZone: CPCodeTimeZone{
   705  					TimeZoneID:    "1",
   706  					TimeZoneValue: "GMT + 1",
   707  				},
   708  				Type: "Regular",
   709  				Contracts: []CPCodeContract{
   710  					{
   711  						ContractID: "test-contract-id",
   712  						Status:     "ongoing",
   713  					},
   714  				},
   715  				Products: []CPCodeProduct{
   716  					{
   717  						ProductID:   "test-product-id",
   718  						ProductName: "test-product-name",
   719  					},
   720  				},
   721  			},
   722  		},
   723  		"200 OK Update purgeable": {
   724  			params: UpdateCPCodeRequest{
   725  				ID:        123,
   726  				Name:      "test-cp-code",
   727  				Purgeable: tools.BoolPtr(false),
   728  				Contracts: []CPCodeContract{
   729  					{
   730  						ContractID: "test-contract-id",
   731  						Status:     "ongoing",
   732  					},
   733  				},
   734  				Products: []CPCodeProduct{
   735  					{
   736  						ProductID:   "test-product-id",
   737  						ProductName: "test-product-name",
   738  					},
   739  				},
   740  			},
   741  			responseStatus: http.StatusOK,
   742  			responseBody: `
   743  {
   744      "cpcodeId": 123,
   745      "cpcodeName": "test-cp-code-updated",
   746      "purgeable": false,
   747      "accountId": "test-account-id",
   748      "defaultTimezone": "GMT 0 (Greenwich Mean Time)",
   749      "overrideTimezone": {
   750          "timezoneId": "0",
   751          "timezoneValue": "GMT 0 (Greenwich Mean Time)"
   752      },
   753      "type": "Regular",
   754      "contracts": [
   755          {
   756              "contractId": "test-contract-id",
   757              "status": "ongoing"
   758          }
   759      ],
   760      "products": [
   761          {
   762              "productId": "test-product-id",
   763              "productName": "test-product-name"
   764          }
   765      ],
   766      "accessGroup": {
   767          "groupId": null,
   768          "contractId": "test-contract-id"
   769      }
   770  }`,
   771  			expectedPath: "/cprg/v1/cpcodes/123",
   772  			expectedResponse: &CPCodeDetailResponse{
   773  				ID:              123,
   774  				Name:            "test-cp-code-updated",
   775  				Purgeable:       false,
   776  				AccountID:       "test-account-id",
   777  				DefaultTimeZone: "GMT 0 (Greenwich Mean Time)",
   778  				OverrideTimeZone: CPCodeTimeZone{
   779  					TimeZoneID:    "0",
   780  					TimeZoneValue: "GMT 0 (Greenwich Mean Time)",
   781  				},
   782  				Type: "Regular",
   783  				Contracts: []CPCodeContract{
   784  					{
   785  						ContractID: "test-contract-id",
   786  						Status:     "ongoing",
   787  					},
   788  				},
   789  				Products: []CPCodeProduct{
   790  					{
   791  						ProductID:   "test-product-id",
   792  						ProductName: "test-product-name",
   793  					},
   794  				},
   795  			},
   796  		},
   797  		"500 internal server error": {
   798  			params: UpdateCPCodeRequest{
   799  				ID:   123,
   800  				Name: "test-cp-code-updated",
   801  				Contracts: []CPCodeContract{
   802  					{
   803  						ContractID: "test-contract-id",
   804  						Status:     "ongoing",
   805  					},
   806  				},
   807  				Products: []CPCodeProduct{
   808  					{
   809  						ProductID:   "test-product-id",
   810  						ProductName: "test-product-name",
   811  					},
   812  				},
   813  			},
   814  			responseStatus: http.StatusInternalServerError,
   815  			responseBody: `
   816  {
   817  	"type": "internal_error",
   818      "title": "Server Error",
   819      "detail": "Error updating cp code",
   820      "status": 500
   821  }`,
   822  			expectedPath: "/cprg/v1/cpcodes/123",
   823  			withError: func(t *testing.T, err error) {
   824  				want := &Error{
   825  					Type:       "internal_error",
   826  					Title:      "Server Error",
   827  					Detail:     "Error updating cp code",
   828  					StatusCode: http.StatusInternalServerError,
   829  				}
   830  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   831  			},
   832  		},
   833  		"validation - id is required": {
   834  			params: UpdateCPCodeRequest{
   835  				Name: "test-cp-code-updated",
   836  				Contracts: []CPCodeContract{
   837  					{
   838  						ContractID: "test-contract-id",
   839  						Status:     "ongoing",
   840  					},
   841  				},
   842  				Products: []CPCodeProduct{
   843  					{
   844  						ProductID:   "test-product-id",
   845  						ProductName: "test-product-name",
   846  					},
   847  				},
   848  			},
   849  			expectedPath: "/cprg/v1/cpcodes/123",
   850  			withError: func(t *testing.T, err error) {
   851  				want := ErrStructValidation
   852  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   853  			},
   854  		},
   855  		"validation - name is required": {
   856  			params: UpdateCPCodeRequest{
   857  				ID: 123,
   858  				Contracts: []CPCodeContract{
   859  					{
   860  						ContractID: "test-contract-id",
   861  						Status:     "ongoing",
   862  					},
   863  				},
   864  				Products: []CPCodeProduct{
   865  					{
   866  						ProductID:   "test-product-id",
   867  						ProductName: "test-product-name",
   868  					},
   869  				},
   870  			},
   871  			expectedPath: "/cprg/v1/cpcodes/123",
   872  			withError: func(t *testing.T, err error) {
   873  				want := ErrStructValidation
   874  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   875  			},
   876  		},
   877  		"validation - contracts is required": {
   878  			params: UpdateCPCodeRequest{
   879  				ID:   123,
   880  				Name: "test-cp-code-updated",
   881  				Products: []CPCodeProduct{
   882  					{
   883  						ProductID:   "test-product-id",
   884  						ProductName: "test-product-name",
   885  					},
   886  				},
   887  			},
   888  			expectedPath: "/cprg/v1/cpcodes/123",
   889  			withError: func(t *testing.T, err error) {
   890  				want := ErrStructValidation
   891  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   892  			},
   893  		},
   894  		"validation - contract id is required": {
   895  			params: UpdateCPCodeRequest{
   896  				ID:   123,
   897  				Name: "test-cp-code-updated",
   898  				Contracts: []CPCodeContract{
   899  					{
   900  						Status: "ongoing",
   901  					},
   902  				},
   903  				Products: []CPCodeProduct{
   904  					{
   905  						ProductID:   "test-product-id",
   906  						ProductName: "test-product-name",
   907  					},
   908  				},
   909  			},
   910  			expectedPath: "/cprg/v1/cpcodes/123",
   911  			withError: func(t *testing.T, err error) {
   912  				want := ErrStructValidation
   913  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   914  			},
   915  		},
   916  		"validation - products is required": {
   917  			params: UpdateCPCodeRequest{
   918  				ID:   123,
   919  				Name: "test-cp-code-updated",
   920  				Contracts: []CPCodeContract{
   921  					{
   922  						ContractID: "test-contract-id",
   923  						Status:     "ongoing",
   924  					},
   925  				},
   926  			},
   927  			expectedPath: "/cprg/v1/cpcodes/123",
   928  			withError: func(t *testing.T, err error) {
   929  				want := ErrStructValidation
   930  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   931  			},
   932  		},
   933  		"validation - product id is required": {
   934  			params: UpdateCPCodeRequest{
   935  				ID:   123,
   936  				Name: "test-cp-code-updated",
   937  				Contracts: []CPCodeContract{
   938  					{
   939  						ContractID: "test-contract-id",
   940  						Status:     "ongoing",
   941  					},
   942  				},
   943  				Products: []CPCodeProduct{
   944  					{
   945  						ProductName: "test-product-name",
   946  					},
   947  				},
   948  			},
   949  			expectedPath: "/cprg/v1/cpcodes/123",
   950  			withError: func(t *testing.T, err error) {
   951  				want := ErrStructValidation
   952  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   953  			},
   954  		},
   955  		"validation - time zone id is required": {
   956  			params: UpdateCPCodeRequest{
   957  				ID:   123,
   958  				Name: "test-cp-code-updated",
   959  				OverrideTimeZone: &CPCodeTimeZone{
   960  					TimeZoneValue: "GMT + 1",
   961  				},
   962  				Contracts: []CPCodeContract{
   963  					{
   964  						ContractID: "test-contract-id",
   965  						Status:     "ongoing",
   966  					},
   967  				},
   968  				Products: []CPCodeProduct{
   969  					{
   970  						ProductID:   "test-product-id",
   971  						ProductName: "test-product-name",
   972  					},
   973  				},
   974  			},
   975  			expectedPath: "/cprg/v1/cpcodes/123",
   976  			withError: func(t *testing.T, err error) {
   977  				want := ErrStructValidation
   978  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   979  			},
   980  		},
   981  	}
   982  
   983  	for name, test := range tests {
   984  		t.Run(name, func(t *testing.T) {
   985  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   986  				assert.Equal(t, test.expectedPath, r.URL.String())
   987  				assert.Equal(t, http.MethodPut, r.Method)
   988  				w.WriteHeader(test.responseStatus)
   989  				_, err := w.Write([]byte(test.responseBody))
   990  				assert.NoError(t, err)
   991  			}))
   992  			client := mockAPIClient(t, mockServer)
   993  			result, err := client.UpdateCPCode(context.Background(), test.params)
   994  			if test.withError != nil {
   995  				test.withError(t, err)
   996  				return
   997  			}
   998  			require.NoError(t, err)
   999  			assert.Equal(t, test.expectedResponse, result)
  1000  		})
  1001  	}
  1002  }