sigs.k8s.io/external-dns@v0.14.1/provider/dyn/dyn_test.go (about) 1 /* 2 Copyright 2018 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 dyn 18 19 import ( 20 "errors" 21 "fmt" 22 "testing" 23 24 "github.com/nesv/go-dynect/dynect" 25 "github.com/stretchr/testify/assert" 26 27 "sigs.k8s.io/external-dns/endpoint" 28 "sigs.k8s.io/external-dns/provider" 29 ) 30 31 func TestDynMerge_NoUpdateOnTTL0Changes(t *testing.T) { 32 updateOld := []*endpoint.Endpoint{ 33 { 34 DNSName: "name1", 35 Targets: endpoint.Targets{"target1"}, 36 RecordTTL: endpoint.TTL(1), 37 RecordType: endpoint.RecordTypeA, 38 }, 39 { 40 DNSName: "name2", 41 Targets: endpoint.Targets{"target2"}, 42 RecordTTL: endpoint.TTL(1), 43 RecordType: endpoint.RecordTypeA, 44 }, 45 } 46 47 updateNew := []*endpoint.Endpoint{ 48 { 49 DNSName: "name1", 50 Targets: endpoint.Targets{"target1"}, 51 RecordTTL: endpoint.TTL(0), 52 RecordType: endpoint.RecordTypeCNAME, 53 }, 54 { 55 DNSName: "name2", 56 Targets: endpoint.Targets{"target2"}, 57 RecordTTL: endpoint.TTL(0), 58 RecordType: endpoint.RecordTypeCNAME, 59 }, 60 } 61 62 assert.Equal(t, 0, len(merge(updateOld, updateNew))) 63 } 64 65 func TestDynMerge_UpdateOnTTLChanges(t *testing.T) { 66 updateOld := []*endpoint.Endpoint{ 67 { 68 DNSName: "name1", 69 Targets: endpoint.Targets{"target1"}, 70 RecordTTL: endpoint.TTL(1), 71 RecordType: endpoint.RecordTypeCNAME, 72 }, 73 { 74 DNSName: "name2", 75 Targets: endpoint.Targets{"target2"}, 76 RecordTTL: endpoint.TTL(1), 77 RecordType: endpoint.RecordTypeCNAME, 78 }, 79 } 80 81 updateNew := []*endpoint.Endpoint{ 82 { 83 DNSName: "name1", 84 Targets: endpoint.Targets{"target1"}, 85 RecordTTL: endpoint.TTL(77), 86 RecordType: endpoint.RecordTypeCNAME, 87 }, 88 { 89 DNSName: "name2", 90 Targets: endpoint.Targets{"target2"}, 91 RecordTTL: endpoint.TTL(10), 92 RecordType: endpoint.RecordTypeCNAME, 93 }, 94 } 95 96 merged := merge(updateOld, updateNew) 97 assert.Equal(t, 2, len(merged)) 98 assert.Equal(t, "name1", merged[0].DNSName) 99 } 100 101 func TestDynMerge_AlwaysUpdateTarget(t *testing.T) { 102 updateOld := []*endpoint.Endpoint{ 103 { 104 DNSName: "name1", 105 Targets: endpoint.Targets{"target1"}, 106 RecordTTL: endpoint.TTL(1), 107 RecordType: endpoint.RecordTypeCNAME, 108 }, 109 { 110 DNSName: "name2", 111 Targets: endpoint.Targets{"target2"}, 112 RecordTTL: endpoint.TTL(1), 113 RecordType: endpoint.RecordTypeCNAME, 114 }, 115 } 116 117 updateNew := []*endpoint.Endpoint{ 118 { 119 DNSName: "name1", 120 Targets: endpoint.Targets{"target1-changed"}, 121 RecordTTL: endpoint.TTL(0), 122 RecordType: endpoint.RecordTypeCNAME, 123 }, 124 { 125 DNSName: "name2", 126 Targets: endpoint.Targets{"target2"}, 127 RecordTTL: endpoint.TTL(0), 128 RecordType: endpoint.RecordTypeCNAME, 129 }, 130 } 131 132 merged := merge(updateOld, updateNew) 133 assert.Equal(t, 1, len(merged)) 134 assert.Equal(t, "target1-changed", merged[0].Targets[0]) 135 } 136 137 func TestDynMerge_NoUpdateIfTTLUnchanged(t *testing.T) { 138 updateOld := []*endpoint.Endpoint{ 139 { 140 DNSName: "name1", 141 Targets: endpoint.Targets{"target1"}, 142 RecordTTL: endpoint.TTL(55), 143 RecordType: endpoint.RecordTypeCNAME, 144 }, 145 { 146 DNSName: "name2", 147 Targets: endpoint.Targets{"target2"}, 148 RecordTTL: endpoint.TTL(55), 149 RecordType: endpoint.RecordTypeCNAME, 150 }, 151 } 152 153 updateNew := []*endpoint.Endpoint{ 154 { 155 DNSName: "name1", 156 Targets: endpoint.Targets{"target1"}, 157 RecordTTL: endpoint.TTL(55), 158 RecordType: endpoint.RecordTypeCNAME, 159 }, 160 { 161 DNSName: "name2", 162 Targets: endpoint.Targets{"target2"}, 163 RecordTTL: endpoint.TTL(55), 164 RecordType: endpoint.RecordTypeCNAME, 165 }, 166 } 167 168 merged := merge(updateOld, updateNew) 169 assert.Equal(t, 0, len(merged)) 170 } 171 172 func TestDyn_endpointToRecord(t *testing.T) { 173 tests := []struct { 174 ep *endpoint.Endpoint 175 extractor func(*dynect.DataBlock) string 176 }{ 177 {endpoint.NewEndpoint("address", "A", "the-target"), func(b *dynect.DataBlock) string { return b.Address }}, 178 {endpoint.NewEndpoint("cname", "CNAME", "the-target"), func(b *dynect.DataBlock) string { return b.CName }}, 179 {endpoint.NewEndpoint("text", "TXT", "the-target"), func(b *dynect.DataBlock) string { return b.TxtData }}, 180 } 181 182 for _, tc := range tests { 183 block := endpointToRecord(tc.ep) 184 assert.Equal(t, "the-target", tc.extractor(block)) 185 } 186 } 187 188 func TestDyn_buildLinkToRecord(t *testing.T) { 189 provider := &dynProviderState{ 190 DynConfig: DynConfig{ 191 ZoneIDFilter: provider.NewZoneIDFilter([]string{"example.com"}), 192 DomainFilter: endpoint.NewDomainFilter([]string{"the-target.example.com"}), 193 }, 194 } 195 196 tests := []struct { 197 ep *endpoint.Endpoint 198 link string 199 }{ 200 {endpoint.NewEndpoint("sub.the-target.example.com", "A", "address"), "ARecord/example.com/sub.the-target.example.com/"}, 201 {endpoint.NewEndpoint("the-target.example.com", "CNAME", "cname"), "CNAMERecord/example.com/the-target.example.com/"}, 202 {endpoint.NewEndpoint("the-target.example.com", "TXT", "text"), "TXTRecord/example.com/the-target.example.com/"}, 203 {endpoint.NewEndpoint("the-target.google.com", "TXT", "text"), ""}, 204 {endpoint.NewEndpoint("mail.example.com", "TXT", "text"), ""}, 205 {nil, ""}, 206 } 207 208 for _, tc := range tests { 209 assert.Equal(t, tc.link, provider.buildLinkToRecord(tc.ep)) 210 } 211 } 212 213 func TestDyn_errorOrValue(t *testing.T) { 214 e := errors.New("an error") 215 val := "value" 216 assert.Equal(t, e, errorOrValue(e, val)) 217 assert.Equal(t, val, errorOrValue(nil, val)) 218 } 219 220 func TestDyn_filterAndFixLinks(t *testing.T) { 221 links := []string{ 222 "/REST/ARecord/example.com/the-target.example.com/", 223 "/REST/ARecord/example.com/the-target.google.com/", 224 "/REST/TXTRecord/example.com/the-target.example.com/", 225 "/REST/TXTRecord/example.com/the-target.google.com/", 226 "/REST/CNAMERecord/example.com/the-target.google.com/", 227 "/REST/CNAMERecord/example.com/the-target.example.com/", 228 "/REST/NSRecord/example.com/the-target.google.com/", 229 "/REST/NSRecord/example.com/the-target.example.com/", 230 } 231 filter := endpoint.NewDomainFilter([]string{"example.com"}) 232 result := filterAndFixLinks(links, filter) 233 234 // should skip non-example.com records and NS records too 235 assert.Equal(t, 3, len(result)) 236 assert.Equal(t, "ARecord/example.com/the-target.example.com/", result[0]) 237 assert.Equal(t, "TXTRecord/example.com/the-target.example.com/", result[1]) 238 assert.Equal(t, "CNAMERecord/example.com/the-target.example.com/", result[2]) 239 } 240 241 func TestDyn_fixMissingTTL(t *testing.T) { 242 assert.Equal(t, fmt.Sprintf("%v", dynDefaultTTL), fixMissingTTL(endpoint.TTL(0), 0)) 243 244 // nothing to fix 245 assert.Equal(t, "111", fixMissingTTL(endpoint.TTL(111), 25)) 246 247 // apply min TTL 248 assert.Equal(t, "1992", fixMissingTTL(endpoint.TTL(111), 1992)) 249 } 250 251 func TestDyn_Snapshot(t *testing.T) { 252 snap := ZoneSnapshot{ 253 serials: map[string]int{}, 254 endpoints: map[string][]*endpoint.Endpoint{}, 255 } 256 257 recs := []*endpoint.Endpoint{ 258 { 259 DNSName: "name", 260 Targets: endpoint.Targets{"target"}, 261 RecordTTL: endpoint.TTL(10000), 262 RecordType: "A", 263 }, 264 } 265 266 snap.StoreRecordsForSerial("test", 12, recs) 267 268 cached := snap.GetRecordsForSerial("test", 12) 269 assert.Equal(t, recs, cached) 270 271 cached = snap.GetRecordsForSerial("test", 999) 272 assert.Nil(t, cached) 273 274 cached = snap.GetRecordsForSerial("sfas", 12) 275 assert.Nil(t, cached) 276 277 recs2 := []*endpoint.Endpoint{ 278 { 279 DNSName: "name", 280 Targets: endpoint.Targets{"target2"}, 281 RecordTTL: endpoint.TTL(100), 282 RecordType: "CNAME", 283 }, 284 } 285 286 // update zone with different records and newer serial 287 snap.StoreRecordsForSerial("test", 13, recs2) 288 289 cached = snap.GetRecordsForSerial("test", 13) 290 assert.Equal(t, recs2, cached) 291 292 cached = snap.GetRecordsForSerial("test", 12) 293 assert.Nil(t, cached) 294 }