github.com/thanos-io/thanos@v0.32.5/pkg/discovery/dns/resolver_test.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package dns
     5  
     6  import (
     7  	"context"
     8  	"net"
     9  	"sort"
    10  	"testing"
    11  
    12  	"github.com/go-kit/log"
    13  
    14  	"github.com/pkg/errors"
    15  
    16  	"github.com/efficientgo/core/testutil"
    17  )
    18  
    19  type mockHostnameResolver struct {
    20  	resultIPs  map[string][]net.IPAddr
    21  	resultSRVs map[string][]*net.SRV
    22  	err        error
    23  }
    24  
    25  func (m mockHostnameResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) {
    26  	if m.err != nil {
    27  		return nil, m.err
    28  	}
    29  	return m.resultIPs[host], nil
    30  }
    31  
    32  func (m mockHostnameResolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error) {
    33  	if m.err != nil {
    34  		return "", nil, m.err
    35  	}
    36  	return "", m.resultSRVs[name], nil
    37  }
    38  
    39  func (m mockHostnameResolver) IsNotFound(err error) bool {
    40  	return false
    41  }
    42  
    43  type DNSSDTest struct {
    44  	testName       string
    45  	addr           string
    46  	qtype          QType
    47  	expectedResult []string
    48  	expectedErr    error
    49  	resolver       *mockHostnameResolver
    50  }
    51  
    52  var (
    53  	errorFromResolver = errors.New("error from resolver")
    54  
    55  	dnsSDTests = []DNSSDTest{
    56  		{
    57  			testName:       "single ip from dns lookup of host port",
    58  			addr:           "test.mycompany.com:8080",
    59  			qtype:          A,
    60  			expectedResult: []string{"192.168.0.1:8080"},
    61  			expectedErr:    nil,
    62  			resolver: &mockHostnameResolver{
    63  				resultIPs: map[string][]net.IPAddr{
    64  					"test.mycompany.com": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}},
    65  				},
    66  			},
    67  		},
    68  		// Scheme is preserved.
    69  		{
    70  			testName:       "single ip from dns lookup of host port with scheme",
    71  			addr:           "http://test.mycompany.com:8080",
    72  			qtype:          A,
    73  			expectedResult: []string{"http://192.168.0.1:8080"},
    74  			expectedErr:    nil,
    75  			resolver: &mockHostnameResolver{
    76  				resultIPs: map[string][]net.IPAddr{
    77  					"test.mycompany.com": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}},
    78  				},
    79  			},
    80  		},
    81  		{
    82  			testName:       "error on dns lookup when no port is specified",
    83  			addr:           "test.mycompany.com",
    84  			qtype:          A,
    85  			expectedResult: nil,
    86  			expectedErr:    errors.New("missing port in address given for dns lookup: test.mycompany.com"),
    87  			resolver:       &mockHostnameResolver{},
    88  		},
    89  		{
    90  			testName:       "multiple SRV records from SRV lookup",
    91  			addr:           "_test._tcp.mycompany.com",
    92  			qtype:          SRV,
    93  			expectedResult: []string{"192.168.0.1:8080", "192.168.0.2:8081"},
    94  			expectedErr:    nil,
    95  			resolver: &mockHostnameResolver{
    96  				resultSRVs: map[string][]*net.SRV{
    97  					"_test._tcp.mycompany.com": {
    98  						&net.SRV{Target: "alt1.mycompany.com.", Port: 8080},
    99  						&net.SRV{Target: "alt2.mycompany.com.", Port: 8081},
   100  					},
   101  				},
   102  				resultIPs: map[string][]net.IPAddr{
   103  					"alt1.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}},
   104  					"alt2.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.2")}},
   105  				},
   106  			},
   107  		},
   108  		{
   109  			testName:       "multiple SRV records from SRV lookup with specified port",
   110  			addr:           "_test._tcp.mycompany.com:8082",
   111  			qtype:          SRV,
   112  			expectedResult: []string{"192.168.0.1:8082", "192.168.0.2:8082"},
   113  			expectedErr:    nil,
   114  			resolver: &mockHostnameResolver{
   115  				resultSRVs: map[string][]*net.SRV{
   116  					"_test._tcp.mycompany.com": {
   117  						&net.SRV{Target: "alt1.mycompany.com.", Port: 8080},
   118  						&net.SRV{Target: "alt2.mycompany.com.", Port: 8081},
   119  					},
   120  				},
   121  				resultIPs: map[string][]net.IPAddr{
   122  					"alt1.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.1")}},
   123  					"alt2.mycompany.com.": {net.IPAddr{IP: net.ParseIP("192.168.0.2")}},
   124  				},
   125  			},
   126  		},
   127  		{
   128  			testName:       "error from SRV resolver",
   129  			addr:           "_test._tcp.mycompany.com",
   130  			qtype:          SRV,
   131  			expectedResult: nil,
   132  			expectedErr:    errors.Wrapf(errorFromResolver, "lookup SRV records \"_test._tcp.mycompany.com\""),
   133  			resolver:       &mockHostnameResolver{err: errorFromResolver},
   134  		},
   135  		{
   136  			testName:       "multiple SRV records from SRV no A lookup",
   137  			addr:           "_test._tcp.mycompany.com",
   138  			qtype:          SRVNoA,
   139  			expectedResult: []string{"192.168.0.1:8080", "192.168.0.2:8081"},
   140  			expectedErr:    nil,
   141  			resolver: &mockHostnameResolver{
   142  				resultSRVs: map[string][]*net.SRV{
   143  					"_test._tcp.mycompany.com": {
   144  						&net.SRV{Target: "192.168.0.1", Port: 8080},
   145  						&net.SRV{Target: "192.168.0.2", Port: 8081},
   146  					},
   147  				},
   148  			},
   149  		},
   150  		{
   151  			testName:       "multiple SRV records from SRV no A lookup with specified port",
   152  			addr:           "_test._tcp.mycompany.com:8082",
   153  			qtype:          SRVNoA,
   154  			expectedResult: []string{"192.168.0.1:8082", "192.168.0.2:8082"},
   155  			expectedErr:    nil,
   156  			resolver: &mockHostnameResolver{
   157  				resultSRVs: map[string][]*net.SRV{
   158  					"_test._tcp.mycompany.com": {
   159  						&net.SRV{Target: "192.168.0.1", Port: 8080},
   160  						&net.SRV{Target: "192.168.0.2", Port: 8081},
   161  					},
   162  				},
   163  			},
   164  		},
   165  		{
   166  			testName:       "error from SRV no A lookup",
   167  			addr:           "_test._tcp.mycompany.com",
   168  			qtype:          SRV,
   169  			expectedResult: nil,
   170  			expectedErr:    errors.Wrapf(errorFromResolver, "lookup SRV records \"_test._tcp.mycompany.com\""),
   171  			resolver:       &mockHostnameResolver{err: errorFromResolver},
   172  		},
   173  		{
   174  			testName:       "error on bad qtype",
   175  			addr:           "test.mycompany.com",
   176  			qtype:          "invalid",
   177  			expectedResult: nil,
   178  			expectedErr:    errors.New("invalid lookup scheme \"invalid\""),
   179  			resolver:       &mockHostnameResolver{},
   180  		},
   181  	}
   182  )
   183  
   184  func TestDnsSD_Resolve(t *testing.T) {
   185  	for _, tt := range dnsSDTests {
   186  		t.Run(tt.testName, func(t *testing.T) {
   187  			testDnsSd(t, tt)
   188  		})
   189  	}
   190  }
   191  
   192  func testDnsSd(t *testing.T, tt DNSSDTest) {
   193  	ctx := context.TODO()
   194  	dnsSD := dnsSD{tt.resolver, log.NewNopLogger()}
   195  
   196  	result, err := dnsSD.Resolve(ctx, tt.addr, tt.qtype)
   197  	if tt.expectedErr != nil {
   198  		testutil.NotOk(t, err)
   199  		testutil.Assert(t, tt.expectedErr.Error() == err.Error(), "expected error '%v', but got '%v'", tt.expectedErr.Error(), err.Error())
   200  	} else {
   201  		testutil.Ok(t, err)
   202  	}
   203  	sort.Strings(result)
   204  	testutil.Equals(t, tt.expectedResult, result)
   205  }