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 }