sigs.k8s.io/external-dns@v0.14.1/provider/transip/transip_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 transip 18 19 import ( 20 "context" 21 "encoding/json" 22 "errors" 23 "strings" 24 "testing" 25 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/require" 28 "github.com/transip/gotransip/v6/domain" 29 "github.com/transip/gotransip/v6/rest" 30 31 "sigs.k8s.io/external-dns/endpoint" 32 "sigs.k8s.io/external-dns/provider" 33 ) 34 35 func newProvider() *TransIPProvider { 36 return &TransIPProvider{ 37 zoneMap: provider.ZoneIDName{}, 38 } 39 } 40 41 func TestTransIPDnsEntriesAreEqual(t *testing.T) { 42 // test with equal set 43 a := []domain.DNSEntry{ 44 { 45 Name: "www.example.org", 46 Type: "CNAME", 47 Expire: 3600, 48 Content: "www.example.com", 49 }, 50 { 51 Name: "www.example.com", 52 Type: "A", 53 Expire: 3600, 54 Content: "192.168.0.1", 55 }, 56 } 57 58 b := []domain.DNSEntry{ 59 { 60 Name: "www.example.com", 61 Type: "A", 62 Expire: 3600, 63 Content: "192.168.0.1", 64 }, 65 { 66 Name: "www.example.org", 67 Type: "CNAME", 68 Expire: 3600, 69 Content: "www.example.com", 70 }, 71 } 72 73 assert.Equal(t, true, dnsEntriesAreEqual(a, b)) 74 75 // change type on one of b's records 76 b[1].Type = "NS" 77 assert.Equal(t, false, dnsEntriesAreEqual(a, b)) 78 b[1].Type = "CNAME" 79 80 // change ttl on one of b's records 81 b[1].Expire = 1800 82 assert.Equal(t, false, dnsEntriesAreEqual(a, b)) 83 b[1].Expire = 3600 84 85 // change name on one of b's records 86 b[1].Name = "example.org" 87 assert.Equal(t, false, dnsEntriesAreEqual(a, b)) 88 89 // remove last entry of b 90 b = b[:1] 91 assert.Equal(t, false, dnsEntriesAreEqual(a, b)) 92 } 93 94 func TestTransIPGetMinimalValidTTL(t *testing.T) { 95 // test with 'unconfigured' TTL 96 ep := &endpoint.Endpoint{} 97 assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep)) 98 99 // test with lower than minimal ttl 100 ep.RecordTTL = (transipMinimalValidTTL - 1) 101 assert.EqualValues(t, transipMinimalValidTTL, getMinimalValidTTL(ep)) 102 103 // test with higher than minimal ttl 104 ep.RecordTTL = (transipMinimalValidTTL + 1) 105 assert.EqualValues(t, transipMinimalValidTTL+1, getMinimalValidTTL(ep)) 106 } 107 108 func TestTransIPRecordNameForEndpoint(t *testing.T) { 109 ep := &endpoint.Endpoint{ 110 DNSName: "example.org", 111 } 112 d := domain.Domain{ 113 Name: "example.org", 114 } 115 116 assert.Equal(t, "@", recordNameForEndpoint(ep, d.Name)) 117 118 ep.DNSName = "www.example.org" 119 assert.Equal(t, "www", recordNameForEndpoint(ep, d.Name)) 120 } 121 122 func TestTransIPEndpointNameForRecord(t *testing.T) { 123 r := domain.DNSEntry{ 124 Name: "@", 125 } 126 d := domain.Domain{ 127 Name: "example.org", 128 } 129 130 assert.Equal(t, d.Name, endpointNameForRecord(r, d.Name)) 131 132 r.Name = "www" 133 assert.Equal(t, "www.example.org", endpointNameForRecord(r, d.Name)) 134 } 135 136 func TestTransIPAddEndpointToEntries(t *testing.T) { 137 // prepare endpoint 138 ep := &endpoint.Endpoint{ 139 DNSName: "www.example.org", 140 RecordType: "A", 141 RecordTTL: 1800, 142 Targets: []string{ 143 "192.168.0.1", 144 "192.168.0.2", 145 }, 146 } 147 148 // prepare zone with DNS entry set 149 zone := domain.Domain{ 150 Name: "example.org", 151 } 152 153 // add endpoint to zone's entries 154 result := dnsEntriesForEndpoint(ep, zone.Name) 155 156 if assert.Equal(t, 2, len(result)) { 157 assert.Equal(t, "www", result[0].Name) 158 assert.Equal(t, "A", result[0].Type) 159 assert.Equal(t, "192.168.0.1", result[0].Content) 160 assert.EqualValues(t, 1800, result[0].Expire) 161 assert.Equal(t, "www", result[1].Name) 162 assert.Equal(t, "A", result[1].Type) 163 assert.Equal(t, "192.168.0.2", result[1].Content) 164 assert.EqualValues(t, 1800, result[1].Expire) 165 } 166 167 // try again with CNAME 168 ep.RecordType = "CNAME" 169 ep.Targets = []string{"foo.bar"} 170 result = dnsEntriesForEndpoint(ep, zone.Name) 171 if assert.Equal(t, 1, len(result)) { 172 assert.Equal(t, "CNAME", result[0].Type) 173 assert.Equal(t, "foo.bar.", result[0].Content) 174 } 175 } 176 177 func TestZoneNameForDNSName(t *testing.T) { 178 p := newProvider() 179 p.zoneMap.Add("example.com", "example.com") 180 181 zoneName, err := p.zoneNameForDNSName("www.example.com") 182 if assert.NoError(t, err) { 183 assert.Equal(t, "example.com", zoneName) 184 } 185 186 _, err = p.zoneNameForDNSName("www.example.org") 187 if assert.Error(t, err) { 188 assert.Equal(t, "could not find zoneName for www.example.org", err.Error()) 189 } 190 } 191 192 // fakeClient mocks the REST API client 193 type fakeClient struct { 194 getFunc func(rest.Request, interface{}) error 195 } 196 197 func (f *fakeClient) Get(request rest.Request, dest interface{}) error { 198 if f.getFunc == nil { 199 return errors.New("GET not defined") 200 } 201 202 return f.getFunc(request, dest) 203 } 204 205 func (f fakeClient) Put(request rest.Request) error { 206 return errors.New("PUT not implemented") 207 } 208 209 func (f fakeClient) Post(request rest.Request) error { 210 return errors.New("POST not implemented") 211 } 212 213 func (f fakeClient) Delete(request rest.Request) error { 214 return errors.New("DELETE not implemented") 215 } 216 217 func (f fakeClient) Patch(request rest.Request) error { 218 return errors.New("PATCH not implemented") 219 } 220 221 func (f fakeClient) PatchWithResponse(request rest.Request) (rest.Response, error) { 222 return rest.Response{}, errors.New("PATCH with response not implemented") 223 } 224 225 func (f fakeClient) PostWithResponse(request rest.Request) (rest.Response, error) { 226 return rest.Response{}, errors.New("POST with response not implemented") 227 } 228 229 func (f fakeClient) PutWithResponse(request rest.Request) (rest.Response, error) { 230 return rest.Response{}, errors.New("PUT with response not implemented") 231 } 232 233 func TestProviderRecords(t *testing.T) { 234 // set up the fake REST client 235 client := &fakeClient{} 236 client.getFunc = func(req rest.Request, dest interface{}) error { 237 var data []byte 238 switch { 239 case req.Endpoint == "/domains": 240 // return list of some domain names 241 // names only, other fields are not used 242 data = []byte(`{"domains":[{"name":"example.org"}, {"name":"example.com"}]}`) 243 case strings.HasSuffix(req.Endpoint, "/dns"): 244 // return list of DNS entries 245 // also some unsupported types 246 data = []byte(`{"dnsEntries":[{"name":"www", "expire":1234, "type":"CNAME", "content":"@"},{"type":"MX"},{"type":"AAAA"}]}`) 247 } 248 249 // unmarshal the prepared return data into the given destination type 250 return json.Unmarshal(data, &dest) 251 } 252 253 // set up provider 254 p := newProvider() 255 p.domainRepo = domain.Repository{Client: client} 256 257 endpoints, err := p.Records(context.TODO()) 258 if assert.NoError(t, err) { 259 if assert.Equal(t, 4, len(endpoints)) { 260 assert.Equal(t, "www.example.org", endpoints[0].DNSName) 261 assert.EqualValues(t, "@", endpoints[0].Targets[0]) 262 assert.Equal(t, "CNAME", endpoints[0].RecordType) 263 assert.Equal(t, 0, len(endpoints[0].Labels)) 264 assert.EqualValues(t, 1234, endpoints[0].RecordTTL) 265 } 266 } 267 } 268 269 func TestProviderEntriesForEndpoint(t *testing.T) { 270 // set up fake REST client 271 client := &fakeClient{} 272 273 // set up provider 274 p := newProvider() 275 p.domainRepo = domain.Repository{Client: client} 276 p.zoneMap.Add("example.com", "example.com") 277 278 // get entries for endpoint with unknown zone 279 _, _, err := p.entriesForEndpoint(&endpoint.Endpoint{ 280 DNSName: "www.example.org", 281 }) 282 if assert.Error(t, err) { 283 assert.Equal(t, "could not find zoneName for www.example.org", err.Error()) 284 } 285 286 // get entries for endpoint with known zone but client returns error 287 // we leave GET functions undefined so we know which error to expect 288 zoneName, _, err := p.entriesForEndpoint(&endpoint.Endpoint{ 289 DNSName: "www.example.com", 290 }) 291 if assert.Error(t, err) { 292 assert.Equal(t, "GET not defined", err.Error()) 293 } 294 assert.Equal(t, "example.com", zoneName) 295 296 // to be able to return a valid set of DNS entries through the API, we define 297 // some first, then JSON encode them and have the fake API client's Get function 298 // return that 299 // in this set are some entries that do and others that don't match the given 300 // endpoint 301 dnsEntries := []domain.DNSEntry{ 302 { 303 Name: "www", 304 Type: "A", 305 Expire: 3600, 306 Content: "1.2.3.4", 307 }, 308 { 309 Name: "ftp", 310 Type: "A", 311 Expire: 86400, 312 Content: "3.4.5.6", 313 }, 314 { 315 Name: "www", 316 Type: "A", 317 Expire: 3600, 318 Content: "2.3.4.5", 319 }, 320 { 321 Name: "www", 322 Type: "CNAME", 323 Expire: 3600, 324 Content: "@", 325 }, 326 } 327 var v struct { 328 DNSEntries []domain.DNSEntry `json:"dnsEntries"` 329 } 330 v.DNSEntries = dnsEntries 331 returnData, err := json.Marshal(&v) 332 require.NoError(t, err) 333 334 // define GET function 335 client.getFunc = func(unused rest.Request, dest interface{}) error { 336 // unmarshal the prepared return data into the given dnsEntriesWrapper 337 return json.Unmarshal(returnData, &dest) 338 } 339 _, entries, err := p.entriesForEndpoint(&endpoint.Endpoint{ 340 DNSName: "www.example.com", 341 RecordType: "A", 342 }) 343 if assert.NoError(t, err) { 344 if assert.Equal(t, 2, len(entries)) { 345 // only first and third entry should be returned 346 assert.Equal(t, dnsEntries[0], entries[0]) 347 assert.Equal(t, dnsEntries[2], entries[1]) 348 } 349 } 350 }