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  }