github.com/netdata/go.d.plugin@v0.58.1/modules/powerdns/authoritativens_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package powerdns
     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  	v430statistics, _     = os.ReadFile("testdata/v4.3.0/statistics.json")
    20  	recursorStatistics, _ = os.ReadFile("testdata/recursor/statistics.json")
    21  )
    22  
    23  func Test_testDataIsCorrectlyReadAndValid(t *testing.T) {
    24  	for name, data := range map[string][]byte{
    25  		"v430statistics":     v430statistics,
    26  		"recursorStatistics": recursorStatistics,
    27  	} {
    28  		require.NotNilf(t, data, name)
    29  	}
    30  }
    31  
    32  func TestNew(t *testing.T) {
    33  	assert.IsType(t, (*AuthoritativeNS)(nil), New())
    34  }
    35  
    36  func TestRecursor_Init(t *testing.T) {
    37  	tests := map[string]struct {
    38  		config   Config
    39  		wantFail bool
    40  	}{
    41  		"success on default config": {
    42  			config: New().Config,
    43  		},
    44  		"fails on unset URL": {
    45  			wantFail: true,
    46  			config: Config{
    47  				HTTP: web.HTTP{
    48  					Request: web.Request{URL: ""},
    49  				},
    50  			},
    51  		},
    52  		"fails on invalid TLSCA": {
    53  			wantFail: true,
    54  			config: Config{
    55  				HTTP: web.HTTP{
    56  					Request: web.Request{
    57  						URL: "http://127.0.0.1:38001",
    58  					},
    59  					Client: web.Client{
    60  						TLSConfig: tlscfg.TLSConfig{TLSCA: "testdata/tls"},
    61  					},
    62  				},
    63  			},
    64  		},
    65  	}
    66  
    67  	for name, test := range tests {
    68  		t.Run(name, func(t *testing.T) {
    69  			ns := New()
    70  			ns.Config = test.config
    71  
    72  			if test.wantFail {
    73  				assert.False(t, ns.Init())
    74  			} else {
    75  				assert.True(t, ns.Init())
    76  			}
    77  		})
    78  	}
    79  }
    80  
    81  func TestRecursor_Check(t *testing.T) {
    82  	tests := map[string]struct {
    83  		prepare  func() (p *AuthoritativeNS, cleanup func())
    84  		wantFail bool
    85  	}{
    86  		"success on valid response v4.3.0": {
    87  			prepare: preparePowerDNSAuthoritativeNSV430,
    88  		},
    89  		"fails on response from PowerDNS Recursor": {
    90  			wantFail: true,
    91  			prepare:  preparePowerDNSAuthoritativeNSRecursorData,
    92  		},
    93  		"fails on 404 response": {
    94  			wantFail: true,
    95  			prepare:  preparePowerDNSAuthoritativeNS404,
    96  		},
    97  		"fails on connection refused": {
    98  			wantFail: true,
    99  			prepare:  preparePowerDNSAuthoritativeNSConnectionRefused,
   100  		},
   101  		"fails on response with invalid data": {
   102  			wantFail: true,
   103  			prepare:  preparePowerDNSAuthoritativeNSInvalidData,
   104  		},
   105  	}
   106  
   107  	for name, test := range tests {
   108  		t.Run(name, func(t *testing.T) {
   109  			recursor, cleanup := test.prepare()
   110  			defer cleanup()
   111  			require.True(t, recursor.Init())
   112  
   113  			if test.wantFail {
   114  				assert.False(t, recursor.Check())
   115  			} else {
   116  				assert.True(t, recursor.Check())
   117  			}
   118  		})
   119  	}
   120  }
   121  
   122  func TestRecursor_Charts(t *testing.T) {
   123  	recursor := New()
   124  	require.True(t, recursor.Init())
   125  	assert.NotNil(t, recursor.Charts())
   126  }
   127  
   128  func TestRecursor_Cleanup(t *testing.T) {
   129  	assert.NotPanics(t, New().Cleanup)
   130  }
   131  
   132  func TestRecursor_Collect(t *testing.T) {
   133  	tests := map[string]struct {
   134  		prepare       func() (p *AuthoritativeNS, cleanup func())
   135  		wantCollected map[string]int64
   136  	}{
   137  		"success on valid response v4.3.0": {
   138  			prepare: preparePowerDNSAuthoritativeNSV430,
   139  			wantCollected: map[string]int64{
   140  				"corrupt-packets":                1,
   141  				"cpu-iowait":                     513,
   142  				"cpu-steal":                      1,
   143  				"deferred-cache-inserts":         1,
   144  				"deferred-cache-lookup":          1,
   145  				"deferred-packetcache-inserts":   1,
   146  				"deferred-packetcache-lookup":    1,
   147  				"dnsupdate-answers":              1,
   148  				"dnsupdate-changes":              1,
   149  				"dnsupdate-queries":              1,
   150  				"dnsupdate-refused":              1,
   151  				"fd-usage":                       23,
   152  				"incoming-notifications":         1,
   153  				"key-cache-size":                 1,
   154  				"latency":                        1,
   155  				"meta-cache-size":                1,
   156  				"open-tcp-connections":           1,
   157  				"overload-drops":                 1,
   158  				"packetcache-hit":                1,
   159  				"packetcache-miss":               1,
   160  				"packetcache-size":               1,
   161  				"qsize-q":                        1,
   162  				"query-cache-hit":                1,
   163  				"query-cache-miss":               1,
   164  				"query-cache-size":               1,
   165  				"rd-queries":                     1,
   166  				"real-memory-usage":              164507648,
   167  				"recursing-answers":              1,
   168  				"recursing-questions":            1,
   169  				"recursion-unanswered":           1,
   170  				"ring-logmessages-capacity":      10000,
   171  				"ring-logmessages-size":          10,
   172  				"ring-noerror-queries-capacity":  10000,
   173  				"ring-noerror-queries-size":      1,
   174  				"ring-nxdomain-queries-capacity": 10000,
   175  				"ring-nxdomain-queries-size":     1,
   176  				"ring-queries-capacity":          10000,
   177  				"ring-queries-size":              1,
   178  				"ring-remotes-capacity":          10000,
   179  				"ring-remotes-corrupt-capacity":  10000,
   180  				"ring-remotes-corrupt-size":      1,
   181  				"ring-remotes-size":              1,
   182  				"ring-remotes-unauth-capacity":   10000,
   183  				"ring-remotes-unauth-size":       1,
   184  				"ring-servfail-queries-capacity": 10000,
   185  				"ring-servfail-queries-size":     1,
   186  				"ring-unauth-queries-capacity":   10000,
   187  				"ring-unauth-queries-size":       1,
   188  				"security-status":                1,
   189  				"servfail-packets":               1,
   190  				"signature-cache-size":           1,
   191  				"signatures":                     1,
   192  				"sys-msec":                       128,
   193  				"tcp-answers":                    1,
   194  				"tcp-answers-bytes":              1,
   195  				"tcp-queries":                    1,
   196  				"tcp4-answers":                   1,
   197  				"tcp4-answers-bytes":             1,
   198  				"tcp4-queries":                   1,
   199  				"tcp6-answers":                   1,
   200  				"tcp6-answers-bytes":             1,
   201  				"tcp6-queries":                   1,
   202  				"timedout-packets":               1,
   203  				"udp-answers":                    1,
   204  				"udp-answers-bytes":              1,
   205  				"udp-do-queries":                 1,
   206  				"udp-in-errors":                  1,
   207  				"udp-noport-errors":              1,
   208  				"udp-queries":                    1,
   209  				"udp-recvbuf-errors":             1,
   210  				"udp-sndbuf-errors":              1,
   211  				"udp4-answers":                   1,
   212  				"udp4-answers-bytes":             1,
   213  				"udp4-queries":                   1,
   214  				"udp6-answers":                   1,
   215  				"udp6-answers-bytes":             1,
   216  				"udp6-queries":                   1,
   217  				"uptime":                         207,
   218  				"user-msec":                      56,
   219  			},
   220  		},
   221  		"fails on response from PowerDNS Recursor": {
   222  			prepare: preparePowerDNSAuthoritativeNSRecursorData,
   223  		},
   224  		"fails on 404 response": {
   225  			prepare: preparePowerDNSAuthoritativeNS404,
   226  		},
   227  		"fails on connection refused": {
   228  			prepare: preparePowerDNSAuthoritativeNSConnectionRefused,
   229  		},
   230  		"fails on response with invalid data": {
   231  			prepare: preparePowerDNSAuthoritativeNSInvalidData,
   232  		},
   233  	}
   234  
   235  	for name, test := range tests {
   236  		t.Run(name, func(t *testing.T) {
   237  			ns, cleanup := test.prepare()
   238  			defer cleanup()
   239  			require.True(t, ns.Init())
   240  
   241  			collected := ns.Collect()
   242  
   243  			assert.Equal(t, test.wantCollected, collected)
   244  			if len(test.wantCollected) > 0 {
   245  				ensureCollectedHasAllChartsDimsVarsIDs(t, ns, collected)
   246  			}
   247  		})
   248  	}
   249  }
   250  
   251  func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, ns *AuthoritativeNS, collected map[string]int64) {
   252  	for _, chart := range *ns.Charts() {
   253  		if chart.Obsolete {
   254  			continue
   255  		}
   256  		for _, dim := range chart.Dims {
   257  			_, ok := collected[dim.ID]
   258  			assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", dim.ID, chart.ID)
   259  		}
   260  		for _, v := range chart.Vars {
   261  			_, ok := collected[v.ID]
   262  			assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", v.ID, chart.ID)
   263  		}
   264  	}
   265  }
   266  
   267  func preparePowerDNSAuthoritativeNSV430() (*AuthoritativeNS, func()) {
   268  	srv := preparePowerDNSAuthoritativeNSEndpoint()
   269  	ns := New()
   270  	ns.URL = srv.URL
   271  
   272  	return ns, srv.Close
   273  }
   274  
   275  func preparePowerDNSAuthoritativeNSRecursorData() (*AuthoritativeNS, func()) {
   276  	srv := preparePowerDNSRecursorEndpoint()
   277  	ns := New()
   278  	ns.URL = srv.URL
   279  
   280  	return ns, srv.Close
   281  }
   282  
   283  func preparePowerDNSAuthoritativeNSInvalidData() (*AuthoritativeNS, func()) {
   284  	srv := httptest.NewServer(http.HandlerFunc(
   285  		func(w http.ResponseWriter, r *http.Request) {
   286  			_, _ = w.Write([]byte("hello and\n goodbye"))
   287  		}))
   288  	ns := New()
   289  	ns.URL = srv.URL
   290  
   291  	return ns, srv.Close
   292  }
   293  
   294  func preparePowerDNSAuthoritativeNS404() (*AuthoritativeNS, func()) {
   295  	srv := httptest.NewServer(http.HandlerFunc(
   296  		func(w http.ResponseWriter, r *http.Request) {
   297  			w.WriteHeader(http.StatusNotFound)
   298  		}))
   299  	ns := New()
   300  	ns.URL = srv.URL
   301  
   302  	return ns, srv.Close
   303  }
   304  
   305  func preparePowerDNSAuthoritativeNSConnectionRefused() (*AuthoritativeNS, func()) {
   306  	ns := New()
   307  	ns.URL = "http://127.0.0.1:38001"
   308  
   309  	return ns, func() {}
   310  }
   311  
   312  func preparePowerDNSAuthoritativeNSEndpoint() *httptest.Server {
   313  	return httptest.NewServer(http.HandlerFunc(
   314  		func(w http.ResponseWriter, r *http.Request) {
   315  			switch r.URL.Path {
   316  			case urlPathLocalStatistics:
   317  				_, _ = w.Write(v430statistics)
   318  			default:
   319  				w.WriteHeader(http.StatusNotFound)
   320  			}
   321  		}))
   322  }
   323  
   324  func preparePowerDNSRecursorEndpoint() *httptest.Server {
   325  	return httptest.NewServer(http.HandlerFunc(
   326  		func(w http.ResponseWriter, r *http.Request) {
   327  			switch r.URL.Path {
   328  			case urlPathLocalStatistics:
   329  				_, _ = w.Write(recursorStatistics)
   330  			default:
   331  				w.WriteHeader(http.StatusNotFound)
   332  			}
   333  		}))
   334  }