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 }