github.com/netdata/go.d.plugin@v0.58.1/modules/supervisord/supervisord_test.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package supervisord
     4  
     5  import (
     6  	"errors"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestNew(t *testing.T) {
    14  	assert.IsType(t, (*Supervisord)(nil), New())
    15  }
    16  
    17  func TestSupervisord_Init(t *testing.T) {
    18  	tests := map[string]struct {
    19  		config   Config
    20  		wantFail bool
    21  	}{
    22  		"success on default config": {
    23  			config: New().Config,
    24  		},
    25  		"fails on unset 'url'": {
    26  			wantFail: true,
    27  			config:   Config{URL: ""},
    28  		},
    29  		"fails on unexpected 'url' scheme": {
    30  			wantFail: true,
    31  			config:   Config{URL: "tcp://127.0.0.1:9001/RPC2"},
    32  		},
    33  	}
    34  
    35  	for name, test := range tests {
    36  		t.Run(name, func(t *testing.T) {
    37  			supvr := New()
    38  			supvr.Config = test.config
    39  
    40  			if test.wantFail {
    41  				assert.False(t, supvr.Init())
    42  			} else {
    43  				assert.True(t, supvr.Init())
    44  			}
    45  		})
    46  	}
    47  }
    48  
    49  func TestSupervisord_Check(t *testing.T) {
    50  	tests := map[string]struct {
    51  		prepare  func(t *testing.T) *Supervisord
    52  		wantFail bool
    53  	}{
    54  		"success on valid response": {
    55  			prepare: prepareSupervisordSuccessOnGetAllProcessInfo,
    56  		},
    57  		"success on zero processes response": {
    58  			prepare: prepareSupervisordZeroProcessesOnGetAllProcessInfo,
    59  		},
    60  		"fails on error": {
    61  			wantFail: true,
    62  			prepare:  prepareSupervisordErrorOnGetAllProcessInfo,
    63  		},
    64  	}
    65  
    66  	for name, test := range tests {
    67  		t.Run(name, func(t *testing.T) {
    68  			supvr := test.prepare(t)
    69  			defer supvr.Cleanup()
    70  
    71  			if test.wantFail {
    72  				assert.False(t, supvr.Check())
    73  			} else {
    74  				assert.True(t, supvr.Check())
    75  			}
    76  		})
    77  	}
    78  }
    79  
    80  func TestSupervisord_Charts(t *testing.T) {
    81  	supvr := New()
    82  	require.True(t, supvr.Init())
    83  
    84  	assert.NotNil(t, supvr.Charts())
    85  }
    86  
    87  func TestSupervisord_Cleanup(t *testing.T) {
    88  	supvr := New()
    89  	assert.NotPanics(t, supvr.Cleanup)
    90  
    91  	require.True(t, supvr.Init())
    92  	m := &mockSupervisorClient{}
    93  	supvr.client = m
    94  
    95  	supvr.Cleanup()
    96  
    97  	assert.True(t, m.calledCloseIdleConnections)
    98  }
    99  
   100  func TestSupervisord_Collect(t *testing.T) {
   101  	tests := map[string]struct {
   102  		prepare       func(t *testing.T) *Supervisord
   103  		wantCollected map[string]int64
   104  	}{
   105  		"success on valid response": {
   106  			prepare: prepareSupervisordSuccessOnGetAllProcessInfo,
   107  			wantCollected: map[string]int64{
   108  				"group_proc1_non_running_processes":  1,
   109  				"group_proc1_process_00_downtime":    16276,
   110  				"group_proc1_process_00_exit_status": 0,
   111  				"group_proc1_process_00_state_code":  200,
   112  				"group_proc1_process_00_uptime":      0,
   113  				"group_proc1_running_processes":      0,
   114  				"group_proc2_non_running_processes":  0,
   115  				"group_proc2_process_00_downtime":    0,
   116  				"group_proc2_process_00_exit_status": 0,
   117  				"group_proc2_process_00_state_code":  20,
   118  				"group_proc2_process_00_uptime":      2,
   119  				"group_proc2_process_01_downtime":    0,
   120  				"group_proc2_process_01_exit_status": 0,
   121  				"group_proc2_process_01_state_code":  20,
   122  				"group_proc2_process_01_uptime":      2,
   123  				"group_proc2_process_02_downtime":    0,
   124  				"group_proc2_process_02_exit_status": 0,
   125  				"group_proc2_process_02_state_code":  20,
   126  				"group_proc2_process_02_uptime":      8,
   127  				"group_proc2_running_processes":      3,
   128  				"group_proc3_non_running_processes":  0,
   129  				"group_proc3_process_00_downtime":    0,
   130  				"group_proc3_process_00_exit_status": 0,
   131  				"group_proc3_process_00_state_code":  20,
   132  				"group_proc3_process_00_uptime":      16291,
   133  				"group_proc3_running_processes":      1,
   134  				"non_running_processes":              1,
   135  				"running_processes":                  4,
   136  			},
   137  		},
   138  		"success on response with zero processes": {
   139  			prepare: prepareSupervisordZeroProcessesOnGetAllProcessInfo,
   140  			wantCollected: map[string]int64{
   141  				"non_running_processes": 0,
   142  				"running_processes":     0,
   143  			},
   144  		},
   145  		"fails on error on getAllProcessesInfo": {
   146  			prepare: prepareSupervisordErrorOnGetAllProcessInfo,
   147  		},
   148  	}
   149  
   150  	for name, test := range tests {
   151  		t.Run(name, func(t *testing.T) {
   152  			supvr := test.prepare(t)
   153  			defer supvr.Cleanup()
   154  
   155  			ms := supvr.Collect()
   156  			assert.Equal(t, test.wantCollected, ms)
   157  			if len(test.wantCollected) > 0 {
   158  				ensureCollectedHasAllChartsDimsVarsIDs(t, supvr, ms)
   159  				ensureCollectedProcessesAddedToCharts(t, supvr)
   160  			}
   161  		})
   162  	}
   163  }
   164  
   165  func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, supvr *Supervisord, ms map[string]int64) {
   166  	for _, chart := range *supvr.Charts() {
   167  		if chart.Obsolete {
   168  			continue
   169  		}
   170  		for _, dim := range chart.Dims {
   171  			_, ok := ms[dim.ID]
   172  			assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", dim.ID, chart.ID)
   173  		}
   174  		for _, v := range chart.Vars {
   175  			_, ok := ms[v.ID]
   176  			assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", v.ID, chart.ID)
   177  		}
   178  	}
   179  }
   180  
   181  func ensureCollectedProcessesAddedToCharts(t *testing.T, supvr *Supervisord) {
   182  	for group := range supvr.cache {
   183  		for _, c := range *newProcGroupCharts(group) {
   184  			assert.NotNilf(t, supvr.Charts().Get(c.ID), "'%s' chart is not in charts", c.ID)
   185  		}
   186  	}
   187  }
   188  
   189  func prepareSupervisordSuccessOnGetAllProcessInfo(t *testing.T) *Supervisord {
   190  	supvr := New()
   191  	require.True(t, supvr.Init())
   192  	supvr.client = &mockSupervisorClient{}
   193  	return supvr
   194  }
   195  
   196  func prepareSupervisordZeroProcessesOnGetAllProcessInfo(t *testing.T) *Supervisord {
   197  	supvr := New()
   198  	require.True(t, supvr.Init())
   199  	supvr.client = &mockSupervisorClient{returnZeroProcesses: true}
   200  	return supvr
   201  }
   202  
   203  func prepareSupervisordErrorOnGetAllProcessInfo(t *testing.T) *Supervisord {
   204  	supvr := New()
   205  	require.True(t, supvr.Init())
   206  	supvr.client = &mockSupervisorClient{errOnGetAllProcessInfo: true}
   207  	return supvr
   208  }
   209  
   210  type mockSupervisorClient struct {
   211  	errOnGetAllProcessInfo     bool
   212  	returnZeroProcesses        bool
   213  	calledCloseIdleConnections bool
   214  }
   215  
   216  func (m mockSupervisorClient) getAllProcessInfo() ([]processStatus, error) {
   217  	if m.errOnGetAllProcessInfo {
   218  		return nil, errors.New("mock errOnGetAllProcessInfo")
   219  	}
   220  	if m.returnZeroProcesses {
   221  		return nil, nil
   222  	}
   223  	info := []processStatus{
   224  		{
   225  			name: "00", group: "proc1",
   226  			start: 1613374760, stop: 1613374762, now: 1613391038,
   227  			state: 200, stateName: "FATAL",
   228  			exitStatus: 0,
   229  		},
   230  		{
   231  			name: "00", group: "proc2",
   232  			start: 1613391036, stop: 1613391036, now: 1613391038,
   233  			state: 20, stateName: "RUNNING",
   234  			exitStatus: 0,
   235  		},
   236  		{
   237  			name: "01", group: "proc2",
   238  			start: 1613391036, stop: 1613391036, now: 1613391038,
   239  			state: 20, stateName: "RUNNING",
   240  			exitStatus: 0,
   241  		},
   242  		{
   243  			name: "02", group: "proc2",
   244  			start: 1613391030, stop: 1613391029, now: 1613391038,
   245  			state: 20, stateName: "RUNNING",
   246  			exitStatus: 0,
   247  		},
   248  		{
   249  			name: "00", group: "proc3",
   250  			start: 1613374747, stop: 0, now: 1613391038,
   251  			state: 20, stateName: "RUNNING",
   252  			exitStatus: 0,
   253  		},
   254  	}
   255  	return info, nil
   256  }
   257  
   258  func (m *mockSupervisorClient) closeIdleConnections() {
   259  	m.calledCloseIdleConnections = true
   260  }