master
go 305 lines 11.8 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package clickhouse
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 dataRespSystemAsyncMetrics, _ = os.ReadFile("testdata/resp_system_async_metrics.csv")
24 dataRespSystemMetrics, _ = os.ReadFile("testdata/resp_system_metrics.csv")
25 dataRespSystemEvents, _ = os.ReadFile("testdata/resp_system_events.csv")
26 dataRespSystemParts, _ = os.ReadFile("testdata/resp_system_parts.csv")
27 dataRespSystemDisks, _ = os.ReadFile("testdata/resp_system_disks.csv")
28 dataRespLongestQueryTime, _ = os.ReadFile("testdata/resp_longest_query_time.csv")
29 )
30
31 func Test_testDataIsValid(t *testing.T) {
32 for name, data := range map[string][]byte{
33 "dataConfigJSON": dataConfigJSON,
34 "dataConfigYAML": dataConfigYAML,
35 "dataRespSystemAsyncMetrics": dataRespSystemAsyncMetrics,
36 "dataRespSystemMetrics": dataRespSystemMetrics,
37 "dataRespSystemEvents": dataRespSystemEvents,
38 "dataRespSystemParts": dataRespSystemParts,
39 "dataRespSystemDisks": dataRespSystemDisks,
40 "dataRespLongestQueryTime": dataRespLongestQueryTime,
41 } {
42 require.NotNil(t, data, name)
43 }
44 }
45
46 func TestClickhouse_ConfigurationSerialize(t *testing.T) {
47 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
48 }
49
50 func TestCollector_Init(t *testing.T) {
51 tests := map[string]struct {
52 wantFail bool
53 config Config
54 }{
55 "success with default": {
56 wantFail: false,
57 config: New().Config,
58 },
59 "fail when URL not set": {
60 wantFail: true,
61 config: Config{
62 HTTPConfig: web.HTTPConfig{
63 RequestConfig: web.RequestConfig{URL: ""},
64 },
65 },
66 },
67 }
68
69 for name, test := range tests {
70 t.Run(name, func(t *testing.T) {
71 collr := New()
72 collr.Config = test.config
73
74 if test.wantFail {
75 assert.Error(t, collr.Init(context.Background()))
76 } else {
77 assert.NoError(t, collr.Init(context.Background()))
78 }
79 })
80 }
81 }
82
83 func TestCollector_Charts(t *testing.T) {
84 assert.NotNil(t, New().Charts())
85 }
86
87 func TestCollector_Check(t *testing.T) {
88 tests := map[string]struct {
89 wantFail bool
90 prepare func(t *testing.T) (*Collector, func())
91 }{
92 "success on valid response": {
93 wantFail: false,
94 prepare: prepareCaseOk,
95 },
96 "fails on unexpected response": {
97 wantFail: true,
98 prepare: prepareCaseUnexpectedResponse,
99 },
100 "fails on connection refused": {
101 wantFail: true,
102 prepare: prepareCaseConnectionRefused,
103 },
104 }
105
106 for name, test := range tests {
107 t.Run(name, func(t *testing.T) {
108 collr, cleanup := test.prepare(t)
109 defer cleanup()
110
111 if test.wantFail {
112 assert.Error(t, collr.Check(context.Background()))
113 } else {
114 assert.NoError(t, collr.Check(context.Background()))
115 }
116 })
117 }
118 }
119
120 func TestCollector_Collect(t *testing.T) {
121 tests := map[string]struct {
122 prepare func(t *testing.T) (*Collector, func())
123 wantMetrics map[string]int64
124 }{
125 "success on valid response": {
126 prepare: prepareCaseOk,
127 wantMetrics: map[string]int64{
128 "LongestRunningQueryTime": 73,
129 "async_metrics_MaxPartCountForPartition": 7,
130 "async_metrics_ReplicasMaxAbsoluteDelay": 0,
131 "async_metrics_Uptime": 64380,
132 "disk_default_free_space_bytes": 165494767616,
133 "disk_default_used_space_bytes": 45184565248,
134 "events_DelayedInserts": 0,
135 "events_DelayedInsertsMilliseconds": 0,
136 "events_DistributedAsyncInsertionFailures": 0,
137 "events_DistributedConnectionFailAtAll": 0,
138 "events_DistributedConnectionFailTry": 0,
139 "events_DistributedConnectionTries": 0,
140 "events_DistributedDelayedInserts": 0,
141 "events_DistributedDelayedInsertsMilliseconds": 0,
142 "events_DistributedRejectedInserts": 0,
143 "events_DistributedSyncInsertionTimeoutExceeded": 0,
144 "events_FailedInsertQuery": 0,
145 "events_FailedQuery": 0,
146 "events_FailedSelectQuery": 0,
147 "events_FileOpen": 1568962,
148 "events_InsertQuery": 0,
149 "events_InsertQueryTimeMicroseconds": 0,
150 "events_InsertedBytes": 0,
151 "events_InsertedRows": 0,
152 "events_MarkCacheHits": 0,
153 "events_MarkCacheMisses": 0,
154 "events_Merge": 0,
155 "events_MergeTreeDataWriterCompressedBytes": 0,
156 "events_MergeTreeDataWriterRows": 0,
157 "events_MergeTreeDataWriterUncompressedBytes": 0,
158 "events_MergedRows": 0,
159 "events_MergedUncompressedBytes": 0,
160 "events_MergesTimeMilliseconds": 0,
161 "events_Query": 0,
162 "events_QueryMemoryLimitExceeded": 0,
163 "events_QueryPreempted": 0,
164 "events_QueryTimeMicroseconds": 0,
165 "events_ReadBackoff": 0,
166 "events_ReadBufferFromFileDescriptorRead": 0,
167 "events_ReadBufferFromFileDescriptorReadBytes": 0,
168 "events_ReadBufferFromFileDescriptorReadFailed": 0,
169 "events_RejectedInserts": 0,
170 "events_ReplicatedDataLoss": 0,
171 "events_ReplicatedPartFailedFetches": 0,
172 "events_ReplicatedPartFetches": 0,
173 "events_ReplicatedPartFetchesOfMerged": 0,
174 "events_ReplicatedPartMerges": 0,
175 "events_Seek": 0,
176 "events_SelectQuery": 0,
177 "events_SelectQueryTimeMicroseconds": 0,
178 "events_SelectedBytes": 0,
179 "events_SelectedMarks": 0,
180 "events_SelectedParts": 0,
181 "events_SelectedRanges": 0,
182 "events_SelectedRows": 0,
183 "events_SlowRead": 0,
184 "events_SuccessfulInsertQuery": 0,
185 "events_SuccessfulQuery": 0,
186 "events_SuccessfulSelectQuery": 0,
187 "events_UncompressedCacheHits": 0,
188 "events_UncompressedCacheMisses": 0,
189 "events_WriteBufferFromFileDescriptorWrite": 0,
190 "events_WriteBufferFromFileDescriptorWriteBytes": 0,
191 "events_WriteBufferFromFileDescriptorWriteFailed": 0,
192 "metrics_DistributedFilesToInsert": 0,
193 "metrics_DistributedSend": 0,
194 "metrics_HTTPConnection": 0,
195 "metrics_InterserverConnection": 0,
196 "metrics_MemoryTracking": 1270999152,
197 "metrics_MySQLConnection": 0,
198 "metrics_PartsActive": 25,
199 "metrics_PartsCompact": 233,
200 "metrics_PartsDeleteOnDestroy": 0,
201 "metrics_PartsDeleting": 0,
202 "metrics_PartsOutdated": 284,
203 "metrics_PartsPreActive": 0,
204 "metrics_PartsTemporary": 0,
205 "metrics_PartsWide": 76,
206 "metrics_PostgreSQLConnection": 0,
207 "metrics_Query": 1,
208 "metrics_QueryPreempted": 0,
209 "metrics_ReadonlyReplica": 0,
210 "metrics_ReplicatedChecks": 0,
211 "metrics_ReplicatedFetch": 0,
212 "metrics_ReplicatedSend": 0,
213 "metrics_TCPConnection": 1,
214 "table_asynchronous_metric_log_database_system_parts": 6,
215 "table_asynchronous_metric_log_database_system_rows": 70377261,
216 "table_asynchronous_metric_log_database_system_size_bytes": 19113663,
217 "table_metric_log_database_system_parts": 6,
218 "table_metric_log_database_system_rows": 162718,
219 "table_metric_log_database_system_size_bytes": 18302533,
220 "table_processors_profile_log_database_system_parts": 5,
221 "table_processors_profile_log_database_system_rows": 20107,
222 "table_processors_profile_log_database_system_size_bytes": 391629,
223 "table_query_log_database_system_parts": 5,
224 "table_query_log_database_system_rows": 761,
225 "table_query_log_database_system_size_bytes": 196403,
226 "table_trace_log_database_system_parts": 8,
227 "table_trace_log_database_system_rows": 1733076,
228 "table_trace_log_database_system_size_bytes": 28695023,
229 },
230 },
231 "fails on unexpected response": {
232 prepare: prepareCaseUnexpectedResponse,
233 },
234 "fails on connection refused": {
235 prepare: prepareCaseConnectionRefused,
236 },
237 }
238
239 for name, test := range tests {
240 t.Run(name, func(t *testing.T) {
241 collr, cleanup := test.prepare(t)
242 defer cleanup()
243
244 mx := collr.Collect(context.Background())
245
246 require.Equal(t, test.wantMetrics, mx)
247
248 if len(test.wantMetrics) > 0 {
249 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
250 }
251 })
252 }
253 }
254
255 func prepareCaseOk(t *testing.T) (*Collector, func()) {
256 t.Helper()
257 srv := httptest.NewServer(http.HandlerFunc(
258 func(w http.ResponseWriter, r *http.Request) {
259 switch r.URL.Query().Get("query") {
260 case querySystemEvents:
261 _, _ = w.Write(dataRespSystemEvents)
262 case querySystemMetrics:
263 _, _ = w.Write(dataRespSystemMetrics)
264 case querySystemAsyncMetrics:
265 _, _ = w.Write(dataRespSystemAsyncMetrics)
266 case querySystemParts:
267 _, _ = w.Write(dataRespSystemParts)
268 case querySystemDisks:
269 _, _ = w.Write(dataRespSystemDisks)
270 case queryLongestQueryTime:
271 _, _ = w.Write(dataRespLongestQueryTime)
272 default:
273 w.WriteHeader(http.StatusNotFound)
274 }
275 }))
276
277 collr := New()
278 collr.URL = srv.URL
279 require.NoError(t, collr.Init(context.Background()))
280
281 return collr, srv.Close
282 }
283
284 func prepareCaseUnexpectedResponse(t *testing.T) (*Collector, func()) {
285 t.Helper()
286 srv := httptest.NewServer(http.HandlerFunc(
287 func(w http.ResponseWriter, r *http.Request) {
288 _, _ = w.Write([]byte("hello and\n goodbye"))
289 }))
290
291 collr := New()
292 collr.URL = srv.URL
293 require.NoError(t, collr.Init(context.Background()))
294
295 return collr, srv.Close
296 }
297
298 func prepareCaseConnectionRefused(t *testing.T) (*Collector, func()) {
299 t.Helper()
300 collr := New()
301 collr.URL = "http://127.0.0.1:65001/stat"
302 require.NoError(t, collr.Init(context.Background()))
303
304 return collr, func() {}
305 }