github.com/netdata/go.d.plugin@v0.58.1/modules/dnsdist/dnsdist_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package dnsdist
     4  
     5  import (
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"os"
     9  	"testing"
    10  
    11  	"github.com/netdata/go.d.plugin/pkg/tlscfg"
    12  	"github.com/netdata/go.d.plugin/pkg/web"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  var (
    19  	v151JSONStat, _ = os.ReadFile("testdata/v1.5.1/jsonstat.json")
    20  )
    21  
    22  func Test_testDataIsCorrectlyReadAndValid(t *testing.T) {
    23  	for name, data := range map[string][]byte{
    24  		"v151JSONStat": v151JSONStat,
    25  	} {
    26  		require.NotNilf(t, data, name)
    27  	}
    28  }
    29  
    30  func TestNew(t *testing.T) {
    31  	assert.IsType(t, (*DNSdist)(nil), New())
    32  }
    33  
    34  func Test_Init(t *testing.T) {
    35  	tests := map[string]struct {
    36  		config   Config
    37  		wantFail bool
    38  	}{
    39  		"success on default config": {
    40  			config: New().Config,
    41  		},
    42  		"fails on unset URL": {
    43  			wantFail: true,
    44  			config: Config{
    45  				HTTP: web.HTTP{
    46  					Request: web.Request{URL: ""},
    47  				},
    48  			},
    49  		},
    50  		"fails on invalid TLSCA": {
    51  			wantFail: true,
    52  			config: Config{
    53  				HTTP: web.HTTP{
    54  					Request: web.Request{
    55  						URL: "http://127.0.0.1:38001",
    56  					},
    57  					Client: web.Client{
    58  						TLSConfig: tlscfg.TLSConfig{TLSCA: "testdata/tls"},
    59  					},
    60  				},
    61  			},
    62  		},
    63  	}
    64  
    65  	for name, test := range tests {
    66  		t.Run(name, func(t *testing.T) {
    67  			ns := New()
    68  			ns.Config = test.config
    69  
    70  			if test.wantFail {
    71  				assert.False(t, ns.Init())
    72  			} else {
    73  				assert.True(t, ns.Init())
    74  			}
    75  		})
    76  	}
    77  }
    78  
    79  func Test_Charts(t *testing.T) {
    80  	dist := New()
    81  	require.True(t, dist.Init())
    82  	assert.NotNil(t, dist.Charts())
    83  }
    84  
    85  func Test_Cleanup(t *testing.T) {
    86  	assert.NotPanics(t, New().Cleanup)
    87  }
    88  
    89  func Test_Check(t *testing.T) {
    90  	tests := map[string]struct {
    91  		prepare  func() (dist *DNSdist, cleanup func())
    92  		wantFail bool
    93  	}{
    94  		"success on valid response v1.5.1": {
    95  			prepare:  preparePowerDNSdistV151,
    96  			wantFail: false,
    97  		},
    98  		"fails on 404 response": {
    99  			prepare:  preparePowerDNSdist404,
   100  			wantFail: true,
   101  		},
   102  		"fails on connection refused": {
   103  			prepare:  preparePowerDNSdistConnectionRefused,
   104  			wantFail: true,
   105  		},
   106  		"fails with invalid data": {
   107  			prepare:  preparePowerDNSdistInvalidData,
   108  			wantFail: true,
   109  		},
   110  	}
   111  
   112  	for name, test := range tests {
   113  		t.Run(name, func(t *testing.T) {
   114  			dist, cleanup := test.prepare()
   115  			defer cleanup()
   116  			require.True(t, dist.Init())
   117  
   118  			if test.wantFail {
   119  				assert.False(t, dist.Check())
   120  			} else {
   121  				assert.True(t, dist.Check())
   122  			}
   123  		})
   124  	}
   125  }
   126  
   127  func Test_Collect(t *testing.T) {
   128  	tests := map[string]struct {
   129  		prepare       func() (dist *DNSdist, cleanup func())
   130  		wantCollected map[string]int64
   131  	}{
   132  		"success on valid response v1.5.1": {
   133  			prepare: preparePowerDNSdistV151,
   134  			wantCollected: map[string]int64{
   135  				"acl-drops":              1,
   136  				"cache-hits":             1,
   137  				"cache-misses":           1,
   138  				"cpu-sys-msec":           411,
   139  				"cpu-user-msec":          939,
   140  				"downstream-send-errors": 1,
   141  				"downstream-timeouts":    1,
   142  				"dyn-blocked":            1,
   143  				"empty-queries":          1,
   144  				"latency-avg100":         14237,
   145  				"latency-avg1000":        9728,
   146  				"latency-avg10000":       1514,
   147  				"latency-avg1000000":     15,
   148  				"latency-slow":           1,
   149  				"latency0-1":             1,
   150  				"latency1-10":            3,
   151  				"latency10-50":           996,
   152  				"latency100-1000":        4,
   153  				"latency50-100":          1,
   154  				"no-policy":              1,
   155  				"noncompliant-queries":   1,
   156  				"noncompliant-responses": 1,
   157  				"queries":                1003,
   158  				"rdqueries":              1003,
   159  				"real-memory-usage":      202125312,
   160  				"responses":              1003,
   161  				"rule-drop":              1,
   162  				"rule-nxdomain":          1,
   163  				"rule-refused":           1,
   164  				"self-answered":          1,
   165  				"servfail-responses":     1,
   166  				"trunc-failures":         1,
   167  			},
   168  		},
   169  		"fails on 404 response": {
   170  			prepare: preparePowerDNSdist404,
   171  		},
   172  		"fails on connection refused": {
   173  			prepare: preparePowerDNSdistConnectionRefused,
   174  		},
   175  		"fails with invalid data": {
   176  			prepare: preparePowerDNSdistInvalidData,
   177  		},
   178  	}
   179  
   180  	for name, test := range tests {
   181  		t.Run(name, func(t *testing.T) {
   182  			dist, cleanup := test.prepare()
   183  			defer cleanup()
   184  			require.True(t, dist.Init())
   185  
   186  			collected := dist.Collect()
   187  
   188  			assert.Equal(t, test.wantCollected, collected)
   189  			if len(test.wantCollected) > 0 {
   190  				ensureCollectedHasAllChartsDimsVarsIDs(t, dist, collected)
   191  			}
   192  		})
   193  	}
   194  }
   195  
   196  func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, dist *DNSdist, collected map[string]int64) {
   197  	for _, chart := range *dist.Charts() {
   198  		if chart.Obsolete {
   199  			continue
   200  		}
   201  		for _, dim := range chart.Dims {
   202  			_, ok := collected[dim.ID]
   203  			assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", dim.ID, chart.ID)
   204  		}
   205  		for _, v := range chart.Vars {
   206  			_, ok := collected[v.ID]
   207  			assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", v.ID, chart.ID)
   208  		}
   209  	}
   210  }
   211  
   212  func preparePowerDNSdistV151() (*DNSdist, func()) {
   213  	srv := preparePowerDNSDistEndpoint()
   214  	ns := New()
   215  	ns.URL = srv.URL
   216  
   217  	return ns, srv.Close
   218  }
   219  
   220  func preparePowerDNSdist404() (*DNSdist, func()) {
   221  	srv := httptest.NewServer(http.HandlerFunc(
   222  		func(w http.ResponseWriter, r *http.Request) {
   223  			w.WriteHeader(http.StatusNotFound)
   224  		}))
   225  	ns := New()
   226  	ns.URL = srv.URL
   227  
   228  	return ns, srv.Close
   229  }
   230  
   231  func preparePowerDNSdistConnectionRefused() (*DNSdist, func()) {
   232  	ns := New()
   233  	ns.URL = "http://127.0.0.1:38001"
   234  
   235  	return ns, func() {}
   236  }
   237  
   238  func preparePowerDNSdistInvalidData() (*DNSdist, func()) {
   239  	srv := httptest.NewServer(http.HandlerFunc(
   240  		func(w http.ResponseWriter, r *http.Request) {
   241  			_, _ = w.Write([]byte("hello and\n goodbye"))
   242  		}))
   243  	ns := New()
   244  	ns.URL = srv.URL
   245  
   246  	return ns, srv.Close
   247  }
   248  
   249  func preparePowerDNSDistEndpoint() *httptest.Server {
   250  	return httptest.NewServer(http.HandlerFunc(
   251  		func(w http.ResponseWriter, r *http.Request) {
   252  			switch r.URL.String() {
   253  			case "/jsonstat?command=stats":
   254  				_, _ = w.Write(v151JSONStat)
   255  			default:
   256  				w.WriteHeader(http.StatusNotFound)
   257  			}
   258  		}))
   259  }