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

     1  package dns
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  
    10  	"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestDNS_ListZones(t *testing.T) {
    16  
    17  	tests := map[string]struct {
    18  		args             []ZoneListQueryArgs
    19  		responseStatus   int
    20  		responseBody     string
    21  		expectedPath     string
    22  		expectedResponse *ZoneListResponse
    23  		withError        error
    24  		headers          http.Header
    25  	}{
    26  		"200 OK": {
    27  			args: []ZoneListQueryArgs{
    28  				{
    29  					ContractIDs: "1-1ACYUM",
    30  					Search:      "org",
    31  					SortBy:      "-contractId,zone",
    32  					Types:       "primary,alias",
    33  					Page:        1,
    34  					PageSize:    25,
    35  				},
    36  			},
    37  			headers: http.Header{
    38  				"Accept": []string{"application/json"},
    39  			},
    40  			responseStatus: http.StatusOK,
    41  			responseBody: `
    42  			{
    43  				"metadata": {
    44  					"page": 1,
    45  					"pageSize": 3,
    46  					"showAll": false,
    47  					"totalElements": 17,
    48  					"contractIds": [
    49  						"1-2ABCDE"
    50  					]
    51  				},
    52  				"zones": [
    53  					{
    54  						"contractId": "1-2ABCDE",
    55  						"zone": "example.com",
    56  						"type": "primary",
    57  						"aliasCount": 1,
    58  						"signAndServe": false,
    59  						"versionId": "ae02357c-693d-4ac4-b33d-8352d9b7c786",
    60  						"lastModifiedDate": "2017-01-03T12:00:00Z",
    61  						"lastModifiedBy": "user28",
    62  						"lastActivationDate": "2017-01-03T12:00:00Z",
    63  						"activationState": "ACTIVE"
    64  					}
    65  				]
    66  			}`,
    67  			expectedPath: "/config-dns/v2/zones?contractIds=1-1ACYUM&search=org&sortBy=-contractId%2Czone&types=primary%2Calias&page=1&pageSize=25&showAll=false",
    68  			expectedResponse: &ZoneListResponse{
    69  				Metadata: &ListMetadata{
    70  					Page:          1,
    71  					PageSize:      3,
    72  					ShowAll:       false,
    73  					TotalElements: 17,
    74  					ContractIDs:   []string{"1-2ABCDE"},
    75  				},
    76  				Zones: []*ZoneResponse{
    77  					{
    78  						ContractID:         "1-2ABCDE",
    79  						Zone:               "example.com",
    80  						Type:               "primary",
    81  						AliasCount:         1,
    82  						SignAndServe:       false,
    83  						VersionID:          "ae02357c-693d-4ac4-b33d-8352d9b7c786",
    84  						LastModifiedDate:   "2017-01-03T12:00:00Z",
    85  						LastModifiedBy:     "user28",
    86  						LastActivationDate: "2017-01-03T12:00:00Z",
    87  						ActivationState:    "ACTIVE",
    88  					},
    89  				},
    90  			},
    91  		},
    92  		"500 internal server error": {
    93  			args: []ZoneListQueryArgs{
    94  				{
    95  					ContractIDs: "1-1ACYUM",
    96  					Search:      "org",
    97  					SortBy:      "-contractId,zone",
    98  					Types:       "primary,alias",
    99  					Page:        1,
   100  					PageSize:    25,
   101  				},
   102  			},
   103  			responseStatus: http.StatusInternalServerError,
   104  			responseBody: `
   105  {
   106  	"type": "internal_error",
   107      "title": "Internal Server Error",
   108      "detail": "Error fetching authorities",
   109      "status": 500
   110  }`,
   111  			expectedPath: "/config-dns/v2/zones?contractIds=1-1ACYUM&search=org&sortBy=-contractId%2Czone&types=primary%2Calias&page=1&pageSize=25&showAll=false",
   112  			withError: &Error{
   113  				Type:       "internal_error",
   114  				Title:      "Internal Server Error",
   115  				Detail:     "Error fetching authorities",
   116  				StatusCode: http.StatusInternalServerError,
   117  			},
   118  		},
   119  	}
   120  
   121  	for name, test := range tests {
   122  		t.Run(name, func(t *testing.T) {
   123  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   124  				assert.Equal(t, http.MethodGet, r.Method)
   125  				w.WriteHeader(test.responseStatus)
   126  				_, err := w.Write([]byte(test.responseBody))
   127  				assert.NoError(t, err)
   128  			}))
   129  			client := mockAPIClient(t, mockServer)
   130  			result, err := client.ListZones(
   131  				session.ContextWithOptions(
   132  					context.Background(),
   133  					session.WithContextHeaders(test.headers)), test.args...)
   134  			if test.withError != nil {
   135  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   136  				return
   137  			}
   138  			require.NoError(t, err)
   139  			assert.Equal(t, test.expectedResponse, result)
   140  		})
   141  	}
   142  }
   143  
   144  func TestDNS_GetZone(t *testing.T) {
   145  	tests := map[string]struct {
   146  		zone             string
   147  		responseStatus   int
   148  		responseBody     string
   149  		expectedPath     string
   150  		expectedResponse *ZoneResponse
   151  		withError        error
   152  	}{
   153  		"200 OK": {
   154  			zone:           "example.com",
   155  			responseStatus: http.StatusOK,
   156  			responseBody: `
   157  			{
   158  				"contractId": "1-2ABCDE",
   159  				"zone": "example.com",
   160  				"type": "primary",
   161  				"aliasCount": 1,
   162  				"signAndServe": true,
   163  				"signAndServeAlgorithm": "RSA_SHA256",
   164  				"versionId": "ae02357c-693d-4ac4-b33d-8352d9b7c786",
   165  				"lastModifiedDate": "2017-01-03T12:00:00Z",
   166  				"lastModifiedBy": "user28",
   167  				"lastActivationDate": "2017-01-03T12:00:00Z",
   168  				"activationState": "ACTIVE"
   169  			}`,
   170  			expectedPath: "/config-dns/v2/zones/example.com",
   171  			expectedResponse: &ZoneResponse{
   172  				ContractID:            "1-2ABCDE",
   173  				Zone:                  "example.com",
   174  				Type:                  "primary",
   175  				AliasCount:            1,
   176  				SignAndServe:          true,
   177  				SignAndServeAlgorithm: "RSA_SHA256",
   178  				VersionID:             "ae02357c-693d-4ac4-b33d-8352d9b7c786",
   179  				LastModifiedDate:      "2017-01-03T12:00:00Z",
   180  				LastModifiedBy:        "user28",
   181  				LastActivationDate:    "2017-01-03T12:00:00Z",
   182  				ActivationState:       "ACTIVE",
   183  			},
   184  		},
   185  		"500 internal server error": {
   186  			zone:           "example.com",
   187  			responseStatus: http.StatusInternalServerError,
   188  			responseBody: `
   189  {
   190  	"type": "internal_error",
   191      "title": "Internal Server Error",
   192      "detail": "Error fetching authorities",
   193      "status": 500
   194  }`,
   195  			expectedPath: "/config-dns/v2/zones/example.com",
   196  			withError: &Error{
   197  				Type:       "internal_error",
   198  				Title:      "Internal Server Error",
   199  				Detail:     "Error fetching authorities",
   200  				StatusCode: http.StatusInternalServerError,
   201  			},
   202  		},
   203  	}
   204  
   205  	for name, test := range tests {
   206  		t.Run(name, func(t *testing.T) {
   207  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   208  				//assert.Equal(t, test.expectedPath, r.URL.String())
   209  				assert.Equal(t, http.MethodGet, r.Method)
   210  				w.WriteHeader(test.responseStatus)
   211  				_, err := w.Write([]byte(test.responseBody))
   212  				assert.NoError(t, err)
   213  			}))
   214  			client := mockAPIClient(t, mockServer)
   215  			result, err := client.GetZone(context.Background(), test.zone)
   216  			if test.withError != nil {
   217  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   218  				return
   219  			}
   220  			require.NoError(t, err)
   221  			assert.Equal(t, test.expectedResponse, result)
   222  		})
   223  	}
   224  }
   225  
   226  func TestDNS_GetZoneMasterFile(t *testing.T) {
   227  	tests := map[string]struct {
   228  		zone             string
   229  		responseStatus   int
   230  		responseBody     string
   231  		expectedPath     string
   232  		expectedResponse string
   233  		withError        error
   234  	}{
   235  		"200 OK": {
   236  			zone:           "example.com",
   237  			responseStatus: http.StatusOK,
   238  			responseBody: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   239  example.com.        10000    IN NS  ns1.akamaidns.com.
   240  example.com.        10000    IN NS  ns2.akamaidns.com.
   241  example.com.            300 IN  A   10.0.0.1
   242  example.com.            300 IN  A   10.0.0.2
   243  www.example.com.        300 IN  A   10.0.0.1
   244  www.example.com.        300 IN  A   10.0.0.2"`,
   245  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   246  			expectedResponse: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   247  example.com.        10000    IN NS  ns1.akamaidns.com.
   248  example.com.        10000    IN NS  ns2.akamaidns.com.
   249  example.com.            300 IN  A   10.0.0.1
   250  example.com.            300 IN  A   10.0.0.2
   251  www.example.com.        300 IN  A   10.0.0.1
   252  www.example.com.        300 IN  A   10.0.0.2"`,
   253  		},
   254  		"500 internal server error": {
   255  			zone:           "example.com",
   256  			responseStatus: http.StatusInternalServerError,
   257  			responseBody: `
   258  {
   259  	"type": "internal_error",
   260      "title": "Internal Server Error",
   261      "detail": "Error fetching authorities",
   262      "status": 500
   263  }`,
   264  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   265  			withError: &Error{
   266  				Type:       "internal_error",
   267  				Title:      "Internal Server Error",
   268  				Detail:     "Error fetching authorities",
   269  				StatusCode: http.StatusInternalServerError,
   270  			},
   271  		},
   272  	}
   273  
   274  	for name, test := range tests {
   275  		t.Run(name, func(t *testing.T) {
   276  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   277  				//assert.Equal(t, test.expectedPath, r.URL.String())
   278  				assert.Equal(t, http.MethodGet, r.Method)
   279  				w.WriteHeader(test.responseStatus)
   280  				_, err := w.Write([]byte(test.responseBody))
   281  				assert.NoError(t, err)
   282  			}))
   283  			client := mockAPIClient(t, mockServer)
   284  			result, err := client.GetMasterZoneFile(context.Background(), test.zone)
   285  			if test.withError != nil {
   286  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   287  				return
   288  			}
   289  			require.NoError(t, err)
   290  			assert.Equal(t, test.expectedResponse, result)
   291  		})
   292  	}
   293  }
   294  
   295  func TestDNS_UpdateZoneMasterFile(t *testing.T) {
   296  	tests := map[string]struct {
   297  		zone           string
   298  		masterfile     string
   299  		responseStatus int
   300  		expectedPath   string
   301  		responseBody   string
   302  		withError      error
   303  	}{
   304  		"204 Updated": {
   305  			zone: "example.com",
   306  			masterfile: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   307  example.com.        10000    IN NS  ns1.akamaidns.com.
   308  example.com.        10000    IN NS  ns2.akamaidns.com.
   309  example.com.            300 IN  A   10.0.0.1
   310  example.com.            300 IN  A   10.0.0.2
   311  www.example.com.        300 IN  A   10.0.0.1
   312  www.example.com.        300 IN  A   10.0.0.2"`,
   313  			responseStatus: http.StatusNoContent,
   314  			responseBody:   "",
   315  			expectedPath:   "/config-dns/v2/zones/example.com/zone-file",
   316  		},
   317  		"500 internal server error": {
   318  			zone: "example.com",
   319  			masterfile: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   320  example.com.        10000    IN NS  ns1.akamaidns.com.
   321  example.com.        10000    IN NS  ns2.akamaidns.com.
   322  example.com.            300 IN  A   10.0.0.1
   323  example.com.            300 IN  A   10.0.0.2
   324  www.example.com.        300 IN  A   10.0.0.1
   325  www.example.com.        300 IN  A   10.0.0.2"`,
   326  			responseStatus: http.StatusInternalServerError,
   327  			responseBody: `
   328  {
   329  	"type": "internal_error",
   330      "title": "Internal Server Error",
   331      "detail": "Error creating zone",
   332      "status": 500
   333  }`,
   334  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   335  			withError: &Error{
   336  				Type:       "internal_error",
   337  				Title:      "Internal Server Error",
   338  				Detail:     "Error creating zone",
   339  				StatusCode: http.StatusInternalServerError,
   340  			},
   341  		},
   342  	}
   343  
   344  	for name, test := range tests {
   345  		t.Run(name, func(t *testing.T) {
   346  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   347  				assert.Equal(t, http.MethodPost, r.Method)
   348  				w.WriteHeader(test.responseStatus)
   349  				if len(test.responseBody) > 0 {
   350  					_, err := w.Write([]byte(test.responseBody))
   351  					assert.NoError(t, err)
   352  				}
   353  			}))
   354  			client := mockAPIClient(t, mockServer)
   355  			err := client.PostMasterZoneFile(context.Background(), test.zone, test.masterfile)
   356  			if test.withError != nil {
   357  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   358  				return
   359  			}
   360  			require.NoError(t, err)
   361  		})
   362  	}
   363  }
   364  
   365  func TestDNS_GetChangeList(t *testing.T) {
   366  	tests := map[string]struct {
   367  		zone             string
   368  		responseStatus   int
   369  		responseBody     string
   370  		expectedPath     string
   371  		expectedResponse *ChangeListResponse
   372  		withError        error
   373  	}{
   374  		"200 OK": {
   375  			zone:           "example.com",
   376  			responseStatus: http.StatusOK,
   377  			responseBody: `
   378  			{
   379  				"zone": "example.com",
   380  				"changeTag": "476754f4-d605-479f-853b-db854d7254fa",
   381  				"zoneVersionId": "1d9c887c-49bb-4382-87a6-d1bf690aa58f",
   382  				"lastModifiedDate": "2017-02-01T12:00:12.524Z",
   383  				"stale": false
   384  			}`,
   385  			expectedPath: "/config-dns/v2/zones/example.com",
   386  			expectedResponse: &ChangeListResponse{
   387  				Zone:             "example.com",
   388  				ChangeTag:        "476754f4-d605-479f-853b-db854d7254fa",
   389  				ZoneVersionID:    "1d9c887c-49bb-4382-87a6-d1bf690aa58f",
   390  				LastModifiedDate: "2017-02-01T12:00:12.524Z",
   391  				Stale:            false,
   392  			},
   393  		},
   394  		"500 internal server error": {
   395  			zone:           "example.com",
   396  			responseStatus: http.StatusInternalServerError,
   397  			responseBody: `
   398  {
   399  	"type": "internal_error",
   400      "title": "Internal Server Error",
   401      "detail": "Error fetching authorities",
   402      "status": 500
   403  }`,
   404  			expectedPath: "/config-dns/v2/zones/example.com",
   405  			withError: &Error{
   406  				Type:       "internal_error",
   407  				Title:      "Internal Server Error",
   408  				Detail:     "Error fetching authorities",
   409  				StatusCode: http.StatusInternalServerError,
   410  			},
   411  		},
   412  	}
   413  
   414  	for name, test := range tests {
   415  		t.Run(name, func(t *testing.T) {
   416  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   417  				//assert.Equal(t, test.expectedPath, r.URL.String())
   418  				assert.Equal(t, http.MethodGet, r.Method)
   419  				w.WriteHeader(test.responseStatus)
   420  				_, err := w.Write([]byte(test.responseBody))
   421  				assert.NoError(t, err)
   422  			}))
   423  			client := mockAPIClient(t, mockServer)
   424  			result, err := client.GetChangeList(context.Background(), test.zone)
   425  			if test.withError != nil {
   426  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   427  				return
   428  			}
   429  			require.NoError(t, err)
   430  			assert.Equal(t, test.expectedResponse, result)
   431  		})
   432  	}
   433  }
   434  
   435  func TestDNS_GetMasterZoneFile(t *testing.T) {
   436  	tests := map[string]struct {
   437  		zone             string
   438  		responseStatus   int
   439  		responseBody     string
   440  		expectedPath     string
   441  		expectedResponse string
   442  		withError        error
   443  	}{
   444  		"200 OK": {
   445  			zone:           "example.com",
   446  			responseStatus: http.StatusOK,
   447  			responseBody: `
   448  			example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   449  			example.com.        10000    IN NS  ns1.akamaidns.com.
   450  			example.com.        10000    IN NS  ns2.akamaidns.com.
   451  			example.com.            300 IN  A   10.0.0.1
   452  			example.com.            300 IN  A   10.0.0.2
   453  			www.example.com.        300 IN  A   10.0.0.1
   454  			www.example.com.        300 IN  A   10.0.0.2`,
   455  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   456  			expectedResponse: `
   457  			example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   458  			example.com.        10000    IN NS  ns1.akamaidns.com.
   459  			example.com.        10000    IN NS  ns2.akamaidns.com.
   460  			example.com.            300 IN  A   10.0.0.1
   461  			example.com.            300 IN  A   10.0.0.2
   462  			www.example.com.        300 IN  A   10.0.0.1
   463  			www.example.com.        300 IN  A   10.0.0.2`,
   464  		},
   465  		"500 internal server error": {
   466  			zone:           "example.com",
   467  			responseStatus: http.StatusInternalServerError,
   468  			responseBody: `
   469  {
   470  	"type": "internal_error",
   471      "title": "Internal Server Error",
   472      "detail": "Error fetching master zone file",
   473      "status": 500
   474  }`,
   475  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   476  			withError: &Error{
   477  				Type:       "internal_error",
   478  				Title:      "Internal Server Error",
   479  				Detail:     "Error fetching master zone file",
   480  				StatusCode: http.StatusInternalServerError,
   481  			},
   482  		},
   483  	}
   484  
   485  	for name, test := range tests {
   486  		t.Run(name, func(t *testing.T) {
   487  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   488  				assert.Equal(t, test.expectedPath, r.URL.String())
   489  				assert.Equal(t, http.MethodGet, r.Method)
   490  				w.WriteHeader(test.responseStatus)
   491  				if len(test.responseBody) > 0 {
   492  					_, err := w.Write([]byte(test.responseBody))
   493  					assert.NoError(t, err)
   494  				}
   495  			}))
   496  			client := mockAPIClient(t, mockServer)
   497  			result, err := client.GetMasterZoneFile(context.Background(), test.zone)
   498  			if test.withError != nil {
   499  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   500  				return
   501  			}
   502  			require.NoError(t, err)
   503  			assert.Equal(t, test.expectedResponse, result)
   504  		})
   505  	}
   506  }
   507  
   508  func TestDNS_CreateZone(t *testing.T) {
   509  	tests := map[string]struct {
   510  		zone           ZoneCreate
   511  		query          ZoneQueryString
   512  		responseStatus int
   513  		responseBody   string
   514  		expectedPath   string
   515  		withError      error
   516  	}{
   517  		"201 Created": {
   518  			zone: ZoneCreate{
   519  				Zone:       "example.com",
   520  				ContractID: "1-2ABCDE",
   521  				Type:       "primary",
   522  			},
   523  			responseStatus: http.StatusCreated,
   524  			responseBody: `
   525  			{
   526  				"contractId": "1-2ABCDE",
   527  				"zone": "other.com",
   528  				"type": "primary",
   529  				"aliasCount": 1,
   530  				"signAndServe": false,
   531  				"comment": "Initial add",
   532  				"versionId": "7949b2db-ac43-4773-a3ec-dc93202142fd",
   533  				"lastModifiedDate": "2016-12-11T03:21:00Z",
   534  				"lastModifiedBy": "user31",
   535  				"lastActivationDate": "2017-01-03T12:00:00Z",
   536  				"activationState": "ERROR",
   537  				"masters": [
   538  					"1.2.3.4",
   539  					"1.2.3.5"
   540  				],
   541  				"tsigKey": {
   542  					"name": "other.com.akamai.com.",
   543  					"algorithm": "hmac-sha512",
   544  					"secret": "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw=="
   545  				}
   546  			}`,
   547  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   548  		},
   549  		"500 internal server error": {
   550  			zone: ZoneCreate{
   551  				Zone:       "example.com",
   552  				ContractID: "1-2ABCDE",
   553  				Type:       "secondary",
   554  			},
   555  			responseStatus: http.StatusInternalServerError,
   556  			responseBody: `
   557  {
   558  	"type": "internal_error",
   559      "title": "Internal Server Error",
   560      "detail": "Error creating zone",
   561      "status": 500
   562  }`,
   563  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   564  			withError: &Error{
   565  				Type:       "internal_error",
   566  				Title:      "Internal Server Error",
   567  				Detail:     "Error creating zone",
   568  				StatusCode: http.StatusInternalServerError,
   569  			},
   570  		},
   571  	}
   572  
   573  	for name, test := range tests {
   574  		t.Run(name, func(t *testing.T) {
   575  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   576  				assert.Equal(t, http.MethodPost, r.Method)
   577  				w.WriteHeader(test.responseStatus)
   578  				if len(test.responseBody) > 0 {
   579  					_, err := w.Write([]byte(test.responseBody))
   580  					assert.NoError(t, err)
   581  				}
   582  			}))
   583  			client := mockAPIClient(t, mockServer)
   584  			err := client.CreateZone(context.Background(), &test.zone, test.query, true)
   585  			if test.withError != nil {
   586  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   587  				return
   588  			}
   589  			require.NoError(t, err)
   590  		})
   591  	}
   592  }
   593  
   594  func TestDNS_SaveChangelist(t *testing.T) {
   595  	tests := map[string]struct {
   596  		zone           ZoneCreate
   597  		responseStatus int
   598  		responseBody   string
   599  		expectedPath   string
   600  		withError      error
   601  	}{
   602  		"201 Created": {
   603  			zone: ZoneCreate{
   604  				Zone:       "example.com",
   605  				ContractID: "1-2ABCDE",
   606  				Type:       "primary",
   607  			},
   608  			responseStatus: http.StatusCreated,
   609  			expectedPath:   "/config-dns/v2/changelists?zone=example.com",
   610  		},
   611  		"500 internal server error": {
   612  			zone: ZoneCreate{
   613  				Zone:       "example.com",
   614  				ContractID: "1-2ABCDE",
   615  				Type:       "secondary",
   616  			},
   617  			responseStatus: http.StatusInternalServerError,
   618  			responseBody: `
   619  {
   620  	"type": "internal_error",
   621      "title": "Internal Server Error",
   622      "detail": "Error creating zone",
   623      "status": 500
   624  }`,
   625  			expectedPath: "/config-dns/v2/changelists?zone=example.com",
   626  			withError: &Error{
   627  				Type:       "internal_error",
   628  				Title:      "Internal Server Error",
   629  				Detail:     "Error creating zone",
   630  				StatusCode: http.StatusInternalServerError,
   631  			},
   632  		},
   633  	}
   634  
   635  	for name, test := range tests {
   636  		t.Run(name, func(t *testing.T) {
   637  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   638  				assert.Equal(t, http.MethodPost, r.Method)
   639  				w.WriteHeader(test.responseStatus)
   640  				if len(test.responseBody) > 0 {
   641  					_, err := w.Write([]byte(test.responseBody))
   642  					assert.NoError(t, err)
   643  				}
   644  			}))
   645  			client := mockAPIClient(t, mockServer)
   646  			err := client.SaveChangelist(context.Background(), &test.zone)
   647  			if test.withError != nil {
   648  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   649  				return
   650  			}
   651  			require.NoError(t, err)
   652  		})
   653  	}
   654  }
   655  
   656  func TestDNS_SubmitChangelist(t *testing.T) {
   657  	tests := map[string]struct {
   658  		zone           ZoneCreate
   659  		responseStatus int
   660  		responseBody   string
   661  		expectedPath   string
   662  		withError      error
   663  	}{
   664  		"204 No Content": {
   665  			zone: ZoneCreate{
   666  				Zone:       "example.com",
   667  				ContractID: "1-2ABCDE",
   668  				Type:       "primary",
   669  			},
   670  			responseStatus: http.StatusNoContent,
   671  			expectedPath:   "/config-dns/v2/changelists?zone=example.com",
   672  		},
   673  		"500 internal server error": {
   674  			zone: ZoneCreate{
   675  				Zone:       "example.com",
   676  				ContractID: "1-2ABCDE",
   677  				Type:       "secondary",
   678  			},
   679  			responseStatus: http.StatusInternalServerError,
   680  			responseBody: `
   681  {
   682  	"type": "internal_error",
   683      "title": "Internal Server Error",
   684      "detail": "Error creating zone",
   685      "status": 500
   686  }`,
   687  			expectedPath: "/config-dns/v2/changelists?zone=example.com",
   688  			withError: &Error{
   689  				Type:       "internal_error",
   690  				Title:      "Internal Server Error",
   691  				Detail:     "Error creating zone",
   692  				StatusCode: http.StatusInternalServerError,
   693  			},
   694  		},
   695  	}
   696  
   697  	for name, test := range tests {
   698  		t.Run(name, func(t *testing.T) {
   699  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   700  				assert.Equal(t, http.MethodPost, r.Method)
   701  				w.WriteHeader(test.responseStatus)
   702  				if len(test.responseBody) > 0 {
   703  					_, err := w.Write([]byte(test.responseBody))
   704  					assert.NoError(t, err)
   705  				}
   706  			}))
   707  			client := mockAPIClient(t, mockServer)
   708  			err := client.SubmitChangelist(context.Background(), &test.zone)
   709  			if test.withError != nil {
   710  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   711  				return
   712  			}
   713  			require.NoError(t, err)
   714  		})
   715  	}
   716  }
   717  
   718  func TestDNS_UpdateZone(t *testing.T) {
   719  	tests := map[string]struct {
   720  		zone           ZoneCreate
   721  		query          ZoneQueryString
   722  		responseStatus int
   723  		responseBody   string
   724  		expectedPath   string
   725  		withError      error
   726  	}{
   727  		"200 OK": {
   728  			zone: ZoneCreate{
   729  				Zone:       "example.com",
   730  				ContractID: "1-2ABCDE",
   731  				Type:       "primary",
   732  			},
   733  			responseStatus: http.StatusOK,
   734  			responseBody: `
   735  			{
   736  				"contractId": "1-2ABCDE",
   737  				"zone": "other.com",
   738  				"type": "primary",
   739  				"aliasCount": 1,
   740  				"signAndServe": false,
   741  				"comment": "Initial add",
   742  				"versionId": "7949b2db-ac43-4773-a3ec-dc93202142fd",
   743  				"lastModifiedDate": "2016-12-11T03:21:00Z",
   744  				"lastModifiedBy": "user31",
   745  				"lastActivationDate": "2017-01-03T12:00:00Z",
   746  				"activationState": "ERROR",
   747  				"masters": [
   748  					"1.2.3.4",
   749  					"1.2.3.5"
   750  				],
   751  				"tsigKey": {
   752  					"name": "other.com.akamai.com.",
   753  					"algorithm": "hmac-sha512",
   754  					"secret": "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw=="
   755  				}
   756  			}`,
   757  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   758  		},
   759  		"500 internal server error": {
   760  			zone: ZoneCreate{
   761  				Zone:       "example.com",
   762  				ContractID: "1-2ABCDE",
   763  				Type:       "secondary",
   764  			},
   765  			responseStatus: http.StatusInternalServerError,
   766  			responseBody: `
   767  {
   768  	"type": "internal_error",
   769      "title": "Internal Server Error",
   770      "detail": "Error creating zone",
   771      "status": 500
   772  }`,
   773  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   774  			withError: &Error{
   775  				Type:       "internal_error",
   776  				Title:      "Internal Server Error",
   777  				Detail:     "Error creating zone",
   778  				StatusCode: http.StatusInternalServerError,
   779  			},
   780  		},
   781  	}
   782  
   783  	for name, test := range tests {
   784  		t.Run(name, func(t *testing.T) {
   785  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   786  				assert.Equal(t, http.MethodPut, r.Method)
   787  				w.WriteHeader(test.responseStatus)
   788  				if len(test.responseBody) > 0 {
   789  					_, err := w.Write([]byte(test.responseBody))
   790  					assert.NoError(t, err)
   791  				}
   792  			}))
   793  			client := mockAPIClient(t, mockServer)
   794  			err := client.UpdateZone(context.Background(), &test.zone, test.query)
   795  			if test.withError != nil {
   796  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   797  				return
   798  			}
   799  			require.NoError(t, err)
   800  		})
   801  	}
   802  }
   803  
   804  func TestDNS_GetZoneNames(t *testing.T) {
   805  	tests := map[string]struct {
   806  		zone             string
   807  		responseStatus   int
   808  		responseBody     string
   809  		expectedPath     string
   810  		expectedResponse *ZoneNamesResponse
   811  		withError        error
   812  	}{
   813  		"200 OK": {
   814  			zone:           "example.com",
   815  			responseStatus: http.StatusOK,
   816  			responseBody: `
   817  			{
   818  				"names": [
   819  					"example.com",
   820  					"www.example.com",
   821  					"ftp.example.com",
   822  					"space.example.com",
   823  					"bar.example.com"
   824  				]
   825  			}`,
   826  			expectedPath: "/config-dns/v2/zones/example.com/names",
   827  			expectedResponse: &ZoneNamesResponse{
   828  				Names: []string{"example.com", "www.example.com", "ftp.example.com", "space.example.com", "bar.example.com"},
   829  			},
   830  		},
   831  		"500 internal server error": {
   832  			zone:           "example.com",
   833  			responseStatus: http.StatusInternalServerError,
   834  			responseBody: `
   835  {
   836  	"type": "internal_error",
   837      "title": "Internal Server Error",
   838      "detail": "Error fetching authorities",
   839      "status": 500
   840  }`,
   841  			expectedPath: "/config-dns/v2/zones/example.com/names",
   842  			withError: &Error{
   843  				Type:       "internal_error",
   844  				Title:      "Internal Server Error",
   845  				Detail:     "Error fetching authorities",
   846  				StatusCode: http.StatusInternalServerError,
   847  			},
   848  		},
   849  	}
   850  
   851  	for name, test := range tests {
   852  		t.Run(name, func(t *testing.T) {
   853  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   854  				//assert.Equal(t, test.expectedPath, r.URL.String())
   855  				assert.Equal(t, http.MethodGet, r.Method)
   856  				w.WriteHeader(test.responseStatus)
   857  				_, err := w.Write([]byte(test.responseBody))
   858  				assert.NoError(t, err)
   859  			}))
   860  			client := mockAPIClient(t, mockServer)
   861  			result, err := client.GetZoneNames(context.Background(), test.zone)
   862  			if test.withError != nil {
   863  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   864  				return
   865  			}
   866  			require.NoError(t, err)
   867  			assert.Equal(t, test.expectedResponse, result)
   868  		})
   869  	}
   870  }
   871  
   872  func TestDNS_GetZoneNameTypes(t *testing.T) {
   873  	tests := map[string]struct {
   874  		zone             string
   875  		zname            string
   876  		responseStatus   int
   877  		responseBody     string
   878  		expectedPath     string
   879  		expectedResponse *ZoneNameTypesResponse
   880  		withError        error
   881  	}{
   882  		"200 OK": {
   883  			zone:           "example.com",
   884  			zname:          "names",
   885  			responseStatus: http.StatusOK,
   886  			responseBody: `
   887  			{
   888  				"types": [
   889  					"A",
   890  					"AAAA",
   891  					"MX"
   892  				]
   893  			}`,
   894  			expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types",
   895  			expectedResponse: &ZoneNameTypesResponse{
   896  				Types: []string{"A", "AAAA", "MX"},
   897  			},
   898  		},
   899  		"500 internal server error": {
   900  			zone:           "example.com",
   901  			zname:          "names",
   902  			responseStatus: http.StatusInternalServerError,
   903  			responseBody: `
   904  {
   905  	"type": "internal_error",
   906      "title": "Internal Server Error",
   907      "detail": "Error fetching authorities",
   908      "status": 500
   909  }`,
   910  			expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types",
   911  			withError: &Error{
   912  				Type:       "internal_error",
   913  				Title:      "Internal Server Error",
   914  				Detail:     "Error fetching authorities",
   915  				StatusCode: http.StatusInternalServerError,
   916  			},
   917  		},
   918  	}
   919  
   920  	for name, test := range tests {
   921  		t.Run(name, func(t *testing.T) {
   922  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   923  				//assert.Equal(t, test.expectedPath, r.URL.String())
   924  				assert.Equal(t, http.MethodGet, r.Method)
   925  				w.WriteHeader(test.responseStatus)
   926  				_, err := w.Write([]byte(test.responseBody))
   927  				assert.NoError(t, err)
   928  			}))
   929  			client := mockAPIClient(t, mockServer)
   930  			result, err := client.GetZoneNameTypes(context.Background(), test.zname, test.zone)
   931  			if test.withError != nil {
   932  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   933  				return
   934  			}
   935  			require.NoError(t, err)
   936  			assert.Equal(t, test.expectedResponse, result)
   937  		})
   938  	}
   939  }
   940  
   941  func Test_ValidateZoneErrors(t *testing.T) {
   942  	tests := map[string]ZoneCreate{
   943  		"empty zone": {},
   944  		"bad type": {
   945  			Zone: "example.com",
   946  			Type: "BAD",
   947  		},
   948  		"secondary tsig": {
   949  			Zone: "example.com",
   950  			Type: "PRIMARY",
   951  			TSIGKey: &TSIGKey{
   952  				Name: "example.com",
   953  			},
   954  		},
   955  		"alias empty target": {
   956  			Zone:   "example.com",
   957  			Type:   "ALIAS",
   958  			Target: "",
   959  		},
   960  		"alias masters": {
   961  			Zone:    "example.com",
   962  			Type:    "ALIAS",
   963  			Target:  "10.0.0.1",
   964  			Masters: []string{"master"},
   965  		},
   966  		"alias sign": {
   967  			Zone:         "example.com",
   968  			Type:         "ALIAS",
   969  			Target:       "10.0.0.1",
   970  			SignAndServe: true,
   971  		},
   972  		"alias sign algo": {
   973  			Zone:                  "example.com",
   974  			Type:                  "ALIAS",
   975  			Target:                "10.0.0.1",
   976  			SignAndServe:          false,
   977  			SignAndServeAlgorithm: "foo",
   978  		},
   979  		"primary bad target": {
   980  			Zone:   "example.com",
   981  			Type:   "PRIMARY",
   982  			Target: "10.0.0.1",
   983  		},
   984  		"primary bad masters": {
   985  			Zone:    "example.com",
   986  			Type:    "PRIMARY",
   987  			Masters: []string{"foo"},
   988  		},
   989  	}
   990  
   991  	for name, test := range tests {
   992  		t.Run(name, func(t *testing.T) {
   993  			err := ValidateZone(&test)
   994  			assert.NotNil(t, err)
   995  		})
   996  	}
   997  }