sigs.k8s.io/external-dns@v0.14.1/provider/ns1/ns1_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 ns1 18 19 import ( 20 "context" 21 "fmt" 22 "net/http" 23 "os" 24 "testing" 25 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/mock" 28 "github.com/stretchr/testify/require" 29 api "gopkg.in/ns1/ns1-go.v2/rest" 30 "gopkg.in/ns1/ns1-go.v2/rest/model/dns" 31 32 "sigs.k8s.io/external-dns/endpoint" 33 "sigs.k8s.io/external-dns/plan" 34 "sigs.k8s.io/external-dns/provider" 35 ) 36 37 type MockNS1DomainClient struct { 38 mock.Mock 39 } 40 41 func (m *MockNS1DomainClient) CreateRecord(r *dns.Record) (*http.Response, error) { 42 return nil, nil 43 } 44 45 func (m *MockNS1DomainClient) DeleteRecord(zone string, domain string, t string) (*http.Response, error) { 46 return nil, nil 47 } 48 49 func (m *MockNS1DomainClient) UpdateRecord(r *dns.Record) (*http.Response, error) { 50 return nil, nil 51 } 52 53 func (m *MockNS1DomainClient) GetZone(zone string) (*dns.Zone, *http.Response, error) { 54 r := &dns.ZoneRecord{ 55 Domain: "test.foo.com", 56 ShortAns: []string{"2.2.2.2"}, 57 TTL: 3600, 58 Type: "A", 59 ID: "123456789abcdefghijklmno", 60 } 61 z := &dns.Zone{ 62 Zone: "foo.com", 63 Records: []*dns.ZoneRecord{r}, 64 TTL: 3600, 65 ID: "12345678910111213141516a", 66 } 67 68 if zone == "foo.com" { 69 return z, nil, nil 70 } 71 return nil, nil, nil 72 } 73 74 func (m *MockNS1DomainClient) ListZones() ([]*dns.Zone, *http.Response, error) { 75 zones := []*dns.Zone{ 76 {Zone: "foo.com", ID: "12345678910111213141516a"}, 77 {Zone: "bar.com", ID: "12345678910111213141516b"}, 78 } 79 return zones, nil, nil 80 } 81 82 type MockNS1GetZoneFail struct{} 83 84 func (m *MockNS1GetZoneFail) CreateRecord(r *dns.Record) (*http.Response, error) { 85 return nil, nil 86 } 87 88 func (m *MockNS1GetZoneFail) DeleteRecord(zone string, domain string, t string) (*http.Response, error) { 89 return nil, nil 90 } 91 92 func (m *MockNS1GetZoneFail) UpdateRecord(r *dns.Record) (*http.Response, error) { 93 return nil, nil 94 } 95 96 func (m *MockNS1GetZoneFail) GetZone(zone string) (*dns.Zone, *http.Response, error) { 97 return nil, nil, api.ErrZoneMissing 98 } 99 100 func (m *MockNS1GetZoneFail) ListZones() ([]*dns.Zone, *http.Response, error) { 101 zones := []*dns.Zone{ 102 {Zone: "foo.com", ID: "12345678910111213141516a"}, 103 {Zone: "bar.com", ID: "12345678910111213141516b"}, 104 } 105 return zones, nil, nil 106 } 107 108 type MockNS1ListZonesFail struct{} 109 110 func (m *MockNS1ListZonesFail) CreateRecord(r *dns.Record) (*http.Response, error) { 111 return nil, nil 112 } 113 114 func (m *MockNS1ListZonesFail) DeleteRecord(zone string, domain string, t string) (*http.Response, error) { 115 return nil, nil 116 } 117 118 func (m *MockNS1ListZonesFail) UpdateRecord(r *dns.Record) (*http.Response, error) { 119 return nil, nil 120 } 121 122 func (m *MockNS1ListZonesFail) GetZone(zone string) (*dns.Zone, *http.Response, error) { 123 return &dns.Zone{}, nil, nil 124 } 125 126 func (m *MockNS1ListZonesFail) ListZones() ([]*dns.Zone, *http.Response, error) { 127 return nil, nil, fmt.Errorf("no zones available") 128 } 129 130 func TestNS1Records(t *testing.T) { 131 provider := &NS1Provider{ 132 client: &MockNS1DomainClient{}, 133 domainFilter: endpoint.NewDomainFilter([]string{"foo.com."}), 134 zoneIDFilter: provider.NewZoneIDFilter([]string{""}), 135 minTTLSeconds: 3600, 136 } 137 ctx := context.Background() 138 139 records, err := provider.Records(ctx) 140 require.NoError(t, err) 141 assert.Equal(t, 1, len(records)) 142 143 provider.client = &MockNS1GetZoneFail{} 144 _, err = provider.Records(ctx) 145 require.Error(t, err) 146 147 provider.client = &MockNS1ListZonesFail{} 148 _, err = provider.Records(ctx) 149 require.Error(t, err) 150 } 151 152 func TestNewNS1Provider(t *testing.T) { 153 _ = os.Setenv("NS1_APIKEY", "xxxxxxxxxxxxxxxxx") 154 testNS1Config := NS1Config{ 155 DomainFilter: endpoint.NewDomainFilter([]string{"foo.com."}), 156 ZoneIDFilter: provider.NewZoneIDFilter([]string{""}), 157 DryRun: false, 158 } 159 _, err := NewNS1Provider(testNS1Config) 160 require.NoError(t, err) 161 162 _ = os.Unsetenv("NS1_APIKEY") 163 _, err = NewNS1Provider(testNS1Config) 164 require.Error(t, err) 165 } 166 167 func TestNS1Zones(t *testing.T) { 168 provider := &NS1Provider{ 169 client: &MockNS1DomainClient{}, 170 domainFilter: endpoint.NewDomainFilter([]string{"foo.com."}), 171 zoneIDFilter: provider.NewZoneIDFilter([]string{""}), 172 } 173 174 zones, err := provider.zonesFiltered() 175 require.NoError(t, err) 176 177 validateNS1Zones(t, zones, []*dns.Zone{ 178 {Zone: "foo.com"}, 179 }) 180 } 181 182 func validateNS1Zones(t *testing.T, zones []*dns.Zone, expected []*dns.Zone) { 183 require.Len(t, zones, len(expected)) 184 185 for i, zone := range zones { 186 assert.Equal(t, expected[i].Zone, zone.Zone) 187 } 188 } 189 190 func TestNS1BuildRecord(t *testing.T) { 191 change := &ns1Change{ 192 Action: ns1Create, 193 Endpoint: &endpoint.Endpoint{ 194 DNSName: "new", 195 Targets: endpoint.Targets{"target"}, 196 RecordType: "A", 197 }, 198 } 199 200 provider := &NS1Provider{ 201 client: &MockNS1DomainClient{}, 202 domainFilter: endpoint.NewDomainFilter([]string{"foo.com."}), 203 zoneIDFilter: provider.NewZoneIDFilter([]string{""}), 204 minTTLSeconds: 300, 205 } 206 207 record := provider.ns1BuildRecord("foo.com", change) 208 assert.Equal(t, "foo.com", record.Zone) 209 assert.Equal(t, "new.foo.com", record.Domain) 210 assert.Equal(t, 300, record.TTL) 211 212 changeWithTTL := &ns1Change{ 213 Action: ns1Create, 214 Endpoint: &endpoint.Endpoint{ 215 DNSName: "new-b", 216 Targets: endpoint.Targets{"target"}, 217 RecordType: "A", 218 RecordTTL: 3600, 219 }, 220 } 221 record = provider.ns1BuildRecord("foo.com", changeWithTTL) 222 assert.Equal(t, "foo.com", record.Zone) 223 assert.Equal(t, "new-b.foo.com", record.Domain) 224 assert.Equal(t, 3600, record.TTL) 225 } 226 227 func TestNS1ApplyChanges(t *testing.T) { 228 changes := &plan.Changes{} 229 provider := &NS1Provider{ 230 client: &MockNS1DomainClient{}, 231 } 232 changes.Create = []*endpoint.Endpoint{ 233 {DNSName: "new.foo.com", Targets: endpoint.Targets{"target"}}, 234 {DNSName: "new.subdomain.bar.com", Targets: endpoint.Targets{"target"}}, 235 } 236 changes.Delete = []*endpoint.Endpoint{{DNSName: "test.foo.com", Targets: endpoint.Targets{"target"}}} 237 changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "test.foo.com", Targets: endpoint.Targets{"target-new"}}} 238 err := provider.ApplyChanges(context.Background(), changes) 239 require.NoError(t, err) 240 241 // empty changes 242 changes.Create = []*endpoint.Endpoint{} 243 changes.Delete = []*endpoint.Endpoint{} 244 changes.UpdateNew = []*endpoint.Endpoint{} 245 err = provider.ApplyChanges(context.Background(), changes) 246 require.NoError(t, err) 247 } 248 249 func TestNewNS1Changes(t *testing.T) { 250 endpoints := []*endpoint.Endpoint{ 251 { 252 DNSName: "testa.foo.com", 253 Targets: endpoint.Targets{"target-old"}, 254 RecordType: "A", 255 }, 256 { 257 DNSName: "testba.bar.com", 258 Targets: endpoint.Targets{"target-new"}, 259 RecordType: "A", 260 }, 261 } 262 expected := []*ns1Change{ 263 { 264 Action: "ns1Create", 265 Endpoint: endpoints[0], 266 }, 267 { 268 Action: "ns1Create", 269 Endpoint: endpoints[1], 270 }, 271 } 272 changes := newNS1Changes("ns1Create", endpoints) 273 require.Len(t, changes, len(expected)) 274 assert.Equal(t, expected, changes) 275 } 276 277 func TestNewNS1ChangesByZone(t *testing.T) { 278 provider := &NS1Provider{ 279 client: &MockNS1DomainClient{}, 280 } 281 zones, _ := provider.zonesFiltered() 282 changeSets := []*ns1Change{ 283 { 284 Action: "ns1Create", 285 Endpoint: &endpoint.Endpoint{ 286 DNSName: "new.foo.com", 287 Targets: endpoint.Targets{"target"}, 288 RecordType: "A", 289 }, 290 }, 291 { 292 Action: "ns1Create", 293 Endpoint: &endpoint.Endpoint{ 294 DNSName: "unrelated.bar.com", 295 Targets: endpoint.Targets{"target"}, 296 RecordType: "A", 297 }, 298 }, 299 { 300 Action: "ns1Delete", 301 Endpoint: &endpoint.Endpoint{ 302 DNSName: "test.foo.com", 303 Targets: endpoint.Targets{"target"}, 304 RecordType: "A", 305 }, 306 }, 307 { 308 Action: "ns1Update", 309 Endpoint: &endpoint.Endpoint{ 310 DNSName: "test.foo.com", 311 Targets: endpoint.Targets{"target-new"}, 312 RecordType: "A", 313 }, 314 }, 315 } 316 317 changes := ns1ChangesByZone(zones, changeSets) 318 assert.Len(t, changes["bar.com"], 1) 319 assert.Len(t, changes["foo.com"], 3) 320 }