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

     1  package imaging
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/http/httptest"
    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  		expectedHeaders  map[string][]string
    25  		withError        error
    26  	}{
    27  		"200 OK": {
    28  			params: ListPoliciesRequest{
    29  				Network:     PolicyNetworkStaging,
    30  				ContractID:  "3-WNKXX1",
    31  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
    32  			},
    33  			responseStatus: http.StatusOK,
    34  			responseBody: `
    35  {
    36      "itemKind": "POLICY",
    37      "items": [
    38          {
    39              "id": ".auto",
    40              "version": 1,
    41              "previousVersion": 0,
    42              "rolloutInfo": {
    43                  "startTime": 1626379176,
    44                  "endTime": 1626379177,
    45                  "rolloutDuration": 1
    46              },
    47              "video": false,
    48              "user": "system",
    49              "dateCreated": "2021-07-15 19:59:35+0000"
    50          },
    51          {
    52              "id": "asd",
    53              "version": 2,
    54              "previousVersion": 1,
    55              "rolloutInfo": {
    56                  "startTime": 1638894035,
    57                  "endTime": 1638894036,
    58                  "rolloutDuration": 1
    59              },
    60              "breakpoints": {
    61                  "widths": [
    62                      320,
    63                      640,
    64                      1024,
    65                      2048,
    66                      5000
    67                  ]
    68              },
    69              "output": {
    70                  "perceptualQuality": "mediumHigh"
    71              },
    72              "transformations": [
    73                  {
    74                      "transformation": "Composite",
    75                      "xPosition": 0,
    76                      "yPosition": 0,
    77                      "gravity": "NorthWest",
    78                      "placement": "Over",
    79                      "image": {
    80                          "type": "Text",
    81                          "fill": "#000000",
    82                          "size": 72,
    83                          "stroke": "#FFFFFF",
    84                          "strokeSize": 0,
    85                          "text": "Hello There",
    86                          "transformation": {
    87                              "transformation": "Compound",
    88                              "transformations": []
    89                          }
    90                      }
    91                  }
    92              ],
    93              "video": false,
    94              "user": "jsmith",
    95              "dateCreated": "2021-12-07 16:20:34+0000"
    96          },
    97          {
    98              "id": "cheese",
    99              "version": 1,
   100              "previousVersion": 0,
   101              "rolloutInfo": {
   102                  "startTime": 1628279193,
   103                  "endTime": 1628279194,
   104                  "rolloutDuration": 1
   105              },
   106              "breakpoints": {
   107                  "widths": [
   108                      720,
   109                      1080,
   110                      1366,
   111                      1920,
   112                      5000
   113                  ]
   114              },
   115              "output": {
   116                  "perceptualQuality": "mediumHigh"
   117              },
   118              "video": false,
   119              "user": "jsmith",
   120              "dateCreated": "2021-08-06 19:46:32+0000"
   121          },
   122          {
   123              "id": "example",
   124              "version": 9,
   125              "previousVersion": 8,
   126              "rolloutInfo": {
   127                  "startTime": 1639680399,
   128                  "endTime": 1639680400,
   129                  "rolloutDuration": 1
   130              },
   131              "breakpoints": {
   132                  "widths": [
   133                      320,
   134                      640,
   135                      1024,
   136                      2048,
   137                      5000
   138                  ]
   139              },
   140              "output": {
   141                  "perceptualQuality": "mediumHigh"
   142              },
   143              "transformations": [
   144                  {
   145                      "transformation": "Blur",
   146                      "sigma": {
   147                          "var": "blurVar"
   148                      }
   149                  },
   150                  {
   151                      "transformation": "MaxColors",
   152                      "colors": 2
   153                  }
   154              ],
   155              "variables": [
   156                  {
   157                      "name": "blurVar",
   158                      "type": "number",
   159                      "defaultValue": "5"
   160                  }
   161              ],
   162              "video": false,
   163              "user": "foofoo5",
   164              "dateCreated": "2021-12-16 18:46:38+0000"
   165          },
   166          {
   167              "id": "mgw",
   168              "version": 1,
   169              "previousVersion": 0,
   170              "rolloutInfo": {
   171                  "startTime": 1639680457,
   172                  "endTime": 1639680458,
   173                  "rolloutDuration": 1
   174              },
   175              "breakpoints": {
   176                  "widths": [
   177                      320,
   178                      640,
   179                      1024,
   180                      2048,
   181                      5000
   182                  ]
   183              },
   184              "output": {
   185                  "perceptualQuality": "mediumHigh"
   186              },
   187              "transformations": [
   188                  {
   189                      "transformation": "Blur",
   190                      "sigma": {
   191                          "var": "blurVar"
   192                      }
   193                  },
   194                  {
   195                      "transformation": "MaxColors",
   196                      "colors": 2
   197                  }
   198              ],
   199              "variables": [
   200                  {
   201                      "name": "blurVar",
   202                      "type": "number",
   203                      "defaultValue": "5"
   204                  }
   205              ],
   206              "video": false,
   207              "user": "foofoo5",
   208              "dateCreated": "2021-12-16 18:47:36+0000"
   209          },
   210          {
   211              "id": "testPolicy2",
   212              "version": 1,
   213              "previousVersion": 0,
   214              "rolloutInfo": {
   215                  "startTime": 1643052400,
   216                  "endTime": 1643052401,
   217                  "rolloutDuration": 1
   218              },
   219              "video": false,
   220              "user": "jsmith",
   221              "dateCreated": "2022-01-24 19:26:39+0000"
   222          },
   223          {
   224              "id": "testpolicy",
   225              "version": 1,
   226              "previousVersion": 0,
   227              "rolloutInfo": {
   228                  "startTime": 1643052164,
   229                  "endTime": 1643052165,
   230                  "rolloutDuration": 1
   231              },
   232              "video": false,
   233              "user": "jsmith",
   234              "dateCreated": "2022-01-24 19:22:43+0000"
   235          },
   236          {
   237              "id": "updatePolicy",
   238              "version": 2,
   239              "previousVersion": 1,
   240              "rolloutInfo": {
   241                  "startTime": 1643055431,
   242                  "endTime": 1643055432,
   243                  "rolloutDuration": 1
   244              },
   245              "output": {
   246                  "perceptualQuality": "mediumHigh"
   247              },
   248              "video": true,
   249              "user": "jsmith",
   250              "dateCreated": "2022-01-24 20:17:10+0000"
   251          }
   252      ],
   253      "totalItems": 8
   254  }`,
   255  			expectedPath: "/imaging/v2/network/staging/policies/",
   256  			expectedHeaders: map[string][]string{
   257  				"Contract":   {"3-WNKXX1"},
   258  				"Policy-Set": {"570f9090-5dbe-11ec-8a0a-71665789c1d8"},
   259  			},
   260  			expectedResponse: &ListPoliciesResponse{
   261  				ItemKind: "POLICY",
   262  				Items: PolicyOutputs{
   263  					&PolicyOutputImage{
   264  						ID:              ".auto",
   265  						Version:         1,
   266  						PreviousVersion: 0,
   267  						RolloutInfo: &RolloutInfo{
   268  							StartTime:       1626379176,
   269  							EndTime:         1626379177,
   270  							RolloutDuration: 1,
   271  						},
   272  						Video:       tools.BoolPtr(false),
   273  						User:        "system",
   274  						DateCreated: "2021-07-15 19:59:35+0000",
   275  					},
   276  					&PolicyOutputImage{
   277  						ID:              "asd",
   278  						Version:         2,
   279  						PreviousVersion: 1,
   280  						RolloutInfo: &RolloutInfo{
   281  							StartTime:       1638894035,
   282  							EndTime:         1638894036,
   283  							RolloutDuration: 1,
   284  						},
   285  						Breakpoints: &Breakpoints{
   286  							Widths: []int{320, 640, 1024, 2048, 5000},
   287  						},
   288  						Output: &OutputImage{
   289  							PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
   290  								Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh),
   291  							},
   292  						},
   293  						Transformations: []TransformationType{
   294  							&Composite{
   295  								Transformation: "Composite",
   296  								XPosition: &IntegerVariableInline{
   297  									Value: tools.IntPtr(0),
   298  								},
   299  								YPosition: &IntegerVariableInline{
   300  									Value: tools.IntPtr(0),
   301  								},
   302  								Gravity: &GravityVariableInline{
   303  									Value: GravityPtr(GravityNorthWest),
   304  								},
   305  								Placement: &CompositePlacementVariableInline{
   306  									Value: CompositePlacementPtr(CompositePlacementOver),
   307  								},
   308  								Image: &TextImageType{
   309  									Type: "Text",
   310  									Fill: &StringVariableInline{
   311  										Value: tools.StringPtr("#000000"),
   312  									},
   313  									Size: &NumberVariableInline{
   314  										Value: tools.Float64Ptr(72),
   315  									},
   316  									Stroke: &StringVariableInline{
   317  										Value: tools.StringPtr("#FFFFFF"),
   318  									},
   319  									StrokeSize: &NumberVariableInline{
   320  										Value: tools.Float64Ptr(0),
   321  									},
   322  									Text: &StringVariableInline{
   323  										Value: tools.StringPtr("Hello There"),
   324  									},
   325  									Transformation: &Compound{
   326  										Transformation: "Compound",
   327  									},
   328  								},
   329  							},
   330  						},
   331  						Video:       tools.BoolPtr(false),
   332  						User:        "jsmith",
   333  						DateCreated: "2021-12-07 16:20:34+0000",
   334  					},
   335  					&PolicyOutputImage{
   336  						ID:              "cheese",
   337  						Version:         1,
   338  						PreviousVersion: 0,
   339  						RolloutInfo: &RolloutInfo{
   340  							StartTime:       1628279193,
   341  							EndTime:         1628279194,
   342  							RolloutDuration: 1,
   343  						},
   344  						Breakpoints: &Breakpoints{
   345  							Widths: []int{720, 1080, 1366, 1920, 5000},
   346  						},
   347  						Output: &OutputImage{
   348  							PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
   349  								Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh),
   350  							},
   351  						},
   352  						Video:       tools.BoolPtr(false),
   353  						User:        "jsmith",
   354  						DateCreated: "2021-08-06 19:46:32+0000",
   355  					},
   356  					&PolicyOutputImage{
   357  						ID:              "example",
   358  						Version:         9,
   359  						PreviousVersion: 8,
   360  						RolloutInfo: &RolloutInfo{
   361  							StartTime:       1639680399,
   362  							EndTime:         1639680400,
   363  							RolloutDuration: 1,
   364  						},
   365  						Breakpoints: &Breakpoints{
   366  							Widths: []int{320, 640, 1024, 2048, 5000},
   367  						},
   368  						Output: &OutputImage{
   369  							PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
   370  								Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh),
   371  							},
   372  						},
   373  						Transformations: []TransformationType{
   374  							&Blur{
   375  								Transformation: "Blur",
   376  								Sigma: &NumberVariableInline{
   377  									Name: tools.StringPtr("blurVar"),
   378  								},
   379  							},
   380  							&MaxColors{
   381  								Transformation: "MaxColors",
   382  								Colors: &IntegerVariableInline{
   383  									Value: tools.IntPtr(2),
   384  								},
   385  							},
   386  						},
   387  						Variables: []Variable{
   388  							{
   389  								Name:         "blurVar",
   390  								Type:         VariableTypeNumber,
   391  								DefaultValue: "5",
   392  							},
   393  						},
   394  						Video:       tools.BoolPtr(false),
   395  						User:        "foofoo5",
   396  						DateCreated: "2021-12-16 18:46:38+0000",
   397  					},
   398  					&PolicyOutputImage{
   399  						ID:              "mgw",
   400  						Version:         1,
   401  						PreviousVersion: 0,
   402  						RolloutInfo: &RolloutInfo{
   403  							StartTime:       1639680457,
   404  							EndTime:         1639680458,
   405  							RolloutDuration: 1,
   406  						},
   407  						Breakpoints: &Breakpoints{
   408  							Widths: []int{320, 640, 1024, 2048, 5000},
   409  						},
   410  						Output: &OutputImage{
   411  							PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
   412  								Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh),
   413  							},
   414  						},
   415  						Transformations: []TransformationType{
   416  							&Blur{
   417  								Transformation: "Blur",
   418  								Sigma: &NumberVariableInline{
   419  									Name: tools.StringPtr("blurVar"),
   420  								},
   421  							},
   422  							&MaxColors{
   423  								Transformation: "MaxColors",
   424  								Colors: &IntegerVariableInline{
   425  									Value: tools.IntPtr(2),
   426  								},
   427  							},
   428  						},
   429  						Variables: []Variable{
   430  							{
   431  								Name:         "blurVar",
   432  								Type:         VariableTypeNumber,
   433  								DefaultValue: "5",
   434  							},
   435  						},
   436  						Video:       tools.BoolPtr(false),
   437  						User:        "foofoo5",
   438  						DateCreated: "2021-12-16 18:47:36+0000",
   439  					},
   440  					&PolicyOutputImage{
   441  						ID:              "testPolicy2",
   442  						Version:         1,
   443  						PreviousVersion: 0,
   444  						RolloutInfo: &RolloutInfo{
   445  							StartTime:       1643052400,
   446  							EndTime:         1643052401,
   447  							RolloutDuration: 1,
   448  						},
   449  						Video:       tools.BoolPtr(false),
   450  						User:        "jsmith",
   451  						DateCreated: "2022-01-24 19:26:39+0000",
   452  					},
   453  					&PolicyOutputImage{
   454  						ID:              "testpolicy",
   455  						Version:         1,
   456  						PreviousVersion: 0,
   457  						RolloutInfo: &RolloutInfo{
   458  							StartTime:       1643052164,
   459  							EndTime:         1643052165,
   460  							RolloutDuration: 1,
   461  						},
   462  						Video:       tools.BoolPtr(false),
   463  						User:        "jsmith",
   464  						DateCreated: "2022-01-24 19:22:43+0000",
   465  					},
   466  					&PolicyOutputVideo{
   467  						ID:              "updatePolicy",
   468  						Version:         2,
   469  						PreviousVersion: 1,
   470  						RolloutInfo: &RolloutInfo{
   471  							StartTime:       1643055431,
   472  							EndTime:         1643055432,
   473  							RolloutDuration: 1,
   474  						},
   475  						Output: &OutputVideo{
   476  							PerceptualQuality: &OutputVideoPerceptualQualityVariableInline{
   477  								Value: OutputVideoPerceptualQualityPtr(OutputVideoPerceptualQualityMediumHigh),
   478  							},
   479  						},
   480  						Video:       tools.BoolPtr(true),
   481  						User:        "jsmith",
   482  						DateCreated: "2022-01-24 20:17:10+0000",
   483  					},
   484  				},
   485  				TotalItems: 8,
   486  			},
   487  		},
   488  		"200 OK very deep": {
   489  			params: ListPoliciesRequest{
   490  				Network:     PolicyNetworkStaging,
   491  				ContractID:  "3-WNKXX1",
   492  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
   493  			},
   494  			responseStatus: http.StatusOK,
   495  			responseBody: `
   496  {
   497      "itemKind": "POLICY",
   498      "items": [
   499  {
   500  	"variables": [
   501  		{
   502  			"name": "ResizeDim",
   503  			"type": "number",
   504  			"defaultValue": "280"
   505  		},
   506  		{
   507  			"name": "ResizeDimWithBorder",
   508  			"type": "number",
   509  			"defaultValue": "260"
   510  		},
   511  		{
   512  			"name": "MinDim",
   513  			"type": "number",
   514  			"defaultValue": "1000"
   515  		},
   516  		{
   517  			"name": "MinDimNew",
   518  			"type": "number",
   519  			"defaultValue": "1450"
   520  		},
   521  		{
   522  			"name": "MaxDimOld",
   523  			"type": "number",
   524  			"defaultValue": "1500"
   525  		}
   526  	],
   527  	"transformations": [
   528  		{
   529  			"transformation": "Trim",
   530  			"fuzz": 0.08,
   531  			"padding": 0
   532  		},
   533  		{
   534  			"transformation": "IfDimension",
   535  			"dimension": "width",
   536  			"value": {
   537  				"var": "MaxDimOld"
   538  			},
   539  			"default": {
   540  				"transformation": "Compound",
   541  				"transformations": [
   542  					{
   543  						"transformation": "IfDimension",
   544  						"dimension": "width",
   545  						"value": {
   546  							"var": "MinDim"
   547  						},
   548  						"lessThan": {
   549  							"transformation": "Compound",
   550  							"transformations": [
   551  								{
   552  									"transformation": "Resize",
   553  									"aspect": "fit",
   554  									"type": "normal",
   555  									"width": {
   556  										"var": "ResizeDimWithBorder"
   557  									},
   558  									"height": {
   559  										"var": "ResizeDimWithBorder"
   560  									}
   561  								},
   562  								{
   563  									"transformation": "Crop",
   564  									"xPosition": 0,
   565  									"yPosition": 0,
   566  									"gravity": "Center",
   567  									"allowExpansion": true,
   568  									"width": {
   569  										"var": "ResizeDim"
   570  									},
   571  									"height": {
   572  										"var": "ResizeDim"
   573  									}
   574  								},
   575  								{
   576  									"transformation": "BackgroundColor",
   577  									"color": "#ffffff"
   578  								}
   579  							]
   580  						},
   581  						"default": {
   582  							"transformation": "Compound",
   583  							"transformations": [
   584  								{
   585  									"transformation": "IfDimension",
   586  									"dimension": "height",
   587  									"value": {
   588  										"var": "MinDim"
   589  									},
   590  									"lessThan": {
   591  										"transformation": "Compound",
   592  										"transformations": [
   593  											{
   594  												"transformation": "Resize",
   595  												"aspect": "fit",
   596  												"type": "normal",
   597  												"width": {
   598  													"var": "ResizeDimWithBorder"
   599  												},
   600  												"height": {
   601  													"var": "ResizeDimWithBorder"
   602  												}
   603  											},
   604  											{
   605  												"transformation": "Crop",
   606  												"xPosition": 0,
   607  												"yPosition": 0,
   608  												"gravity": "Center",
   609  												"allowExpansion": true,
   610  												"width": {
   611  													"var": "ResizeDim"
   612  												},
   613  												"height": {
   614  													"var": "ResizeDim"
   615  												}
   616  											},
   617  											{
   618  												"transformation": "BackgroundColor",
   619  												"color": "#ffffff"
   620  											}
   621  										]
   622  									},
   623  									"default": {
   624  										"transformation": "Compound",
   625  										"transformations": [
   626  											{
   627  												"transformation": "IfDimension",
   628  												"dimension": "height",
   629  												"value": {
   630  													"var": "MaxDimOld"
   631  												},
   632  												"greaterThan": {
   633  													"transformation": "Compound",
   634  													"transformations": [
   635  														{
   636  															"transformation": "Resize",
   637  															"aspect": "fit",
   638  															"type": "normal",
   639  															"width": {
   640  																"var": "ResizeDimWithBorder"
   641  															},
   642  															"height": {
   643  																"var": "ResizeDimWithBorder"
   644  															}
   645  														},
   646  														{
   647  															"transformation": "Crop",
   648  															"xPosition": 0,
   649  															"yPosition": 0,
   650  															"gravity": "Center",
   651  															"allowExpansion": true,
   652  															"width": {
   653  																"var": "ResizeDim"
   654  															},
   655  															"height": {
   656  																"var": "ResizeDim"
   657  															}
   658  														},
   659  														{
   660  															"transformation": "BackgroundColor",
   661  															"color": "#ffffff"
   662  														}
   663  													]
   664  												},
   665  												"default": {
   666  													"transformation": "Compound",
   667  													"transformations": [
   668  														{
   669  															"transformation": "Resize",
   670  															"aspect": "fit",
   671  															"type": "normal",
   672  															"width": {
   673  																"var": "ResizeDim"
   674  															},
   675  															"height": {
   676  																"var": "ResizeDim"
   677  															}
   678  														},
   679  														{
   680  															"transformation": "Crop",
   681  															"xPosition": 0,
   682  															"yPosition": 0,
   683  															"gravity": "Center",
   684  															"allowExpansion": true,
   685  															"width": {
   686  																"var": "ResizeDim"
   687  															},
   688  															"height": {
   689  																"var": "ResizeDim"
   690  															}
   691  														},
   692  														{
   693  															"transformation": "BackgroundColor",
   694  															"color": "#ffffff"
   695  														}
   696  													]
   697  												}
   698  											}
   699  										]
   700  									}
   701  								}
   702  							]
   703  						}
   704  					}
   705  				]
   706  			}
   707  		}
   708  	],
   709  	"breakpoints": {
   710  		"widths": [
   711  			280
   712  		]
   713  	},
   714  	"output": {
   715  		"perceptualQuality": "mediumHigh",
   716  		"adaptiveQuality": 50
   717  	},
   718  	"video": false,
   719  	"id": "multidimension",
   720  	"dateCreated": "2022-01-01 12:00:00+0000",
   721  	"previousVersion": 0,
   722  	"version": 1
   723          }
   724      ],
   725      "totalItems": 8
   726  }`,
   727  			expectedPath: "/imaging/v2/network/staging/policies/",
   728  			expectedResponse: &ListPoliciesResponse{
   729  				ItemKind: "POLICY",
   730  				Items: PolicyOutputs{
   731  					&PolicyOutputImage{
   732  						Variables: []Variable{
   733  							{
   734  								Name:         "ResizeDim",
   735  								Type:         "number",
   736  								DefaultValue: "280",
   737  							},
   738  							{
   739  								Name:         "ResizeDimWithBorder",
   740  								Type:         "number",
   741  								DefaultValue: "260",
   742  							},
   743  							{
   744  								Name:         "MinDim",
   745  								Type:         "number",
   746  								DefaultValue: "1000",
   747  							},
   748  							{
   749  								Name:         "MinDimNew",
   750  								Type:         "number",
   751  								DefaultValue: "1450",
   752  							},
   753  							{
   754  								Name:         "MaxDimOld",
   755  								Type:         "number",
   756  								DefaultValue: "1500",
   757  							},
   758  						},
   759  						Transformations: []TransformationType{
   760  							&Trim{
   761  								Transformation: "Trim",
   762  								Fuzz: &NumberVariableInline{
   763  									Value: tools.Float64Ptr(0.08),
   764  								},
   765  								Padding: &IntegerVariableInline{
   766  									Value: tools.IntPtr(0),
   767  								},
   768  							},
   769  							&IfDimension{
   770  								Transformation: "IfDimension",
   771  								Dimension: &IfDimensionDimensionVariableInline{
   772  									Value: IfDimensionDimensionPtr("width"),
   773  								},
   774  								Value: &IntegerVariableInline{
   775  									Name: tools.StringPtr("MaxDimOld"),
   776  								},
   777  								Default: &Compound{
   778  									Transformation: "Compound",
   779  									Transformations: []TransformationType{
   780  										&IfDimension{
   781  											Transformation: "IfDimension",
   782  											Dimension: &IfDimensionDimensionVariableInline{
   783  												Value: IfDimensionDimensionPtr("width"),
   784  											},
   785  											Value: &IntegerVariableInline{
   786  												Name: tools.StringPtr("MinDim"),
   787  											},
   788  											LessThan: &Compound{
   789  												Transformation: "Compound",
   790  												Transformations: []TransformationType{
   791  													&Resize{
   792  														Transformation: "Resize",
   793  														Aspect: &ResizeAspectVariableInline{
   794  															Value: ResizeAspectPtr("fit"),
   795  														},
   796  														Type: &ResizeTypeVariableInline{
   797  															Value: ResizeTypePtr("normal"),
   798  														},
   799  														Width: &IntegerVariableInline{
   800  															Name: tools.StringPtr("ResizeDimWithBorder"),
   801  														},
   802  														Height: &IntegerVariableInline{
   803  															Name: tools.StringPtr("ResizeDimWithBorder"),
   804  														},
   805  													},
   806  													&Crop{
   807  														Transformation: "Crop",
   808  														XPosition: &IntegerVariableInline{
   809  															Value: tools.IntPtr(0),
   810  														},
   811  														YPosition: &IntegerVariableInline{
   812  															Value: tools.IntPtr(0),
   813  														},
   814  														Gravity: &GravityVariableInline{
   815  															Value: GravityPtr("Center"),
   816  														},
   817  														AllowExpansion: &BooleanVariableInline{
   818  															Value: tools.BoolPtr(true),
   819  														},
   820  														Width: &IntegerVariableInline{
   821  															Name: tools.StringPtr("ResizeDim"),
   822  														},
   823  														Height: &IntegerVariableInline{
   824  															Name: tools.StringPtr("ResizeDim"),
   825  														},
   826  													},
   827  													&BackgroundColor{
   828  														Transformation: "BackgroundColor",
   829  														Color: &StringVariableInline{
   830  															Value: tools.StringPtr("#ffffff"),
   831  														},
   832  													},
   833  												},
   834  											},
   835  											Default: &Compound{
   836  												Transformation: "Compound",
   837  												Transformations: []TransformationType{
   838  													&IfDimension{
   839  														Transformation: "IfDimension",
   840  														Dimension: &IfDimensionDimensionVariableInline{
   841  															Value: IfDimensionDimensionPtr("height"),
   842  														},
   843  														Value: &IntegerVariableInline{
   844  															Name: tools.StringPtr("MinDim"),
   845  														},
   846  														LessThan: &Compound{
   847  															Transformation: "Compound",
   848  															Transformations: []TransformationType{
   849  																&Resize{
   850  																	Transformation: "Resize",
   851  																	Aspect: &ResizeAspectVariableInline{
   852  																		Value: ResizeAspectPtr("fit"),
   853  																	},
   854  																	Type: &ResizeTypeVariableInline{
   855  																		Value: ResizeTypePtr("normal"),
   856  																	},
   857  																	Width: &IntegerVariableInline{
   858  																		Name: tools.StringPtr("ResizeDimWithBorder"),
   859  																	},
   860  																	Height: &IntegerVariableInline{
   861  																		Name: tools.StringPtr("ResizeDimWithBorder"),
   862  																	},
   863  																},
   864  																&Crop{
   865  																	Transformation: "Crop",
   866  																	XPosition: &IntegerVariableInline{
   867  																		Value: tools.IntPtr(0),
   868  																	},
   869  																	YPosition: &IntegerVariableInline{
   870  																		Value: tools.IntPtr(0),
   871  																	},
   872  																	Gravity: &GravityVariableInline{
   873  																		Value: GravityPtr("Center"),
   874  																	},
   875  																	AllowExpansion: &BooleanVariableInline{
   876  																		Value: tools.BoolPtr(true),
   877  																	},
   878  																	Width: &IntegerVariableInline{
   879  																		Name: tools.StringPtr("ResizeDim"),
   880  																	},
   881  																	Height: &IntegerVariableInline{
   882  																		Name: tools.StringPtr("ResizeDim"),
   883  																	},
   884  																},
   885  																&BackgroundColor{
   886  																	Transformation: "BackgroundColor",
   887  																	Color: &StringVariableInline{
   888  																		Value: tools.StringPtr("#ffffff"),
   889  																	},
   890  																},
   891  															},
   892  														},
   893  														Default: &Compound{
   894  															Transformation: "Compound",
   895  															Transformations: []TransformationType{
   896  																&IfDimension{
   897  																	Transformation: "IfDimension",
   898  																	Dimension: &IfDimensionDimensionVariableInline{
   899  																		Value: IfDimensionDimensionPtr("height"),
   900  																	},
   901  																	Value: &IntegerVariableInline{
   902  																		Name: tools.StringPtr("MaxDimOld"),
   903  																	},
   904  																	GreaterThan: &Compound{
   905  																		Transformation: "Compound",
   906  																		Transformations: []TransformationType{
   907  																			&Resize{
   908  																				Transformation: "Resize",
   909  																				Aspect: &ResizeAspectVariableInline{
   910  																					Value: ResizeAspectPtr("fit"),
   911  																				},
   912  																				Type: &ResizeTypeVariableInline{
   913  																					Value: ResizeTypePtr("normal"),
   914  																				},
   915  
   916  																				Width: &IntegerVariableInline{
   917  																					Name: tools.StringPtr("ResizeDimWithBorder"),
   918  																				},
   919  																				Height: &IntegerVariableInline{
   920  																					Name: tools.StringPtr("ResizeDimWithBorder"),
   921  																				},
   922  																			},
   923  																			&Crop{
   924  																				Transformation: "Crop",
   925  																				XPosition: &IntegerVariableInline{
   926  																					Value: tools.IntPtr(0),
   927  																				},
   928  																				YPosition: &IntegerVariableInline{
   929  																					Value: tools.IntPtr(0),
   930  																				},
   931  																				Gravity: &GravityVariableInline{
   932  																					Value: GravityPtr("Center"),
   933  																				},
   934  																				AllowExpansion: &BooleanVariableInline{
   935  																					Value: tools.BoolPtr(true),
   936  																				},
   937  																				Width: &IntegerVariableInline{
   938  																					Name: tools.StringPtr("ResizeDim"),
   939  																				},
   940  																				Height: &IntegerVariableInline{
   941  																					Name: tools.StringPtr("ResizeDim"),
   942  																				},
   943  																			},
   944  																			&BackgroundColor{
   945  																				Transformation: "BackgroundColor",
   946  																				Color: &StringVariableInline{
   947  																					Value: tools.StringPtr("#ffffff"),
   948  																				},
   949  																			},
   950  																		},
   951  																	},
   952  																	Default: &Compound{
   953  																		Transformation: "Compound",
   954  																		Transformations: []TransformationType{
   955  																			&Resize{
   956  																				Transformation: "Resize",
   957  																				Aspect: &ResizeAspectVariableInline{
   958  																					Value: ResizeAspectPtr("fit"),
   959  																				},
   960  																				Type: &ResizeTypeVariableInline{
   961  																					Value: ResizeTypePtr("normal"),
   962  																				},
   963  																				Width: &IntegerVariableInline{
   964  																					Name: tools.StringPtr("ResizeDim"),
   965  																				},
   966  																				Height: &IntegerVariableInline{
   967  																					Name: tools.StringPtr("ResizeDim"),
   968  																				},
   969  																			},
   970  																			&Crop{
   971  																				Transformation: "Crop",
   972  																				XPosition: &IntegerVariableInline{
   973  																					Value: tools.IntPtr(0),
   974  																				},
   975  																				YPosition: &IntegerVariableInline{
   976  																					Value: tools.IntPtr(0),
   977  																				},
   978  																				Gravity: &GravityVariableInline{
   979  																					Value: GravityPtr("Center"),
   980  																				},
   981  																				AllowExpansion: &BooleanVariableInline{
   982  																					Value: tools.BoolPtr(true),
   983  																				},
   984  																				Width: &IntegerVariableInline{
   985  																					Name: tools.StringPtr("ResizeDim"),
   986  																				},
   987  																				Height: &IntegerVariableInline{
   988  																					Name: tools.StringPtr("ResizeDim"),
   989  																				},
   990  																			},
   991  																			&BackgroundColor{
   992  																				Transformation: "BackgroundColor",
   993  																				Color: &StringVariableInline{
   994  																					Value: tools.StringPtr("#ffffff"),
   995  																				},
   996  																			},
   997  																		},
   998  																	},
   999  																},
  1000  															},
  1001  														},
  1002  													},
  1003  												},
  1004  											},
  1005  										},
  1006  									},
  1007  								},
  1008  							},
  1009  						},
  1010  						Breakpoints: &Breakpoints{
  1011  							Widths: []int{280},
  1012  						},
  1013  						Output: &OutputImage{
  1014  							PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
  1015  								Value: OutputImagePerceptualQualityPtr("mediumHigh"),
  1016  							},
  1017  							AdaptiveQuality: tools.IntPtr(50),
  1018  						},
  1019  						Video:           tools.BoolPtr(false),
  1020  						ID:              "multidimension",
  1021  						DateCreated:     "2022-01-01 12:00:00+0000",
  1022  						PreviousVersion: 0,
  1023  						Version:         1,
  1024  					},
  1025  				},
  1026  				TotalItems: 8,
  1027  			},
  1028  		},
  1029  		"400 Bad request": {
  1030  			params: ListPoliciesRequest{
  1031  				Network:     PolicyNetworkStaging,
  1032  				ContractID:  "3-WNKXX1",
  1033  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1034  			},
  1035  			responseStatus: http.StatusInternalServerError,
  1036  			responseBody: `{
  1037  "type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  1038  "title": "Bad Request",
  1039  "instance": "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  1040  "status": 400,
  1041  "detail": "A contract must be specified using the Contract header.",
  1042  "problemId": "52a21f40-9861-4d35-95d0-a603c85cb2ad"
  1043  }`,
  1044  			expectedPath: "/imaging/v2/network/staging/policies/",
  1045  			withError: &Error{
  1046  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  1047  				Title:     "Bad Request",
  1048  				Instance:  "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  1049  				Status:    400,
  1050  				Detail:    "A contract must be specified using the Contract header.",
  1051  				ProblemID: "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  1052  			},
  1053  		},
  1054  		"401 Not authorized": {
  1055  			params: ListPoliciesRequest{
  1056  				Network:     PolicyNetworkStaging,
  1057  				ContractID:  "3-WNKXX1",
  1058  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1059  			},
  1060  			responseStatus: http.StatusInternalServerError,
  1061  			responseBody: `{
  1062  "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  1063  "title": "Not authorized",
  1064  "status": 401,
  1065  "detail": "Inactive client token",
  1066  "instance": "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  1067  "method": "GET",
  1068  "serverIp": "104.81.220.242",
  1069  "clientIp": "22.22.22.22",
  1070  "requestId": "124cc33c",
  1071  "requestTime": "2022-01-12T16:53:44Z"
  1072  }`,
  1073  			expectedPath: "/imaging/v2/network/staging/policies/",
  1074  			withError: &Error{
  1075  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  1076  				Title:       "Not authorized",
  1077  				Status:      401,
  1078  				Detail:      "Inactive client token",
  1079  				Instance:    "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  1080  				Method:      "GET",
  1081  				ServerIP:    "104.81.220.242",
  1082  				ClientIP:    "22.22.22.22",
  1083  				RequestID:   "124cc33c",
  1084  				RequestTime: "2022-01-12T16:53:44Z",
  1085  			},
  1086  		},
  1087  		"403 Forbidden": {
  1088  			params: ListPoliciesRequest{
  1089  				Network:     PolicyNetworkStaging,
  1090  				ContractID:  "3-WNKXX1",
  1091  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1092  			},
  1093  			responseStatus: http.StatusForbidden,
  1094  			responseBody: `{
  1095  				"type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  1096  				"title": "Forbidden",
  1097  				"instance": "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  1098  				"status": 403,
  1099  				"detail": "User does not have authorization to perform this action.",
  1100  				"problemId": "7d633d60-b120-4f28-a0de-ad86aeaf3c68"
  1101  			}`,
  1102  			expectedPath: "/imaging/v2/network/staging/policies/",
  1103  			withError: &Error{
  1104  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  1105  				Title:     "Forbidden",
  1106  				Instance:  "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  1107  				Status:    403,
  1108  				Detail:    "User does not have authorization to perform this action.",
  1109  				ProblemID: "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  1110  			},
  1111  		},
  1112  		// 500
  1113  		"invalid network": {
  1114  			params: ListPoliciesRequest{
  1115  				ContractID: "3-WNKXX1",
  1116  				Network:    "foo",
  1117  			},
  1118  			withError: ErrStructValidation,
  1119  		},
  1120  		"missing contract": {
  1121  			params: ListPoliciesRequest{
  1122  				Network: PolicyNetworkProduction,
  1123  			},
  1124  			withError: ErrStructValidation,
  1125  		},
  1126  	}
  1127  
  1128  	for name, test := range tests {
  1129  		t.Run(name, func(t *testing.T) {
  1130  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1131  				assert.Equal(t, test.expectedPath, r.URL.String())
  1132  				for h := range test.expectedHeaders {
  1133  					assert.Equal(t, test.expectedHeaders[h], r.Header[h])
  1134  				}
  1135  				assert.Equal(t, http.MethodGet, r.Method)
  1136  				w.WriteHeader(test.responseStatus)
  1137  				_, err := w.Write([]byte(test.responseBody))
  1138  				assert.NoError(t, err)
  1139  			}))
  1140  			client := mockAPIClient(t, mockServer)
  1141  			result, err := client.ListPolicies(context.Background(), test.params)
  1142  			if test.withError != nil {
  1143  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  1144  				return
  1145  			}
  1146  			require.NoError(t, err)
  1147  			assert.Equal(t, test.expectedResponse, result)
  1148  		})
  1149  	}
  1150  }
  1151  
  1152  func TestGetPolicy(t *testing.T) {
  1153  	tests := map[string]struct {
  1154  		params           GetPolicyRequest
  1155  		responseStatus   int
  1156  		responseBody     string
  1157  		expectedPath     string
  1158  		expectedResponse PolicyOutput
  1159  		expectedHeaders  map[string][]string
  1160  		withError        error
  1161  	}{
  1162  		"200 OK - image": {
  1163  			params: GetPolicyRequest{
  1164  				Network:     PolicyNetworkStaging,
  1165  				ContractID:  "3-WNKXX1",
  1166  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1167  				PolicyID:    "foo",
  1168  			},
  1169  			responseStatus: http.StatusOK,
  1170  			responseBody: `
  1171          {
  1172              "id": "foo",
  1173              "version": 2,
  1174              "previousVersion": 1,
  1175              "rolloutInfo": {
  1176                  "startTime": 1638894035,
  1177                  "endTime": 1638894036,
  1178                  "rolloutDuration": 1
  1179              },
  1180              "breakpoints": {
  1181                  "widths": [
  1182                      320,
  1183                      640,
  1184                      1024,
  1185                      2048,
  1186                      5000
  1187                  ]
  1188              },
  1189              "output": {
  1190                  "perceptualQuality": "mediumHigh"
  1191              },
  1192              "transformations": [
  1193  				{
  1194  					"transformation": "Append",
  1195  					"gravity": "Center",
  1196  					"gravityPriority": "horizontal",
  1197  					"preserveMinorDimension": true,
  1198  					"image": {
  1199  						"type": "Text",
  1200  						"fill": "#000000",
  1201  						"size": 72,
  1202  						"stroke": "#FFFFFF",
  1203  						"strokeSize": 0,
  1204  						"text": "test",
  1205  						"transformation": {
  1206  							"transformation": "Compound",
  1207  							"transformations": []
  1208  						}
  1209  					}
  1210  				},
  1211  				{
  1212  					"transformation": "RegionOfInterestCrop",
  1213  					"style": "fill",
  1214  					"gravity": "Center",
  1215  					"width": 7,
  1216  					"height": 8,
  1217  					"regionOfInterest": {
  1218  						"anchor": {
  1219  							"x": 4,
  1220  							"y": 5
  1221  						},
  1222  						"width": 8,
  1223  						"height": 9
  1224  					} 
  1225  				},
  1226                  {
  1227                      "transformation": "Composite",
  1228                      "xPosition": 0,
  1229                      "yPosition": 0,
  1230                      "gravity": "NorthWest",
  1231                      "placement": "Over",
  1232                      "image": {
  1233                          "type": "Text",
  1234                          "fill": "#000000",
  1235                          "size": 72,
  1236                          "stroke": "#FFFFFF",
  1237                          "strokeSize": 0,
  1238                          "text": "Hello There",
  1239                          "transformation": {
  1240                              "transformation": "Compound",
  1241                              "transformations": []
  1242                          }
  1243                      }
  1244                  }
  1245              ],
  1246              "video": false,
  1247              "user": "jsmith",
  1248              "dateCreated": "2021-12-07 16:20:34+0000" 
  1249  }`,
  1250  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1251  			expectedHeaders: map[string][]string{
  1252  				"Contract":   {"3-WNKXX1"},
  1253  				"Policy-Set": {"570f9090-5dbe-11ec-8a0a-71665789c1d8"},
  1254  			},
  1255  			expectedResponse: &PolicyOutputImage{
  1256  				ID:              "foo",
  1257  				Version:         2,
  1258  				PreviousVersion: 1,
  1259  				RolloutInfo: &RolloutInfo{
  1260  					StartTime:       1638894035,
  1261  					EndTime:         1638894036,
  1262  					RolloutDuration: 1,
  1263  				},
  1264  				Breakpoints: &Breakpoints{
  1265  					Widths: []int{320, 640, 1024, 2048, 5000},
  1266  				},
  1267  				Output: &OutputImage{
  1268  					PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
  1269  						Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh),
  1270  					},
  1271  				},
  1272  				Transformations: []TransformationType{
  1273  					&Append{
  1274  						Transformation:         "Append",
  1275  						Gravity:                &GravityVariableInline{Value: GravityPtr("Center")},
  1276  						GravityPriority:        &AppendGravityPriorityVariableInline{Value: AppendGravityPriorityPtr("horizontal")},
  1277  						PreserveMinorDimension: &BooleanVariableInline{Value: tools.BoolPtr(true)},
  1278  						Image: &TextImageType{
  1279  							Type:       "Text",
  1280  							Fill:       &StringVariableInline{Value: tools.StringPtr("#000000")},
  1281  							Size:       &NumberVariableInline{Value: tools.Float64Ptr(72)},
  1282  							Stroke:     &StringVariableInline{Value: tools.StringPtr("#FFFFFF")},
  1283  							StrokeSize: &NumberVariableInline{Value: tools.Float64Ptr(0)},
  1284  							Text:       &StringVariableInline{Value: tools.StringPtr("test")},
  1285  							Transformation: &Compound{
  1286  								Transformation: "Compound",
  1287  							},
  1288  						},
  1289  					},
  1290  					&RegionOfInterestCrop{
  1291  						Transformation: "RegionOfInterestCrop",
  1292  						Style:          &RegionOfInterestCropStyleVariableInline{Value: RegionOfInterestCropStylePtr("fill")},
  1293  						Gravity:        &GravityVariableInline{Value: GravityPtr("Center")},
  1294  						Width:          &IntegerVariableInline{Value: tools.IntPtr(7)},
  1295  						Height:         &IntegerVariableInline{Value: tools.IntPtr(8)},
  1296  						RegionOfInterest: &RectangleShapeType{
  1297  							Anchor: &PointShapeType{
  1298  								X: &NumberVariableInline{Value: tools.Float64Ptr(4)},
  1299  								Y: &NumberVariableInline{Value: tools.Float64Ptr(5)},
  1300  							},
  1301  							Width:  &NumberVariableInline{Value: tools.Float64Ptr(8)},
  1302  							Height: &NumberVariableInline{Value: tools.Float64Ptr(9)},
  1303  						},
  1304  					},
  1305  					&Composite{
  1306  						Transformation: "Composite",
  1307  						XPosition: &IntegerVariableInline{
  1308  							Value: tools.IntPtr(0),
  1309  						},
  1310  						YPosition: &IntegerVariableInline{
  1311  							Value: tools.IntPtr(0),
  1312  						},
  1313  						Gravity: &GravityVariableInline{
  1314  							Value: GravityPtr(GravityNorthWest),
  1315  						},
  1316  						Placement: &CompositePlacementVariableInline{
  1317  							Value: CompositePlacementPtr(CompositePlacementOver),
  1318  						},
  1319  						Image: &TextImageType{
  1320  							Type: "Text",
  1321  							Fill: &StringVariableInline{
  1322  								Value: tools.StringPtr("#000000"),
  1323  							},
  1324  							Size: &NumberVariableInline{
  1325  								Value: tools.Float64Ptr(72),
  1326  							},
  1327  							Stroke: &StringVariableInline{
  1328  								Value: tools.StringPtr("#FFFFFF"),
  1329  							},
  1330  							StrokeSize: &NumberVariableInline{
  1331  								Value: tools.Float64Ptr(0),
  1332  							},
  1333  							Text: &StringVariableInline{
  1334  								Value: tools.StringPtr("Hello There"),
  1335  							},
  1336  							Transformation: &Compound{
  1337  								Transformation: "Compound",
  1338  							},
  1339  						},
  1340  					},
  1341  				},
  1342  				Video:       tools.BoolPtr(false),
  1343  				User:        "jsmith",
  1344  				DateCreated: "2021-12-07 16:20:34+0000",
  1345  			},
  1346  		},
  1347  		"200 OK - image post break transformation": {
  1348  			params: GetPolicyRequest{
  1349  				Network:     PolicyNetworkStaging,
  1350  				ContractID:  "3-WNKXX1",
  1351  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1352  				PolicyID:    "foo",
  1353  			},
  1354  			responseStatus: http.StatusOK,
  1355  			responseBody: `
  1356          {
  1357              "id": "foo",
  1358              "version": 2,
  1359              "previousVersion": 1,
  1360              "rolloutInfo": {
  1361                  "startTime": 1638894035,
  1362                  "endTime": 1638894036,
  1363                  "rolloutDuration": 1
  1364              },
  1365              "breakpoints": {
  1366                  "widths": [
  1367                      320,
  1368                      640,
  1369                      1024,
  1370                      2048,
  1371                      5000
  1372                  ]
  1373              },
  1374              "output": {
  1375                  "perceptualQuality": "mediumHigh"
  1376              },
  1377              "transformations": [
  1378  				{
  1379  					"transformation": "Append",
  1380  					"gravity": "Center",
  1381  					"gravityPriority": "horizontal",
  1382  					"preserveMinorDimension": true,
  1383  					"image": {
  1384  						"type": "Text",
  1385  						"fill": "#000000",
  1386  						"size": 72,
  1387  						"stroke": "#FFFFFF",
  1388  						"strokeSize": 0,
  1389  						"text": "test",
  1390  						"transformation": {
  1391  							"transformation": "Compound",
  1392  							"transformations": []
  1393  						}
  1394  					}
  1395  				},
  1396  				{
  1397  					"transformation": "RegionOfInterestCrop",
  1398  					"style": "fill",
  1399  					"gravity": "Center",
  1400  					"width": 7,
  1401  					"height": 8,
  1402  					"regionOfInterest": {
  1403  						"anchor": {
  1404  							"x": 4,
  1405  							"y": 5
  1406  						},
  1407  						"width": 8,
  1408  						"height": 9
  1409  					} 
  1410  				},
  1411                  {
  1412                      "transformation": "Composite",
  1413                      "xPosition": 0,
  1414                      "yPosition": 0,
  1415                      "gravity": "NorthWest",
  1416                      "placement": "Over",
  1417                      "image": {
  1418                          "type": "Text",
  1419                          "fill": "#000000",
  1420                          "size": 72,
  1421                          "stroke": "#FFFFFF",
  1422                          "strokeSize": 0,
  1423                          "text": "Hello There",
  1424                          "transformation": {
  1425                              "transformation": "Compound",
  1426                              "transformations": []
  1427                          }
  1428                      }
  1429                  }
  1430              ],
  1431  			"postBreakpointTransformations": [
  1432  					{
  1433  						"transformation": "IfDimension",
  1434  						"dimension": "width",
  1435  						"value": {
  1436  							"var": "MaxDimOld"
  1437  						},
  1438  						"default": {
  1439  							"transformation": "Compound",
  1440  							"transformations": [
  1441  								{
  1442  									"transformation": "IfDimension",
  1443  									"dimension": "width",
  1444  									"value": {
  1445  										"var": "MinDim"
  1446  									},
  1447  									"lessThan": {
  1448  										"transformation": "Compound",
  1449  										"transformations": [
  1450  											{
  1451  												"transformation": "BackgroundColor",
  1452  												"color": "#ffffff"
  1453  											},
  1454  											{
  1455  												"transformation": "BackgroundColor",
  1456  												"color": "#00ffff"
  1457  											}
  1458  										]
  1459  									}
  1460  								}
  1461  							]
  1462  						}
  1463  					},
  1464  					{
  1465  					  "transformation": "Composite",
  1466  					  "xPosition": 0,
  1467  					  "yPosition": 0,
  1468  					  "gravity": "NorthWest",
  1469  					  "placement": "Over",
  1470  					  "image": {
  1471  						"type": "Text",
  1472  						"fill": "#000000",
  1473  						"size": 72,
  1474  						"stroke": "#FFFFFF",
  1475  						"strokeSize": 0,
  1476  						"text": "test",
  1477  						"transformation": {
  1478  						  "transformation": "Compound",
  1479  						  "transformations": []
  1480  						}
  1481  					  }
  1482  					}
  1483  				],
  1484              "video": false,
  1485              "user": "jsmith",
  1486              "dateCreated": "2021-12-07 16:20:34+0000" 
  1487  }`,
  1488  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1489  			expectedHeaders: map[string][]string{
  1490  				"Contract":   {"3-WNKXX1"},
  1491  				"Policy-Set": {"570f9090-5dbe-11ec-8a0a-71665789c1d8"},
  1492  			},
  1493  			expectedResponse: &PolicyOutputImage{
  1494  				ID:              "foo",
  1495  				Version:         2,
  1496  				PreviousVersion: 1,
  1497  				RolloutInfo: &RolloutInfo{
  1498  					StartTime:       1638894035,
  1499  					EndTime:         1638894036,
  1500  					RolloutDuration: 1,
  1501  				},
  1502  				Breakpoints: &Breakpoints{
  1503  					Widths: []int{320, 640, 1024, 2048, 5000},
  1504  				},
  1505  				Output: &OutputImage{
  1506  					PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
  1507  						Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh),
  1508  					},
  1509  				},
  1510  				Transformations: []TransformationType{
  1511  					&Append{
  1512  						Transformation:         "Append",
  1513  						Gravity:                &GravityVariableInline{Value: GravityPtr("Center")},
  1514  						GravityPriority:        &AppendGravityPriorityVariableInline{Value: AppendGravityPriorityPtr("horizontal")},
  1515  						PreserveMinorDimension: &BooleanVariableInline{Value: tools.BoolPtr(true)},
  1516  						Image: &TextImageType{
  1517  							Type:       "Text",
  1518  							Fill:       &StringVariableInline{Value: tools.StringPtr("#000000")},
  1519  							Size:       &NumberVariableInline{Value: tools.Float64Ptr(72)},
  1520  							Stroke:     &StringVariableInline{Value: tools.StringPtr("#FFFFFF")},
  1521  							StrokeSize: &NumberVariableInline{Value: tools.Float64Ptr(0)},
  1522  							Text:       &StringVariableInline{Value: tools.StringPtr("test")},
  1523  							Transformation: &Compound{
  1524  								Transformation: "Compound",
  1525  							},
  1526  						},
  1527  					},
  1528  					&RegionOfInterestCrop{
  1529  						Transformation: "RegionOfInterestCrop",
  1530  						Style:          &RegionOfInterestCropStyleVariableInline{Value: RegionOfInterestCropStylePtr("fill")},
  1531  						Gravity:        &GravityVariableInline{Value: GravityPtr("Center")},
  1532  						Width:          &IntegerVariableInline{Value: tools.IntPtr(7)},
  1533  						Height:         &IntegerVariableInline{Value: tools.IntPtr(8)},
  1534  						RegionOfInterest: &RectangleShapeType{
  1535  							Anchor: &PointShapeType{
  1536  								X: &NumberVariableInline{Value: tools.Float64Ptr(4)},
  1537  								Y: &NumberVariableInline{Value: tools.Float64Ptr(5)},
  1538  							},
  1539  							Width:  &NumberVariableInline{Value: tools.Float64Ptr(8)},
  1540  							Height: &NumberVariableInline{Value: tools.Float64Ptr(9)},
  1541  						},
  1542  					},
  1543  					&Composite{
  1544  						Transformation: "Composite",
  1545  						XPosition: &IntegerVariableInline{
  1546  							Value: tools.IntPtr(0),
  1547  						},
  1548  						YPosition: &IntegerVariableInline{
  1549  							Value: tools.IntPtr(0),
  1550  						},
  1551  						Gravity: &GravityVariableInline{
  1552  							Value: GravityPtr(GravityNorthWest),
  1553  						},
  1554  						Placement: &CompositePlacementVariableInline{
  1555  							Value: CompositePlacementPtr(CompositePlacementOver),
  1556  						},
  1557  						Image: &TextImageType{
  1558  							Type: "Text",
  1559  							Fill: &StringVariableInline{
  1560  								Value: tools.StringPtr("#000000"),
  1561  							},
  1562  							Size: &NumberVariableInline{
  1563  								Value: tools.Float64Ptr(72),
  1564  							},
  1565  							Stroke: &StringVariableInline{
  1566  								Value: tools.StringPtr("#FFFFFF"),
  1567  							},
  1568  							StrokeSize: &NumberVariableInline{
  1569  								Value: tools.Float64Ptr(0),
  1570  							},
  1571  							Text: &StringVariableInline{
  1572  								Value: tools.StringPtr("Hello There"),
  1573  							},
  1574  							Transformation: &Compound{
  1575  								Transformation: "Compound",
  1576  							},
  1577  						},
  1578  					},
  1579  				},
  1580  				PostBreakpointTransformations: []TransformationTypePost{
  1581  					&IfDimensionPost{
  1582  						Transformation: "IfDimension",
  1583  						Dimension: &IfDimensionPostDimensionVariableInline{
  1584  							Value: IfDimensionPostDimensionPtr("width"),
  1585  						},
  1586  						Value: &IntegerVariableInline{
  1587  							Name: tools.StringPtr("MaxDimOld"),
  1588  						},
  1589  						Default: &CompoundPost{
  1590  							Transformation: "Compound",
  1591  							Transformations: []TransformationTypePost{
  1592  								&IfDimensionPost{
  1593  									Transformation: "IfDimension",
  1594  									Dimension: &IfDimensionPostDimensionVariableInline{
  1595  										Value: IfDimensionPostDimensionPtr("width"),
  1596  									},
  1597  									Value: &IntegerVariableInline{
  1598  										Name: tools.StringPtr("MinDim"),
  1599  									},
  1600  									LessThan: &CompoundPost{
  1601  										Transformation: "Compound",
  1602  										Transformations: []TransformationTypePost{
  1603  											&BackgroundColor{
  1604  												Transformation: "BackgroundColor",
  1605  												Color: &StringVariableInline{
  1606  													Value: tools.StringPtr("#ffffff"),
  1607  												},
  1608  											},
  1609  											&BackgroundColor{
  1610  												Transformation: "BackgroundColor",
  1611  												Color: &StringVariableInline{
  1612  													Value: tools.StringPtr("#00ffff"),
  1613  												},
  1614  											},
  1615  										},
  1616  									},
  1617  								},
  1618  							},
  1619  						},
  1620  					},
  1621  					&CompositePost{
  1622  						Gravity: &GravityPostVariableInline{Value: GravityPostPtr("NorthWest")},
  1623  						Image: &TextImageTypePost{
  1624  							Fill:       &StringVariableInline{Value: tools.StringPtr("#000000")},
  1625  							Size:       &NumberVariableInline{Value: tools.Float64Ptr(72)},
  1626  							Stroke:     &StringVariableInline{Value: tools.StringPtr("#FFFFFF")},
  1627  							StrokeSize: &NumberVariableInline{Value: tools.Float64Ptr(0)},
  1628  							Text:       &StringVariableInline{Value: tools.StringPtr("test")},
  1629  							Type:       TextImageTypePostTypeText,
  1630  							Transformation: &CompoundPost{
  1631  								Transformation: CompoundPostTransformationCompound,
  1632  							},
  1633  						},
  1634  						Placement:      &CompositePostPlacementVariableInline{Value: CompositePostPlacementPtr(CompositePostPlacementOver)},
  1635  						Transformation: CompositePostTransformationComposite,
  1636  						XPosition:      &IntegerVariableInline{Value: tools.IntPtr(0)},
  1637  						YPosition:      &IntegerVariableInline{Value: tools.IntPtr(0)},
  1638  					},
  1639  				},
  1640  				Video:       tools.BoolPtr(false),
  1641  				User:        "jsmith",
  1642  				DateCreated: "2021-12-07 16:20:34+0000",
  1643  			},
  1644  		},
  1645  		"200 OK - video": {
  1646  			params: GetPolicyRequest{
  1647  				Network:     PolicyNetworkStaging,
  1648  				ContractID:  "3-WNKXX1",
  1649  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1650  				PolicyID:    "foo",
  1651  			},
  1652  			responseStatus: http.StatusOK,
  1653  			responseBody: `
  1654  		       {
  1655  		           "id": "foo",
  1656  		           "version": 2,
  1657  		           "previousVersion": 1,
  1658  		           "rolloutInfo": {
  1659  		               "startTime": 1643055431,
  1660  		               "endTime": 1643055432,
  1661  		               "rolloutDuration": 1
  1662  		           },
  1663  		           "output": {
  1664  		               "perceptualQuality": "mediumHigh"
  1665  		           },
  1666  		           "video": true,
  1667  		           "user": "jsmith",
  1668  		           "dateCreated": "2022-01-24 20:17:10+0000"
  1669  		}`,
  1670  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1671  			expectedResponse: &PolicyOutputVideo{
  1672  				ID:              "foo",
  1673  				Version:         2,
  1674  				PreviousVersion: 1,
  1675  				RolloutInfo: &RolloutInfo{
  1676  					StartTime:       1643055431,
  1677  					EndTime:         1643055432,
  1678  					RolloutDuration: 1,
  1679  				},
  1680  				Output: &OutputVideo{
  1681  					PerceptualQuality: &OutputVideoPerceptualQualityVariableInline{
  1682  						Value: OutputVideoPerceptualQualityPtr(OutputVideoPerceptualQualityMediumHigh),
  1683  					},
  1684  				},
  1685  				Video:       tools.BoolPtr(true),
  1686  				User:        "jsmith",
  1687  				DateCreated: "2022-01-24 20:17:10+0000",
  1688  			},
  1689  		},
  1690  		"400 Bad request": {
  1691  			params: GetPolicyRequest{
  1692  				Network:     PolicyNetworkStaging,
  1693  				ContractID:  "3-WNKXX1",
  1694  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1695  				PolicyID:    "foo",
  1696  			},
  1697  			responseStatus: http.StatusInternalServerError,
  1698  			responseBody: `{
  1699  "type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  1700  "title": "Bad Request",
  1701  "instance": "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  1702  "status": 400,
  1703  "detail": "A contract must be specified using the Contract header.",
  1704  "problemId": "52a21f40-9861-4d35-95d0-a603c85cb2ad"
  1705  }`,
  1706  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1707  			withError: &Error{
  1708  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  1709  				Title:     "Bad Request",
  1710  				Instance:  "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  1711  				Status:    400,
  1712  				Detail:    "A contract must be specified using the Contract header.",
  1713  				ProblemID: "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  1714  			},
  1715  		},
  1716  		"401 Not authorized": {
  1717  			params: GetPolicyRequest{
  1718  				Network:     PolicyNetworkStaging,
  1719  				ContractID:  "3-WNKXX1",
  1720  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1721  				PolicyID:    "foo",
  1722  			},
  1723  			responseStatus: http.StatusInternalServerError,
  1724  			responseBody: `{
  1725  "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  1726  "title": "Not authorized",
  1727  "status": 401,
  1728  "detail": "Inactive client token",
  1729  "instance": "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  1730  "method": "GET",
  1731  "serverIp": "104.81.220.242",
  1732  "clientIp": "22.22.22.22",
  1733  "requestId": "124cc33c",
  1734  "requestTime": "2022-01-12T16:53:44Z"
  1735  }`,
  1736  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1737  			withError: &Error{
  1738  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  1739  				Title:       "Not authorized",
  1740  				Status:      401,
  1741  				Detail:      "Inactive client token",
  1742  				Instance:    "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  1743  				Method:      "GET",
  1744  				ServerIP:    "104.81.220.242",
  1745  				ClientIP:    "22.22.22.22",
  1746  				RequestID:   "124cc33c",
  1747  				RequestTime: "2022-01-12T16:53:44Z",
  1748  			},
  1749  		},
  1750  		"403 Forbidden": {
  1751  			params: GetPolicyRequest{
  1752  				Network:     PolicyNetworkStaging,
  1753  				ContractID:  "3-WNKXX1",
  1754  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1755  				PolicyID:    "foo",
  1756  			},
  1757  			responseStatus: http.StatusForbidden,
  1758  			responseBody: `{
  1759  				"type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  1760  				"title": "Forbidden",
  1761  				"instance": "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  1762  				"status": 403,
  1763  				"detail": "User does not have authorization to perform this action.",
  1764  				"problemId": "7d633d60-b120-4f28-a0de-ad86aeaf3c68"
  1765  			}`,
  1766  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1767  			withError: &Error{
  1768  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  1769  				Title:     "Forbidden",
  1770  				Instance:  "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  1771  				Status:    403,
  1772  				Detail:    "User does not have authorization to perform this action.",
  1773  				ProblemID: "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  1774  			},
  1775  		},
  1776  		// 500
  1777  		"invalid network": {
  1778  			params: GetPolicyRequest{
  1779  				ContractID:  "3-WNKXX1",
  1780  				Network:     "foo",
  1781  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1782  				PolicyID:    "foo",
  1783  			},
  1784  			withError: ErrStructValidation,
  1785  		},
  1786  		"missing contract": {
  1787  			params: GetPolicyRequest{
  1788  				Network:     PolicyNetworkProduction,
  1789  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1790  				PolicyID:    "foo",
  1791  			},
  1792  			withError: ErrStructValidation,
  1793  		},
  1794  		"missing policy id": {
  1795  			params: GetPolicyRequest{
  1796  				Network:     PolicyNetworkProduction,
  1797  				ContractID:  "3-WNKXX1",
  1798  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1799  			},
  1800  			withError: ErrStructValidation,
  1801  		},
  1802  		"missing policy set id": {
  1803  			params: GetPolicyRequest{
  1804  				Network:    PolicyNetworkProduction,
  1805  				PolicyID:   "foo",
  1806  				ContractID: "3-WNKXX1",
  1807  			},
  1808  			withError: ErrStructValidation,
  1809  		},
  1810  	}
  1811  
  1812  	for name, test := range tests {
  1813  		t.Run(name, func(t *testing.T) {
  1814  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1815  				assert.Equal(t, test.expectedPath, r.URL.String())
  1816  				for h := range test.expectedHeaders {
  1817  					assert.Equal(t, test.expectedHeaders[h], r.Header[h])
  1818  				}
  1819  				assert.Equal(t, http.MethodGet, r.Method)
  1820  				w.WriteHeader(test.responseStatus)
  1821  				_, err := w.Write([]byte(test.responseBody))
  1822  				assert.NoError(t, err)
  1823  			}))
  1824  			client := mockAPIClient(t, mockServer)
  1825  			result, err := client.GetPolicy(context.Background(), test.params)
  1826  			if test.withError != nil {
  1827  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  1828  				return
  1829  			}
  1830  			require.NoError(t, err)
  1831  			assert.Equal(t, test.expectedResponse, result)
  1832  		})
  1833  	}
  1834  }
  1835  func TestPutPolicy(t *testing.T) {
  1836  	tests := map[string]struct {
  1837  		params              UpsertPolicyRequest
  1838  		responseStatus      int
  1839  		responseBody        string
  1840  		expectedRequestBody string
  1841  		expectedPath        string
  1842  		expectedResponse    *PolicyResponse
  1843  		expectedHeaders     map[string][]string
  1844  		withError           error
  1845  	}{
  1846  		"200 OK - image": {
  1847  			params: UpsertPolicyRequest{
  1848  				Network:     PolicyNetworkStaging,
  1849  				ContractID:  "3-WNKXX1",
  1850  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1851  				PolicyID:    "foo",
  1852  				PolicyInput: &PolicyInputImage{
  1853  					Breakpoints: &Breakpoints{
  1854  						Widths: []int{320, 640, 1024, 2048, 5000},
  1855  					},
  1856  					Output: &OutputImage{
  1857  						PerceptualQuality: &OutputImagePerceptualQualityVariableInline{
  1858  							Value: OutputImagePerceptualQualityPtr(OutputImagePerceptualQualityMediumHigh),
  1859  						},
  1860  					},
  1861  					Transformations: []TransformationType{
  1862  						&Composite{
  1863  							Transformation: "Composite",
  1864  							XPosition: &IntegerVariableInline{
  1865  								Value: tools.IntPtr(0),
  1866  							},
  1867  							YPosition: &IntegerVariableInline{
  1868  								Value: tools.IntPtr(0),
  1869  							},
  1870  							Gravity: &GravityVariableInline{
  1871  								Value: GravityPtr(GravityNorthWest),
  1872  							},
  1873  							Placement: &CompositePlacementVariableInline{
  1874  								Value: CompositePlacementPtr(CompositePlacementOver),
  1875  							},
  1876  							Image: &TextImageType{
  1877  								Type: "Text",
  1878  								Fill: &StringVariableInline{
  1879  									Value: tools.StringPtr("#000000"),
  1880  								},
  1881  								Size: &NumberVariableInline{
  1882  									Value: tools.Float64Ptr(72),
  1883  								},
  1884  								Stroke: &StringVariableInline{
  1885  									Value: tools.StringPtr("#FFFFFF"),
  1886  								},
  1887  								StrokeSize: &NumberVariableInline{
  1888  									Value: tools.Float64Ptr(0),
  1889  								},
  1890  								Text: &StringVariableInline{
  1891  									Value: tools.StringPtr("Hello There"),
  1892  								},
  1893  								Transformation: &Compound{
  1894  									Transformation: "Compound",
  1895  								},
  1896  							},
  1897  						},
  1898  					},
  1899  				},
  1900  			},
  1901  			responseStatus: http.StatusOK,
  1902  			expectedRequestBody: `
  1903  			{
  1904  				"breakpoints": {
  1905  					"widths": [
  1906  						320,
  1907  						640,
  1908  						1024,
  1909  						2048,
  1910  						5000
  1911  					]
  1912  				},
  1913  				"output": {
  1914  					"perceptualQuality": "mediumHigh"
  1915  				},
  1916  				"transformations": [
  1917  					{
  1918  						"transformation": "Composite",
  1919  						"xPosition": 0,
  1920  						"yPosition": 0,
  1921  						"gravity": "NorthWest",
  1922  						"placement": "Over",
  1923  						"image": {
  1924  							"type": "Text",
  1925  							"fill": "#000000",
  1926  							"size": 72,
  1927  							"stroke": "#FFFFFF",
  1928  							"strokeSize": 0,
  1929  							"text": "Hello There",
  1930  							"transformation": {
  1931  								"transformation": "Compound"
  1932  							}
  1933  						}
  1934  					}
  1935  				]
  1936  			}`,
  1937  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1938  			expectedHeaders: map[string][]string{
  1939  				"Contract":   {"3-WNKXX1"},
  1940  				"Policy-Set": {"570f9090-5dbe-11ec-8a0a-71665789c1d8"},
  1941  			},
  1942  			responseBody: `
  1943  			{
  1944  				"operationPerformed": "UPDATED",
  1945  				"description": "Policy foo updated.",
  1946  				"id": "foo"
  1947  			}`,
  1948  			expectedResponse: &PolicyResponse{
  1949  				OperationPerformed: "UPDATED",
  1950  				Description:        "Policy foo updated.",
  1951  				ID:                 "foo",
  1952  			},
  1953  		},
  1954  		"200 OK - video": {
  1955  			params: UpsertPolicyRequest{
  1956  				Network:     PolicyNetworkStaging,
  1957  				ContractID:  "3-WNKXX1",
  1958  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1959  				PolicyID:    "foo",
  1960  				PolicyInput: &PolicyInputVideo{
  1961  					Output: &OutputVideo{
  1962  						PerceptualQuality: &OutputVideoPerceptualQualityVariableInline{
  1963  							Value: OutputVideoPerceptualQualityPtr(OutputVideoPerceptualQualityMediumHigh),
  1964  						},
  1965  					},
  1966  				},
  1967  			},
  1968  			responseStatus: http.StatusOK,
  1969  			expectedRequestBody: `
  1970  		       {
  1971  		           "output": {
  1972  		               "perceptualQuality": "mediumHigh"
  1973  		           }
  1974  		}`,
  1975  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  1976  			responseBody: `
  1977  			{
  1978  				"operationPerformed": "UPDATED",
  1979  				"description": "Policy foo updated.",
  1980  				"id": "foo"
  1981  			}`,
  1982  			expectedResponse: &PolicyResponse{
  1983  				OperationPerformed: "UPDATED",
  1984  				Description:        "Policy foo updated.",
  1985  				ID:                 "foo",
  1986  			},
  1987  		},
  1988  		"400 Bad request": {
  1989  			params: UpsertPolicyRequest{
  1990  				Network:     PolicyNetworkStaging,
  1991  				ContractID:  "3-WNKXX1",
  1992  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  1993  				PolicyID:    "foo",
  1994  				PolicyInput: &PolicyInputImage{},
  1995  			},
  1996  			responseStatus: http.StatusInternalServerError,
  1997  			responseBody: `{
  1998  "type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  1999  "title": "Bad Request",
  2000  "instance": "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2001  "status": 400,
  2002  "detail": "A contract must be specified using the Contract header.",
  2003  "problemId": "52a21f40-9861-4d35-95d0-a603c85cb2ad"
  2004  }`,
  2005  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  2006  			withError: &Error{
  2007  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  2008  				Title:     "Bad Request",
  2009  				Instance:  "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2010  				Status:    400,
  2011  				Detail:    "A contract must be specified using the Contract header.",
  2012  				ProblemID: "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2013  			},
  2014  		},
  2015  		"401 Not authorized": {
  2016  			params: UpsertPolicyRequest{
  2017  				Network:     PolicyNetworkStaging,
  2018  				ContractID:  "3-WNKXX1",
  2019  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2020  				PolicyID:    "foo",
  2021  				PolicyInput: &PolicyInputImage{},
  2022  			},
  2023  			responseStatus: http.StatusInternalServerError,
  2024  			responseBody: `{
  2025  "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2026  "title": "Not authorized",
  2027  "status": 401,
  2028  "detail": "Inactive client token",
  2029  "instance": "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2030  "method": "GET",
  2031  "serverIp": "104.81.220.242",
  2032  "clientIp": "22.22.22.22",
  2033  "requestId": "124cc33c",
  2034  "requestTime": "2022-01-12T16:53:44Z"
  2035  }`,
  2036  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  2037  			withError: &Error{
  2038  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2039  				Title:       "Not authorized",
  2040  				Status:      401,
  2041  				Detail:      "Inactive client token",
  2042  				Instance:    "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2043  				Method:      "GET",
  2044  				ServerIP:    "104.81.220.242",
  2045  				ClientIP:    "22.22.22.22",
  2046  				RequestID:   "124cc33c",
  2047  				RequestTime: "2022-01-12T16:53:44Z",
  2048  			},
  2049  		},
  2050  		"403 Forbidden": {
  2051  			params: UpsertPolicyRequest{
  2052  				Network:     PolicyNetworkStaging,
  2053  				ContractID:  "3-WNKXX1",
  2054  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2055  				PolicyID:    "foo",
  2056  				PolicyInput: &PolicyInputImage{},
  2057  			},
  2058  			responseStatus: http.StatusForbidden,
  2059  			responseBody: `{
  2060  				"type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2061  				"title": "Forbidden",
  2062  				"instance": "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2063  				"status": 403,
  2064  				"detail": "User does not have authorization to perform this action.",
  2065  				"problemId": "7d633d60-b120-4f28-a0de-ad86aeaf3c68"
  2066  			}`,
  2067  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  2068  			withError: &Error{
  2069  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2070  				Title:     "Forbidden",
  2071  				Instance:  "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2072  				Status:    403,
  2073  				Detail:    "User does not have authorization to perform this action.",
  2074  				ProblemID: "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2075  			},
  2076  		},
  2077  		// 500
  2078  		"invalid network": {
  2079  			params: UpsertPolicyRequest{
  2080  				ContractID:  "3-WNKXX1",
  2081  				Network:     "foo",
  2082  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2083  				PolicyID:    "foo",
  2084  			},
  2085  			withError: ErrStructValidation,
  2086  		},
  2087  		"missing contract": {
  2088  			params: UpsertPolicyRequest{
  2089  				Network:     PolicyNetworkProduction,
  2090  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2091  				PolicyID:    "foo",
  2092  			},
  2093  			withError: ErrStructValidation,
  2094  		},
  2095  		"missing policy id": {
  2096  			params: UpsertPolicyRequest{
  2097  				Network:     PolicyNetworkProduction,
  2098  				ContractID:  "3-WNKXX1",
  2099  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2100  			},
  2101  			withError: ErrStructValidation,
  2102  		},
  2103  		"missing policy set id": {
  2104  			params: UpsertPolicyRequest{
  2105  				Network:    PolicyNetworkProduction,
  2106  				PolicyID:   "foo",
  2107  				ContractID: "3-WNKXX1",
  2108  			},
  2109  			withError: ErrStructValidation,
  2110  		},
  2111  		"missing policy": {
  2112  			params: UpsertPolicyRequest{
  2113  				Network:     PolicyNetworkProduction,
  2114  				PolicyID:    "foo",
  2115  				ContractID:  "3-WNKXX1",
  2116  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2117  			},
  2118  			withError: ErrStructValidation,
  2119  		},
  2120  	}
  2121  
  2122  	for name, test := range tests {
  2123  		t.Run(name, func(t *testing.T) {
  2124  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  2125  				assert.Equal(t, test.expectedPath, r.URL.String())
  2126  				for h := range test.expectedHeaders {
  2127  					assert.Equal(t, test.expectedHeaders[h], r.Header[h])
  2128  				}
  2129  				assert.Equal(t, http.MethodPut, r.Method)
  2130  				w.WriteHeader(test.responseStatus)
  2131  				_, err := w.Write([]byte(test.responseBody))
  2132  				assert.NoError(t, err)
  2133  				if len(test.expectedRequestBody) > 0 {
  2134  					var prettyExpectedJSON map[string]interface{}
  2135  					err := json.Unmarshal([]byte(test.expectedRequestBody), &prettyExpectedJSON)
  2136  					require.NoError(t, err)
  2137  
  2138  					body, err := ioutil.ReadAll(r.Body)
  2139  					require.NoError(t, err)
  2140  
  2141  					var prettyActualJSON map[string]interface{}
  2142  					err = json.Unmarshal(body, &prettyActualJSON)
  2143  					require.NoError(t, err)
  2144  
  2145  					assert.Equal(t, prettyExpectedJSON, prettyActualJSON)
  2146  				}
  2147  			}))
  2148  			client := mockAPIClient(t, mockServer)
  2149  			result, err := client.UpsertPolicy(context.Background(), test.params)
  2150  			if test.withError != nil {
  2151  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  2152  				return
  2153  			}
  2154  			require.NoError(t, err)
  2155  			assert.Equal(t, test.expectedResponse, result)
  2156  		})
  2157  	}
  2158  }
  2159  
  2160  func TestDeletePolicy(t *testing.T) {
  2161  	tests := map[string]struct {
  2162  		params           DeletePolicyRequest
  2163  		responseStatus   int
  2164  		responseBody     string
  2165  		expectedPath     string
  2166  		expectedResponse *PolicyResponse
  2167  		expectedHeaders  map[string][]string
  2168  		withError        error
  2169  	}{
  2170  		"200 OK": {
  2171  			params: DeletePolicyRequest{
  2172  				Network:     PolicyNetworkStaging,
  2173  				ContractID:  "3-WNKXX1",
  2174  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2175  				PolicyID:    "foo",
  2176  			},
  2177  			responseStatus: http.StatusOK,
  2178  			expectedPath:   "/imaging/v2/network/staging/policies/foo",
  2179  			expectedHeaders: map[string][]string{
  2180  				"Contract":   {"3-WNKXX1"},
  2181  				"Policy-Set": {"570f9090-5dbe-11ec-8a0a-71665789c1d8"},
  2182  			},
  2183  			responseBody: `
  2184  			{
  2185  				"operationPerformed": "DELETED",
  2186  				"description": "Policy foo deleted.",
  2187  				"id": "foo"
  2188  			}`,
  2189  			expectedResponse: &PolicyResponse{
  2190  				OperationPerformed: "DELETED",
  2191  				Description:        "Policy foo deleted.",
  2192  				ID:                 "foo",
  2193  			},
  2194  		},
  2195  		"400 Bad request": {
  2196  			params: DeletePolicyRequest{
  2197  				Network:     PolicyNetworkStaging,
  2198  				ContractID:  "3-WNKXX1",
  2199  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2200  				PolicyID:    "foo",
  2201  			},
  2202  			responseStatus: http.StatusInternalServerError,
  2203  			responseBody: `{
  2204  "type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  2205  "title": "Bad Request",
  2206  "instance": "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2207  "status": 400,
  2208  "detail": "A contract must be specified using the Contract header.",
  2209  "problemId": "52a21f40-9861-4d35-95d0-a603c85cb2ad"
  2210  }`,
  2211  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  2212  			withError: &Error{
  2213  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  2214  				Title:     "Bad Request",
  2215  				Instance:  "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2216  				Status:    400,
  2217  				Detail:    "A contract must be specified using the Contract header.",
  2218  				ProblemID: "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2219  			},
  2220  		},
  2221  		"401 Not authorized": {
  2222  			params: DeletePolicyRequest{
  2223  				Network:     PolicyNetworkStaging,
  2224  				ContractID:  "3-WNKXX1",
  2225  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2226  				PolicyID:    "foo",
  2227  			},
  2228  			responseStatus: http.StatusInternalServerError,
  2229  			responseBody: `{
  2230  "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2231  "title": "Not authorized",
  2232  "status": 401,
  2233  "detail": "Inactive client token",
  2234  "instance": "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2235  "method": "GET",
  2236  "serverIp": "104.81.220.242",
  2237  "clientIp": "22.22.22.22",
  2238  "requestId": "124cc33c",
  2239  "requestTime": "2022-01-12T16:53:44Z"
  2240  }`,
  2241  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  2242  			withError: &Error{
  2243  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2244  				Title:       "Not authorized",
  2245  				Status:      401,
  2246  				Detail:      "Inactive client token",
  2247  				Instance:    "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2248  				Method:      "GET",
  2249  				ServerIP:    "104.81.220.242",
  2250  				ClientIP:    "22.22.22.22",
  2251  				RequestID:   "124cc33c",
  2252  				RequestTime: "2022-01-12T16:53:44Z",
  2253  			},
  2254  		},
  2255  		"403 Forbidden": {
  2256  			params: DeletePolicyRequest{
  2257  				Network:     PolicyNetworkStaging,
  2258  				ContractID:  "3-WNKXX1",
  2259  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2260  				PolicyID:    "foo",
  2261  			},
  2262  			responseStatus: http.StatusForbidden,
  2263  			responseBody: `{
  2264  				"type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2265  				"title": "Forbidden",
  2266  				"instance": "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2267  				"status": 403,
  2268  				"detail": "User does not have authorization to perform this action.",
  2269  				"problemId": "7d633d60-b120-4f28-a0de-ad86aeaf3c68"
  2270  			}`,
  2271  			expectedPath: "/imaging/v2/network/staging/policies/foo",
  2272  			withError: &Error{
  2273  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2274  				Title:     "Forbidden",
  2275  				Instance:  "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2276  				Status:    403,
  2277  				Detail:    "User does not have authorization to perform this action.",
  2278  				ProblemID: "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2279  			},
  2280  		},
  2281  		// 500
  2282  		"invalid network": {
  2283  			params: DeletePolicyRequest{
  2284  				ContractID:  "3-WNKXX1",
  2285  				Network:     "foo",
  2286  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2287  				PolicyID:    "foo",
  2288  			},
  2289  			withError: ErrStructValidation,
  2290  		},
  2291  		"missing contract": {
  2292  			params: DeletePolicyRequest{
  2293  				Network:     PolicyNetworkProduction,
  2294  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2295  				PolicyID:    "foo",
  2296  			},
  2297  			withError: ErrStructValidation,
  2298  		},
  2299  		"missing policy id": {
  2300  			params: DeletePolicyRequest{
  2301  				Network:     PolicyNetworkProduction,
  2302  				ContractID:  "3-WNKXX1",
  2303  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2304  			},
  2305  			withError: ErrStructValidation,
  2306  		},
  2307  		"missing policy set id": {
  2308  			params: DeletePolicyRequest{
  2309  				Network:    PolicyNetworkProduction,
  2310  				PolicyID:   "foo",
  2311  				ContractID: "3-WNKXX1",
  2312  			},
  2313  			withError: ErrStructValidation,
  2314  		},
  2315  	}
  2316  
  2317  	for name, test := range tests {
  2318  		t.Run(name, func(t *testing.T) {
  2319  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  2320  				assert.Equal(t, test.expectedPath, r.URL.String())
  2321  				for h := range test.expectedHeaders {
  2322  					assert.Equal(t, test.expectedHeaders[h], r.Header[h])
  2323  				}
  2324  				assert.Equal(t, http.MethodDelete, r.Method)
  2325  				w.WriteHeader(test.responseStatus)
  2326  				_, err := w.Write([]byte(test.responseBody))
  2327  				assert.NoError(t, err)
  2328  			}))
  2329  			client := mockAPIClient(t, mockServer)
  2330  			result, err := client.DeletePolicy(context.Background(), test.params)
  2331  			if test.withError != nil {
  2332  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  2333  				return
  2334  			}
  2335  			require.NoError(t, err)
  2336  			assert.Equal(t, test.expectedResponse, result)
  2337  		})
  2338  	}
  2339  }
  2340  
  2341  func TestGetPolicyHistory(t *testing.T) {
  2342  	tests := map[string]struct {
  2343  		params           GetPolicyHistoryRequest
  2344  		responseStatus   int
  2345  		responseBody     string
  2346  		expectedPath     string
  2347  		expectedResponse *GetPolicyHistoryResponse
  2348  		expectedHeaders  map[string][]string
  2349  		withError        error
  2350  	}{
  2351  		"200 OK": {
  2352  			params: GetPolicyHistoryRequest{
  2353  				Network:     PolicyNetworkStaging,
  2354  				ContractID:  "3-WNKXX1",
  2355  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2356  				PolicyID:    "foo",
  2357  			},
  2358  			responseStatus: http.StatusOK,
  2359  			responseBody: `
  2360  {
  2361      "itemKind": "POLICIESLOG",
  2362      "items": [
  2363          {
  2364              "id": "foo",
  2365              "dateCreated": "2021-12-07 16:20:34+0000",
  2366              "action": "UPSERT",
  2367              "user": "jsmith",
  2368              "version": 2,
  2369              "policy": "{\"breakpoints\":{\"widths\":[320,640,1024,2048,5000]},\"output\":{\"perceptualQuality\":\"mediumHigh\"},\"transformations\":[{\"transformation\":\"Composite\",\"xPosition\":0,\"yPosition\":0,\"gravity\":\"NorthWest\",\"placement\":\"Over\",\"image\":{\"type\":\"Text\",\"fill\":\"#000000\",\"size\":72,\"stroke\":\"#FFFFFF\",\"strokeSize\":0,\"text\":\"Hello There\",\"transformation\":{\"transformation\":\"Compound\",\"transformations\":[]}}}],\"video\":false}"
  2370          },
  2371          {
  2372              "id": "asd",
  2373              "dateCreated": "2021-12-07 16:18:39+0000",
  2374              "action": "UPSERT",
  2375              "user": "asmith",
  2376              "version": 1,
  2377              "policy": "{\"breakpoints\":{\"widths\":[320,640,1024,2048,5000]},\"output\":{\"perceptualQuality\":\"mediumHigh\"},\"transformations\":[{\"transformation\":\"Composite\",\"xPosition\":0,\"yPosition\":0,\"gravity\":\"NorthWest\",\"placement\":\"Over\",\"image\":{\"type\":\"Text\",\"fill\":\"#000000\",\"size\":72,\"stroke\":\"#FFFFFF\",\"strokeSize\":0,\"text\":\"Hello\",\"transformation\":{\"transformation\":\"Compound\",\"transformations\":[]}}}],\"video\":false}"
  2378          }
  2379      ],
  2380      "totalItems": 2
  2381  		}`,
  2382  			expectedPath: "/imaging/v2/network/staging/policies/history/foo",
  2383  			expectedResponse: &GetPolicyHistoryResponse{
  2384  				ItemKind: "POLICIESLOG",
  2385  				Items: []PolicyHistoryItem{{
  2386  					ID:          "foo",
  2387  					DateCreated: "2021-12-07 16:20:34+0000",
  2388  					Action:      "UPSERT",
  2389  					User:        "jsmith",
  2390  					Version:     2,
  2391  					Policy:      "{\"breakpoints\":{\"widths\":[320,640,1024,2048,5000]},\"output\":{\"perceptualQuality\":\"mediumHigh\"},\"transformations\":[{\"transformation\":\"Composite\",\"xPosition\":0,\"yPosition\":0,\"gravity\":\"NorthWest\",\"placement\":\"Over\",\"image\":{\"type\":\"Text\",\"fill\":\"#000000\",\"size\":72,\"stroke\":\"#FFFFFF\",\"strokeSize\":0,\"text\":\"Hello There\",\"transformation\":{\"transformation\":\"Compound\",\"transformations\":[]}}}],\"video\":false}",
  2392  				},
  2393  					{
  2394  						ID:          "asd",
  2395  						DateCreated: "2021-12-07 16:18:39+0000",
  2396  						Action:      "UPSERT",
  2397  						User:        "asmith",
  2398  						Version:     1,
  2399  						Policy:      "{\"breakpoints\":{\"widths\":[320,640,1024,2048,5000]},\"output\":{\"perceptualQuality\":\"mediumHigh\"},\"transformations\":[{\"transformation\":\"Composite\",\"xPosition\":0,\"yPosition\":0,\"gravity\":\"NorthWest\",\"placement\":\"Over\",\"image\":{\"type\":\"Text\",\"fill\":\"#000000\",\"size\":72,\"stroke\":\"#FFFFFF\",\"strokeSize\":0,\"text\":\"Hello\",\"transformation\":{\"transformation\":\"Compound\",\"transformations\":[]}}}],\"video\":false}",
  2400  					},
  2401  				},
  2402  				TotalItems: 2,
  2403  			},
  2404  		},
  2405  		"400 Bad request": {
  2406  			params: GetPolicyHistoryRequest{
  2407  				Network:     PolicyNetworkStaging,
  2408  				ContractID:  "3-WNKXX1",
  2409  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2410  				PolicyID:    "foo",
  2411  			},
  2412  			responseStatus: http.StatusInternalServerError,
  2413  			responseBody: `{
  2414  "type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  2415  "title": "Bad Request",
  2416  "instance": "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2417  "status": 400,
  2418  "detail": "A contract must be specified using the Contract header.",
  2419  "problemId": "52a21f40-9861-4d35-95d0-a603c85cb2ad"
  2420  }`,
  2421  			expectedPath: "/imaging/v2/network/staging/policies/history/foo",
  2422  			withError: &Error{
  2423  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  2424  				Title:     "Bad Request",
  2425  				Instance:  "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2426  				Status:    400,
  2427  				Detail:    "A contract must be specified using the Contract header.",
  2428  				ProblemID: "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2429  			},
  2430  		},
  2431  		"401 Not authorized": {
  2432  			params: GetPolicyHistoryRequest{
  2433  				Network:     PolicyNetworkStaging,
  2434  				ContractID:  "3-WNKXX1",
  2435  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2436  				PolicyID:    "foo",
  2437  			},
  2438  			responseStatus: http.StatusInternalServerError,
  2439  			responseBody: `{
  2440  "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2441  "title": "Not authorized",
  2442  "status": 401,
  2443  "detail": "Inactive client token",
  2444  "instance": "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2445  "method": "GET",
  2446  "serverIp": "104.81.220.242",
  2447  "clientIp": "22.22.22.22",
  2448  "requestId": "124cc33c",
  2449  "requestTime": "2022-01-12T16:53:44Z"
  2450  }`,
  2451  			expectedPath: "/imaging/v2/network/staging/policies/history/foo",
  2452  			withError: &Error{
  2453  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2454  				Title:       "Not authorized",
  2455  				Status:      401,
  2456  				Detail:      "Inactive client token",
  2457  				Instance:    "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2458  				Method:      "GET",
  2459  				ServerIP:    "104.81.220.242",
  2460  				ClientIP:    "22.22.22.22",
  2461  				RequestID:   "124cc33c",
  2462  				RequestTime: "2022-01-12T16:53:44Z",
  2463  			},
  2464  		},
  2465  		"403 Forbidden": {
  2466  			params: GetPolicyHistoryRequest{
  2467  				Network:     PolicyNetworkStaging,
  2468  				ContractID:  "3-WNKXX1",
  2469  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2470  				PolicyID:    "foo",
  2471  			},
  2472  			responseStatus: http.StatusForbidden,
  2473  			responseBody: `{
  2474  				"type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2475  				"title": "Forbidden",
  2476  				"instance": "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2477  				"status": 403,
  2478  				"detail": "User does not have authorization to perform this action.",
  2479  				"problemId": "7d633d60-b120-4f28-a0de-ad86aeaf3c68"
  2480  			}`,
  2481  			expectedPath: "/imaging/v2/network/staging/policies/history/foo",
  2482  			withError: &Error{
  2483  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2484  				Title:     "Forbidden",
  2485  				Instance:  "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2486  				Status:    403,
  2487  				Detail:    "User does not have authorization to perform this action.",
  2488  				ProblemID: "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2489  			},
  2490  		},
  2491  		// 500
  2492  		"invalid network": {
  2493  			params: GetPolicyHistoryRequest{
  2494  				ContractID:  "3-WNKXX1",
  2495  				Network:     "foo",
  2496  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2497  				PolicyID:    "foo",
  2498  			},
  2499  			withError: ErrStructValidation,
  2500  		},
  2501  		"missing contract": {
  2502  			params: GetPolicyHistoryRequest{
  2503  				Network:     PolicyNetworkProduction,
  2504  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2505  				PolicyID:    "foo",
  2506  			},
  2507  			withError: ErrStructValidation,
  2508  		},
  2509  		"missing policy id": {
  2510  			params: GetPolicyHistoryRequest{
  2511  				Network:     PolicyNetworkProduction,
  2512  				ContractID:  "3-WNKXX1",
  2513  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2514  			},
  2515  			withError: ErrStructValidation,
  2516  		},
  2517  		"missing policy set id": {
  2518  			params: GetPolicyHistoryRequest{
  2519  				Network:    PolicyNetworkProduction,
  2520  				PolicyID:   "foo",
  2521  				ContractID: "3-WNKXX1",
  2522  			},
  2523  			withError: ErrStructValidation,
  2524  		},
  2525  	}
  2526  
  2527  	for name, test := range tests {
  2528  		t.Run(name, func(t *testing.T) {
  2529  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  2530  				assert.Equal(t, test.expectedPath, r.URL.String())
  2531  				for h := range test.expectedHeaders {
  2532  					assert.Equal(t, test.expectedHeaders[h], r.Header[h])
  2533  				}
  2534  				assert.Equal(t, http.MethodGet, r.Method)
  2535  				w.WriteHeader(test.responseStatus)
  2536  				_, err := w.Write([]byte(test.responseBody))
  2537  				assert.NoError(t, err)
  2538  			}))
  2539  			client := mockAPIClient(t, mockServer)
  2540  			result, err := client.GetPolicyHistory(context.Background(), test.params)
  2541  			if test.withError != nil {
  2542  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  2543  				return
  2544  			}
  2545  			require.NoError(t, err)
  2546  			assert.Equal(t, test.expectedResponse, result)
  2547  		})
  2548  	}
  2549  }
  2550  
  2551  func TestRollbackPolicy(t *testing.T) {
  2552  	tests := map[string]struct {
  2553  		params           RollbackPolicyRequest
  2554  		responseStatus   int
  2555  		responseBody     string
  2556  		expectedPath     string
  2557  		expectedResponse *PolicyResponse
  2558  		expectedHeaders  map[string][]string
  2559  		withError        error
  2560  	}{
  2561  		"200 OK": {
  2562  			params: RollbackPolicyRequest{
  2563  				Network:     PolicyNetworkStaging,
  2564  				ContractID:  "3-WNKXX1",
  2565  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2566  				PolicyID:    "foo",
  2567  			},
  2568  			responseStatus: http.StatusOK,
  2569  			expectedPath:   "/imaging/v2/network/staging/policies/rollback/foo",
  2570  			expectedHeaders: map[string][]string{
  2571  				"Contract":   {"3-WNKXX1"},
  2572  				"Policy-Set": {"570f9090-5dbe-11ec-8a0a-71665789c1d8"},
  2573  			},
  2574  			responseBody: `
  2575  			{
  2576  				"operationPerformed": "UPDATED",
  2577  				"description": "Policy foo has been rolled back to version 3.",
  2578  				"id": "foo"
  2579  			}`,
  2580  			expectedResponse: &PolicyResponse{
  2581  				OperationPerformed: "UPDATED",
  2582  				Description:        "Policy foo has been rolled back to version 3.",
  2583  				ID:                 "foo",
  2584  			},
  2585  		},
  2586  		"400 Bad request": {
  2587  			params: RollbackPolicyRequest{
  2588  				Network:     PolicyNetworkStaging,
  2589  				ContractID:  "3-WNKXX1",
  2590  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2591  				PolicyID:    "foo",
  2592  			},
  2593  			responseStatus: http.StatusInternalServerError,
  2594  			responseBody: `{
  2595  "type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  2596  "title": "Bad Request",
  2597  "instance": "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2598  "status": 400,
  2599  "detail": "A contract must be specified using the Contract header.",
  2600  "problemId": "52a21f40-9861-4d35-95d0-a603c85cb2ad"
  2601  }`,
  2602  			expectedPath: "/imaging/v2/network/staging/policies/rollback/foo",
  2603  			withError: &Error{
  2604  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1004",
  2605  				Title:     "Bad Request",
  2606  				Instance:  "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2607  				Status:    400,
  2608  				Detail:    "A contract must be specified using the Contract header.",
  2609  				ProblemID: "52a21f40-9861-4d35-95d0-a603c85cb2ad",
  2610  			},
  2611  		},
  2612  		"401 Not authorized": {
  2613  			params: RollbackPolicyRequest{
  2614  				Network:     PolicyNetworkStaging,
  2615  				ContractID:  "3-WNKXX1",
  2616  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2617  				PolicyID:    "foo",
  2618  			},
  2619  			responseStatus: http.StatusInternalServerError,
  2620  			responseBody: `{
  2621  "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2622  "title": "Not authorized",
  2623  "status": 401,
  2624  "detail": "Inactive client token",
  2625  "instance": "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2626  "method": "GET",
  2627  "serverIp": "104.81.220.242",
  2628  "clientIp": "22.22.22.22",
  2629  "requestId": "124cc33c",
  2630  "requestTime": "2022-01-12T16:53:44Z"
  2631  }`,
  2632  			expectedPath: "/imaging/v2/network/staging/policies/rollback/foo",
  2633  			withError: &Error{
  2634  				Type:        "https://problems.luna-dev.akamaiapis.net/-/pep-authn/deny",
  2635  				Title:       "Not authorized",
  2636  				Status:      401,
  2637  				Detail:      "Inactive client token",
  2638  				Instance:    "https://akaa-mgfkwp3rw4k2whym-eyn4wdjeur5lz37c.luna-dev.akamaiapis.net/imaging/v2/network/staging/policysets/",
  2639  				Method:      "GET",
  2640  				ServerIP:    "104.81.220.242",
  2641  				ClientIP:    "22.22.22.22",
  2642  				RequestID:   "124cc33c",
  2643  				RequestTime: "2022-01-12T16:53:44Z",
  2644  			},
  2645  		},
  2646  		"403 Forbidden": {
  2647  			params: RollbackPolicyRequest{
  2648  				Network:     PolicyNetworkStaging,
  2649  				ContractID:  "3-WNKXX1",
  2650  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2651  				PolicyID:    "foo",
  2652  			},
  2653  			responseStatus: http.StatusForbidden,
  2654  			responseBody: `{
  2655  				"type": "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2656  				"title": "Forbidden",
  2657  				"instance": "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2658  				"status": 403,
  2659  				"detail": "User does not have authorization to perform this action.",
  2660  				"problemId": "7d633d60-b120-4f28-a0de-ad86aeaf3c68"
  2661  			}`,
  2662  			expectedPath: "/imaging/v2/network/staging/policies/rollback/foo",
  2663  			withError: &Error{
  2664  				Type:      "https://problems.luna.akamaiapis.net/image-policy-manager/IVM_1002",
  2665  				Title:     "Forbidden",
  2666  				Instance:  "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2667  				Status:    403,
  2668  				Detail:    "User does not have authorization to perform this action.",
  2669  				ProblemID: "7d633d60-b120-4f28-a0de-ad86aeaf3c68",
  2670  			},
  2671  		},
  2672  		// 500
  2673  		"invalid network": {
  2674  			params: RollbackPolicyRequest{
  2675  				ContractID:  "3-WNKXX1",
  2676  				Network:     "foo",
  2677  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2678  				PolicyID:    "foo",
  2679  			},
  2680  			withError: ErrStructValidation,
  2681  		},
  2682  		"missing contract": {
  2683  			params: RollbackPolicyRequest{
  2684  				Network:     PolicyNetworkProduction,
  2685  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2686  				PolicyID:    "foo",
  2687  			},
  2688  			withError: ErrStructValidation,
  2689  		},
  2690  		"missing policy id": {
  2691  			params: RollbackPolicyRequest{
  2692  				Network:     PolicyNetworkProduction,
  2693  				ContractID:  "3-WNKXX1",
  2694  				PolicySetID: "570f9090-5dbe-11ec-8a0a-71665789c1d8",
  2695  			},
  2696  			withError: ErrStructValidation,
  2697  		},
  2698  		"missing policy set id": {
  2699  			params: RollbackPolicyRequest{
  2700  				Network:    PolicyNetworkProduction,
  2701  				PolicyID:   "foo",
  2702  				ContractID: "3-WNKXX1",
  2703  			},
  2704  			withError: ErrStructValidation,
  2705  		},
  2706  	}
  2707  
  2708  	for name, test := range tests {
  2709  		t.Run(name, func(t *testing.T) {
  2710  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  2711  				assert.Equal(t, test.expectedPath, r.URL.String())
  2712  				for h := range test.expectedHeaders {
  2713  					assert.Equal(t, test.expectedHeaders[h], r.Header[h])
  2714  				}
  2715  				assert.Equal(t, http.MethodPut, r.Method)
  2716  				w.WriteHeader(test.responseStatus)
  2717  				_, err := w.Write([]byte(test.responseBody))
  2718  				assert.NoError(t, err)
  2719  			}))
  2720  			client := mockAPIClient(t, mockServer)
  2721  			result, err := client.RollbackPolicy(context.Background(), test.params)
  2722  			if test.withError != nil {
  2723  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  2724  				return
  2725  			}
  2726  			require.NoError(t, err)
  2727  			assert.Equal(t, test.expectedResponse, result)
  2728  		})
  2729  	}
  2730  }