github.com/netdata/go.d.plugin@v0.58.1/modules/nginxvts/nginxvts_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package nginxvts
     4  
     5  import (
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"os"
     9  	"testing"
    10  
    11  	"github.com/netdata/go.d.plugin/agent/module"
    12  	"github.com/netdata/go.d.plugin/pkg/tlscfg"
    13  	"github.com/netdata/go.d.plugin/pkg/web"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  var (
    20  	v0118Response, _ = os.ReadFile("testdata/vts-v0.1.18.json")
    21  )
    22  
    23  func Test_testDataIsCorrectlyReadAndValid(t *testing.T) {
    24  	for name, data := range map[string][]byte{
    25  		"v0118Response": v0118Response,
    26  	} {
    27  		require.NotNilf(t, data, name)
    28  	}
    29  }
    30  
    31  func TestNew(t *testing.T) {
    32  	assert.Implements(t, (*module.Module)(nil), New())
    33  }
    34  
    35  func TestNginxVTS_Init(t *testing.T) {
    36  	tests := map[string]struct {
    37  		config          Config
    38  		wantNumOfCharts int
    39  		wantFail        bool
    40  	}{
    41  		"default": {
    42  			wantNumOfCharts: numOfCharts(
    43  				mainCharts,
    44  				sharedZonesCharts,
    45  				serverZonesCharts,
    46  			),
    47  			config: New().Config,
    48  		},
    49  		"URL not set": {
    50  			wantFail: true,
    51  			config: Config{
    52  				HTTP: web.HTTP{
    53  					Request: web.Request{URL: ""},
    54  				}},
    55  		},
    56  		"invalid TLSCA": {
    57  			wantFail: true,
    58  			config: Config{
    59  				HTTP: web.HTTP{
    60  					Client: web.Client{
    61  						TLSConfig: tlscfg.TLSConfig{TLSCA: "testdata/tls"},
    62  					},
    63  				}},
    64  		},
    65  	}
    66  
    67  	for name, test := range tests {
    68  		t.Run(name, func(t *testing.T) {
    69  			es := New()
    70  			es.Config = test.config
    71  
    72  			if test.wantFail {
    73  				assert.False(t, es.Init())
    74  			} else {
    75  				assert.True(t, es.Init())
    76  				assert.Equal(t, test.wantNumOfCharts, len(*es.Charts()))
    77  			}
    78  		})
    79  	}
    80  }
    81  
    82  func TestNginxVTS_Check(t *testing.T) {
    83  	tests := map[string]struct {
    84  		prepare  func(*testing.T) (vts *NginxVTS, cleanup func())
    85  		wantFail bool
    86  	}{
    87  		"valid data":         {prepare: prepareNginxVTSValidData},
    88  		"invalid data":       {prepare: prepareNginxVTSInvalidData, wantFail: true},
    89  		"404":                {prepare: prepareNginxVTS404, wantFail: true},
    90  		"connection refused": {prepare: prepareNginxVTSConnectionRefused, wantFail: true},
    91  	}
    92  
    93  	for name, test := range tests {
    94  		t.Run(name, func(t *testing.T) {
    95  			vts, cleanup := test.prepare(t)
    96  			defer cleanup()
    97  
    98  			if test.wantFail {
    99  				assert.False(t, vts.Check())
   100  			} else {
   101  				assert.True(t, vts.Check())
   102  			}
   103  		})
   104  	}
   105  }
   106  
   107  func TestNginxVTS_Charts(t *testing.T) {
   108  	assert.Nil(t, New().Charts())
   109  }
   110  
   111  func TestNginxVTS_Cleanup(t *testing.T) {
   112  	assert.NotPanics(t, New().Cleanup)
   113  }
   114  
   115  func TestNginxVTS_Collect(t *testing.T) {
   116  	tests := map[string]struct {
   117  		// prepare       func() *NginxVTS
   118  		prepare       func(t *testing.T) (vts *NginxVTS, cleanup func())
   119  		wantCollected map[string]int64
   120  		checkCharts   bool
   121  	}{
   122  		"right metrics": {
   123  			prepare: prepareNginxVTSValidData,
   124  			wantCollected: map[string]int64{
   125  				// Nginx running time
   126  				"uptime": 319,
   127  				// Nginx connections
   128  				"connections_active":   2,
   129  				"connections_reading":  0,
   130  				"connections_writing":  1,
   131  				"connections_waiting":  1,
   132  				"connections_accepted": 12,
   133  				"connections_handled":  12,
   134  				"connections_requests": 17,
   135  				// Nginx shared memory
   136  				"sharedzones_maxsize":  1048575,
   137  				"sharedzones_usedsize": 45799,
   138  				"sharedzones_usednode": 13,
   139  				// Nginx traffic
   140  				"total_requestcounter": 2,
   141  				"total_inbytes":        156,
   142  				"total_outbytes":       692,
   143  				// Nginx response code
   144  				"total_responses_1xx": 1,
   145  				"total_responses_2xx": 2,
   146  				"total_responses_3xx": 3,
   147  				"total_responses_4xx": 4,
   148  				"total_responses_5xx": 5,
   149  				// Nginx cache
   150  				"total_cache_miss":        2,
   151  				"total_cache_bypass":      4,
   152  				"total_cache_expired":     6,
   153  				"total_cache_stale":       8,
   154  				"total_cache_updating":    10,
   155  				"total_cache_revalidated": 12,
   156  				"total_cache_hit":         14,
   157  				"total_cache_scarce":      16,
   158  			},
   159  			checkCharts: true,
   160  		},
   161  	}
   162  
   163  	for name, test := range tests {
   164  		t.Run(name, func(t *testing.T) {
   165  			vts, cleanup := test.prepare(t)
   166  			defer cleanup()
   167  
   168  			collected := vts.Collect()
   169  
   170  			assert.Equal(t, test.wantCollected, collected)
   171  			if test.checkCharts {
   172  				ensureCollectedHasAllChartsDimsVarsIDs(t, vts, collected)
   173  			}
   174  		})
   175  	}
   176  }
   177  
   178  func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, vts *NginxVTS, collected map[string]int64) {
   179  	for _, chart := range *vts.Charts() {
   180  		if chart.Obsolete {
   181  			continue
   182  		}
   183  		for _, dim := range chart.Dims {
   184  			_, ok := collected[dim.ID]
   185  			assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID)
   186  		}
   187  		for _, v := range chart.Vars {
   188  			_, ok := collected[v.ID]
   189  			assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID)
   190  		}
   191  	}
   192  }
   193  
   194  func prepareNginxVTS(t *testing.T, createNginxVTS func() *NginxVTS) (vts *NginxVTS, cleanup func()) {
   195  	t.Helper()
   196  	vts = createNginxVTS()
   197  	srv := prepareNginxVTSEndpoint()
   198  	vts.URL = srv.URL
   199  
   200  	require.True(t, vts.Init())
   201  
   202  	return vts, srv.Close
   203  }
   204  
   205  func prepareNginxVTSValidData(t *testing.T) (vts *NginxVTS, cleanup func()) {
   206  	return prepareNginxVTS(t, New)
   207  }
   208  
   209  func prepareNginxVTSInvalidData(t *testing.T) (*NginxVTS, func()) {
   210  	t.Helper()
   211  	srv := httptest.NewServer(http.HandlerFunc(
   212  		func(w http.ResponseWriter, r *http.Request) {
   213  			_, _ = w.Write([]byte("hello and\n goodbye"))
   214  		}))
   215  	vts := New()
   216  	vts.URL = srv.URL
   217  	require.True(t, vts.Init())
   218  
   219  	return vts, srv.Close
   220  }
   221  
   222  func prepareNginxVTS404(t *testing.T) (*NginxVTS, func()) {
   223  	t.Helper()
   224  	srv := httptest.NewServer(http.HandlerFunc(
   225  		func(w http.ResponseWriter, r *http.Request) {
   226  			w.WriteHeader(http.StatusNotFound)
   227  		}))
   228  	vts := New()
   229  	vts.URL = srv.URL
   230  	require.True(t, vts.Init())
   231  
   232  	return vts, srv.Close
   233  }
   234  
   235  func prepareNginxVTSConnectionRefused(t *testing.T) (*NginxVTS, func()) {
   236  	t.Helper()
   237  	vts := New()
   238  	vts.URL = "http://127.0.0.1:18080"
   239  	require.True(t, vts.Init())
   240  
   241  	return vts, func() {}
   242  }
   243  
   244  func prepareNginxVTSEndpoint() *httptest.Server {
   245  	return httptest.NewServer(http.HandlerFunc(
   246  		func(w http.ResponseWriter, r *http.Request) {
   247  			switch r.URL.Path {
   248  			case "/":
   249  				_, _ = w.Write(v0118Response)
   250  			default:
   251  				w.WriteHeader(http.StatusNotFound)
   252  			}
   253  		}))
   254  }
   255  
   256  func numOfCharts(charts ...module.Charts) (num int) {
   257  	for _, v := range charts {
   258  		num += len(v)
   259  	}
   260  	return num
   261  }