github.com/netdata/go.d.plugin@v0.58.1/modules/dnsquery/dnsquery_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package dnsquery
     4  
     5  import (
     6  	"errors"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/netdata/go.d.plugin/agent/module"
    11  	"github.com/netdata/go.d.plugin/pkg/web"
    12  
    13  	"github.com/miekg/dns"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestNew(t *testing.T) {
    19  	assert.Implements(t, (*module.Module)(nil), New())
    20  }
    21  
    22  func TestDNSQuery_Init(t *testing.T) {
    23  	tests := map[string]struct {
    24  		wantFail bool
    25  		config   Config
    26  	}{
    27  		"success when all set": {
    28  			wantFail: false,
    29  			config: Config{
    30  				Domains:     []string{"example.com"},
    31  				Servers:     []string{"192.0.2.0"},
    32  				Network:     "udp",
    33  				RecordTypes: []string{"A"},
    34  				Port:        53,
    35  				Timeout:     web.Duration{Duration: time.Second},
    36  			},
    37  		},
    38  		"success when using deprecated record_type": {
    39  			wantFail: false,
    40  			config: Config{
    41  				Domains:    []string{"example.com"},
    42  				Servers:    []string{"192.0.2.0"},
    43  				Network:    "udp",
    44  				RecordType: "A",
    45  				Port:       53,
    46  				Timeout:    web.Duration{Duration: time.Second},
    47  			},
    48  		},
    49  		"fail with default": {
    50  			wantFail: true,
    51  			config:   New().Config,
    52  		},
    53  		"fail when domains not set": {
    54  			wantFail: true,
    55  			config: Config{
    56  				Domains:     nil,
    57  				Servers:     []string{"192.0.2.0"},
    58  				Network:     "udp",
    59  				RecordTypes: []string{"A"},
    60  				Port:        53,
    61  				Timeout:     web.Duration{Duration: time.Second},
    62  			},
    63  		},
    64  		"fail when servers not set": {
    65  			wantFail: true,
    66  			config: Config{
    67  				Domains:     []string{"example.com"},
    68  				Servers:     nil,
    69  				Network:     "udp",
    70  				RecordTypes: []string{"A"},
    71  				Port:        53,
    72  				Timeout:     web.Duration{Duration: time.Second},
    73  			},
    74  		},
    75  		"fail when network is invalid": {
    76  			wantFail: true,
    77  			config: Config{
    78  				Domains:     []string{"example.com"},
    79  				Servers:     []string{"192.0.2.0"},
    80  				Network:     "gcp",
    81  				RecordTypes: []string{"A"},
    82  				Port:        53,
    83  				Timeout:     web.Duration{Duration: time.Second},
    84  			},
    85  		},
    86  		"fail when record_type is invalid": {
    87  			wantFail: true,
    88  			config: Config{
    89  				Domains:     []string{"example.com"},
    90  				Servers:     []string{"192.0.2.0"},
    91  				Network:     "udp",
    92  				RecordTypes: []string{"B"},
    93  				Port:        53,
    94  				Timeout:     web.Duration{Duration: time.Second},
    95  			},
    96  		},
    97  	}
    98  
    99  	for name, test := range tests {
   100  		t.Run(name, func(t *testing.T) {
   101  			dq := New()
   102  			dq.Config = test.config
   103  
   104  			if test.wantFail {
   105  				assert.False(t, dq.Init())
   106  			} else {
   107  				assert.True(t, dq.Init())
   108  			}
   109  		})
   110  	}
   111  }
   112  
   113  func TestDNSQuery_Check(t *testing.T) {
   114  	tests := map[string]struct {
   115  		wantFail bool
   116  		prepare  func() *DNSQuery
   117  	}{
   118  		"success when DNS query successful": {
   119  			wantFail: false,
   120  			prepare:  caseDNSClientOK,
   121  		},
   122  		"success when DNS query returns an error": {
   123  			wantFail: false,
   124  			prepare:  caseDNSClientErr,
   125  		},
   126  	}
   127  
   128  	for name, test := range tests {
   129  		t.Run(name, func(t *testing.T) {
   130  			dq := test.prepare()
   131  
   132  			require.True(t, dq.Init())
   133  
   134  			if test.wantFail {
   135  				assert.False(t, dq.Check())
   136  			} else {
   137  				assert.True(t, dq.Check())
   138  			}
   139  		})
   140  	}
   141  }
   142  
   143  func TestDNSQuery_Charts(t *testing.T) {
   144  	dq := New()
   145  
   146  	dq.Domains = []string{"google.com"}
   147  	dq.Servers = []string{"192.0.2.0", "192.0.2.1"}
   148  	require.True(t, dq.Init())
   149  
   150  	assert.NotNil(t, dq.Charts())
   151  	assert.Len(t, *dq.Charts(), len(dnsChartsTmpl)*len(dq.Servers))
   152  }
   153  
   154  func TestDNSQuery_Collect(t *testing.T) {
   155  	tests := map[string]struct {
   156  		prepare     func() *DNSQuery
   157  		wantMetrics map[string]int64
   158  	}{
   159  		"success when DNS query successful": {
   160  			prepare: caseDNSClientOK,
   161  			wantMetrics: map[string]int64{
   162  				"server_192.0.2.0_record_A_query_status_dns_error":     0,
   163  				"server_192.0.2.0_record_A_query_status_network_error": 0,
   164  				"server_192.0.2.0_record_A_query_status_success":       1,
   165  				"server_192.0.2.0_record_A_query_time":                 1000000000,
   166  				"server_192.0.2.1_record_A_query_status_dns_error":     0,
   167  				"server_192.0.2.1_record_A_query_status_network_error": 0,
   168  				"server_192.0.2.1_record_A_query_status_success":       1,
   169  				"server_192.0.2.1_record_A_query_time":                 1000000000,
   170  			},
   171  		},
   172  		"fail when DNS query returns an error": {
   173  			prepare: caseDNSClientErr,
   174  			wantMetrics: map[string]int64{
   175  				"server_192.0.2.0_record_A_query_status_dns_error":     0,
   176  				"server_192.0.2.0_record_A_query_status_network_error": 1,
   177  				"server_192.0.2.0_record_A_query_status_success":       0,
   178  				"server_192.0.2.1_record_A_query_status_dns_error":     0,
   179  				"server_192.0.2.1_record_A_query_status_network_error": 1,
   180  				"server_192.0.2.1_record_A_query_status_success":       0,
   181  			},
   182  		},
   183  	}
   184  
   185  	for name, test := range tests {
   186  		t.Run(name, func(t *testing.T) {
   187  			dq := test.prepare()
   188  
   189  			require.True(t, dq.Init())
   190  
   191  			mx := dq.Collect()
   192  
   193  			require.Equal(t, test.wantMetrics, mx)
   194  		})
   195  	}
   196  }
   197  
   198  func caseDNSClientOK() *DNSQuery {
   199  	dq := New()
   200  	dq.Domains = []string{"example.com"}
   201  	dq.Servers = []string{"192.0.2.0", "192.0.2.1"}
   202  	dq.newDNSClient = func(_ string, _ time.Duration) dnsClient {
   203  		return mockDNSClient{errOnExchange: false}
   204  	}
   205  	return dq
   206  }
   207  
   208  func caseDNSClientErr() *DNSQuery {
   209  	dq := New()
   210  	dq.Domains = []string{"example.com"}
   211  	dq.Servers = []string{"192.0.2.0", "192.0.2.1"}
   212  	dq.newDNSClient = func(_ string, _ time.Duration) dnsClient {
   213  		return mockDNSClient{errOnExchange: true}
   214  	}
   215  	return dq
   216  }
   217  
   218  type mockDNSClient struct {
   219  	errOnExchange bool
   220  }
   221  
   222  func (m mockDNSClient) Exchange(_ *dns.Msg, _ string) (response *dns.Msg, rtt time.Duration, err error) {
   223  	if m.errOnExchange {
   224  		return nil, time.Second, errors.New("mock.Exchange() error")
   225  	}
   226  	return nil, time.Second, nil
   227  }