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

     1  package edgeworkers
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"strconv"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestCreateEdgeKVAccessToken(t *testing.T) {
    17  	tests := map[string]struct {
    18  		params              CreateEdgeKVAccessTokenRequest
    19  		expectedRequestBody string
    20  		responseStatus      int
    21  		responseBody        string
    22  		expectedPath        string
    23  		expectedResponse    *CreateEdgeKVAccessTokenResponse
    24  		withError           error
    25  	}{
    26  		"200 OK - create token": {
    27  			params: CreateEdgeKVAccessTokenRequest{
    28  				AllowOnProduction: false,
    29  				AllowOnStaging:    true,
    30  				Expiry:            "2022-03-30",
    31  				Name:              "devexp-token-1",
    32  				NamespacePermissions: NamespacePermissions{
    33  					"default":            []Permission{"r", "w", "d"},
    34  					"devexp-jsmith-test": []Permission{"r", "w"},
    35  				},
    36  			},
    37  			expectedRequestBody: `{"allowOnProduction":false,"allowOnStaging":true,"expiry":"2022-03-30","name":"devexp-token-1","namespacePermissions":{"default":["r","w","d"],"devexp-jsmith-test":["r","w"]}}`,
    38  			responseStatus:      http.StatusOK,
    39  			responseBody: `
    40  {
    41      "name": "devexp-token-1",
    42      "uuid": "1ab0e94b-c47e-568e-ab3e-1921ffcefe0c",
    43      "expiry": "2022-03-30",
    44      "value": "eyJ0eXAiOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg"
    45  }`,
    46  			expectedPath: "/edgekv/v1/tokens",
    47  			expectedResponse: &CreateEdgeKVAccessTokenResponse{
    48  				Name:   "devexp-token-1",
    49  				UUID:   "1ab0e94b-c47e-568e-ab3e-1921ffcefe0c",
    50  				Expiry: "2022-03-30",
    51  				Value:  "eyJ0eXAiOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg",
    52  			},
    53  		},
    54  		"at least one allow is required": {
    55  			params: CreateEdgeKVAccessTokenRequest{
    56  				AllowOnProduction: false,
    57  				AllowOnStaging:    false,
    58  				Expiry:            "2022-03-30",
    59  				Name:              "name",
    60  				NamespacePermissions: NamespacePermissions{
    61  					"default":            []Permission{"r", "w", "d"},
    62  					"devexp-jsmith-test": []Permission{"r", "w"},
    63  				},
    64  			},
    65  			withError: ErrStructValidation,
    66  		},
    67  		"missing Name": {
    68  			params: CreateEdgeKVAccessTokenRequest{
    69  				AllowOnProduction: true,
    70  				AllowOnStaging:    true,
    71  				Expiry:            "2022-03-30",
    72  				Name:              "",
    73  				NamespacePermissions: NamespacePermissions{
    74  					"default":            []Permission{"r", "w", "d"},
    75  					"devexp-jsmith-test": []Permission{"r", "w"},
    76  				},
    77  			}, withError: ErrStructValidation,
    78  		},
    79  		"invalid date": {
    80  			params: CreateEdgeKVAccessTokenRequest{
    81  				AllowOnProduction: true,
    82  				AllowOnStaging:    true,
    83  				Expiry:            "30/09/2021",
    84  				Name:              "name",
    85  				NamespacePermissions: NamespacePermissions{
    86  					"default":            []Permission{"r", "w", "d"},
    87  					"devexp-jsmith-test": []Permission{"r", "w"},
    88  				},
    89  			}, withError: ErrStructValidation,
    90  		},
    91  		"invalid permission": {
    92  			params: CreateEdgeKVAccessTokenRequest{
    93  				AllowOnProduction: true,
    94  				AllowOnStaging:    true,
    95  				Expiry:            "2022-03-30",
    96  				Name:              "devexp-token-1",
    97  				NamespacePermissions: NamespacePermissions{
    98  					"default": []Permission{"a", "w", "d"},
    99  				},
   100  			}, withError: ErrStructValidation,
   101  		},
   102  		"empty namespace": {
   103  			params: CreateEdgeKVAccessTokenRequest{
   104  				AllowOnProduction: true,
   105  				AllowOnStaging:    true,
   106  				Expiry:            "2022-03-30",
   107  				Name:              "devexp-token-1",
   108  				NamespacePermissions: NamespacePermissions{
   109  					"": []Permission{"r", "w", "d"},
   110  				},
   111  			}, withError: ErrStructValidation,
   112  		},
   113  		"missing permission": {
   114  			params: CreateEdgeKVAccessTokenRequest{
   115  				AllowOnProduction: true,
   116  				AllowOnStaging:    true,
   117  				Expiry:            "2022-03-30",
   118  				Name:              "devexp-token-1",
   119  				NamespacePermissions: NamespacePermissions{
   120  					"default": []Permission{},
   121  				},
   122  			}, withError: ErrStructValidation,
   123  		},
   124  		"missing NamespacePermissions": {
   125  			params: CreateEdgeKVAccessTokenRequest{
   126  				AllowOnProduction: true,
   127  				AllowOnStaging:    true,
   128  				Expiry:            "2022-03-30",
   129  				Name:              "devexp-token-1",
   130  			}, withError: ErrStructValidation,
   131  		},
   132  		"400 bad request": {
   133  			params: CreateEdgeKVAccessTokenRequest{
   134  				AllowOnProduction: true,
   135  				AllowOnStaging:    true,
   136  				Expiry:            "2022-03-30",
   137  				Name:              "devexp-token-1",
   138  				NamespacePermissions: NamespacePermissions{
   139  					"default": []Permission{"r", "w", "d"},
   140  				},
   141  			},
   142  			responseStatus: http.StatusConflict,
   143  			responseBody: `
   144  {
   145      "detail": "Invalid permission",
   146      "errorCode": "EKV_2000",
   147      "instance": "/edgeKV/error-instances/1f2a46ed-b6e8-4f50-b4db-102e260c1753",
   148      "status": 400,
   149      "title": "Bad Request",
   150      "type": "https://learn.akamai.com",
   151      "additionalDetail": {
   152          "requestId": "f60f61cda34a0657"
   153      }
   154  }`,
   155  			expectedPath: "/edgekv/v1/tokens",
   156  			withError: &Error{
   157  				Detail:    "Invalid permission",
   158  				ErrorCode: "EKV_2000",
   159  				Instance:  "/edgeKV/error-instances/1f2a46ed-b6e8-4f50-b4db-102e260c1753",
   160  				Status:    400,
   161  				Title:     "Bad Request",
   162  				Type:      "https://learn.akamai.com",
   163  				AdditionalDetail: Additional{
   164  					RequestID: "f60f61cda34a0657",
   165  				},
   166  			},
   167  		},
   168  		"401 Not authorized - incorrect credentials": {
   169  			params: CreateEdgeKVAccessTokenRequest{
   170  				AllowOnProduction: true,
   171  				AllowOnStaging:    true,
   172  				Expiry:            "2022-03-30",
   173  				Name:              "devexp-token-1",
   174  				NamespacePermissions: NamespacePermissions{
   175  					"default":            []Permission{"r", "w", "d"},
   176  					"devexp-jsmith-test": []Permission{"r", "w"},
   177  				},
   178  			},
   179  			responseStatus: http.StatusUnauthorized,
   180  			responseBody: `
   181  {
   182      "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   183      "title": "Not authorized",
   184      "status": 401,
   185      "detail": "Inactive client token",
   186      "instance": "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens",
   187      "method": "POST",
   188      "serverIp": "104.81.220.242",
   189      "clientIp": "22.22.22.22",
   190      "requestId": "1e7f0f0f",
   191      "requestTime": "2021-12-30T14:12:50Z"
   192  }`,
   193  			expectedPath: "/edgekv/v1/tokens",
   194  			withError: &Error{
   195  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   196  				Title:       "Not authorized",
   197  				Status:      401,
   198  				Detail:      "Inactive client token",
   199  				Instance:    "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens",
   200  				Method:      "POST",
   201  				ServerIP:    "104.81.220.242",
   202  				ClientIP:    "22.22.22.22",
   203  				RequestID:   "1e7f0f0f",
   204  				RequestTime: "2021-12-30T14:12:50Z",
   205  			},
   206  		},
   207  		"409 duplicated token name": {
   208  			params: CreateEdgeKVAccessTokenRequest{
   209  				AllowOnProduction: true,
   210  				AllowOnStaging:    true,
   211  				Expiry:            "2022-03-30",
   212  				Name:              "devexp-token-1",
   213  				NamespacePermissions: NamespacePermissions{
   214  					"default":            []Permission{"r", "w", "d"},
   215  					"devexp-jsmith-test": []Permission{"r", "w"},
   216  				},
   217  			},
   218  			responseStatus: http.StatusConflict,
   219  			responseBody: `
   220  {
   221      "detail": "Token with name devexp-token-1 is already stored.",
   222      "errorCode": "EKV_3000",
   223      "instance": "/edgeKV/error-instances/e82edcd9-498e-42f9-a078-6d9c4f9dbcb9",
   224      "status": 409,
   225      "title": "Conflict",
   226      "type": "https://learn.akamai.com",
   227      "additionalDetail": {
   228          "requestId": "bc7561cda1f3021b"
   229      }
   230  }`,
   231  			expectedPath: "/edgekv/v1/tokens",
   232  			withError: &Error{
   233  				Detail:    "Token with name devexp-token-1 is already stored.",
   234  				ErrorCode: "EKV_3000",
   235  				Instance:  "/edgeKV/error-instances/e82edcd9-498e-42f9-a078-6d9c4f9dbcb9",
   236  				Status:    409,
   237  				Title:     "Conflict",
   238  				Type:      "https://learn.akamai.com",
   239  				AdditionalDetail: Additional{
   240  					RequestID: "bc7561cda1f3021b",
   241  				},
   242  			},
   243  		},
   244  		"500 internal server error": {
   245  			params: CreateEdgeKVAccessTokenRequest{
   246  				AllowOnProduction: true,
   247  				AllowOnStaging:    true,
   248  				Expiry:            "2022-03-30",
   249  				Name:              "devexp-token-1",
   250  				NamespacePermissions: NamespacePermissions{
   251  					"default":            []Permission{"r", "w", "d"},
   252  					"devexp-jsmith-test": []Permission{"r", "w"},
   253  				},
   254  			},
   255  			responseStatus: http.StatusInternalServerError,
   256  			responseBody: `
   257  {
   258      "detail": "An internal error occurred.",
   259      "errorCode": "EKV_0000",
   260      "instance": "/edgeKV/error-instances/e9bc19b5-ec1e-485d-80d0-20237a928684",
   261      "status": 500,
   262      "title": "Internal Server Error",
   263      "type": "https://learn.akamai.com",
   264      "additionalDetail": {
   265          "requestId": "b2f461d47426558c"
   266      }
   267  }`,
   268  			expectedPath: "/edgekv/v1/tokens",
   269  			withError: &Error{
   270  				Detail:    "An internal error occurred.",
   271  				ErrorCode: "EKV_0000",
   272  				Instance:  "/edgeKV/error-instances/e9bc19b5-ec1e-485d-80d0-20237a928684",
   273  				Status:    500,
   274  				Title:     "Internal Server Error",
   275  				Type:      "https://learn.akamai.com",
   276  				AdditionalDetail: Additional{
   277  					RequestID: "b2f461d47426558c",
   278  				},
   279  			},
   280  		},
   281  	}
   282  	for name, test := range tests {
   283  		t.Run(name, func(t *testing.T) {
   284  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   285  				assert.Equal(t, test.expectedPath, r.URL.String())
   286  				assert.Equal(t, http.MethodPost, r.Method)
   287  				w.WriteHeader(test.responseStatus)
   288  				_, err := w.Write([]byte(test.responseBody))
   289  				assert.NoError(t, err)
   290  
   291  				if len(test.expectedRequestBody) > 0 {
   292  					body, err := ioutil.ReadAll(r.Body)
   293  					require.NoError(t, err)
   294  					assert.Equal(t, test.expectedRequestBody, string(body))
   295  				}
   296  
   297  			}))
   298  			client := mockAPIClient(t, mockServer)
   299  			result, err := client.CreateEdgeKVAccessToken(context.Background(), test.params)
   300  			if test.withError != nil {
   301  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   302  				return
   303  			}
   304  			require.NoError(t, err)
   305  			assert.Equal(t, test.expectedResponse, result)
   306  		})
   307  	}
   308  }
   309  
   310  func TestGetEdgeKVAccessToken(t *testing.T) {
   311  	tests := map[string]struct {
   312  		params           GetEdgeKVAccessTokenRequest
   313  		responseStatus   int
   314  		responseBody     string
   315  		expectedPath     string
   316  		expectedResponse *GetEdgeKVAccessTokenResponse
   317  		withError        error
   318  	}{
   319  		"200 OK - get token": {
   320  			params: GetEdgeKVAccessTokenRequest{
   321  				TokenName: "devexp-token-1",
   322  			},
   323  			responseStatus: http.StatusOK,
   324  			responseBody: `
   325  {
   326      "name": "devexp-token-1",
   327      "uuid": "10b0e94b-c47e-568e-ab3e-1921ffcefe0c",
   328      "expiry": "2022-03-30",
   329      "value": "eyJ0eXAxOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg"
   330  }`,
   331  			expectedPath: "/edgekv/v1/tokens/devexp-token-1",
   332  			expectedResponse: &GetEdgeKVAccessTokenResponse{
   333  				Name:   "devexp-token-1",
   334  				UUID:   "10b0e94b-c47e-568e-ab3e-1921ffcefe0c",
   335  				Expiry: "2022-03-30",
   336  				Value:  "eyJ0eXAxOxJKV1QxLCJhbGciOiJSUzI1NiJ9.eyJld2lkcyI6ImFsbCIsInN1YiI6IjUwMCIsIm5hbWVzcGFjZS1kZWZhdWx0IjpbInIiLCJkIiwidyJdLCJjcGMiOiI5NzEwNTIiLCJpc3MiOiJha2FtYWkuY29tL0VkZ2VEQi9QdWxzYXIvdjAuMTEuMCIsIm5hbWVzcGFjZS1kZXZleHAtcm9iZXJ0by10ZXN0IjpbInIiLCJ3Il0sImV4cCI6MTY0ODY4NDc5OSwiZW52IjpbInAiLCJzIl0sImlhdCI6MTY0MDg1ODIzNywianRpIjoiMTBiMGU5NGItYzQ3ZS01NjhlLWFiM2UtMTkyMWZmY2VmZTBjIiwicmVxaWQiOiJha2FtYWkiLCJub2VjbCI6dHJ1ZX0.AZfP-VFqDKNWcu1Or73EFfjG_GBDdJUP81Zs0BnNs_bScc8oyBAEiBjxwEsUxrvRRr7rSu-BxFjiDpxx5DlfbgEwd8H2DFV08cfQFqs7aab4WYLrx4ZweD9Hbg2gGLA-dRAbtSrq_FQKQysOvO2ymPn13E78PvK96t8r4cnN1irXbfyBUOXOE3OVOAKsk-w0Ig7qFDa_4o6YyDMPTpwEQ34T1cVqRYStIVzjSaCwgSfdaQG5qzTzTlFoDzG24tz8YlLgoM5OQf9xgsTsisCOF2jf44VWMu2S0e6MIC5gg7zXx7X2t59Y8TsAd0VqqB37y0AzEXkJblbZUlO9HcGebg",
   337  			},
   338  		},
   339  		"missing token name": {
   340  			params:    GetEdgeKVAccessTokenRequest{},
   341  			withError: ErrStructValidation,
   342  		},
   343  		"403 Forbidden - incorrect credentials": {
   344  			params: GetEdgeKVAccessTokenRequest{
   345  				TokenName: "devexp-token-1",
   346  			},
   347  			responseStatus: http.StatusForbidden,
   348  			responseBody: `
   349  {
   350      "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   351      "title": "Not authorized",
   352      "status": 401,
   353      "detail": "Inactive client token",
   354      "instance": "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens/devexp-token-99",
   355      "method": "GET",
   356      "serverIp": "104.81.220.242",
   357      "clientIp": "22.22.22.22",
   358      "requestId": "cb5cd20",
   359      "requestTime": "2022-01-03T07:46:28Z"
   360  }`,
   361  			expectedPath: "/edgekv/v1/tokens/devexp-token-1",
   362  			withError: &Error{
   363  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   364  				Title:       "Not authorized",
   365  				Status:      401,
   366  				Detail:      "Inactive client token",
   367  				Instance:    "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens/devexp-token-99",
   368  				Method:      "GET",
   369  				ServerIP:    "104.81.220.242",
   370  				ClientIP:    "22.22.22.22",
   371  				RequestID:   "cb5cd20",
   372  				RequestTime: "2022-01-03T07:46:28Z",
   373  			},
   374  		},
   375  		"404 Not Found - Token doesn't exist": {
   376  			params: GetEdgeKVAccessTokenRequest{
   377  				TokenName: "devexp-token-99",
   378  			},
   379  			responseStatus: http.StatusNotFound,
   380  			responseBody: `
   381  {
   382      "detail": "Token with name devexp-token-99 does not exist.",
   383      "errorCode": "EKV_3000",
   384      "instance": "/edgeKV/error-instances/add4ab5a-48b0-4350-aa8b-7f64e9b6a5ea",
   385      "status": 404,
   386      "title": "Not Found",
   387      "type": "https://learn.akamai.com",
   388      "additionalDetail": {
   389          "requestId": "ae9061cddea87d94"
   390      }
   391  }`,
   392  			expectedPath: "/edgekv/v1/tokens/devexp-token-99",
   393  			withError: &Error{
   394  				Detail:    "Token with name devexp-token-99 does not exist.",
   395  				ErrorCode: "EKV_3000",
   396  				Instance:  "/edgeKV/error-instances/add4ab5a-48b0-4350-aa8b-7f64e9b6a5ea",
   397  				Status:    404,
   398  				Title:     "Not Found",
   399  				Type:      "https://learn.akamai.com",
   400  				AdditionalDetail: Additional{
   401  					RequestID: "ae9061cddea87d94",
   402  				},
   403  			},
   404  		},
   405  		"500 Internal server error": {
   406  			params: GetEdgeKVAccessTokenRequest{
   407  				TokenName: ";",
   408  			},
   409  			responseStatus: http.StatusInternalServerError,
   410  			responseBody: `
   411  {
   412      "type": "https://problems.luna-dev.akamaiapis.net/-/resource-impl/forward-origin-error",
   413      "title": "Server Error",
   414      "status": 500,
   415      "instance": "https://akaa-7udtftgmvpnmsbwx-noxd5uwfehzxv4rj.luna-dev.akamaiapis.net/edgekv/v1/tokens/;",
   416      "method": "GET",
   417      "serverIp": "104.81.220.242",
   418      "clientIp": "22.22.22.22",
   419      "requestId": "e98b01a",
   420      "requestTime": "2022-01-03T11:13:00Z"
   421  }`,
   422  			expectedPath: "/edgekv/v1/tokens/;",
   423  			withError: &Error{
   424  				Type:        "https://problems.luna-dev.akamaiapis.net/-/resource-impl/forward-origin-error",
   425  				Title:       "Server Error",
   426  				Status:      500,
   427  				Instance:    "https://akaa-7udtftgmvpnmsbwx-noxd5uwfehzxv4rj.luna-dev.akamaiapis.net/edgekv/v1/tokens/;",
   428  				Method:      "GET",
   429  				ServerIP:    "104.81.220.242",
   430  				ClientIP:    "22.22.22.22",
   431  				RequestID:   "e98b01a",
   432  				RequestTime: "2022-01-03T11:13:00Z",
   433  			},
   434  		},
   435  	}
   436  
   437  	for name, test := range tests {
   438  		t.Run(name, func(t *testing.T) {
   439  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   440  				assert.Equal(t, test.expectedPath, r.URL.String())
   441  				assert.Equal(t, http.MethodGet, r.Method)
   442  				w.WriteHeader(test.responseStatus)
   443  				_, err := w.Write([]byte(test.responseBody))
   444  				assert.NoError(t, err)
   445  			}))
   446  			client := mockAPIClient(t, mockServer)
   447  			result, err := client.GetEdgeKVAccessToken(context.Background(), test.params)
   448  			if test.withError != nil {
   449  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   450  				return
   451  			}
   452  			require.NoError(t, err)
   453  			assert.Equal(t, test.expectedResponse, result)
   454  		})
   455  	}
   456  }
   457  
   458  func TestListEdgeKVAccessTokens(t *testing.T) {
   459  	tests := map[string]struct {
   460  		params           ListEdgeKVAccessTokensRequest
   461  		responseStatus   int
   462  		responseBody     string
   463  		expectedPath     string
   464  		expectedResponse *ListEdgeKVAccessTokensResponse
   465  		withError        error
   466  	}{
   467  		"200 OK - list EdgeKV tokens": {
   468  			responseStatus: http.StatusOK,
   469  			responseBody: `
   470  {
   471      "tokens": [
   472          {
   473              "name": "my_token",
   474              "uuid": "8301fef4-80e5-5efb-9bfb-8f5869a5df7b",
   475              "expiry": "2022-03-30"
   476          },
   477          {
   478              "name": "token1",
   479              "uuid": "5b5d3bfb-8d2e-5fbb-858d-33807edc9554",
   480              "expiry": "2022-01-22"
   481          },
   482          {
   483              "name": "token2",
   484              "uuid": "62181cfe-268a-5302-8834-67c67ec86efd",
   485              "expiry": "2022-01-22"
   486          },
   487          {
   488              "name": "token3",
   489              "uuid": "edb02678-ae1c-564c-8f73-c977ffdfe016",
   490              "expiry": "2022-01-22"
   491          }
   492      ]
   493  }`,
   494  			expectedPath: "/edgekv/v1/tokens",
   495  			expectedResponse: &ListEdgeKVAccessTokensResponse{
   496  				[]EdgeKVAccessToken{
   497  					{
   498  						Name:   "my_token",
   499  						UUID:   "8301fef4-80e5-5efb-9bfb-8f5869a5df7b",
   500  						Expiry: "2022-03-30",
   501  					},
   502  					{
   503  						Name:   "token1",
   504  						UUID:   "5b5d3bfb-8d2e-5fbb-858d-33807edc9554",
   505  						Expiry: "2022-01-22",
   506  					},
   507  					{
   508  						Name:   "token2",
   509  						UUID:   "62181cfe-268a-5302-8834-67c67ec86efd",
   510  						Expiry: "2022-01-22",
   511  					},
   512  					{
   513  						Name:   "token3",
   514  						UUID:   "edb02678-ae1c-564c-8f73-c977ffdfe016",
   515  						Expiry: "2022-01-22",
   516  					},
   517  				},
   518  			},
   519  		},
   520  		"200 OK - list EdgeKV tokens including expired": {
   521  			params: ListEdgeKVAccessTokensRequest{
   522  				IncludeExpired: true,
   523  			},
   524  			responseStatus: http.StatusOK,
   525  			responseBody: `
   526  {
   527      "tokens": [
   528          {
   529              "name": "my_token",
   530              "uuid": "8301fef4-80e5-5efb-9bfb-8f5869a5df7b",
   531              "expiry": "2022-03-30"
   532          },
   533          {
   534              "name": "token1",
   535              "uuid": "5b5d3bfb-8d2e-5fbb-858d-33807edc9554",
   536              "expiry": "2022-01-22"
   537          },
   538          {
   539              "name": "token2",
   540              "uuid": "62181cfe-268a-5302-8834-67c67ec86efd",
   541              "expiry": "2022-01-22"
   542          },
   543          {
   544              "name": "token3",
   545              "uuid": "edb02678-ae1c-564c-8f73-c977ffdfe016",
   546              "expiry": "2022-01-22"
   547          },
   548          {
   549              "name": "preexistingTokenTest",
   550              "uuid": "7a14da8c-1709-570b-9535-2cc6e2ee5a8a",
   551              "expiry": "2021-12-21"
   552          }
   553      ]
   554  }`,
   555  			expectedPath: "/edgekv/v1/tokens?includeExpired=true",
   556  			expectedResponse: &ListEdgeKVAccessTokensResponse{
   557  				[]EdgeKVAccessToken{
   558  					{
   559  						Name:   "my_token",
   560  						UUID:   "8301fef4-80e5-5efb-9bfb-8f5869a5df7b",
   561  						Expiry: "2022-03-30",
   562  					},
   563  					{
   564  						Name:   "token1",
   565  						UUID:   "5b5d3bfb-8d2e-5fbb-858d-33807edc9554",
   566  						Expiry: "2022-01-22",
   567  					},
   568  					{
   569  						Name:   "token2",
   570  						UUID:   "62181cfe-268a-5302-8834-67c67ec86efd",
   571  						Expiry: "2022-01-22",
   572  					},
   573  					{
   574  						Name:   "token3",
   575  						UUID:   "edb02678-ae1c-564c-8f73-c977ffdfe016",
   576  						Expiry: "2022-01-22",
   577  					},
   578  					{
   579  						Name:   "preexistingTokenTest",
   580  						UUID:   "7a14da8c-1709-570b-9535-2cc6e2ee5a8a",
   581  						Expiry: "2021-12-21",
   582  					},
   583  				},
   584  			},
   585  		},
   586  		"401 Forbidden - incorrect credentials": {
   587  			responseStatus: http.StatusForbidden,
   588  			responseBody: `
   589  {
   590      "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   591      "title": "Not authorized",
   592      "status": 401,
   593      "detail": "Inactive client token",
   594      "instance": "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens",
   595      "method": "GET",
   596      "serverIp": "104.81.220.242",
   597      "clientIp": "22.22.22.22",
   598      "requestId": "d64edd6",
   599      "requestTime": "2022-01-03T09:01:30Z"
   600  }`,
   601  			expectedPath: "/edgekv/v1/tokens",
   602  			withError: &Error{
   603  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   604  				Title:       "Not authorized",
   605  				Status:      401,
   606  				Detail:      "Inactive client token",
   607  				Instance:    "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens",
   608  				Method:      "GET",
   609  				ServerIP:    "104.81.220.242",
   610  				ClientIP:    "22.22.22.22",
   611  				RequestID:   "d64edd6",
   612  				RequestTime: "2022-01-03T09:01:30Z",
   613  			},
   614  		},
   615  		"500 internal server error": {
   616  			responseStatus: http.StatusInternalServerError,
   617  			responseBody: `
   618  {
   619      "type": "https://problems.luna-dev.akamaiapis.net/-/resource-impl/forward-origin-error",
   620      "title": "Server Error",
   621      "status": 500,
   622      "instance": "https://akaa-7udtftgmvpnmsbwx-noxd5uwfehzxv4rj.luna-dev.akamaiapis.net/edgekv/v1/tokens/;",
   623      "method": "GET",
   624      "serverIp": "104.81.220.242",
   625      "clientIp": "22.22.22.22",
   626      "requestId": "e98b01a",
   627      "requestTime": "2022-01-03T11:13:00Z"
   628  }`,
   629  			expectedPath: "/edgekv/v1/tokens",
   630  			withError: &Error{
   631  				Type:        "https://problems.luna-dev.akamaiapis.net/-/resource-impl/forward-origin-error",
   632  				Title:       "Server Error",
   633  				Status:      500,
   634  				Instance:    "https://akaa-7udtftgmvpnmsbwx-noxd5uwfehzxv4rj.luna-dev.akamaiapis.net/edgekv/v1/tokens/;",
   635  				Method:      "GET",
   636  				ServerIP:    "104.81.220.242",
   637  				ClientIP:    "22.22.22.22",
   638  				RequestID:   "e98b01a",
   639  				RequestTime: "2022-01-03T11:13:00Z",
   640  			},
   641  		},
   642  	}
   643  	for name, test := range tests {
   644  		t.Run(name, func(t *testing.T) {
   645  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   646  				assert.Equal(t, test.expectedPath, r.URL.String())
   647  				assert.Equal(t, http.MethodGet, r.Method)
   648  				w.WriteHeader(test.responseStatus)
   649  				_, err := w.Write([]byte(test.responseBody))
   650  				assert.NoError(t, err)
   651  			}))
   652  			client := mockAPIClient(t, mockServer)
   653  			result, err := client.ListEdgeKVAccessTokens(context.Background(), test.params)
   654  			if test.withError != nil {
   655  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   656  				return
   657  			}
   658  			require.NoError(t, err)
   659  			assert.Equal(t, test.expectedResponse, result)
   660  		})
   661  	}
   662  }
   663  
   664  func TestDeleteEdgeKVAccessToken(t *testing.T) {
   665  	tests := map[string]struct {
   666  		params           DeleteEdgeKVAccessTokenRequest
   667  		withError        error
   668  		expectedPath     string
   669  		responseStatus   int
   670  		responseBody     string
   671  		expectedResponse *DeleteEdgeKVAccessTokenResponse
   672  	}{
   673  		"200 Deleted": {
   674  			params: DeleteEdgeKVAccessTokenRequest{
   675  				TokenName: "devexp-token-3",
   676  			},
   677  			expectedPath: "/edgekv/v1/tokens/devexp-token-3",
   678  			responseBody: `
   679  {
   680      "name": "devexp-token-3",
   681      "uuid": "cc0a9045-e654-5f17-9b37-6ab6e565803f"
   682  }`,
   683  			expectedResponse: &DeleteEdgeKVAccessTokenResponse{
   684  				Name: "devexp-token-3",
   685  				UUID: "cc0a9045-e654-5f17-9b37-6ab6e565803f",
   686  			},
   687  			responseStatus: http.StatusOK,
   688  		},
   689  		"missing token name": {
   690  			params: DeleteEdgeKVAccessTokenRequest{
   691  				TokenName: "",
   692  			},
   693  			withError: ErrStructValidation,
   694  		},
   695  		"401 not authorized": {
   696  			responseStatus: http.StatusUnauthorized,
   697  			params: DeleteEdgeKVAccessTokenRequest{
   698  				TokenName: "devexp-token-99",
   699  			},
   700  			expectedPath: "/edgekv/v1/tokens/devexp-token-99",
   701  			responseBody: `{
   702      "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   703      "title": "Not authorized",
   704      "status": 401,
   705      "detail": "Inactive client token",
   706      "instance": "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens/devexp-token-3",
   707      "method": "DELETE",
   708      "serverIp": "104.81.220.242",
   709      "clientIp": "22.22.22.22",
   710      "requestId": "ddc683c",
   711      "requestTime": "2022-01-03T09:51:55Z"
   712  }`,
   713  			withError: &Error{
   714  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
   715  				Title:       "Not authorized",
   716  				Status:      401,
   717  				Detail:      "Inactive client token",
   718  				Instance:    "https://akaa-p3wvjp6bqtotgpjh-fbk2vczjtq7b5l6a.luna-dev.akamaiapis.net/edgekv/v1/tokens/devexp-token-3",
   719  				Method:      "DELETE",
   720  				ServerIP:    "104.81.220.242",
   721  				ClientIP:    "22.22.22.22",
   722  				RequestID:   "ddc683c",
   723  				RequestTime: "2022-01-03T09:51:55Z",
   724  			},
   725  		},
   726  		"404 Not Found": {
   727  			params: DeleteEdgeKVAccessTokenRequest{
   728  				TokenName: "devexp-token-99",
   729  			},
   730  			expectedPath:   "/edgekv/v1/tokens/devexp-token-99",
   731  			responseStatus: http.StatusNotFound,
   732  			responseBody: `
   733  {
   734      "detail": "Token with name devexp-token-99 does not exist.",
   735      "errorCode": "EKV_3000",
   736      "instance": "/edgeKV/error-instances/d4d7171f-2ef9-4e60-96ba-1ad74e35bb39",
   737      "status": 404,
   738      "title": "Not Found",
   739      "type": "https://learn.akamai.com",
   740      "additionalDetail": {
   741          "requestId": "a46f61d2c9539c77"
   742      }
   743  }`,
   744  			withError: &Error{
   745  				Detail:    "Token with name devexp-token-99 does not exist.",
   746  				ErrorCode: "EKV_3000",
   747  				Instance:  "/edgeKV/error-instances/d4d7171f-2ef9-4e60-96ba-1ad74e35bb39",
   748  				Status:    404,
   749  				Title:     "Not Found",
   750  				Type:      "https://learn.akamai.com",
   751  				AdditionalDetail: Additional{
   752  					RequestID: "a46f61d2c9539c77",
   753  				},
   754  			},
   755  		},
   756  		"500 internal server error": {
   757  			params: DeleteEdgeKVAccessTokenRequest{
   758  				TokenName: ";",
   759  			},
   760  			responseStatus: http.StatusInternalServerError,
   761  			responseBody: `
   762  {
   763      "type": "https://problems.luna-dev.akamaiapis.net/-/resource-impl/forward-origin-error",
   764      "title": "Server Error",
   765      "status": 500,
   766      "instance": "https://akaa-7udtftgmvpnmsbwx-noxd5uwfehzxv4rj.luna-dev.akamaiapis.net/edgekv/v1/tokens/;",
   767      "method": "DELETE",
   768      "serverIp": "104.81.220.242",
   769      "clientIp": "22.22.22.22",
   770      "requestId": "e6f4e86",
   771      "requestTime": "2022-01-03T10:55:00Z"
   772  }`,
   773  			expectedPath: "/edgekv/v1/tokens/;",
   774  			withError: &Error{
   775  				Type:        "https://problems.luna-dev.akamaiapis.net/-/resource-impl/forward-origin-error",
   776  				Title:       "Server Error",
   777  				Status:      500,
   778  				Instance:    "https://akaa-7udtftgmvpnmsbwx-noxd5uwfehzxv4rj.luna-dev.akamaiapis.net/edgekv/v1/tokens/;",
   779  				Method:      "DELETE",
   780  				ServerIP:    "104.81.220.242",
   781  				ClientIP:    "22.22.22.22",
   782  				RequestID:   "e6f4e86",
   783  				RequestTime: "2022-01-03T10:55:00Z",
   784  			},
   785  		},
   786  	}
   787  	for name, test := range tests {
   788  		t.Run(name, func(t *testing.T) {
   789  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   790  				assert.Equal(t, test.expectedPath, r.URL.String())
   791  				assert.Equal(t, http.MethodDelete, r.Method)
   792  				w.WriteHeader(test.responseStatus)
   793  				_, err := w.Write([]byte(test.responseBody))
   794  				assert.NoError(t, err)
   795  			}))
   796  			client := mockAPIClient(t, mockServer)
   797  			_, err := client.DeleteEdgeKVAccessToken(context.Background(), test.params)
   798  			if test.withError != nil {
   799  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   800  				if test.responseStatus != 0 {
   801  					assert.Contains(t, err.Error(), strconv.FormatInt(int64(test.responseStatus), 10))
   802  				}
   803  
   804  				return
   805  			}
   806  			require.NoError(t, err)
   807  		})
   808  	}
   809  }