diff options
Diffstat (limited to '')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/squidlog/squidlog_test.go | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/squidlog/squidlog_test.go b/src/go/collectors/go.d.plugin/modules/squidlog/squidlog_test.go new file mode 100644 index 000000000..5cc8a7285 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/squidlog/squidlog_test.go @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package squidlog + +import ( + "bytes" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/pkg/logs" + "github.com/netdata/netdata/go/go.d.plugin/pkg/metrics" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") + + dataNativeFormatAccessLog, _ = os.ReadFile("testdata/access.log") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + "dataNativeFormatAccessLog": dataNativeFormatAccessLog, + } { + require.NotNil(t, data, name) + } +} + +func TestSquidLog_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &SquidLog{}, dataConfigJSON, dataConfigYAML) +} + +func TestNew(t *testing.T) { + assert.Implements(t, (*module.Module)(nil), New()) +} + +func TestSquidLog_Init(t *testing.T) { + squidlog := New() + + assert.NoError(t, squidlog.Init()) +} + +func TestSquidLog_Check(t *testing.T) { +} + +func TestSquidLog_Check_ErrorOnCreatingLogReaderNoLogFile(t *testing.T) { + squid := New() + defer squid.Cleanup() + squid.Path = "testdata/not_exists.log" + require.NoError(t, squid.Init()) + + assert.Error(t, squid.Check()) +} + +func TestSquid_Check_ErrorOnCreatingParserUnknownFormat(t *testing.T) { + squid := New() + defer squid.Cleanup() + squid.Path = "testdata/unknown.log" + require.NoError(t, squid.Init()) + + assert.Error(t, squid.Check()) +} + +func TestSquid_Check_ErrorOnCreatingParserZeroKnownFields(t *testing.T) { + squid := New() + defer squid.Cleanup() + squid.Path = "testdata/access.log" + squid.ParserConfig.CSV.Format = "$one $two" + require.NoError(t, squid.Init()) + + assert.Error(t, squid.Check()) +} + +func TestSquidLog_Charts(t *testing.T) { + assert.Nil(t, New().Charts()) + + squid := prepareSquidCollect(t) + assert.NotNil(t, squid.Charts()) + +} + +func TestSquidLog_Cleanup(t *testing.T) { + New().Cleanup() +} + +func TestSquidLog_Collect(t *testing.T) { + squid := prepareSquidCollect(t) + + expected := map[string]int64{ + "bytes_sent": 6827357, + "cache_error_tag_ABORTED": 326, + "cache_handling_tag_CF": 154, + "cache_handling_tag_CLIENT": 172, + "cache_load_source_tag_MEM": 172, + "cache_object_tag_NEGATIVE": 308, + "cache_object_tag_STALE": 172, + "cache_result_code_NONE": 158, + "cache_result_code_TCP_CF_NEGATIVE_NEGATIVE_ABORTED": 154, + "cache_result_code_UDP_CLIENT_STALE_MEM_ABORTED": 172, + "cache_transport_tag_NONE": 158, + "cache_transport_tag_TCP": 154, + "cache_transport_tag_UDP": 172, + "hier_code_HIER_CACHE_DIGEST_HIT": 128, + "hier_code_HIER_NO_CACHE_DIGEST_DIRECT": 130, + "hier_code_HIER_PARENT_HIT": 106, + "hier_code_HIER_SINGLE_PARENT": 120, + "http_resp_0xx": 51, + "http_resp_1xx": 45, + "http_resp_2xx": 62, + "http_resp_3xx": 120, + "http_resp_4xx": 112, + "http_resp_5xx": 46, + "http_resp_6xx": 48, + "http_resp_code_0": 51, + "http_resp_code_100": 45, + "http_resp_code_200": 62, + "http_resp_code_300": 58, + "http_resp_code_304": 62, + "http_resp_code_400": 56, + "http_resp_code_401": 56, + "http_resp_code_500": 46, + "http_resp_code_603": 48, + "mime_type_application": 52, + "mime_type_audio": 56, + "mime_type_font": 44, + "mime_type_image": 50, + "mime_type_message": 44, + "mime_type_model": 62, + "mime_type_multipart": 61, + "mime_type_text": 61, + "mime_type_video": 54, + "req_method_COPY": 84, + "req_method_GET": 70, + "req_method_HEAD": 59, + "req_method_OPTIONS": 99, + "req_method_POST": 74, + "req_method_PURGE": 98, + "req_type_bad": 56, + "req_type_error": 94, + "req_type_redirect": 58, + "req_type_success": 276, + "requests": 500, + "resp_time_avg": 3015931, + "resp_time_count": 484, + "resp_time_max": 4988000, + "resp_time_min": 1002000, + "resp_time_sum": 1459711000, + "server_address_2001:db8:2ce:a": 79, + "server_address_2001:db8:2ce:b": 89, + "server_address_203.0.113.100": 67, + "server_address_203.0.113.200": 70, + "server_address_content-gateway": 87, + "uniq_clients": 5, + "unmatched": 16, + } + + collected := squid.Collect() + + assert.Equal(t, expected, collected) + testCharts(t, squid, collected) +} + +func TestSquidLog_Collect_ReturnOldDataIfNothingRead(t *testing.T) { + squid := prepareSquidCollect(t) + + expected := map[string]int64{ + "bytes_sent": 6827357, + "cache_error_tag_ABORTED": 326, + "cache_handling_tag_CF": 154, + "cache_handling_tag_CLIENT": 172, + "cache_load_source_tag_MEM": 172, + "cache_object_tag_NEGATIVE": 308, + "cache_object_tag_STALE": 172, + "cache_result_code_NONE": 158, + "cache_result_code_TCP_CF_NEGATIVE_NEGATIVE_ABORTED": 154, + "cache_result_code_UDP_CLIENT_STALE_MEM_ABORTED": 172, + "cache_transport_tag_NONE": 158, + "cache_transport_tag_TCP": 154, + "cache_transport_tag_UDP": 172, + "hier_code_HIER_CACHE_DIGEST_HIT": 128, + "hier_code_HIER_NO_CACHE_DIGEST_DIRECT": 130, + "hier_code_HIER_PARENT_HIT": 106, + "hier_code_HIER_SINGLE_PARENT": 120, + "http_resp_0xx": 51, + "http_resp_1xx": 45, + "http_resp_2xx": 62, + "http_resp_3xx": 120, + "http_resp_4xx": 112, + "http_resp_5xx": 46, + "http_resp_6xx": 48, + "http_resp_code_0": 51, + "http_resp_code_100": 45, + "http_resp_code_200": 62, + "http_resp_code_300": 58, + "http_resp_code_304": 62, + "http_resp_code_400": 56, + "http_resp_code_401": 56, + "http_resp_code_500": 46, + "http_resp_code_603": 48, + "mime_type_application": 52, + "mime_type_audio": 56, + "mime_type_font": 44, + "mime_type_image": 50, + "mime_type_message": 44, + "mime_type_model": 62, + "mime_type_multipart": 61, + "mime_type_text": 61, + "mime_type_video": 54, + "req_method_COPY": 84, + "req_method_GET": 70, + "req_method_HEAD": 59, + "req_method_OPTIONS": 99, + "req_method_POST": 74, + "req_method_PURGE": 98, + "req_type_bad": 56, + "req_type_error": 94, + "req_type_redirect": 58, + "req_type_success": 276, + "requests": 500, + "resp_time_avg": 0, + "resp_time_count": 0, + "resp_time_max": 0, + "resp_time_min": 0, + "resp_time_sum": 0, + "server_address_2001:db8:2ce:a": 79, + "server_address_2001:db8:2ce:b": 89, + "server_address_203.0.113.100": 67, + "server_address_203.0.113.200": 70, + "server_address_content-gateway": 87, + "uniq_clients": 0, + "unmatched": 16, + } + + _ = squid.Collect() + collected := squid.Collect() + + assert.Equal(t, expected, collected) + testCharts(t, squid, collected) +} + +func testCharts(t *testing.T, squidlog *SquidLog, collected map[string]int64) { + t.Helper() + ensureChartsDynamicDimsCreated(t, squidlog) + ensureCollectedHasAllChartsDimsVarsIDs(t, squidlog, collected) +} + +func ensureChartsDynamicDimsCreated(t *testing.T, squid *SquidLog) { + ensureDynamicDimsCreated(t, squid, cacheCodeChart.ID, pxCacheCode, squid.mx.CacheCode) + ensureDynamicDimsCreated(t, squid, cacheCodeTransportTagChart.ID, pxTransportTag, squid.mx.CacheCodeTransportTag) + ensureDynamicDimsCreated(t, squid, cacheCodeHandlingTagChart.ID, pxHandlingTag, squid.mx.CacheCodeHandlingTag) + ensureDynamicDimsCreated(t, squid, cacheCodeObjectTagChart.ID, pxObjectTag, squid.mx.CacheCodeObjectTag) + ensureDynamicDimsCreated(t, squid, cacheCodeLoadSourceTagChart.ID, pxSourceTag, squid.mx.CacheCodeLoadSourceTag) + ensureDynamicDimsCreated(t, squid, cacheCodeErrorTagChart.ID, pxErrorTag, squid.mx.CacheCodeErrorTag) + ensureDynamicDimsCreated(t, squid, httpRespCodesChart.ID, pxHTTPCode, squid.mx.HTTPRespCode) + ensureDynamicDimsCreated(t, squid, reqMethodChart.ID, pxReqMethod, squid.mx.ReqMethod) + ensureDynamicDimsCreated(t, squid, hierCodeChart.ID, pxHierCode, squid.mx.HierCode) + ensureDynamicDimsCreated(t, squid, serverAddrChart.ID, pxSrvAddr, squid.mx.Server) + ensureDynamicDimsCreated(t, squid, mimeTypeChart.ID, pxMimeType, squid.mx.MimeType) +} + +func ensureDynamicDimsCreated(t *testing.T, squid *SquidLog, chartID, dimPrefix string, data metrics.CounterVec) { + chart := squid.Charts().Get(chartID) + assert.NotNilf(t, chart, "chart '%s' is not created", chartID) + if chart == nil { + return + } + for v := range data { + id := dimPrefix + v + assert.Truef(t, chart.HasDim(id), "chart '%s' has no dim for '%s', expected '%s'", chart.ID, v, id) + } +} + +func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, s *SquidLog, collected map[string]int64) { + for _, chart := range *s.Charts() { + for _, dim := range chart.Dims { + _, ok := collected[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := collected[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +func prepareSquidCollect(t *testing.T) *SquidLog { + t.Helper() + squid := New() + squid.Path = "testdata/access.log" + require.NoError(t, squid.Init()) + require.NoError(t, squid.Check()) + defer squid.Cleanup() + + p, err := logs.NewCSVParser(squid.ParserConfig.CSV, bytes.NewReader(dataNativeFormatAccessLog)) + require.NoError(t, err) + squid.parser = p + return squid +} + +// generateLogs is used to populate 'testdata/access.log' +//func generateLogs(w io.Writer, num int) error { +// var ( +// client = []string{"localhost", "203.0.113.1", "203.0.113.2", "2001:db8:2ce:1", "2001:db8:2ce:2"} +// cacheCode = []string{"TCP_CF_NEGATIVE_NEGATIVE_ABORTED", "UDP_CLIENT_STALE_MEM_ABORTED", "NONE"} +// httpCode = []string{"000", "100", "200", "300", "304", "400", "401", "500", "603"} +// method = []string{"GET", "HEAD", "POST", "COPY", "PURGE", "OPTIONS"} +// hierCode = []string{"HIER_PARENT_HIT", "HIER_SINGLE_PARENT", "HIER_CACHE_DIGEST_HIT", "HIER_NO_CACHE_DIGEST_DIRECT"} +// server = []string{"content-gateway", "203.0.113.100", "203.0.113.200", "2001:db8:2ce:a", "2001:db8:2ce:b", "-"} +// mimeType = []string{"application", "audio", "font", "image", "message", "model", "multipart", "video", "text"} +// ) +// +// r := rand.New(rand.NewSource(time.Now().UnixNano())) +// randFromString := func(s []string) string { return s[r.Intn(len(s))] } +// randInt := func(min, max int) int { return r.Intn(max-min) + min } +// +// var line string +// for i := 0; i < num; i++ { +// unmatched := randInt(1, 100) > 95 +// if i > 0 && unmatched { +// line = "Unmatched! The rat the cat the dog chased killed ate the malt!\n" +// } else { +// // 1576177221.686 0 ::1 TCP_MISS/200 1621 GET cache_object://localhost/counters - HIER_NONE/- text/plain +// line = fmt.Sprintf( +// "1576177221.686 %d %s %s/%s %d %s cache_object://localhost/counters - %s/%s %s/plain\n", +// randInt(1000, 5000), +// randFromString(client), +// randFromString(cacheCode), +// randFromString(httpCode), +// randInt(9000, 19000), +// randFromString(method), +// randFromString(hierCode), +// randFromString(server), +// randFromString(mimeType), +// ) +// } +// _, err := fmt.Fprint(w, line) +// if err != nil { +// return err +// } +// } +// return nil +//} |