github.com/netdata/go.d.plugin@v0.58.1/modules/energid/energid_test.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package energid 4 5 import ( 6 "encoding/json" 7 "io" 8 "net/http" 9 "net/http/httptest" 10 "os" 11 "testing" 12 13 "github.com/netdata/go.d.plugin/pkg/tlscfg" 14 "github.com/netdata/go.d.plugin/pkg/web" 15 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 var ( 21 v241GetBlockchainInfo, _ = os.ReadFile("testdata/v2.4.1/getblockchaininfo.json") 22 v241GetMemPoolInfo, _ = os.ReadFile("testdata/v2.4.1/getmempoolinfo.json") 23 v241GetNetworkInfo, _ = os.ReadFile("testdata/v2.4.1/getnetworkinfo.json") 24 v241GetTXOutSetInfo, _ = os.ReadFile("testdata/v2.4.1/gettxoutsetinfo.json") 25 v241GetMemoryInfo, _ = os.ReadFile("testdata/v2.4.1/getmemoryinfo.json") 26 ) 27 28 func Test_Testdata(t *testing.T) { 29 for name, data := range map[string][]byte{ 30 "v241GetBlockchainInfo": v241GetBlockchainInfo, 31 "v241GetMemPoolInfo": v241GetMemPoolInfo, 32 "v241GetNetworkInfo": v241GetNetworkInfo, 33 "v241GetTXOutSetInfo": v241GetTXOutSetInfo, 34 "v241GetMemoryInfo": v241GetMemoryInfo, 35 } { 36 require.NotNilf(t, data, name) 37 } 38 } 39 40 func TestNew(t *testing.T) { 41 assert.IsType(t, (*Energid)(nil), New()) 42 } 43 44 func Test_Init(t *testing.T) { 45 tests := map[string]struct { 46 config Config 47 wantFail bool 48 }{ 49 "success on default config": { 50 config: New().Config, 51 }, 52 "fails on unset URL": { 53 wantFail: true, 54 config: Config{ 55 HTTP: web.HTTP{ 56 Request: web.Request{URL: ""}, 57 }, 58 }, 59 }, 60 "fails on invalid TLSCA": { 61 wantFail: true, 62 config: Config{ 63 HTTP: web.HTTP{ 64 Request: web.Request{ 65 URL: "http://127.0.0.1:38001", 66 }, 67 Client: web.Client{ 68 TLSConfig: tlscfg.TLSConfig{TLSCA: "testdata/tls"}, 69 }, 70 }, 71 }, 72 }, 73 } 74 75 for name, test := range tests { 76 t.Run(name, func(t *testing.T) { 77 energid := New() 78 energid.Config = test.config 79 80 if test.wantFail { 81 assert.False(t, energid.Init()) 82 } else { 83 assert.True(t, energid.Init()) 84 } 85 }) 86 } 87 } 88 89 func Test_Charts(t *testing.T) { 90 energid := New() 91 require.True(t, energid.Init()) 92 assert.NotNil(t, energid.Charts()) 93 } 94 95 func Test_Cleanup(t *testing.T) { 96 assert.NotPanics(t, New().Cleanup) 97 } 98 99 func Test_Check(t *testing.T) { 100 tests := map[string]struct { 101 prepare func() (energid *Energid, cleanup func()) 102 wantFail bool 103 }{ 104 "success on valid v2.4.1 response": { 105 prepare: prepareEnergidV241, 106 }, 107 "fails on 404 response": { 108 wantFail: true, 109 prepare: prepareEnergid404, 110 }, 111 "fails on connection refused": { 112 wantFail: true, 113 prepare: prepareEnergidConnectionRefused, 114 }, 115 "fails on response with invalid data": { 116 wantFail: true, 117 prepare: prepareEnergidInvalidData, 118 }, 119 } 120 121 for name, test := range tests { 122 t.Run(name, func(t *testing.T) { 123 energid, cleanup := test.prepare() 124 defer cleanup() 125 126 require.True(t, energid.Init()) 127 128 if test.wantFail { 129 assert.False(t, energid.Check()) 130 } else { 131 assert.True(t, energid.Check()) 132 } 133 }) 134 } 135 } 136 137 func Test_Collect(t *testing.T) { 138 tests := map[string]struct { 139 prepare func() (energid *Energid, cleanup func()) 140 wantCollected map[string]int64 141 }{ 142 "success on valid v2.4.1 response": { 143 prepare: prepareEnergidV241, 144 wantCollected: map[string]int64{ 145 "blockchain_blocks": 1, 146 "blockchain_difficulty": 0, 147 "blockchain_headers": 1, 148 "mempool_current": 1, 149 "mempool_max": 300000000, 150 "mempool_txsize": 1, 151 "network_connections": 1, 152 "network_timeoffset": 1, 153 "secmem_free": 65248, 154 "secmem_locked": 65536, 155 "secmem_total": 65536, 156 "secmem_used": 288, 157 "utxo_output_transactions": 1, 158 "utxo_transactions": 1, 159 }, 160 }, 161 "fails on 404 response": { 162 prepare: prepareEnergid404, 163 }, 164 "fails on connection refused": { 165 prepare: prepareEnergidConnectionRefused, 166 }, 167 "fails on response with invalid data": { 168 prepare: prepareEnergidInvalidData, 169 }, 170 } 171 172 for name, test := range tests { 173 t.Run(name, func(t *testing.T) { 174 energid, cleanup := test.prepare() 175 defer cleanup() 176 require.True(t, energid.Init()) 177 178 collected := energid.Collect() 179 180 assert.Equal(t, test.wantCollected, collected) 181 if len(test.wantCollected) > 0 { 182 ensureCollectedHasAllChartsDimsVarsIDs(t, energid, collected) 183 } 184 }) 185 } 186 } 187 188 func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, energid *Energid, ms map[string]int64) { 189 for _, chart := range *energid.Charts() { 190 if chart.Obsolete { 191 continue 192 } 193 for _, dim := range chart.Dims { 194 _, ok := ms[dim.ID] 195 assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", dim.ID, chart.ID) 196 } 197 for _, v := range chart.Vars { 198 _, ok := ms[v.ID] 199 assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", v.ID, chart.ID) 200 } 201 } 202 } 203 204 func prepareEnergidV241() (*Energid, func()) { 205 srv := prepareEnergidEndPoint() 206 energid := New() 207 energid.URL = srv.URL 208 209 return energid, srv.Close 210 } 211 212 func prepareEnergidInvalidData() (*Energid, func()) { 213 srv := httptest.NewServer(http.HandlerFunc( 214 func(w http.ResponseWriter, r *http.Request) { 215 _, _ = w.Write([]byte("Hello world!")) 216 })) 217 energid := New() 218 energid.URL = srv.URL 219 220 return energid, srv.Close 221 } 222 223 func prepareEnergid404() (*Energid, func()) { 224 srv := httptest.NewServer(http.HandlerFunc( 225 func(w http.ResponseWriter, r *http.Request) { 226 w.WriteHeader(http.StatusNotFound) 227 })) 228 energid := New() 229 energid.URL = srv.URL 230 231 return energid, srv.Close 232 } 233 234 func prepareEnergidConnectionRefused() (*Energid, func()) { 235 energid := New() 236 energid.URL = "http://127.0.0.1:38001" 237 238 return energid, func() {} 239 } 240 241 func prepareEnergidEndPoint() *httptest.Server { 242 return httptest.NewServer(http.HandlerFunc( 243 func(w http.ResponseWriter, r *http.Request) { 244 if r.Method != http.MethodPost { 245 w.WriteHeader(http.StatusMethodNotAllowed) 246 return 247 } 248 249 body, _ := io.ReadAll(r.Body) 250 var requests rpcRequests 251 if err := json.Unmarshal(body, &requests); err != nil || len(requests) == 0 { 252 w.WriteHeader(http.StatusInternalServerError) 253 return 254 } 255 256 var responses rpcResponses 257 for _, req := range requests { 258 resp := rpcResponse{JSONRPC: jsonRPCVersion, ID: req.ID} 259 switch req.Method { 260 case methodGetBlockchainInfo: 261 resp.Result = prepareResult(v241GetBlockchainInfo) 262 case methodGetMemPoolInfo: 263 resp.Result = prepareResult(v241GetMemPoolInfo) 264 case methodGetNetworkInfo: 265 resp.Result = prepareResult(v241GetNetworkInfo) 266 case methodGetTXOutSetInfo: 267 resp.Result = prepareResult(v241GetTXOutSetInfo) 268 case methodGetMemoryInfo: 269 resp.Result = prepareResult(v241GetMemoryInfo) 270 default: 271 resp.Error = &rpcError{Code: -32601, Message: "Method not found"} 272 } 273 responses = append(responses, resp) 274 } 275 276 bs, _ := json.Marshal(responses) 277 _, _ = w.Write(bs) 278 })) 279 } 280 281 func prepareResult(resp []byte) json.RawMessage { 282 var r rpcResponse 283 _ = json.Unmarshal(resp, &r) 284 return r.Result 285 }