github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/modules/dns-helper/dns_helper_test.go (about)

     1  package dns_helper
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/gruntwork-io/terratest/modules/retry"
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  // These are the current public nameservers for gruntwork.io domain
    13  // They should be updated whenever they change to pass the tests
    14  // relying on the public DNS infrastructure
    15  var publicDomainNameservers = []string{
    16  	"ns-1499.awsdns-59.org",
    17  	"ns-190.awsdns-23.com",
    18  	"ns-1989.awsdns-56.co.uk",
    19  	"ns-853.awsdns-42.net",
    20  }
    21  
    22  var testDNSDatabase = dnsDatabase{
    23  	DNSQuery{"A", "a." + testDomain}: DNSAnswers{
    24  		{"A", "2.2.2.2"},
    25  		{"A", "1.1.1.1"},
    26  	},
    27  
    28  	DNSQuery{"AAAA", "aaaa." + testDomain}: DNSAnswers{
    29  		{"AAAA", "2001:db8::aaaa"},
    30  	},
    31  
    32  	DNSQuery{"CNAME", "terratest." + testDomain}: DNSAnswers{
    33  		{"CNAME", "gruntwork-io.github.io."},
    34  	},
    35  
    36  	DNSQuery{"CNAME", "cname1." + testDomain}: DNSAnswers{
    37  		{"CNAME", "cname2." + testDomain + "."},
    38  	},
    39  
    40  	DNSQuery{"A", "cname1." + testDomain}: DNSAnswers{
    41  		{"CNAME", "cname2." + testDomain + "."},
    42  		{"CNAME", "cname3." + testDomain + "."},
    43  		{"CNAME", "cname4." + testDomain + "."},
    44  		{"CNAME", "cnamefinal." + testDomain + "."},
    45  		{"A", "1.1.1.1"},
    46  	},
    47  
    48  	DNSQuery{"TXT", "txt." + testDomain}: DNSAnswers{
    49  		{"TXT", `"This is a text."`},
    50  	},
    51  
    52  	DNSQuery{"MX", testDomain}: DNSAnswers{
    53  		{"MX", "10 mail." + testDomain + "."},
    54  	},
    55  }
    56  
    57  // Lookup should succeed in finding the nameservers of the public domain
    58  // Uses system resolver config
    59  func TestOkDNSFindNameservers(t *testing.T) {
    60  	t.Parallel()
    61  	fqdn := "terratest.gruntwork.io"
    62  	expectedNameservers := publicDomainNameservers
    63  	nameservers, err := DNSFindNameserversE(t, fqdn, nil)
    64  	require.NoError(t, err)
    65  	require.ElementsMatch(t, nameservers, expectedNameservers)
    66  }
    67  
    68  // Lookup should fail because of inexistent domain
    69  // Uses system resolver config
    70  func TestErrorDNSFindNameservers(t *testing.T) {
    71  	t.Parallel()
    72  	fqdn := "this.domain.doesnt.exist"
    73  	nameservers, err := DNSFindNameserversE(t, fqdn, nil)
    74  	require.Error(t, err)
    75  	require.Nil(t, nameservers)
    76  }
    77  
    78  // Lookup should succeed with answers from just one authoritative nameserver
    79  // Uses system resolver config to lookup a public domain and its public nameservers
    80  func TestOkTerratestDNSLookupAuthoritative(t *testing.T) {
    81  	t.Parallel()
    82  	dnsQuery := DNSQuery{"CNAME", "terratest." + testDomain}
    83  	expected := DNSAnswers{{"CNAME", "gruntwork-io.github.io."}}
    84  	res, err := DNSLookupAuthoritativeE(t, dnsQuery, nil)
    85  	require.NoError(t, err)
    86  	require.ElementsMatch(t, res, expected)
    87  }
    88  
    89  // ***********************************
    90  // Tests that use local dnsTestServers
    91  
    92  // Lookup should succeed with answers from just one authoritative nameserver
    93  func TestOkLocalDNSLookupAuthoritative(t *testing.T) {
    94  	t.Parallel()
    95  	s1, s2 := setupTestDNSServers(t)
    96  	defer shutDownServers(t, s1, s2)
    97  	for dnsQuery, expected := range testDNSDatabase {
    98  		s1.AddEntryToDNSDatabase(dnsQuery, expected)
    99  		res, err := DNSLookupAuthoritativeE(t, dnsQuery, []string{s1.Address(), s2.Address()})
   100  		require.NoError(t, err)
   101  		require.ElementsMatch(t, res, expected)
   102  	}
   103  }
   104  
   105  // Lookup should fail because of missing answers from all authoritative nameservers
   106  func TestErrorLocalDNSLookupAuthoritative(t *testing.T) {
   107  	t.Parallel()
   108  	s1, s2 := setupTestDNSServers(t)
   109  	defer shutDownServers(t, s1, s2)
   110  	dnsQuery := DNSQuery{"A", "txt." + testDomain}
   111  	_, err := DNSLookupAuthoritativeE(t, dnsQuery, []string{s1.Address(), s2.Address()})
   112  	if _, ok := err.(*NotFoundError); !ok {
   113  		t.Errorf("unexpected error, got %q", err)
   114  	}
   115  }
   116  
   117  // Lookup should succeed with consistent answers from all authoritative nameservers
   118  func TestOkLocalDNSLookupAuthoritativeAll(t *testing.T) {
   119  	t.Parallel()
   120  	s1, s2 := setupTestDNSServers(t)
   121  	defer shutDownServers(t, s1, s2)
   122  	for dnsQuery, expected := range testDNSDatabase {
   123  		s1.AddEntryToDNSDatabase(dnsQuery, expected)
   124  		s2.AddEntryToDNSDatabase(dnsQuery, expected)
   125  		res, err := DNSLookupAuthoritativeE(t, dnsQuery, []string{s1.Address(), s2.Address()})
   126  		require.NoError(t, err)
   127  		require.ElementsMatch(t, res, expected)
   128  	}
   129  }
   130  
   131  // Lookup should fail because of missing answers from all authoritative nameservers
   132  func TestError1DNSLookupAuthoritativeAll(t *testing.T) {
   133  	t.Parallel()
   134  	s1, s2 := setupTestDNSServers(t)
   135  	defer shutDownServers(t, s1, s2)
   136  	dnsQuery := DNSQuery{"A", "txt." + testDomain}
   137  	_, err := DNSLookupAuthoritativeAllE(t, dnsQuery, []string{s1.Address(), s2.Address()})
   138  	if _, ok := err.(*NotFoundError); !ok {
   139  		t.Errorf("unexpected error, got %q", err)
   140  	}
   141  }
   142  
   143  // Lookup should fail because of missing answers from one authoritative nameserver
   144  func TestError2DNSLookupAuthoritativeAll(t *testing.T) {
   145  	t.Parallel()
   146  	s1, s2 := setupTestDNSServers(t)
   147  	defer shutDownServers(t, s1, s2)
   148  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   149  	s1.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "1.1.1.1"}})
   150  	_, err := DNSLookupAuthoritativeAllE(t, dnsQuery, []string{s1.Address(), s2.Address()})
   151  	if _, ok := err.(*NotFoundError); !ok {
   152  		t.Errorf("unexpected error, got %q", err)
   153  	}
   154  }
   155  
   156  // Lookup should fail because of inconsistent answers from authoritative nameservers
   157  func TestError3DNSLookupAuthoritativeAll(t *testing.T) {
   158  	t.Parallel()
   159  	s1, s2 := setupTestDNSServers(t)
   160  	defer shutDownServers(t, s1, s2)
   161  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   162  	s1.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "1.1.1.1"}})
   163  	s2.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   164  	_, err := DNSLookupAuthoritativeAllE(t, dnsQuery, []string{s1.Address(), s2.Address()})
   165  	if _, ok := err.(*InconsistentAuthoritativeError); !ok {
   166  		t.Errorf("unexpected error, got %q", err)
   167  	}
   168  }
   169  
   170  // Lookup should fail because of inexistent domain
   171  func TestError4DNSLookupAuthoritativeAll(t *testing.T) {
   172  	t.Parallel()
   173  	s1, s2 := setupTestDNSServers(t)
   174  	defer shutDownServers(t, s1, s2)
   175  	dnsQuery := DNSQuery{"A", "this.domain.doesnt.exist"}
   176  	_, err := DNSLookupAuthoritativeAllE(t, dnsQuery, []string{s1.Address(), s2.Address()})
   177  	if _, ok := err.(*NSNotFoundError); !ok {
   178  		t.Errorf("unexpected error, got %q", err)
   179  	}
   180  }
   181  
   182  // First lookups should fail because of missing answers from all authoritative nameservers
   183  // Retry lookups should succeed with answers from just one authoritative nameserver
   184  func TestOkDNSLookupAuthoritativeWithRetry(t *testing.T) {
   185  	t.Parallel()
   186  	s1, s2 := setupTestDNSServersRetry(t)
   187  	defer shutDownServers(t, s1, s2)
   188  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   189  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   190  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   191  	res, err := DNSLookupAuthoritativeWithRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, 5, time.Second)
   192  	require.NoError(t, err)
   193  	require.ElementsMatch(t, res, expectedRes)
   194  }
   195  
   196  // First lookups should fail because of missing answers from all authoritative nameservers
   197  // Retry lookups should fail because of missing answers from all authoritative nameservers
   198  func TestErrorDNSLookupAuthoritativeWithRetry(t *testing.T) {
   199  	t.Parallel()
   200  	s1, s2 := setupTestDNSServersRetry(t)
   201  	defer shutDownServers(t, s1, s2)
   202  	dnsQuery := DNSQuery{"A", "txt." + testDomain}
   203  	_, err := DNSLookupAuthoritativeWithRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, 5, time.Second)
   204  	require.Error(t, err)
   205  	if _, ok := err.(retry.MaxRetriesExceeded); !ok {
   206  		t.Errorf("unexpected error, got %q", err)
   207  	}
   208  }
   209  
   210  // First lookups should fail because of missing answers from one authoritative nameservers
   211  // Retry lookups should succeed with consistent answers
   212  func TestOkDNSLookupAuthoritativeAllWithRetryNotfound(t *testing.T) {
   213  	t.Parallel()
   214  	s1, s2 := setupTestDNSServersRetry(t)
   215  	defer shutDownServers(t, s1, s2)
   216  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   217  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   218  	s1.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   219  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   220  	s2.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   221  	res, err := DNSLookupAuthoritativeAllWithRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, 5, time.Second)
   222  	require.NoError(t, err)
   223  	require.ElementsMatch(t, res, expectedRes)
   224  }
   225  
   226  // First lookups should fail because of inconsistent answers from authoritative nameservers
   227  // Retry lookups should succeed with consistent answers
   228  func TestOkDNSLookupAuthoritativeAllWithRetryInconsistent(t *testing.T) {
   229  	t.Parallel()
   230  	s1, s2 := setupTestDNSServersRetry(t)
   231  	defer shutDownServers(t, s1, s2)
   232  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   233  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   234  	s1.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   235  	s2.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   236  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   237  	s2.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   238  	res, err := DNSLookupAuthoritativeAllWithRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, 5, time.Second)
   239  	require.NoError(t, err)
   240  	require.ElementsMatch(t, res, expectedRes)
   241  }
   242  
   243  // First lookups should fail because of missing answer from one authoritative nameserver
   244  // Retry lookups should fail because of inconsistent answers from authoritative nameservers
   245  func TestErrorDNSLookupAuthoritativeAllWithRetry(t *testing.T) {
   246  	t.Parallel()
   247  	s1, s2 := setupTestDNSServersRetry(t)
   248  	defer shutDownServers(t, s1, s2)
   249  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   250  	s1.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   251  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}})
   252  	s2.AddEntryToDNSDatabaseRetry(dnsQuery, DNSAnswers{{"A", "1.1.1.1"}})
   253  	_, err := DNSLookupAuthoritativeAllWithRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, 5, time.Second)
   254  	require.Error(t, err)
   255  	if _, ok := err.(retry.MaxRetriesExceeded); !ok {
   256  		t.Errorf("unexpected error, got %q", err)
   257  	}
   258  }
   259  
   260  // Lookup should succeed with consistent and validated replies
   261  func TestOkDNSLookupAuthoritativeAllWithValidation(t *testing.T) {
   262  	t.Parallel()
   263  	s1, s2 := setupTestDNSServers(t)
   264  	defer shutDownServers(t, s1, s2)
   265  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   266  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   267  	s1.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   268  	s2.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   269  	err := DNSLookupAuthoritativeAllWithValidationE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes)
   270  	require.NoError(t, err)
   271  }
   272  
   273  // Lookup should fail because of missing answers from all authoritative nameservers
   274  func TestErrorDNSLookupAuthoritativeAllWithValidation(t *testing.T) {
   275  	t.Parallel()
   276  	s1, s2 := setupTestDNSServers(t)
   277  	defer shutDownServers(t, s1, s2)
   278  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   279  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   280  	err := DNSLookupAuthoritativeAllWithValidationE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes)
   281  	require.Error(t, err)
   282  	if _, ok := err.(*NotFoundError); !ok {
   283  		t.Errorf("unexpected error, got %q", err)
   284  	}
   285  }
   286  
   287  // Lookup should fail because of missing answers from one authoritative nameservers
   288  func TestError2DNSLookupAuthoritativeAllWithValidation(t *testing.T) {
   289  	t.Parallel()
   290  	s1, s2 := setupTestDNSServers(t)
   291  	defer shutDownServers(t, s1, s2)
   292  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   293  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   294  	s1.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   295  	err := DNSLookupAuthoritativeAllWithValidationE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes)
   296  	require.Error(t, err)
   297  	if _, ok := err.(*NotFoundError); !ok {
   298  		t.Errorf("unexpected error, got %q", err)
   299  	}
   300  }
   301  
   302  // Lookup should fail because of inconsistent authoritative replies
   303  func TestError3DNSLookupAuthoritativeAllWithValidation(t *testing.T) {
   304  	t.Parallel()
   305  	s1, s2 := setupTestDNSServers(t)
   306  	defer shutDownServers(t, s1, s2)
   307  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   308  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   309  	s1.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   310  	s2.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   311  	err := DNSLookupAuthoritativeAllWithValidationE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes)
   312  	require.Error(t, err)
   313  	if _, ok := err.(*InconsistentAuthoritativeError); !ok {
   314  		t.Errorf("unexpected error, got %q", err)
   315  	}
   316  }
   317  
   318  // First lookups should fail because of missing answers from all authoritative nameservers
   319  // Retry lookups should succeed with consistent and validated replies
   320  func TestOkDNSLookupAuthoritativeAllWithValidationRetry(t *testing.T) {
   321  	t.Parallel()
   322  	s1, s2 := setupTestDNSServersRetry(t)
   323  	defer shutDownServers(t, s1, s2)
   324  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   325  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   326  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   327  	s2.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   328  	err := DNSLookupAuthoritativeAllWithValidationRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes, 5, time.Second)
   329  	require.NoError(t, err)
   330  }
   331  
   332  // First lookups should fail because of missing answer from one authoritative nameserver
   333  // Retry lookups should succeed with consistent and validated replies
   334  func TestOk2DNSLookupAuthoritativeAllWithValidationRetry(t *testing.T) {
   335  	t.Parallel()
   336  	s1, s2 := setupTestDNSServersRetry(t)
   337  	defer shutDownServers(t, s1, s2)
   338  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   339  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   340  	s1.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   341  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   342  	s2.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   343  	err := DNSLookupAuthoritativeAllWithValidationRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes, 5, time.Second)
   344  	require.NoError(t, err)
   345  }
   346  
   347  // First lookups should fail because of inconsistent authoritative replies
   348  // Retry lookups should succeed with consistent and validated replies
   349  func TestOk3DNSLookupAuthoritativeAllWithValidationRetry(t *testing.T) {
   350  	t.Parallel()
   351  	s1, s2 := setupTestDNSServersRetry(t)
   352  	defer shutDownServers(t, s1, s2)
   353  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   354  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   355  	s1.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   356  	s2.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   357  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   358  	s2.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   359  	err := DNSLookupAuthoritativeAllWithValidationRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes, 5, time.Second)
   360  	require.NoError(t, err)
   361  }
   362  
   363  // First lookups should fail because of inconsistent authoritative replies
   364  // Retry lookups should fail also because of inconsistent authoritative replies
   365  func TestErrorDNSLookupAuthoritativeAllWithValidationRetry(t *testing.T) {
   366  	t.Parallel()
   367  	s1, s2 := setupTestDNSServersRetry(t)
   368  	defer shutDownServers(t, s1, s2)
   369  	dnsQuery := DNSQuery{"A", "a." + testDomain}
   370  	expectedRes := DNSAnswers{{"A", "1.1.1.1"}, {"A", "2.2.2.2"}}
   371  	s1.AddEntryToDNSDatabase(dnsQuery, expectedRes)
   372  	s2.AddEntryToDNSDatabase(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   373  	s1.AddEntryToDNSDatabaseRetry(dnsQuery, expectedRes)
   374  	s2.AddEntryToDNSDatabaseRetry(dnsQuery, DNSAnswers{{"A", "2.2.2.2"}})
   375  	err := DNSLookupAuthoritativeAllWithValidationRetryE(t, dnsQuery, []string{s1.Address(), s2.Address()}, expectedRes, 5, time.Second)
   376  	if _, ok := err.(retry.MaxRetriesExceeded); !ok {
   377  		t.Errorf("unexpected error, got %q", err)
   378  	}
   379  }
   380  
   381  func shutDownServers(t *testing.T, s1, s2 *dnsTestServer) {
   382  	err := s1.Server.Shutdown()
   383  	assert.NoError(t, err)
   384  	err = s2.Server.Shutdown()
   385  	assert.NoError(t, err)
   386  }