sigs.k8s.io/external-dns@v0.14.1/provider/godaddy/godaddy_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package godaddy
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"sort"
    24  	"testing"
    25  
    26  	log "github.com/sirupsen/logrus"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/mock"
    29  	"sigs.k8s.io/external-dns/endpoint"
    30  	"sigs.k8s.io/external-dns/plan"
    31  )
    32  
    33  type mockGoDaddyClient struct {
    34  	mock.Mock
    35  	currentTest *testing.T
    36  }
    37  
    38  func newMockGoDaddyClient(t *testing.T) *mockGoDaddyClient {
    39  	return &mockGoDaddyClient{
    40  		currentTest: t,
    41  	}
    42  }
    43  
    44  var (
    45  	zoneNameExampleOrg string = "example.org"
    46  	zoneNameExampleNet string = "example.net"
    47  )
    48  
    49  func (c *mockGoDaddyClient) Post(endpoint string, input interface{}, output interface{}) error {
    50  	log.Infof("POST: %s - %v", endpoint, input)
    51  	stub := c.Called(endpoint, input)
    52  	data, _ := json.Marshal(stub.Get(0))
    53  	json.Unmarshal(data, output)
    54  	return stub.Error(1)
    55  }
    56  
    57  func (c *mockGoDaddyClient) Patch(endpoint string, input interface{}, output interface{}) error {
    58  	log.Infof("PATCH: %s - %v", endpoint, input)
    59  	stub := c.Called(endpoint, input)
    60  	data, _ := json.Marshal(stub.Get(0))
    61  	json.Unmarshal(data, output)
    62  	return stub.Error(1)
    63  }
    64  
    65  func (c *mockGoDaddyClient) Put(endpoint string, input interface{}, output interface{}) error {
    66  	log.Infof("PUT: %s - %v", endpoint, input)
    67  	stub := c.Called(endpoint, input)
    68  	data, _ := json.Marshal(stub.Get(0))
    69  	json.Unmarshal(data, output)
    70  	return stub.Error(1)
    71  }
    72  
    73  func (c *mockGoDaddyClient) Get(endpoint string, output interface{}) error {
    74  	log.Infof("GET: %s", endpoint)
    75  	stub := c.Called(endpoint)
    76  	data, _ := json.Marshal(stub.Get(0))
    77  	json.Unmarshal(data, output)
    78  	return stub.Error(1)
    79  }
    80  
    81  func (c *mockGoDaddyClient) Delete(endpoint string, output interface{}) error {
    82  	log.Infof("DELETE: %s", endpoint)
    83  	stub := c.Called(endpoint)
    84  	data, _ := json.Marshal(stub.Get(0))
    85  	json.Unmarshal(data, output)
    86  	return stub.Error(1)
    87  }
    88  
    89  func TestGoDaddyZones(t *testing.T) {
    90  	assert := assert.New(t)
    91  	client := newMockGoDaddyClient(t)
    92  	provider := &GDProvider{
    93  		client:       client,
    94  		domainFilter: endpoint.NewDomainFilter([]string{"com"}),
    95  	}
    96  
    97  	// Basic zones
    98  	client.On("Get", domainsURI).Return([]gdZone{
    99  		{
   100  			Domain: "example.com",
   101  		},
   102  		{
   103  			Domain: "example.net",
   104  		},
   105  	}, nil).Once()
   106  
   107  	domains, err := provider.zones()
   108  
   109  	assert.NoError(err)
   110  	assert.Contains(domains, "example.com")
   111  	assert.NotContains(domains, "example.net")
   112  
   113  	client.AssertExpectations(t)
   114  
   115  	// Error on getting zones
   116  	client.On("Get", domainsURI).Return(nil, ErrAPIDown).Once()
   117  	domains, err = provider.zones()
   118  	assert.Error(err)
   119  	assert.Nil(domains)
   120  	client.AssertExpectations(t)
   121  }
   122  
   123  func TestGoDaddyZoneRecords(t *testing.T) {
   124  	assert := assert.New(t)
   125  	client := newMockGoDaddyClient(t)
   126  	provider := &GDProvider{
   127  		client: client,
   128  	}
   129  
   130  	// Basic zones records
   131  	client.On("Get", domainsURI).Return([]gdZone{
   132  		{
   133  			Domain: zoneNameExampleNet,
   134  		},
   135  	}, nil).Once()
   136  
   137  	client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{
   138  		{
   139  			Name: "godaddy",
   140  			Type: "NS",
   141  			TTL:  gdMinimalTTL,
   142  			Data: "203.0.113.42",
   143  		},
   144  		{
   145  			Name: "godaddy",
   146  			Type: "A",
   147  			TTL:  gdMinimalTTL,
   148  			Data: "203.0.113.42",
   149  		},
   150  	}, nil).Once()
   151  
   152  	zones, records, err := provider.zonesRecords(context.TODO(), true)
   153  
   154  	assert.NoError(err)
   155  
   156  	assert.ElementsMatch(zones, []string{
   157  		zoneNameExampleNet,
   158  	})
   159  
   160  	assert.ElementsMatch(records, []gdRecords{
   161  		{
   162  			zone: zoneNameExampleNet,
   163  			records: []gdRecordField{
   164  				{
   165  					Name: "godaddy",
   166  					Type: "NS",
   167  					TTL:  gdMinimalTTL,
   168  					Data: "203.0.113.42",
   169  				},
   170  				{
   171  					Name: "godaddy",
   172  					Type: "A",
   173  					TTL:  gdMinimalTTL,
   174  					Data: "203.0.113.42",
   175  				},
   176  			},
   177  		},
   178  	})
   179  
   180  	client.AssertExpectations(t)
   181  
   182  	// Error on getting zones list
   183  	client.On("Get", domainsURI).Return(nil, ErrAPIDown).Once()
   184  	zones, records, err = provider.zonesRecords(context.TODO(), false)
   185  	assert.Error(err)
   186  	assert.Nil(zones)
   187  	assert.Nil(records)
   188  	client.AssertExpectations(t)
   189  
   190  	// Error on getting zone records
   191  	client.On("Get", domainsURI).Return([]gdZone{
   192  		{
   193  			Domain: zoneNameExampleNet,
   194  		},
   195  	}, nil).Once()
   196  
   197  	client.On("Get", "/v1/domains/example.net/records").Return(nil, ErrAPIDown).Once()
   198  
   199  	zones, records, err = provider.zonesRecords(context.TODO(), false)
   200  
   201  	assert.Error(err)
   202  	assert.Nil(zones)
   203  	assert.Nil(records)
   204  	client.AssertExpectations(t)
   205  
   206  	// Error on getting zone record detail
   207  	client.On("Get", domainsURI).Return([]gdZone{
   208  		{
   209  			Domain: zoneNameExampleNet,
   210  		},
   211  	}, nil).Once()
   212  
   213  	client.On("Get", "/v1/domains/example.net/records").Return(nil, ErrAPIDown).Once()
   214  
   215  	zones, records, err = provider.zonesRecords(context.TODO(), false)
   216  	assert.Error(err)
   217  	assert.Nil(zones)
   218  	assert.Nil(records)
   219  	client.AssertExpectations(t)
   220  }
   221  
   222  func TestGoDaddyRecords(t *testing.T) {
   223  	assert := assert.New(t)
   224  	client := newMockGoDaddyClient(t)
   225  	provider := &GDProvider{
   226  		client: client,
   227  	}
   228  
   229  	// Basic zones records
   230  	client.On("Get", domainsURI).Return([]gdZone{
   231  		{
   232  			Domain: zoneNameExampleOrg,
   233  		},
   234  		{
   235  			Domain: zoneNameExampleNet,
   236  		},
   237  	}, nil).Once()
   238  
   239  	client.On("Get", "/v1/domains/example.org/records").Return([]gdRecordField{
   240  		{
   241  			Name: "@",
   242  			Type: "A",
   243  			TTL:  gdMinimalTTL,
   244  			Data: "203.0.113.42",
   245  		},
   246  		{
   247  			Name: "www",
   248  			Type: "CNAME",
   249  			TTL:  gdMinimalTTL,
   250  			Data: "example.org",
   251  		},
   252  	}, nil).Once()
   253  
   254  	client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{
   255  		{
   256  			Name: "godaddy",
   257  			Type: "A",
   258  			TTL:  gdMinimalTTL,
   259  			Data: "203.0.113.42",
   260  		},
   261  		{
   262  			Name: "godaddy",
   263  			Type: "A",
   264  			TTL:  gdMinimalTTL,
   265  			Data: "203.0.113.43",
   266  		},
   267  	}, nil).Once()
   268  
   269  	endpoints, err := provider.Records(context.TODO())
   270  	assert.NoError(err)
   271  
   272  	// Little fix for multi targets endpoint
   273  	for _, endpoint := range endpoints {
   274  		sort.Strings(endpoint.Targets)
   275  	}
   276  
   277  	assert.ElementsMatch(endpoints, []*endpoint.Endpoint{
   278  		{
   279  			DNSName:    "godaddy.example.net",
   280  			RecordType: "A",
   281  			RecordTTL:  gdMinimalTTL,
   282  			Labels:     endpoint.NewLabels(),
   283  			Targets: []string{
   284  				"203.0.113.42",
   285  				"203.0.113.43",
   286  			},
   287  		},
   288  		{
   289  			DNSName:    "example.org",
   290  			RecordType: "A",
   291  			RecordTTL:  gdMinimalTTL,
   292  			Labels:     endpoint.NewLabels(),
   293  			Targets: []string{
   294  				"203.0.113.42",
   295  			},
   296  		},
   297  		{
   298  			DNSName:    "www.example.org",
   299  			RecordType: "CNAME",
   300  			RecordTTL:  gdMinimalTTL,
   301  			Labels:     endpoint.NewLabels(),
   302  			Targets: []string{
   303  				"example.org",
   304  			},
   305  		},
   306  	})
   307  
   308  	client.AssertExpectations(t)
   309  
   310  	// Error getting zone
   311  	client.On("Get", domainsURI).Return(nil, ErrAPIDown).Once()
   312  	endpoints, err = provider.Records(context.TODO())
   313  	assert.Error(err)
   314  	assert.Nil(endpoints)
   315  	client.AssertExpectations(t)
   316  }
   317  
   318  func TestGoDaddyChange(t *testing.T) {
   319  	assert := assert.New(t)
   320  	client := newMockGoDaddyClient(t)
   321  	provider := &GDProvider{
   322  		client: client,
   323  	}
   324  
   325  	changes := plan.Changes{
   326  		Create: []*endpoint.Endpoint{
   327  			{
   328  				DNSName:    ".example.net",
   329  				RecordType: "A",
   330  				RecordTTL:  gdMinimalTTL,
   331  				Targets: []string{
   332  					"203.0.113.42",
   333  				},
   334  			},
   335  		},
   336  		Delete: []*endpoint.Endpoint{
   337  			{
   338  				DNSName:    "godaddy.example.net",
   339  				RecordType: "A",
   340  				Targets: []string{
   341  					"203.0.113.43",
   342  				},
   343  			},
   344  		},
   345  	}
   346  
   347  	// Fetch domains
   348  	client.On("Get", domainsURI).Return([]gdZone{
   349  		{
   350  			Domain: zoneNameExampleNet,
   351  		},
   352  	}, nil).Once()
   353  
   354  	// Fetch record
   355  	client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{
   356  		{
   357  			Name: "godaddy",
   358  			Type: "A",
   359  			TTL:  gdMinimalTTL,
   360  			Data: "203.0.113.43",
   361  		},
   362  	}, nil).Once()
   363  
   364  	// Add entry
   365  	client.On("Patch", "/v1/domains/example.net/records", []gdRecordField{
   366  		{
   367  			Name: "@",
   368  			Type: "A",
   369  			TTL:  gdMinimalTTL,
   370  			Data: "203.0.113.42",
   371  		},
   372  	}).Return(nil, nil).Once()
   373  
   374  	// Delete entry
   375  	client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(nil, nil).Once()
   376  
   377  	assert.NoError(provider.ApplyChanges(context.TODO(), &changes))
   378  
   379  	client.AssertExpectations(t)
   380  }
   381  
   382  const (
   383  	operationFailedTestErrCode = "GD500"
   384  	operationFailedTestReason  = "Could not apply request"
   385  	recordNotFoundErrCode      = "GD404"
   386  	recordNotFoundReason       = "The requested record is not found in DNS zone"
   387  )
   388  
   389  func TestGoDaddyErrorResponse(t *testing.T) {
   390  	assert := assert.New(t)
   391  	client := newMockGoDaddyClient(t)
   392  	provider := &GDProvider{
   393  		client: client,
   394  	}
   395  
   396  	changes := plan.Changes{
   397  		Create: []*endpoint.Endpoint{
   398  			{
   399  				DNSName:    ".example.net",
   400  				RecordType: "A",
   401  				RecordTTL:  gdMinimalTTL,
   402  				Targets: []string{
   403  					"203.0.113.42",
   404  				},
   405  			},
   406  		},
   407  		Delete: []*endpoint.Endpoint{
   408  			{
   409  				DNSName:    "godaddy.example.net",
   410  				RecordType: "A",
   411  				Targets: []string{
   412  					"203.0.113.43",
   413  				},
   414  			},
   415  		},
   416  	}
   417  
   418  	// Fetch domains
   419  	client.On("Get", domainsURI).Return([]gdZone{
   420  		{
   421  			Domain: zoneNameExampleNet,
   422  		},
   423  	}, nil).Once()
   424  
   425  	// Fetch record
   426  	client.On("Get", "/v1/domains/example.net/records").Return([]gdRecordField{
   427  		{
   428  			Name: "godaddy",
   429  			Type: "A",
   430  			TTL:  gdMinimalTTL,
   431  			Data: "203.0.113.43",
   432  		},
   433  	}, nil).Once()
   434  
   435  	// Delete entry
   436  	client.On("Delete", "/v1/domains/example.net/records/A/godaddy").Return(GDErrorResponse{
   437  		Code:    operationFailedTestErrCode,
   438  		Message: operationFailedTestReason,
   439  		Fields: []GDErrorField{{
   440  			Code:    recordNotFoundErrCode,
   441  			Message: recordNotFoundReason,
   442  		}},
   443  	}, errors.New(operationFailedTestReason)).Once()
   444  
   445  	assert.Error(provider.ApplyChanges(context.TODO(), &changes))
   446  
   447  	client.AssertExpectations(t)
   448  }