master
go 299 lines 12 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package cassandra
4
5 import (
6 "context"
7 "net/http"
8 "net/http/httptest"
9 "os"
10 "testing"
11
12 "github.com/netdata/netdata/go/plugins/pkg/web"
13 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
14
15 "github.com/stretchr/testify/assert"
16 "github.com/stretchr/testify/require"
17 )
18
19 var (
20 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
21 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
22
23 dataExpectedMetrics, _ = os.ReadFile("testdata/metrics.txt")
24 )
25
26 func Test_testDataIsValid(t *testing.T) {
27 for name, data := range map[string][]byte{
28 "dataConfigJSON": dataConfigJSON,
29 "dataConfigYAML": dataConfigYAML,
30 "dataExpectedMetrics": dataExpectedMetrics,
31 } {
32 assert.NotNil(t, data, name)
33 }
34 }
35
36 func TestCollector_ConfigurationSerialize(t *testing.T) {
37 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
38 }
39
40 func TestNew(t *testing.T) {
41 assert.IsType(t, (*Collector)(nil), New())
42 }
43
44 func TestCollector_Init(t *testing.T) {
45 tests := map[string]struct {
46 config Config
47 wantFail bool
48 }{
49 "success if 'url' is set": {
50 config: Config{
51 HTTPConfig: web.HTTPConfig{RequestConfig: web.RequestConfig{URL: "http://127.0.0.1:7072"}}},
52 },
53 "success on default config": {
54 wantFail: false,
55 config: New().Config,
56 },
57 "fails if 'url' is unset": {
58 wantFail: true,
59 config: Config{HTTPConfig: web.HTTPConfig{RequestConfig: web.RequestConfig{URL: ""}}},
60 },
61 }
62
63 for name, test := range tests {
64 t.Run(name, func(t *testing.T) {
65 collr := New()
66 collr.Config = test.config
67
68 if test.wantFail {
69 assert.Error(t, collr.Init(context.Background()))
70 } else {
71 assert.NoError(t, collr.Init(context.Background()))
72 }
73 })
74 }
75 }
76
77 func TestCollector_Check(t *testing.T) {
78 tests := map[string]struct {
79 prepare func() (c *Collector, cleanup func())
80 wantFail bool
81 }{
82 "success on valid response": {
83 prepare: prepareCassandra,
84 },
85 "fails if endpoint returns invalid data": {
86 wantFail: true,
87 prepare: prepareCassandraInvalidData,
88 },
89 "fails on connection refused": {
90 wantFail: true,
91 prepare: prepareCassandraConnectionRefused,
92 },
93 "fails on 404 response": {
94 wantFail: true,
95 prepare: prepareCassandraResponse404,
96 },
97 }
98
99 for name, test := range tests {
100 t.Run(name, func(t *testing.T) {
101 collr, cleanup := test.prepare()
102 defer cleanup()
103
104 require.NoError(t, collr.Init(context.Background()))
105
106 if test.wantFail {
107 assert.Error(t, collr.Check(context.Background()))
108 } else {
109 assert.NoError(t, collr.Check(context.Background()))
110 }
111 })
112 }
113 }
114
115 func TestCollector_Charts(t *testing.T) {
116 assert.NotNil(t, New().Charts())
117 }
118
119 func TestCollector_Collect(t *testing.T) {
120 tests := map[string]struct {
121 prepare func() (c *Collector, cleanup func())
122 wantCollected map[string]int64
123 }{
124 "success on valid response": {
125 prepare: prepareCassandra,
126 wantCollected: map[string]int64{
127 "client_request_failures_reads": 0,
128 "client_request_failures_writes": 0,
129 "client_request_latency_reads": 333316,
130 "client_request_latency_writes": 331841,
131 "client_request_read_latency_p50": 61,
132 "client_request_read_latency_p75": 88,
133 "client_request_read_latency_p95": 126,
134 "client_request_read_latency_p98": 182,
135 "client_request_read_latency_p99": 219,
136 "client_request_read_latency_p999": 454,
137 "client_request_timeouts_reads": 0,
138 "client_request_timeouts_writes": 0,
139 "client_request_total_latency_reads": 23688998,
140 "client_request_total_latency_writes": 14253267,
141 "client_request_unavailables_reads": 0,
142 "client_request_unavailables_writes": 0,
143 "client_request_write_latency_p50": 35,
144 "client_request_write_latency_p75": 61,
145 "client_request_write_latency_p95": 105,
146 "client_request_write_latency_p98": 126,
147 "client_request_write_latency_p99": 152,
148 "client_request_write_latency_p999": 315,
149 "compaction_bytes_compacted": 2532,
150 "compaction_completed_tasks": 1078,
151 "compaction_pending_tasks": 0,
152 "dropped_messages": 0,
153 "jvm_gc_cms_count": 1,
154 "jvm_gc_cms_time": 59,
155 "jvm_gc_parnew_count": 218,
156 "jvm_gc_parnew_time": 1617,
157 "jvm_memory_heap_used": 1134866288,
158 "jvm_memory_nonheap_used": 96565696,
159 "key_cache_hit_ratio": 87273,
160 "key_cache_hits": 1336427,
161 "key_cache_misses": 194890,
162 "key_cache_size": 196559936,
163 "key_cache_utilization": 20828,
164 "row_cache_hit_ratio": 0,
165 "row_cache_hits": 0,
166 "row_cache_misses": 0,
167 "row_cache_size": 0,
168 "row_cache_utilization": 0,
169 "storage_exceptions": 0,
170 "storage_load": 858272986,
171 "thread_pool_CacheCleanupExecutor_active_tasks": 0,
172 "thread_pool_CacheCleanupExecutor_blocked_tasks": 0,
173 "thread_pool_CacheCleanupExecutor_pending_tasks": 0,
174 "thread_pool_CacheCleanupExecutor_total_blocked_tasks": 0,
175 "thread_pool_CompactionExecutor_active_tasks": 0,
176 "thread_pool_CompactionExecutor_blocked_tasks": 0,
177 "thread_pool_CompactionExecutor_pending_tasks": 0,
178 "thread_pool_CompactionExecutor_total_blocked_tasks": 0,
179 "thread_pool_GossipStage_active_tasks": 0,
180 "thread_pool_GossipStage_blocked_tasks": 0,
181 "thread_pool_GossipStage_pending_tasks": 0,
182 "thread_pool_GossipStage_total_blocked_tasks": 0,
183 "thread_pool_HintsDispatcher_active_tasks": 0,
184 "thread_pool_HintsDispatcher_blocked_tasks": 0,
185 "thread_pool_HintsDispatcher_pending_tasks": 0,
186 "thread_pool_HintsDispatcher_total_blocked_tasks": 0,
187 "thread_pool_MemtableFlushWriter_active_tasks": 0,
188 "thread_pool_MemtableFlushWriter_blocked_tasks": 0,
189 "thread_pool_MemtableFlushWriter_pending_tasks": 0,
190 "thread_pool_MemtableFlushWriter_total_blocked_tasks": 0,
191 "thread_pool_MemtablePostFlush_active_tasks": 0,
192 "thread_pool_MemtablePostFlush_blocked_tasks": 0,
193 "thread_pool_MemtablePostFlush_pending_tasks": 0,
194 "thread_pool_MemtablePostFlush_total_blocked_tasks": 0,
195 "thread_pool_MemtableReclaimMemory_active_tasks": 0,
196 "thread_pool_MemtableReclaimMemory_blocked_tasks": 0,
197 "thread_pool_MemtableReclaimMemory_pending_tasks": 0,
198 "thread_pool_MemtableReclaimMemory_total_blocked_tasks": 0,
199 "thread_pool_MutationStage_active_tasks": 0,
200 "thread_pool_MutationStage_blocked_tasks": 0,
201 "thread_pool_MutationStage_pending_tasks": 0,
202 "thread_pool_MutationStage_total_blocked_tasks": 0,
203 "thread_pool_Native-Transport-Requests_active_tasks": 0,
204 "thread_pool_Native-Transport-Requests_blocked_tasks": 0,
205 "thread_pool_Native-Transport-Requests_pending_tasks": 0,
206 "thread_pool_Native-Transport-Requests_total_blocked_tasks": 0,
207 "thread_pool_PendingRangeCalculator_active_tasks": 0,
208 "thread_pool_PendingRangeCalculator_blocked_tasks": 0,
209 "thread_pool_PendingRangeCalculator_pending_tasks": 0,
210 "thread_pool_PendingRangeCalculator_total_blocked_tasks": 0,
211 "thread_pool_PerDiskMemtableFlushWriter_0_active_tasks": 0,
212 "thread_pool_PerDiskMemtableFlushWriter_0_blocked_tasks": 0,
213 "thread_pool_PerDiskMemtableFlushWriter_0_pending_tasks": 0,
214 "thread_pool_PerDiskMemtableFlushWriter_0_total_blocked_tasks": 0,
215 "thread_pool_ReadStage_active_tasks": 0,
216 "thread_pool_ReadStage_blocked_tasks": 0,
217 "thread_pool_ReadStage_pending_tasks": 0,
218 "thread_pool_ReadStage_total_blocked_tasks": 0,
219 "thread_pool_Sampler_active_tasks": 0,
220 "thread_pool_Sampler_blocked_tasks": 0,
221 "thread_pool_Sampler_pending_tasks": 0,
222 "thread_pool_Sampler_total_blocked_tasks": 0,
223 "thread_pool_SecondaryIndexManagement_active_tasks": 0,
224 "thread_pool_SecondaryIndexManagement_blocked_tasks": 0,
225 "thread_pool_SecondaryIndexManagement_pending_tasks": 0,
226 "thread_pool_SecondaryIndexManagement_total_blocked_tasks": 0,
227 "thread_pool_ValidationExecutor_active_tasks": 0,
228 "thread_pool_ValidationExecutor_blocked_tasks": 0,
229 "thread_pool_ValidationExecutor_pending_tasks": 0,
230 "thread_pool_ValidationExecutor_total_blocked_tasks": 0,
231 "thread_pool_ViewBuildExecutor_active_tasks": 0,
232 "thread_pool_ViewBuildExecutor_blocked_tasks": 0,
233 "thread_pool_ViewBuildExecutor_pending_tasks": 0,
234 "thread_pool_ViewBuildExecutor_total_blocked_tasks": 0,
235 },
236 },
237 "fails if endpoint returns invalid data": {
238 prepare: prepareCassandraInvalidData,
239 },
240 "fails on connection refused": {
241 prepare: prepareCassandraConnectionRefused,
242 },
243 "fails on 404 response": {
244 prepare: prepareCassandraResponse404,
245 },
246 }
247
248 for name, test := range tests {
249 t.Run(name, func(t *testing.T) {
250 collr, cleanup := test.prepare()
251 defer cleanup()
252
253 require.NoError(t, collr.Init(context.Background()))
254
255 mx := collr.Collect(context.Background())
256
257 assert.Equal(t, test.wantCollected, mx)
258 })
259 }
260 }
261
262 func prepareCassandra() (collr *Collector, cleanup func()) {
263 ts := httptest.NewServer(http.HandlerFunc(
264 func(w http.ResponseWriter, r *http.Request) {
265 _, _ = w.Write(dataExpectedMetrics)
266 }))
267
268 collr = New()
269 collr.URL = ts.URL
270 return collr, ts.Close
271 }
272
273 func prepareCassandraInvalidData() (collr *Collector, cleanup func()) {
274 ts := httptest.NewServer(http.HandlerFunc(
275 func(w http.ResponseWriter, r *http.Request) {
276 _, _ = w.Write([]byte("hello and\n goodbye"))
277 }))
278
279 collr = New()
280 collr.URL = ts.URL
281 return collr, ts.Close
282 }
283
284 func prepareCassandraConnectionRefused() (collr *Collector, cleanup func()) {
285 collr = New()
286 collr.URL = "http://127.0.0.1:38001"
287 return collr, func() {}
288 }
289
290 func prepareCassandraResponse404() (collr *Collector, cleanup func()) {
291 ts := httptest.NewServer(http.HandlerFunc(
292 func(w http.ResponseWriter, r *http.Request) {
293 w.WriteHeader(http.StatusNotFound)
294 }))
295
296 collr = New()
297 collr.URL = ts.URL
298 return collr, ts.Close
299 }