sigs.k8s.io/external-dns@v0.14.1/provider/rcode0/rcode0_test.go (about) 1 /* 2 Copyright 2019 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 rcode0 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "testing" 24 25 rc0 "github.com/nic-at/rc0go" 26 "github.com/stretchr/testify/require" 27 28 "sigs.k8s.io/external-dns/endpoint" 29 "sigs.k8s.io/external-dns/plan" 30 ) 31 32 const ( 33 testZoneOne = "testzone1.at" 34 testZoneTwo = "testzone2.at" 35 36 rrsetChangesUnsupportedChangeType = 0 37 ) 38 39 type mockRcodeZeroClient rc0.Client 40 41 type mockZoneManagementService struct { 42 TestNilZonesReturned bool 43 TestErrorReturned bool 44 } 45 46 type mockRRSetService struct { 47 TestErrorReturned bool 48 } 49 50 func (m *mockZoneManagementService) resetTestConditions() { 51 m.TestNilZonesReturned = false 52 m.TestErrorReturned = false 53 } 54 55 func TestRcodeZeroProvider_Records(t *testing.T) { 56 mockRRSetService := &mockRRSetService{} 57 mockZoneManagementService := &mockZoneManagementService{} 58 59 provider := &RcodeZeroProvider{ 60 Client: (*rc0.Client)(&mockRcodeZeroClient{ 61 Zones: mockZoneManagementService, 62 RRSet: mockRRSetService, 63 }), 64 } 65 66 ctx := context.Background() 67 68 endpoints, err := provider.Records(ctx) // should return 6 rrs 69 if err != nil { 70 t.Errorf("should not fail, %s", err) 71 } 72 require.Equal(t, 10, len(endpoints)) 73 74 mockRRSetService.TestErrorReturned = true 75 76 _, err = provider.Records(ctx) 77 if err == nil { 78 t.Errorf("expected to fail, %s", err) 79 } 80 } 81 82 func TestRcodeZeroProvider_ApplyChanges(t *testing.T) { 83 mockRRSetService := &mockRRSetService{} 84 mockZoneManagementService := &mockZoneManagementService{} 85 86 provider := &RcodeZeroProvider{ 87 Client: (*rc0.Client)(&mockRcodeZeroClient{ 88 Zones: mockZoneManagementService, 89 RRSet: mockRRSetService, 90 }), 91 DomainFilter: endpoint.NewDomainFilter([]string{testZoneOne}), 92 } 93 94 changes := mockChanges() 95 96 err := provider.ApplyChanges(context.Background(), changes) 97 if err != nil { 98 t.Errorf("should not fail, %s", err) 99 } 100 } 101 102 func TestRcodeZeroProvider_NewRcodezeroChanges(t *testing.T) { 103 provider := &RcodeZeroProvider{} 104 105 changes := mockChanges() 106 107 createChanges := provider.NewRcodezeroChanges(testZoneOne, changes.Create) 108 require.Equal(t, 4, len(createChanges)) 109 110 deleteChanges := provider.NewRcodezeroChanges(testZoneOne, changes.Delete) 111 require.Equal(t, 1, len(deleteChanges)) 112 113 updateOldChanges := provider.NewRcodezeroChanges(testZoneOne, changes.UpdateOld) 114 require.Equal(t, 1, len(updateOldChanges)) 115 116 updateNewChanges := provider.NewRcodezeroChanges(testZoneOne, changes.UpdateNew) 117 require.Equal(t, 1, len(updateNewChanges)) 118 } 119 120 func TestRcodeZeroProvider_NewRcodezeroChange(t *testing.T) { 121 _endpoint := &endpoint.Endpoint{ 122 RecordType: "A", 123 DNSName: "app." + testZoneOne, 124 RecordTTL: 300, 125 Targets: endpoint.Targets{"target"}, 126 } 127 128 provider := &RcodeZeroProvider{} 129 130 rrsetChange := provider.NewRcodezeroChange(testZoneOne, _endpoint) 131 132 require.Equal(t, _endpoint.RecordType, rrsetChange.Type) 133 require.Equal(t, _endpoint.DNSName, rrsetChange.Name) 134 require.Equal(t, _endpoint.Targets[0], rrsetChange.Records[0].Content) 135 // require.Equal(t, endpoint.RecordTTL, rrsetChange.TTL) 136 } 137 138 func Test_submitChanges(t *testing.T) { 139 mockRRSetService := &mockRRSetService{} 140 mockZoneManagementService := &mockZoneManagementService{} 141 142 provider := &RcodeZeroProvider{ 143 Client: (*rc0.Client)(&mockRcodeZeroClient{ 144 Zones: mockZoneManagementService, 145 RRSet: mockRRSetService, 146 }), 147 DomainFilter: endpoint.NewDomainFilter([]string{testZoneOne}), 148 } 149 150 changes := mockRRSetChanges(rrsetChangesUnsupportedChangeType) 151 152 err := provider.submitChanges(changes) 153 154 if err == nil { 155 t.Errorf("expected to fail, %s", err) 156 } 157 } 158 159 func mockRRSetChanges(condition int) []*rc0.RRSetChange { 160 switch condition { 161 case rrsetChangesUnsupportedChangeType: 162 return []*rc0.RRSetChange{ 163 { 164 Name: testZoneOne, 165 Type: "A", 166 ChangeType: "UNSUPPORTED", 167 Records: []*rc0.Record{{Content: "fail"}}, 168 }, 169 } 170 default: 171 return nil 172 } 173 } 174 175 func mockChanges() *plan.Changes { 176 changes := &plan.Changes{} 177 178 changes.Create = []*endpoint.Endpoint{ 179 {DNSName: "new.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target"}, RecordType: "A"}, 180 {DNSName: "new.ext-dns-test-with-ttl." + testZoneOne, Targets: endpoint.Targets{"target"}, RecordType: "A", RecordTTL: 100}, 181 {DNSName: "new.ext-dns-test.unexpected.com", Targets: endpoint.Targets{"target"}, RecordType: "AAAA"}, 182 {DNSName: testZoneOne, Targets: endpoint.Targets{"target"}, RecordType: "CNAME"}, 183 } 184 changes.Delete = []*endpoint.Endpoint{{DNSName: "foobar.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target"}}} 185 changes.UpdateOld = []*endpoint.Endpoint{{DNSName: "foobar.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target-old"}}} 186 changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "foobar.ext-dns-test." + testZoneOne, Targets: endpoint.Targets{"target-new"}, RecordType: "CNAME", RecordTTL: 100}} 187 188 return changes 189 } 190 191 func TestRcodeZeroProvider_Zones(t *testing.T) { 192 mockRRSetService := &mockRRSetService{} 193 mockZoneManagementService := &mockZoneManagementService{} 194 195 provider := &RcodeZeroProvider{ 196 Client: (*rc0.Client)(&mockRcodeZeroClient{ 197 Zones: mockZoneManagementService, 198 RRSet: mockRRSetService, 199 }), 200 } 201 202 mockZoneManagementService.TestNilZonesReturned = true 203 204 zones, err := provider.Zones() 205 if err != nil { 206 t.Fatal(err) 207 } 208 require.Equal(t, 0, len(zones)) 209 mockZoneManagementService.resetTestConditions() 210 211 mockZoneManagementService.TestErrorReturned = true 212 213 _, err = provider.Zones() 214 if err == nil { 215 t.Errorf("expected to fail, %s", err) 216 } 217 } 218 219 func TestNewRcodeZeroProvider(t *testing.T) { 220 _ = os.Setenv("RC0_API_KEY", "123") 221 p, err := NewRcodeZeroProvider(endpoint.NewDomainFilter([]string{"ext-dns-test." + testZoneOne + "."}), true, true) 222 if err != nil { 223 t.Errorf("should not fail, %s", err) 224 } 225 226 require.Equal(t, true, p.DryRun) 227 require.Equal(t, true, p.TXTEncrypt) 228 require.Equal(t, true, p.DomainFilter.IsConfigured()) 229 require.Equal(t, false, p.DomainFilter.Match("ext-dns-test."+testZoneTwo+".")) // filter is set, so it should match only provided domains 230 231 p, err = NewRcodeZeroProvider(endpoint.DomainFilter{}, false, false) 232 233 if err != nil { 234 t.Errorf("should not fail, %s", err) 235 } 236 237 require.Equal(t, false, p.DryRun) 238 require.Equal(t, false, p.DomainFilter.IsConfigured()) 239 require.Equal(t, true, p.DomainFilter.Match("ext-dns-test."+testZoneOne+".")) // filter is not set, so it should match any 240 241 _ = os.Unsetenv("RC0_API_KEY") 242 _, err = NewRcodeZeroProvider(endpoint.DomainFilter{}, false, false) 243 244 if err == nil { 245 t.Errorf("expected to fail") 246 } 247 } 248 249 /* mocking mockRRSetServiceInterface */ 250 251 func (m *mockRRSetService) List(zone string, options *rc0.ListOptions) ([]*rc0.RRType, *rc0.Page, error) { 252 if m.TestErrorReturned { 253 return nil, nil, fmt.Errorf("operation RRSet.List failed") 254 } 255 256 return mockRRSet(zone), nil, nil 257 } 258 259 func mockRRSet(zone string) []*rc0.RRType { 260 return []*rc0.RRType{ 261 { 262 Name: "app." + zone + ".", 263 Type: "TXT", 264 TTL: 300, 265 Records: []*rc0.Record{ 266 { 267 Content: "\"heritage=external-dns,external-dns/owner=default,external-dns/resource=ingress/default/app\"", 268 Disabled: false, 269 }, 270 }, 271 }, 272 { 273 Name: "app." + zone + ".", 274 Type: "A", 275 TTL: 300, 276 Records: []*rc0.Record{ 277 { 278 Content: "127.0.0.1", 279 Disabled: false, 280 }, 281 }, 282 }, 283 { 284 Name: "www." + zone + ".", 285 Type: "A", 286 TTL: 300, 287 Records: []*rc0.Record{ 288 { 289 Content: "127.0.0.1", 290 Disabled: false, 291 }, 292 }, 293 }, 294 { 295 Name: zone + ".", 296 Type: "SOA", 297 TTL: 3600, 298 Records: []*rc0.Record{ 299 { 300 Content: "sec1.rcode0.net. rcodezero-soa.ipcom.at. 2019011616 10800 3600 604800 3600", 301 Disabled: false, 302 }, 303 }, 304 }, 305 { 306 Name: zone + ".", 307 Type: "NS", 308 TTL: 3600, 309 Records: []*rc0.Record{ 310 { 311 Content: "sec2.rcode0.net.", 312 Disabled: false, 313 }, 314 { 315 Content: "sec1.rcode0.net.", 316 Disabled: false, 317 }, 318 }, 319 }, 320 } 321 } 322 323 func (m *mockRRSetService) Create(zone string, rrsetCreate []*rc0.RRSetChange) (*rc0.StatusResponse, error) { 324 return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil 325 } 326 327 func (m *mockRRSetService) Edit(zone string, rrsetEdit []*rc0.RRSetChange) (*rc0.StatusResponse, error) { 328 return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil 329 } 330 331 func (m *mockRRSetService) Delete(zone string, rrsetDelete []*rc0.RRSetChange) (*rc0.StatusResponse, error) { 332 return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil 333 } 334 335 func (m *mockRRSetService) SubmitChangeSet(zone string, changeSet []*rc0.RRSetChange) (*rc0.StatusResponse, error) { 336 return &rc0.StatusResponse{Status: "ok", Message: "pass"}, nil 337 } 338 339 func (m *mockRRSetService) EncryptTXT(key []byte, rrType *rc0.RRSetChange) {} 340 341 func (m *mockRRSetService) DecryptTXT(key []byte, rrType *rc0.RRType) {} 342 343 /* mocking ZoneManagementServiceInterface */ 344 345 func (m *mockZoneManagementService) List(options *rc0.ListOptions) ([]*rc0.Zone, *rc0.Page, error) { 346 if m.TestNilZonesReturned { 347 return nil, nil, nil 348 } 349 350 if m.TestErrorReturned { 351 return nil, nil, fmt.Errorf("operation Zone.List failed") 352 } 353 354 zones := []*rc0.Zone{ 355 { 356 Domain: testZoneOne, 357 Type: "SLAVE", 358 // "dnssec": "yes", @todo: add this 359 // "created": "2018-04-09T09:27:31Z", @todo: add this 360 LastCheck: "", 361 Serial: 20180411, 362 Masters: []string{ 363 "193.0.2.2", 364 "2001:db8::2", 365 }, 366 }, 367 { 368 Domain: testZoneTwo, 369 Type: "MASTER", 370 // "dnssec": "no", @todo: add this 371 // "created": "2019-01-15T13:20:10Z", @todo: add this 372 LastCheck: "", 373 Serial: 2019011616, 374 Masters: []string{ 375 "", 376 }, 377 }, 378 } 379 380 return zones, nil, nil 381 } 382 383 func (m *mockZoneManagementService) Get(zone string) (*rc0.Zone, error) { return nil, nil } 384 func (m *mockZoneManagementService) Create(zoneCreate *rc0.ZoneCreate) (*rc0.StatusResponse, error) { 385 return nil, nil 386 } 387 388 func (m *mockZoneManagementService) Edit(zone string, zoneEdit *rc0.ZoneEdit) (*rc0.StatusResponse, error) { 389 return nil, nil 390 } 391 func (m *mockZoneManagementService) Delete(zone string) (*rc0.StatusResponse, error) { return nil, nil } 392 func (m *mockZoneManagementService) Transfer(zone string) (*rc0.StatusResponse, error) { 393 return nil, nil 394 }