github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/dnscache/storage_test.go (about)

     1  package dnscache
     2  
     3  import (
     4  	"net"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/miekg/dns"
    10  
    11  	"github.com/TykTechnologies/tyk/test"
    12  )
    13  
    14  var (
    15  	expiration    = 10
    16  	checkInterval = 5
    17  )
    18  
    19  const (
    20  	host             = "orig-host.com."
    21  	singleRecordHost = "single.orig-host.com."
    22  	host2            = "orig-host2.com."
    23  	host3            = "some.orig-host3.com"
    24  	host4            = "some.orig-host4.com"
    25  	hostErrorable    = "unknown.orig-host.com."
    26  	wsHost           = "ws.orig-host.com."
    27  )
    28  
    29  var (
    30  	etcHostsMap = map[string][]string{
    31  		singleRecordHost: {"10.0.2.10"},
    32  		host:             {"127.0.0.1", "127.0.0.2", "127.0.0.3"},
    33  		host2:            {"10.0.2.0", "10.0.2.1", "10.0.2.2"},
    34  		host3:            {"10.0.2.15", "10.0.2.16"},
    35  		host4:            {"10.0.2.11", "10.0.2.10"},
    36  		wsHost:           {"127.0.0.1", "127.0.0.1"},
    37  	}
    38  
    39  	etcHostsErrorMap = map[string]int{
    40  		hostErrorable: dns.RcodeServerFailure,
    41  	}
    42  )
    43  
    44  type configTestStorageFetchItem struct {
    45  	*testing.T
    46  	etcHostsMap       map[string][]string
    47  	etcHostsErrorsMap map[string]int
    48  }
    49  
    50  func setupTestStorageFetchItem(cfg *configTestStorageFetchItem) func() {
    51  	handle, err := test.InitDNSMock(cfg.etcHostsMap, cfg.etcHostsErrorsMap)
    52  	if err != nil {
    53  		cfg.T.Error(err.Error())
    54  	}
    55  
    56  	return func() {
    57  		if err := handle.ShutdownDnsMock(); err != nil {
    58  			cfg.T.Error(err.Error())
    59  		}
    60  	}
    61  }
    62  
    63  func TestStorageFetchItem(t *testing.T) {
    64  	dnsCache := NewDnsCacheStorage(time.Duration(expiration)*time.Second, time.Duration(checkInterval)*time.Second)
    65  
    66  	tearDownTestStorageFetchItem := setupTestStorageFetchItem(&configTestStorageFetchItem{t, etcHostsMap, etcHostsErrorMap})
    67  	defer func() {
    68  		tearDownTestStorageFetchItem()
    69  		dnsCache.Clear()
    70  		dnsCache = nil
    71  	}()
    72  
    73  	cases := []struct {
    74  		name string
    75  
    76  		Host        string
    77  		ExpectedIPs []string
    78  
    79  		expectedErrorType    reflect.Type
    80  		shouldExistInCache   bool
    81  		shouldBeAddedToCache bool
    82  	}{
    83  		{
    84  			"Should cache first dns record first fetch",
    85  			host, etcHostsMap[host],
    86  			nil, false, true,
    87  		},
    88  		{
    89  			"Should cache second dns record first fetch",
    90  			host2, etcHostsMap[host2],
    91  			nil, false, true,
    92  		},
    93  		{
    94  			"Should populate from cache first dns record second fetch",
    95  			host, etcHostsMap[host],
    96  			nil, true, false,
    97  		},
    98  		{
    99  			"Should populate from cache first dns record third fetch",
   100  			host, etcHostsMap[host],
   101  			nil, true, false,
   102  		},
   103  		{
   104  			"Should populate from cache second dns record second fetch",
   105  			host2, etcHostsMap[host2],
   106  			nil, true, false,
   107  		},
   108  		{
   109  			"Shouldn't cache dns record fetch in case error",
   110  			hostErrorable, nil,
   111  			reflect.TypeOf(&net.DNSError{}), false, false,
   112  		},
   113  	}
   114  
   115  	for _, tc := range cases {
   116  		t.Run(tc.name, func(t *testing.T) {
   117  			got, err := dnsCache.FetchItem(tc.Host)
   118  
   119  			if tc.expectedErrorType != nil {
   120  				if err == nil || tc.expectedErrorType != reflect.TypeOf(err) {
   121  					t.Fatalf("wanted FetchItem error type %v, got %v. Error=%#v", tc.expectedErrorType, reflect.TypeOf(err), err)
   122  				}
   123  
   124  				if _, ok := dnsCache.Get(tc.Host); got != nil || ok {
   125  					t.Fatalf("wanted FetchItem error to omit cache. got %#v, ok=%t", got, ok)
   126  				}
   127  				return
   128  			}
   129  
   130  			if err != nil || !reflect.DeepEqual(got, tc.ExpectedIPs) {
   131  				t.Fatalf("wanted ips %q, got %q. Error: %v", tc.ExpectedIPs, got, err)
   132  			}
   133  
   134  			if tc.shouldExistInCache || tc.shouldBeAddedToCache {
   135  				record, ok := dnsCache.Get(tc.Host)
   136  
   137  				if !ok {
   138  					t.Fatalf("Host addresses weren't found in cache; host %q", tc.Host)
   139  				}
   140  
   141  				if !test.IsDnsRecordsAddrsEqualsTo(record.Addrs, tc.ExpectedIPs) {
   142  					t.Fatalf("wanted cached ips %v, got record %v", tc.ExpectedIPs, record)
   143  				}
   144  			} else {
   145  				if got, ok := dnsCache.Get(tc.Host); !test.IsDnsRecordsAddrsEqualsTo(got.Addrs, nil) || ok {
   146  					t.Fatalf("wanted FetchItem to omit write to cache. got %#v, ok=%t", got, ok)
   147  				}
   148  			}
   149  		})
   150  	}
   151  }
   152  
   153  func TestStorageRecordExpiration(t *testing.T) {
   154  	var (
   155  		expiration    = 2000
   156  		checkInterval = 1500
   157  	)
   158  
   159  	type testRecord struct {
   160  		dns      string
   161  		addrs    []string
   162  		addDelay time.Duration
   163  	}
   164  
   165  	cases := []struct {
   166  		name string
   167  
   168  		records              []testRecord
   169  		sleepBeforeCleanup   time.Duration
   170  		notExpiredAfterDelay []testRecord
   171  		checkInterval        int
   172  	}{
   173  		{
   174  			"Shouldn't remove dns record when ttl/expiration < 1",
   175  			[]testRecord{
   176  				{dns: host, addrs: etcHostsMap[host]},
   177  			},
   178  			time.Duration(checkInterval+10) * time.Millisecond,
   179  			[]testRecord{
   180  				{dns: host, addrs: etcHostsMap[host]},
   181  			},
   182  			checkInterval,
   183  		},
   184  		{
   185  			"Should remove single dns record after expiration",
   186  			[]testRecord{
   187  				{dns: host, addrs: etcHostsMap[host]},
   188  			},
   189  			time.Duration(expiration+10) * time.Millisecond,
   190  			[]testRecord{},
   191  			checkInterval,
   192  		},
   193  		{
   194  			"Should leave as expired dns records if check_interval=-1",
   195  			[]testRecord{
   196  				{dns: host, addrs: etcHostsMap[host]},
   197  				{dns: host2, addrs: etcHostsMap[host2]},
   198  				{dns: wsHost, addrs: etcHostsMap[wsHost]},
   199  			},
   200  			time.Duration(checkInterval+10) * time.Millisecond,
   201  			[]testRecord{
   202  				{dns: host, addrs: etcHostsMap[host]},
   203  				{dns: host2, addrs: etcHostsMap[host2]},
   204  				{dns: wsHost, addrs: etcHostsMap[wsHost]},
   205  			},
   206  			-1,
   207  		},
   208  		{
   209  			"Should remove all(>1) dns records after expiration",
   210  			[]testRecord{
   211  				{dns: host2, addrs: etcHostsMap[host]},
   212  				{dns: host2, addrs: etcHostsMap[host2]},
   213  				{dns: host2, addrs: etcHostsMap[wsHost]},
   214  			},
   215  			time.Duration(expiration+10) * time.Millisecond,
   216  			[]testRecord{},
   217  			checkInterval,
   218  		},
   219  		{
   220  			"Should remove only expired record after expiration",
   221  			[]testRecord{
   222  				{dns: host, addrs: etcHostsMap[host]},
   223  				{dns: host2, addrs: etcHostsMap[host2], addDelay: 500 * time.Millisecond},
   224  				{dns: wsHost, addrs: etcHostsMap[wsHost]},
   225  			},
   226  			time.Duration(expiration-400) * time.Millisecond,
   227  			[]testRecord{
   228  				{dns: host2, addrs: etcHostsMap[host2]},
   229  				{dns: wsHost, addrs: etcHostsMap[wsHost]},
   230  			},
   231  			checkInterval,
   232  		},
   233  		{
   234  			"Should remove only expired records after expiration",
   235  			[]testRecord{
   236  				{dns: host, addrs: etcHostsMap[host]},
   237  				{dns: host2, addrs: etcHostsMap[host2], addDelay: 250 * time.Millisecond},
   238  				{dns: host3, addrs: etcHostsMap[host3], addDelay: 500 * time.Millisecond},
   239  				{dns: host4, addrs: etcHostsMap[host4], addDelay: 100 * time.Millisecond},
   240  				{dns: wsHost, addrs: etcHostsMap[wsHost]},
   241  			},
   242  			time.Duration(expiration-350) * time.Millisecond,
   243  			[]testRecord{
   244  				{dns: host3, addrs: etcHostsMap[host3]},
   245  				{dns: host4, addrs: etcHostsMap[host4]},
   246  				{dns: wsHost, addrs: etcHostsMap[wsHost]},
   247  			},
   248  			checkInterval,
   249  		},
   250  	}
   251  
   252  	for _, tc := range cases {
   253  		t.Run(tc.name, func(t *testing.T) {
   254  			dnsCache := NewDnsCacheStorage(time.Duration(expiration)*time.Millisecond, time.Duration(tc.checkInterval)*time.Millisecond)
   255  
   256  			for _, r := range tc.records {
   257  				if r.addDelay > 0 {
   258  					time.Sleep(r.addDelay)
   259  				}
   260  				dnsCache.Set(r.dns, r.addrs)
   261  			}
   262  
   263  			if tc.sleepBeforeCleanup > 0 {
   264  				time.Sleep(tc.sleepBeforeCleanup)
   265  			}
   266  			if lenNonExpired, lenCurrent := len(tc.notExpiredAfterDelay), len(dnsCache.Items(tc.checkInterval == -1)); lenNonExpired != lenCurrent {
   267  				t.Fatalf("wanted len(nonExpiredItems) %d, got %d. items=%+v", lenNonExpired, lenCurrent, dnsCache.Items(tc.checkInterval == -1))
   268  			}
   269  
   270  			if tc.checkInterval == -1 {
   271  				for _, r := range tc.records {
   272  					if item, ok := dnsCache.Items(true)[r.dns]; !ok || !test.IsDnsRecordsAddrsEqualsTo(item.Addrs, r.addrs) {
   273  						t.Fatalf("wanted expired cached ips %v, got item %#v. items=%+v, ok=%t", r.addrs, item, dnsCache.Items(true), ok)
   274  					}
   275  				}
   276  			} else {
   277  				for _, r := range tc.notExpiredAfterDelay {
   278  					if item, ok := dnsCache.Get(r.dns); !ok || !test.IsDnsRecordsAddrsEqualsTo(item.Addrs, r.addrs) {
   279  						t.Fatalf("wanted cached ips %v, got item %#v. items=%+v, ok=%t", r.addrs, item, dnsCache.Items(false), ok)
   280  					}
   281  				}
   282  			}
   283  
   284  			dnsCache.Clear()
   285  			dnsCache = nil
   286  		})
   287  	}
   288  }