github.com/netdata/go.d.plugin@v0.58.1/modules/apache/apache_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package apache
     4  
     5  import (
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"os"
     9  	"testing"
    10  
    11  	"github.com/netdata/go.d.plugin/pkg/web"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  var (
    18  	dataSimpleStatusMPMEvent, _     = os.ReadFile("testdata/simple-status-mpm-event.txt")
    19  	dataExtendedStatusMPMEvent, _   = os.ReadFile("testdata/extended-status-mpm-event.txt")
    20  	dataExtendedStatusMPMPrefork, _ = os.ReadFile("testdata/extended-status-mpm-prefork.txt")
    21  	dataLighttpdStatus, _           = os.ReadFile("testdata/lighttpd-status.txt")
    22  )
    23  
    24  func Test_testDataIsValid(t *testing.T) {
    25  	for name, data := range map[string][]byte{
    26  		"dataSimpleStatusMPMEvent":     dataSimpleStatusMPMEvent,
    27  		"dataExtendedStatusMPMEvent":   dataExtendedStatusMPMEvent,
    28  		"dataExtendedStatusMPMPrefork": dataExtendedStatusMPMPrefork,
    29  		"dataLighttpdStatus":           dataLighttpdStatus,
    30  	} {
    31  		require.NotNilf(t, data, name)
    32  
    33  	}
    34  }
    35  
    36  func TestApache_Init(t *testing.T) {
    37  	tests := map[string]struct {
    38  		wantFail bool
    39  		config   Config
    40  	}{
    41  		"success with default": {
    42  			wantFail: false,
    43  			config:   New().Config,
    44  		},
    45  		"fail when URL not set": {
    46  			wantFail: true,
    47  			config: Config{
    48  				HTTP: web.HTTP{
    49  					Request: web.Request{URL: ""},
    50  				},
    51  			},
    52  		},
    53  		"fail when URL has no wantMetrics suffix": {
    54  			wantFail: true,
    55  			config: Config{
    56  				HTTP: web.HTTP{
    57  					Request: web.Request{URL: "http://127.0.0.1:38001"},
    58  				},
    59  			},
    60  		},
    61  	}
    62  
    63  	for name, test := range tests {
    64  		t.Run(name, func(t *testing.T) {
    65  			apache := New()
    66  			apache.Config = test.config
    67  
    68  			if test.wantFail {
    69  				assert.False(t, apache.Init())
    70  			} else {
    71  				assert.True(t, apache.Init())
    72  			}
    73  		})
    74  	}
    75  }
    76  
    77  func TestApache_Check(t *testing.T) {
    78  	tests := map[string]struct {
    79  		wantFail bool
    80  		prepare  func(t *testing.T) (apache *Apache, cleanup func())
    81  	}{
    82  		"success on simple status MPM Event": {
    83  			wantFail: false,
    84  			prepare:  caseMPMEventSimpleStatus,
    85  		},
    86  		"success on extended status MPM Event": {
    87  			wantFail: false,
    88  			prepare:  caseMPMEventExtendedStatus,
    89  		},
    90  		"success on extended status MPM Prefork": {
    91  			wantFail: false,
    92  			prepare:  caseMPMPreforkExtendedStatus,
    93  		},
    94  		"fail on Lighttpd response": {
    95  			wantFail: true,
    96  			prepare:  caseLighttpdResponse,
    97  		},
    98  		"fail on invalid data response": {
    99  			wantFail: true,
   100  			prepare:  caseInvalidDataResponse,
   101  		},
   102  		"fail on connection refused": {
   103  			wantFail: true,
   104  			prepare:  caseConnectionRefused,
   105  		},
   106  		"fail on 404 response": {
   107  			wantFail: true,
   108  			prepare:  case404,
   109  		},
   110  	}
   111  
   112  	for name, test := range tests {
   113  		t.Run(name, func(t *testing.T) {
   114  			apache, cleanup := test.prepare(t)
   115  			defer cleanup()
   116  
   117  			if test.wantFail {
   118  				assert.False(t, apache.Check())
   119  			} else {
   120  				assert.True(t, apache.Check())
   121  			}
   122  		})
   123  	}
   124  }
   125  
   126  func TestApache_Charts(t *testing.T) {
   127  	assert.NotNil(t, New().Charts())
   128  }
   129  
   130  func TestApache_Collect(t *testing.T) {
   131  	tests := map[string]struct {
   132  		prepare         func(t *testing.T) (apache *Apache, cleanup func())
   133  		wantNumOfCharts int
   134  		wantMetrics     map[string]int64
   135  	}{
   136  		"success on simple status MPM Event": {
   137  			prepare:         caseMPMEventSimpleStatus,
   138  			wantNumOfCharts: len(baseCharts),
   139  			wantMetrics: map[string]int64{
   140  				"busy_workers":            1,
   141  				"conns_async_closing":     0,
   142  				"conns_async_keep_alive":  0,
   143  				"conns_async_writing":     0,
   144  				"conns_total":             0,
   145  				"idle_workers":            74,
   146  				"scoreboard_closing":      0,
   147  				"scoreboard_dns_lookup":   0,
   148  				"scoreboard_finishing":    0,
   149  				"scoreboard_idle_cleanup": 0,
   150  				"scoreboard_keepalive":    0,
   151  				"scoreboard_logging":      0,
   152  				"scoreboard_open":         325,
   153  				"scoreboard_reading":      0,
   154  				"scoreboard_sending":      1,
   155  				"scoreboard_starting":     0,
   156  				"scoreboard_waiting":      74,
   157  			},
   158  		},
   159  		"success on extended status MPM Event": {
   160  			prepare:         caseMPMEventExtendedStatus,
   161  			wantNumOfCharts: len(baseCharts) + len(extendedCharts),
   162  			wantMetrics: map[string]int64{
   163  				"busy_workers":            1,
   164  				"bytes_per_req":           136533000,
   165  				"bytes_per_sec":           4800000,
   166  				"conns_async_closing":     0,
   167  				"conns_async_keep_alive":  0,
   168  				"conns_async_writing":     0,
   169  				"conns_total":             0,
   170  				"idle_workers":            99,
   171  				"req_per_sec":             3515,
   172  				"scoreboard_closing":      0,
   173  				"scoreboard_dns_lookup":   0,
   174  				"scoreboard_finishing":    0,
   175  				"scoreboard_idle_cleanup": 0,
   176  				"scoreboard_keepalive":    0,
   177  				"scoreboard_logging":      0,
   178  				"scoreboard_open":         300,
   179  				"scoreboard_reading":      0,
   180  				"scoreboard_sending":      1,
   181  				"scoreboard_starting":     0,
   182  				"scoreboard_waiting":      99,
   183  				"total_accesses":          9,
   184  				"total_kBytes":            12,
   185  				"uptime":                  256,
   186  			},
   187  		},
   188  		"success on extended status MPM Prefork": {
   189  			prepare:         caseMPMPreforkExtendedStatus,
   190  			wantNumOfCharts: len(baseCharts) + len(extendedCharts) - 2,
   191  			wantMetrics: map[string]int64{
   192  				"busy_workers":            70,
   193  				"bytes_per_req":           3617880000,
   194  				"bytes_per_sec":           614250000000,
   195  				"idle_workers":            1037,
   196  				"req_per_sec":             16978100,
   197  				"scoreboard_closing":      0,
   198  				"scoreboard_dns_lookup":   0,
   199  				"scoreboard_finishing":    0,
   200  				"scoreboard_idle_cleanup": 0,
   201  				"scoreboard_keepalive":    0,
   202  				"scoreboard_logging":      0,
   203  				"scoreboard_open":         3,
   204  				"scoreboard_reading":      0,
   205  				"scoreboard_sending":      0,
   206  				"scoreboard_starting":     0,
   207  				"scoreboard_waiting":      3,
   208  				"total_accesses":          120358784,
   209  				"total_kBytes":            4252382776,
   210  				"uptime":                  708904,
   211  			},
   212  		},
   213  		"fail on Lighttpd response": {
   214  			prepare:         caseLighttpdResponse,
   215  			wantNumOfCharts: 0,
   216  			wantMetrics:     nil,
   217  		},
   218  		"fail on invalid data response": {
   219  			prepare:         caseInvalidDataResponse,
   220  			wantNumOfCharts: 0,
   221  			wantMetrics:     nil,
   222  		},
   223  		"fail on connection refused": {
   224  			prepare:         caseConnectionRefused,
   225  			wantNumOfCharts: 0,
   226  			wantMetrics:     nil,
   227  		},
   228  		"fail on 404 response": {
   229  			prepare:         case404,
   230  			wantNumOfCharts: 0,
   231  			wantMetrics:     nil,
   232  		},
   233  	}
   234  
   235  	for name, test := range tests {
   236  		t.Run(name, func(t *testing.T) {
   237  			apache, cleanup := test.prepare(t)
   238  			defer cleanup()
   239  
   240  			_ = apache.Check()
   241  
   242  			collected := apache.Collect()
   243  
   244  			require.Equal(t, test.wantMetrics, collected)
   245  			assert.Equal(t, test.wantNumOfCharts, len(*apache.Charts()))
   246  		})
   247  	}
   248  }
   249  
   250  func caseMPMEventSimpleStatus(t *testing.T) (*Apache, func()) {
   251  	t.Helper()
   252  	srv := httptest.NewServer(http.HandlerFunc(
   253  		func(w http.ResponseWriter, r *http.Request) {
   254  			_, _ = w.Write(dataSimpleStatusMPMEvent)
   255  		}))
   256  	apache := New()
   257  	apache.URL = srv.URL + "/server-status?auto"
   258  	require.True(t, apache.Init())
   259  
   260  	return apache, srv.Close
   261  }
   262  
   263  func caseMPMEventExtendedStatus(t *testing.T) (*Apache, func()) {
   264  	t.Helper()
   265  	srv := httptest.NewServer(http.HandlerFunc(
   266  		func(w http.ResponseWriter, r *http.Request) {
   267  			_, _ = w.Write(dataExtendedStatusMPMEvent)
   268  		}))
   269  	apache := New()
   270  	apache.URL = srv.URL + "/server-status?auto"
   271  	require.True(t, apache.Init())
   272  
   273  	return apache, srv.Close
   274  }
   275  
   276  func caseMPMPreforkExtendedStatus(t *testing.T) (*Apache, func()) {
   277  	t.Helper()
   278  	srv := httptest.NewServer(http.HandlerFunc(
   279  		func(w http.ResponseWriter, r *http.Request) {
   280  			_, _ = w.Write(dataExtendedStatusMPMPrefork)
   281  		}))
   282  	apache := New()
   283  	apache.URL = srv.URL + "/server-status?auto"
   284  	require.True(t, apache.Init())
   285  
   286  	return apache, srv.Close
   287  }
   288  
   289  func caseLighttpdResponse(t *testing.T) (*Apache, func()) {
   290  	t.Helper()
   291  	srv := httptest.NewServer(http.HandlerFunc(
   292  		func(w http.ResponseWriter, r *http.Request) {
   293  			_, _ = w.Write(dataLighttpdStatus)
   294  		}))
   295  	apache := New()
   296  	apache.URL = srv.URL + "/server-status?auto"
   297  	require.True(t, apache.Init())
   298  
   299  	return apache, srv.Close
   300  }
   301  
   302  func caseInvalidDataResponse(t *testing.T) (*Apache, func()) {
   303  	t.Helper()
   304  	srv := httptest.NewServer(http.HandlerFunc(
   305  		func(w http.ResponseWriter, r *http.Request) {
   306  			_, _ = w.Write([]byte("hello and\n goodbye"))
   307  		}))
   308  	apache := New()
   309  	apache.URL = srv.URL + "/server-status?auto"
   310  	require.True(t, apache.Init())
   311  
   312  	return apache, srv.Close
   313  }
   314  
   315  func caseConnectionRefused(t *testing.T) (*Apache, func()) {
   316  	t.Helper()
   317  	apache := New()
   318  	apache.URL = "http://127.0.0.1:65001/server-status?auto"
   319  	require.True(t, apache.Init())
   320  
   321  	return apache, func() {}
   322  }
   323  
   324  func case404(t *testing.T) (*Apache, func()) {
   325  	t.Helper()
   326  	srv := httptest.NewServer(http.HandlerFunc(
   327  		func(w http.ResponseWriter, r *http.Request) {
   328  			w.WriteHeader(http.StatusNotFound)
   329  		}))
   330  	apache := New()
   331  	apache.URL = srv.URL + "/server-status?auto"
   332  	require.True(t, apache.Init())
   333  
   334  	return apache, srv.Close
   335  }