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

     1  package edgeworkers
     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 TestListNamespaces(t *testing.T) {
    16  	tests := map[string]struct {
    17  		params         ListEdgeKVNamespacesRequest
    18  		withError      func(*testing.T, error)
    19  		expectedPath   string
    20  		responseStatus int
    21  		responseBody   string
    22  		expectedResult *ListEdgeKVNamespacesResponse
    23  	}{
    24  		"200 OK - production network": {
    25  			params: ListEdgeKVNamespacesRequest{
    26  				Network: NamespaceProductionNetwork,
    27  			},
    28  			expectedPath:   "/edgekv/v1/networks/production/namespaces",
    29  			responseStatus: http.StatusOK,
    30  			responseBody: `{
    31  				"namespaces": [
    32  					{
    33  						"namespace": "testNs_1"
    34  					},
    35  					{
    36  						"namespace": "testNs_2"
    37  					},
    38  					{
    39  						"namespace": "testNs_3"
    40  					}
    41  				]
    42  			}`,
    43  			expectedResult: &ListEdgeKVNamespacesResponse{
    44  				Namespaces: []Namespace{
    45  					{
    46  						Name: "testNs_1",
    47  					},
    48  					{
    49  						Name: "testNs_2",
    50  					},
    51  					{
    52  						Name: "testNs_3",
    53  					},
    54  				},
    55  			},
    56  		},
    57  		"200 OK - staging network": {
    58  			params: ListEdgeKVNamespacesRequest{
    59  				Network: NamespaceStagingNetwork,
    60  			},
    61  			expectedPath:   "/edgekv/v1/networks/staging/namespaces",
    62  			responseStatus: http.StatusOK,
    63  			responseBody: `{
    64  				"namespaces": [
    65  					{
    66  						"namespace": "testNs_1"
    67  					},
    68  					{
    69  						"namespace": "testNs_2"
    70  					},
    71  					{
    72  						"namespace": "testNs_3"
    73  					}
    74  				]
    75  			}`,
    76  			expectedResult: &ListEdgeKVNamespacesResponse{
    77  				Namespaces: []Namespace{
    78  					{
    79  						Name: "testNs_1",
    80  					},
    81  					{
    82  						Name: "testNs_2",
    83  					},
    84  					{
    85  						Name: "testNs_3",
    86  					},
    87  				},
    88  			},
    89  		},
    90  		"200 OK - details on": {
    91  			params: ListEdgeKVNamespacesRequest{
    92  				Network: NamespaceProductionNetwork,
    93  				Details: true,
    94  			},
    95  			expectedPath:   "/edgekv/v1/networks/production/namespaces?details=on",
    96  			responseStatus: http.StatusOK,
    97  			responseBody: `{
    98  				"namespaces": [
    99  					{
   100  						"namespace": "testNs_1",
   101  						"retentionInSeconds": 0,
   102  						"geoLocation": "EU",
   103  						"groupId": 0
   104  					},
   105  					{
   106  						"namespace": "testNs_2",
   107  						"retentionInSeconds": 86400,
   108  						"geoLocation": "JP",
   109  						"groupId": 123
   110  					},
   111  					{
   112  						"namespace": "testNs_3",
   113  						"retentionInSeconds": 315360000,
   114  						"geoLocation": "US",
   115  						"groupId": 234
   116  					}
   117  				]
   118  			}`,
   119  			expectedResult: &ListEdgeKVNamespacesResponse{
   120  				Namespaces: []Namespace{
   121  					{
   122  						Name:        "testNs_1",
   123  						Retention:   tools.IntPtr(0),
   124  						GeoLocation: "EU",
   125  						GroupID:     tools.IntPtr(0),
   126  					},
   127  					{
   128  						Name:        "testNs_2",
   129  						Retention:   tools.IntPtr(86400),
   130  						GeoLocation: "JP",
   131  						GroupID:     tools.IntPtr(123),
   132  					},
   133  					{
   134  						Name:        "testNs_3",
   135  						Retention:   tools.IntPtr(315360000),
   136  						GeoLocation: "US",
   137  						GroupID:     tools.IntPtr(234),
   138  					},
   139  				},
   140  			},
   141  		},
   142  		"missing network": {
   143  			params: ListEdgeKVNamespacesRequest{},
   144  			withError: func(t *testing.T, err error) {
   145  				assert.Containsf(t, err.Error(), "Network: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   146  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   147  			},
   148  		},
   149  		"invalid network": {
   150  			params: ListEdgeKVNamespacesRequest{
   151  				Network: "invalidNetwork",
   152  			},
   153  			withError: func(t *testing.T, err error) {
   154  				assert.Containsf(t, err.Error(), "Network: value 'invalidNetwork' is invalid. Must be one of: 'staging' or 'production'", "want: %s; got: %s", ErrStructValidation, err)
   155  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   156  			},
   157  		},
   158  	}
   159  
   160  	for name, test := range tests {
   161  		t.Run(name, func(t *testing.T) {
   162  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   163  				assert.Equal(t, test.expectedPath, r.URL.String())
   164  				assert.Equal(t, http.MethodGet, r.Method)
   165  				w.WriteHeader(test.responseStatus)
   166  				_, err := w.Write([]byte(test.responseBody))
   167  				assert.NoError(t, err)
   168  			}))
   169  			client := mockAPIClient(t, mockServer)
   170  
   171  			result, err := client.ListEdgeKVNamespaces(context.Background(), test.params)
   172  			if test.withError != nil {
   173  				test.withError(t, err)
   174  				return
   175  			}
   176  			require.NoError(t, err)
   177  			assert.Equal(t, test.expectedResult, result)
   178  		})
   179  	}
   180  }
   181  
   182  func TestGetNamespace(t *testing.T) {
   183  	tests := map[string]struct {
   184  		params         GetEdgeKVNamespaceRequest
   185  		withError      func(*testing.T, error)
   186  		expectedPath   string
   187  		responseStatus int
   188  		responseBody   string
   189  		expectedResult *Namespace
   190  	}{
   191  		"200 OK - production": {
   192  			params: GetEdgeKVNamespaceRequest{
   193  				Network: NamespaceProductionNetwork,
   194  				Name:    "testNs",
   195  			},
   196  			expectedPath:   "/edgekv/v1/networks/production/namespaces/testNs",
   197  			responseStatus: http.StatusOK,
   198  			responseBody: `{
   199  				"namespace": "testNs",
   200  				"retentionInSeconds": 0,
   201  				"geoLocation": "EU",
   202  				"groupId": 0
   203  			}`,
   204  			expectedResult: &Namespace{
   205  				Name:        "testNs",
   206  				Retention:   tools.IntPtr(0),
   207  				GeoLocation: "EU",
   208  				GroupID:     tools.IntPtr(0),
   209  			},
   210  		},
   211  		"200 OK - staging": {
   212  			params: GetEdgeKVNamespaceRequest{
   213  				Network: NamespaceStagingNetwork,
   214  				Name:    "testNs",
   215  			},
   216  			expectedPath:   "/edgekv/v1/networks/staging/namespaces/testNs",
   217  			responseStatus: http.StatusOK,
   218  			responseBody: `{
   219  				"namespace": "testNs",
   220  				"retentionInSeconds": 86400,
   221  				"geoLocation": "US",
   222  				"groupId": 0
   223  			}`,
   224  			expectedResult: &Namespace{
   225  				Name:        "testNs",
   226  				Retention:   tools.IntPtr(86400),
   227  				GeoLocation: "US",
   228  				GroupID:     tools.IntPtr(0),
   229  			},
   230  		},
   231  		"400 bad request - namespace does not exist": {
   232  			params: GetEdgeKVNamespaceRequest{
   233  				Network: NamespaceStagingNetwork,
   234  				Name:    "testNs",
   235  			},
   236  			withError: func(t *testing.T, err error) {
   237  				expected := &Error{
   238  					Detail:    "The requested namespace does not exist.",
   239  					Instance:  "/edgeKV/error-instances/f65424a8-dbea-4799-a2f1-44acc45a121b",
   240  					Status:    http.StatusBadRequest,
   241  					Title:     "Bad Request",
   242  					Type:      "https://learn.akamai.com",
   243  					ErrorCode: "EKV_9000",
   244  					AdditionalDetail: Additional{
   245  						RequestID: "a46f61d2c9539c77",
   246  					},
   247  				}
   248  				assert.True(t, errors.Is(err, expected), "want: %s; got: %s", expected, err)
   249  			},
   250  			expectedPath:   "/edgekv/v1/networks/staging/namespaces/testNs",
   251  			responseStatus: http.StatusBadRequest,
   252  			responseBody: `{
   253  				"detail": "The requested namespace does not exist.",
   254  				"errorCode": "EKV_9000",
   255  				"instance": "/edgeKV/error-instances/f65424a8-dbea-4799-a2f1-44acc45a121b",
   256  				"status": 400,
   257  				"title": "Bad Request",
   258  				"type": "https://learn.akamai.com",
   259  				"additionalDetail": {
   260  					"requestId": "a46f61d2c9539c77"
   261  				}
   262  			}`,
   263  		},
   264  		"missing required parameters": {
   265  			params: GetEdgeKVNamespaceRequest{},
   266  			withError: func(t *testing.T, err error) {
   267  				assert.Containsf(t, err.Error(), "Network: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   268  				assert.Containsf(t, err.Error(), "Name: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   269  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   270  			},
   271  		},
   272  		"namespace name too long": {
   273  			params: GetEdgeKVNamespaceRequest{
   274  				Network: NamespaceStagingNetwork,
   275  				Name:    "namespaceNameThatHasMoreThan32Letters",
   276  			},
   277  			withError: func(t *testing.T, err error) {
   278  				assert.Containsf(t, err.Error(), "Name: the length must be between 1 and 32", "want: %s; got: %s", ErrStructValidation, err)
   279  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   280  			},
   281  		},
   282  	}
   283  
   284  	for name, test := range tests {
   285  		t.Run(name, func(t *testing.T) {
   286  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   287  				assert.Equal(t, test.expectedPath, r.URL.String())
   288  				assert.Equal(t, http.MethodGet, r.Method)
   289  				w.WriteHeader(test.responseStatus)
   290  				_, err := w.Write([]byte(test.responseBody))
   291  				assert.NoError(t, err)
   292  			}))
   293  			client := mockAPIClient(t, mockServer)
   294  
   295  			result, err := client.GetEdgeKVNamespace(context.Background(), test.params)
   296  			if test.withError != nil {
   297  				test.withError(t, err)
   298  				return
   299  			}
   300  			require.NoError(t, err)
   301  			assert.Equal(t, test.expectedResult, result)
   302  		})
   303  	}
   304  }
   305  
   306  func TestCreateNamespace(t *testing.T) {
   307  	tests := map[string]struct {
   308  		params         CreateEdgeKVNamespaceRequest
   309  		withError      func(*testing.T, error)
   310  		expectedPath   string
   311  		responseStatus int
   312  		responseBody   string
   313  		expectedResult *Namespace
   314  	}{
   315  		"200 OK - production": {
   316  			params: CreateEdgeKVNamespaceRequest{
   317  				Network: NamespaceProductionNetwork,
   318  				Namespace: Namespace{
   319  					Name:        "testNs",
   320  					Retention:   tools.IntPtr(0),
   321  					GeoLocation: "EU",
   322  					GroupID:     tools.IntPtr(0),
   323  				},
   324  			},
   325  			expectedPath:   "/edgekv/v1/networks/production/namespaces",
   326  			responseStatus: http.StatusOK,
   327  			responseBody: `{
   328  				"namespace": "testNs",
   329  				"retentionInSeconds": 0,
   330  				"geoLocation": "EU",
   331  				"groupId": 0
   332  			}`,
   333  			expectedResult: &Namespace{
   334  				Name:        "testNs",
   335  				Retention:   tools.IntPtr(0),
   336  				GeoLocation: "EU",
   337  				GroupID:     tools.IntPtr(0),
   338  			},
   339  		},
   340  		"200 OK - staging": {
   341  			params: CreateEdgeKVNamespaceRequest{
   342  				Network: NamespaceStagingNetwork,
   343  				Namespace: Namespace{
   344  					Name:      "testNs",
   345  					Retention: tools.IntPtr(86400),
   346  					GroupID:   tools.IntPtr(123),
   347  				},
   348  			},
   349  			expectedPath:   "/edgekv/v1/networks/staging/namespaces",
   350  			responseStatus: http.StatusOK,
   351  			responseBody: `{
   352  				"namespace": "testNs",
   353  				"retentionInSeconds": 86400,
   354  				"geoLocation": "US",
   355  				"groupId": 123
   356  			}`,
   357  			expectedResult: &Namespace{
   358  				Name:        "testNs",
   359  				Retention:   tools.IntPtr(86400),
   360  				GeoLocation: "US",
   361  				GroupID:     tools.IntPtr(123),
   362  			},
   363  		},
   364  		"400 bad request - invalid geoLocation for staging network": {
   365  			params: CreateEdgeKVNamespaceRequest{
   366  				Network: NamespaceStagingNetwork,
   367  				Namespace: Namespace{
   368  					Name:        "testNs",
   369  					Retention:   tools.IntPtr(0),
   370  					GeoLocation: "JP",
   371  					GroupID:     tools.IntPtr(0),
   372  				},
   373  			},
   374  			withError: func(t *testing.T, err error) {
   375  				expected := &Error{
   376  					Detail:    "The staging network only supports US location.",
   377  					Instance:  "/edgeKV/error-instances/afe8f030-30cc-4c8e-9e33-df6b86a9f947",
   378  					Status:    http.StatusBadRequest,
   379  					Title:     "Bad Request",
   380  					Type:      "https://learn.akamai.com",
   381  					ErrorCode: "EKV_2000",
   382  					AdditionalDetail: Additional{
   383  						RequestID: "a46f61d2c9539c77",
   384  					},
   385  				}
   386  				assert.True(t, errors.Is(err, expected), "want: %s; got: %s", expected, err)
   387  			},
   388  			expectedPath:   "/edgekv/v1/networks/staging/namespaces",
   389  			responseStatus: http.StatusBadRequest,
   390  			responseBody: `{
   391  				"detail": "The staging network only supports US location.",
   392      			"errorCode": "EKV_2000",
   393      			"instance": "/edgeKV/error-instances/afe8f030-30cc-4c8e-9e33-df6b86a9f947",
   394      			"status": 400,
   395      			"title": "Bad Request",
   396      			"type": "https://learn.akamai.com",
   397  				"additionalDetail": {
   398  					"requestId": "a46f61d2c9539c77"
   399  				}
   400  			}`,
   401  		},
   402  		"400 bad request - geoLocation for production network": {
   403  			params: CreateEdgeKVNamespaceRequest{
   404  				Network: NamespaceProductionNetwork,
   405  				Namespace: Namespace{
   406  					Name:        "testNs",
   407  					Retention:   tools.IntPtr(0),
   408  					GeoLocation: "INVALID",
   409  					GroupID:     tools.IntPtr(0),
   410  				},
   411  			},
   412  			withError: func(t *testing.T, err error) {
   413  				expected := &Error{
   414  					Detail:    "Specified geoLocation not supported. Please specify one of US, EU, JP, GLOBAL",
   415  					Instance:  "/edgeKV/error-instances/d4ae9ce3-7068-4ff8-aef6-3477a0dadbf0",
   416  					Status:    http.StatusBadRequest,
   417  					Title:     "Bad Request",
   418  					Type:      "https://learn.akamai.com",
   419  					ErrorCode: "EKV_2000",
   420  					AdditionalDetail: Additional{
   421  						RequestID: "a46f61d2c9539c77",
   422  					},
   423  				}
   424  				assert.True(t, errors.Is(err, expected), "want: %s; got: %s", expected, err)
   425  			},
   426  			expectedPath:   "/edgekv/v1/networks/production/namespaces",
   427  			responseStatus: http.StatusBadRequest,
   428  			responseBody: `{
   429  				"detail": "Specified geoLocation not supported. Please specify one of US, EU, JP, GLOBAL",
   430  				"errorCode": "EKV_2000",
   431  				"instance": "/edgeKV/error-instances/d4ae9ce3-7068-4ff8-aef6-3477a0dadbf0",
   432  				"status": 400,
   433  				"title": "Bad Request",
   434  				"type": "https://learn.akamai.com",
   435  				"additionalDetail": {
   436  					"requestId": "a46f61d2c9539c77"
   437  				}
   438  			}`,
   439  		},
   440  		"413 payload too large": {
   441  			params: CreateEdgeKVNamespaceRequest{
   442  				Network: NamespaceStagingNetwork,
   443  				Namespace: Namespace{
   444  					Name:      "testNs",
   445  					Retention: tools.IntPtr(0),
   446  					GroupID:   tools.IntPtr(0),
   447  				},
   448  			},
   449  			withError: func(t *testing.T, err error) {
   450  				expected := &Error{
   451  					Detail:    "Each account is allowed 20 namespaces. This limit has already been reached.",
   452  					Instance:  "/edgeKV/error-instances/f65424a8-dbea-4799-a2f1-44acc45a121b",
   453  					Status:    http.StatusRequestEntityTooLarge,
   454  					Title:     "Payload Too Large",
   455  					Type:      "https://learn.akamai.com",
   456  					ErrorCode: "EKV_9000",
   457  					AdditionalDetail: Additional{
   458  						RequestID: "a46f61d2c9539c77",
   459  					},
   460  				}
   461  				assert.True(t, errors.Is(err, expected), "want: %s; got: %s", expected, err)
   462  			},
   463  			expectedPath:   "/edgekv/v1/networks/staging/namespaces",
   464  			responseStatus: http.StatusBadRequest,
   465  			responseBody: `{
   466  				"detail": "Each account is allowed 20 namespaces. This limit has already been reached.",
   467  				"errorCode": "EKV_9000",
   468  				"instance": "/edgeKV/error-instances/f65424a8-dbea-4799-a2f1-44acc45a121b",
   469  				"status": 413,
   470  				"title": "Payload Too Large",
   471  				"type": "https://learn.akamai.com",
   472  				"additionalDetail": {
   473  					"requestId": "a46f61d2c9539c77"
   474  				}
   475  			}`,
   476  		},
   477  		"missing required parameters": {
   478  			params: CreateEdgeKVNamespaceRequest{},
   479  			withError: func(t *testing.T, err error) {
   480  				assert.Containsf(t, err.Error(), "Network: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   481  				assert.Containsf(t, err.Error(), "Name: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   482  				assert.Containsf(t, err.Error(), "Retention: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   483  				assert.Containsf(t, err.Error(), "GroupID: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   484  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   485  			},
   486  		},
   487  		"retention less than 86400": {
   488  			params: CreateEdgeKVNamespaceRequest{
   489  				Network: NamespaceStagingNetwork,
   490  				Namespace: Namespace{
   491  					Name:      "testNs",
   492  					Retention: tools.IntPtr(86399),
   493  					GroupID:   tools.IntPtr(0),
   494  				},
   495  			},
   496  			withError: func(t *testing.T, err error) {
   497  				assert.Containsf(t, err.Error(), "Retention: a non zero value specified for retention period cannot be less than 86400 or more than 315360000", "want: %s; got: %s", ErrStructValidation, err)
   498  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   499  			},
   500  		},
   501  		"retention more than 315360000": {
   502  			params: CreateEdgeKVNamespaceRequest{
   503  				Network: NamespaceStagingNetwork,
   504  				Namespace: Namespace{
   505  					Name:      "testNs",
   506  					Retention: tools.IntPtr(315360001),
   507  					GroupID:   tools.IntPtr(0),
   508  				},
   509  			},
   510  			withError: func(t *testing.T, err error) {
   511  				assert.Containsf(t, err.Error(), "Retention: a non zero value specified for retention period cannot be less than 86400 or more than 315360000", "want: %s; got: %s", ErrStructValidation, err)
   512  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   513  			},
   514  		},
   515  		"namespace name too long": {
   516  			params: CreateEdgeKVNamespaceRequest{
   517  				Network: NamespaceStagingNetwork,
   518  				Namespace: Namespace{
   519  					Name:      "namespaceNameThatHasMoreThan32Letters",
   520  					Retention: tools.IntPtr(0),
   521  					GroupID:   tools.IntPtr(0),
   522  				},
   523  			},
   524  			withError: func(t *testing.T, err error) {
   525  				assert.Containsf(t, err.Error(), "Name: the length must be between 1 and 32", "want: %s; got: %s", ErrStructValidation, err)
   526  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   527  			},
   528  		},
   529  		"groupID less than 0": {
   530  			params: CreateEdgeKVNamespaceRequest{
   531  				Network: NamespaceStagingNetwork,
   532  				Namespace: Namespace{
   533  					Name:      "groupIDLessThan0",
   534  					Retention: tools.IntPtr(0),
   535  					GroupID:   tools.IntPtr(-1),
   536  				},
   537  			},
   538  			withError: func(t *testing.T, err error) {
   539  				assert.Containsf(t, err.Error(), "GroupID: cannot be less than 0", "want: %s; got: %s", ErrStructValidation, err)
   540  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   541  			},
   542  		},
   543  	}
   544  
   545  	for name, test := range tests {
   546  		t.Run(name, func(t *testing.T) {
   547  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   548  				assert.Equal(t, test.expectedPath, r.URL.String())
   549  				assert.Equal(t, http.MethodPost, r.Method)
   550  				w.WriteHeader(test.responseStatus)
   551  				_, err := w.Write([]byte(test.responseBody))
   552  				assert.NoError(t, err)
   553  			}))
   554  			client := mockAPIClient(t, mockServer)
   555  
   556  			result, err := client.CreateEdgeKVNamespace(context.Background(), test.params)
   557  			if test.withError != nil {
   558  				test.withError(t, err)
   559  				return
   560  			}
   561  			require.NoError(t, err)
   562  			assert.Equal(t, test.expectedResult, result)
   563  		})
   564  	}
   565  }
   566  
   567  func TestUpdateNamespace(t *testing.T) {
   568  	tests := map[string]struct {
   569  		params         UpdateEdgeKVNamespaceRequest
   570  		withError      func(*testing.T, error)
   571  		expectedPath   string
   572  		responseStatus int
   573  		responseBody   string
   574  		expectedResult *Namespace
   575  	}{
   576  		"200 OK - production": {
   577  			params: UpdateEdgeKVNamespaceRequest{
   578  				Network: NamespaceProductionNetwork,
   579  				UpdateNamespace: UpdateNamespace{
   580  					Name:      "testNs",
   581  					Retention: tools.IntPtr(86400),
   582  					GroupID:   tools.IntPtr(0),
   583  				},
   584  			},
   585  			expectedPath:   "/edgekv/v1/networks/production/namespaces/testNs",
   586  			responseStatus: http.StatusOK,
   587  			responseBody: `{
   588  				"namespace": "testNs",
   589  				"retentionInSeconds": 86400,
   590  				"geoLocation": "EU",
   591  				"groupId": 0
   592  			}`,
   593  			expectedResult: &Namespace{
   594  				Name:        "testNs",
   595  				Retention:   tools.IntPtr(86400),
   596  				GeoLocation: "EU",
   597  				GroupID:     tools.IntPtr(0),
   598  			},
   599  		},
   600  		"200 OK - staging": {
   601  			params: UpdateEdgeKVNamespaceRequest{
   602  				Network: NamespaceStagingNetwork,
   603  				UpdateNamespace: UpdateNamespace{
   604  					Name:      "testNs",
   605  					Retention: tools.IntPtr(86400),
   606  					GroupID:   tools.IntPtr(123),
   607  				},
   608  			},
   609  			expectedPath:   "/edgekv/v1/networks/staging/namespaces/testNs",
   610  			responseStatus: http.StatusOK,
   611  			responseBody: `{
   612  				"namespace": "testNs",
   613  				"retentionInSeconds": 86400,
   614  				"geoLocation": "US",
   615  				"groupId": 123
   616  			}`,
   617  			expectedResult: &Namespace{
   618  				Name:        "testNs",
   619  				Retention:   tools.IntPtr(86400),
   620  				GeoLocation: "US",
   621  				GroupID:     tools.IntPtr(123),
   622  			},
   623  		},
   624  		"409 conflict": {
   625  			params: UpdateEdgeKVNamespaceRequest{
   626  				Network: NamespaceStagingNetwork,
   627  				UpdateNamespace: UpdateNamespace{
   628  					Name:      "testNs_2",
   629  					Retention: tools.IntPtr(0),
   630  					GroupID:   tools.IntPtr(0),
   631  				},
   632  			},
   633  			withError: func(t *testing.T, err error) {
   634  				expected := &Error{
   635  					Detail:    "Cannot update a namespace that does not exist on the network",
   636  					Instance:  "/edgeKV/error-instances/792cc619-2e89-4474-b5e5-e302d2f59e05",
   637  					Status:    http.StatusConflict,
   638  					Title:     "Conflict",
   639  					Type:      "https://learn.akamai.com",
   640  					ErrorCode: "EKV_3000",
   641  					AdditionalDetail: Additional{
   642  						RequestID: "a46f61d2c9539c77",
   643  					},
   644  				}
   645  				assert.True(t, errors.Is(err, expected), "want: %s; got: %s", expected, err)
   646  			},
   647  			expectedPath:   "/edgekv/v1/networks/staging/namespaces/testNs_2",
   648  			responseStatus: http.StatusBadRequest,
   649  			responseBody: `{
   650  				"detail": "Cannot update a namespace that does not exist on the network",
   651  				"errorCode": "EKV_3000",
   652  				"instance": "/edgeKV/error-instances/792cc619-2e89-4474-b5e5-e302d2f59e05",
   653  				"status": 409,
   654  				"title": "Conflict",
   655  				"type": "https://learn.akamai.com",
   656  				"additionalDetail": {
   657  					"requestId": "a46f61d2c9539c77"
   658  				}
   659  			}`,
   660  		},
   661  		"missing required parameters": {
   662  			params: UpdateEdgeKVNamespaceRequest{},
   663  			withError: func(t *testing.T, err error) {
   664  				assert.Containsf(t, err.Error(), "Network: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   665  				assert.Containsf(t, err.Error(), "Name: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   666  				assert.Containsf(t, err.Error(), "Retention: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   667  				assert.Containsf(t, err.Error(), "GroupID: cannot be blank", "want: %s; got: %s", ErrStructValidation, err)
   668  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   669  			},
   670  		},
   671  		"namespace name too long": {
   672  			params: UpdateEdgeKVNamespaceRequest{
   673  				Network: NamespaceStagingNetwork,
   674  				UpdateNamespace: UpdateNamespace{
   675  					Name:      "namespaceNameThatHasMoreThan32Letters",
   676  					Retention: tools.IntPtr(0),
   677  					GroupID:   tools.IntPtr(0),
   678  				},
   679  			},
   680  			withError: func(t *testing.T, err error) {
   681  				assert.Containsf(t, err.Error(), "Name: the length must be between 1 and 32", "want: %s; got: %s", ErrStructValidation, err)
   682  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   683  			},
   684  		},
   685  		"groupID less than 0": {
   686  			params: UpdateEdgeKVNamespaceRequest{
   687  				Network: NamespaceStagingNetwork,
   688  				UpdateNamespace: UpdateNamespace{
   689  					Name:      "groupIDLessThan0",
   690  					Retention: tools.IntPtr(0),
   691  					GroupID:   tools.IntPtr(-1),
   692  				},
   693  			},
   694  			withError: func(t *testing.T, err error) {
   695  				assert.Containsf(t, err.Error(), "GroupID: cannot be less than 0", "want: %s; got: %s", ErrStructValidation, err)
   696  				assert.True(t, errors.Is(err, ErrStructValidation), "want: %s; got: %s", ErrStructValidation, err)
   697  			},
   698  		},
   699  	}
   700  
   701  	for name, test := range tests {
   702  		t.Run(name, func(t *testing.T) {
   703  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   704  				assert.Equal(t, test.expectedPath, r.URL.String())
   705  				assert.Equal(t, http.MethodPut, r.Method)
   706  				w.WriteHeader(test.responseStatus)
   707  				_, err := w.Write([]byte(test.responseBody))
   708  				assert.NoError(t, err)
   709  			}))
   710  			client := mockAPIClient(t, mockServer)
   711  
   712  			result, err := client.UpdateEdgeKVNamespace(context.Background(), test.params)
   713  			if test.withError != nil {
   714  				test.withError(t, err)
   715  				return
   716  			}
   717  			require.NoError(t, err)
   718  			assert.Equal(t, test.expectedResult, result)
   719  		})
   720  	}
   721  }