summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/pihole/pihole_test.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/pihole/pihole_test.go278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/pihole/pihole_test.go b/src/go/collectors/go.d.plugin/modules/pihole/pihole_test.go
new file mode 100644
index 000000000..6af8267f1
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/pihole/pihole_test.go
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package pihole
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "testing"
+
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/web"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+const (
+ pathSetupVarsOK = "testdata/setupVars.conf"
+ pathSetupVarsWrong = "testdata/wrong.conf"
+)
+
+var (
+ dataConfigJSON, _ = os.ReadFile("testdata/config.json")
+ dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
+
+ dataEmptyResp = []byte("[]")
+ dataSummaryRawResp, _ = os.ReadFile("testdata/summaryRaw.json")
+ dataGetQueryTypesResp, _ = os.ReadFile("testdata/getQueryTypes.json")
+ dataGetForwardDestinationsResp, _ = os.ReadFile("testdata/getForwardDestinations.json")
+)
+
+func Test_testDataIsValid(t *testing.T) {
+ for name, data := range map[string][]byte{
+ "dataConfigJSON": dataConfigJSON,
+ "dataConfigYAML": dataConfigYAML,
+ "dataEmptyResp": dataEmptyResp,
+ "dataSummaryRawResp": dataSummaryRawResp,
+ "dataGetQueryTypesResp": dataGetQueryTypesResp,
+ "dataGetForwardDestinationsResp": dataGetForwardDestinationsResp,
+ } {
+ require.NotNil(t, data, name)
+ }
+}
+
+func TestPihole_ConfigurationSerialize(t *testing.T) {
+ module.TestConfigurationSerialize(t, &Pihole{}, dataConfigJSON, dataConfigYAML)
+}
+
+func TestPihole_Init(t *testing.T) {
+ tests := map[string]struct {
+ wantFail bool
+ config Config
+ }{
+ "success with default": {
+ wantFail: false,
+ config: New().Config,
+ },
+ "fail when URL not set": {
+ wantFail: true,
+ config: Config{
+ HTTP: web.HTTP{
+ Request: web.Request{URL: ""},
+ },
+ },
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ p := New()
+ p.Config = test.config
+
+ if test.wantFail {
+ assert.Error(t, p.Init())
+ } else {
+ assert.NoError(t, p.Init())
+ }
+ })
+ }
+}
+
+func TestPihole_Check(t *testing.T) {
+ tests := map[string]struct {
+ wantFail bool
+ prepare func(t *testing.T) (p *Pihole, cleanup func())
+ }{
+ "success with web password": {
+ wantFail: false,
+ prepare: caseSuccessWithWebPassword,
+ },
+ "fail without web password": {
+ wantFail: true,
+ prepare: caseFailNoWebPassword,
+ },
+ "fail on unsupported version": {
+ wantFail: true,
+ prepare: caseFailUnsupportedVersion,
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ p, cleanup := test.prepare(t)
+ defer cleanup()
+
+ if test.wantFail {
+ assert.Error(t, p.Check())
+ } else {
+ assert.NoError(t, p.Check())
+ }
+ })
+ }
+}
+
+func TestPihole_Charts(t *testing.T) {
+ assert.NotNil(t, New().Charts())
+}
+
+func TestPihole_Collect(t *testing.T) {
+ tests := map[string]struct {
+ prepare func(t *testing.T) (p *Pihole, cleanup func())
+ wantMetrics map[string]int64
+ wantNumCharts int
+ }{
+ "success with web password": {
+ prepare: caseSuccessWithWebPassword,
+ wantNumCharts: len(baseCharts) + 2,
+ wantMetrics: map[string]int64{
+ "A": 1229,
+ "AAAA": 1229,
+ "ANY": 100,
+ "PTR": 7143,
+ "SOA": 100,
+ "SRV": 100,
+ "TXT": 100,
+ "ads_blocked_today": 1,
+ "ads_blocked_today_perc": 33333,
+ "ads_percentage_today": 100,
+ "blocking_status_disabled": 0,
+ "blocking_status_enabled": 1,
+ "blocklist_last_update": 106273651,
+ "destination_blocked": 220,
+ "destination_cached": 8840,
+ "destination_other": 940,
+ "dns_queries_today": 1,
+ "domains_being_blocked": 1,
+ "queries_cached": 1,
+ "queries_cached_perc": 33333,
+ "queries_forwarded": 1,
+ "queries_forwarded_perc": 33333,
+ "unique_clients": 1,
+ },
+ },
+ "fail without web password": {
+ prepare: caseFailNoWebPassword,
+ wantMetrics: nil,
+ },
+ "fail on unsupported version": {
+ prepare: caseFailUnsupportedVersion,
+ wantMetrics: nil,
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ p, cleanup := test.prepare(t)
+ defer cleanup()
+
+ mx := p.Collect()
+
+ copyBlockListLastUpdate(mx, test.wantMetrics)
+ require.Equal(t, test.wantMetrics, mx)
+ if len(test.wantMetrics) > 0 {
+ assert.Len(t, *p.Charts(), test.wantNumCharts)
+ }
+ })
+ }
+}
+
+func caseSuccessWithWebPassword(t *testing.T) (*Pihole, func()) {
+ p, srv := New(), mockPiholeServer{}.newPiholeHTTPServer()
+
+ p.SetupVarsPath = pathSetupVarsOK
+ p.URL = srv.URL
+
+ require.NoError(t, p.Init())
+
+ return p, srv.Close
+}
+
+func caseFailNoWebPassword(t *testing.T) (*Pihole, func()) {
+ p, srv := New(), mockPiholeServer{}.newPiholeHTTPServer()
+
+ p.SetupVarsPath = pathSetupVarsWrong
+ p.URL = srv.URL
+
+ require.NoError(t, p.Init())
+
+ return p, srv.Close
+}
+
+func caseFailUnsupportedVersion(t *testing.T) (*Pihole, func()) {
+ p, srv := New(), mockPiholeServer{unsupportedVersion: true}.newPiholeHTTPServer()
+
+ p.SetupVarsPath = pathSetupVarsOK
+ p.URL = srv.URL
+
+ require.NoError(t, p.Init())
+
+ return p, srv.Close
+}
+
+type mockPiholeServer struct {
+ unsupportedVersion bool
+ errOnAPIVersion bool
+ errOnSummary bool
+ errOnQueryTypes bool
+ errOnGetForwardDst bool
+}
+
+func (m mockPiholeServer) newPiholeHTTPServer() *httptest.Server {
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != urlPathAPI || len(r.URL.Query()) == 0 {
+ w.WriteHeader(http.StatusBadRequest)
+ }
+
+ if r.URL.Query().Get(urlQueryKeyAuth) == "" {
+ _, _ = w.Write(dataEmptyResp)
+ return
+ }
+
+ if r.URL.Query().Has(urlQueryKeyAPIVersion) {
+ if m.errOnAPIVersion {
+ w.WriteHeader(http.StatusNotFound)
+ } else if m.unsupportedVersion {
+ _, _ = w.Write([]byte(fmt.Sprintf(`{"version": %d}`, wantAPIVersion+1)))
+ } else {
+ _, _ = w.Write([]byte(fmt.Sprintf(`{"version": %d}`, wantAPIVersion)))
+ }
+ return
+ }
+
+ if r.URL.Query().Has(urlQueryKeySummaryRaw) {
+ if m.errOnSummary {
+ w.WriteHeader(http.StatusNotFound)
+ } else {
+ _, _ = w.Write(dataSummaryRawResp)
+ }
+ return
+ }
+
+ data := dataEmptyResp
+ isErr := false
+ switch {
+ case r.URL.Query().Has(urlQueryKeyGetQueryTypes):
+ data, isErr = dataGetQueryTypesResp, m.errOnQueryTypes
+ case r.URL.Query().Has(urlQueryKeyGetForwardDestinations):
+ data, isErr = dataGetForwardDestinationsResp, m.errOnGetForwardDst
+ }
+
+ if isErr {
+ w.WriteHeader(http.StatusNotFound)
+ } else {
+ _, _ = w.Write(data)
+ }
+ }))
+}
+
+func copyBlockListLastUpdate(dst, src map[string]int64) {
+ k := "blocklist_last_update"
+ if v, ok := src[k]; ok {
+ if _, ok := dst[k]; ok {
+ dst[k] = v
+ }
+ }
+}