github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/cloudlets/v3/policy_test.go (about)

     1  package v3
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"io"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/tools"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestListPolicies(t *testing.T) {
    18  	tests := map[string]struct {
    19  		params           ListPoliciesRequest
    20  		responseStatus   int
    21  		responseBody     string
    22  		expectedPath     string
    23  		expectedResponse *ListPoliciesResponse
    24  		withError        func(*testing.T, error)
    25  	}{
    26  		"200 OK - two policies, one minimal and one with activation data": {
    27  			params:         ListPoliciesRequest{},
    28  			responseStatus: http.StatusOK,
    29  			responseBody: `
    30  {
    31      "content": [
    32          {
    33              "cloudletType": "CD",
    34              "createdBy": "User1",
    35              "createdDate": "2023-10-23T11:21:19.896Z",
    36              "currentActivations": {
    37                  "production": {
    38                      "effective": null,
    39                      "latest": null
    40                  },
    41                  "staging": {
    42                      "effective": null,
    43                      "latest": null
    44                  }
    45              },
    46              "description": null,
    47              "groupId": 1,
    48              "id": 11,
    49              "links": [
    50                  {
    51                      "href": "Link1",
    52                      "rel": "self"
    53                  }
    54              ],
    55              "modifiedBy": "User2",
    56              "modifiedDate": "2023-10-23T11:21:19.896Z",
    57              "name": "Name1",
    58              "policyType": "SHARED"
    59          },
    60          {
    61              "cloudletType": "CD",
    62              "createdBy": "User1",
    63              "createdDate": "2023-10-23T11:21:19.896Z",
    64              "currentActivations": {
    65                  "production": {
    66                      "effective": {
    67                          "createdBy": "User1",
    68  						"createdDate": "2023-10-23T11:21:19.896Z",
    69  						"finishDate": "2023-10-23T11:22:57.589Z",
    70                          "id": 123,
    71                          "links": [
    72                              {
    73                                  "href": "Link1",
    74                                  "rel": "self"
    75                              }
    76                          ],
    77                          "network": "PRODUCTION",
    78                          "operation": "ACTIVATION",
    79                          "policyId": 1234,
    80                          "policyVersion": 1,
    81                          "policyVersionDeleted": false,
    82                          "status": "SUCCESS"
    83                      },
    84                      "latest": {
    85                          "createdBy": "User1",
    86  						"createdDate": "2023-10-23T11:21:19.896Z",
    87  						"finishDate": "2023-10-23T11:22:57.589Z",
    88                          "id": 321,
    89                          "links": [
    90                              {
    91                                  "href": "Link2",
    92                                  "rel": "self"
    93                              }
    94                          ],
    95                          "network": "PRODUCTION",
    96                          "operation": "ACTIVATION",
    97                          "policyId": 4321,
    98                          "policyVersion": 1,
    99                          "policyVersionDeleted": false,
   100                          "status": "SUCCESS"
   101                      }
   102                  },
   103                  "staging": {
   104                      "effective": {
   105                          "createdBy": "User3",
   106  						"createdDate": "2023-10-23T11:21:19.896Z",
   107  						"finishDate": "2023-10-23T11:22:57.589Z",
   108                          "id": 789,
   109                          "links": [
   110                              {
   111                                  "href": "Link3",
   112                                  "rel": "self"
   113                              }
   114                          ],
   115                          "network": "STAGING",
   116                          "operation": "ACTIVATION",
   117                          "policyId": 6789,
   118                          "policyVersion": 1,
   119                          "policyVersionDeleted": false,
   120                          "status": "SUCCESS"
   121                      },
   122                      "latest": {
   123                          "createdBy": "User3",
   124  						"createdDate": "2023-10-23T11:21:19.896Z",
   125  						"finishDate": "2023-10-23T11:22:57.589Z",
   126                          "id": 987,
   127                          "links": [
   128                              {
   129                                  "href": "Link4",
   130                                  "rel": "self"
   131                              }
   132                          ],
   133                          "network": "STAGING",
   134                          "operation": "ACTIVATION",
   135                          "policyId": 9876,
   136                          "policyVersion": 1,
   137                          "policyVersionDeleted": false,
   138                          "status": "SUCCESS"
   139                      }
   140                  }
   141              },
   142              "description": "Test",
   143              "groupId": 1,
   144              "id": 22,
   145              "links": [
   146                  {
   147                      "href": "Link5",
   148                      "rel": "self"
   149                  }
   150              ],
   151              "modifiedBy": "User1",
   152              "modifiedDate": "2023-10-23T11:21:19.896Z",
   153              "name": "TestName",
   154              "policyType": "SHARED"
   155          }
   156  	],
   157      "links": [
   158          {
   159              "href": "/cloudlets/v3/policies?page=0&size=1000",
   160              "rel": "self"
   161          }
   162      ],
   163      "page": {
   164          "number": 0,
   165          "size": 1000,
   166          "totalElements": 54,
   167          "totalPages": 1
   168      }
   169  }
   170  `,
   171  			expectedPath: "/cloudlets/v3/policies",
   172  			expectedResponse: &ListPoliciesResponse{
   173  				Content: []Policy{
   174  					{
   175  						CloudletType:       CloudletTypeCD,
   176  						CreatedBy:          "User1",
   177  						CreatedDate:        *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   178  						CurrentActivations: CurrentActivations{},
   179  						Description:        nil,
   180  						GroupID:            1,
   181  						ID:                 11,
   182  						Links: []Link{
   183  							{
   184  								Href: "Link1",
   185  								Rel:  "self",
   186  							},
   187  						},
   188  						ModifiedBy:   "User2",
   189  						ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   190  						Name:         "Name1",
   191  						PolicyType:   PolicyTypeShared,
   192  					},
   193  					{
   194  						CloudletType: CloudletTypeCD,
   195  						CreatedBy:    "User1",
   196  						CreatedDate:  *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   197  						CurrentActivations: CurrentActivations{
   198  							Production: ActivationInfo{
   199  								Effective: &PolicyActivation{
   200  									CreatedBy:   "User1",
   201  									CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   202  									FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   203  									ID:          123,
   204  									Links: []Link{
   205  										{
   206  											Href: "Link1",
   207  											Rel:  "self",
   208  										},
   209  									},
   210  									Network:              ProductionNetwork,
   211  									Operation:            OperationActivation,
   212  									PolicyID:             1234,
   213  									PolicyVersion:        1,
   214  									PolicyVersionDeleted: false,
   215  									Status:               ActivationStatusSuccess,
   216  								},
   217  								Latest: &PolicyActivation{
   218  									CreatedBy:   "User1",
   219  									CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   220  									FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   221  									ID:          321,
   222  									Links: []Link{
   223  										{
   224  											Href: "Link2",
   225  											Rel:  "self",
   226  										},
   227  									},
   228  									Network:              ProductionNetwork,
   229  									Operation:            OperationActivation,
   230  									PolicyID:             4321,
   231  									PolicyVersion:        1,
   232  									PolicyVersionDeleted: false,
   233  									Status:               ActivationStatusSuccess,
   234  								},
   235  							},
   236  							Staging: ActivationInfo{
   237  								Effective: &PolicyActivation{
   238  									CreatedBy:   "User3",
   239  									CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   240  									FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   241  									ID:          789,
   242  									Links: []Link{
   243  										{
   244  											Href: "Link3",
   245  											Rel:  "self",
   246  										},
   247  									},
   248  									Network:              StagingNetwork,
   249  									Operation:            OperationActivation,
   250  									PolicyID:             6789,
   251  									PolicyVersion:        1,
   252  									PolicyVersionDeleted: false,
   253  									Status:               ActivationStatusSuccess,
   254  								},
   255  								Latest: &PolicyActivation{
   256  									CreatedBy:   "User3",
   257  									CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   258  									FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   259  									ID:          987,
   260  									Links: []Link{
   261  										{
   262  											Href: "Link4",
   263  											Rel:  "self",
   264  										},
   265  									},
   266  									Network:              StagingNetwork,
   267  									Operation:            OperationActivation,
   268  									PolicyID:             9876,
   269  									PolicyVersion:        1,
   270  									PolicyVersionDeleted: false,
   271  									Status:               ActivationStatusSuccess,
   272  								},
   273  							},
   274  						},
   275  						Description: tools.StringPtr("Test"),
   276  						GroupID:     1,
   277  						ID:          22,
   278  						Links: []Link{
   279  							{
   280  								Href: "Link5",
   281  								Rel:  "self",
   282  							},
   283  						},
   284  						ModifiedBy:   "User1",
   285  						ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   286  						Name:         "TestName",
   287  						PolicyType:   PolicyTypeShared,
   288  					},
   289  				},
   290  				Links: []Link{
   291  					{
   292  						Href: "/cloudlets/v3/policies?page=0&size=1000",
   293  						Rel:  "self",
   294  					},
   295  				},
   296  				Page: Page{
   297  					Number:        0,
   298  					Size:          1000,
   299  					TotalElements: 54,
   300  					TotalPages:    1,
   301  				},
   302  			},
   303  		},
   304  		"200 OK - with query params": {
   305  			params: ListPoliciesRequest{
   306  				Page: 2,
   307  				Size: 12,
   308  			},
   309  			responseStatus: http.StatusOK,
   310  			responseBody: `
   311  {
   312      "content": [
   313          {
   314              "cloudletType": "CD",
   315              "createdBy": "User1",
   316              "createdDate": "2023-10-23T11:21:19.896Z",
   317              "currentActivations": {
   318                  "production": {
   319                      "effective": null,
   320                      "latest": null
   321                  },
   322                  "staging": {
   323                      "effective": null,
   324                      "latest": null
   325                  }
   326              },
   327              "description": null,
   328              "groupId": 1,
   329              "id": 11,
   330              "links": [
   331                  {
   332                      "href": "Link1",
   333                      "rel": "self"
   334                  }
   335              ],
   336              "modifiedBy": "User2",
   337              "modifiedDate": "2023-10-23T11:21:19.896Z",
   338              "name": "Name1",
   339              "policyType": "SHARED"
   340          }
   341  	],
   342      "links": [
   343          {
   344              "href": "/cloudlets/v3/policies?page=0&size=1000",
   345              "rel": "self"
   346          }
   347      ],
   348      "page": {
   349          "number": 0,
   350          "size": 1000,
   351          "totalElements": 54,
   352          "totalPages": 1
   353      }
   354  }
   355  `,
   356  			expectedPath: "/cloudlets/v3/policies?page=2&size=12",
   357  			expectedResponse: &ListPoliciesResponse{
   358  				Content: []Policy{
   359  					{
   360  						CloudletType:       CloudletTypeCD,
   361  						CreatedBy:          "User1",
   362  						CreatedDate:        *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   363  						CurrentActivations: CurrentActivations{},
   364  						Description:        nil,
   365  						GroupID:            1,
   366  						ID:                 11,
   367  						Links: []Link{
   368  							{
   369  								Href: "Link1",
   370  								Rel:  "self",
   371  							},
   372  						},
   373  						ModifiedBy:   "User2",
   374  						ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   375  						Name:         "Name1",
   376  						PolicyType:   PolicyTypeShared,
   377  					},
   378  				},
   379  				Links: []Link{
   380  					{
   381  						Href: "/cloudlets/v3/policies?page=0&size=1000",
   382  						Rel:  "self",
   383  					},
   384  				},
   385  				Page: Page{
   386  					Number:        0,
   387  					Size:          1000,
   388  					TotalElements: 54,
   389  					TotalPages:    1,
   390  				},
   391  			},
   392  		},
   393  		"200 OK - empty content": {
   394  			params:         ListPoliciesRequest{},
   395  			responseStatus: http.StatusOK,
   396  			responseBody: `
   397  {
   398      "content": [],
   399      "links": [
   400          {
   401              "href": "/cloudlets/v3/policies?page=0&size=1000",
   402              "rel": "self"
   403          }
   404      ],
   405      "page": {
   406          "number": 0,
   407          "size": 1000,
   408          "totalElements": 0,
   409          "totalPages": 1
   410      }
   411  }
   412  `,
   413  			expectedPath: "/cloudlets/v3/policies",
   414  			expectedResponse: &ListPoliciesResponse{
   415  				Content: []Policy{},
   416  				Links: []Link{
   417  					{
   418  						Href: "/cloudlets/v3/policies?page=0&size=1000",
   419  						Rel:  "self",
   420  					},
   421  				},
   422  				Page: Page{
   423  					Number:        0,
   424  					Size:          1000,
   425  					TotalElements: 0,
   426  					TotalPages:    1,
   427  				},
   428  			},
   429  		},
   430  		"validation errors - size lower than 10, negative page number": {
   431  			params: ListPoliciesRequest{
   432  				Page: -2,
   433  				Size: 5,
   434  			},
   435  			withError: func(t *testing.T, err error) {
   436  				assert.Equal(t, "list shared policies: struct validation: Page: must be no less than 0\nSize: must be no less than 10", err.Error())
   437  			},
   438  		},
   439  		"500 Internal Server Error": {
   440  			params:         ListPoliciesRequest{},
   441  			responseStatus: http.StatusInternalServerError,
   442  			responseBody: `
   443  		{
   444  			"type": "internal_error",
   445  			"title": "Internal Server Error",
   446  			"status": 500,
   447  			"requestId": "1",
   448  			"requestTime": "12:00",
   449  			"clientIp": "1.1.1.1",
   450  			"serverIp": "2.2.2.2",
   451  			"method": "GET"
   452  		}`,
   453  			expectedPath: "/cloudlets/v3/policies",
   454  			withError: func(t *testing.T, err error) {
   455  				want := &Error{
   456  					Type:        "internal_error",
   457  					Title:       "Internal Server Error",
   458  					Status:      http.StatusInternalServerError,
   459  					RequestID:   "1",
   460  					RequestTime: "12:00",
   461  					ClientIP:    "1.1.1.1",
   462  					ServerIP:    "2.2.2.2",
   463  					Method:      "GET",
   464  				}
   465  				assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err)
   466  			},
   467  		},
   468  	}
   469  
   470  	for name, test := range tests {
   471  		t.Run(name, func(t *testing.T) {
   472  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   473  				assert.Equal(t, test.expectedPath, r.URL.String())
   474  				assert.Equal(t, http.MethodGet, r.Method)
   475  				w.WriteHeader(test.responseStatus)
   476  				_, err := w.Write([]byte(test.responseBody))
   477  				assert.NoError(t, err)
   478  			}))
   479  			client := mockAPIClient(t, mockServer)
   480  			result, err := client.ListPolicies(context.Background(), test.params)
   481  			if test.withError != nil {
   482  				test.withError(t, err)
   483  				return
   484  			}
   485  			require.NoError(t, err)
   486  			assert.Equal(t, test.expectedResponse, result)
   487  		})
   488  	}
   489  }
   490  
   491  func TestCreatePolicy(t *testing.T) {
   492  	tests := map[string]struct {
   493  		params              CreatePolicyRequest
   494  		responseStatus      int
   495  		responseBody        string
   496  		expectedPath        string
   497  		expectedRequestBody string
   498  		expectedResponse    *Policy
   499  		withError           func(*testing.T, error)
   500  	}{
   501  		"200 OK - minimal data": {
   502  			params: CreatePolicyRequest{
   503  				CloudletType: CloudletTypeFR,
   504  				GroupID:      1,
   505  				Name:         "TestName",
   506  			},
   507  			responseStatus: http.StatusCreated,
   508  			responseBody: `
   509  {
   510      "cloudletType": "FR",
   511      "createdBy": "User1",
   512      "createdDate": "2023-10-23T11:21:19.896Z",
   513      "currentActivations": {
   514          "production": {
   515              "effective": null,
   516              "latest": null
   517          },
   518          "staging": {
   519              "effective": null,
   520              "latest": null
   521          }
   522      },
   523      "description": null,
   524      "groupId": 1,
   525      "id": 11,
   526      "links": [
   527          {
   528              "href": "Link1",
   529              "rel": "self"
   530          }
   531      ],
   532      "modifiedBy": "User1",
   533      "modifiedDate": "2023-10-23T11:21:19.896Z",
   534      "name": "TestName",
   535      "policyType": "SHARED"
   536  }
   537  `,
   538  			expectedPath: "/cloudlets/v3/policies",
   539  			expectedRequestBody: `
   540  {
   541    "cloudletType": "FR",
   542    "groupId": 1,
   543    "name": "TestName"
   544  }`,
   545  			expectedResponse: &Policy{
   546  				CloudletType:       CloudletTypeFR,
   547  				CreatedBy:          "User1",
   548  				CreatedDate:        *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   549  				CurrentActivations: CurrentActivations{},
   550  				Description:        nil,
   551  				GroupID:            1,
   552  				ID:                 11,
   553  				Links: []Link{
   554  					{
   555  						Href: "Link1",
   556  						Rel:  "self",
   557  					},
   558  				},
   559  				ModifiedBy:   "User1",
   560  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   561  				Name:         "TestName",
   562  				PolicyType:   PolicyTypeShared,
   563  			},
   564  		},
   565  		"200 OK - all data": {
   566  			params: CreatePolicyRequest{
   567  				CloudletType: CloudletTypeFR,
   568  				Description:  tools.StringPtr("Description"),
   569  				GroupID:      1,
   570  				Name:         "TestName",
   571  				PolicyType:   PolicyTypeShared,
   572  			},
   573  			responseStatus: http.StatusCreated,
   574  			responseBody: `
   575  {
   576      "cloudletType": "FR",
   577      "createdBy": "User1",
   578      "createdDate": "2023-10-23T11:21:19.896Z",
   579      "currentActivations": {
   580          "production": {
   581              "effective": null,
   582              "latest": null
   583          },
   584          "staging": {
   585              "effective": null,
   586              "latest": null
   587          }
   588      },
   589      "description": "Description",
   590      "groupId": 1,
   591      "id": 11,
   592      "links": [
   593          {
   594              "href": "Link1",
   595              "rel": "self"
   596          }
   597      ],
   598      "modifiedBy": "User1",
   599      "modifiedDate": "2023-10-23T11:21:19.896Z",
   600      "name": "TestName",
   601      "policyType": "SHARED"
   602  }
   603  `,
   604  			expectedPath: "/cloudlets/v3/policies",
   605  			expectedRequestBody: `
   606  {
   607    "cloudletType": "FR",
   608    "description": "Description",
   609    "groupId": 1,
   610    "name": "TestName",
   611    "policyType": "SHARED"
   612  }
   613  `,
   614  			expectedResponse: &Policy{
   615  				CloudletType:       CloudletTypeFR,
   616  				CreatedBy:          "User1",
   617  				CreatedDate:        *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   618  				CurrentActivations: CurrentActivations{},
   619  				Description:        tools.StringPtr("Description"),
   620  				GroupID:            1,
   621  				ID:                 11,
   622  				Links: []Link{
   623  					{
   624  						Href: "Link1",
   625  						Rel:  "self",
   626  					},
   627  				},
   628  				ModifiedBy:   "User1",
   629  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   630  				Name:         "TestName",
   631  				PolicyType:   PolicyTypeShared,
   632  			},
   633  		},
   634  		"validation errors": {
   635  			params: CreatePolicyRequest{
   636  				CloudletType: "Wrong Cloudlet Type",
   637  				Description:  tools.StringPtr(strings.Repeat("Too long description", 20)),
   638  				GroupID:      1,
   639  				Name:         "TestName not match",
   640  				PolicyType:   "Wrong Policy Type",
   641  			},
   642  			withError: func(t *testing.T, err error) {
   643  				assert.Equal(t, "create shared policy: struct validation: CloudletType: value 'Wrong Cloudlet Type' is invalid. Must be one of: 'AP', 'AS', 'CD', 'ER', 'FR', 'IG'\nDescription: the length must be no more than 255\nName: value 'TestName not match' is invalid. Must be of format: ^[a-z_A-Z0-9]+$\nPolicyType: value 'Wrong Policy Type' is invalid. Must be 'SHARED'", err.Error())
   644  			},
   645  		},
   646  		"validation errors - missing required params": {
   647  			params: CreatePolicyRequest{},
   648  			withError: func(t *testing.T, err error) {
   649  				assert.Equal(t, "create shared policy: struct validation: CloudletType: cannot be blank\nGroupID: cannot be blank\nName: cannot be blank", err.Error())
   650  			},
   651  		},
   652  	}
   653  
   654  	for name, test := range tests {
   655  		t.Run(name, func(t *testing.T) {
   656  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   657  				assert.Equal(t, test.expectedPath, r.URL.String())
   658  				assert.Equal(t, http.MethodPost, r.Method)
   659  				w.WriteHeader(test.responseStatus)
   660  				_, err := w.Write([]byte(test.responseBody))
   661  				assert.NoError(t, err)
   662  				if test.expectedRequestBody != "" {
   663  					body, err := io.ReadAll(r.Body)
   664  					assert.NoError(t, err)
   665  					assert.JSONEq(t, test.expectedRequestBody, string(body))
   666  				}
   667  			}))
   668  			client := mockAPIClient(t, mockServer)
   669  			result, err := client.CreatePolicy(context.Background(), test.params)
   670  			if test.withError != nil {
   671  				test.withError(t, err)
   672  				return
   673  			}
   674  			require.NoError(t, err)
   675  			assert.Equal(t, test.expectedResponse, result)
   676  		})
   677  	}
   678  }
   679  
   680  func TestDeletePolicy(t *testing.T) {
   681  	tests := map[string]struct {
   682  		params         DeletePolicyRequest
   683  		responseStatus int
   684  		responseBody   string
   685  		expectedPath   string
   686  		withError      func(*testing.T, error)
   687  	}{
   688  		"204": {
   689  			params: DeletePolicyRequest{
   690  				PolicyID: 1,
   691  			},
   692  			responseStatus: http.StatusNoContent,
   693  			expectedPath:   "/cloudlets/v3/policies/1",
   694  		},
   695  		"validation errors - missing required param": {
   696  			params: DeletePolicyRequest{},
   697  			withError: func(t *testing.T, err error) {
   698  				assert.Equal(t, "delete shared policy: struct validation: PolicyID: cannot be blank", err.Error())
   699  			},
   700  		},
   701  	}
   702  
   703  	for name, test := range tests {
   704  		t.Run(name, func(t *testing.T) {
   705  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   706  				assert.Equal(t, test.expectedPath, r.URL.String())
   707  				assert.Equal(t, http.MethodDelete, r.Method)
   708  				w.WriteHeader(test.responseStatus)
   709  				_, err := w.Write([]byte(test.responseBody))
   710  				assert.NoError(t, err)
   711  			}))
   712  			client := mockAPIClient(t, mockServer)
   713  			err := client.DeletePolicy(context.Background(), test.params)
   714  			if test.withError != nil {
   715  				test.withError(t, err)
   716  				return
   717  			}
   718  			require.NoError(t, err)
   719  		})
   720  	}
   721  }
   722  
   723  func TestGetPolicy(t *testing.T) {
   724  	tests := map[string]struct {
   725  		params           GetPolicyRequest
   726  		responseStatus   int
   727  		responseBody     string
   728  		expectedPath     string
   729  		expectedResponse *Policy
   730  		withError        func(*testing.T, error)
   731  	}{
   732  		"200 OK - minimal data": {
   733  			params: GetPolicyRequest{
   734  				PolicyID: 1,
   735  			},
   736  			responseStatus: http.StatusOK,
   737  			responseBody: `
   738  
   739  	{
   740  	    "cloudletType": "FR",
   741  	    "createdBy": "User1",
   742  	    "createdDate": "2023-10-23T11:21:19.896Z",
   743  	    "currentActivations": {
   744  	        "production": {
   745  	            "effective": null,
   746  	            "latest": null
   747  	        },
   748  	        "staging": {
   749  	            "effective": null,
   750  	            "latest": null
   751  	        }
   752  	    },
   753  	    "description": null,
   754  	    "groupId": 1,
   755  	    "id": 11,
   756  	    "links": [
   757  	        {
   758  	            "href": "Link1",
   759  	            "rel": "self"
   760  	        }
   761  	    ],
   762  	    "modifiedBy": "User1",
   763  	    "modifiedDate": "2023-10-23T11:21:19.896Z",
   764  	    "name": "TestName",
   765  	    "policyType": "SHARED"
   766  	}
   767  
   768  `,
   769  
   770  			expectedPath: "/cloudlets/v3/policies/1",
   771  			expectedResponse: &Policy{
   772  				CloudletType:       CloudletTypeFR,
   773  				CreatedBy:          "User1",
   774  				CreatedDate:        *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   775  				CurrentActivations: CurrentActivations{},
   776  				Description:        nil,
   777  				GroupID:            1,
   778  				ID:                 11,
   779  				Links: []Link{
   780  					{
   781  						Href: "Link1",
   782  						Rel:  "self",
   783  					},
   784  				},
   785  				ModifiedBy:   "User1",
   786  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   787  				Name:         "TestName",
   788  				PolicyType:   PolicyTypeShared,
   789  			},
   790  		},
   791  		"200 OK - with activation information": {
   792  			params: GetPolicyRequest{
   793  				PolicyID: 1,
   794  			},
   795  			responseStatus: http.StatusOK,
   796  			responseBody: `
   797  
   798  	{
   799  	    "cloudletType": "FR",
   800  	    "createdBy": "User1",
   801  	    "createdDate": "2023-10-23T11:21:19.896Z",
   802  	    "currentActivations": {
   803  			"production": {
   804  				"effective": {
   805  					"createdBy": "User1",
   806  					"createdDate": "2023-10-23T11:21:19.896Z",
   807  					"finishDate": "2023-10-23T11:22:57.589Z",
   808  					"id": 123,
   809  					"links": [
   810  						{
   811  							"href": "Link1",
   812  							"rel": "self"
   813  						}
   814  					],
   815  					"network": "PRODUCTION",
   816  					"operation": "ACTIVATION",
   817  					"policyId": 1234,
   818  					"policyVersion": 1,
   819  					"policyVersionDeleted": false,
   820  					"status": "SUCCESS"
   821  				},
   822  				"latest": {
   823  					"createdBy": "User1",
   824  					"createdDate": "2023-10-23T11:21:19.896Z",
   825  					"finishDate": "2023-10-23T11:22:57.589Z",
   826  					"id": 321,
   827  					"links": [
   828  						{
   829  							"href": "Link2",
   830  							"rel": "self"
   831  						}
   832  					],
   833  					"network": "PRODUCTION",
   834  					"operation": "ACTIVATION",
   835  					"policyId": 4321,
   836  					"policyVersion": 1,
   837  					"policyVersionDeleted": false,
   838  					"status": "SUCCESS"
   839  				}
   840  			},
   841  			"staging": {
   842  				"effective": {
   843  					"createdBy": "User3",
   844  					"createdDate": "2023-10-23T11:21:19.896Z",
   845  					"finishDate": "2023-10-23T11:22:57.589Z",
   846  					"id": 789,
   847  					"links": [
   848  						{
   849  							"href": "Link3",
   850  							"rel": "self"
   851  						}
   852  					],
   853  					"network": "STAGING",
   854  					"operation": "ACTIVATION",
   855  					"policyId": 6789,
   856  					"policyVersion": 1,
   857  					"policyVersionDeleted": false,
   858  					"status": "SUCCESS"
   859  				},
   860  				"latest": {
   861  					"createdBy": "User3",
   862  					"createdDate": "2023-10-23T11:21:19.896Z",
   863  					"finishDate": "2023-10-23T11:22:57.589Z",
   864  					"id": 987,
   865  					"links": [
   866  						{
   867  							"href": "Link4",
   868  							"rel": "self"
   869  						}
   870  					],
   871  					"network": "STAGING",
   872  					"operation": "ACTIVATION",
   873  					"policyId": 9876,
   874  					"policyVersion": 1,
   875  					"policyVersionDeleted": false,
   876  					"status": "SUCCESS"
   877  				}
   878  			}
   879  		},
   880  	    "description": "Description",
   881  	    "groupId": 1,
   882  	    "id": 11,
   883  	    "links": [
   884  	        {
   885  	            "href": "Link1",
   886  	            "rel": "self"
   887  	        }
   888  	    ],
   889  	    "modifiedBy": "User1",
   890  	    "modifiedDate": "2023-10-23T11:21:19.896Z",
   891  	    "name": "TestName",
   892  	    "policyType": "SHARED"
   893  	}
   894  
   895  `,
   896  
   897  			expectedPath: "/cloudlets/v3/policies/1",
   898  			expectedResponse: &Policy{
   899  				CloudletType: CloudletTypeFR,
   900  				CreatedBy:    "User1",
   901  				CreatedDate:  *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   902  				CurrentActivations: CurrentActivations{
   903  					Production: ActivationInfo{
   904  						Effective: &PolicyActivation{
   905  							CreatedBy:   "User1",
   906  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   907  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   908  							ID:          123,
   909  							Links: []Link{
   910  								{
   911  									Href: "Link1",
   912  									Rel:  "self",
   913  								},
   914  							},
   915  							Network:              ProductionNetwork,
   916  							Operation:            OperationActivation,
   917  							PolicyID:             1234,
   918  							PolicyVersion:        1,
   919  							PolicyVersionDeleted: false,
   920  							Status:               ActivationStatusSuccess,
   921  						},
   922  						Latest: &PolicyActivation{
   923  							CreatedBy:   "User1",
   924  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   925  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   926  							ID:          321,
   927  							Links: []Link{
   928  								{
   929  									Href: "Link2",
   930  									Rel:  "self",
   931  								},
   932  							},
   933  							Network:              ProductionNetwork,
   934  							Operation:            OperationActivation,
   935  							PolicyID:             4321,
   936  							PolicyVersion:        1,
   937  							PolicyVersionDeleted: false,
   938  							Status:               ActivationStatusSuccess,
   939  						},
   940  					},
   941  					Staging: ActivationInfo{
   942  						Effective: &PolicyActivation{
   943  							CreatedBy:   "User3",
   944  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   945  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   946  							ID:          789,
   947  							Links: []Link{
   948  								{
   949  									Href: "Link3",
   950  									Rel:  "self",
   951  								},
   952  							},
   953  							Network:              StagingNetwork,
   954  							Operation:            OperationActivation,
   955  							PolicyID:             6789,
   956  							PolicyVersion:        1,
   957  							PolicyVersionDeleted: false,
   958  							Status:               ActivationStatusSuccess,
   959  						},
   960  						Latest: &PolicyActivation{
   961  							CreatedBy:   "User3",
   962  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   963  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
   964  							ID:          987,
   965  							Links: []Link{
   966  								{
   967  									Href: "Link4",
   968  									Rel:  "self",
   969  								},
   970  							},
   971  							Network:              StagingNetwork,
   972  							Operation:            OperationActivation,
   973  							PolicyID:             9876,
   974  							PolicyVersion:        1,
   975  							PolicyVersionDeleted: false,
   976  							Status:               ActivationStatusSuccess,
   977  						},
   978  					},
   979  				},
   980  				Description: tools.StringPtr("Description"),
   981  				GroupID:     1,
   982  				ID:          11,
   983  				Links: []Link{
   984  					{
   985  						Href: "Link1",
   986  						Rel:  "self",
   987  					},
   988  				},
   989  				ModifiedBy:   "User1",
   990  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
   991  				Name:         "TestName",
   992  				PolicyType:   PolicyTypeShared,
   993  			},
   994  		},
   995  		"200 OK - one network is active": {
   996  			params: GetPolicyRequest{
   997  				PolicyID: 1,
   998  			},
   999  			responseStatus: http.StatusOK,
  1000  			responseBody: `
  1001  
  1002  	{
  1003  	    "cloudletType": "FR",
  1004  	    "createdBy": "User1",
  1005  	    "createdDate": "2023-10-23T11:21:19.896Z",
  1006  	    "currentActivations": {
  1007  			"production": {
  1008  				"effective": null,
  1009  				"latest": null
  1010  			},
  1011  			"staging": {
  1012  				"effective": {
  1013  					"createdBy": "User3",
  1014  					"createdDate": "2023-10-23T11:21:19.896Z",
  1015  					"finishDate": "2023-10-23T11:22:57.589Z",
  1016  					"id": 789,
  1017  					"links": [
  1018  						{
  1019  							"href": "Link3",
  1020  							"rel": "self"
  1021  						}
  1022  					],
  1023  					"network": "STAGING",
  1024  					"operation": "ACTIVATION",
  1025  					"policyId": 6789,
  1026  					"policyVersion": 1,
  1027  					"policyVersionDeleted": false,
  1028  					"status": "SUCCESS"
  1029  				},
  1030  				"latest": {
  1031  					"createdBy": "User3",
  1032  					"createdDate": "2023-10-23T11:21:19.896Z",
  1033  					"finishDate": "2023-10-23T11:22:57.589Z",
  1034  					"id": 987,
  1035  					"links": [
  1036  						{
  1037  							"href": "Link4",
  1038  							"rel": "self"
  1039  						}
  1040  					],
  1041  					"network": "STAGING",
  1042  					"operation": "ACTIVATION",
  1043  					"policyId": 9876,
  1044  					"policyVersion": 1,
  1045  					"policyVersionDeleted": false,
  1046  					"status": "SUCCESS"
  1047  				}
  1048  			}
  1049  		},
  1050  	    "description": "Description",
  1051  	    "groupId": 1,
  1052  	    "id": 11,
  1053  	    "links": [
  1054  	        {
  1055  	            "href": "Link1",
  1056  	            "rel": "self"
  1057  	        }
  1058  	    ],
  1059  	    "modifiedBy": "User1",
  1060  	    "modifiedDate": "2023-10-23T11:21:19.896Z",
  1061  	    "name": "TestName",
  1062  	    "policyType": "SHARED"
  1063  	}
  1064  
  1065  `,
  1066  
  1067  			expectedPath: "/cloudlets/v3/policies/1",
  1068  			expectedResponse: &Policy{
  1069  				CloudletType: CloudletTypeFR,
  1070  				CreatedBy:    "User1",
  1071  				CreatedDate:  *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1072  				CurrentActivations: CurrentActivations{
  1073  					Production: ActivationInfo{
  1074  						Effective: nil,
  1075  						Latest:    nil,
  1076  					},
  1077  					Staging: ActivationInfo{
  1078  						Effective: &PolicyActivation{
  1079  							CreatedBy:   "User3",
  1080  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1081  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1082  							ID:          789,
  1083  							Links: []Link{
  1084  								{
  1085  									Href: "Link3",
  1086  									Rel:  "self",
  1087  								},
  1088  							},
  1089  							Network:              StagingNetwork,
  1090  							Operation:            OperationActivation,
  1091  							PolicyID:             6789,
  1092  							PolicyVersion:        1,
  1093  							PolicyVersionDeleted: false,
  1094  							Status:               ActivationStatusSuccess,
  1095  						},
  1096  						Latest: &PolicyActivation{
  1097  							CreatedBy:   "User3",
  1098  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1099  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1100  							ID:          987,
  1101  							Links: []Link{
  1102  								{
  1103  									Href: "Link4",
  1104  									Rel:  "self",
  1105  								},
  1106  							},
  1107  							Network:              StagingNetwork,
  1108  							Operation:            OperationActivation,
  1109  							PolicyID:             9876,
  1110  							PolicyVersion:        1,
  1111  							PolicyVersionDeleted: false,
  1112  							Status:               ActivationStatusSuccess,
  1113  						},
  1114  					},
  1115  				},
  1116  				Description: tools.StringPtr("Description"),
  1117  				GroupID:     1,
  1118  				ID:          11,
  1119  				Links: []Link{
  1120  					{
  1121  						Href: "Link1",
  1122  						Rel:  "self",
  1123  					},
  1124  				},
  1125  				ModifiedBy:   "User1",
  1126  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1127  				Name:         "TestName",
  1128  				PolicyType:   PolicyTypeShared,
  1129  			},
  1130  		},
  1131  		"validation errors - missing required params": {
  1132  			params: GetPolicyRequest{},
  1133  			withError: func(t *testing.T, err error) {
  1134  				assert.Equal(t, "get shared policy: struct validation: PolicyID: cannot be blank", err.Error())
  1135  			},
  1136  		},
  1137  	}
  1138  
  1139  	for name, test := range tests {
  1140  		t.Run(name, func(t *testing.T) {
  1141  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1142  				assert.Equal(t, test.expectedPath, r.URL.String())
  1143  				assert.Equal(t, http.MethodGet, r.Method)
  1144  				w.WriteHeader(test.responseStatus)
  1145  				_, err := w.Write([]byte(test.responseBody))
  1146  				assert.NoError(t, err)
  1147  			}))
  1148  			client := mockAPIClient(t, mockServer)
  1149  			result, err := client.GetPolicy(context.Background(), test.params)
  1150  			if test.withError != nil {
  1151  				test.withError(t, err)
  1152  				return
  1153  			}
  1154  			require.NoError(t, err)
  1155  			assert.Equal(t, test.expectedResponse, result)
  1156  		})
  1157  	}
  1158  }
  1159  
  1160  func TestUpdatePolicy(t *testing.T) {
  1161  	tests := map[string]struct {
  1162  		params              UpdatePolicyRequest
  1163  		responseStatus      int
  1164  		responseBody        string
  1165  		expectedPath        string
  1166  		expectedRequestBody string
  1167  		expectedResponse    *Policy
  1168  		withError           func(*testing.T, error)
  1169  	}{
  1170  		"200 OK - minimal data": {
  1171  			params: UpdatePolicyRequest{
  1172  				PolicyID: 1,
  1173  				BodyParams: UpdatePolicyBodyParams{
  1174  					GroupID: 11,
  1175  				},
  1176  			},
  1177  			responseStatus: http.StatusOK,
  1178  			responseBody: `
  1179  {
  1180      "cloudletType": "FR",
  1181      "createdBy": "User1",
  1182      "createdDate": "2023-10-23T11:21:19.896Z",
  1183      "currentActivations": {
  1184          "production": {
  1185              "effective": null,
  1186              "latest": null
  1187          },
  1188          "staging": {
  1189              "effective": null,
  1190              "latest": null
  1191          }
  1192      },
  1193      "description": null,
  1194      "groupId": 1,
  1195      "id": 11,
  1196      "links": [
  1197          {
  1198              "href": "Link1",
  1199              "rel": "self"
  1200          }
  1201      ],
  1202      "modifiedBy": "User1",
  1203      "modifiedDate": "2023-10-23T11:21:19.896Z",
  1204      "name": "TestName",
  1205      "policyType": "SHARED"
  1206  }
  1207  `,
  1208  			expectedPath: "/cloudlets/v3/policies/1",
  1209  			expectedRequestBody: `
  1210  {
  1211    "groupId": 11
  1212  }
  1213  `,
  1214  			expectedResponse: &Policy{
  1215  				CloudletType:       CloudletTypeFR,
  1216  				CreatedBy:          "User1",
  1217  				CreatedDate:        *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1218  				CurrentActivations: CurrentActivations{},
  1219  				Description:        nil,
  1220  				GroupID:            1,
  1221  				ID:                 11,
  1222  				Links: []Link{
  1223  					{
  1224  						Href: "Link1",
  1225  						Rel:  "self",
  1226  					},
  1227  				},
  1228  				ModifiedBy:   "User1",
  1229  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1230  				Name:         "TestName",
  1231  				PolicyType:   PolicyTypeShared,
  1232  			},
  1233  		},
  1234  		"200 OK - with description and activations": {
  1235  			params: UpdatePolicyRequest{
  1236  				PolicyID: 1,
  1237  				BodyParams: UpdatePolicyBodyParams{
  1238  					GroupID:     11,
  1239  					Description: tools.StringPtr("Description"),
  1240  				},
  1241  			},
  1242  			responseStatus: http.StatusOK,
  1243  			responseBody: `
  1244  {
  1245      "cloudletType": "FR",
  1246      "createdBy": "User1",
  1247      "createdDate": "2023-10-23T11:21:19.896Z",
  1248      "currentActivations": {
  1249  		"production": {
  1250  			"effective": {
  1251  				"createdBy": "User1",
  1252  				"createdDate": "2023-10-23T11:21:19.896Z",
  1253  				"finishDate": "2023-10-23T11:22:57.589Z",
  1254  				"id": 123,
  1255  				"links": [
  1256  					{
  1257  						"href": "Link1",
  1258  						"rel": "self"
  1259  					}
  1260  				],
  1261  				"network": "PRODUCTION",
  1262  				"operation": "ACTIVATION",
  1263  				"policyId": 1234,
  1264  				"policyVersion": 1,
  1265  				"policyVersionDeleted": false,
  1266  				"status": "SUCCESS"
  1267  			},
  1268  			"latest": {
  1269  				"createdBy": "User1",
  1270  				"createdDate": "2023-10-23T11:21:19.896Z",
  1271  				"finishDate": "2023-10-23T11:22:57.589Z",
  1272  				"id": 321,
  1273  				"links": [
  1274  					{
  1275  						"href": "Link2",
  1276  						"rel": "self"
  1277  					}
  1278  				],
  1279  				"network": "PRODUCTION",
  1280  				"operation": "ACTIVATION",
  1281  				"policyId": 4321,
  1282  				"policyVersion": 1,
  1283  				"policyVersionDeleted": false,
  1284  				"status": "SUCCESS"
  1285  			}
  1286  		},
  1287  		"staging": {
  1288  			"effective": {
  1289  				"createdBy": "User3",
  1290  				"createdDate": "2023-10-23T11:21:19.896Z",
  1291  				"finishDate": "2023-10-23T11:22:57.589Z",
  1292  				"id": 789,
  1293  				"links": [
  1294  					{
  1295  						"href": "Link3",
  1296  						"rel": "self"
  1297  					}
  1298  				],
  1299  				"network": "STAGING",
  1300  				"operation": "ACTIVATION",
  1301  				"policyId": 6789,
  1302  				"policyVersion": 1,
  1303  				"policyVersionDeleted": false,
  1304  				"status": "SUCCESS"
  1305  			},
  1306  			"latest": {
  1307  				"createdBy": "User3",
  1308  				"createdDate": "2023-10-23T11:21:19.896Z",
  1309  				"finishDate": "2023-10-23T11:22:57.589Z",
  1310  				"id": 987,
  1311  				"links": [
  1312  					{
  1313  						"href": "Link4",
  1314  						"rel": "self"
  1315  					}
  1316  				],
  1317  				"network": "STAGING",
  1318  				"operation": "ACTIVATION",
  1319  				"policyId": 9876,
  1320  				"policyVersion": 1,
  1321  				"policyVersionDeleted": false,
  1322  				"status": "SUCCESS"
  1323  			}
  1324  		}
  1325  	},
  1326      "description": "Description",
  1327      "groupId": 1,
  1328      "id": 11,
  1329      "links": [
  1330          {
  1331              "href": "Link1",
  1332              "rel": "self"
  1333          }
  1334      ],
  1335      "modifiedBy": "User1",
  1336      "modifiedDate": "2023-10-23T11:21:19.896Z",
  1337      "name": "TestName",
  1338      "policyType": "SHARED"
  1339  }
  1340  `,
  1341  			expectedPath: "/cloudlets/v3/policies/1",
  1342  			expectedRequestBody: `
  1343  {
  1344    "groupId": 11,
  1345    "description": "Description"
  1346  }
  1347  `,
  1348  			expectedResponse: &Policy{
  1349  				CloudletType: CloudletTypeFR,
  1350  				CreatedBy:    "User1",
  1351  				CreatedDate:  *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1352  				CurrentActivations: CurrentActivations{
  1353  					Production: ActivationInfo{
  1354  						Effective: &PolicyActivation{
  1355  							CreatedBy:   "User1",
  1356  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1357  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1358  							ID:          123,
  1359  							Links: []Link{
  1360  								{
  1361  									Href: "Link1",
  1362  									Rel:  "self",
  1363  								},
  1364  							},
  1365  							Network:              ProductionNetwork,
  1366  							Operation:            OperationActivation,
  1367  							PolicyID:             1234,
  1368  							PolicyVersion:        1,
  1369  							PolicyVersionDeleted: false,
  1370  							Status:               ActivationStatusSuccess,
  1371  						},
  1372  						Latest: &PolicyActivation{
  1373  							CreatedBy:   "User1",
  1374  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1375  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1376  							ID:          321,
  1377  							Links: []Link{
  1378  								{
  1379  									Href: "Link2",
  1380  									Rel:  "self",
  1381  								},
  1382  							},
  1383  							Network:              ProductionNetwork,
  1384  							Operation:            OperationActivation,
  1385  							PolicyID:             4321,
  1386  							PolicyVersion:        1,
  1387  							PolicyVersionDeleted: false,
  1388  							Status:               ActivationStatusSuccess,
  1389  						},
  1390  					},
  1391  					Staging: ActivationInfo{
  1392  						Effective: &PolicyActivation{
  1393  							CreatedBy:   "User3",
  1394  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1395  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1396  							ID:          789,
  1397  							Links: []Link{
  1398  								{
  1399  									Href: "Link3",
  1400  									Rel:  "self",
  1401  								},
  1402  							},
  1403  							Network:              StagingNetwork,
  1404  							Operation:            OperationActivation,
  1405  							PolicyID:             6789,
  1406  							PolicyVersion:        1,
  1407  							PolicyVersionDeleted: false,
  1408  							Status:               ActivationStatusSuccess,
  1409  						},
  1410  						Latest: &PolicyActivation{
  1411  							CreatedBy:   "User3",
  1412  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1413  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1414  							ID:          987,
  1415  							Links: []Link{
  1416  								{
  1417  									Href: "Link4",
  1418  									Rel:  "self",
  1419  								},
  1420  							},
  1421  							Network:              StagingNetwork,
  1422  							Operation:            OperationActivation,
  1423  							PolicyID:             9876,
  1424  							PolicyVersion:        1,
  1425  							PolicyVersionDeleted: false,
  1426  							Status:               ActivationStatusSuccess,
  1427  						},
  1428  					},
  1429  				},
  1430  				Description: tools.StringPtr("Description"),
  1431  				GroupID:     1,
  1432  				ID:          11,
  1433  				Links: []Link{
  1434  					{
  1435  						Href: "Link1",
  1436  						Rel:  "self",
  1437  					},
  1438  				},
  1439  				ModifiedBy:   "User1",
  1440  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1441  				Name:         "TestName",
  1442  				PolicyType:   PolicyTypeShared,
  1443  			},
  1444  		},
  1445  		"validation errors - missing required params": {
  1446  			params: UpdatePolicyRequest{},
  1447  			withError: func(t *testing.T, err error) {
  1448  				assert.Equal(t, "update shared policy: struct validation: GroupID: cannot be blank\nPolicyID: cannot be blank", err.Error())
  1449  			},
  1450  		},
  1451  		"validation errors - description too long": {
  1452  			params: UpdatePolicyRequest{
  1453  				PolicyID: 1,
  1454  				BodyParams: UpdatePolicyBodyParams{
  1455  					GroupID:     11,
  1456  					Description: tools.StringPtr(strings.Repeat("TestDescription", 30)),
  1457  				},
  1458  			},
  1459  			withError: func(t *testing.T, err error) {
  1460  				assert.Equal(t, "update shared policy: struct validation: Description: the length must be no more than 255", err.Error())
  1461  			},
  1462  		},
  1463  	}
  1464  
  1465  	for name, test := range tests {
  1466  		t.Run(name, func(t *testing.T) {
  1467  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1468  				assert.Equal(t, test.expectedPath, r.URL.String())
  1469  				assert.Equal(t, http.MethodPut, r.Method)
  1470  				if test.expectedRequestBody != "" {
  1471  					body, err := io.ReadAll(r.Body)
  1472  					require.NoError(t, err)
  1473  					assert.JSONEq(t, test.expectedRequestBody, string(body))
  1474  				}
  1475  				w.WriteHeader(test.responseStatus)
  1476  				_, err := w.Write([]byte(test.responseBody))
  1477  				assert.NoError(t, err)
  1478  			}))
  1479  			client := mockAPIClient(t, mockServer)
  1480  			result, err := client.UpdatePolicy(context.Background(), test.params)
  1481  			if test.withError != nil {
  1482  				test.withError(t, err)
  1483  				return
  1484  			}
  1485  			require.NoError(t, err)
  1486  			assert.Equal(t, test.expectedResponse, result)
  1487  		})
  1488  	}
  1489  }
  1490  
  1491  func TestClonePolicy(t *testing.T) {
  1492  	tests := map[string]struct {
  1493  		params              ClonePolicyRequest
  1494  		responseStatus      int
  1495  		responseBody        string
  1496  		expectedPath        string
  1497  		expectedRequestBody string
  1498  		expectedResponse    *Policy
  1499  		withError           func(*testing.T, error)
  1500  	}{
  1501  		"200 OK - minimal data": {
  1502  			params: ClonePolicyRequest{
  1503  				PolicyID: 1,
  1504  				BodyParams: ClonePolicyBodyParams{
  1505  					NewName: "NewName",
  1506  				},
  1507  			},
  1508  			responseStatus: http.StatusOK,
  1509  			responseBody: `
  1510  {
  1511      "cloudletType": "FR",
  1512      "createdBy": "User1",
  1513      "createdDate": "2023-10-23T11:21:19.896Z",
  1514      "currentActivations": {
  1515          "production": {
  1516              "effective": null,
  1517              "latest": null
  1518          },
  1519          "staging": {
  1520              "effective": null,
  1521              "latest": null
  1522          }
  1523      },
  1524      "description": null,
  1525      "groupId": 1,
  1526      "id": 11,
  1527      "links": [
  1528          {
  1529              "href": "Link1",
  1530              "rel": "self"
  1531          }
  1532      ],
  1533      "modifiedBy": "User1",
  1534      "modifiedDate": "2023-10-23T11:21:19.896Z",
  1535      "name": "NewName",
  1536      "policyType": "SHARED"
  1537  }
  1538  `,
  1539  			expectedPath: "/cloudlets/v3/policies/1/clone",
  1540  			expectedRequestBody: `
  1541  {
  1542    "newName": "NewName"
  1543  }
  1544  `,
  1545  			expectedResponse: &Policy{
  1546  				CloudletType:       "FR",
  1547  				CreatedBy:          "User1",
  1548  				CreatedDate:        *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1549  				CurrentActivations: CurrentActivations{},
  1550  				Description:        nil,
  1551  				GroupID:            1,
  1552  				ID:                 11,
  1553  				Links: []Link{
  1554  					{
  1555  						Href: "Link1",
  1556  						Rel:  "self",
  1557  					},
  1558  				},
  1559  				ModifiedBy:   "User1",
  1560  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1561  				Name:         "NewName",
  1562  				PolicyType:   PolicyTypeShared,
  1563  			},
  1564  		},
  1565  		"200 OK - all data": {
  1566  			params: ClonePolicyRequest{
  1567  				PolicyID: 1,
  1568  				BodyParams: ClonePolicyBodyParams{
  1569  					AdditionalVersions: []int64{1, 2},
  1570  					GroupID:            11,
  1571  					NewName:            "NewName",
  1572  				},
  1573  			},
  1574  			responseStatus: http.StatusOK,
  1575  			responseBody: `
  1576  {
  1577      "cloudletType": "FR",
  1578      "createdBy": "User1",
  1579      "createdDate": "2023-10-23T11:21:19.896Z",
  1580      "currentActivations": {
  1581  		"production": {
  1582  			"effective": {
  1583  				"createdBy": "User1",
  1584  				"createdDate": "2023-10-23T11:21:19.896Z",
  1585  				"finishDate": "2023-10-23T11:22:57.589Z",
  1586  				"id": 123,
  1587  				"links": [
  1588  					{
  1589  						"href": "Link1",
  1590  						"rel": "self"
  1591  					}
  1592  				],
  1593  				"network": "PRODUCTION",
  1594  				"operation": "ACTIVATION",
  1595  				"policyId": 1234,
  1596  				"policyVersion": 1,
  1597  				"policyVersionDeleted": false,
  1598  				"status": "SUCCESS"
  1599  			},
  1600  			"latest": {
  1601  				"createdBy": "User1",
  1602  				"createdDate": "2023-10-23T11:21:19.896Z",
  1603  				"finishDate": "2023-10-23T11:22:57.589Z",
  1604  				"id": 321,
  1605  				"links": [
  1606  					{
  1607  						"href": "Link2",
  1608  						"rel": "self"
  1609  					}
  1610  				],
  1611  				"network": "PRODUCTION",
  1612  				"operation": "ACTIVATION",
  1613  				"policyId": 4321,
  1614  				"policyVersion": 1,
  1615  				"policyVersionDeleted": false,
  1616  				"status": "SUCCESS"
  1617  			}
  1618  		},
  1619  		"staging": {
  1620  			"effective": {
  1621  				"createdBy": "User3",
  1622  				"createdDate": "2023-10-23T11:21:19.896Z",
  1623  				"finishDate": "2023-10-23T11:22:57.589Z",
  1624  				"id": 789,
  1625  				"links": [
  1626  					{
  1627  						"href": "Link3",
  1628  						"rel": "self"
  1629  					}
  1630  				],
  1631  				"network": "STAGING",
  1632  				"operation": "ACTIVATION",
  1633  				"policyId": 6789,
  1634  				"policyVersion": 1,
  1635  				"policyVersionDeleted": false,
  1636  				"status": "SUCCESS"
  1637  			},
  1638  			"latest": {
  1639  				"createdBy": "User3",
  1640  				"createdDate": "2023-10-23T11:21:19.896Z",
  1641  				"finishDate": "2023-10-23T11:22:57.589Z",
  1642  				"id": 987,
  1643  				"links": [
  1644  					{
  1645  						"href": "Link4",
  1646  						"rel": "self"
  1647  					}
  1648  				],
  1649  				"network": "STAGING",
  1650  				"operation": "ACTIVATION",
  1651  				"policyId": 9876,
  1652  				"policyVersion": 1,
  1653  				"policyVersionDeleted": false,
  1654  				"status": "SUCCESS"
  1655  			}
  1656  		}
  1657  	},
  1658      "description": "Description",
  1659      "groupId": 1,
  1660      "id": 11,
  1661      "links": [
  1662          {
  1663              "href": "Link1",
  1664              "rel": "self"
  1665          }
  1666      ],
  1667      "modifiedBy": "User1",
  1668      "modifiedDate": "2023-10-23T11:21:19.896Z",
  1669      "name": "NewName",
  1670      "policyType": "SHARED"
  1671  }
  1672  `,
  1673  			expectedPath: "/cloudlets/v3/policies/1/clone",
  1674  			expectedRequestBody: `
  1675  {
  1676     "additionalVersions": [1, 2],
  1677     "groupId": 11,
  1678     "newName": "NewName"
  1679  }
  1680  `,
  1681  			expectedResponse: &Policy{
  1682  				CloudletType: "FR",
  1683  				CreatedBy:    "User1",
  1684  				CreatedDate:  *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1685  				CurrentActivations: CurrentActivations{
  1686  					Production: ActivationInfo{
  1687  						Effective: &PolicyActivation{
  1688  							CreatedBy:   "User1",
  1689  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1690  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1691  							ID:          123,
  1692  							Links: []Link{
  1693  								{
  1694  									Href: "Link1",
  1695  									Rel:  "self",
  1696  								},
  1697  							},
  1698  							Network:              ProductionNetwork,
  1699  							Operation:            OperationActivation,
  1700  							PolicyID:             1234,
  1701  							PolicyVersion:        1,
  1702  							PolicyVersionDeleted: false,
  1703  							Status:               ActivationStatusSuccess,
  1704  						},
  1705  						Latest: &PolicyActivation{
  1706  							CreatedBy:   "User1",
  1707  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1708  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1709  							ID:          321,
  1710  							Links: []Link{
  1711  								{
  1712  									Href: "Link2",
  1713  									Rel:  "self",
  1714  								},
  1715  							},
  1716  							Network:              ProductionNetwork,
  1717  							Operation:            OperationActivation,
  1718  							PolicyID:             4321,
  1719  							PolicyVersion:        1,
  1720  							PolicyVersionDeleted: false,
  1721  							Status:               ActivationStatusSuccess,
  1722  						},
  1723  					},
  1724  					Staging: ActivationInfo{
  1725  						Effective: &PolicyActivation{
  1726  							CreatedBy:   "User3",
  1727  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1728  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1729  							ID:          789,
  1730  							Links: []Link{
  1731  								{
  1732  									Href: "Link3",
  1733  									Rel:  "self",
  1734  								},
  1735  							},
  1736  							Network:              StagingNetwork,
  1737  							Operation:            OperationActivation,
  1738  							PolicyID:             6789,
  1739  							PolicyVersion:        1,
  1740  							PolicyVersionDeleted: false,
  1741  							Status:               ActivationStatusSuccess,
  1742  						},
  1743  						Latest: &PolicyActivation{
  1744  							CreatedBy:   "User3",
  1745  							CreatedDate: *newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1746  							FinishDate:  newTimeFromString(t, "2023-10-23T11:22:57.589Z"),
  1747  							ID:          987,
  1748  							Links: []Link{
  1749  								{
  1750  									Href: "Link4",
  1751  									Rel:  "self",
  1752  								},
  1753  							},
  1754  							Network:              StagingNetwork,
  1755  							Operation:            OperationActivation,
  1756  							PolicyID:             9876,
  1757  							PolicyVersion:        1,
  1758  							PolicyVersionDeleted: false,
  1759  							Status:               ActivationStatusSuccess,
  1760  						},
  1761  					},
  1762  				},
  1763  				Description: tools.StringPtr("Description"),
  1764  				GroupID:     1,
  1765  				ID:          11,
  1766  				Links: []Link{
  1767  					{
  1768  						Href: "Link1",
  1769  						Rel:  "self",
  1770  					},
  1771  				},
  1772  				ModifiedBy:   "User1",
  1773  				ModifiedDate: newTimeFromString(t, "2023-10-23T11:21:19.896Z"),
  1774  				Name:         "NewName",
  1775  				PolicyType:   PolicyTypeShared,
  1776  			},
  1777  		},
  1778  		"validation errors - missing required params": {
  1779  			params: ClonePolicyRequest{},
  1780  			withError: func(t *testing.T, err error) {
  1781  				assert.Equal(t, "clone policy: struct validation: NewName: cannot be blank\nPolicyID: cannot be blank", err.Error())
  1782  			},
  1783  		},
  1784  		"validation errors - newName too long": {
  1785  			params: ClonePolicyRequest{
  1786  				PolicyID: 1,
  1787  				BodyParams: ClonePolicyBodyParams{
  1788  					GroupID: 11,
  1789  					NewName: strings.Repeat("TestNameTooLong", 10),
  1790  				},
  1791  			},
  1792  			withError: func(t *testing.T, err error) {
  1793  				assert.Equal(t, "clone policy: struct validation: NewName: the length must be no more than 64", err.Error())
  1794  			},
  1795  		},
  1796  	}
  1797  
  1798  	for name, test := range tests {
  1799  		t.Run(name, func(t *testing.T) {
  1800  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1801  				assert.Equal(t, test.expectedPath, r.URL.String())
  1802  				assert.Equal(t, http.MethodPost, r.Method)
  1803  
  1804  				if test.expectedRequestBody != "" {
  1805  					body, err := io.ReadAll(r.Body)
  1806  					require.NoError(t, err)
  1807  					assert.JSONEq(t, test.expectedRequestBody, string(body))
  1808  				}
  1809  				w.WriteHeader(test.responseStatus)
  1810  				_, err := w.Write([]byte(test.responseBody))
  1811  				assert.NoError(t, err)
  1812  			}))
  1813  			client := mockAPIClient(t, mockServer)
  1814  			result, err := client.ClonePolicy(context.Background(), test.params)
  1815  			if test.withError != nil {
  1816  				test.withError(t, err)
  1817  				return
  1818  			}
  1819  			require.NoError(t, err)
  1820  			assert.Equal(t, test.expectedResponse, result)
  1821  		})
  1822  	}
  1823  }