github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/configdns/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/v2/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, test.expectedPath, r.URL.String())
   125  				assert.Equal(t, http.MethodGet, r.Method)
   126  				w.WriteHeader(test.responseStatus)
   127  				_, err := w.Write([]byte(test.responseBody))
   128  				assert.NoError(t, err)
   129  			}))
   130  			client := mockAPIClient(t, mockServer)
   131  			result, err := client.ListZones(
   132  				session.ContextWithOptions(
   133  					context.Background(),
   134  					session.WithContextHeaders(test.headers)), test.args...)
   135  			if test.withError != nil {
   136  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   137  				return
   138  			}
   139  			require.NoError(t, err)
   140  			assert.Equal(t, test.expectedResponse, result)
   141  		})
   142  	}
   143  }
   144  
   145  func TestDns_NewZone(t *testing.T) {
   146  	client := Client(session.Must(session.New()))
   147  
   148  	inp := ZoneCreate{
   149  		Type:   "A",
   150  		Target: "10.0.0.1",
   151  	}
   152  
   153  	out := client.NewZone(context.Background(), inp)
   154  
   155  	assert.Equal(t, &inp, out)
   156  }
   157  
   158  func TestDns_NewZoneResponse(t *testing.T) {
   159  	client := Client(session.Must(session.New()))
   160  
   161  	out := client.NewZoneResponse(context.Background(), "example.com")
   162  
   163  	assert.Equal(t, out.Zone, "example.com")
   164  }
   165  
   166  func TestDns_NewChangeListResponse(t *testing.T) {
   167  	client := Client(session.Must(session.New()))
   168  
   169  	out := client.NewChangeListResponse(context.Background(), "example.com")
   170  
   171  	assert.Equal(t, out.Zone, "example.com")
   172  }
   173  
   174  func TestDns_NewZoneQueryString(t *testing.T) {
   175  	client := Client(session.Must(session.New()))
   176  
   177  	out := client.NewZoneQueryString(context.Background(), "foo", "bar")
   178  
   179  	assert.Equal(t, out.Contract, "foo")
   180  	assert.Equal(t, out.Group, "bar")
   181  }
   182  
   183  func TestDns_GetZone(t *testing.T) {
   184  	tests := map[string]struct {
   185  		zone             string
   186  		responseStatus   int
   187  		responseBody     string
   188  		expectedPath     string
   189  		expectedResponse *ZoneResponse
   190  		withError        error
   191  	}{
   192  		"200 OK": {
   193  			zone:           "example.com",
   194  			responseStatus: http.StatusOK,
   195  			responseBody: `
   196  			{
   197  				"contractId": "1-2ABCDE",
   198  				"zone": "example.com",
   199  				"type": "primary",
   200  				"aliasCount": 1,
   201  				"signAndServe": true,
   202  				"signAndServeAlgorithm": "RSA_SHA256",
   203  				"versionId": "ae02357c-693d-4ac4-b33d-8352d9b7c786",
   204  				"lastModifiedDate": "2017-01-03T12:00:00Z",
   205  				"lastModifiedBy": "user28",
   206  				"lastActivationDate": "2017-01-03T12:00:00Z",
   207  				"activationState": "ACTIVE"
   208  			}`,
   209  			expectedPath: "/config-dns/v2/zones/example.com",
   210  			expectedResponse: &ZoneResponse{
   211  				ContractID:            "1-2ABCDE",
   212  				Zone:                  "example.com",
   213  				Type:                  "primary",
   214  				AliasCount:            1,
   215  				SignAndServe:          true,
   216  				SignAndServeAlgorithm: "RSA_SHA256",
   217  				VersionId:             "ae02357c-693d-4ac4-b33d-8352d9b7c786",
   218  				LastModifiedDate:      "2017-01-03T12:00:00Z",
   219  				LastModifiedBy:        "user28",
   220  				LastActivationDate:    "2017-01-03T12:00:00Z",
   221  				ActivationState:       "ACTIVE",
   222  			},
   223  		},
   224  		"500 internal server error": {
   225  			zone:           "example.com",
   226  			responseStatus: http.StatusInternalServerError,
   227  			responseBody: `
   228  {
   229  	"type": "internal_error",
   230      "title": "Internal Server Error",
   231      "detail": "Error fetching authorities",
   232      "status": 500
   233  }`,
   234  			expectedPath: "/config-dns/v2/zones/example.com",
   235  			withError: &Error{
   236  				Type:       "internal_error",
   237  				Title:      "Internal Server Error",
   238  				Detail:     "Error fetching authorities",
   239  				StatusCode: http.StatusInternalServerError,
   240  			},
   241  		},
   242  	}
   243  
   244  	for name, test := range tests {
   245  		t.Run(name, func(t *testing.T) {
   246  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   247  				//assert.Equal(t, test.expectedPath, r.URL.String())
   248  				assert.Equal(t, http.MethodGet, r.Method)
   249  				w.WriteHeader(test.responseStatus)
   250  				_, err := w.Write([]byte(test.responseBody))
   251  				assert.NoError(t, err)
   252  			}))
   253  			client := mockAPIClient(t, mockServer)
   254  			result, err := client.GetZone(context.Background(), test.zone)
   255  			if test.withError != nil {
   256  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   257  				return
   258  			}
   259  			require.NoError(t, err)
   260  			assert.Equal(t, test.expectedResponse, result)
   261  		})
   262  	}
   263  }
   264  
   265  func TestDns_GetZoneMasterFile(t *testing.T) {
   266  	tests := map[string]struct {
   267  		zone             string
   268  		responseStatus   int
   269  		responseBody     string
   270  		expectedPath     string
   271  		expectedResponse string
   272  		withError        error
   273  	}{
   274  		"200 OK": {
   275  			zone:           "example.com",
   276  			responseStatus: http.StatusOK,
   277  			responseBody: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   278  example.com.        10000    IN NS  ns1.akamaidns.com.
   279  example.com.        10000    IN NS  ns2.akamaidns.com.
   280  example.com.            300 IN  A   10.0.0.1
   281  example.com.            300 IN  A   10.0.0.2
   282  www.example.com.        300 IN  A   10.0.0.1
   283  www.example.com.        300 IN  A   10.0.0.2"`,
   284  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   285  			expectedResponse: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   286  example.com.        10000    IN NS  ns1.akamaidns.com.
   287  example.com.        10000    IN NS  ns2.akamaidns.com.
   288  example.com.            300 IN  A   10.0.0.1
   289  example.com.            300 IN  A   10.0.0.2
   290  www.example.com.        300 IN  A   10.0.0.1
   291  www.example.com.        300 IN  A   10.0.0.2"`,
   292  		},
   293  		"500 internal server error": {
   294  			zone:           "example.com",
   295  			responseStatus: http.StatusInternalServerError,
   296  			responseBody: `
   297  {
   298  	"type": "internal_error",
   299      "title": "Internal Server Error",
   300      "detail": "Error fetching authorities",
   301      "status": 500
   302  }`,
   303  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   304  			withError: &Error{
   305  				Type:       "internal_error",
   306  				Title:      "Internal Server Error",
   307  				Detail:     "Error fetching authorities",
   308  				StatusCode: http.StatusInternalServerError,
   309  			},
   310  		},
   311  	}
   312  
   313  	for name, test := range tests {
   314  		t.Run(name, func(t *testing.T) {
   315  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   316  				//assert.Equal(t, test.expectedPath, r.URL.String())
   317  				assert.Equal(t, http.MethodGet, r.Method)
   318  				w.WriteHeader(test.responseStatus)
   319  				_, err := w.Write([]byte(test.responseBody))
   320  				assert.NoError(t, err)
   321  			}))
   322  			client := mockAPIClient(t, mockServer)
   323  			result, err := client.GetMasterZoneFile(context.Background(), test.zone)
   324  			if test.withError != nil {
   325  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   326  				return
   327  			}
   328  			require.NoError(t, err)
   329  			assert.Equal(t, test.expectedResponse, result)
   330  		})
   331  	}
   332  }
   333  
   334  func TestDns_UpdateZoneMasterFile(t *testing.T) {
   335  	tests := map[string]struct {
   336  		zone           string
   337  		masterfile     string
   338  		responseStatus int
   339  		expectedPath   string
   340  		responseBody   string
   341  		withError      error
   342  	}{
   343  		"204 Updated": {
   344  			zone: "example.com",
   345  			masterfile: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   346  example.com.        10000    IN NS  ns1.akamaidns.com.
   347  example.com.        10000    IN NS  ns2.akamaidns.com.
   348  example.com.            300 IN  A   10.0.0.1
   349  example.com.            300 IN  A   10.0.0.2
   350  www.example.com.        300 IN  A   10.0.0.1
   351  www.example.com.        300 IN  A   10.0.0.2"`,
   352  			responseStatus: http.StatusNoContent,
   353  			responseBody:   "",
   354  			expectedPath:   "/config-dns/v2/zones/example.com/zone-file",
   355  		},
   356  		"500 internal server error": {
   357  			zone: "example.com",
   358  			masterfile: `"example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   359  example.com.        10000    IN NS  ns1.akamaidns.com.
   360  example.com.        10000    IN NS  ns2.akamaidns.com.
   361  example.com.            300 IN  A   10.0.0.1
   362  example.com.            300 IN  A   10.0.0.2
   363  www.example.com.        300 IN  A   10.0.0.1
   364  www.example.com.        300 IN  A   10.0.0.2"`,
   365  			responseStatus: http.StatusInternalServerError,
   366  			responseBody: `
   367  {
   368  	"type": "internal_error",
   369      "title": "Internal Server Error",
   370      "detail": "Error creating zone",
   371      "status": 500
   372  }`,
   373  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   374  			withError: &Error{
   375  				Type:       "internal_error",
   376  				Title:      "Internal Server Error",
   377  				Detail:     "Error creating zone",
   378  				StatusCode: http.StatusInternalServerError,
   379  			},
   380  		},
   381  	}
   382  
   383  	for name, test := range tests {
   384  		t.Run(name, func(t *testing.T) {
   385  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   386  				assert.Equal(t, http.MethodPost, r.Method)
   387  				w.WriteHeader(test.responseStatus)
   388  				if len(test.responseBody) > 0 {
   389  					_, err := w.Write([]byte(test.responseBody))
   390  					assert.NoError(t, err)
   391  				}
   392  			}))
   393  			client := mockAPIClient(t, mockServer)
   394  			err := client.PostMasterZoneFile(context.Background(), test.zone, test.masterfile)
   395  			if test.withError != nil {
   396  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   397  				return
   398  			}
   399  			require.NoError(t, err)
   400  		})
   401  	}
   402  }
   403  
   404  func TestDns_GetChangeList(t *testing.T) {
   405  	tests := map[string]struct {
   406  		zone             string
   407  		responseStatus   int
   408  		responseBody     string
   409  		expectedPath     string
   410  		expectedResponse *ChangeListResponse
   411  		withError        error
   412  	}{
   413  		"200 OK": {
   414  			zone:           "example.com",
   415  			responseStatus: http.StatusOK,
   416  			responseBody: `
   417  			{
   418  				"zone": "example.com",
   419  				"changeTag": "476754f4-d605-479f-853b-db854d7254fa",
   420  				"zoneVersionId": "1d9c887c-49bb-4382-87a6-d1bf690aa58f",
   421  				"lastModifiedDate": "2017-02-01T12:00:12.524Z",
   422  				"stale": false
   423  			}`,
   424  			expectedPath: "/config-dns/v2/zones/example.com",
   425  			expectedResponse: &ChangeListResponse{
   426  				Zone:             "example.com",
   427  				ChangeTag:        "476754f4-d605-479f-853b-db854d7254fa",
   428  				ZoneVersionID:    "1d9c887c-49bb-4382-87a6-d1bf690aa58f",
   429  				LastModifiedDate: "2017-02-01T12:00:12.524Z",
   430  				Stale:            false,
   431  			},
   432  		},
   433  		"500 internal server error": {
   434  			zone:           "example.com",
   435  			responseStatus: http.StatusInternalServerError,
   436  			responseBody: `
   437  {
   438  	"type": "internal_error",
   439      "title": "Internal Server Error",
   440      "detail": "Error fetching authorities",
   441      "status": 500
   442  }`,
   443  			expectedPath: "/config-dns/v2/zones/example.com",
   444  			withError: &Error{
   445  				Type:       "internal_error",
   446  				Title:      "Internal Server Error",
   447  				Detail:     "Error fetching authorities",
   448  				StatusCode: http.StatusInternalServerError,
   449  			},
   450  		},
   451  	}
   452  
   453  	for name, test := range tests {
   454  		t.Run(name, func(t *testing.T) {
   455  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   456  				//assert.Equal(t, test.expectedPath, r.URL.String())
   457  				assert.Equal(t, http.MethodGet, r.Method)
   458  				w.WriteHeader(test.responseStatus)
   459  				_, err := w.Write([]byte(test.responseBody))
   460  				assert.NoError(t, err)
   461  			}))
   462  			client := mockAPIClient(t, mockServer)
   463  			result, err := client.GetChangeList(context.Background(), test.zone)
   464  			if test.withError != nil {
   465  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   466  				return
   467  			}
   468  			require.NoError(t, err)
   469  			assert.Equal(t, test.expectedResponse, result)
   470  		})
   471  	}
   472  }
   473  
   474  func TestDns_GetMasterZoneFile(t *testing.T) {
   475  	tests := map[string]struct {
   476  		zone             string
   477  		responseStatus   int
   478  		responseBody     string
   479  		expectedPath     string
   480  		expectedResponse string
   481  		withError        error
   482  	}{
   483  		"200 OK": {
   484  			zone:           "example.com",
   485  			responseStatus: http.StatusOK,
   486  			responseBody: `
   487  			example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   488  			example.com.        10000    IN NS  ns1.akamaidns.com.
   489  			example.com.        10000    IN NS  ns2.akamaidns.com.
   490  			example.com.            300 IN  A   10.0.0.1
   491  			example.com.            300 IN  A   10.0.0.2
   492  			www.example.com.        300 IN  A   10.0.0.1
   493  			www.example.com.        300 IN  A   10.0.0.2`,
   494  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   495  			expectedResponse: `
   496  			example.com.        10000    IN SOA ns1.akamaidns.com. webmaster.example.com. 1 28800 14400 2419200 86400
   497  			example.com.        10000    IN NS  ns1.akamaidns.com.
   498  			example.com.        10000    IN NS  ns2.akamaidns.com.
   499  			example.com.            300 IN  A   10.0.0.1
   500  			example.com.            300 IN  A   10.0.0.2
   501  			www.example.com.        300 IN  A   10.0.0.1
   502  			www.example.com.        300 IN  A   10.0.0.2`,
   503  		},
   504  		"500 internal server error": {
   505  			zone:           "example.com",
   506  			responseStatus: http.StatusInternalServerError,
   507  			responseBody: `
   508  {
   509  	"type": "internal_error",
   510      "title": "Internal Server Error",
   511      "detail": "Error fetching master zone file",
   512      "status": 500
   513  }`,
   514  			expectedPath: "/config-dns/v2/zones/example.com/zone-file",
   515  			withError: &Error{
   516  				Type:       "internal_error",
   517  				Title:      "Internal Server Error",
   518  				Detail:     "Error fetching master zone file",
   519  				StatusCode: http.StatusInternalServerError,
   520  			},
   521  		},
   522  	}
   523  
   524  	for name, test := range tests {
   525  		t.Run(name, func(t *testing.T) {
   526  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   527  				assert.Equal(t, test.expectedPath, r.URL.String())
   528  				assert.Equal(t, http.MethodGet, r.Method)
   529  				w.WriteHeader(test.responseStatus)
   530  				if len(test.responseBody) > 0 {
   531  					_, err := w.Write([]byte(test.responseBody))
   532  					assert.NoError(t, err)
   533  				}
   534  			}))
   535  			client := mockAPIClient(t, mockServer)
   536  			result, err := client.GetMasterZoneFile(context.Background(), test.zone)
   537  			if test.withError != nil {
   538  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   539  				return
   540  			}
   541  			require.NoError(t, err)
   542  			assert.Equal(t, test.expectedResponse, result)
   543  		})
   544  	}
   545  }
   546  
   547  func TestDns_CreateZone(t *testing.T) {
   548  	tests := map[string]struct {
   549  		zone           ZoneCreate
   550  		query          ZoneQueryString
   551  		responseStatus int
   552  		responseBody   string
   553  		expectedPath   string
   554  		withError      error
   555  	}{
   556  		"201 Created": {
   557  			zone: ZoneCreate{
   558  				Zone:       "example.com",
   559  				ContractID: "1-2ABCDE",
   560  				Type:       "primary",
   561  			},
   562  			responseStatus: http.StatusCreated,
   563  			responseBody: `
   564  			{
   565  				"contractId": "1-2ABCDE",
   566  				"zone": "other.com",
   567  				"type": "primary",
   568  				"aliasCount": 1,
   569  				"signAndServe": false,
   570  				"comment": "Initial add",
   571  				"versionId": "7949b2db-ac43-4773-a3ec-dc93202142fd",
   572  				"lastModifiedDate": "2016-12-11T03:21:00Z",
   573  				"lastModifiedBy": "user31",
   574  				"lastActivationDate": "2017-01-03T12:00:00Z",
   575  				"activationState": "ERROR",
   576  				"masters": [
   577  					"1.2.3.4",
   578  					"1.2.3.5"
   579  				],
   580  				"tsigKey": {
   581  					"name": "other.com.akamai.com.",
   582  					"algorithm": "hmac-sha512",
   583  					"secret": "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw=="
   584  				}
   585  			}`,
   586  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   587  		},
   588  		"500 internal server error": {
   589  			zone: ZoneCreate{
   590  				Zone:       "example.com",
   591  				ContractID: "1-2ABCDE",
   592  				Type:       "secondary",
   593  			},
   594  			responseStatus: http.StatusInternalServerError,
   595  			responseBody: `
   596  {
   597  	"type": "internal_error",
   598      "title": "Internal Server Error",
   599      "detail": "Error creating zone",
   600      "status": 500
   601  }`,
   602  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   603  			withError: &Error{
   604  				Type:       "internal_error",
   605  				Title:      "Internal Server Error",
   606  				Detail:     "Error creating zone",
   607  				StatusCode: http.StatusInternalServerError,
   608  			},
   609  		},
   610  	}
   611  
   612  	for name, test := range tests {
   613  		t.Run(name, func(t *testing.T) {
   614  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   615  				assert.Equal(t, http.MethodPost, r.Method)
   616  				w.WriteHeader(test.responseStatus)
   617  				if len(test.responseBody) > 0 {
   618  					_, err := w.Write([]byte(test.responseBody))
   619  					assert.NoError(t, err)
   620  				}
   621  			}))
   622  			client := mockAPIClient(t, mockServer)
   623  			err := client.CreateZone(context.Background(), &test.zone, test.query, true)
   624  			if test.withError != nil {
   625  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   626  				return
   627  			}
   628  			require.NoError(t, err)
   629  		})
   630  	}
   631  }
   632  
   633  func TestDns_SaveChangelist(t *testing.T) {
   634  	tests := map[string]struct {
   635  		zone           ZoneCreate
   636  		responseStatus int
   637  		responseBody   string
   638  		expectedPath   string
   639  		withError      error
   640  	}{
   641  		"201 Created": {
   642  			zone: ZoneCreate{
   643  				Zone:       "example.com",
   644  				ContractID: "1-2ABCDE",
   645  				Type:       "primary",
   646  			},
   647  			responseStatus: http.StatusCreated,
   648  			expectedPath:   "/config-dns/v2/changelists?zone=example.com",
   649  		},
   650  		"500 internal server error": {
   651  			zone: ZoneCreate{
   652  				Zone:       "example.com",
   653  				ContractID: "1-2ABCDE",
   654  				Type:       "secondary",
   655  			},
   656  			responseStatus: http.StatusInternalServerError,
   657  			responseBody: `
   658  {
   659  	"type": "internal_error",
   660      "title": "Internal Server Error",
   661      "detail": "Error creating zone",
   662      "status": 500
   663  }`,
   664  			expectedPath: "/config-dns/v2/changelists?zone=example.com",
   665  			withError: &Error{
   666  				Type:       "internal_error",
   667  				Title:      "Internal Server Error",
   668  				Detail:     "Error creating zone",
   669  				StatusCode: http.StatusInternalServerError,
   670  			},
   671  		},
   672  	}
   673  
   674  	for name, test := range tests {
   675  		t.Run(name, func(t *testing.T) {
   676  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   677  				assert.Equal(t, http.MethodPost, r.Method)
   678  				w.WriteHeader(test.responseStatus)
   679  				if len(test.responseBody) > 0 {
   680  					_, err := w.Write([]byte(test.responseBody))
   681  					assert.NoError(t, err)
   682  				}
   683  			}))
   684  			client := mockAPIClient(t, mockServer)
   685  			err := client.SaveChangelist(context.Background(), &test.zone)
   686  			if test.withError != nil {
   687  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   688  				return
   689  			}
   690  			require.NoError(t, err)
   691  		})
   692  	}
   693  }
   694  
   695  func TestDns_SubmitChangelist(t *testing.T) {
   696  	tests := map[string]struct {
   697  		zone           ZoneCreate
   698  		responseStatus int
   699  		responseBody   string
   700  		expectedPath   string
   701  		withError      error
   702  	}{
   703  		"204 No Content": {
   704  			zone: ZoneCreate{
   705  				Zone:       "example.com",
   706  				ContractID: "1-2ABCDE",
   707  				Type:       "primary",
   708  			},
   709  			responseStatus: http.StatusNoContent,
   710  			expectedPath:   "/config-dns/v2/changelists?zone=example.com",
   711  		},
   712  		"500 internal server error": {
   713  			zone: ZoneCreate{
   714  				Zone:       "example.com",
   715  				ContractID: "1-2ABCDE",
   716  				Type:       "secondary",
   717  			},
   718  			responseStatus: http.StatusInternalServerError,
   719  			responseBody: `
   720  {
   721  	"type": "internal_error",
   722      "title": "Internal Server Error",
   723      "detail": "Error creating zone",
   724      "status": 500
   725  }`,
   726  			expectedPath: "/config-dns/v2/changelists?zone=example.com",
   727  			withError: &Error{
   728  				Type:       "internal_error",
   729  				Title:      "Internal Server Error",
   730  				Detail:     "Error creating zone",
   731  				StatusCode: http.StatusInternalServerError,
   732  			},
   733  		},
   734  	}
   735  
   736  	for name, test := range tests {
   737  		t.Run(name, func(t *testing.T) {
   738  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   739  				assert.Equal(t, http.MethodPost, r.Method)
   740  				w.WriteHeader(test.responseStatus)
   741  				if len(test.responseBody) > 0 {
   742  					_, err := w.Write([]byte(test.responseBody))
   743  					assert.NoError(t, err)
   744  				}
   745  			}))
   746  			client := mockAPIClient(t, mockServer)
   747  			err := client.SubmitChangelist(context.Background(), &test.zone)
   748  			if test.withError != nil {
   749  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   750  				return
   751  			}
   752  			require.NoError(t, err)
   753  		})
   754  	}
   755  }
   756  
   757  func TestDns_UpdateZone(t *testing.T) {
   758  	tests := map[string]struct {
   759  		zone           ZoneCreate
   760  		query          ZoneQueryString
   761  		responseStatus int
   762  		responseBody   string
   763  		expectedPath   string
   764  		withError      error
   765  	}{
   766  		"200 OK": {
   767  			zone: ZoneCreate{
   768  				Zone:       "example.com",
   769  				ContractID: "1-2ABCDE",
   770  				Type:       "primary",
   771  			},
   772  			responseStatus: http.StatusOK,
   773  			responseBody: `
   774  			{
   775  				"contractId": "1-2ABCDE",
   776  				"zone": "other.com",
   777  				"type": "primary",
   778  				"aliasCount": 1,
   779  				"signAndServe": false,
   780  				"comment": "Initial add",
   781  				"versionId": "7949b2db-ac43-4773-a3ec-dc93202142fd",
   782  				"lastModifiedDate": "2016-12-11T03:21:00Z",
   783  				"lastModifiedBy": "user31",
   784  				"lastActivationDate": "2017-01-03T12:00:00Z",
   785  				"activationState": "ERROR",
   786  				"masters": [
   787  					"1.2.3.4",
   788  					"1.2.3.5"
   789  				],
   790  				"tsigKey": {
   791  					"name": "other.com.akamai.com.",
   792  					"algorithm": "hmac-sha512",
   793  					"secret": "Ok1qR5IW1ajVka5cHPEJQIXfLyx5V3PSkFBROAzOn21JumDq6nIpoj6H8rfj5Uo+Ok55ZWQ0Wgrf302fDscHLw=="
   794  				}
   795  			}`,
   796  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   797  		},
   798  		"500 internal server error": {
   799  			zone: ZoneCreate{
   800  				Zone:       "example.com",
   801  				ContractID: "1-2ABCDE",
   802  				Type:       "secondary",
   803  			},
   804  			responseStatus: http.StatusInternalServerError,
   805  			responseBody: `
   806  {
   807  	"type": "internal_error",
   808      "title": "Internal Server Error",
   809      "detail": "Error creating zone",
   810      "status": 500
   811  }`,
   812  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   813  			withError: &Error{
   814  				Type:       "internal_error",
   815  				Title:      "Internal Server Error",
   816  				Detail:     "Error creating zone",
   817  				StatusCode: http.StatusInternalServerError,
   818  			},
   819  		},
   820  	}
   821  
   822  	for name, test := range tests {
   823  		t.Run(name, func(t *testing.T) {
   824  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   825  				assert.Equal(t, http.MethodPut, r.Method)
   826  				w.WriteHeader(test.responseStatus)
   827  				if len(test.responseBody) > 0 {
   828  					_, err := w.Write([]byte(test.responseBody))
   829  					assert.NoError(t, err)
   830  				}
   831  			}))
   832  			client := mockAPIClient(t, mockServer)
   833  			err := client.UpdateZone(context.Background(), &test.zone, test.query)
   834  			if test.withError != nil {
   835  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   836  				return
   837  			}
   838  			require.NoError(t, err)
   839  		})
   840  	}
   841  }
   842  
   843  func TestDns_DeleteZone(t *testing.T) {
   844  	tests := map[string]struct {
   845  		zone           ZoneCreate
   846  		query          ZoneQueryString
   847  		responseStatus int
   848  		responseBody   string
   849  		expectedPath   string
   850  		withError      error
   851  	}{
   852  		"204 No Content": {
   853  			zone: ZoneCreate{
   854  				Zone:       "example.com",
   855  				ContractID: "1-2ABCDE",
   856  				Type:       "primary",
   857  			},
   858  			responseStatus: http.StatusNoContent,
   859  			expectedPath:   "/config-dns/v2/zones?contractId=1-2ABCDE",
   860  		},
   861  		"500 internal server error": {
   862  			zone: ZoneCreate{
   863  				Zone:       "example.com",
   864  				ContractID: "1-2ABCDE",
   865  				Type:       "secondary",
   866  			},
   867  			responseStatus: http.StatusInternalServerError,
   868  			responseBody: `
   869  {
   870  	"type": "internal_error",
   871      "title": "Internal Server Error",
   872      "detail": "Error creating zone",
   873      "status": 500
   874  }`,
   875  			expectedPath: "/config-dns/v2/zones?contractId=1-2ABCDE",
   876  			withError: &Error{
   877  				Type:       "internal_error",
   878  				Title:      "Internal Server Error",
   879  				Detail:     "Error creating zone",
   880  				StatusCode: http.StatusInternalServerError,
   881  			},
   882  		},
   883  	}
   884  
   885  	for name, test := range tests {
   886  		t.Run(name, func(t *testing.T) {
   887  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   888  				assert.Equal(t, http.MethodDelete, r.Method)
   889  				w.WriteHeader(test.responseStatus)
   890  				if len(test.responseBody) > 0 {
   891  					_, err := w.Write([]byte(test.responseBody))
   892  					assert.NoError(t, err)
   893  				}
   894  			}))
   895  			client := mockAPIClient(t, mockServer)
   896  			err := client.DeleteZone(context.Background(), &test.zone, test.query)
   897  			if test.withError != nil {
   898  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   899  				return
   900  			}
   901  			require.NoError(t, err)
   902  		})
   903  	}
   904  }
   905  
   906  func TestDns_GetZoneNames(t *testing.T) {
   907  	tests := map[string]struct {
   908  		zone             string
   909  		responseStatus   int
   910  		responseBody     string
   911  		expectedPath     string
   912  		expectedResponse *ZoneNamesResponse
   913  		withError        error
   914  	}{
   915  		"200 OK": {
   916  			zone:           "example.com",
   917  			responseStatus: http.StatusOK,
   918  			responseBody: `
   919  			{
   920  				"names": [
   921  					"example.com",
   922  					"www.example.com",
   923  					"ftp.example.com",
   924  					"space.example.com",
   925  					"bar.example.com"
   926  				]
   927  			}`,
   928  			expectedPath: "/config-dns/v2/zones/example.com/names",
   929  			expectedResponse: &ZoneNamesResponse{
   930  				Names: []string{"example.com", "www.example.com", "ftp.example.com", "space.example.com", "bar.example.com"},
   931  			},
   932  		},
   933  		"500 internal server error": {
   934  			zone:           "example.com",
   935  			responseStatus: http.StatusInternalServerError,
   936  			responseBody: `
   937  {
   938  	"type": "internal_error",
   939      "title": "Internal Server Error",
   940      "detail": "Error fetching authorities",
   941      "status": 500
   942  }`,
   943  			expectedPath: "/config-dns/v2/zones/example.com/names",
   944  			withError: &Error{
   945  				Type:       "internal_error",
   946  				Title:      "Internal Server Error",
   947  				Detail:     "Error fetching authorities",
   948  				StatusCode: http.StatusInternalServerError,
   949  			},
   950  		},
   951  	}
   952  
   953  	for name, test := range tests {
   954  		t.Run(name, func(t *testing.T) {
   955  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   956  				//assert.Equal(t, test.expectedPath, r.URL.String())
   957  				assert.Equal(t, http.MethodGet, r.Method)
   958  				w.WriteHeader(test.responseStatus)
   959  				_, err := w.Write([]byte(test.responseBody))
   960  				assert.NoError(t, err)
   961  			}))
   962  			client := mockAPIClient(t, mockServer)
   963  			result, err := client.GetZoneNames(context.Background(), test.zone)
   964  			if test.withError != nil {
   965  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
   966  				return
   967  			}
   968  			require.NoError(t, err)
   969  			assert.Equal(t, test.expectedResponse, result)
   970  		})
   971  	}
   972  }
   973  
   974  func TestDns_GetZoneNameTypes(t *testing.T) {
   975  	tests := map[string]struct {
   976  		zone             string
   977  		zname            string
   978  		responseStatus   int
   979  		responseBody     string
   980  		expectedPath     string
   981  		expectedResponse *ZoneNameTypesResponse
   982  		withError        error
   983  	}{
   984  		"200 OK": {
   985  			zone:           "example.com",
   986  			zname:          "names",
   987  			responseStatus: http.StatusOK,
   988  			responseBody: `
   989  			{
   990  				"types": [
   991  					"A",
   992  					"AAAA",
   993  					"MX"
   994  				]
   995  			}`,
   996  			expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types",
   997  			expectedResponse: &ZoneNameTypesResponse{
   998  				Types: []string{"A", "AAAA", "MX"},
   999  			},
  1000  		},
  1001  		"500 internal server error": {
  1002  			zone:           "example.com",
  1003  			zname:          "names",
  1004  			responseStatus: http.StatusInternalServerError,
  1005  			responseBody: `
  1006  {
  1007  	"type": "internal_error",
  1008      "title": "Internal Server Error",
  1009      "detail": "Error fetching authorities",
  1010      "status": 500
  1011  }`,
  1012  			expectedPath: "/config-dns/v2/zones/example.com/names/www.example.com/types",
  1013  			withError: &Error{
  1014  				Type:       "internal_error",
  1015  				Title:      "Internal Server Error",
  1016  				Detail:     "Error fetching authorities",
  1017  				StatusCode: http.StatusInternalServerError,
  1018  			},
  1019  		},
  1020  	}
  1021  
  1022  	for name, test := range tests {
  1023  		t.Run(name, func(t *testing.T) {
  1024  			mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  1025  				//assert.Equal(t, test.expectedPath, r.URL.String())
  1026  				assert.Equal(t, http.MethodGet, r.Method)
  1027  				w.WriteHeader(test.responseStatus)
  1028  				_, err := w.Write([]byte(test.responseBody))
  1029  				assert.NoError(t, err)
  1030  			}))
  1031  			client := mockAPIClient(t, mockServer)
  1032  			result, err := client.GetZoneNameTypes(context.Background(), test.zname, test.zone)
  1033  			if test.withError != nil {
  1034  				assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err)
  1035  				return
  1036  			}
  1037  			require.NoError(t, err)
  1038  			assert.Equal(t, test.expectedResponse, result)
  1039  		})
  1040  	}
  1041  }
  1042  
  1043  func Test_ValidateZoneErrors(t *testing.T) {
  1044  	client := Client(session.Must(session.New()))
  1045  
  1046  	tests := map[string]ZoneCreate{
  1047  		"empty zone": {},
  1048  		"bad type": {
  1049  			Zone: "example.com",
  1050  			Type: "BAD",
  1051  		},
  1052  		"secondary tsig": {
  1053  			Zone: "example.com",
  1054  			Type: "PRIMARY",
  1055  			TsigKey: &TSIGKey{
  1056  				Name: "example.com",
  1057  			},
  1058  		},
  1059  		"alias empty target": {
  1060  			Zone:   "example.com",
  1061  			Type:   "ALIAS",
  1062  			Target: "",
  1063  		},
  1064  		"alias masters": {
  1065  			Zone:    "example.com",
  1066  			Type:    "ALIAS",
  1067  			Target:  "10.0.0.1",
  1068  			Masters: []string{"master"},
  1069  		},
  1070  		"alias sign": {
  1071  			Zone:         "example.com",
  1072  			Type:         "ALIAS",
  1073  			Target:       "10.0.0.1",
  1074  			SignAndServe: true,
  1075  		},
  1076  		"alias sign algo": {
  1077  			Zone:                  "example.com",
  1078  			Type:                  "ALIAS",
  1079  			Target:                "10.0.0.1",
  1080  			SignAndServe:          false,
  1081  			SignAndServeAlgorithm: "foo",
  1082  		},
  1083  		"primary bad target": {
  1084  			Zone:   "example.com",
  1085  			Type:   "PRIMARY",
  1086  			Target: "10.0.0.1",
  1087  		},
  1088  		"primary bad masters": {
  1089  			Zone:    "example.com",
  1090  			Type:    "PRIMARY",
  1091  			Masters: []string{"foo"},
  1092  		},
  1093  	}
  1094  
  1095  	for name, test := range tests {
  1096  		t.Run(name, func(t *testing.T) {
  1097  			err := client.ValidateZone(context.Background(), &test)
  1098  			assert.NotNil(t, err)
  1099  		})
  1100  	}
  1101  }