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

     1  package papi
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestPapi_CreateActivation(t *testing.T) {
    15  	tests := map[string]struct {
    16  		request          CreateActivationRequest
    17  		responseStatus   int
    18  		responseBody     string
    19  		expectedPath     string
    20  		expectedResponse *CreateActivationResponse
    21  		withError        error
    22  		assertError      func(*testing.T, error)
    23  	}{
    24  		"200 OK": {
    25  			request: CreateActivationRequest{
    26  				PropertyID: "prp_175780",
    27  				ContractID: "ctr_1-1TJZFW",
    28  				GroupID:    "grp_15166",
    29  				Activation: Activation{
    30  					PropertyVersion: 1,
    31  					Network:         ActivationNetworkStaging,
    32  					UseFastFallback: false,
    33  					NotifyEmails: []string{
    34  						"you@example.com",
    35  						"them@example.com",
    36  					},
    37  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
    38  				},
    39  			},
    40  			responseStatus: http.StatusCreated,
    41  			responseBody: `
    42  {
    43  	"activationLink": "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225"
    44  }`,
    45  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
    46  			expectedResponse: &CreateActivationResponse{
    47  				ActivationID:   "atv_67037",
    48  				ActivationLink: "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225",
    49  			},
    50  		},
    51  		"200 Activate property with ComplianceRecord None": {
    52  			request: CreateActivationRequest{
    53  				PropertyID: "prp_175780",
    54  				ContractID: "ctr_1-1TJZFW",
    55  				GroupID:    "grp_15166",
    56  				Activation: Activation{
    57  					PropertyVersion: 1,
    58  					Network:         ActivationNetworkStaging,
    59  					UseFastFallback: false,
    60  					ComplianceRecord: &ComplianceRecordNone{
    61  						CustomerEmail:  "sb@akamai.com",
    62  						PeerReviewedBy: "sb@akamai.com",
    63  						UnitTested:     true,
    64  						TicketID:       "123",
    65  					},
    66  					NotifyEmails: []string{
    67  						"you@example.com",
    68  						"them@example.com",
    69  					},
    70  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
    71  				},
    72  			},
    73  			responseStatus: http.StatusCreated,
    74  			responseBody: `
    75  {
    76  	"activationLink": "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225"
    77  }`,
    78  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
    79  			expectedResponse: &CreateActivationResponse{
    80  				ActivationID:   "atv_67037",
    81  				ActivationLink: "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225",
    82  			},
    83  		},
    84  		"200 Activate property with ComplianceRecord Other": {
    85  			request: CreateActivationRequest{
    86  				PropertyID: "prp_175780",
    87  				ContractID: "ctr_1-1TJZFW",
    88  				GroupID:    "grp_15166",
    89  				Activation: Activation{
    90  					PropertyVersion: 1,
    91  					Network:         ActivationNetworkStaging,
    92  					UseFastFallback: false,
    93  					ComplianceRecord: &ComplianceRecordOther{
    94  						OtherNoncomplianceReason: "some other reason",
    95  						TicketID:                 "123",
    96  					},
    97  					NotifyEmails: []string{
    98  						"you@example.com",
    99  						"them@example.com",
   100  					},
   101  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   102  				},
   103  			},
   104  			responseStatus: http.StatusCreated,
   105  			responseBody: `
   106  {
   107  	"activationLink": "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225"
   108  }`,
   109  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   110  			expectedResponse: &CreateActivationResponse{
   111  				ActivationID:   "atv_67037",
   112  				ActivationLink: "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225",
   113  			},
   114  		},
   115  		"200 Activate property with ComplianceRecord No_Production_Traffic": {
   116  			request: CreateActivationRequest{
   117  				PropertyID: "prp_175780",
   118  				ContractID: "ctr_1-1TJZFW",
   119  				GroupID:    "grp_15166",
   120  				Activation: Activation{
   121  					PropertyVersion: 1,
   122  					Network:         ActivationNetworkStaging,
   123  					UseFastFallback: false,
   124  					ComplianceRecord: &ComplianceRecordNoProductionTraffic{
   125  						TicketID: "123",
   126  					},
   127  					NotifyEmails: []string{
   128  						"you@example.com",
   129  						"them@example.com",
   130  					},
   131  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   132  				},
   133  			},
   134  			responseStatus: http.StatusCreated,
   135  			responseBody: `
   136  {
   137  	"activationLink": "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225"
   138  }`,
   139  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   140  			expectedResponse: &CreateActivationResponse{
   141  				ActivationID:   "atv_67037",
   142  				ActivationLink: "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225",
   143  			},
   144  		},
   145  		"200 Activate property with ComplianceRecord Emergency": {
   146  			request: CreateActivationRequest{
   147  				PropertyID: "prp_175780",
   148  				ContractID: "ctr_1-1TJZFW",
   149  				GroupID:    "grp_15166",
   150  				Activation: Activation{
   151  					PropertyVersion: 1,
   152  					Network:         ActivationNetworkStaging,
   153  					UseFastFallback: false,
   154  					ComplianceRecord: &ComplianceRecordEmergency{
   155  						TicketID: "123",
   156  					},
   157  					NotifyEmails: []string{
   158  						"you@example.com",
   159  						"them@example.com",
   160  					},
   161  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   162  				},
   163  			},
   164  			responseStatus: http.StatusCreated,
   165  			responseBody: `
   166  {
   167  	"activationLink": "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225"
   168  }`,
   169  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   170  			expectedResponse: &CreateActivationResponse{
   171  				ActivationID:   "atv_67037",
   172  				ActivationLink: "/papi/v1/properties/prp_173136/activations/atv_67037?contractId=ctr_1-1TJZFB&groupId=grp_15225",
   173  			},
   174  		},
   175  		"500 internal server error": {
   176  			request: CreateActivationRequest{
   177  				PropertyID: "prp_175780",
   178  				ContractID: "ctr_1-1TJZFW",
   179  				GroupID:    "grp_15166",
   180  				Activation: Activation{
   181  					PropertyVersion: 1,
   182  					Network:         ActivationNetworkStaging,
   183  					UseFastFallback: false,
   184  					NotifyEmails: []string{
   185  						"you@example.com",
   186  						"them@example.com",
   187  					},
   188  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   189  				},
   190  			},
   191  			responseStatus: http.StatusInternalServerError,
   192  			responseBody: `
   193  {
   194  	"type": "internal_error",
   195      "title": "Internal Server Error",
   196      "detail": "Error creating activation",
   197      "status": 500
   198  }`,
   199  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   200  			withError: &Error{
   201  				Type:       "internal_error",
   202  				Title:      "Internal Server Error",
   203  				Detail:     "Error creating activation",
   204  				StatusCode: http.StatusInternalServerError,
   205  			},
   206  		},
   207  		"validation error - missing property ID": {
   208  			request: CreateActivationRequest{
   209  				ContractID: "ctr_1-1TJZFW",
   210  				GroupID:    "grp_15166",
   211  				Activation: Activation{
   212  					PropertyVersion: 1,
   213  					Network:         ActivationNetworkStaging,
   214  					UseFastFallback: false,
   215  					NotifyEmails: []string{
   216  						"you@example.com",
   217  						"them@example.com",
   218  					},
   219  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   220  				},
   221  			},
   222  			withError: ErrStructValidation,
   223  		},
   224  		"validation error - not valid ComplianceRecordNone": {
   225  			request: CreateActivationRequest{
   226  				ContractID: "ctr_1-1TJZFW",
   227  				GroupID:    "grp_15166",
   228  				Activation: Activation{
   229  					PropertyVersion: 1,
   230  					Network:         ActivationNetworkStaging,
   231  					UseFastFallback: false,
   232  					ComplianceRecord: &ComplianceRecordNone{
   233  						UnitTested: true,
   234  						TicketID:   "123",
   235  					},
   236  					NotifyEmails: []string{
   237  						"you@example.com",
   238  						"them@example.com",
   239  					},
   240  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   241  				},
   242  			},
   243  			withError: ErrStructValidation,
   244  			assertError: func(t *testing.T, err error) {
   245  				assert.Contains(t, err.Error(), "CustomerEmail: cannot be blank")
   246  				assert.Contains(t, err.Error(), "PeerReviewedBy: cannot be blank")
   247  			},
   248  		},
   249  		"validation error - not valid UnitTested field for PRODUCTION activation network and ComplianceRecordNone": {
   250  			request: CreateActivationRequest{
   251  				ContractID: "ctr_1-1TJZFW",
   252  				GroupID:    "grp_15166",
   253  				Activation: Activation{
   254  					PropertyVersion: 1,
   255  					Network:         ActivationNetworkProduction,
   256  					UseFastFallback: false,
   257  					ComplianceRecord: &ComplianceRecordNone{
   258  						CustomerEmail:  "sb@akamai.com",
   259  						PeerReviewedBy: "sb@akamai.com",
   260  						UnitTested:     false,
   261  						TicketID:       "123",
   262  					},
   263  					NotifyEmails: []string{
   264  						"you@example.com",
   265  						"them@example.com",
   266  					},
   267  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   268  				},
   269  			},
   270  			withError: ErrStructValidation,
   271  			assertError: func(t *testing.T, err error) {
   272  				assert.Contains(t, err.Error(), "for PRODUCTION activation network and nonComplianceRecord, UnitTested value has to be set to true, otherwise API will not work correctly")
   273  			},
   274  		},
   275  		"validation error - not valid ComplianceRecordOther": {
   276  			request: CreateActivationRequest{
   277  				ContractID: "ctr_1-1TJZFW",
   278  				GroupID:    "grp_15166",
   279  				Activation: Activation{
   280  					PropertyVersion:  1,
   281  					Network:          ActivationNetworkProduction,
   282  					UseFastFallback:  false,
   283  					ComplianceRecord: &ComplianceRecordOther{},
   284  					NotifyEmails: []string{
   285  						"you@example.com",
   286  						"them@example.com",
   287  					},
   288  					AcknowledgeWarnings: []string{"msg_baa4560881774a45b5fd25f5b1eab021d7c40b4f"},
   289  				},
   290  			},
   291  			withError: ErrStructValidation,
   292  			assertError: func(t *testing.T, err error) {
   293  				assert.Contains(t, err.Error(), "OtherNoncomplianceReason: cannot be blank")
   294  			},
   295  		},
   296  	}
   297  
   298  	for name, test := range tests {
   299  		t.Run(name, func(t *testing.T) {
   300  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   301  				assert.Equal(t, test.expectedPath, r.URL.String())
   302  				assert.Equal(t, http.MethodPost, r.Method)
   303  				w.WriteHeader(test.responseStatus)
   304  				_, err := w.Write([]byte(test.responseBody))
   305  				assert.NoError(t, err)
   306  			}))
   307  			client := mockAPIClient(t, mockServer)
   308  			result, err := client.CreateActivation(context.Background(), test.request)
   309  			if test.withError != nil || test.assertError != nil {
   310  				if test.withError != nil {
   311  					assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   312  				}
   313  				if test.assertError != nil {
   314  					test.assertError(t, err)
   315  				}
   316  				return
   317  			}
   318  			require.NoError(t, err)
   319  			assert.Equal(t, test.expectedResponse, result)
   320  		})
   321  	}
   322  }
   323  
   324  func TestPapi_GetActivations(t *testing.T) {
   325  	tests := map[string]struct {
   326  		request          GetActivationsRequest
   327  		responseStatus   int
   328  		responseBody     string
   329  		expectedPath     string
   330  		expectedResponse *GetActivationsResponse
   331  		withError        error
   332  	}{
   333  		"200 OK": {
   334  			request: GetActivationsRequest{
   335  				PropertyID: "prp_175780",
   336  				ContractID: "ctr_1-1TJZFW",
   337  				GroupID:    "grp_15166",
   338  			},
   339  			responseStatus: http.StatusOK,
   340  			responseBody: `
   341  {
   342  	"accountId": "act_1-1TJZFB",
   343  	"contractId": "ctr_1-1TJZFW",
   344  	"groupId": "grp_15166",
   345  	"activations": {
   346  		"items": [
   347  			{
   348  				"activationId": "atv_1696985",
   349  				"propertyName": "example.com",
   350  				"propertyId": "prp_173136",
   351  				"propertyVersion": 1,
   352  				"network": "STAGING",
   353  				"activationType": "ACTIVATE",
   354  				"status": "PENDING",
   355  				"submitDate": "2014-03-02T02:22:12Z",
   356  				"updateDate": "2014-03-01T21:12:57Z",
   357  				"note": "Sample activation",
   358  				"fmaActivationState": "steady",
   359  				"notifyEmails": [
   360  					"you@example.com",
   361  					"them@example.com"
   362  				],
   363  				"fallbackInfo": {
   364  					"fastFallbackAttempted": false,
   365  					"fallbackVersion": 10,
   366  					"canFastFallback": true,
   367  					"steadyStateTime": 1506448172,
   368  					"fastFallbackExpirationTime": 1506451772,
   369  					"fastFallbackRecoveryState": null
   370  				}
   371  			}
   372  		]
   373  	}
   374  }`,
   375  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   376  			expectedResponse: &GetActivationsResponse{
   377  				Response: Response{
   378  					AccountID:  "act_1-1TJZFB",
   379  					ContractID: "ctr_1-1TJZFW",
   380  					GroupID:    "grp_15166",
   381  				},
   382  				Activations: ActivationsItems{Items: []*Activation{{
   383  					ActivationID:       "atv_1696985",
   384  					PropertyName:       "example.com",
   385  					PropertyID:         "prp_173136",
   386  					PropertyVersion:    1,
   387  					Network:            ActivationNetworkStaging,
   388  					ActivationType:     ActivationTypeActivate,
   389  					Status:             ActivationStatusPending,
   390  					SubmitDate:         "2014-03-02T02:22:12Z",
   391  					UpdateDate:         "2014-03-01T21:12:57Z",
   392  					Note:               "Sample activation",
   393  					FMAActivationState: "steady",
   394  					NotifyEmails: []string{
   395  						"you@example.com",
   396  						"them@example.com",
   397  					},
   398  					FallbackInfo: &ActivationFallbackInfo{
   399  						FastFallbackAttempted:      false,
   400  						FallbackVersion:            10,
   401  						CanFastFallback:            true,
   402  						SteadyStateTime:            1506448172,
   403  						FastFallbackExpirationTime: 1506451772,
   404  						FastFallbackRecoveryState:  nil,
   405  					},
   406  				}},
   407  				},
   408  			},
   409  		},
   410  		"500 internal server error": {
   411  			request: GetActivationsRequest{
   412  				PropertyID: "prp_175780",
   413  				ContractID: "ctr_1-1TJZFW",
   414  				GroupID:    "grp_15166",
   415  			},
   416  			responseStatus: http.StatusInternalServerError,
   417  			responseBody: `
   418  {
   419  	"type": "internal_error",
   420      "title": "Internal Server Error",
   421      "detail": "Error fetching activation",
   422      "status": 500
   423  }`,
   424  			expectedPath: "/papi/v1/properties/prp_175780/activations?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   425  			withError: &Error{
   426  				Type:       "internal_error",
   427  				Title:      "Internal Server Error",
   428  				Detail:     "Error fetching activation",
   429  				StatusCode: http.StatusInternalServerError,
   430  			},
   431  		},
   432  		"validation error": {
   433  			request: GetActivationsRequest{
   434  				ContractID: "ctr_1-1TJZFW",
   435  				GroupID:    "grp_15166",
   436  			},
   437  			withError: ErrStructValidation,
   438  		},
   439  	}
   440  
   441  	for name, test := range tests {
   442  		t.Run(name, func(t *testing.T) {
   443  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   444  				assert.Equal(t, test.expectedPath, r.URL.String())
   445  				assert.Equal(t, http.MethodGet, r.Method)
   446  				w.WriteHeader(test.responseStatus)
   447  				_, err := w.Write([]byte(test.responseBody))
   448  				assert.NoError(t, err)
   449  			}))
   450  			client := mockAPIClient(t, mockServer)
   451  			result, err := client.GetActivations(context.Background(), test.request)
   452  			if test.withError != nil {
   453  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   454  				return
   455  			}
   456  			require.NoError(t, err)
   457  			assert.Equal(t, test.expectedResponse, result)
   458  		})
   459  	}
   460  }
   461  
   462  func TestPapi_GetActivation(t *testing.T) {
   463  	tests := map[string]struct {
   464  		request          GetActivationRequest
   465  		responseStatus   int
   466  		responseBody     string
   467  		expectedPath     string
   468  		expectedResponse *GetActivationResponse
   469  		withError        error
   470  	}{
   471  		"200 OK": {
   472  			request: GetActivationRequest{
   473  				PropertyID:   "prp_175780",
   474  				ActivationID: "atv_1696855",
   475  				ContractID:   "ctr_1-1TJZFW",
   476  				GroupID:      "grp_15166",
   477  			},
   478  			responseStatus: http.StatusOK,
   479  			responseBody: `
   480  {
   481  	"accountId": "act_1-1TJZFB",
   482  	"contractId": "ctr_1-1TJZFW",
   483  	"groupId": "grp_15166",
   484  	"activations": {
   485  		"items": [
   486  			{
   487  				"activationId": "atv_1696985",
   488  				"propertyName": "example.com",
   489  				"propertyId": "prp_173136",
   490  				"propertyVersion": 1,
   491  				"network": "STAGING",
   492  				"activationType": "ACTIVATE",
   493  				"status": "PENDING",
   494  				"submitDate": "2014-03-02T02:22:12Z",
   495  				"updateDate": "2014-03-01T21:12:57Z",
   496  				"note": "Sample activation",
   497  				"fmaActivationState": "steady",
   498  				"notifyEmails": [
   499  					"you@example.com",
   500  					"them@example.com"
   501  				],
   502  				"fallbackInfo": {
   503  					"fastFallbackAttempted": false,
   504  					"fallbackVersion": 10,
   505  					"canFastFallback": true,
   506  					"steadyStateTime": 1506448172,
   507  					"fastFallbackExpirationTime": 1506451772,
   508  					"fastFallbackRecoveryState": null
   509  				}
   510  			}
   511  		]
   512  	}
   513  }`,
   514  			expectedPath: "/papi/v1/properties/prp_175780/activations/atv_1696855?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   515  			expectedResponse: &GetActivationResponse{
   516  				GetActivationsResponse: GetActivationsResponse{
   517  					Response: Response{
   518  						AccountID:  "act_1-1TJZFB",
   519  						ContractID: "ctr_1-1TJZFW",
   520  						GroupID:    "grp_15166",
   521  					},
   522  					Activations: ActivationsItems{Items: []*Activation{{
   523  						ActivationID:       "atv_1696985",
   524  						PropertyName:       "example.com",
   525  						PropertyID:         "prp_173136",
   526  						PropertyVersion:    1,
   527  						Network:            ActivationNetworkStaging,
   528  						ActivationType:     ActivationTypeActivate,
   529  						Status:             ActivationStatusPending,
   530  						SubmitDate:         "2014-03-02T02:22:12Z",
   531  						UpdateDate:         "2014-03-01T21:12:57Z",
   532  						Note:               "Sample activation",
   533  						FMAActivationState: "steady",
   534  						NotifyEmails: []string{
   535  							"you@example.com",
   536  							"them@example.com",
   537  						},
   538  						FallbackInfo: &ActivationFallbackInfo{
   539  							FastFallbackAttempted:      false,
   540  							FallbackVersion:            10,
   541  							CanFastFallback:            true,
   542  							SteadyStateTime:            1506448172,
   543  							FastFallbackExpirationTime: 1506451772,
   544  							FastFallbackRecoveryState:  nil,
   545  						},
   546  					}},
   547  					},
   548  				},
   549  				Activation: &Activation{
   550  					ActivationID:       "atv_1696985",
   551  					PropertyName:       "example.com",
   552  					PropertyID:         "prp_173136",
   553  					PropertyVersion:    1,
   554  					Network:            ActivationNetworkStaging,
   555  					ActivationType:     ActivationTypeActivate,
   556  					Status:             ActivationStatusPending,
   557  					SubmitDate:         "2014-03-02T02:22:12Z",
   558  					UpdateDate:         "2014-03-01T21:12:57Z",
   559  					Note:               "Sample activation",
   560  					FMAActivationState: "steady",
   561  					NotifyEmails: []string{
   562  						"you@example.com",
   563  						"them@example.com",
   564  					},
   565  					FallbackInfo: &ActivationFallbackInfo{
   566  						FastFallbackAttempted:      false,
   567  						FallbackVersion:            10,
   568  						CanFastFallback:            true,
   569  						SteadyStateTime:            1506448172,
   570  						FastFallbackExpirationTime: 1506451772,
   571  						FastFallbackRecoveryState:  nil,
   572  					},
   573  				},
   574  			},
   575  		},
   576  		"activation not found": {
   577  			request: GetActivationRequest{
   578  				PropertyID:   "prp_175780",
   579  				ActivationID: "atv_1696855",
   580  				ContractID:   "ctr_1-1TJZFW",
   581  				GroupID:      "grp_15166",
   582  			},
   583  			responseStatus: http.StatusOK,
   584  			responseBody: `
   585  {
   586  	"accountId": "act_1-1TJZFB",
   587  	"contractId": "ctr_1-1TJZFW",
   588  	"groupId": "grp_15166",
   589  	"activations": {
   590  		"items": [
   591  		]
   592  	}
   593  }`,
   594  			expectedPath: "/papi/v1/properties/prp_175780/activations/atv_1696855?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   595  			withError:    ErrNotFound,
   596  		},
   597  		"500 internal server error": {
   598  			request: GetActivationRequest{
   599  				PropertyID:   "prp_175780",
   600  				ActivationID: "atv_1696855",
   601  				ContractID:   "ctr_1-1TJZFW",
   602  				GroupID:      "grp_15166",
   603  			},
   604  			responseStatus: http.StatusInternalServerError,
   605  			responseBody: `
   606  {
   607  	"type": "internal_error",
   608      "title": "Internal Server Error",
   609      "detail": "Error fetching activation",
   610      "status": 500
   611  }`,
   612  			expectedPath: "/papi/v1/properties/prp_175780/activations/atv_1696855?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   613  			withError: &Error{
   614  				Type:       "internal_error",
   615  				Title:      "Internal Server Error",
   616  				Detail:     "Error fetching activation",
   617  				StatusCode: http.StatusInternalServerError,
   618  			},
   619  		},
   620  		"validation error": {
   621  			request: GetActivationRequest{
   622  				ActivationID: "atv_1696855",
   623  				ContractID:   "ctr_1-1TJZFW",
   624  				GroupID:      "grp_15166",
   625  			},
   626  			withError: ErrStructValidation,
   627  		},
   628  	}
   629  
   630  	for name, test := range tests {
   631  		t.Run(name, func(t *testing.T) {
   632  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   633  				assert.Equal(t, test.expectedPath, r.URL.String())
   634  				assert.Equal(t, http.MethodGet, r.Method)
   635  				w.WriteHeader(test.responseStatus)
   636  				_, err := w.Write([]byte(test.responseBody))
   637  				assert.NoError(t, err)
   638  			}))
   639  			client := mockAPIClient(t, mockServer)
   640  			result, err := client.GetActivation(context.Background(), test.request)
   641  			if test.withError != nil {
   642  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   643  				return
   644  			}
   645  			require.NoError(t, err)
   646  			assert.Equal(t, test.expectedResponse, result)
   647  		})
   648  	}
   649  }
   650  
   651  func TestPapi_CancelActivation(t *testing.T) {
   652  	tests := map[string]struct {
   653  		request          CancelActivationRequest
   654  		responseStatus   int
   655  		responseBody     string
   656  		expectedPath     string
   657  		expectedResponse *CancelActivationResponse
   658  		withError        error
   659  	}{
   660  		"200 OK": {
   661  			request: CancelActivationRequest{
   662  				PropertyID:   "prp_175780",
   663  				ActivationID: "atv_1696855",
   664  				ContractID:   "ctr_1-1TJZFW",
   665  				GroupID:      "grp_15166",
   666  			},
   667  			responseStatus: http.StatusOK,
   668  			responseBody: `
   669  {
   670  	"activations": {
   671  		"items": [
   672  			{
   673  				"activationId": "atv_1696985",
   674  				"propertyName": "example.com",
   675  				"propertyId": "prp_173136",
   676  				"propertyVersion": 1,
   677  				"network": "STAGING",
   678  				"activationType": "ACTIVATE",
   679  				"status": "ABORTED",
   680  				"submitDate": "2014-03-02T02:22:12Z",
   681  				"updateDate": "2014-03-01T21:12:57Z",
   682  				"note": "Sample activation",
   683  				"fmaActivationState": "steady",
   684  				"notifyEmails": [
   685  					"you@example.com",
   686  					"them@example.com"
   687  				],
   688  				"fallbackInfo": {
   689  					"fastFallbackAttempted": false,
   690  					"fallbackVersion": 10,
   691  					"canFastFallback": true,
   692  					"steadyStateTime": 1506448172,
   693  					"fastFallbackExpirationTime": 1506451772,
   694  					"fastFallbackRecoveryState": null
   695  				}
   696  			}
   697  		]
   698  	}
   699  }`,
   700  			expectedPath: "/papi/v1/properties/prp_175780/activations/atv_1696855?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   701  			expectedResponse: &CancelActivationResponse{
   702  				Activations: ActivationsItems{Items: []*Activation{{
   703  					ActivationID:       "atv_1696985",
   704  					PropertyName:       "example.com",
   705  					PropertyID:         "prp_173136",
   706  					PropertyVersion:    1,
   707  					Network:            ActivationNetworkStaging,
   708  					ActivationType:     ActivationTypeActivate,
   709  					Status:             ActivationStatusAborted,
   710  					SubmitDate:         "2014-03-02T02:22:12Z",
   711  					UpdateDate:         "2014-03-01T21:12:57Z",
   712  					Note:               "Sample activation",
   713  					FMAActivationState: "steady",
   714  					NotifyEmails: []string{
   715  						"you@example.com",
   716  						"them@example.com",
   717  					},
   718  					FallbackInfo: &ActivationFallbackInfo{
   719  						FastFallbackAttempted:      false,
   720  						FallbackVersion:            10,
   721  						CanFastFallback:            true,
   722  						SteadyStateTime:            1506448172,
   723  						FastFallbackExpirationTime: 1506451772,
   724  						FastFallbackRecoveryState:  nil,
   725  					},
   726  				}},
   727  				},
   728  			},
   729  		},
   730  		"500 internal server error": {
   731  			request: CancelActivationRequest{
   732  				PropertyID:   "prp_175780",
   733  				ActivationID: "atv_1696855",
   734  				ContractID:   "ctr_1-1TJZFW",
   735  				GroupID:      "grp_15166",
   736  			},
   737  			responseStatus: http.StatusInternalServerError,
   738  			responseBody: `
   739  {
   740  	"type": "internal_error",
   741      "title": "Internal Server Error",
   742      "detail": "Error deleting activation",
   743      "status": 500
   744  }`,
   745  			expectedPath: "/papi/v1/properties/prp_175780/activations/atv_1696855?contractId=ctr_1-1TJZFW&groupId=grp_15166",
   746  			withError: &Error{
   747  				Type:       "internal_error",
   748  				Title:      "Internal Server Error",
   749  				Detail:     "Error deleting activation",
   750  				StatusCode: http.StatusInternalServerError,
   751  			},
   752  		},
   753  		"validation error": {
   754  			request: CancelActivationRequest{
   755  				ActivationID: "atv_1696855",
   756  				ContractID:   "ctr_1-1TJZFW",
   757  				GroupID:      "grp_15166",
   758  			},
   759  			withError: ErrStructValidation,
   760  		},
   761  	}
   762  
   763  	for name, test := range tests {
   764  		t.Run(name, func(t *testing.T) {
   765  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   766  				assert.Equal(t, test.expectedPath, r.URL.String())
   767  				assert.Equal(t, http.MethodDelete, r.Method)
   768  				w.WriteHeader(test.responseStatus)
   769  				_, err := w.Write([]byte(test.responseBody))
   770  				assert.NoError(t, err)
   771  			}))
   772  			client := mockAPIClient(t, mockServer)
   773  			result, err := client.CancelActivation(context.Background(), test.request)
   774  			if test.withError != nil {
   775  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   776  				return
   777  			}
   778  			require.NoError(t, err)
   779  			assert.Equal(t, test.expectedResponse, result)
   780  		})
   781  	}
   782  }