sigs.k8s.io/external-dns@v0.14.1/provider/ovh/ovh_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 ovh 18 19 import ( 20 "context" 21 "encoding/json" 22 "errors" 23 "sort" 24 "testing" 25 "time" 26 27 "github.com/miekg/dns" 28 "github.com/ovh/go-ovh/ovh" 29 "github.com/patrickmn/go-cache" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/mock" 32 "go.uber.org/ratelimit" 33 "sigs.k8s.io/external-dns/endpoint" 34 "sigs.k8s.io/external-dns/plan" 35 ) 36 37 type mockOvhClient struct { 38 mock.Mock 39 } 40 41 func (c *mockOvhClient) Post(endpoint string, input interface{}, output interface{}) error { 42 stub := c.Called(endpoint, input) 43 data, _ := json.Marshal(stub.Get(0)) 44 json.Unmarshal(data, output) 45 return stub.Error(1) 46 } 47 48 func (c *mockOvhClient) Get(endpoint string, output interface{}) error { 49 stub := c.Called(endpoint) 50 data, _ := json.Marshal(stub.Get(0)) 51 json.Unmarshal(data, output) 52 return stub.Error(1) 53 } 54 55 func (c *mockOvhClient) Delete(endpoint string, output interface{}) error { 56 stub := c.Called(endpoint) 57 data, _ := json.Marshal(stub.Get(0)) 58 json.Unmarshal(data, output) 59 return stub.Error(1) 60 } 61 62 type mockDnsClient struct { 63 mock.Mock 64 } 65 66 func (c *mockDnsClient) ExchangeContext(ctx context.Context, m *dns.Msg, addr string) (*dns.Msg, time.Duration, error) { 67 args := c.Called(ctx, m, addr) 68 69 msg := args.Get(0).(*dns.Msg) 70 err := args.Error(1) 71 72 return msg, time.Duration(0), err 73 } 74 75 func TestOvhZones(t *testing.T) { 76 assert := assert.New(t) 77 client := new(mockOvhClient) 78 provider := &OVHProvider{ 79 client: client, 80 apiRateLimiter: ratelimit.New(10), 81 domainFilter: endpoint.NewDomainFilter([]string{"com"}), 82 cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration), 83 dnsClient: new(mockDnsClient), 84 } 85 86 // Basic zones 87 client.On("Get", "/domain/zone").Return([]string{"example.com", "example.net"}, nil).Once() 88 domains, err := provider.zones() 89 assert.NoError(err) 90 assert.Contains(domains, "example.com") 91 assert.NotContains(domains, "example.net") 92 client.AssertExpectations(t) 93 94 // Error on getting zones 95 client.On("Get", "/domain/zone").Return(nil, ovh.ErrAPIDown).Once() 96 domains, err = provider.zones() 97 assert.Error(err) 98 assert.Nil(domains) 99 client.AssertExpectations(t) 100 } 101 102 func TestOvhZoneRecords(t *testing.T) { 103 assert := assert.New(t) 104 client := new(mockOvhClient) 105 provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10), cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration), dnsClient: nil, UseCache: true} 106 107 // Basic zones records 108 t.Log("Basic zones records") 109 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 110 client.On("Get", "/domain/zone/example.org/soa").Return(ovhSoa{Server: "ns.example.org.", Serial: 2022090901}, nil).Once() 111 client.On("Get", "/domain/zone/example.org/record").Return([]uint64{24, 42}, nil).Once() 112 client.On("Get", "/domain/zone/example.org/record/24").Return(ovhRecord{ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 113 client.On("Get", "/domain/zone/example.org/record/42").Return(ovhRecord{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 114 zones, records, err := provider.zonesRecords(context.TODO()) 115 assert.NoError(err) 116 assert.ElementsMatch(zones, []string{"example.org"}) 117 assert.ElementsMatch(records, []ovhRecord{{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, {ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}}) 118 client.AssertExpectations(t) 119 120 // Error on getting zones list 121 t.Log("Error on getting zones list") 122 client.On("Get", "/domain/zone").Return(nil, ovh.ErrAPIDown).Once() 123 zones, records, err = provider.zonesRecords(context.TODO()) 124 assert.Error(err) 125 assert.Nil(zones) 126 assert.Nil(records) 127 client.AssertExpectations(t) 128 129 // Error on getting zone SOA 130 t.Log("Error on getting zone SOA") 131 provider.cacheInstance = cache.New(cache.NoExpiration, cache.NoExpiration) 132 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 133 client.On("Get", "/domain/zone/example.org/soa").Return(nil, ovh.ErrAPIDown).Once() 134 zones, records, err = provider.zonesRecords(context.TODO()) 135 assert.Error(err) 136 assert.Nil(zones) 137 assert.Nil(records) 138 client.AssertExpectations(t) 139 140 // Error on getting zone records 141 t.Log("Error on getting zone records") 142 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 143 client.On("Get", "/domain/zone/example.org/soa").Return(ovhSoa{Server: "ns.example.org.", Serial: 2022090902}, nil).Once() 144 client.On("Get", "/domain/zone/example.org/record").Return(nil, ovh.ErrAPIDown).Once() 145 zones, records, err = provider.zonesRecords(context.TODO()) 146 assert.Error(err) 147 assert.Nil(zones) 148 assert.Nil(records) 149 client.AssertExpectations(t) 150 151 // Error on getting zone record detail 152 t.Log("Error on getting zone record detail") 153 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 154 client.On("Get", "/domain/zone/example.org/soa").Return(ovhSoa{Server: "ns.example.org.", Serial: 2022090902}, nil).Once() 155 client.On("Get", "/domain/zone/example.org/record").Return([]uint64{42}, nil).Once() 156 client.On("Get", "/domain/zone/example.org/record/42").Return(nil, ovh.ErrAPIDown).Once() 157 zones, records, err = provider.zonesRecords(context.TODO()) 158 assert.Error(err) 159 assert.Nil(zones) 160 assert.Nil(records) 161 client.AssertExpectations(t) 162 } 163 164 func TestOvhZoneRecordsCache(t *testing.T) { 165 assert := assert.New(t) 166 client := new(mockOvhClient) 167 dnsClient := new(mockDnsClient) 168 provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10), cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration), dnsClient: dnsClient, UseCache: true} 169 170 // First call, cache miss 171 t.Log("First call, cache miss") 172 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 173 client.On("Get", "/domain/zone/example.org/soa").Return(ovhSoa{Server: "ns.example.org.", Serial: 2022090901}, nil).Once() 174 client.On("Get", "/domain/zone/example.org/record").Return([]uint64{24, 42}, nil).Once() 175 client.On("Get", "/domain/zone/example.org/record/24").Return(ovhRecord{ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 176 client.On("Get", "/domain/zone/example.org/record/42").Return(ovhRecord{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 177 178 zones, records, err := provider.zonesRecords(context.TODO()) 179 assert.NoError(err) 180 assert.ElementsMatch(zones, []string{"example.org"}) 181 assert.ElementsMatch(records, []ovhRecord{{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, {ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}}) 182 client.AssertExpectations(t) 183 dnsClient.AssertExpectations(t) 184 185 // reset mock 186 client = new(mockOvhClient) 187 dnsClient = new(mockDnsClient) 188 provider.client, provider.dnsClient = client, dnsClient 189 190 // second call, cache hit 191 t.Log("second call, cache hit") 192 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 193 dnsClient.On("ExchangeContext", mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("*dns.Msg"), "ns.example.org:53"). 194 Return(&dns.Msg{Answer: []dns.RR{&dns.SOA{Serial: 2022090901}}}, nil) 195 zones, records, err = provider.zonesRecords(context.TODO()) 196 assert.NoError(err) 197 assert.ElementsMatch(zones, []string{"example.org"}) 198 assert.ElementsMatch(records, []ovhRecord{{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, {ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}}) 199 client.AssertExpectations(t) 200 dnsClient.AssertExpectations(t) 201 202 // reset mock 203 client = new(mockOvhClient) 204 dnsClient = new(mockDnsClient) 205 provider.client, provider.dnsClient = client, dnsClient 206 207 // third call, cache out of date 208 t.Log("third call, cache out of date") 209 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 210 dnsClient.On("ExchangeContext", mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("*dns.Msg"), "ns.example.org:53"). 211 Return(&dns.Msg{Answer: []dns.RR{&dns.SOA{Serial: 2022090902}}}, nil) 212 client.On("Get", "/domain/zone/example.org/soa").Return(ovhSoa{Server: "ns.example.org.", Serial: 2022090902}, nil).Once() 213 client.On("Get", "/domain/zone/example.org/record").Return([]uint64{24}, nil).Once() 214 client.On("Get", "/domain/zone/example.org/record/24").Return(ovhRecord{ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 215 216 zones, records, err = provider.zonesRecords(context.TODO()) 217 assert.NoError(err) 218 assert.ElementsMatch(zones, []string{"example.org"}) 219 assert.ElementsMatch(records, []ovhRecord{{ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}}) 220 client.AssertExpectations(t) 221 dnsClient.AssertExpectations(t) 222 223 // reset mock 224 client = new(mockOvhClient) 225 dnsClient = new(mockDnsClient) 226 provider.client, provider.dnsClient = client, dnsClient 227 228 // fourth call, cache hit 229 t.Log("fourth call, cache hit") 230 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 231 dnsClient.On("ExchangeContext", mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("*dns.Msg"), "ns.example.org:53"). 232 Return(&dns.Msg{Answer: []dns.RR{&dns.SOA{Serial: 2022090902}}}, nil) 233 234 zones, records, err = provider.zonesRecords(context.TODO()) 235 assert.NoError(err) 236 assert.ElementsMatch(zones, []string{"example.org"}) 237 assert.ElementsMatch(records, []ovhRecord{{ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}}) 238 client.AssertExpectations(t) 239 dnsClient.AssertExpectations(t) 240 241 // reset mock 242 client = new(mockOvhClient) 243 dnsClient = new(mockDnsClient) 244 provider.client, provider.dnsClient = client, dnsClient 245 246 // fifth call, dns issue 247 t.Log("fourth call, cache hit") 248 client.On("Get", "/domain/zone").Return([]string{"example.org"}, nil).Once() 249 dnsClient.On("ExchangeContext", mock.AnythingOfType("*context.cancelCtx"), mock.AnythingOfType("*dns.Msg"), "ns.example.org:53"). 250 Return(&dns.Msg{Answer: []dns.RR{}}, errors.New("dns issue")) 251 client.On("Get", "/domain/zone/example.org/soa").Return(ovhSoa{Server: "ns.example.org.", Serial: 2022090903}, nil).Once() 252 client.On("Get", "/domain/zone/example.org/record").Return([]uint64{24, 42}, nil).Once() 253 client.On("Get", "/domain/zone/example.org/record/24").Return(ovhRecord{ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 254 client.On("Get", "/domain/zone/example.org/record/42").Return(ovhRecord{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 255 256 zones, records, err = provider.zonesRecords(context.TODO()) 257 assert.NoError(err) 258 assert.ElementsMatch(zones, []string{"example.org"}) 259 assert.ElementsMatch(records, []ovhRecord{{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, {ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "NS", TTL: 10, Target: "203.0.113.42"}}}) 260 client.AssertExpectations(t) 261 dnsClient.AssertExpectations(t) 262 } 263 264 func TestOvhRecords(t *testing.T) { 265 assert := assert.New(t) 266 client := new(mockOvhClient) 267 provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10), cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration)} 268 269 // Basic zones records 270 client.On("Get", "/domain/zone").Return([]string{"example.org", "example.net"}, nil).Once() 271 client.On("Get", "/domain/zone/example.org/record").Return([]uint64{24, 42}, nil).Once() 272 client.On("Get", "/domain/zone/example.org/record/24").Return(ovhRecord{ID: 24, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 273 client.On("Get", "/domain/zone/example.org/record/42").Return(ovhRecord{ID: 42, Zone: "example.org", ovhRecordFields: ovhRecordFields{SubDomain: "www", FieldType: "CNAME", TTL: 10, Target: "example.org."}}, nil).Once() 274 client.On("Get", "/domain/zone/example.net/record").Return([]uint64{24, 42}, nil).Once() 275 client.On("Get", "/domain/zone/example.net/record/24").Return(ovhRecord{ID: 24, Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}, nil).Once() 276 client.On("Get", "/domain/zone/example.net/record/42").Return(ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.43"}}, nil).Once() 277 endpoints, err := provider.Records(context.TODO()) 278 assert.NoError(err) 279 // Little fix for multi targets endpoint 280 for _, endpoint := range endpoints { 281 sort.Strings(endpoint.Targets) 282 } 283 assert.ElementsMatch(endpoints, []*endpoint.Endpoint{ 284 {DNSName: "example.org", RecordType: "A", RecordTTL: 10, Labels: endpoint.NewLabels(), Targets: []string{"203.0.113.42"}}, 285 {DNSName: "www.example.org", RecordType: "CNAME", RecordTTL: 10, Labels: endpoint.NewLabels(), Targets: []string{"example.org"}}, 286 {DNSName: "ovh.example.net", RecordType: "A", RecordTTL: 10, Labels: endpoint.NewLabels(), Targets: []string{"203.0.113.42", "203.0.113.43"}}, 287 }) 288 client.AssertExpectations(t) 289 290 // Error getting zone 291 client.On("Get", "/domain/zone").Return(nil, ovh.ErrAPIDown).Once() 292 endpoints, err = provider.Records(context.TODO()) 293 assert.Error(err) 294 assert.Nil(endpoints) 295 client.AssertExpectations(t) 296 } 297 298 func TestOvhRefresh(t *testing.T) { 299 client := new(mockOvhClient) 300 provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10), cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration)} 301 302 // Basic zone refresh 303 client.On("Post", "/domain/zone/example.net/refresh", nil).Return(nil, nil).Once() 304 provider.refresh("example.net") 305 client.AssertExpectations(t) 306 } 307 308 func TestOvhNewChange(t *testing.T) { 309 assert := assert.New(t) 310 endpoints := []*endpoint.Endpoint{ 311 {DNSName: ".example.net", RecordType: "A", RecordTTL: 10, Targets: []string{"203.0.113.42"}}, 312 {DNSName: "ovh.example.net", RecordType: "A", Targets: []string{"203.0.113.43"}}, 313 {DNSName: "ovh2.example.net", RecordType: "CNAME", Targets: []string{"ovh.example.net"}}, 314 {DNSName: "test.example.org"}, 315 } 316 317 // Create change 318 changes := newOvhChange(ovhCreate, endpoints, []string{"example.net"}, []ovhRecord{}) 319 assert.ElementsMatch(changes, []ovhChange{ 320 {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "", FieldType: "A", TTL: 10, Target: "203.0.113.42"}}}, 321 {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: ovhDefaultTTL, Target: "203.0.113.43"}}}, 322 {Action: ovhCreate, ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh2", FieldType: "CNAME", TTL: ovhDefaultTTL, Target: "ovh.example.net."}}}, 323 }) 324 325 // Delete change 326 endpoints = []*endpoint.Endpoint{ 327 {DNSName: "ovh.example.net", RecordType: "A", Targets: []string{"203.0.113.42"}}, 328 } 329 records := []ovhRecord{ 330 {ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{FieldType: "A", SubDomain: "ovh", Target: "203.0.113.42"}}, 331 } 332 changes = newOvhChange(ovhDelete, endpoints, []string{"example.net"}, records) 333 assert.ElementsMatch(changes, []ovhChange{ 334 {Action: ovhDelete, ovhRecord: ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: ovhDefaultTTL, Target: "203.0.113.42"}}}, 335 }) 336 } 337 338 func TestOvhApplyChanges(t *testing.T) { 339 assert := assert.New(t) 340 client := new(mockOvhClient) 341 provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10), cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration)} 342 changes := plan.Changes{ 343 Create: []*endpoint.Endpoint{ 344 {DNSName: ".example.net", RecordType: "A", RecordTTL: 10, Targets: []string{"203.0.113.42"}}, 345 }, 346 Delete: []*endpoint.Endpoint{ 347 {DNSName: "ovh.example.net", RecordType: "A", Targets: []string{"203.0.113.43"}}, 348 }, 349 } 350 351 client.On("Get", "/domain/zone").Return([]string{"example.net"}, nil).Once() 352 client.On("Get", "/domain/zone/example.net/record").Return([]uint64{42}, nil).Once() 353 client.On("Get", "/domain/zone/example.net/record/42").Return(ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh", FieldType: "A", TTL: 10, Target: "203.0.113.43"}}, nil).Once() 354 client.On("Post", "/domain/zone/example.net/record", ovhRecordFields{SubDomain: "", FieldType: "A", TTL: 10, Target: "203.0.113.42"}).Return(nil, nil).Once() 355 client.On("Delete", "/domain/zone/example.net/record/42").Return(nil, nil).Once() 356 client.On("Post", "/domain/zone/example.net/refresh", nil).Return(nil, nil).Once() 357 358 // Basic changes 359 assert.NoError(provider.ApplyChanges(context.TODO(), &changes)) 360 client.AssertExpectations(t) 361 362 // Getting zones failed 363 client.On("Get", "/domain/zone").Return(nil, ovh.ErrAPIDown).Once() 364 assert.Error(provider.ApplyChanges(context.TODO(), &changes)) 365 client.AssertExpectations(t) 366 367 // Apply change failed 368 client.On("Get", "/domain/zone").Return([]string{"example.net"}, nil).Once() 369 client.On("Get", "/domain/zone/example.net/record").Return([]uint64{}, nil).Once() 370 client.On("Post", "/domain/zone/example.net/record", ovhRecordFields{SubDomain: "", FieldType: "A", TTL: 10, Target: "203.0.113.42"}).Return(nil, ovh.ErrAPIDown).Once() 371 assert.Error(provider.ApplyChanges(context.TODO(), &plan.Changes{ 372 Create: []*endpoint.Endpoint{ 373 {DNSName: ".example.net", RecordType: "A", RecordTTL: 10, Targets: []string{"203.0.113.42"}}, 374 }, 375 })) 376 client.AssertExpectations(t) 377 378 // Refresh failed 379 client.On("Get", "/domain/zone").Return([]string{"example.net"}, nil).Once() 380 client.On("Get", "/domain/zone/example.net/record").Return([]uint64{}, nil).Once() 381 client.On("Post", "/domain/zone/example.net/record", ovhRecordFields{SubDomain: "", FieldType: "A", TTL: 10, Target: "203.0.113.42"}).Return(nil, nil).Once() 382 client.On("Post", "/domain/zone/example.net/refresh", nil).Return(nil, ovh.ErrAPIDown).Once() 383 assert.Error(provider.ApplyChanges(context.TODO(), &plan.Changes{ 384 Create: []*endpoint.Endpoint{ 385 {DNSName: ".example.net", RecordType: "A", RecordTTL: 10, Targets: []string{"203.0.113.42"}}, 386 }, 387 })) 388 client.AssertExpectations(t) 389 } 390 391 func TestOvhChange(t *testing.T) { 392 assert := assert.New(t) 393 client := new(mockOvhClient) 394 provider := &OVHProvider{client: client, apiRateLimiter: ratelimit.New(10), cacheInstance: cache.New(cache.NoExpiration, cache.NoExpiration)} 395 396 // Record creation 397 client.On("Post", "/domain/zone/example.net/record", ovhRecordFields{SubDomain: "ovh"}).Return(nil, nil).Once() 398 assert.NoError(provider.change(ovhChange{ 399 Action: ovhCreate, 400 ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh"}}, 401 })) 402 client.AssertExpectations(t) 403 404 // Record deletion 405 client.On("Delete", "/domain/zone/example.net/record/42").Return(nil, nil).Once() 406 assert.NoError(provider.change(ovhChange{ 407 Action: ovhDelete, 408 ovhRecord: ovhRecord{ID: 42, Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh"}}, 409 })) 410 client.AssertExpectations(t) 411 412 // Record deletion error 413 assert.Error(provider.change(ovhChange{ 414 Action: ovhDelete, 415 ovhRecord: ovhRecord{Zone: "example.net", ovhRecordFields: ovhRecordFields{SubDomain: "ovh"}}, 416 })) 417 client.AssertExpectations(t) 418 } 419 420 func TestOvhCountTargets(t *testing.T) { 421 cases := []struct { 422 endpoints [][]*endpoint.Endpoint 423 count int 424 }{ 425 {[][]*endpoint.Endpoint{{{DNSName: "ovh.example.net", Targets: endpoint.Targets{"target"}}}}, 1}, 426 {[][]*endpoint.Endpoint{{{DNSName: "ovh.example.net", Targets: endpoint.Targets{"target"}}, {DNSName: "ovh.example.net", Targets: endpoint.Targets{"target"}}}}, 2}, 427 {[][]*endpoint.Endpoint{{{DNSName: "ovh.example.net", Targets: endpoint.Targets{"target", "target", "target"}}}}, 3}, 428 {[][]*endpoint.Endpoint{{{DNSName: "ovh.example.net", Targets: endpoint.Targets{"target", "target"}}}, {{DNSName: "ovh.example.net", Targets: endpoint.Targets{"target", "target"}}}}, 4}, 429 } 430 for _, test := range cases { 431 count := countTargets(test.endpoints...) 432 if count != test.count { 433 t.Errorf("Wrong targets counts (Should be %d, get %d)", test.count, count) 434 } 435 } 436 }